1 /*
2 * Copyright (c) 2019, 2021, 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
25 #include "asm/assembler.hpp"
26 #include "asm/assembler.inline.hpp"
27 #include "asm/macroAssembler.hpp"
28 #include "jvm.h"
29 #include "oops/inlineKlass.inline.hpp"
30 #include "runtime/sharedRuntime.hpp"
31 #include "runtime/signature_cc.hpp"
32 #ifdef COMPILER2
33 #include "opto/compile.hpp"
34 #include "opto/node.hpp"
35 #endif
36
37 void MacroAssembler::skip_unpacked_fields(const GrowableArray<SigEntry>* sig, int& sig_index, VMRegPair* regs_from, int regs_from_count, int& from_index) {
38 ScalarizedInlineArgsStream stream(sig, sig_index, regs_from, regs_from_count, from_index);
39 VMReg reg;
40 BasicType bt;
41 while (stream.next(reg, bt)) {}
42 sig_index = stream.sig_index();
43 from_index = stream.regs_index();
44 }
45
46 bool MacroAssembler::is_reg_in_unpacked_fields(const GrowableArray<SigEntry>* sig, int sig_index, VMReg to, VMRegPair* regs_from, int regs_from_count, int from_index) {
47 ScalarizedInlineArgsStream stream(sig, sig_index, regs_from, regs_from_count, from_index);
48 VMReg reg;
49 BasicType bt;
50 while (stream.next(reg, bt)) {
51 if (reg == to) {
52 return true;
53 }
54 }
55 return false;
56 }
57
58 MacroAssembler::RegState* MacroAssembler::init_reg_state(VMRegPair* regs, int num_regs, int sp_inc, int max_stack) {
59 int max_reg = VMRegImpl::stack2reg(max_stack)->value();
60 MacroAssembler::RegState* reg_state = NEW_RESOURCE_ARRAY(MacroAssembler::RegState, max_reg);
61
62 // Make all writable
63 for (int i = 0; i < max_reg; ++i) {
64 reg_state[i] = MacroAssembler::reg_writable;
65 }
66 // Set all source registers/stack slots to readonly to prevent accidental overwriting
67 for (int i = 0; i < num_regs; ++i) {
68 VMReg reg = regs[i].first();
69 if (!reg->is_valid()) continue;
70 if (reg->is_stack()) {
71 // Update source stack location by adding stack increment
72 reg = VMRegImpl::stack2reg(reg->reg2stack() + sp_inc/VMRegImpl::stack_slot_size);
73 regs[i] = reg;
74 }
75 assert(reg->value() >= 0 && reg->value() < max_reg, "reg value out of bounds");
76 reg_state[reg->value()] = MacroAssembler::reg_readonly;
77 }
78 return reg_state;
79 }
80
81 #ifdef COMPILER2
82 int MacroAssembler::unpack_inline_args(Compile* C, bool receiver_only) {
83 assert(C->has_scalarized_args(), "inline type argument scalarization is disabled");
84 ciMethod* method = C->method();
85 const GrowableArray<SigEntry>* sig = method->get_sig_cc();
86 assert(sig != nullptr, "must have scalarized signature");
87
88 // Get unscalarized calling convention
89 BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, 256);
90 int args_passed = 0;
91 if (!method->is_static()) {
92 sig_bt[args_passed++] = T_OBJECT;
93 }
94 if (!receiver_only) {
95 for (ciSignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) {
96 BasicType bt = ss.type()->basic_type();
97 sig_bt[args_passed++] = bt;
98 if (type2size[bt] == 2) {
99 sig_bt[args_passed++] = T_VOID;
100 }
101 }
102 } else {
103 // Only unpack the receiver, all other arguments are already scalarized
104 ciInstanceKlass* holder = method->holder();
105 int rec_len = (holder->is_inlinetype() && method->is_scalarized_arg(0)) ? holder->as_inline_klass()->inline_arg_length() : 1;
106 // Copy scalarized signature but skip receiver and inline type delimiters
107 for (int i = 0; i < sig->length(); i++) {
108 if (SigEntry::skip_value_delimiters(sig, i) && rec_len <= 0) {
109 sig_bt[args_passed++] = sig->at(i)._bt;
110 }
111 rec_len--;
112 }
113 }
114 VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, args_passed);
115 int args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, args_passed);
116
117 // Get scalarized calling convention
118 int args_passed_cc = SigEntry::fill_sig_bt(sig, sig_bt);
119 VMRegPair* regs_cc = NEW_RESOURCE_ARRAY(VMRegPair, sig->length());
120 int args_on_stack_cc = SharedRuntime::java_calling_convention(sig_bt, regs_cc, args_passed_cc);
121
122 // Check if we need to extend the stack for unpacking
123 int sp_inc = 0;
124 if (args_on_stack_cc > args_on_stack) {
125 sp_inc = extend_stack_for_inline_args(args_on_stack_cc);
126 }
127 shuffle_inline_args(false, receiver_only, sig,
128 args_passed, args_on_stack, regs, // from
129 args_passed_cc, args_on_stack_cc, regs_cc, // to
130 sp_inc, noreg);
131 return sp_inc;
132 }
133 #endif // COMPILER2
134
135 void MacroAssembler::shuffle_inline_args(bool is_packing, bool receiver_only,
136 const GrowableArray<SigEntry>* sig,
137 int args_passed, int args_on_stack, VMRegPair* regs,
138 int args_passed_to, int args_on_stack_to, VMRegPair* regs_to,
139 int sp_inc, Register val_array) {
140 int max_stack = MAX2(args_on_stack + sp_inc/VMRegImpl::stack_slot_size, args_on_stack_to);
141 RegState* reg_state = init_reg_state(regs, args_passed, sp_inc, max_stack);
142
143 // Emit code for packing/unpacking inline type arguments
144 // We try multiple times and eventually start spilling to resolve (circular) dependencies
145 bool done = (args_passed_to == 0);
146 for (int i = 0; i < 2*args_passed_to && !done; ++i) {
147 done = true;
148 bool spill = (i > args_passed_to); // Start spilling?
149 // Iterate over all arguments (when unpacking, do in reverse)
150 int step = is_packing ? 1 : -1;
151 int from_index = is_packing ? 0 : args_passed - 1;
152 int to_index = is_packing ? 0 : args_passed_to - 1;
153 int sig_index = is_packing ? 0 : sig->length() - 1;
154 int sig_index_end = is_packing ? sig->length() : -1;
155 int vtarg_index = 0;
156 for (; sig_index != sig_index_end; sig_index += step) {
157 assert(0 <= sig_index && sig_index < sig->length(), "index out of bounds");
158 if (spill) {
159 // This call returns true IFF we should keep trying to spill in this round.
160 spill = shuffle_inline_args_spill(is_packing, sig, sig_index, regs, from_index, args_passed,
161 reg_state);
162 }
163 BasicType bt = sig->at(sig_index)._bt;
164 if (SigEntry::skip_value_delimiters(sig, sig_index)) {
165 VMReg from_reg = regs[from_index].first();
166 if (from_reg->is_valid()) {
167 done &= move_helper(from_reg, regs_to[to_index].first(), bt, reg_state);
168 } else {
169 // halves of T_LONG or T_DOUBLE
170 assert(bt == T_VOID, "unexpected basic type");
171 }
172 to_index += step;
173 from_index += step;
174 } else if (is_packing) {
175 assert(val_array != noreg, "must be");
176 VMReg reg_to = regs_to[to_index].first();
177 done &= pack_inline_helper(sig, sig_index, vtarg_index,
178 regs, args_passed, from_index, reg_to,
179 reg_state, val_array);
180 vtarg_index++;
181 to_index++;
182 } else if (!receiver_only || (from_index == 0 && bt == T_VOID)) {
183 VMReg from_reg = regs[from_index].first();
184 done &= unpack_inline_helper(sig, sig_index,
185 from_reg, from_index, regs_to, args_passed_to, to_index,
186 reg_state);
187 if (from_index == -1 && sig_index != 0) {
188 // This can happen when we are confusing an empty inline type argument which is
189 // not counted in the scalarized signature for the receiver. Just ignore it.
190 assert(receiver_only, "sanity");
191 from_index = 0;
192 }
193 }
194 }
195 }
196 guarantee(done, "Could not resolve circular dependency when shuffling inline type arguments");
197 }
198
199 bool MacroAssembler::shuffle_inline_args_spill(bool is_packing, const GrowableArray<SigEntry>* sig, int sig_index,
200 VMRegPair* regs_from, int from_index, int regs_from_count, RegState* reg_state) {
201 VMReg reg;
202 if (!is_packing || SigEntry::skip_value_delimiters(sig, sig_index)) {
203 reg = regs_from[from_index].first();
204 if (!reg->is_valid() || reg_state[reg->value()] != reg_readonly) {
205 // Spilling this won't break cycles
206 return true;
207 }
208 } else {
209 ScalarizedInlineArgsStream stream(sig, sig_index, regs_from, regs_from_count, from_index);
210 VMReg from_reg;
211 BasicType bt;
212 bool found = false;
213 while (stream.next(from_reg, bt)) {
214 reg = from_reg;
215 assert(from_reg->is_valid(), "must be");
216 if (reg_state[from_reg->value()] == reg_readonly) {
217 found = true;
218 break;
219 }
220 }
221 if (!found) {
222 // Spilling fields in this inline type arg won't break cycles
223 return true;
224 }
225 }
226
227 // Spill argument to be able to write the source and resolve circular dependencies
228 VMReg spill_reg = spill_reg_for(reg);
229 if (reg_state[spill_reg->value()] == reg_readonly) {
230 // We have already spilled (in previous round). The spilled register should be consumed by this round.
231 } else {
232 bool res = move_helper(reg, spill_reg, T_DOUBLE, reg_state);
233 assert(res, "Spilling should not fail");
234 // Set spill_reg as new source and update state
235 reg = spill_reg;
236 regs_from[from_index].set1(reg);
237 reg_state[reg->value()] = reg_readonly;
238 }
239
240 return false; // Do not spill again in this round
241 }