--- /dev/null 2016-08-24 15:41:39.598575000 -0400 +++ new/hotspot/src/cpu/arm/vm/nativeInst_arm_64.cpp 2016-12-02 11:22:38.000266619 -0500 @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "assembler_arm.inline.hpp" +#include "code/codeCache.hpp" +#include "memory/resourceArea.hpp" +#include "nativeInst_arm.hpp" +#include "oops/klass.inline.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/handles.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "utilities/ostream.hpp" +#ifdef COMPILER1 +#include "c1/c1_Runtime1.hpp" +#endif + +void RawNativeInstruction::verify() { + // make sure code pattern is actually an instruction address + address addr = instruction_address(); + if (addr == NULL || ((intptr_t)addr & (instruction_size - 1)) != 0) { + fatal("not an instruction address"); + } +} + +void NativeMovRegMem::set_offset(int x) { + int scale = get_offset_scale(); + assert((x & right_n_bits(scale)) == 0, "offset should be aligned"); + guarantee((x >> 24) == 0, "encoding constraint"); + + if (Assembler::is_unsigned_imm_in_range(x, 12, scale)) { + set_unsigned_imm(x, 12, get_offset_scale(), 10); + return; + } + + // If offset is too large to be placed into single ldr/str instruction, we replace + // ldr/str Rt, [Rn, #offset] + // nop + // with + // add LR, Rn, #offset_hi + // ldr/str Rt, [LR, #offset_lo] + + // Note: Rtemp cannot be used as a temporary register as it could be used + // for value being stored (see LIR_Assembler::reg2mem). + // Patchable NativeMovRegMem instructions are generated in LIR_Assembler::mem2reg and LIR_Assembler::reg2mem + // which do not use LR, so it is free. Also, it does not conflict with LR usages in c1_LIRGenerator_arm.cpp. + const int tmp = LR->encoding(); + const int rn = (encoding() >> 5) & 0x1f; + + NativeInstruction* next = nativeInstruction_at(next_raw_instruction_address()); + assert(next->is_nop(), "must be"); + + next->set_encoding((encoding() & 0xffc0001f) | Assembler::encode_unsigned_imm((x & 0xfff), 12, scale, 10) | tmp << 5); + this->set_encoding(0x91400000 | Assembler::encode_unsigned_imm((x >> 12), 12, 0, 10) | rn << 5 | tmp); +} + +intptr_t NativeMovConstReg::_data() const { +#ifdef COMPILER2 + if (is_movz()) { + // narrow constant or ic call cached value + RawNativeInstruction* ni = next_raw(); + assert(ni->is_movk(), "movz;movk expected"); + uint lo16 = (encoding() >> 5) & 0xffff; + intptr_t hi = 0; + int i = 0; + while (ni->is_movk() && i < 3) { + uint hi16 = (ni->encoding() >> 5) & 0xffff; + int shift = ((ni->encoding() >> 21) & 0x3) << 4; + hi |= (intptr_t)hi16 << shift; + ni = ni->next_raw(); + ++i; + } + return lo16 | hi; + } +#endif + return (intptr_t)(nativeLdrLiteral_at(instruction_address())->literal_value()); +} + +static void raw_set_data(RawNativeInstruction* si, intptr_t x, oop* oop_addr, Metadata** metadata_addr) { +#ifdef COMPILER2 + if (si->is_movz()) { + // narrow constant or ic call cached value + uintptr_t nx = 0; + int val_size = 32; + if (oop_addr != NULL) { + narrowOop encoded_oop = oopDesc::encode_heap_oop(*oop_addr); + nx = encoded_oop; + } else if (metadata_addr != NULL) { + assert((*metadata_addr)->is_klass(), "expected Klass"); + narrowKlass encoded_k = Klass::encode_klass((Klass *)*metadata_addr); + nx = encoded_k; + } else { + nx = x; + val_size = 64; + } + RawNativeInstruction* ni = si->next_raw(); + uint lo16 = nx & 0xffff; + int shift = 16; + int imm16 = 0xffff << 5; + si->set_encoding((si->encoding() & ~imm16) | (lo16 << 5)); + while (shift < val_size) { + assert(ni->is_movk(), "movk expected"); + assert((((ni->encoding() >> 21) & 0x3) << 4) == shift, "wrong shift"); + uint hi16 = (nx >> shift) & 0xffff; + ni->set_encoding((ni->encoding() & ~imm16) | (hi16 << 5)); + shift += 16; + ni = ni->next_raw(); + } + return; + } +#endif + + assert(si->is_ldr_literal(), "should be"); + + if (oop_addr == NULL && metadata_addr == NULL) { + // A static ldr_literal without oop_relocation + nativeLdrLiteral_at(si->instruction_address())->set_literal_value((address)x); + } else { + // Oop is loaded from oops section + address addr = oop_addr != NULL ? (address)oop_addr : (address)metadata_addr; + int offset = addr - si->instruction_address(); + + assert((((intptr_t)addr) & 0x7) == 0, "target address should be aligned"); + assert((offset & 0x3) == 0, "offset should be aligned"); + + guarantee(Assembler::is_offset_in_range(offset, 19), "offset is not in range"); + nativeLdrLiteral_at(si->instruction_address())->set_literal_address(si->instruction_address() + offset); + } +} + +void NativeMovConstReg::set_data(intptr_t x) { + // Find and replace the oop corresponding to this instruction in oops section + oop* oop_addr = NULL; + Metadata** metadata_addr = NULL; + CodeBlob* cb = CodeCache::find_blob(instruction_address()); + { + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL) { + RelocIterator iter(nm, instruction_address(), next_raw()->instruction_address()); + while (iter.next()) { + if (iter.type() == relocInfo::oop_type) { + oop_addr = iter.oop_reloc()->oop_addr(); + *oop_addr = cast_to_oop(x); + break; + } else if (iter.type() == relocInfo::metadata_type) { + metadata_addr = iter.metadata_reloc()->metadata_addr(); + *metadata_addr = (Metadata*)x; + break; + } + } + } + } + raw_set_data(adjust(this), x, oop_addr, metadata_addr); +} + +void NativeJump::check_verified_entry_alignment(address entry, address verified_entry) { +} + +void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) { + assert(dest == SharedRuntime::get_handle_wrong_method_stub(), "should be"); + + NativeInstruction* instr = nativeInstruction_at(verified_entry); + assert(instr->is_nop() || instr->encoding() == zombie_illegal_instruction, "required for MT-safe patching"); + instr->set_encoding(zombie_illegal_instruction); +} + +void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) { + assert (nativeInstruction_at(instr_addr)->is_b(), "MT-safe patching of arbitrary instructions is not allowed"); + assert (nativeInstruction_at(code_buffer)->is_nop(), "MT-safe patching of arbitrary instructions is not allowed"); + nativeInstruction_at(instr_addr)->set_encoding(*(int*)code_buffer); +} + +void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { + // Insert at code_pos unconditional B instruction jumping to entry + intx offset = entry - code_pos; + assert (Assembler::is_offset_in_range(offset, 26), "offset is out of range"); + + NativeInstruction* instr = nativeInstruction_at(code_pos); + assert (instr->is_b() || instr->is_nop(), "MT-safe patching of arbitrary instructions is not allowed"); + + instr->set_encoding(0x5 << 26 | Assembler::encode_offset(offset, 26, 0)); +} + +static address call_for(address return_address) { + CodeBlob* cb = CodeCache::find_blob(return_address); + nmethod* nm = cb->as_nmethod_or_null(); + if (nm == NULL) { + ShouldNotReachHere(); + return NULL; + } + + // Look back 8 instructions (for LIR_Assembler::ic_call and MacroAssembler::patchable_call) + address begin = return_address - 8*NativeInstruction::instruction_size; + if (begin < nm->code_begin()) { + begin = nm->code_begin(); + } + RelocIterator iter(nm, begin, return_address); + while (iter.next()) { + Relocation* reloc = iter.reloc(); + if (reloc->is_call()) { + address call = reloc->addr(); + if (nativeInstruction_at(call)->is_call()) { + if (nativeCall_at(call)->return_address() == return_address) { + return call; + } + } + } + } + + return NULL; +} + +bool NativeCall::is_call_before(address return_address) { + return (call_for(return_address) != NULL); +} + +NativeCall* nativeCall_before(address return_address) { + assert(NativeCall::is_call_before(return_address), "must be"); + return nativeCall_at(call_for(return_address)); +} +