Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.cpp
32285 views
/*1* Copyright (c) 2013, Red Hat Inc.2* Copyright (c) 1999, 2011, Oracle and/or its affiliates.3* 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 it7* under the terms of the GNU General Public License version 2 only, as8* published by the Free Software Foundation.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 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 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*24*/2526#include "precompiled.hpp"27#include "c1/c1_MacroAssembler.hpp"28#include "c1/c1_Runtime1.hpp"29#include "classfile/systemDictionary.hpp"30#include "gc_interface/collectedHeap.hpp"31#include "interpreter/interpreter.hpp"32#include "oops/arrayOop.hpp"33#include "oops/markOop.hpp"34#include "runtime/basicLock.hpp"35#include "runtime/biasedLocking.hpp"36#include "runtime/os.hpp"37#include "runtime/stubRoutines.hpp"3839void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result,40FloatRegister f0, FloatRegister f1,41Register result)42{43Label done;44if (is_float) {45fcmps(f0, f1);46} else {47fcmpd(f0, f1);48}49if (unordered_result < 0) {50// we want -1 for unordered or less than, 0 for equal and 1 for51// greater than.52cset(result, NE); // Not equal or unordered53cneg(result, result, LT); // Less than or unordered54} else {55// we want -1 for less than, 0 for equal and 1 for unordered or56// greater than.57cset(result, NE); // Not equal or unordered58cneg(result, result, LO); // Less than59}60}6162int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register scratch, Label& slow_case) {63const int aligned_mask = BytesPerWord -1;64const int hdr_offset = oopDesc::mark_offset_in_bytes();65assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different");66Label done, fail;67int null_check_offset = -1;6869verify_oop(obj);7071// save object being locked into the BasicObjectLock72str(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));7374if (UseBiasedLocking) {75assert(scratch != noreg, "should have scratch register at this point");76null_check_offset = biased_locking_enter(disp_hdr, obj, hdr, scratch, false, done, &slow_case);77} else {78null_check_offset = offset();79}8081// Load object header82ldr(hdr, Address(obj, hdr_offset));83// and mark it as unlocked84orr(hdr, hdr, markOopDesc::unlocked_value);85// save unlocked object header into the displaced header location on the stack86str(hdr, Address(disp_hdr, 0));87// test if object header is still the same (i.e. unlocked), and if so, store the88// displaced header address in the object header - if it is not the same, get the89// object header instead90lea(rscratch2, Address(obj, hdr_offset));91cmpxchgptr(hdr, disp_hdr, rscratch2, rscratch1, done, /*fallthough*/NULL);92// if the object header was the same, we're done93// if the object header was not the same, it is now in the hdr register94// => test if it is a stack pointer into the same stack (recursive locking), i.e.:95//96// 1) (hdr & aligned_mask) == 097// 2) sp <= hdr98// 3) hdr <= sp + page_size99//100// these 3 tests can be done by evaluating the following expression:101//102// (hdr - sp) & (aligned_mask - page_size)103//104// assuming both the stack pointer and page_size have their least105// significant 2 bits cleared and page_size is a power of 2106mov(rscratch1, sp);107sub(hdr, hdr, rscratch1);108ands(hdr, hdr, aligned_mask - os::vm_page_size());109// for recursive locking, the result is zero => save it in the displaced header110// location (NULL in the displaced hdr location indicates recursive locking)111str(hdr, Address(disp_hdr, 0));112// otherwise we don't care about the result and handle locking via runtime call113cbnz(hdr, slow_case);114// done115bind(done);116if (PrintBiasedLockingStatistics) {117lea(rscratch2, ExternalAddress((address)BiasedLocking::fast_path_entry_count_addr()));118addmw(Address(rscratch2, 0), 1, rscratch1);119}120return null_check_offset;121}122123124void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {125const int aligned_mask = BytesPerWord -1;126const int hdr_offset = oopDesc::mark_offset_in_bytes();127assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different");128Label done;129130if (UseBiasedLocking) {131// load object132ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));133biased_locking_exit(obj, hdr, done);134}135136// load displaced header137ldr(hdr, Address(disp_hdr, 0));138// if the loaded hdr is NULL we had recursive locking139// if we had recursive locking, we are done140cbz(hdr, done);141if (!UseBiasedLocking) {142// load object143ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));144}145verify_oop(obj);146// test if object header is pointing to the displaced header, and if so, restore147// the displaced header in the object - if the object header is not pointing to148// the displaced header, get the object header instead149// if the object header was not pointing to the displaced header,150// we do unlocking via runtime call151if (hdr_offset) {152lea(rscratch1, Address(obj, hdr_offset));153cmpxchgptr(disp_hdr, hdr, rscratch1, rscratch2, done, &slow_case);154} else {155cmpxchgptr(disp_hdr, hdr, obj, rscratch2, done, &slow_case);156}157// done158bind(done);159}160161162// Defines obj, preserves var_size_in_bytes163void C1_MacroAssembler::try_allocate(Register obj, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2, Label& slow_case) {164if (UseTLAB) {165tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case);166} else {167eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case);168incr_allocated_bytes(noreg, var_size_in_bytes, con_size_in_bytes, t1);169}170}171172void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) {173assert_different_registers(obj, klass, len);174if (UseBiasedLocking && !len->is_valid()) {175assert_different_registers(obj, klass, len, t1, t2);176ldr(t1, Address(klass, Klass::prototype_header_offset()));177} else {178// This assumes that all prototype bits fit in an int32_t179mov(t1, (int32_t)(intptr_t)markOopDesc::prototype());180}181str(t1, Address(obj, oopDesc::mark_offset_in_bytes()));182183if (UseCompressedClassPointers) { // Take care not to kill klass184encode_klass_not_null(t1, klass);185strw(t1, Address(obj, oopDesc::klass_offset_in_bytes()));186} else {187str(klass, Address(obj, oopDesc::klass_offset_in_bytes()));188}189190if (len->is_valid()) {191strw(len, Address(obj, arrayOopDesc::length_offset_in_bytes()));192} else if (UseCompressedClassPointers) {193store_klass_gap(obj, zr);194}195}196197// Zero words; len is in bytes198// Destroys all registers except addr199// len must be a nonzero multiple of wordSize200void C1_MacroAssembler::zero_memory(Register addr, Register len, Register t1) {201assert_different_registers(addr, len, t1, rscratch1, rscratch2);202203#ifdef ASSERT204{ Label L;205tst(len, BytesPerWord - 1);206br(Assembler::EQ, L);207stop("len is not a multiple of BytesPerWord");208bind(L);209}210#endif211212#ifndef PRODUCT213block_comment("zero memory");214#endif215216Label loop;217Label entry;218219// Algorithm:220//221// scratch1 = cnt & 7;222// cnt -= scratch1;223// p += scratch1;224// switch (scratch1) {225// do {226// cnt -= 8;227// p[-8] = 0;228// case 7:229// p[-7] = 0;230// case 6:231// p[-6] = 0;232// // ...233// case 1:234// p[-1] = 0;235// case 0:236// p += 8;237// } while (cnt);238// }239240const int unroll = 8; // Number of str(zr) instructions we'll unroll241242lsr(len, len, LogBytesPerWord);243andr(rscratch1, len, unroll - 1); // tmp1 = cnt % unroll244sub(len, len, rscratch1); // cnt -= unroll245// t1 always points to the end of the region we're about to zero246add(t1, addr, rscratch1, Assembler::LSL, LogBytesPerWord);247adr(rscratch2, entry);248sub(rscratch2, rscratch2, rscratch1, Assembler::LSL, 2);249br(rscratch2);250bind(loop);251sub(len, len, unroll);252for (int i = -unroll; i < 0; i++)253str(zr, Address(t1, i * wordSize));254bind(entry);255add(t1, t1, unroll * wordSize);256cbnz(len, loop);257}258259// preserves obj, destroys len_in_bytes260void C1_MacroAssembler::initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register t1) {261Label done;262assert(obj != len_in_bytes && obj != t1 && t1 != len_in_bytes, "registers must be different");263assert((hdr_size_in_bytes & (BytesPerWord - 1)) == 0, "header size is not a multiple of BytesPerWord");264Register index = len_in_bytes;265// index is positive and ptr sized266subs(index, index, hdr_size_in_bytes);267br(Assembler::EQ, done);268// note: for the remaining code to work, index must be a multiple of BytesPerWord269#ifdef ASSERT270{ Label L;271tst(index, BytesPerWord - 1);272br(Assembler::EQ, L);273stop("index is not a multiple of BytesPerWord");274bind(L);275}276#endif277278// Preserve obj279if (hdr_size_in_bytes)280add(obj, obj, hdr_size_in_bytes);281zero_memory(obj, index, t1);282if (hdr_size_in_bytes)283sub(obj, obj, hdr_size_in_bytes);284285// done286bind(done);287}288289290void C1_MacroAssembler::allocate_object(Register obj, Register t1, Register t2, int header_size, int object_size, Register klass, Label& slow_case) {291assert_different_registers(obj, t1, t2); // XXX really?292assert(header_size >= 0 && object_size >= header_size, "illegal sizes");293294try_allocate(obj, noreg, object_size * BytesPerWord, t1, t2, slow_case);295296initialize_object(obj, klass, noreg, object_size * HeapWordSize, t1, t2);297}298299void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2) {300assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0,301"con_size_in_bytes is not multiple of alignment");302const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize;303304initialize_header(obj, klass, noreg, t1, t2);305306// clear rest of allocated space307const Register index = t2;308const int threshold = 16 * BytesPerWord; // approximate break even point for code size (see comments below)309if (var_size_in_bytes != noreg) {310mov(index, var_size_in_bytes);311initialize_body(obj, index, hdr_size_in_bytes, t1);312} else if (con_size_in_bytes <= threshold) {313// use explicit null stores314int i = hdr_size_in_bytes;315if (i < con_size_in_bytes && (con_size_in_bytes % (2 * BytesPerWord))) {316str(zr, Address(obj, i));317i += BytesPerWord;318}319for (; i < con_size_in_bytes; i += 2 * BytesPerWord)320stp(zr, zr, Address(obj, i));321} else if (con_size_in_bytes > hdr_size_in_bytes) {322block_comment("zero memory");323// use loop to null out the fields324325int words = (con_size_in_bytes - hdr_size_in_bytes) / BytesPerWord;326mov(index, words / 8);327328const int unroll = 8; // Number of str(zr) instructions we'll unroll329int remainder = words % unroll;330lea(rscratch1, Address(obj, hdr_size_in_bytes + remainder * BytesPerWord));331332Label entry_point, loop;333b(entry_point);334335bind(loop);336sub(index, index, 1);337for (int i = -unroll; i < 0; i++) {338if (-i == remainder)339bind(entry_point);340str(zr, Address(rscratch1, i * wordSize));341}342if (remainder == 0)343bind(entry_point);344add(rscratch1, rscratch1, unroll * wordSize);345cbnz(index, loop);346347}348349membar(StoreStore);350351if (CURRENT_ENV->dtrace_alloc_probes()) {352assert(obj == r0, "must be");353far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));354}355356verify_oop(obj);357}358void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1, Register t2, int header_size, int f, Register klass, Label& slow_case) {359assert_different_registers(obj, len, t1, t2, klass);360361// determine alignment mask362assert(!(BytesPerWord & 1), "must be a multiple of 2 for masking code to work");363364// check for negative or excessive length365mov(rscratch1, (int32_t)max_array_allocation_length);366cmp(len, rscratch1);367br(Assembler::HS, slow_case);368369const Register arr_size = t2; // okay to be the same370// align object end371mov(arr_size, (int32_t)header_size * BytesPerWord + MinObjAlignmentInBytesMask);372add(arr_size, arr_size, len, ext::uxtw, f);373andr(arr_size, arr_size, ~MinObjAlignmentInBytesMask);374375try_allocate(obj, arr_size, 0, t1, t2, slow_case);376377initialize_header(obj, klass, len, t1, t2);378379// clear rest of allocated space380const Register len_zero = len;381initialize_body(obj, arr_size, header_size * BytesPerWord, len_zero);382383membar(StoreStore);384385if (CURRENT_ENV->dtrace_alloc_probes()) {386assert(obj == r0, "must be");387far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));388}389390verify_oop(obj);391}392393394void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) {395verify_oop(receiver);396// explicit NULL check not needed since load from [klass_offset] causes a trap397// check against inline cache398assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()), "must add explicit null check");399400cmp_klass(receiver, iCache, rscratch1);401}402403404void C1_MacroAssembler::build_frame(int framesize, int bang_size_in_bytes) {405// If we have to make this method not-entrant we'll overwrite its406// first instruction with a jump. For this action to be legal we407// must ensure that this first instruction is a B, BL, NOP, BKPT,408// SVC, HVC, or SMC. Make it a NOP.409nop();410assert(bang_size_in_bytes >= framesize, "stack bang size incorrect");411// Make sure there is enough stack space for this method's activation.412// Note that we do this before doing an enter().413generate_stack_overflow_check(bang_size_in_bytes);414MacroAssembler::build_frame(framesize + 2 * wordSize);415}416417void C1_MacroAssembler::remove_frame(int framesize) {418MacroAssembler::remove_frame(framesize + 2 * wordSize);419}420421422void C1_MacroAssembler::verified_entry() {423}424425#ifndef PRODUCT426427void C1_MacroAssembler::verify_stack_oop(int stack_offset) {428if (!VerifyOops) return;429verify_oop_addr(Address(sp, stack_offset), "oop");430}431432void C1_MacroAssembler::verify_not_null_oop(Register r) {433if (!VerifyOops) return;434Label not_null;435cbnz(r, not_null);436stop("non-null oop required");437bind(not_null);438verify_oop(r);439}440441void C1_MacroAssembler::invalidate_registers(bool inv_r0, bool inv_r19, bool inv_r2, bool inv_r3, bool inv_r4, bool inv_r5) {442#ifdef ASSERT443static int nn;444if (inv_r0) mov(r0, 0xDEAD);445if (inv_r19) mov(r19, 0xDEAD);446if (inv_r2) mov(r2, nn++);447if (inv_r3) mov(r3, 0xDEAD);448if (inv_r4) mov(r4, 0xDEAD);449if (inv_r5) mov(r5, 0xDEAD);450#endif451}452#endif // ifndef PRODUCT453454455