view src/cpu/s390/vm/relocInfo_s390.cpp @ 12547:0c6ed760800c

8172049: [s390] Implement "JEP 270: Reserved Stack Areas for Critical Sections". Reviewed-by: mdoerr
author goetz
date Tue, 27 Dec 2016 16:10:59 +0100
parents 2844bdfd7a99
children
line wrap: on
line source
/*
 * 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) {
}