1 /*
2 * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2012, 2026 SAP SE. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #include "asm/macroAssembler.inline.hpp"
27 #include "c1/c1_MacroAssembler.hpp"
28 #include "c1/c1_Runtime1.hpp"
29 #include "gc/shared/collectedHeap.hpp"
30 #include "gc/shared/barrierSet.hpp"
31 #include "gc/shared/barrierSetAssembler.hpp"
32 #include "gc/shared/tlab_globals.hpp"
33 #include "interpreter/interpreter.hpp"
34 #include "oops/arrayOop.hpp"
35 #include "oops/markWord.hpp"
36 #include "runtime/arguments.hpp"
37 #include "runtime/basicLock.hpp"
38 #include "runtime/os.hpp"
39 #include "runtime/sharedRuntime.hpp"
40 #include "runtime/stubRoutines.hpp"
41 #include "utilities/align.hpp"
42 #include "utilities/macros.hpp"
43 #include "utilities/powerOfTwo.hpp"
44
45
46 void C1_MacroAssembler::explicit_null_check(Register base) {
47 Unimplemented();
48 }
49
50
51 void C1_MacroAssembler::build_frame_helper(int frame_size_in_bytes, int sp_offset_for_orig_pc, int sp_inc, bool reset_orig_pc, bool needs_stack_repair) {
52 const Register return_pc = R20;
53 mflr(return_pc);
54 std(return_pc, _abi0(lr), R1_SP); // SP->lr = return_pc
55 push_frame(frame_size_in_bytes, R0); // SP -= frame_size_in_bytes
56
57 if (needs_stack_repair) {
58 // Save stack increment (also account for fixed framesize and rbp)
59 Unimplemented();
60 }
61 if (reset_orig_pc) {
62 // Zero orig_pc to detect deoptimization during buffering in the entry points
63 li(R0, 0);
64 untested("build_frame_helper reset_orig_pc");
65 std(R0, sp_offset_for_orig_pc, R1_SP);
66 }
67 }
68
69
70 void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes,
71 int sp_offset_for_orig_pc,
72 bool needs_stack_repair, bool has_scalarized_args,
73 Label* verified_inline_entry_label) {
74 // Make sure there is enough stack space for this method's activation.
75 assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect");
76 generate_stack_overflow_check(bang_size_in_bytes);
77
78 build_frame_helper(frame_size_in_bytes, sp_offset_for_orig_pc, 0, has_scalarized_args, needs_stack_repair);
79
80 BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
81 bs->nmethod_entry_barrier(this, R20);
82
83 if (verified_inline_entry_label != nullptr) {
84 // Jump here from the scalarized entry points that already created the frame.
85 bind(*verified_inline_entry_label);
86 }
87 }
88
89
90 void C1_MacroAssembler::verified_entry(bool breakAtEntry) {
91 if (breakAtEntry) illtrap();
92 // build frame
93 }
94
95
96 void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox, Register Rscratch, Label& slow_case) {
97 assert_different_registers(Rmark, Roop, Rbox, Rscratch);
98
99 Label done, cas_failed, slow_int;
100
101 // The following move must be the first instruction of emitted since debug
102 // information may be generated for it.
103 // Load object header.
104 ld(Rmark, oopDesc::mark_offset_in_bytes(), Roop);
105
106 verify_oop(Roop, FILE_AND_LINE);
107
108 // Save object being locked into the BasicObjectLock...
109 std(Roop, in_bytes(BasicObjectLock::obj_offset()), Rbox);
110
111 fast_lock(Rbox, Roop, Rmark, Rscratch, slow_int);
112 b(done);
113
114 bind(slow_int);
115 b(slow_case); // far
116
117 bind(done);
118 }
119
120
121 void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case) {
122 assert_different_registers(Rmark, Roop, Rbox);
123
124 Label slow_int, done;
125
126 Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
127 assert(mark_addr.disp() == 0, "cas must take a zero displacement");
128
129 // Load object.
130 ld(Roop, in_bytes(BasicObjectLock::obj_offset()), Rbox);
131 verify_oop(Roop, FILE_AND_LINE);
132
133 fast_unlock(Roop, Rmark, slow_int);
134 b(done);
135 bind(slow_int);
136 b(slow_case); // far
137
138 // Done
139 bind(done);
140 }
141
142
143 void C1_MacroAssembler::try_allocate(
144 Register obj, // result: pointer to object after successful allocation
145 Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
146 int con_size_in_bytes, // object size in bytes if known at compile time
147 Register t1, // temp register
148 Register t2, // temp register
149 Label& slow_case // continuation point if fast allocation fails
150 ) {
151 if (UseTLAB) {
152 tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case);
153 } else {
154 b(slow_case);
155 }
156 }
157
158
159 void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) {
160 assert_different_registers(obj, klass, len, t1, t2);
161
162 if (UseCompactObjectHeaders || Arguments::is_valhalla_enabled()) {
163 // COH: Markword contains class pointer which is only known at runtime.
164 // Valhalla: Could have value class which has a different prototype header to a normal object.
165 // In both cases, we need to fetch dynamically.
166 ld(t1, in_bytes(Klass::prototype_header_offset()), klass);
167 } else {
168 // Otherwise: Can use the statically computed prototype header which is the same for every object.
169 load_const_optimized(t1, (intx)markWord::prototype().value());
170 }
171 std(t1, oopDesc::mark_offset_in_bytes(), obj);
172
173 if (!UseCompactObjectHeaders) {
174 // COH: Markword already contains class pointer. Nothing else to do.
175 // Otherwise: Store encoded klass pointer following the markword
176 store_klass(obj, klass);
177 }
178
179 if (len->is_valid()) {
180 stw(len, arrayOopDesc::length_offset_in_bytes(), obj);
181 } else if (!UseCompactObjectHeaders) {
182 // Otherwise length is in the class gap.
183 store_klass_gap(obj);
184 }
185 }
186
187
188 void C1_MacroAssembler::initialize_body(Register base, Register index) {
189 assert_different_registers(base, index);
190 srdi(index, index, LogBytesPerWord);
191 clear_memory_doubleword(base, index);
192 }
193
194 void C1_MacroAssembler::initialize_body(Register obj, Register tmp1, Register tmp2,
195 int obj_size_in_bytes, int hdr_size_in_bytes) {
196 const int index = (obj_size_in_bytes - hdr_size_in_bytes) / HeapWordSize;
197
198 // 2x unrolled loop is shorter with more than 9 HeapWords.
199 if (index <= 9) {
200 clear_memory_unrolled(obj, index, R0, hdr_size_in_bytes);
201 } else {
202 const Register base_ptr = tmp1,
203 cnt_dwords = tmp2;
204
205 addi(base_ptr, obj, hdr_size_in_bytes); // Compute address of first element.
206 clear_memory_doubleword(base_ptr, cnt_dwords, R0, index);
207 }
208 }
209
210 void C1_MacroAssembler::allocate_object(
211 Register obj, // result: pointer to object after successful allocation
212 Register t1, // temp register
213 Register t2, // temp register
214 Register t3, // temp register
215 int hdr_size, // object header size in words
216 int obj_size, // object size in words
217 Register klass, // object klass
218 Label& slow_case // continuation point if fast allocation fails
219 ) {
220 assert_different_registers(obj, t1, t2, t3, klass);
221
222 // allocate space & initialize header
223 if (!is_simm16(obj_size * wordSize)) {
224 // Would need to use extra register to load
225 // object size => go the slow case for now.
226 b(slow_case);
227 return;
228 }
229 try_allocate(obj, noreg, obj_size * wordSize, t2, t3, slow_case);
230
231 initialize_object(obj, klass, noreg, obj_size * HeapWordSize, t1, t2);
232 }
233
234 void C1_MacroAssembler::initialize_object(
235 Register obj, // result: pointer to object after successful allocation
236 Register klass, // object klass
237 Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
238 int con_size_in_bytes, // object size in bytes if known at compile time
239 Register t1, // temp register
240 Register t2 // temp register
241 ) {
242 const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize;
243
244 initialize_header(obj, klass, noreg, t1, t2);
245
246 #ifdef ASSERT
247 {
248 lwz(t1, in_bytes(Klass::layout_helper_offset()), klass);
249 if (var_size_in_bytes != noreg) {
250 cmpw(CR0, t1, var_size_in_bytes);
251 } else {
252 cmpwi(CR0, t1, con_size_in_bytes);
253 }
254 asm_assert_eq("bad size in initialize_object");
255 }
256 #endif
257
258 // Initialize body.
259 if (var_size_in_bytes != noreg) {
260 // Use a loop.
261 addi(t1, obj, hdr_size_in_bytes); // Compute address of first element.
262 addi(t2, var_size_in_bytes, -hdr_size_in_bytes); // Compute size of body.
263 initialize_body(t1, t2);
264 } else if (con_size_in_bytes > hdr_size_in_bytes) {
265 // Use a loop.
266 initialize_body(obj, t1, t2, con_size_in_bytes, hdr_size_in_bytes);
267 }
268
269 verify_oop(obj, FILE_AND_LINE);
270 }
271
272
273 void C1_MacroAssembler::allocate_array(
274 Register obj, // result: pointer to array after successful allocation
275 Register len, // array length
276 Register t1, // temp register
277 Register t2, // temp register
278 Register t3, // temp register
279 int base_offset_in_bytes, // elements offset in bytes
280 int elt_size, // element size in bytes
281 Register klass, // object klass
282 Label& slow_case, // continuation point if fast allocation fails
283 bool zero_array // zero the allocated array or not
284 ) {
285 assert_different_registers(obj, len, t1, t2, t3, klass);
286
287 // Determine alignment mask.
288 assert(!(BytesPerWord & 1), "must be a multiple of 2 for masking code to work");
289 int log2_elt_size = exact_log2(elt_size);
290
291 // Check for negative or excessive length.
292 size_t max_length = max_array_allocation_length >> log2_elt_size;
293 if (UseTLAB) {
294 size_t max_tlab = align_up(ThreadLocalAllocBuffer::max_size() >> log2_elt_size, 64*K);
295 if (max_tlab < max_length) { max_length = max_tlab; }
296 }
297 load_const_optimized(t1, max_length);
298 cmpld(CR0, len, t1);
299 bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CR0, Assembler::greater), slow_case);
300
301 // compute array size
302 // note: If 0 <= len <= max_length, len*elt_size + header + alignment is
303 // smaller or equal to the largest integer; also, since top is always
304 // aligned, we can do the alignment here instead of at the end address
305 // computation.
306 const Register arr_size = t1;
307 Register arr_len_in_bytes = len;
308 if (elt_size != 1) {
309 sldi(t1, len, log2_elt_size);
310 arr_len_in_bytes = t1;
311 }
312 addi(arr_size, arr_len_in_bytes, base_offset_in_bytes + MinObjAlignmentInBytesMask); // Add space for header & alignment.
313 clrrdi(arr_size, arr_size, LogMinObjAlignmentInBytes); // Align array size.
314
315 // Allocate space & initialize header.
316 try_allocate(obj, arr_size, 0, t2, t3, slow_case);
317 initialize_header(obj, klass, len, t2, t3);
318
319 if (zero_array) {
320 // Initialize body.
321 const Register base = t2;
322 const Register index = t3;
323 addi(base, obj, base_offset_in_bytes); // compute address of first element
324 addi(index, arr_size, -(base_offset_in_bytes)); // compute index = number of bytes to clear
325
326 // Zero first 4 bytes, if start offset is not word aligned.
327 if (!is_aligned(base_offset_in_bytes, BytesPerWord)) {
328 assert(is_aligned(base_offset_in_bytes, BytesPerInt), "must be 4-byte aligned");
329 li(t1, 0);
330 stw(t1, 0, base);
331 addi(base, base, BytesPerInt);
332 // Note: initialize_body will align index down, no need to correct it here.
333 }
334
335 initialize_body(base, index);
336 }
337
338 verify_oop(obj, FILE_AND_LINE);
339 }
340
341
342 #ifndef PRODUCT
343
344 void C1_MacroAssembler::verify_stack_oop(int stack_offset) {
345 verify_oop_addr((RegisterOrConstant)stack_offset, R1_SP, "broken oop in stack slot");
346 }
347
348 void C1_MacroAssembler::verify_not_null_oop(Register r) {
349 Label not_null;
350 cmpdi(CR0, r, 0);
351 bne(CR0, not_null);
352 stop("non-null oop required");
353 bind(not_null);
354 verify_oop(r, FILE_AND_LINE);
355 }
356
357 #endif // PRODUCT
358
359 void C1_MacroAssembler::null_check(Register r, Label* Lnull) {
360 if (TrapBasedNullChecks) { // SIGTRAP based
361 trap_null_check(r);
362 } else { // explicit
363 //const address exception_entry = Runtime1::entry_for(StubId::c1_throw_null_pointer_exception_id);
364 assert(Lnull != nullptr, "must have Label for explicit check");
365 cmpdi(CR0, r, 0);
366 bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CR0, Assembler::equal), *Lnull);
367 }
368 }
369
370 int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_inline_entry_label, bool is_inline_ro_entry) {
371 Unimplemented();
372 }
373