1 /*
  2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 #include "precompiled.hpp"
 25 #include "runtime/jniHandles.inline.hpp"
 26 #include "oops/typeArrayOop.inline.hpp"
 27 #include "oops/oopCast.inline.hpp"
 28 #include "prims/foreign_globals.inline.hpp"
 29 #include "runtime/sharedRuntime.hpp"
 30 #include "utilities/formatBuffer.hpp"
 31 
 32 bool ABIDescriptor::is_volatile_reg(Register reg) const {
 33     return _integer_argument_registers.contains(reg)
 34         || _integer_additional_volatile_registers.contains(reg);
 35 }
 36 
 37 bool ABIDescriptor::is_volatile_reg(XMMRegister reg) const {
 38     return _vector_argument_registers.contains(reg)
 39         || _vector_additional_volatile_registers.contains(reg);
 40 }
 41 
 42 #define INTEGER_TYPE 0
 43 #define VECTOR_TYPE 1
 44 #define X87_TYPE 2
 45 
 46 const ABIDescriptor ForeignGlobals::parse_abi_descriptor_impl(jobject jabi) const {
 47   oop abi_oop = JNIHandles::resolve_non_null(jabi);
 48   ABIDescriptor abi;
 49 
 50   objArrayOop inputStorage = oop_cast<objArrayOop>(abi_oop->obj_field(ABI.inputStorage_offset));
 51   loadArray(inputStorage, INTEGER_TYPE, abi._integer_argument_registers, as_Register);
 52   loadArray(inputStorage, VECTOR_TYPE, abi._vector_argument_registers, as_XMMRegister);
 53 
 54   objArrayOop outputStorage = oop_cast<objArrayOop>(abi_oop->obj_field(ABI.outputStorage_offset));
 55   loadArray(outputStorage, INTEGER_TYPE, abi._integer_return_registers, as_Register);
 56   loadArray(outputStorage, VECTOR_TYPE, abi._vector_return_registers, as_XMMRegister);
 57   objArrayOop subarray = oop_cast<objArrayOop>(outputStorage->obj_at(X87_TYPE));
 58   abi._X87_return_registers_noof = subarray->length();
 59 
 60   objArrayOop volatileStorage = oop_cast<objArrayOop>(abi_oop->obj_field(ABI.volatileStorage_offset));
 61   loadArray(volatileStorage, INTEGER_TYPE, abi._integer_additional_volatile_registers, as_Register);
 62   loadArray(volatileStorage, VECTOR_TYPE, abi._vector_additional_volatile_registers, as_XMMRegister);
 63 
 64   abi._stack_alignment_bytes = abi_oop->int_field(ABI.stackAlignment_offset);
 65   abi._shadow_space_bytes = abi_oop->int_field(ABI.shadowSpace_offset);
 66 
 67   abi._target_addr_reg = parse_vmstorage(abi_oop->obj_field(ABI.targetAddrStorage_offset))->as_Register();
 68   abi._ret_buf_addr_reg = parse_vmstorage(abi_oop->obj_field(ABI.retBufAddrStorage_offset))->as_Register();
 69 
 70   return abi;
 71 }
 72 
 73 enum class RegType {
 74   INTEGER = 0,
 75   VECTOR = 1,
 76   X87 = 2,
 77   STACK = 3
 78 };
 79 
 80 VMReg ForeignGlobals::vmstorage_to_vmreg(int type, int index) {
 81   switch(static_cast<RegType>(type)) {
 82     case RegType::INTEGER: return ::as_Register(index)->as_VMReg();
 83     case RegType::VECTOR: return ::as_XMMRegister(index)->as_VMReg();
 84     case RegType::STACK: return VMRegImpl::stack2reg(index LP64_ONLY(* 2)); // numbering on x64 goes per 64-bits
 85     case RegType::X87: break;
 86   }
 87   return VMRegImpl::Bad();
 88 }
 89 
 90 int RegSpiller::pd_reg_size(VMReg reg) {
 91   if (reg->is_Register()) {
 92     return 8;
 93   } else if (reg->is_XMMRegister()) {
 94     return 16;
 95   }
 96   return 0; // stack and BAD
 97 }
 98 
 99 void RegSpiller::pd_store_reg(MacroAssembler* masm, int offset, VMReg reg) {
100   if (reg->is_Register()) {
101     masm->movptr(Address(rsp, offset), reg->as_Register());
102   } else if (reg->is_XMMRegister()) {
103     masm->movdqu(Address(rsp, offset), reg->as_XMMRegister());
104   } else {
105     // stack and BAD
106   }
107 }
108 
109 void RegSpiller::pd_load_reg(MacroAssembler* masm, int offset, VMReg reg) {
110   if (reg->is_Register()) {
111     masm->movptr(reg->as_Register(), Address(rsp, offset));
112   } else if (reg->is_XMMRegister()) {
113     masm->movdqu(reg->as_XMMRegister(), Address(rsp, offset));
114   } else {
115     // stack and BAD
116   }
117 }
118 
119 void ArgumentShuffle::pd_generate(MacroAssembler* masm, VMReg tmp, int in_stk_bias, int out_stk_bias) const {
120   Register tmp_reg = tmp->as_Register();
121   for (int i = 0; i < _moves.length(); i++) {
122     Move move = _moves.at(i);
123     BasicType arg_bt     = move.bt;
124     VMRegPair from_vmreg = move.from;
125     VMRegPair to_vmreg   = move.to;
126 
127     masm->block_comment(err_msg("bt=%s", null_safe_string(type2name(arg_bt))));
128     switch (arg_bt) {
129       case T_BOOLEAN:
130       case T_BYTE:
131       case T_SHORT:
132       case T_CHAR:
133       case T_INT:
134         masm->move32_64(from_vmreg, to_vmreg, tmp_reg, in_stk_bias, out_stk_bias);
135         break;
136 
137       case T_FLOAT:
138         if (to_vmreg.first()->is_Register()) { // Windows vararg call
139           masm->movq(to_vmreg.first()->as_Register(), from_vmreg.first()->as_XMMRegister());
140         } else {
141           masm->float_move(from_vmreg, to_vmreg, tmp_reg, in_stk_bias, out_stk_bias);
142         }
143         break;
144 
145       case T_DOUBLE:
146         if (to_vmreg.first()->is_Register()) { // Windows vararg call
147           masm->movq(to_vmreg.first()->as_Register(), from_vmreg.first()->as_XMMRegister());
148         } else {
149           masm->double_move(from_vmreg, to_vmreg, tmp_reg, in_stk_bias, out_stk_bias);
150         }
151         break;
152 
153       case T_LONG:
154         masm->long_move(from_vmreg, to_vmreg, tmp_reg, in_stk_bias, out_stk_bias);
155         break;
156 
157       default:
158         fatal("found in upcall args: %s", type2name(arg_bt));
159     }
160   }
161 }