Path: blob/master/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp
40930 views
/*1* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2014, Red Hat Inc. 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 it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 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 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#include "precompiled.hpp"26#include "c1/c1_MacroAssembler.hpp"27#include "c1/c1_Runtime1.hpp"28#include "gc/shared/barrierSetAssembler.hpp"29#include "gc/shared/collectedHeap.hpp"30#include "gc/shared/tlab_globals.hpp"31#include "interpreter/interpreter.hpp"32#include "oops/arrayOop.hpp"33#include "oops/markWord.hpp"34#include "runtime/basicLock.hpp"35#include "runtime/biasedLocking.hpp"36#include "runtime/os.hpp"37#include "runtime/sharedRuntime.hpp"38#include "runtime/stubRoutines.hpp"3940void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result,41FloatRegister f0, FloatRegister f1,42Register result)43{44Label done;45if (is_float) {46fcmps(f0, f1);47} else {48fcmpd(f0, f1);49}50if (unordered_result < 0) {51// we want -1 for unordered or less than, 0 for equal and 1 for52// greater than.53cset(result, NE); // Not equal or unordered54cneg(result, result, LT); // Less than or unordered55} else {56// we want -1 for less than, 0 for equal and 1 for unordered or57// greater than.58cset(result, NE); // Not equal or unordered59cneg(result, result, LO); // Less than60}61}6263int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register scratch, Label& slow_case) {64const int aligned_mask = BytesPerWord -1;65const int hdr_offset = oopDesc::mark_offset_in_bytes();66assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different");67Label done;68int null_check_offset = -1;6970verify_oop(obj);7172// save object being locked into the BasicObjectLock73str(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));7475null_check_offset = offset();7677if (DiagnoseSyncOnValueBasedClasses != 0) {78load_klass(hdr, obj);79ldrw(hdr, Address(hdr, Klass::access_flags_offset()));80tstw(hdr, JVM_ACC_IS_VALUE_BASED_CLASS);81br(Assembler::NE, slow_case);82}8384if (UseBiasedLocking) {85assert(scratch != noreg, "should have scratch register at this point");86biased_locking_enter(disp_hdr, obj, hdr, scratch, false, done, &slow_case);87}8889// Load object header90ldr(hdr, Address(obj, hdr_offset));91// and mark it as unlocked92orr(hdr, hdr, markWord::unlocked_value);93// save unlocked object header into the displaced header location on the stack94str(hdr, Address(disp_hdr, 0));95// test if object header is still the same (i.e. unlocked), and if so, store the96// displaced header address in the object header - if it is not the same, get the97// object header instead98lea(rscratch2, Address(obj, hdr_offset));99cmpxchgptr(hdr, disp_hdr, rscratch2, rscratch1, done, /*fallthough*/NULL);100// if the object header was the same, we're done101// if the object header was not the same, it is now in the hdr register102// => test if it is a stack pointer into the same stack (recursive locking), i.e.:103//104// 1) (hdr & aligned_mask) == 0105// 2) sp <= hdr106// 3) hdr <= sp + page_size107//108// these 3 tests can be done by evaluating the following expression:109//110// (hdr - sp) & (aligned_mask - page_size)111//112// assuming both the stack pointer and page_size have their least113// significant 2 bits cleared and page_size is a power of 2114mov(rscratch1, sp);115sub(hdr, hdr, rscratch1);116ands(hdr, hdr, aligned_mask - os::vm_page_size());117// for recursive locking, the result is zero => save it in the displaced header118// location (NULL in the displaced hdr location indicates recursive locking)119str(hdr, Address(disp_hdr, 0));120// otherwise we don't care about the result and handle locking via runtime call121cbnz(hdr, slow_case);122// done123bind(done);124if (PrintBiasedLockingStatistics) {125lea(rscratch2, ExternalAddress((address)BiasedLocking::fast_path_entry_count_addr()));126addmw(Address(rscratch2, 0), 1, rscratch1);127}128return null_check_offset;129}130131132void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {133const int aligned_mask = BytesPerWord -1;134const int hdr_offset = oopDesc::mark_offset_in_bytes();135assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different");136Label done;137138if (UseBiasedLocking) {139// load object140ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));141biased_locking_exit(obj, hdr, done);142}143144// load displaced header145ldr(hdr, Address(disp_hdr, 0));146// if the loaded hdr is NULL we had recursive locking147// if we had recursive locking, we are done148cbz(hdr, done);149if (!UseBiasedLocking) {150// load object151ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));152}153verify_oop(obj);154// test if object header is pointing to the displaced header, and if so, restore155// the displaced header in the object - if the object header is not pointing to156// the displaced header, get the object header instead157// if the object header was not pointing to the displaced header,158// we do unlocking via runtime call159if (hdr_offset) {160lea(rscratch1, Address(obj, hdr_offset));161cmpxchgptr(disp_hdr, hdr, rscratch1, rscratch2, done, &slow_case);162} else {163cmpxchgptr(disp_hdr, hdr, obj, rscratch2, done, &slow_case);164}165// done166bind(done);167}168169170// Defines obj, preserves var_size_in_bytes171void C1_MacroAssembler::try_allocate(Register obj, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2, Label& slow_case) {172if (UseTLAB) {173tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case);174} else {175eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case);176}177}178179void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) {180assert_different_registers(obj, klass, len);181if (UseBiasedLocking && !len->is_valid()) {182assert_different_registers(obj, klass, len, t1, t2);183ldr(t1, Address(klass, Klass::prototype_header_offset()));184} else {185// This assumes that all prototype bits fit in an int32_t186mov(t1, (int32_t)(intptr_t)markWord::prototype().value());187}188str(t1, Address(obj, oopDesc::mark_offset_in_bytes()));189190if (UseCompressedClassPointers) { // Take care not to kill klass191encode_klass_not_null(t1, klass);192strw(t1, Address(obj, oopDesc::klass_offset_in_bytes()));193} else {194str(klass, Address(obj, oopDesc::klass_offset_in_bytes()));195}196197if (len->is_valid()) {198strw(len, Address(obj, arrayOopDesc::length_offset_in_bytes()));199} else if (UseCompressedClassPointers) {200store_klass_gap(obj, zr);201}202}203204// preserves obj, destroys len_in_bytes205void C1_MacroAssembler::initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register t1) {206assert(hdr_size_in_bytes >= 0, "header size must be positive or 0");207Label done;208209// len_in_bytes is positive and ptr sized210subs(len_in_bytes, len_in_bytes, hdr_size_in_bytes);211br(Assembler::EQ, done);212213// Preserve obj214if (hdr_size_in_bytes)215add(obj, obj, hdr_size_in_bytes);216zero_memory(obj, len_in_bytes, t1);217if (hdr_size_in_bytes)218sub(obj, obj, hdr_size_in_bytes);219220bind(done);221}222223224void C1_MacroAssembler::allocate_object(Register obj, Register t1, Register t2, int header_size, int object_size, Register klass, Label& slow_case) {225assert_different_registers(obj, t1, t2); // XXX really?226assert(header_size >= 0 && object_size >= header_size, "illegal sizes");227228try_allocate(obj, noreg, object_size * BytesPerWord, t1, t2, slow_case);229230initialize_object(obj, klass, noreg, object_size * HeapWordSize, t1, t2, UseTLAB);231}232233void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2, bool is_tlab_allocated) {234assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0,235"con_size_in_bytes is not multiple of alignment");236const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize;237238initialize_header(obj, klass, noreg, t1, t2);239240if (!(UseTLAB && ZeroTLAB && is_tlab_allocated)) {241// clear rest of allocated space242const Register index = t2;243const int threshold = 16 * BytesPerWord; // approximate break even point for code size (see comments below)244if (var_size_in_bytes != noreg) {245mov(index, var_size_in_bytes);246initialize_body(obj, index, hdr_size_in_bytes, t1);247} else if (con_size_in_bytes <= threshold) {248// use explicit null stores249int i = hdr_size_in_bytes;250if (i < con_size_in_bytes && (con_size_in_bytes % (2 * BytesPerWord))) {251str(zr, Address(obj, i));252i += BytesPerWord;253}254for (; i < con_size_in_bytes; i += 2 * BytesPerWord)255stp(zr, zr, Address(obj, i));256} else if (con_size_in_bytes > hdr_size_in_bytes) {257block_comment("zero memory");258// use loop to null out the fields259260int words = (con_size_in_bytes - hdr_size_in_bytes) / BytesPerWord;261mov(index, words / 8);262263const int unroll = 8; // Number of str(zr) instructions we'll unroll264int remainder = words % unroll;265lea(rscratch1, Address(obj, hdr_size_in_bytes + remainder * BytesPerWord));266267Label entry_point, loop;268b(entry_point);269270bind(loop);271sub(index, index, 1);272for (int i = -unroll; i < 0; i++) {273if (-i == remainder)274bind(entry_point);275str(zr, Address(rscratch1, i * wordSize));276}277if (remainder == 0)278bind(entry_point);279add(rscratch1, rscratch1, unroll * wordSize);280cbnz(index, loop);281282}283}284285membar(StoreStore);286287if (CURRENT_ENV->dtrace_alloc_probes()) {288assert(obj == r0, "must be");289far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));290}291292verify_oop(obj);293}294void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1, Register t2, int header_size, int f, Register klass, Label& slow_case) {295assert_different_registers(obj, len, t1, t2, klass);296297// determine alignment mask298assert(!(BytesPerWord & 1), "must be a multiple of 2 for masking code to work");299300// check for negative or excessive length301mov(rscratch1, (int32_t)max_array_allocation_length);302cmp(len, rscratch1);303br(Assembler::HS, slow_case);304305const Register arr_size = t2; // okay to be the same306// align object end307mov(arr_size, (int32_t)header_size * BytesPerWord + MinObjAlignmentInBytesMask);308add(arr_size, arr_size, len, ext::uxtw, f);309andr(arr_size, arr_size, ~MinObjAlignmentInBytesMask);310311try_allocate(obj, arr_size, 0, t1, t2, slow_case);312313initialize_header(obj, klass, len, t1, t2);314315// clear rest of allocated space316const Register len_zero = len;317initialize_body(obj, arr_size, header_size * BytesPerWord, len_zero);318319membar(StoreStore);320321if (CURRENT_ENV->dtrace_alloc_probes()) {322assert(obj == r0, "must be");323far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));324}325326verify_oop(obj);327}328329330void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) {331verify_oop(receiver);332// explicit NULL check not needed since load from [klass_offset] causes a trap333// check against inline cache334assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()), "must add explicit null check");335336cmp_klass(receiver, iCache, rscratch1);337}338339340void C1_MacroAssembler::build_frame(int framesize, int bang_size_in_bytes) {341assert(bang_size_in_bytes >= framesize, "stack bang size incorrect");342// Make sure there is enough stack space for this method's activation.343// Note that we do this before creating a frame.344generate_stack_overflow_check(bang_size_in_bytes);345MacroAssembler::build_frame(framesize);346347// Insert nmethod entry barrier into frame.348BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();349bs->nmethod_entry_barrier(this);350}351352void C1_MacroAssembler::remove_frame(int framesize) {353MacroAssembler::remove_frame(framesize);354}355356357void C1_MacroAssembler::verified_entry() {358// If we have to make this method not-entrant we'll overwrite its359// first instruction with a jump. For this action to be legal we360// must ensure that this first instruction is a B, BL, NOP, BKPT,361// SVC, HVC, or SMC. Make it a NOP.362nop();363}364365void C1_MacroAssembler::load_parameter(int offset_in_words, Register reg) {366// rbp, + 0: link367// + 1: return address368// + 2: argument with offset 0369// + 3: argument with offset 1370// + 4: ...371372ldr(reg, Address(rfp, (offset_in_words + 2) * BytesPerWord));373}374375#ifndef PRODUCT376377void C1_MacroAssembler::verify_stack_oop(int stack_offset) {378if (!VerifyOops) return;379verify_oop_addr(Address(sp, stack_offset), "oop");380}381382void C1_MacroAssembler::verify_not_null_oop(Register r) {383if (!VerifyOops) return;384Label not_null;385cbnz(r, not_null);386stop("non-null oop required");387bind(not_null);388verify_oop(r);389}390391void C1_MacroAssembler::invalidate_registers(bool inv_r0, bool inv_r19, bool inv_r2, bool inv_r3, bool inv_r4, bool inv_r5) {392#ifdef ASSERT393static int nn;394if (inv_r0) mov(r0, 0xDEAD);395if (inv_r19) mov(r19, 0xDEAD);396if (inv_r2) mov(r2, nn++);397if (inv_r3) mov(r3, 0xDEAD);398if (inv_r4) mov(r4, 0xDEAD);399if (inv_r5) mov(r5, 0xDEAD);400#endif401}402#endif // ifndef PRODUCT403404405