| /* |
| * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 2016 SAP SE. 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 "asm/assembler.inline.hpp" |
| #include "code/relocInfo.hpp" |
| #include "nativeInst_s390.hpp" |
| #include "oops/oop.inline.hpp" |
| #include "runtime/safepoint.hpp" |
| |
| void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { |
| // we don't support splitting of relocations, so o must be zero: |
| assert(o == 0, "tried to split relocations"); |
| if (!verify_only) { |
| switch (format()) { |
| case relocInfo::uncompressed_format: |
| nativeMovConstReg_at(addr())->set_data_plain(((intptr_t)x) + o, code()); |
| break; |
| case relocInfo::compressed_format: |
| if (type() == relocInfo::metadata_type) |
| nativeMovConstReg_at(addr())->set_narrow_klass(((intptr_t)x) + o); |
| else if (type() == relocInfo::oop_type) |
| nativeMovConstReg_at(addr())->set_narrow_oop(((intptr_t)x) + o); |
| else |
| guarantee(false, "bad relocInfo type for relocInfo::narrow_oop_format"); |
| break; |
| case relocInfo::pcrel_addr_format: // patch target location |
| nativeMovConstReg_at(addr())->set_pcrel_addr(((intptr_t)x) + o, code()); |
| break; |
| case relocInfo::pcrel_data_format: // patch data at target location |
| nativeMovConstReg_at(addr())->set_pcrel_data(((intptr_t)x) + o, code()); |
| break; |
| default: |
| assert(false, "not a valid relocInfo format"); |
| break; |
| } |
| } else { |
| // TODO: Reading of narrow oops out of code stream is not implemented |
| // (see nativeMovConstReg::data()). Implement this if you want to verify. |
| // assert(x == (address) nativeMovConstReg_at(addr())->data(), "Instructions must match"); |
| switch (format()) { |
| case relocInfo::uncompressed_format: |
| break; |
| case relocInfo::compressed_format: |
| break; |
| case relocInfo::pcrel_addr_format: |
| break; |
| case relocInfo::pcrel_data_format: |
| break; |
| default: |
| assert(false, "not a valid relocInfo format"); |
| break; |
| } |
| } |
| } |
| |
| address Relocation::pd_call_destination(address orig_addr) { |
| address inst_addr = addr(); |
| |
| if (NativeFarCall::is_far_call_at(inst_addr)) { |
| if (!ShortenBranches) { |
| if (MacroAssembler::is_call_far_pcrelative(inst_addr)) { |
| address a1 = MacroAssembler::get_target_addr_pcrel(orig_addr+MacroAssembler::nop_size()); |
| #ifdef ASSERT |
| address a2 = MacroAssembler::get_target_addr_pcrel(inst_addr+MacroAssembler::nop_size()); |
| address a3 = nativeFarCall_at(orig_addr)->destination(); |
| address a4 = nativeFarCall_at(inst_addr)->destination(); |
| if ((a1 != a3) || (a2 != a4)) { |
| unsigned int range = 128; |
| Assembler::dump_code_range(tty, inst_addr, range, "pc-relative call w/o ShortenBranches?"); |
| Assembler::dump_code_range(tty, orig_addr, range, "pc-relative call w/o ShortenBranches?"); |
| assert(false, "pc-relative call w/o ShortenBranches?"); |
| } |
| #endif |
| return a1; |
| } |
| return (address)(-1); |
| } |
| NativeFarCall* call; |
| if (orig_addr == NULL) { |
| call = nativeFarCall_at(inst_addr); |
| } else { |
| // must access location (in CP) where destination is stored in unmoved code, because load from CP is pc-relative |
| call = nativeFarCall_at(orig_addr); |
| } |
| return call->destination(); |
| } |
| |
| if (NativeCall::is_call_at(inst_addr)) { |
| NativeCall* call = nativeCall_at(inst_addr); |
| if (call->is_pcrelative()) { |
| intptr_t off = inst_addr - orig_addr; |
| return (address) (call->destination()-off); |
| } |
| } |
| |
| return (address) nativeMovConstReg_at(inst_addr)->data(); |
| } |
| |
| void Relocation::pd_set_call_destination(address x) { |
| address inst_addr = addr(); |
| |
| if (NativeFarCall::is_far_call_at(inst_addr)) { |
| if (!ShortenBranches) { |
| if (MacroAssembler::is_call_far_pcrelative(inst_addr)) { |
| address a1 = MacroAssembler::get_target_addr_pcrel(inst_addr+MacroAssembler::nop_size()); |
| #ifdef ASSERT |
| address a3 = nativeFarCall_at(inst_addr)->destination(); |
| if (a1 != a3) { |
| unsigned int range = 128; |
| Assembler::dump_code_range(tty, inst_addr, range, "pc-relative call w/o ShortenBranches?"); |
| assert(false, "pc-relative call w/o ShortenBranches?"); |
| } |
| #endif |
| nativeFarCall_at(inst_addr)->set_destination(x, 0); |
| return; |
| } |
| assert(x == (address)-1, "consistency check"); |
| return; |
| } |
| int toc_offset = -1; |
| if (type() == relocInfo::runtime_call_w_cp_type) { |
| toc_offset = ((runtime_call_w_cp_Relocation *)this)->get_constant_pool_offset(); |
| } |
| if (toc_offset>=0) { |
| NativeFarCall* call = nativeFarCall_at(inst_addr); |
| call->set_destination(x, toc_offset); |
| return; |
| } |
| } |
| |
| if (NativeCall::is_call_at(inst_addr)) { |
| NativeCall* call = nativeCall_at(inst_addr); |
| if (call->is_pcrelative()) { |
| call->set_destination_mt_safe(x); |
| return; |
| } |
| } |
| |
| // constant is absolute, must use x |
| nativeMovConstReg_at(inst_addr)->set_data(((intptr_t)x)); |
| } |
| |
| |
| // store the new target address into an oop_Relocation cell, if any |
| // return indication if update happened. |
| bool relocInfo::update_oop_pool(address begin, address end, address newTarget, CodeBlob* cb) { |
| |
| // Try to find the CodeBlob, if not given by caller |
| if (cb == NULL) cb = CodeCache::find_blob(begin); |
| #ifdef ASSERT |
| else |
| assert(cb == CodeCache::find_blob(begin), "consistency"); |
| #endif |
| |
| // 'RelocIterator' requires an nmethod |
| nmethod* nm = cb ? cb->as_nmethod_or_null() : NULL; |
| if (nm != NULL) { |
| RelocIterator iter(nm, begin, end); |
| oop* oop_addr = NULL; |
| Metadata** metadata_addr = NULL; |
| while (iter.next()) { |
| if (iter.type() == relocInfo::oop_type) { |
| oop_Relocation *r = iter.oop_reloc(); |
| if (oop_addr == NULL) { |
| oop_addr = r->oop_addr(); |
| *oop_addr = (oop)newTarget; |
| } else { |
| assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); |
| } |
| } |
| if (iter.type() == relocInfo::metadata_type) { |
| metadata_Relocation *r = iter.metadata_reloc(); |
| if (metadata_addr == NULL) { |
| metadata_addr = r->metadata_addr(); |
| *metadata_addr = (Metadata*)newTarget; |
| } else { |
| assert(metadata_addr == r->metadata_addr(), "must be only one set-metadata here"); |
| } |
| } |
| } |
| return oop_addr || metadata_addr; |
| } |
| return false; |
| } |
| |
| |
| address* Relocation::pd_address_in_code() { |
| ShouldNotReachHere(); |
| return 0; |
| } |
| |
| address Relocation::pd_get_address_from_code() { |
| return (address) (nativeMovConstReg_at(addr())->data()); |
| } |
| |
| void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { |
| } |
| |
| void metadata_Relocation::pd_fix_value(address x) { |
| } |