This commit is contained in:
Jesper Wilhelmsson 2017-04-06 22:58:55 +02:00
commit cc14920031
1366 changed files with 37486 additions and 30689 deletions

View File

@ -47,11 +47,9 @@ ifeq ($(INCLUDE_GRAAL), true)
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_MATCH_PROCESSOR, \
SETUP := GENERATE_OLDBYTECODE, \
SRC := \
$(SRC_DIR)/org.graalvm.compiler.common/src \
$(SRC_DIR)/org.graalvm.compiler.core/src \
$(SRC_DIR)/org.graalvm.compiler.core.common/src \
$(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \
$(SRC_DIR)/org.graalvm.compiler.api.collections/src \
$(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
$(SRC_DIR)/org.graalvm.compiler.asm/src \
$(SRC_DIR)/org.graalvm.compiler.bytecode/src \
@ -68,6 +66,7 @@ ifeq ($(INCLUDE_GRAAL), true)
$(SRC_DIR)/org.graalvm.compiler.phases.common/src \
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
$(SRC_DIR)/org.graalvm.compiler.virtual/src \
$(SRC_DIR)/org.graalvm.util/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
@ -102,6 +101,7 @@ ifeq ($(INCLUDE_GRAAL), true)
SRC := \
$(SRC_DIR)/org.graalvm.compiler.options/src \
$(SRC_DIR)/org.graalvm.compiler.options.processor/src \
$(SRC_DIR)/org.graalvm.util/src \
, \
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor, \
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor.jar, \
@ -114,9 +114,7 @@ ifeq ($(INCLUDE_GRAAL), true)
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER, \
SETUP := GENERATE_OLDBYTECODE, \
SRC := \
$(SRC_DIR)/org.graalvm.compiler.common/src \
$(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \
$(SRC_DIR)/org.graalvm.compiler.api.collections/src \
$(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
$(SRC_DIR)/org.graalvm.compiler.code/src \
$(SRC_DIR)/org.graalvm.compiler.core.common/src \
@ -125,6 +123,7 @@ ifeq ($(INCLUDE_GRAAL), true)
$(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
$(SRC_DIR)/org.graalvm.compiler.options/src \
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
$(SRC_DIR)/org.graalvm.util/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \

View File

@ -37,7 +37,6 @@ SRC_DIR := $(HOTSPOT_TOPDIR)/src/$(MODULE)/share/classes
PROC_SRC_SUBDIRS := \
org.graalvm.compiler.code \
org.graalvm.compiler.common \
org.graalvm.compiler.core \
org.graalvm.compiler.core.aarch64 \
org.graalvm.compiler.core.amd64 \

View File

@ -1,53 +0,0 @@
#
# Copyright (c) 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. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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 $(SPEC)
include NativeCompilation.gmk
$(eval $(call IncludeCustomExtension, hotspot, lib/Lib-jdk.aot.gmk))
##############################################################################
# Build libjelfshim only when AOT is enabled.
ifeq ($(ENABLE_AOT), true)
JELFSHIM_NAME := jelfshim
$(eval $(call SetupNativeCompilation, BUILD_LIBJELFSHIM, \
TOOLCHAIN := TOOLCHAIN_DEFAULT, \
OPTIMIZATION := LOW, \
LIBRARY := $(JELFSHIM_NAME), \
OUTPUT_DIR := $(call FindLibDirForModule, $(MODULE)), \
SRC := $(HOTSPOT_TOPDIR)/src/jdk.aot/unix/native/libjelfshim, \
CFLAGS := $(CFLAGS_JDKLIB) $(ELF_CFLAGS) \
-DAOT_VERSION_STRING='"$(VERSION_STRING)"' \
-I$(SUPPORT_OUTPUTDIR)/headers/$(MODULE), \
LDFLAGS := $(LDFLAGS_JDKLIB), \
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/lib$(JELFSHIM_NAME), \
LIBS := $(ELF_LIBS) $(LIBS_JDKLIB), \
))
TARGETS += $(BUILD_LIBJELFSHIM)
endif
##############################################################################

View File

@ -35,12 +35,14 @@ include $(SPEC)
include MakeBase.gmk
include TestFilesCompilation.gmk
$(eval $(call IncludeCustomExtension, hotspot, test/JtregNative.gmk))
################################################################################
# Targets for building the native tests themselves.
################################################################################
# Add more directories here when needed.
BUILD_HOTSPOT_JTREG_NATIVE_SRC := \
BUILD_HOTSPOT_JTREG_NATIVE_SRC += \
$(HOTSPOT_TOPDIR)/test/native_sanity \
$(HOTSPOT_TOPDIR)/test/runtime/jni/8025979 \
$(HOTSPOT_TOPDIR)/test/runtime/jni/8033445 \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -54,9 +54,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
int number_of_arguments,
bool check_exceptions);
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
// base routine for all dispatches
void dispatch_base(TosState state, address* table, bool verifyoop = true);
@ -67,6 +64,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
void jump_to_entry(address entry);
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
// Interpreter-specific registers
void save_bcp() {
str(rbcp, Address(rfp, frame::interpreter_frame_bcp_offset * wordSize));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2017, 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
@ -55,7 +55,7 @@ void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS)
}
}
#endif // ASSERT
Handle obj = HotSpotObjectConstantImpl::object(constant);
Handle obj(THREAD, HotSpotObjectConstantImpl::object(constant));
jobject value = JNIHandles::make_local(obj());
MacroAssembler::patch_oop(pc, (address)obj());
int oop_index = _oop_recorder->find_index(value);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -77,12 +77,6 @@ class MacroAssembler: public Assembler {
bool check_exceptions // whether to check for pending exceptions after return
);
// These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
// The implementation is only non-empty for the InterpreterMacroAssembler,
// as only the interpreter handles PopFrame and ForceEarlyReturn requests.
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions = true);
// Maximum size of class area in Metaspace when compressed
@ -97,6 +91,12 @@ class MacroAssembler: public Assembler {
> (1u << log2_intptr(CompressedClassSpaceSize))));
}
// These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
// The implementation is only non-empty for the InterpreterMacroAssembler,
// as only the interpreter handles PopFrame and ForceEarlyReturn requests.
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
// Biased locking support
// lock_reg and obj_reg must be loaded up with the appropriate values.
// swap_reg is killed.

View File

@ -1,126 +0,0 @@
/*
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. 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/macroAssembler.hpp"
#include "memory/metaspaceShared.hpp"
// Generate the self-patching vtable method:
//
// This method will be called (as any other Klass virtual method) with
// the Klass itself as the first argument. Example:
//
// oop obj;
// int size = obj->klass()->oop_size(this);
//
// for which the virtual method call is Klass::oop_size();
//
// The dummy method is called with the Klass object as the first
// operand, and an object as the second argument.
//
//=====================================================================
// All of the dummy methods in the vtable are essentially identical,
// differing only by an ordinal constant, and they bear no relationship
// to the original method which the caller intended. Also, there needs
// to be 'vtbl_list_size' instances of the vtable in order to
// differentiate between the 'vtable_list_size' original Klass objects.
#define __ masm->
extern "C" {
void aarch64_prolog(void);
}
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
void** vtable,
char** md_top,
char* md_end,
char** mc_top,
char* mc_end) {
#ifdef BUILTIN_SIM
// Write a dummy word to the writable shared metaspace.
// MetaspaceShared::initialize_shared_spaces will fill it with the
// address of aarch64_prolog().
address *prolog_ptr = (address*)*md_top;
*(intptr_t *)(*md_top) = (intptr_t)0;
(*md_top) += sizeof(intptr_t);
#endif
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
*(intptr_t *)(*md_top) = vtable_bytes;
*md_top += sizeof(intptr_t);
void** dummy_vtable = (void**)*md_top;
*vtable = dummy_vtable;
*md_top += vtable_bytes;
// Get ready to generate dummy methods.
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
MacroAssembler* masm = new MacroAssembler(&cb);
Label common_code;
for (int i = 0; i < vtbl_list_size; ++i) {
for (int j = 0; j < num_virtuals; ++j) {
dummy_vtable[num_virtuals * i + j] = (void*)masm->pc();
// We're called directly from C code.
#ifdef BUILTIN_SIM
__ c_stub_prolog(8, 0, MacroAssembler::ret_type_integral, prolog_ptr);
#endif
// Load rscratch1 with a value indicating vtable/offset pair.
// -- bits[ 7..0] (8 bits) which virtual method in table?
// -- bits[12..8] (5 bits) which virtual method table?
__ mov(rscratch1, (i << 8) + j);
__ b(common_code);
}
}
__ bind(common_code);
Register tmp0 = r10, tmp1 = r11; // AAPCS64 temporary registers
__ enter();
__ lsr(tmp0, rscratch1, 8); // isolate vtable identifier.
__ mov(tmp1, (address)vtbl_list); // address of list of vtable pointers.
__ ldr(tmp1, Address(tmp1, tmp0, Address::lsl(LogBytesPerWord))); // get correct vtable pointer.
__ str(tmp1, Address(c_rarg0)); // update vtable pointer in obj.
__ add(rscratch1, tmp1, rscratch1, ext::uxtb, LogBytesPerWord); // address of real method pointer.
__ ldr(rscratch1, Address(rscratch1)); // get real method pointer.
__ blrt(rscratch1, 8, 0, 1); // jump to the real method.
__ leave();
__ ret(lr);
*mc_top = (char*)__ pc();
}
#ifdef BUILTIN_SIM
void MetaspaceShared::relocate_vtbl_list(char **buffer) {
void **sim_entry = (void**)*buffer;
*sim_entry = (void*)aarch64_prolog;
*buffer += sizeof(intptr_t);
}
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -63,7 +63,7 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
Register obj, SystemDictionary::WKID klass_id,
const char* error_message) {
InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
Klass* klass = SystemDictionary::well_known_klass(klass_id);
Register temp = rscratch2;
Register temp2 = rscratch1; // used by MacroAssembler::cmpptr
Label L_ok, L_bad;

View File

@ -402,14 +402,6 @@ address TemplateInterpreterGenerator::generate_exception_handler_common(
return entry;
}
address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
address entry = __ pc();
// NULL last_sp until next java call
__ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
__ dispatch_next(state);
return entry;
}
address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
address entry = __ pc();
@ -444,6 +436,10 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
__ notify(Assembler::method_reentry);
}
#endif
__ check_and_handle_popframe(rthread);
__ check_and_handle_earlyret(rthread);
__ get_dispatch();
__ dispatch_next(state, step);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2017, 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
@ -234,8 +234,15 @@ void AbstractInterpreter::layout_activation(Method* method,
#ifdef AARCH64
interpreter_frame->interpreter_frame_set_stack_top(stack_top);
// We have to add extra reserved slots to max_stack. There are 3 users of the extra slots,
// none of which are at the same time, so we just need to make sure there is enough room
// for the biggest user:
// -reserved slot for exception handler
// -reserved slots for JSR292. Method::extra_stack_entries() is the size.
// -3 reserved slots so get_method_counters() can save some registers before call_VM().
int max_stack = method->constMethod()->max_stack() + MAX2(3, Method::extra_stack_entries());
intptr_t* extended_sp = (intptr_t*) monbot -
(method->max_stack() + 1) * Interpreter::stackElementWords - // +1 is reserved slot for exception handler
(max_stack * Interpreter::stackElementWords) -
popframe_extra_args;
extended_sp = (intptr_t*)round_down((intptr_t)extended_sp, StackAlignmentInBytes);
interpreter_frame->interpreter_frame_set_extended_sp(extended_sp);

View File

@ -2016,75 +2016,42 @@ void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
void InterpreterMacroAssembler::get_method_counters(Register method,
Register Rcounters,
Label& skip) {
Label& skip,
bool saveRegs,
Register reg1,
Register reg2,
Register reg3) {
const Address method_counters(method, Method::method_counters_offset());
Label has_counters;
ldr(Rcounters, method_counters);
cbnz(Rcounters, has_counters);
if (saveRegs) {
// Save and restore in use caller-saved registers since they will be trashed by call_VM
assert(reg1 != noreg, "must specify reg1");
assert(reg2 != noreg, "must specify reg2");
#ifdef AARCH64
const Register tmp = Rcounters;
const int saved_regs_size = 20*wordSize;
// Note: call_VM will cut SP according to Rstack_top value before call, and restore SP to
// extended_sp value from frame after the call.
// So make sure there is enough stack space to save registers and adjust Rstack_top accordingly.
{
Label enough_stack_space;
check_extended_sp(tmp);
sub(Rstack_top, Rstack_top, saved_regs_size);
cmp(SP, Rstack_top);
b(enough_stack_space, ls);
align_reg(tmp, Rstack_top, StackAlignmentInBytes);
mov(SP, tmp);
str(tmp, Address(FP, frame::interpreter_frame_extended_sp_offset * wordSize));
bind(enough_stack_space);
check_stack_top();
int offset = 0;
stp(R0, R1, Address(Rstack_top, offset)); offset += 2*wordSize;
stp(R2, R3, Address(Rstack_top, offset)); offset += 2*wordSize;
stp(R4, R5, Address(Rstack_top, offset)); offset += 2*wordSize;
stp(R6, R7, Address(Rstack_top, offset)); offset += 2*wordSize;
stp(R8, R9, Address(Rstack_top, offset)); offset += 2*wordSize;
stp(R10, R11, Address(Rstack_top, offset)); offset += 2*wordSize;
stp(R12, R13, Address(Rstack_top, offset)); offset += 2*wordSize;
stp(R14, R15, Address(Rstack_top, offset)); offset += 2*wordSize;
stp(R16, R17, Address(Rstack_top, offset)); offset += 2*wordSize;
stp(R18, LR, Address(Rstack_top, offset)); offset += 2*wordSize;
assert (offset == saved_regs_size, "should be");
}
assert(reg3 != noreg, "must specify reg3");
stp(reg1, reg2, Address(Rstack_top, -2*wordSize, pre_indexed));
stp(reg3, ZR, Address(Rstack_top, -2*wordSize, pre_indexed));
#else
push(RegisterSet(R0, R3) | RegisterSet(R12) | RegisterSet(R14));
#endif // AARCH64
assert(reg3 == noreg, "must not specify reg3");
push(RegisterSet(reg1) | RegisterSet(reg2));
#endif
}
mov(R1, method);
call_VM(noreg, CAST_FROM_FN_PTR(address,
InterpreterRuntime::build_method_counters), R1);
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::build_method_counters), R1);
if (saveRegs) {
#ifdef AARCH64
{
int offset = 0;
ldp(R0, R1, Address(Rstack_top, offset)); offset += 2*wordSize;
ldp(R2, R3, Address(Rstack_top, offset)); offset += 2*wordSize;
ldp(R4, R5, Address(Rstack_top, offset)); offset += 2*wordSize;
ldp(R6, R7, Address(Rstack_top, offset)); offset += 2*wordSize;
ldp(R8, R9, Address(Rstack_top, offset)); offset += 2*wordSize;
ldp(R10, R11, Address(Rstack_top, offset)); offset += 2*wordSize;
ldp(R12, R13, Address(Rstack_top, offset)); offset += 2*wordSize;
ldp(R14, R15, Address(Rstack_top, offset)); offset += 2*wordSize;
ldp(R16, R17, Address(Rstack_top, offset)); offset += 2*wordSize;
ldp(R18, LR, Address(Rstack_top, offset)); offset += 2*wordSize;
assert (offset == saved_regs_size, "should be");
add(Rstack_top, Rstack_top, saved_regs_size);
}
ldp(reg3, ZR, Address(Rstack_top, 2*wordSize, post_indexed));
ldp(reg1, reg2, Address(Rstack_top, 2*wordSize, post_indexed));
#else
pop(RegisterSet(R0, R3) | RegisterSet(R12) | RegisterSet(R14));
#endif // AARCH64
pop(RegisterSet(reg1) | RegisterSet(reg2));
#endif
}
ldr(Rcounters, method_counters);
cbz(Rcounters, skip); // No MethodCounters created, OutOfMemory

View File

@ -53,9 +53,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
// Template interpreter specific version of call_VM_helper
virtual void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions);
virtual void check_and_handle_popframe();
virtual void check_and_handle_earlyret();
// base routine for all dispatches
typedef enum { DispatchDefault, DispatchNormal } DispatchTableMode;
void dispatch_base(TosState state, DispatchTableMode table_mode, bool verifyoop = true);
@ -63,6 +60,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
public:
InterpreterMacroAssembler(CodeBuffer* code);
virtual void check_and_handle_popframe();
virtual void check_and_handle_earlyret();
// Interpreter-specific registers
#if defined(AARCH64) && defined(ASSERT)
@ -328,7 +328,13 @@ class InterpreterMacroAssembler: public MacroAssembler {
void trace_state(const char* msg) PRODUCT_RETURN;
void get_method_counters(Register method, Register Rcounters, Label& skip);
void get_method_counters(Register method,
Register Rcounters,
Label& skip,
bool saveRegs = false,
Register reg1 = noreg,
Register reg2 = noreg,
Register reg3 = noreg);
};
#endif // CPU_ARM_VM_INTERP_MASM_ARM_HPP

View File

@ -206,6 +206,9 @@ protected:
// may customize this version by overriding it for its purposes (e.g., to save/restore
// additional registers when doing a VM call).
virtual void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions);
public:
MacroAssembler(CodeBuffer* code) : Assembler(code) {}
// These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
// The implementation is only non-empty for the InterpreterMacroAssembler,
@ -213,10 +216,6 @@ protected:
virtual void check_and_handle_popframe() {}
virtual void check_and_handle_earlyret() {}
public:
MacroAssembler(CodeBuffer* code) : Assembler(code) {}
// By default, we do not need relocation information for non
// patchable absolute addresses. However, when needed by some
// extensions, ignore_non_patchable_relocations can be modified,

View File

@ -1,99 +0,0 @@
/*
* Copyright (c) 2008, 2015, 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 "asm/macroAssembler.hpp"
#include "assembler_arm.inline.hpp"
#include "memory/metaspaceShared.hpp"
// Generate the self-patching vtable method:
//
// This method will be called (as any other Klass virtual method) with
// the Klass itself as the first argument. Example:
//
// oop obj;
// int size = obj->klass()->oop_size(this);
//
// for which the virtual method call is Klass::oop_size();
//
// The dummy method is called with the Klass object as the first
// operand, and an object as the second argument.
//
//=====================================================================
// All of the dummy methods in the vtable are essentially identical,
// differing only by an ordinal constant, and they bear no relationship
// to the original method which the caller intended. Also, there needs
// to be 'vtbl_list_size' instances of the vtable in order to
// differentiate between the 'vtable_list_size' original Klass objects.
#define __ masm->
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
void** vtable,
char** md_top,
char* md_end,
char** mc_top,
char* mc_end) {
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
*(intptr_t *)(*md_top) = vtable_bytes;
*md_top += sizeof(intptr_t);
void** dummy_vtable = (void**)*md_top;
*vtable = dummy_vtable;
*md_top += vtable_bytes;
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
MacroAssembler* masm = new MacroAssembler(&cb);
for (int i = 0; i < vtbl_list_size; ++i) {
Label common_code;
for (int j = 0; j < num_virtuals; ++j) {
dummy_vtable[num_virtuals * i + j] = (void*) __ pc();
__ mov(Rtemp, j); // Rtemp contains an index of a virtual method in the table
__ b(common_code);
}
InlinedAddress vtable_address((address)&vtbl_list[i]);
__ bind(common_code);
const Register tmp2 = AARCH64_ONLY(Rtemp2) NOT_AARCH64(R4);
assert_different_registers(Rtemp, tmp2);
#ifndef AARCH64
__ push(tmp2);
#endif // !AARCH64
// Do not use ldr_global since the code must be portable across all ARM architectures
__ ldr_literal(tmp2, vtable_address);
__ ldr(tmp2, Address(tmp2)); // get correct vtable address
__ ldr(Rtemp, Address::indexed_ptr(tmp2, Rtemp)); // get real method pointer
__ str(tmp2, Address(R0)); // update vtable. R0 = "this"
#ifndef AARCH64
__ pop(tmp2);
#endif // !AARCH64
__ jump(Rtemp);
__ bind_literal(vtable_address);
}
__ flush();
*mc_top = (char*) __ pc();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2017, 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
@ -67,7 +67,7 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
Register obj, Register temp1, Register temp2, SystemDictionary::WKID klass_id,
const char* error_message) {
InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
Klass* klass = SystemDictionary::well_known_klass(klass_id);
Label L_ok, L_bad;
BLOCK_COMMENT("verify_klass {");
__ verify_oop(obj);

View File

@ -270,12 +270,6 @@ address TemplateInterpreterGenerator::generate_exception_handler_common(const ch
return entry;
}
address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
// Not used.
STOP("generate_continuation_for");
return NULL;
}
address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
address entry = __ pc();
@ -310,6 +304,9 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
__ convert_retval_to_tos(state);
#endif // !AARCH64
__ check_and_handle_popframe();
__ check_and_handle_earlyret();
__ dispatch_next(state, step);
return entry;
@ -1401,7 +1398,13 @@ address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {
#ifdef AARCH64
// setup RmaxStack
__ ldrh(RmaxStack, Address(RconstMethod, ConstMethod::max_stack_offset()));
__ add(RmaxStack, RmaxStack, MAX2(1, Method::extra_stack_entries())); // reserve slots for exception handler and JSR292 appendix argument
// We have to add extra reserved slots to max_stack. There are 3 users of the extra slots,
// none of which are at the same time, so we just need to make sure there is enough room
// for the biggest user:
// -reserved slot for exception handler
// -reserved slots for JSR292. Method::extra_stack_entries() is the size.
// -3 reserved slots so get_method_counters() can save some registers before call_VM().
__ add(RmaxStack, RmaxStack, MAX2(3, Method::extra_stack_entries()));
#endif // AARCH64
// see if we've got enough room on the stack for locals plus overhead.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2017, 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
@ -2286,13 +2286,18 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) {
}
__ bind(no_mdo);
// Increment backedge counter in MethodCounters*
__ get_method_counters(Rmethod, Rcounters, dispatch);
// Note Rbumped_taken_count is a callee saved registers for ARM32, but caller saved for ARM64
__ get_method_counters(Rmethod, Rcounters, dispatch, true /*saveRegs*/,
Rdisp, R3_bytecode,
AARCH64_ONLY(Rbumped_taken_count) NOT_AARCH64(noreg));
const Address mask(Rcounters, in_bytes(MethodCounters::backedge_mask_offset()));
__ increment_mask_and_jump(Address(Rcounters, be_offset), increment, mask,
Rcnt, R4_tmp, eq, &backedge_counter_overflow);
} else {
// increment counter
__ get_method_counters(Rmethod, Rcounters, dispatch);
// Increment backedge counter in MethodCounters*
__ get_method_counters(Rmethod, Rcounters, dispatch, true /*saveRegs*/,
Rdisp, R3_bytecode,
AARCH64_ONLY(Rbumped_taken_count) NOT_AARCH64(noreg));
__ ldr_u32(Rtemp, Address(Rcounters, be_offset)); // load backedge counter
__ add(Rtemp, Rtemp, InvocationCounter::count_increment); // increment counter
__ str_32(Rtemp, Address(Rcounters, be_offset)); // store counter

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, 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
@ -3177,9 +3177,8 @@ void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) {
assert_different_registers(val, crc, res);
__ load_const_optimized(res, StubRoutines::crc_table_addr(), R0);
__ nand(crc, crc, crc); // ~crc
__ update_byte_crc32(crc, val, res);
__ nand(res, crc, crc); // ~crc
__ kernel_crc32_singleByteReg(crc, val, res, true);
__ mr(res, crc);
}
#undef __

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, 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
@ -63,18 +63,6 @@ void LIRItem::load_nonconstant() {
}
inline void load_int_as_long(LIR_List *ll, LIRItem &li, LIR_Opr dst) {
LIR_Opr r = li.value()->operand();
if (r->is_register()) {
LIR_Opr dst_l = FrameMap::as_long_opr(dst->as_register());
ll->convert(Bytecodes::_i2l, li.result(), dst_l); // Convert.
} else {
// Constants or memory get loaded with sign extend on this platform.
ll->move(li.result(), dst);
}
}
//--------------------------------------------------------------
// LIRGenerator
//--------------------------------------------------------------
@ -1419,10 +1407,9 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) {
arg2 = cc->at(1),
arg3 = cc->at(2);
// CCallingConventionRequiresIntsAsLongs
crc.load_item_force(arg1); // We skip int->long conversion here, because CRC32 stub doesn't care about high bits.
__ leal(LIR_OprFact::address(a), arg2);
load_int_as_long(gen()->lir(), len, arg3);
len.load_item_force(arg3); // We skip int->long conversion here, , because CRC32 stub expects int.
__ call_runtime_leaf(StubRoutines::updateBytesCRC32(), LIR_OprFact::illegalOpr, result_reg, cc->args());
__ move(result_reg, result);
@ -1434,6 +1421,66 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) {
}
}
void LIRGenerator::do_update_CRC32C(Intrinsic* x) {
assert(UseCRC32CIntrinsics, "or should not be here");
LIR_Opr result = rlock_result(x);
switch (x->id()) {
case vmIntrinsics::_updateBytesCRC32C:
case vmIntrinsics::_updateDirectByteBufferCRC32C: {
bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32C);
LIRItem crc(x->argument_at(0), this);
LIRItem buf(x->argument_at(1), this);
LIRItem off(x->argument_at(2), this);
LIRItem len(x->argument_at(3), this);
buf.load_item();
off.load_nonconstant();
LIR_Opr index = off.result();
int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0;
if (off.result()->is_constant()) {
index = LIR_OprFact::illegalOpr;
offset += off.result()->as_jint();
}
LIR_Opr base_op = buf.result();
LIR_Address* a = NULL;
if (index->is_valid()) {
LIR_Opr tmp = new_register(T_LONG);
__ convert(Bytecodes::_i2l, index, tmp);
index = tmp;
__ add(index, LIR_OprFact::intptrConst(offset), index);
a = new LIR_Address(base_op, index, T_BYTE);
} else {
a = new LIR_Address(base_op, offset, T_BYTE);
}
BasicTypeList signature(3);
signature.append(T_INT);
signature.append(T_ADDRESS);
signature.append(T_INT);
CallingConvention* cc = frame_map()->c_calling_convention(&signature);
const LIR_Opr result_reg = result_register_for(x->type());
LIR_Opr arg1 = cc->at(0),
arg2 = cc->at(1),
arg3 = cc->at(2);
crc.load_item_force(arg1); // We skip int->long conversion here, because CRC32 stub doesn't care about high bits.
__ leal(LIR_OprFact::address(a), arg2);
len.load_item_force(arg3); // We skip int->long conversion here, , because CRC32 stub expects int.
__ call_runtime_leaf(StubRoutines::updateBytesCRC32C(), LIR_OprFact::illegalOpr, result_reg, cc->args());
__ move(result_reg, result);
break;
}
default: {
ShouldNotReachHere();
}
}
}
void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
assert(x->number_of_arguments() == 3, "wrong type");
assert(UseFMA, "Needs FMA instructions support.");
@ -1460,7 +1507,3 @@ void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) {
fatal("vectorizedMismatch intrinsic is not implemented on this platform");
}
void LIRGenerator::do_update_CRC32C(Intrinsic* x) {
Unimplemented();
}

View File

@ -45,8 +45,8 @@ class InterpreterMacroAssembler: public MacroAssembler {
#define thread_(field_name) in_bytes(JavaThread::field_name ## _offset()), R16_thread
#define method_(field_name) in_bytes(Method::field_name ## _offset()), R19_method
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
virtual void check_and_handle_popframe(Register scratch_reg);
virtual void check_and_handle_earlyret(Register scratch_reg);
// Base routine for all dispatches.
void dispatch_base(TosState state, address* table);

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017 SAP SE. All rights reserved.
* Copyright (c) 2012, 2017, 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
@ -4120,7 +4120,7 @@ void MacroAssembler::update_byte_crc32(Register crc, Register val, Register tabl
* @param table register pointing to CRC table
*/
void MacroAssembler::update_byteLoop_crc32(Register crc, Register buf, Register len, Register table,
Register data, bool loopAlignment, bool invertCRC) {
Register data, bool loopAlignment) {
assert_different_registers(crc, buf, len, table, data);
Label L_mainLoop, L_done;
@ -4131,10 +4131,6 @@ void MacroAssembler::update_byteLoop_crc32(Register crc, Register buf, Register
clrldi_(len, len, 32); // Enforce 32 bit. Anything to do?
beq(CCR0, L_done);
if (invertCRC) {
nand(crc, crc, crc); // ~c
}
mtctr(len);
align(mainLoop_alignment);
BIND(L_mainLoop);
@ -4143,10 +4139,6 @@ void MacroAssembler::update_byteLoop_crc32(Register crc, Register buf, Register
update_byte_crc32(crc, data, table);
bdnz(L_mainLoop); // Iterate.
if (invertCRC) {
nand(crc, crc, crc); // ~c
}
bind(L_done);
}
@ -4203,7 +4195,8 @@ void MacroAssembler::update_1word_crc32(Register crc, Register buf, Register tab
*/
void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len, Register table,
Register t0, Register t1, Register t2, Register t3,
Register tc0, Register tc1, Register tc2, Register tc3) {
Register tc0, Register tc1, Register tc2, Register tc3,
bool invertCRC) {
assert_different_registers(crc, buf, len, table);
Label L_mainLoop, L_tail;
@ -4217,14 +4210,16 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
const int complexThreshold = 2*mainLoop_stepping;
// Don't test for len <= 0 here. This pathological case should not occur anyway.
// Optimizing for it by adding a test and a branch seems to be a waste of CPU cycles.
// The situation itself is detected and handled correctly by the conditional branches
// following aghi(len, -stepping) and aghi(len, +stepping).
// Optimizing for it by adding a test and a branch seems to be a waste of CPU cycles
// for all well-behaved cases. The situation itself is detected and handled correctly
// within update_byteLoop_crc32.
assert(tailLoop_stepping == 1, "check tailLoop_stepping!");
BLOCK_COMMENT("kernel_crc32_2word {");
nand(crc, crc, crc); // ~c
if (invertCRC) {
nand(crc, crc, crc); // 1s complement of crc
}
// Check for short (<mainLoop_stepping) buffer.
cmpdi(CCR0, len, complexThreshold);
@ -4245,7 +4240,7 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
blt(CCR0, L_tail); // For less than one mainloop_stepping left, do only tail processing
mr(len, tmp); // remaining bytes for main loop (>=mainLoop_stepping is guaranteed).
}
update_byteLoop_crc32(crc, buf, tmp2, table, data, false, false);
update_byteLoop_crc32(crc, buf, tmp2, table, data, false);
}
srdi(tmp2, len, log_stepping); // #iterations for mainLoop
@ -4281,9 +4276,11 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
// Process last few (<complexThreshold) bytes of buffer.
BIND(L_tail);
update_byteLoop_crc32(crc, buf, len, table, data, false, false);
update_byteLoop_crc32(crc, buf, len, table, data, false);
nand(crc, crc, crc); // ~c
if (invertCRC) {
nand(crc, crc, crc); // 1s complement of crc
}
BLOCK_COMMENT("} kernel_crc32_2word");
}
@ -4297,7 +4294,8 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
*/
void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len, Register table,
Register t0, Register t1, Register t2, Register t3,
Register tc0, Register tc1, Register tc2, Register tc3) {
Register tc0, Register tc1, Register tc2, Register tc3,
bool invertCRC) {
assert_different_registers(crc, buf, len, table);
Label L_mainLoop, L_tail;
@ -4311,14 +4309,16 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
const int complexThreshold = 2*mainLoop_stepping;
// Don't test for len <= 0 here. This pathological case should not occur anyway.
// Optimizing for it by adding a test and a branch seems to be a waste of CPU cycles.
// The situation itself is detected and handled correctly by the conditional branches
// following aghi(len, -stepping) and aghi(len, +stepping).
// Optimizing for it by adding a test and a branch seems to be a waste of CPU cycles
// for all well-behaved cases. The situation itself is detected and handled correctly
// within update_byteLoop_crc32.
assert(tailLoop_stepping == 1, "check tailLoop_stepping!");
BLOCK_COMMENT("kernel_crc32_1word {");
nand(crc, crc, crc); // ~c
if (invertCRC) {
nand(crc, crc, crc); // 1s complement of crc
}
// Check for short (<mainLoop_stepping) buffer.
cmpdi(CCR0, len, complexThreshold);
@ -4339,7 +4339,7 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
blt(CCR0, L_tail); // For less than one mainloop_stepping left, do only tail processing
mr(len, tmp); // remaining bytes for main loop (>=mainLoop_stepping is guaranteed).
}
update_byteLoop_crc32(crc, buf, tmp2, table, data, false, false);
update_byteLoop_crc32(crc, buf, tmp2, table, data, false);
}
srdi(tmp2, len, log_stepping); // #iterations for mainLoop
@ -4374,9 +4374,11 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
// Process last few (<complexThreshold) bytes of buffer.
BIND(L_tail);
update_byteLoop_crc32(crc, buf, len, table, data, false, false);
update_byteLoop_crc32(crc, buf, len, table, data, false);
nand(crc, crc, crc); // ~c
if (invertCRC) {
nand(crc, crc, crc); // 1s complement of crc
}
BLOCK_COMMENT("} kernel_crc32_1word");
}
@ -4389,16 +4391,24 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
* Uses R7_ARG5, R8_ARG6 as work registers.
*/
void MacroAssembler::kernel_crc32_1byte(Register crc, Register buf, Register len, Register table,
Register t0, Register t1, Register t2, Register t3) {
Register t0, Register t1, Register t2, Register t3,
bool invertCRC) {
assert_different_registers(crc, buf, len, table);
Register data = t0; // Holds the current byte to be folded into crc.
BLOCK_COMMENT("kernel_crc32_1byte {");
// Process all bytes in a single-byte loop.
update_byteLoop_crc32(crc, buf, len, table, data, true, true);
if (invertCRC) {
nand(crc, crc, crc); // 1s complement of crc
}
// Process all bytes in a single-byte loop.
update_byteLoop_crc32(crc, buf, len, table, data, true);
if (invertCRC) {
nand(crc, crc, crc); // 1s complement of crc
}
BLOCK_COMMENT("} kernel_crc32_1byte");
}
@ -4416,7 +4426,8 @@ void MacroAssembler::kernel_crc32_1byte(Register crc, Register buf, Register len
*/
void MacroAssembler::kernel_crc32_1word_vpmsumd(Register crc, Register buf, Register len, Register table,
Register constants, Register barretConstants,
Register t0, Register t1, Register t2, Register t3, Register t4) {
Register t0, Register t1, Register t2, Register t3, Register t4,
bool invertCRC) {
assert_different_registers(crc, buf, len, table);
Label L_alignedHead, L_tail, L_alignTail, L_start, L_end;
@ -4434,13 +4445,15 @@ void MacroAssembler::kernel_crc32_1word_vpmsumd(Register crc, Register buf, Regi
Register tc0 = t4;
Register tc1 = constants;
Register tc2 = barretConstants;
kernel_crc32_1word(crc, buf, len, table,t0, t1, t2, t3, tc0, tc1, tc2, table);
kernel_crc32_1word(crc, buf, len, table,t0, t1, t2, t3, tc0, tc1, tc2, table, invertCRC);
b(L_end);
BIND(L_start);
// 2. ~c
nand(crc, crc, crc);
if (invertCRC) {
nand(crc, crc, crc); // 1s complement of crc
}
// 3. calculate from 0 to first 128bit-aligned address
clrldi_(prealign, buf, 57);
@ -4449,7 +4462,7 @@ void MacroAssembler::kernel_crc32_1word_vpmsumd(Register crc, Register buf, Regi
subfic(prealign, prealign, 128);
subf(len, prealign, len);
update_byteLoop_crc32(crc, buf, prealign, table, t2, false, false);
update_byteLoop_crc32(crc, buf, prealign, table, t2, false);
// 4. calculate from first 128bit-aligned address to last 128bit-aligned address
BIND(L_alignedHead);
@ -4464,12 +4477,14 @@ void MacroAssembler::kernel_crc32_1word_vpmsumd(Register crc, Register buf, Regi
cmpdi(CCR0, postalign, 0);
beq(CCR0, L_tail);
update_byteLoop_crc32(crc, buf, postalign, table, t2, false, false);
update_byteLoop_crc32(crc, buf, postalign, table, t2, false);
BIND(L_tail);
// 6. ~c
nand(crc, crc, crc);
if (invertCRC) {
nand(crc, crc, crc); // 1s complement of crc
}
BIND(L_end);
@ -4961,16 +4976,35 @@ void MacroAssembler::kernel_crc32_1word_aligned(Register crc, Register buf, Regi
offsetInt -= 8; ld(R31, offsetInt, R1_SP);
}
void MacroAssembler::kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp) {
void MacroAssembler::kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp, bool invertCRC) {
assert_different_registers(crc, buf, /* len, not used!! */ table, tmp);
BLOCK_COMMENT("kernel_crc32_singleByte:");
nand(crc, crc, crc); // ~c
if (invertCRC) {
nand(crc, crc, crc); // 1s complement of crc
}
lbz(tmp, 0, buf); // Byte from buffer, zero-extended.
lbz(tmp, 0, buf); // Byte from buffer, zero-extended.
update_byte_crc32(crc, tmp, table);
nand(crc, crc, crc); // ~c
if (invertCRC) {
nand(crc, crc, crc); // 1s complement of crc
}
}
void MacroAssembler::kernel_crc32_singleByteReg(Register crc, Register val, Register table, bool invertCRC) {
assert_different_registers(crc, val, table);
BLOCK_COMMENT("kernel_crc32_singleByteReg:");
if (invertCRC) {
nand(crc, crc, crc); // 1s complement of crc
}
update_byte_crc32(crc, val, table);
if (invertCRC) {
nand(crc, crc, crc); // 1s complement of crc
}
}
// dest_lo += src1 + src2

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017 SAP SE. All rights reserved.
* Copyright (c) 2012, 2017, 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
@ -819,33 +819,47 @@ class MacroAssembler: public Assembler {
Register tmp6, Register tmp7, Register tmp8, Register tmp9, Register tmp10,
Register tmp11, Register tmp12, Register tmp13);
// CRC32 Intrinsics.
// Emitters for CRC32 calculation.
// A note on invertCRC:
// Unfortunately, internal representation of crc differs between CRC32 and CRC32C.
// CRC32 holds it's current crc value in the externally visible representation.
// CRC32C holds it's current crc value in internal format, ready for updating.
// Thus, the crc value must be bit-flipped before updating it in the CRC32 case.
// In the CRC32C case, it must be bit-flipped when it is given to the outside world (getValue()).
// The bool invertCRC parameter indicates whether bit-flipping is required before updates.
void load_reverse_32(Register dst, Register src);
int crc32_table_columns(Register table, Register tc0, Register tc1, Register tc2, Register tc3);
void fold_byte_crc32(Register crc, Register val, Register table, Register tmp);
void fold_8bit_crc32(Register crc, Register table, Register tmp);
void update_byte_crc32(Register crc, Register val, Register table);
void update_byteLoop_crc32(Register crc, Register buf, Register len, Register table,
Register data, bool loopAlignment, bool invertCRC);
Register data, bool loopAlignment);
void update_1word_crc32(Register crc, Register buf, Register table, int bufDisp, int bufInc,
Register t0, Register t1, Register t2, Register t3,
Register tc0, Register tc1, Register tc2, Register tc3);
void kernel_crc32_2word(Register crc, Register buf, Register len, Register table,
Register t0, Register t1, Register t2, Register t3,
Register tc0, Register tc1, Register tc2, Register tc3);
Register tc0, Register tc1, Register tc2, Register tc3,
bool invertCRC);
void kernel_crc32_1word(Register crc, Register buf, Register len, Register table,
Register t0, Register t1, Register t2, Register t3,
Register tc0, Register tc1, Register tc2, Register tc3);
Register tc0, Register tc1, Register tc2, Register tc3,
bool invertCRC);
void kernel_crc32_1byte(Register crc, Register buf, Register len, Register table,
Register t0, Register t1, Register t2, Register t3);
Register t0, Register t1, Register t2, Register t3,
bool invertCRC);
void kernel_crc32_1word_vpmsumd(Register crc, Register buf, Register len, Register table,
Register constants, Register barretConstants,
Register t0, Register t1, Register t2, Register t3, Register t4);
Register t0, Register t1, Register t2, Register t3, Register t4,
bool invertCRC);
void kernel_crc32_1word_aligned(Register crc, Register buf, Register len,
Register constants, Register barretConstants,
Register t0, Register t1, Register t2);
void kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp);
void kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp,
bool invertCRC);
void kernel_crc32_singleByteReg(Register crc, Register val, Register table,
bool invertCRC);
//
// Debugging

View File

@ -1,78 +0,0 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013 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/macroAssembler.inline.hpp"
#include "asm/codeBuffer.hpp"
#include "memory/metaspaceShared.hpp"
// Generate the self-patching vtable method:
//
// This method will be called (as any other Klass virtual method) with
// the Klass itself as the first argument. Example:
//
// oop obj;
// int size = obj->klass()->klass_part()->oop_size(this);
//
// for which the virtual method call is Klass::oop_size();
//
// The dummy method is called with the Klass object as the first
// operand, and an object as the second argument.
//
//=====================================================================
// All of the dummy methods in the vtable are essentially identical,
// differing only by an ordinal constant, and they bear no releationship
// to the original method which the caller intended. Also, there needs
// to be 'vtbl_list_size' instances of the vtable in order to
// differentiate between the 'vtable_list_size' original Klass objects.
#define __ masm->
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
void** vtable,
char** md_top,
char* md_end,
char** mc_top,
char* mc_end) {
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
*(intptr_t *)(*md_top) = vtable_bytes;
*md_top += sizeof(intptr_t);
void** dummy_vtable = (void**)*md_top;
*vtable = dummy_vtable;
*md_top += vtable_bytes;
// Get ready to generate dummy methods.
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
MacroAssembler* masm = new MacroAssembler(&cb);
// There are more general problems with CDS on ppc, so I can not
// really test this. But having this instead of Unimplementd() allows
// us to pass TestOptionsWithRanges.java.
__ unimplemented();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -71,7 +71,7 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
Register temp_reg, Register temp2_reg,
const char* error_message) {
InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
Klass* klass = SystemDictionary::well_known_klass(klass_id);
Label L_ok, L_bad;
BLOCK_COMMENT("verify_klass {");
__ verify_oop(obj_reg);

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, 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
@ -3276,6 +3276,36 @@ class StubGenerator: public StubCodeGenerator {
return start;
}
// Compute CRC32/CRC32C function.
void generate_CRC_updateBytes(const char* name, Register table, bool invertCRC) {
// arguments to kernel_crc32:
const Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call.
const Register data = R4_ARG2; // source byte array
const Register dataLen = R5_ARG3; // #bytes to process
const Register t0 = R2;
const Register t1 = R7;
const Register t2 = R8;
const Register t3 = R9;
const Register tc0 = R10;
const Register tc1 = R11;
const Register tc2 = R12;
BLOCK_COMMENT("Stub body {");
assert_different_registers(crc, data, dataLen, table);
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, table, invertCRC);
BLOCK_COMMENT("return");
__ mr_if_needed(R3_RET, crc); // Updated crc is function result. No copying required (R3_ARG1 == R3_RET).
__ blr();
BLOCK_COMMENT("} Stub body");
}
/**
* Arguments:
*
@ -3296,14 +3326,14 @@ class StubGenerator: public StubCodeGenerator {
StubCodeMark mark(this, "StubRoutines", name);
address start = __ function_entry(); // Remember stub start address (is rtn value).
const Register table = R6; // crc table address
#ifdef VM_LITTLE_ENDIAN
// arguments to kernel_crc32:
const Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call.
const Register data = R4_ARG2; // source byte array
const Register dataLen = R5_ARG3; // #bytes to process
const Register table = R6; // crc table address
#ifdef VM_LITTLE_ENDIAN
if (VM_Version::has_vpmsumb()) {
const Register constants = R2; // constants address
const Register bconstants = R8; // barret table address
@ -3321,7 +3351,7 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::ppc64::generate_load_crc_constants_addr(_masm, constants);
StubRoutines::ppc64::generate_load_crc_barret_constants_addr(_masm, bconstants);
__ kernel_crc32_1word_vpmsumd(crc, data, dataLen, table, constants, bconstants, t0, t1, t2, t3, t4);
__ kernel_crc32_1word_vpmsumd(crc, data, dataLen, table, constants, bconstants, t0, t1, t2, t3, t4, true);
BLOCK_COMMENT("return");
__ mr_if_needed(R3_RET, crc); // Updated crc is function result. No copying required (R3_ARG1 == R3_RET).
@ -3331,31 +3361,79 @@ class StubGenerator: public StubCodeGenerator {
} else
#endif
{
const Register t0 = R2;
const Register t1 = R7;
const Register t2 = R8;
const Register t3 = R9;
const Register tc0 = R10;
const Register tc1 = R11;
const Register tc2 = R12;
StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table);
generate_CRC_updateBytes(name, table, true);
}
return start;
}
/**
* Arguments:
*
* Inputs:
* R3_ARG1 - int crc
* R4_ARG2 - byte* buf
* R5_ARG3 - int length (of buffer)
*
* scratch:
* R2, R6-R12
*
* Ouput:
* R3_RET - int crc result
*/
// Compute CRC32C function.
address generate_CRC32C_updateBytes(const char* name) {
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", name);
address start = __ function_entry(); // Remember stub start address (is rtn value).
const Register table = R6; // crc table address
#if 0 // no vector support yet for CRC32C
#ifdef VM_LITTLE_ENDIAN
// arguments to kernel_crc32:
const Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call.
const Register data = R4_ARG2; // source byte array
const Register dataLen = R5_ARG3; // #bytes to process
if (VM_Version::has_vpmsumb()) {
const Register constants = R2; // constants address
const Register bconstants = R8; // barret table address
const Register t0 = R9;
const Register t1 = R10;
const Register t2 = R11;
const Register t3 = R12;
const Register t4 = R7;
BLOCK_COMMENT("Stub body {");
assert_different_registers(crc, data, dataLen, table);
StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table);
StubRoutines::ppc64::generate_load_crc32c_table_addr(_masm, table);
StubRoutines::ppc64::generate_load_crc32c_constants_addr(_masm, constants);
StubRoutines::ppc64::generate_load_crc32c_barret_constants_addr(_masm, bconstants);
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, table);
__ kernel_crc32_1word_vpmsumd(crc, data, dataLen, table, constants, bconstants, t0, t1, t2, t3, t4, false);
BLOCK_COMMENT("return");
__ mr_if_needed(R3_RET, crc); // Updated crc is function result. No copying required (R3_ARG1 == R3_RET).
__ blr();
BLOCK_COMMENT("} Stub body");
} else
#endif
#endif
{
StubRoutines::ppc64::generate_load_crc32c_table_addr(_masm, table);
generate_CRC_updateBytes(name, table, false);
}
return start;
}
// Initialization
void generate_initial() {
// Generates all stubs and initializes the entry points
@ -3383,6 +3461,12 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_crc_table_adr = (address)StubRoutines::ppc64::_crc_table;
StubRoutines::_updateBytesCRC32 = generate_CRC32_updateBytes("CRC32_updateBytes");
}
// CRC32C Intrinsics.
if (UseCRC32CIntrinsics) {
StubRoutines::_crc32c_table_addr = (address)StubRoutines::ppc64::_crc32c_table;
StubRoutines::_updateBytesCRC32C = generate_CRC32C_updateBytes("CRC32C_updateBytes");
}
}
void generate_all() {

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
* Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, 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
@ -55,13 +55,16 @@ class ppc64 {
// CRC32 Intrinsics.
static juint _crc_table[CRC32_TABLES][CRC32_COLUMN_SIZE];
static juint _crc32c_table[CRC32_TABLES][CRC32_COLUMN_SIZE];
static juint* _constants;
static juint* _barret_constants;
public:
// CRC32 Intrinsics.
static void generate_load_table_addr(MacroAssembler* masm, Register table, address table_addr, uint64_t table_contents);
static void generate_load_crc_table_addr(MacroAssembler* masm, Register table);
static void generate_load_crc32c_table_addr(MacroAssembler* masm, Register table);
static void generate_load_crc_constants_addr(MacroAssembler* masm, Register table);
static void generate_load_crc_barret_constants_addr(MacroAssembler* masm, Register table);
static juint* generate_crc_constants();

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2017 SAP SE. All rights reserved.
* Copyright (c) 2015, 2017, 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
@ -643,12 +643,6 @@ address TemplateInterpreterGenerator::generate_exception_handler_common(const ch
return entry;
}
address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
address entry = __ pc();
__ unimplemented("generate_continuation_for");
return entry;
}
// This entry is returned to when a call returns to the interpreter.
// When we arrive here, we expect that the callee stack frame is already popped.
address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
@ -692,6 +686,10 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
#endif
__ sldi(size, size, Interpreter::logStackElementSize);
__ add(R15_esp, R15_esp, size);
__ check_and_handle_popframe(R11_scratch1);
__ check_and_handle_earlyret(R11_scratch1);
__ dispatch_next(state, step);
return entry;
}
@ -1894,7 +1892,7 @@ address TemplateInterpreterGenerator::generate_CRC32_update_entry() {
__ lwz(crc, 2*wordSize, argP); // Current crc state, zero extend to 64 bit to have a clean register.
StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table);
__ kernel_crc32_singleByte(crc, data, dataLen, table, tmp);
__ kernel_crc32_singleByte(crc, data, dataLen, table, tmp, true);
// Restore caller sp for c2i case and return.
__ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
@ -1910,6 +1908,10 @@ address TemplateInterpreterGenerator::generate_CRC32_update_entry() {
return NULL;
}
// TODO: generate_CRC32_updateBytes_entry and generate_CRC32C_updateBytes_entry are identical
// except for using different crc tables and some block comment strings.
// We should provide a common implementation.
// CRC32 Intrinsics.
/**
* Method entry for static native methods:
@ -1986,7 +1988,7 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI
// Performance measurements show the 1word and 2word variants to be almost equivalent,
// with very light advantages for the 1word variant. We chose the 1word variant for
// code compactness.
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, tc3);
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, tc3, true);
// Restore caller sp for c2i case and return.
__ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
@ -2002,8 +2004,84 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI
return NULL;
}
// Not supported
// CRC32C Intrinsics.
/**
* Method entry for static native methods:
* int java.util.zip.CRC32C.updateBytes( int crc, byte[] b, int off, int len)
* int java.util.zip.CRC32C.updateDirectByteBuffer(int crc, long* buf, int off, int len)
**/
address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
if (UseCRC32CIntrinsics) {
address start = __ pc(); // Remember stub start address (is rtn value).
// We don't generate local frame and don't align stack because
// we not even call stub code (we generate the code inline)
// and there is no safepoint on this path.
// Load parameters.
// Z_esp is callers operand stack pointer, i.e. it points to the parameters.
const Register argP = R15_esp;
const Register crc = R3_ARG1; // crc value
const Register data = R4_ARG2; // address of java byte array
const Register dataLen = R5_ARG3; // source data len
const Register table = R6_ARG4; // address of crc32c table
const Register t0 = R9; // scratch registers for crc calculation
const Register t1 = R10;
const Register t2 = R11;
const Register t3 = R12;
const Register tc0 = R2; // registers to hold pre-calculated column addresses
const Register tc1 = R7;
const Register tc2 = R8;
const Register tc3 = table; // table address is reconstructed at the end of kernel_crc32_* emitters
const Register tmp = t0; // Only used very locally to calculate byte buffer address.
// Arguments are reversed on java expression stack.
// Calculate address of start element.
if (kind == Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer) { // Used for "updateDirectByteBuffer".
BLOCK_COMMENT("CRC32C_updateDirectByteBuffer {");
// crc @ (SP + 5W) (32bit)
// buf @ (SP + 3W) (64bit ptr to long array)
// off @ (SP + 2W) (32bit)
// dataLen @ (SP + 1W) (32bit)
// data = buf + off
__ ld( data, 3*wordSize, argP); // start of byte buffer
__ lwa( tmp, 2*wordSize, argP); // byte buffer offset
__ lwa( dataLen, 1*wordSize, argP); // #bytes to process
__ lwz( crc, 5*wordSize, argP); // current crc state
__ add( data, data, tmp); // Add byte buffer offset.
} else { // Used for "updateBytes update".
BLOCK_COMMENT("CRC32C_updateBytes {");
// crc @ (SP + 4W) (32bit)
// buf @ (SP + 3W) (64bit ptr to byte array)
// off @ (SP + 2W) (32bit)
// dataLen @ (SP + 1W) (32bit)
// data = buf + off + base_offset
__ ld( data, 3*wordSize, argP); // start of byte buffer
__ lwa( tmp, 2*wordSize, argP); // byte buffer offset
__ lwa( dataLen, 1*wordSize, argP); // #bytes to process
__ add( data, data, tmp); // add byte buffer offset
__ lwz( crc, 4*wordSize, argP); // current crc state
__ addi(data, data, arrayOopDesc::base_offset_in_bytes(T_BYTE));
}
StubRoutines::ppc64::generate_load_crc32c_table_addr(_masm, table);
// Performance measurements show the 1word and 2word variants to be almost equivalent,
// with very light advantages for the 1word variant. We chose the 1word variant for
// code compactness.
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, tc3, false);
// Restore caller sp for c2i case and return.
__ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
__ blr();
BLOCK_COMMENT("} CRC32C_update{Bytes|DirectByteBuffer}");
return start;
}
return NULL;
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, 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
@ -172,18 +172,27 @@ void VM_Version::initialize() {
assert(AllocatePrefetchStyle >= 0, "AllocatePrefetchStyle should be positive");
// Implementation does not use any of the vector instructions
// available with Power8. Their exploitation is still pending.
// If defined(VM_LITTLE_ENDIAN) and running on Power8 or newer hardware,
// the implementation uses the vector instructions available with Power8.
// In all other cases, the implementation uses only generally available instructions.
if (!UseCRC32Intrinsics) {
if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) {
FLAG_SET_DEFAULT(UseCRC32Intrinsics, true);
}
}
if (UseCRC32CIntrinsics) {
if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics))
warning("CRC32C intrinsics are not available on this CPU");
FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
// Implementation does not use any of the vector instructions available with Power8.
// Their exploitation is still pending (aka "work in progress").
if (!UseCRC32CIntrinsics) {
if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) {
FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true);
}
}
// TODO: Provide implementation.
if (UseAdler32Intrinsics) {
warning("Adler32Intrinsics not available on this CPU.");
FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
}
// The AES intrinsic stubs require AES instruction support.
@ -245,11 +254,6 @@ void VM_Version::initialize() {
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
}
if (UseAdler32Intrinsics) {
warning("Adler32Intrinsics not available on this CPU.");
FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
}
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
UseMultiplyToLenIntrinsic = true;
}

View File

@ -28,8 +28,6 @@
#undef LUCY_DBG
#define NearLabel Label
// Immediate is an abstraction to represent the various immediate
// operands which exist on z/Architecture. Neither this class nor
// instances hereof have an own state. It consists of methods only.

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved.
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -3048,9 +3048,8 @@ void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) {
assert_different_registers(val, crc, res);
__ load_const_optimized(res, StubRoutines::crc_table_addr());
__ not_(crc, noreg, false); // ~crc
__ update_byte_crc32(crc, val, res);
__ not_(res, crc, false); // ~crc
__ kernel_crc32_singleByteReg(crc, val, res, true);
__ z_lgfr(res, crc);
}
#undef __

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved.
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -61,20 +61,6 @@ void LIRItem::load_nonconstant(int bits) {
}
}
inline void load_int_as_long(LIR_List *ll, LIRItem &li, LIR_Opr dst) {
LIR_Opr r = li.value()->operand();
if (r->is_constant()) {
// Constants get loaded with sign extend on this platform.
ll->move(li.result(), dst);
} else {
if (!r->is_register()) {
li.load_item_force(dst);
}
LIR_Opr dst_l = FrameMap::as_long_opr(dst->as_register());
ll->convert(Bytecodes::_i2l, li.result(), dst_l); // Convert.
}
}
//--------------------------------------------------------------
// LIRGenerator
//--------------------------------------------------------------
@ -1217,10 +1203,9 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) {
LIR_Opr arg2 = cc->at(1);
LIR_Opr arg3 = cc->at(2);
// CCallingConventionRequiresIntsAsLongs
crc.load_item_force(arg1); // We skip int->long conversion here, because CRC32 stub doesn't care about high bits.
__ leal(LIR_OprFact::address(a), arg2);
load_int_as_long(gen()->lir(), len, arg3);
len.load_item_force(arg3); // We skip int->long conversion here, because CRC32 stub expects int.
__ call_runtime_leaf(StubRoutines::updateBytesCRC32(), LIR_OprFact::illegalOpr, result_reg, cc->args());
__ move(result_reg, result);
@ -1233,7 +1218,60 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) {
}
void LIRGenerator::do_update_CRC32C(Intrinsic* x) {
Unimplemented();
assert(UseCRC32CIntrinsics, "or should not be here");
LIR_Opr result = rlock_result(x);
switch (x->id()) {
case vmIntrinsics::_updateBytesCRC32C:
case vmIntrinsics::_updateDirectByteBufferCRC32C: {
bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32C);
LIRItem crc(x->argument_at(0), this);
LIRItem buf(x->argument_at(1), this);
LIRItem off(x->argument_at(2), this);
LIRItem len(x->argument_at(3), this);
buf.load_item();
off.load_nonconstant();
LIR_Opr index = off.result();
int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0;
if (off.result()->is_constant()) {
index = LIR_OprFact::illegalOpr;
offset += off.result()->as_jint();
}
LIR_Opr base_op = buf.result();
if (index->is_valid()) {
LIR_Opr tmp = new_register(T_LONG);
__ convert(Bytecodes::_i2l, index, tmp);
index = tmp;
}
LIR_Address* a = new LIR_Address(base_op, index, offset, T_BYTE);
BasicTypeList signature(3);
signature.append(T_INT);
signature.append(T_ADDRESS);
signature.append(T_INT);
CallingConvention* cc = frame_map()->c_calling_convention(&signature);
const LIR_Opr result_reg = result_register_for (x->type());
LIR_Opr arg1 = cc->at(0);
LIR_Opr arg2 = cc->at(1);
LIR_Opr arg3 = cc->at(2);
crc.load_item_force(arg1); // We skip int->long conversion here, because CRC32C stub doesn't care about high bits.
__ leal(LIR_OprFact::address(a), arg2);
len.load_item_force(arg3); // We skip int->long conversion here, because CRC32C stub expects int.
__ call_runtime_leaf(StubRoutines::updateBytesCRC32C(), LIR_OprFact::illegalOpr, result_reg, cc->args());
__ move(result_reg, result);
break;
}
default: {
ShouldNotReachHere();
}
}
}
void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
@ -1264,4 +1302,3 @@ void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) {
fatal("vectorizedMismatch intrinsic is not implemented on this platform");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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.
*
@ -48,9 +48,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
bool allow_relocation,
bool check_exceptions);
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
// Base routine for all dispatches.
void dispatch_base(TosState state, address* table);
@ -58,6 +55,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
InterpreterMacroAssembler(CodeBuffer* c)
: MacroAssembler(c) {}
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
void jump_to_entry(address entry, Register Rscratch);
virtual void load_earlyret_value(TosState state);

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved.
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -1616,6 +1616,8 @@ void MacroAssembler::branch_optimized(Assembler::branch_condition cond, Label& b
if (branch_target.is_bound()) {
address branch_addr = target(branch_target);
branch_optimized(cond, branch_addr);
} else if (branch_target.is_near()) {
z_brc(cond, branch_target); // Caller assures that the target will be in range for z_brc.
} else {
z_brcl(cond, branch_target); // Let's hope target is in range. Otherwise, we will abort at patch time.
}
@ -1674,7 +1676,8 @@ void MacroAssembler::compare_and_branch_optimized(Register r1,
bool has_sign) {
address branch_origin = pc();
bool x2_imm8 = (has_sign && Immediate::is_simm8(x2)) || (!has_sign && Immediate::is_uimm8(x2));
bool is_RelAddr16 = (branch_target.is_bound() &&
bool is_RelAddr16 = branch_target.is_near() ||
(branch_target.is_bound() &&
RelAddr::is_in_range_of_RelAddr16(target(branch_target), branch_origin));
unsigned int casenum = (len64?2:0)+(has_sign?0:1);
@ -1744,13 +1747,21 @@ void MacroAssembler::compare_and_branch_optimized(Register r1,
Label& branch_target,
bool len64,
bool has_sign) {
unsigned int casenum = (len64?2:0)+(has_sign?0:1);
unsigned int casenum = (len64 ? 2 : 0) + (has_sign ? 0 : 1);
if (branch_target.is_bound()) {
address branch_addr = target(branch_target);
compare_and_branch_optimized(r1, r2, cond, branch_addr, len64, has_sign);
} else {
{
if (VM_Version::has_CompareBranch() && branch_target.is_near()) {
switch (casenum) {
case 0: z_crj( r1, r2, cond, branch_target); break;
case 1: z_clrj( r1, r2, cond, branch_target); break;
case 2: z_cgrj( r1, r2, cond, branch_target); break;
case 3: z_clgrj(r1, r2, cond, branch_target); break;
default: ShouldNotReachHere(); break;
}
} else {
switch (casenum) {
case 0: z_cr( r1, r2); break;
case 1: z_clr(r1, r2); break;
@ -2741,11 +2752,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
BLOCK_COMMENT("lookup_interface_method {");
// Load start of itable entries into itable_entry_addr.
z_llgf(vtable_len, Address(recv_klass, InstanceKlass::vtable_length_offset()));
z_llgf(vtable_len, Address(recv_klass, Klass::vtable_length_offset()));
z_sllg(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
// Loop over all itable entries until desired interfaceOop(Rinterface) found.
const int vtable_base_offset = in_bytes(InstanceKlass::vtable_start_offset());
const int vtable_base_offset = in_bytes(Klass::vtable_start_offset());
add2reg_with_index(itable_entry_addr,
vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes(),
@ -5927,8 +5938,7 @@ void MacroAssembler::update_byte_crc32(Register crc, Register val, Register tabl
* @param len register containing number of bytes
* @param table register pointing to CRC table
*/
void MacroAssembler::update_byteLoop_crc32(Register crc, Register buf, Register len, Register table,
Register data, bool invertCRC) {
void MacroAssembler::update_byteLoop_crc32(Register crc, Register buf, Register len, Register table, Register data) {
assert_different_registers(crc, buf, len, table, data);
Label L_mainLoop, L_done;
@ -5938,20 +5948,12 @@ void MacroAssembler::update_byteLoop_crc32(Register crc, Register buf, Register
z_ltr(len, len);
z_brnh(L_done);
if (invertCRC) {
not_(crc, noreg, false); // ~c
}
bind(L_mainLoop);
z_llgc(data, Address(buf, (intptr_t)0));// Current byte of input buffer (zero extended). Avoids garbage in upper half of register.
add2reg(buf, mainLoop_stepping); // Advance buffer position.
update_byte_crc32(crc, data, table);
z_brct(len, L_mainLoop); // Iterate.
if (invertCRC) {
not_(crc, noreg, false); // ~c
}
bind(L_done);
}
@ -5968,6 +5970,7 @@ void MacroAssembler::update_1word_crc32(Register crc, Register buf, Register tab
// c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
// crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
// #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
// Pre-calculate (constant) column offsets, use columns 4..7 for big-endian.
const int ix0 = 4*(4*CRC32_COLUMN_SIZE);
const int ix1 = 5*(4*CRC32_COLUMN_SIZE);
const int ix2 = 6*(4*CRC32_COLUMN_SIZE);
@ -5986,17 +5989,12 @@ void MacroAssembler::update_1word_crc32(Register crc, Register buf, Register tab
rotate_then_insert(t1, t0, 56-2, 63-2, 2-16, true); // ((c >> 16) & 0xff) << 2
rotate_then_insert(t0, t0, 56-2, 63-2, 2-24, true); // ((c >> 24) & 0xff) << 2
// Load pre-calculated table values.
// Use columns 4..7 for big-endian.
z_ly(t3, Address(table, t3, (intptr_t)ix0));
// XOR indexed table values to calculate updated crc.
z_ly(t2, Address(table, t2, (intptr_t)ix1));
z_ly(t1, Address(table, t1, (intptr_t)ix2));
z_ly(t0, Address(table, t0, (intptr_t)ix3));
// Calculate new crc from table values.
z_xr(t2, t3);
z_xr(t0, t1);
z_xr(t0, t2); // Now crc contains the final checksum value.
z_xy(t2, Address(table, t3, (intptr_t)ix0));
z_xy(t0, Address(table, t1, (intptr_t)ix2));
z_xr(t0, t2); // Now t0 contains the updated CRC value.
lgr_if_needed(crc, t0);
}
@ -6009,7 +6007,8 @@ void MacroAssembler::update_1word_crc32(Register crc, Register buf, Register tab
* uses Z_R10..Z_R13 as work register. Must be saved/restored by caller!
*/
void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len, Register table,
Register t0, Register t1, Register t2, Register t3) {
Register t0, Register t1, Register t2, Register t3,
bool invertCRC) {
assert_different_registers(crc, buf, len, table);
Label L_mainLoop, L_tail;
@ -6024,7 +6023,9 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
// The situation itself is detected and handled correctly by the conditional branches
// following aghi(len, -stepping) and aghi(len, +stepping).
not_(crc, noreg, false); // 1s complement of crc
if (invertCRC) {
not_(crc, noreg, false); // 1s complement of crc
}
#if 0
{
@ -6039,7 +6040,7 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
rotate_then_insert(ctr, ctr, 62, 63, 0, true); // TODO: should set cc
z_sgfr(len, ctr); // Remaining len after alignment.
update_byteLoop_crc32(crc, buf, ctr, table, data, false);
update_byteLoop_crc32(crc, buf, ctr, table, data);
}
#endif
@ -6047,21 +6048,23 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
z_srag(ctr, len, log_stepping);
z_brnh(L_tail);
z_lrvr(crc, crc); // Revert byte order because we are dealing with big-endian data.
z_lrvr(crc, crc); // Revert byte order because we are dealing with big-endian data.
rotate_then_insert(len, len, 64-log_stepping, 63, 0, true); // #bytes for tailLoop
BIND(L_mainLoop);
update_1word_crc32(crc, buf, table, 0, 0, crc, t1, t2, t3);
update_1word_crc32(crc, buf, table, 4, mainLoop_stepping, crc, t1, t2, t3);
z_brct(ctr, L_mainLoop); // Iterate.
z_brct(ctr, L_mainLoop); // Iterate.
z_lrvr(crc, crc); // Revert byte order back to original.
z_lrvr(crc, crc); // Revert byte order back to original.
// Process last few (<8) bytes of buffer.
BIND(L_tail);
update_byteLoop_crc32(crc, buf, len, table, data, false);
update_byteLoop_crc32(crc, buf, len, table, data);
not_(crc, noreg, false); // 1s complement of crc
if (invertCRC) {
not_(crc, noreg, false); // 1s complement of crc
}
}
/**
@ -6073,7 +6076,8 @@ void MacroAssembler::kernel_crc32_2word(Register crc, Register buf, Register len
* uses Z_R10..Z_R13 as work register. Must be saved/restored by caller!
*/
void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len, Register table,
Register t0, Register t1, Register t2, Register t3) {
Register t0, Register t1, Register t2, Register t3,
bool invertCRC) {
assert_different_registers(crc, buf, len, table);
Label L_mainLoop, L_tail;
@ -6087,7 +6091,9 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
// The situation itself is detected and handled correctly by the conditional branches
// following aghi(len, -stepping) and aghi(len, +stepping).
not_(crc, noreg, false); // 1s complement of crc
if (invertCRC) {
not_(crc, noreg, false); // 1s complement of crc
}
// Check for short (<4 bytes) buffer.
z_srag(ctr, len, log_stepping);
@ -6099,13 +6105,16 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
BIND(L_mainLoop);
update_1word_crc32(crc, buf, table, 0, mainLoop_stepping, crc, t1, t2, t3);
z_brct(ctr, L_mainLoop); // Iterate.
z_lrvr(crc, crc); // Revert byte order back to original.
// Process last few (<8) bytes of buffer.
BIND(L_tail);
update_byteLoop_crc32(crc, buf, len, table, data, false);
update_byteLoop_crc32(crc, buf, len, table, data);
not_(crc, noreg, false); // 1s complement of crc
if (invertCRC) {
not_(crc, noreg, false); // 1s complement of crc
}
}
/**
@ -6115,22 +6124,51 @@ void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len
* @param table register pointing to CRC table
*/
void MacroAssembler::kernel_crc32_1byte(Register crc, Register buf, Register len, Register table,
Register t0, Register t1, Register t2, Register t3) {
Register t0, Register t1, Register t2, Register t3,
bool invertCRC) {
assert_different_registers(crc, buf, len, table);
Register data = t0;
update_byteLoop_crc32(crc, buf, len, table, data, true);
if (invertCRC) {
not_(crc, noreg, false); // 1s complement of crc
}
update_byteLoop_crc32(crc, buf, len, table, data);
if (invertCRC) {
not_(crc, noreg, false); // 1s complement of crc
}
}
void MacroAssembler::kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp) {
void MacroAssembler::kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp,
bool invertCRC) {
assert_different_registers(crc, buf, len, table, tmp);
not_(crc, noreg, false); // ~c
if (invertCRC) {
not_(crc, noreg, false); // 1s complement of crc
}
z_llgc(tmp, Address(buf, (intptr_t)0)); // Current byte of input buffer (zero extended). Avoids garbage in upper half of register.
update_byte_crc32(crc, tmp, table);
not_(crc, noreg, false); // ~c
if (invertCRC) {
not_(crc, noreg, false); // 1s complement of crc
}
}
void MacroAssembler::kernel_crc32_singleByteReg(Register crc, Register val, Register table,
bool invertCRC) {
assert_different_registers(crc, val, table);
if (invertCRC) {
not_(crc, noreg, false); // 1s complement of crc
}
update_byte_crc32(crc, val, table);
if (invertCRC) {
not_(crc, noreg, false); // 1s complement of crc
}
}
//

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved.
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -1011,22 +1011,35 @@ class MacroAssembler: public Assembler {
int before = 0, int after = 0) PRODUCT_RETURN;
// Emitters for CRC32 calculation.
// A note on invertCRC:
// Unfortunately, internal representation of crc differs between CRC32 and CRC32C.
// CRC32 holds it's current crc value in the externally visible representation.
// CRC32C holds it's current crc value in internal format, ready for updating.
// Thus, the crc value must be bit-flipped before updating it in the CRC32 case.
// In the CRC32C case, it must be bit-flipped when it is given to the outside world (getValue()).
// The bool invertCRC parameter indicates whether bit-flipping is required before updates.
private:
void fold_byte_crc32(Register crc, Register table, Register val, Register tmp);
void fold_8bit_crc32(Register crc, Register table, Register tmp);
void update_byte_crc32( Register crc, Register val, Register table);
void update_byteLoop_crc32(Register crc, Register buf, Register len, Register table,
Register data, bool invertCRC);
Register data);
void update_1word_crc32(Register crc, Register buf, Register table, int bufDisp, int bufInc,
Register t0, Register t1, Register t2, Register t3);
public:
void update_byte_crc32( Register crc, Register val, Register table);
void kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp);
void kernel_crc32_singleByteReg(Register crc, Register val, Register table,
bool invertCRC);
void kernel_crc32_singleByte(Register crc, Register buf, Register len, Register table, Register tmp,
bool invertCRC);
void kernel_crc32_1byte(Register crc, Register buf, Register len, Register table,
Register t0, Register t1, Register t2, Register t3);
Register t0, Register t1, Register t2, Register t3,
bool invertCRC);
void kernel_crc32_1word(Register crc, Register buf, Register len, Register table,
Register t0, Register t1, Register t2, Register t3);
Register t0, Register t1, Register t2, Register t3,
bool invertCRC);
void kernel_crc32_2word(Register crc, Register buf, Register len, Register table,
Register t0, Register t1, Register t2, Register t3);
Register t0, Register t1, Register t2, Register t3,
bool invertCRC);
// Emitters for BigInteger.multiplyToLen intrinsic
// note: length of result array (zlen) is passed on the stack

View File

@ -1,76 +0,0 @@
/*
* 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/codeBuffer.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "memory/metaspaceShared.hpp"
// Generate the self-patching vtable method:
//
// This method will be called (as any other Klass virtual method) with
// the Klass itself as the first argument. Example:
//
// oop obj;
// int size = obj->klass()->klass_part()->oop_size(this);
//
// for which the virtual method call is Klass::oop_size();.
//
// The dummy method is called with the Klass object as the first
// operand, and an object as the second argument.
//
//=====================================================================
// All of the dummy methods in the vtable are essentially identical,
// differing only by an ordinal constant, and they bear no releationship
// to the original method which the caller intended. Also, there needs
// to be 'vtbl_list_size' instances of the vtable in order to
// differentiate between the 'vtable_list_size' original Klass objects.
#undef __
#define __ masm->
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
void** vtable,
char** md_top,
char* md_end,
char** mc_top,
char* mc_end) {
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
*(intptr_t *)(*md_top) = vtable_bytes;
*md_top += sizeof(intptr_t);
void** dummy_vtable = (void**)*md_top;
*vtable = dummy_vtable;
*md_top += vtable_bytes;
// Get ready to generate dummy methods.
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
MacroAssembler* masm = new MacroAssembler(&cb);
__ unimplemented();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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.
*
@ -73,7 +73,7 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
const char* error_message) {
InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
Klass* klass = SystemDictionary::well_known_klass(klass_id);
assert(temp_reg != Z_R0 && // Is used as base register!
temp_reg != noreg && temp2_reg != noreg, "need valid registers!");

View File

@ -6768,6 +6768,7 @@ instruct sllI_reg_imm(iRegI dst, iRegI src, immI nbits) %{
format %{ "SLL $dst,$src,$nbits\t# use RISC-like SLLG also for int" %}
ins_encode %{
int Nbit = $nbits$$constant;
assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
__ z_sllg($dst$$Register, $src$$Register, Nbit & (BitsPerJavaInteger - 1), Z_R0);
%}
ins_pipe(pipe_class_dummy);
@ -6841,6 +6842,7 @@ instruct sraI_reg_imm(iRegI dst, immI src, flagsReg cr) %{
format %{ "SRA $dst,$src" %}
ins_encode %{
int Nbit = $src$$constant;
assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
__ z_sra($dst$$Register, Nbit & (BitsPerJavaInteger - 1), Z_R0);
%}
ins_pipe(pipe_class_dummy);
@ -6893,6 +6895,7 @@ instruct srlI_reg_imm(iRegI dst, immI src) %{
format %{ "SRL $dst,$src" %}
ins_encode %{
int Nbit = $src$$constant;
assert((Nbit & (BitsPerJavaInteger - 1)) == Nbit, "Check shift mask in ideal graph");
__ z_srl($dst$$Register, Nbit & (BitsPerJavaInteger - 1), Z_R0);
%}
ins_pipe(pipe_class_dummy);

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved.
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -623,26 +623,6 @@ class StubGenerator: public StubCodeGenerator {
#define __ (Verbose ? (_masm->block_comment(FILE_AND_LINE),_masm):_masm)->
#endif
//----------------------------------------------------------------------
// The following routine generates a subroutine to throw an asynchronous
// UnknownError when an unsafe access gets a fault that could not be
// reasonably prevented by the programmer. (Example: SIGBUS/OBJERR.)
//
// Arguments:
// trapping PC: ??
//
// Results:
// Posts an asynchronous exception, skips the trapping instruction.
//
address generate_handler_for_unsafe_access() {
StubCodeMark mark(this, "StubRoutines", "handler_for_unsafe_access");
{
address start = __ pc();
__ unimplemented("StubRoutines::handler_for_unsafe_access", 86);
return start;
}
}
// Support for uint StubRoutine::zarch::partial_subtype_check(Klass
// sub, Klass super);
//
@ -2330,26 +2310,25 @@ class StubGenerator: public StubCodeGenerator {
}
// Arguments:
// Z_ARG1 - int crc
// Z_ARG2 - byte* buf
// Z_ARG3 - int length (of buffer)
//
// Result:
// Z_RET - int crc result
//
// Compute CRC32 function.
address generate_CRC32_updateBytes(const char* name) {
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", name);
unsigned int start_off = __ offset(); // Remember stub start address (is rtn value).
/**
* Arguments:
*
* Inputs:
* Z_ARG1 - int crc
* Z_ARG2 - byte* buf
* Z_ARG3 - int length (of buffer)
*
* Result:
* Z_RET - int crc result
**/
// Compute CRC function (generic, for all polynomials).
void generate_CRC_updateBytes(const char* name, Register table, bool invertCRC) {
// arguments to kernel_crc32:
Register crc = Z_ARG1; // Current checksum, preset by caller or result from previous call, int.
Register data = Z_ARG2; // source byte array
Register dataLen = Z_ARG3; // #bytes to process, int
Register table = Z_ARG4; // crc table address
// Register table = Z_ARG4; // crc table address. Preloaded and passed in by caller.
const Register t0 = Z_R10; // work reg for kernel* emitters
const Register t1 = Z_R11; // work reg for kernel* emitters
const Register t2 = Z_R12; // work reg for kernel* emitters
@ -2361,16 +2340,50 @@ class StubGenerator: public StubCodeGenerator {
// Crc used as int.
__ z_llgfr(dataLen, dataLen);
StubRoutines::zarch::generate_load_crc_table_addr(_masm, table);
__ resize_frame(-(6*8), Z_R0, true); // Resize frame to provide add'l space to spill 5 registers.
__ z_stmg(Z_R10, Z_R13, 1*8, Z_SP); // Spill regs 10..11 to make them available as work registers.
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3);
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, invertCRC);
__ z_lmg(Z_R10, Z_R13, 1*8, Z_SP); // Spill regs 10..11 back from stack.
__ resize_frame(+(6*8), Z_R0, true); // Resize frame to provide add'l space to spill 5 registers.
__ z_llgfr(Z_RET, crc); // Updated crc is function result. No copying required, just zero upper 32 bits.
__ z_br(Z_R14); // Result already in Z_RET == Z_ARG1.
}
// Compute CRC32 function.
address generate_CRC32_updateBytes(const char* name) {
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", name);
unsigned int start_off = __ offset(); // Remember stub start address (is rtn value).
assert(UseCRC32Intrinsics, "should not generate this stub (%s) with CRC32 intrinsics disabled", name);
BLOCK_COMMENT("CRC32_updateBytes {");
Register table = Z_ARG4; // crc32 table address.
StubRoutines::zarch::generate_load_crc_table_addr(_masm, table);
generate_CRC_updateBytes(name, table, true);
BLOCK_COMMENT("} CRC32_updateBytes");
return __ addr_at(start_off);
}
// Compute CRC32C function.
address generate_CRC32C_updateBytes(const char* name) {
__ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", name);
unsigned int start_off = __ offset(); // Remember stub start address (is rtn value).
assert(UseCRC32CIntrinsics, "should not generate this stub (%s) with CRC32C intrinsics disabled", name);
BLOCK_COMMENT("CRC32C_updateBytes {");
Register table = Z_ARG4; // crc32c table address.
StubRoutines::zarch::generate_load_crc32c_table_addr(_masm, table);
generate_CRC_updateBytes(name, table, false);
BLOCK_COMMENT("} CRC32C_updateBytes");
return __ addr_at(start_off);
}
@ -2441,9 +2454,13 @@ class StubGenerator: public StubCodeGenerator {
// Entry points that are platform specific.
if (UseCRC32Intrinsics) {
// We have no CRC32 table on z/Architecture.
StubRoutines::_crc_table_adr = (address)StubRoutines::zarch::_crc_table;
StubRoutines::_updateBytesCRC32 = generate_CRC32_updateBytes("CRC32_updateBytes");
StubRoutines::_crc_table_adr = (address)StubRoutines::zarch::_crc_table;
StubRoutines::_updateBytesCRC32 = generate_CRC32_updateBytes("CRC32_updateBytes");
}
if (UseCRC32CIntrinsics) {
StubRoutines::_crc32c_table_addr = (address)StubRoutines::zarch::_crc32c_table;
StubRoutines::_updateBytesCRC32C = generate_CRC32C_updateBytes("CRC32C_updateBytes");
}
// Comapct string intrinsics: Translate table for string inflate intrinsic. Used by trot instruction.
@ -2461,8 +2478,6 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false);
StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false);
StubRoutines::zarch::_handler_for_unsafe_access_entry = generate_handler_for_unsafe_access();
// Support for verify_oop (must happen after universe_init).
StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop_subroutine();

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved.
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -68,12 +68,11 @@ class zarch {
};
private:
static address _handler_for_unsafe_access_entry;
static int _atomic_memory_operation_lock;
static address _partial_subtype_check;
static juint _crc_table[CRC32_TABLES][CRC32_COLUMN_SIZE];
static juint _crc32c_table[CRC32_TABLES][CRC32_COLUMN_SIZE];
// Comapct string intrinsics: Translate table for string inflate intrinsic. Used by trot instruction.
static address _trot_table_addr;
@ -91,11 +90,11 @@ class zarch {
static int atomic_memory_operation_lock() { return _atomic_memory_operation_lock; }
static void set_atomic_memory_operation_lock(int value) { _atomic_memory_operation_lock = value; }
static address handler_for_unsafe_access_entry() { return _handler_for_unsafe_access_entry; }
static address partial_subtype_check() { return _partial_subtype_check; }
static void generate_load_absolute_address(MacroAssembler* masm, Register table, address table_addr, uint64_t table_contents);
static void generate_load_crc_table_addr(MacroAssembler* masm, Register table);
static void generate_load_crc32c_table_addr(MacroAssembler* masm, Register table);
// Comapct string intrinsics: Translate table for string inflate intrinsic. Used by trot instruction.
static void generate_load_trot_table_addr(MacroAssembler* masm, Register table);

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017 SAP SE. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -642,13 +642,6 @@ address TemplateInterpreterGenerator::generate_exception_handler_common(const ch
return entry;
}
// Unused, should never pass by.
address TemplateInterpreterGenerator::generate_continuation_for (TosState state) {
address entry = __ pc();
__ should_not_reach_here();
return entry;
}
address TemplateInterpreterGenerator::generate_return_entry_for (TosState state, int step, size_t index_size) {
address entry = __ pc();
@ -683,6 +676,10 @@ address TemplateInterpreterGenerator::generate_return_entry_for (TosState state,
__ z_llgc(size, Address(cache, offset, flags_offset+(sizeof(size_t)-1)));
__ z_sllg(size, size, Interpreter::logStackElementSize); // Each argument size in bytes.
__ z_agr(Z_esp, size); // Pop arguments.
__ check_and_handle_popframe(Z_thread);
__ check_and_handle_earlyret(Z_thread);
__ dispatch_next(state, step);
BLOCK_COMMENT("} return_entry");
@ -1964,7 +1961,7 @@ address TemplateInterpreterGenerator::generate_CRC32_update_entry() {
__ z_llgf(crc, 2 * wordSize, argP); // Current crc state, zero extend to 64 bit to have a clean register.
StubRoutines::zarch::generate_load_crc_table_addr(_masm, table);
__ kernel_crc32_singleByte(crc, data, dataLen, table, Z_R1);
__ kernel_crc32_singleByte(crc, data, dataLen, table, Z_R1, true);
// Restore caller sp for c2i case.
__ resize_frame_absolute(Z_R10, Z_R0, true); // Cut the stack back to where the caller started.
@ -2020,10 +2017,10 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI
// data = buf + off
BLOCK_COMMENT("CRC32_updateByteBuffer {");
__ z_llgf(crc, 5*wordSize, argP); // current crc state
__ z_lg(data, 3*wordSize, argP); // start of byte buffer
__ z_lg(data, 3*wordSize, argP); // start of byte buffer
__ z_agf(data, 2*wordSize, argP); // Add byte buffer offset.
__ z_lgf(dataLen, 1*wordSize, argP); // #bytes to process
} else { // Used for "updateBytes update".
} else { // Used for "updateBytes update".
// crc @ (SP + 4W) (32bit)
// buf @ (SP + 3W) (64bit ptr to byte array)
// off @ (SP + 2W) (32bit)
@ -2031,7 +2028,7 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI
// data = buf + off + base_offset
BLOCK_COMMENT("CRC32_updateBytes {");
__ z_llgf(crc, 4*wordSize, argP); // current crc state
__ z_lg(data, 3*wordSize, argP); // start of byte buffer
__ z_lg(data, 3*wordSize, argP); // start of byte buffer
__ z_agf(data, 2*wordSize, argP); // Add byte buffer offset.
__ z_lgf(dataLen, 1*wordSize, argP); // #bytes to process
__ z_aghi(data, arrayOopDesc::base_offset_in_bytes(T_BYTE));
@ -2041,7 +2038,7 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI
__ resize_frame(-(6*8), Z_R0, true); // Resize frame to provide add'l space to spill 5 registers.
__ z_stmg(t0, t3, 1*8, Z_SP); // Spill regs 10..13 to make them available as work registers.
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3);
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, true);
__ z_lmg(t0, t3, 1*8, Z_SP); // Spill regs 10..13 back from stack.
// Restore caller sp for c2i case.
@ -2060,8 +2057,73 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI
return NULL;
}
// Not supported
// Method entry for static native methods:
// int java.util.zip.CRC32C.updateBytes(int crc, byte[] b, int off, int len)
// int java.util.zip.CRC32C.updateDirectByteBuffer(int crc, long buf, int off, int len)
address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
if (UseCRC32CIntrinsics) {
uint64_t entry_off = __ offset();
// We don't generate local frame and don't align stack because
// we call stub code and there is no safepoint on this path.
// Load parameters.
// Z_esp is callers operand stack pointer, i.e. it points to the parameters.
const Register argP = Z_esp;
const Register crc = Z_ARG1; // crc value
const Register data = Z_ARG2; // address of java byte array
const Register dataLen = Z_ARG3; // source data len
const Register table = Z_ARG4; // address of crc32 table
const Register t0 = Z_R10; // work reg for kernel* emitters
const Register t1 = Z_R11; // work reg for kernel* emitters
const Register t2 = Z_R12; // work reg for kernel* emitters
const Register t3 = Z_R13; // work reg for kernel* emitters
// Arguments are reversed on java expression stack.
// Calculate address of start element.
if (kind == Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer) { // Used for "updateByteBuffer direct".
// crc @ (SP + 5W) (32bit)
// buf @ (SP + 3W) (64bit ptr to long array)
// off @ (SP + 2W) (32bit)
// dataLen @ (SP + 1W) (32bit)
// data = buf + off
BLOCK_COMMENT("CRC32C_updateDirectByteBuffer {");
__ z_llgf(crc, 5*wordSize, argP); // current crc state
__ z_lg(data, 3*wordSize, argP); // start of byte buffer
__ z_agf(data, 2*wordSize, argP); // Add byte buffer offset.
__ z_lgf(dataLen, 1*wordSize, argP); // #bytes to process
} else { // Used for "updateBytes update".
// crc @ (SP + 4W) (32bit)
// buf @ (SP + 3W) (64bit ptr to byte array)
// off @ (SP + 2W) (32bit)
// dataLen @ (SP + 1W) (32bit)
// data = buf + off + base_offset
BLOCK_COMMENT("CRC32C_updateBytes {");
__ z_llgf(crc, 4*wordSize, argP); // current crc state
__ z_lg(data, 3*wordSize, argP); // start of byte buffer
__ z_agf(data, 2*wordSize, argP); // Add byte buffer offset.
__ z_lgf(dataLen, 1*wordSize, argP); // #bytes to process
__ z_aghi(data, arrayOopDesc::base_offset_in_bytes(T_BYTE));
}
StubRoutines::zarch::generate_load_crc32c_table_addr(_masm, table);
__ resize_frame(-(6*8), Z_R0, true); // Resize frame to provide add'l space to spill 5 registers.
__ z_stmg(t0, t3, 1*8, Z_SP); // Spill regs 10..13 to make them available as work registers.
__ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, false);
__ z_lmg(t0, t3, 1*8, Z_SP); // Spill regs 10..13 back from stack.
// Restore caller sp for c2i case.
__ resize_frame_absolute(Z_R10, Z_R0, true); // Cut the stack back to where the caller started.
__ z_br(Z_R14);
BLOCK_COMMENT("} CRC32C_update{Bytes|DirectByteBuffer}");
return __ addr_at(entry_off);
}
return NULL;
}

View File

@ -3466,7 +3466,7 @@ void TemplateTable::invokevirtual_helper(Register index,
__ z_sllg(index, index, exact_log2(vtableEntry::size_in_bytes()));
__ mem2reg_opt(method,
Address(Z_tmp_2, index,
InstanceKlass::vtable_start_offset() + in_ByteSize(vtableEntry::method_offset_in_bytes())));
Klass::vtable_start_offset() + in_ByteSize(vtableEntry::method_offset_in_bytes())));
__ profile_arguments_type(Z_ARG4, method, Z_ARG5, true);
__ jump_from_interpreted(method, Z_ARG4);
BLOCK_COMMENT("} invokevirtual_helper");

View File

@ -111,13 +111,23 @@ void VM_Version::initialize() {
ContendedPaddingWidth = cache_line_size;
}
// On z/Architecture, the CRC32 intrinsics had to be implemented "by hand".
// They cannot be based on the CHECKSUM instruction which has been there
// since the very beginning (of z/Architecture). It computes "some kind of" a checksum
// which has nothing to do with the CRC32 algorithm.
// On z/Architecture, the CRC32/CRC32C intrinsics are implemented "by hand".
// TODO: Provide implementation based on the vector instructions available from z13.
// Note: The CHECKSUM instruction, which has been there since the very beginning
// (of z/Architecture), computes "some kind of" a checksum.
// It has nothing to do with the CRC32 algorithm.
if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) {
FLAG_SET_DEFAULT(UseCRC32Intrinsics, true);
}
if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) {
FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true);
}
// TODO: Provide implementation.
if (UseAdler32Intrinsics) {
warning("Adler32Intrinsics not available on this CPU.");
FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
}
// On z/Architecture, we take UseAES as the general switch to enable/disable the AES intrinsics.
// The specific, and yet to be defined, switches UseAESxxxIntrinsics will then be set
@ -195,11 +205,6 @@ void VM_Version::initialize() {
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
}
if (UseAdler32Intrinsics) {
warning("Adler32Intrinsics not available on this CPU.");
FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
}
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true);
}

View File

@ -83,7 +83,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
__ load_klass(rcvr_klass, Z_ARG1);
// Set method (in case of interpreted method), and destination address.
int entry_offset = in_bytes(InstanceKlass::vtable_start_offset()) +
int entry_offset = in_bytes(Klass::vtable_start_offset()) +
vtable_index * vtableEntry::size_in_bytes();
#ifndef PRODUCT
@ -96,8 +96,8 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
// worst case actual size
padding_bytes += __ load_const_size() - __ load_const_optimized_rtn_len(vtable_idx, vtable_index*vtableEntry::size_in_bytes(), true);
assert(Immediate::is_uimm12(in_bytes(InstanceKlass::vtable_length_offset())), "disp to large");
__ z_cl(vtable_idx, in_bytes(InstanceKlass::vtable_length_offset()), rcvr_klass);
assert(Immediate::is_uimm12(in_bytes(Klass::vtable_length_offset())), "disp to large");
__ z_cl(vtable_idx, in_bytes(Klass::vtable_length_offset()), rcvr_klass);
__ z_brl(L);
__ z_lghi(Z_ARG3, vtable_index); // Debug code, don't optimize.
__ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), Z_ARG1, Z_ARG3, false);
@ -187,11 +187,11 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
__ load_klass(rcvr_klass, Z_ARG1);
// Load start of itable entries into itable_entry.
__ z_llgf(vtable_len, Address(rcvr_klass, InstanceKlass::vtable_length_offset()));
__ z_llgf(vtable_len, Address(rcvr_klass, Klass::vtable_length_offset()));
__ z_sllg(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
// Loop over all itable entries until desired interfaceOop(Rinterface) found.
const int vtable_base_offset = in_bytes(InstanceKlass::vtable_start_offset());
const int vtable_base_offset = in_bytes(Klass::vtable_start_offset());
// Count unused bytes.
start_pc = __ pc();
__ add2reg_with_index(itable_entry_addr, vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes(), rcvr_klass, vtable_len);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2017, 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
@ -70,9 +70,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
bool check_exception=true
);
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
// base routine for all dispatches
void dispatch_base(TosState state, address* table);
@ -80,6 +77,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
InterpreterMacroAssembler(CodeBuffer* c)
: MacroAssembler(c) {}
virtual void check_and_handle_popframe(Register scratch_reg);
virtual void check_and_handle_earlyret(Register scratch_reg);
void jump_to_entry(address entry);
virtual void load_earlyret_value(TosState state);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2017, 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
@ -44,7 +44,7 @@ jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Hand
void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) {
address pc = _instructions->start() + pc_offset;
Handle obj = HotSpotObjectConstantImpl::object(constant);
Handle obj(THREAD, HotSpotObjectConstantImpl::object(constant));
jobject value = JNIHandles::make_local(obj());
if (HotSpotObjectConstantImpl::compressed(constant)) {
#ifdef _LP64

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2017, 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
@ -604,15 +604,15 @@ class MacroAssembler : public Assembler {
bool check_exception=true // flag which indicates if exception should be checked
);
public:
MacroAssembler(CodeBuffer* code) : Assembler(code) {}
// This routine should emit JVMTI PopFrame and ForceEarlyReturn handling code.
// The implementation is only non-empty for the InterpreterMacroAssembler,
// as only the interpreter handles and ForceEarlyReturn PopFrame requests.
virtual void check_and_handle_popframe(Register scratch_reg);
virtual void check_and_handle_earlyret(Register scratch_reg);
public:
MacroAssembler(CodeBuffer* code) : Assembler(code) {}
// Support for NULL-checks
//
// Generates code that causes a NULL OS exception if the content of reg is NULL.

View File

@ -1,120 +0,0 @@
/*
* Copyright (c) 2004, 2012, 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 "asm/macroAssembler.inline.hpp"
#include "asm/codeBuffer.hpp"
#include "memory/metaspaceShared.hpp"
// Generate the self-patching vtable method:
//
// This method will be called (as any other Klass virtual method) with
// the Klass itself as the first argument. Example:
//
// oop obj;
// int size = obj->klass()->oop_size(this);
//
// for which the virtual method call is Klass::oop_size();
//
// The dummy method is called with the Klass object as the first
// operand, and an object as the second argument.
//
//=====================================================================
// All of the dummy methods in the vtable are essentially identical,
// differing only by an ordinal constant, and they bear no relationship
// to the original method which the caller intended. Also, there needs
// to be 'vtbl_list_size' instances of the vtable in order to
// differentiate between the 'vtable_list_size' original Klass objects.
#define __ masm->
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
void** vtable,
char** md_top,
char* md_end,
char** mc_top,
char* mc_end) {
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
*(intptr_t *)(*md_top) = vtable_bytes;
*md_top += sizeof(intptr_t);
void** dummy_vtable = (void**)*md_top;
*vtable = dummy_vtable;
*md_top += vtable_bytes;
// Get ready to generate dummy methods.
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
MacroAssembler* masm = new MacroAssembler(&cb);
Label common_code;
for (int i = 0; i < vtbl_list_size; ++i) {
for (int j = 0; j < num_virtuals; ++j) {
dummy_vtable[num_virtuals * i + j] = (void*)masm->pc();
__ save(SP, -256, SP);
int offset = (i << 8) + j;
Register src = G0;
if (!Assembler::is_simm13(offset)) {
__ sethi(offset, L0);
src = L0;
offset = offset & ((1 << 10) - 1);
}
__ brx(Assembler::always, false, Assembler::pt, common_code);
// Load L0 with a value indicating vtable/offset pair.
// -- bits[ 7..0] (8 bits) which virtual method in table?
// -- bits[13..8] (6 bits) which virtual method table?
__ delayed()->or3(src, offset, L0);
}
}
__ bind(common_code);
// Expecting to be called with the "this" pointer in O0/I0 (where
// "this" is a Klass object). In addition, L0 was set (above) to
// identify the method and table.
// Look up the correct vtable pointer.
__ set((intptr_t)vtbl_list, L2); // L2 = address of new vtable list.
__ srl(L0, 8, L3); // Isolate L3 = vtable identifier.
__ sll(L3, LogBytesPerWord, L3);
__ ld_ptr(L2, L3, L3); // L3 = new (correct) vtable pointer.
__ st_ptr(L3, Address(I0, 0)); // Save correct vtable ptr in entry.
// Restore registers and jump to the correct method;
__ and3(L0, 255, L4); // Isolate L3 = method offset;.
__ sll(L4, LogBytesPerWord, L4);
__ ld_ptr(L3, L4, L4); // Get address of correct virtual method
__ jmpl(L4, 0, G0); // Jump to correct method.
__ delayed()->restore(); // Restore registers.
__ flush();
*mc_top = (char*)__ pc();
guarantee(*mc_top <= mc_end, "Insufficient space for method wrappers.");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2017, 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
@ -71,7 +71,7 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
Register temp_reg, Register temp2_reg,
const char* error_message) {
InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
Klass* klass = SystemDictionary::well_known_klass(klass_id);
bool did_save = false;
if (temp_reg == noreg || temp2_reg == noreg) {
temp_reg = L1;

View File

@ -374,6 +374,10 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
__ and3(flags, ConstantPoolCacheEntry::parameter_size_mask, parameter_size); // argument size in words
__ sll(parameter_size, Interpreter::logStackElementSize, parameter_size); // each argument size in bytes
__ add(Lesp, parameter_size, Lesp); // pop arguments
__ check_and_handle_popframe(Gtemp);
__ check_and_handle_earlyret(Gtemp);
__ dispatch_next(state, step);
return entry;
@ -466,12 +470,6 @@ address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state,
}
address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
address entry = __ pc();
__ dispatch_next(state);
return entry;
}
//
// Helpers for commoning out cases in the various type of method entries.
//

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -21,6 +21,8 @@
* questions.
*/
#include "precompiled.hpp"
#include "aot/compiledIC_aot.hpp"
#include "code/codeCache.hpp"
#include "memory/resourceArea.hpp"

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2017, 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
@ -48,9 +48,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
int number_of_arguments,
bool check_exceptions);
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
// base routine for all dispatches
void dispatch_base(TosState state, address* table, bool verifyoop = true);
@ -61,6 +58,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
void jump_to_entry(address entry);
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
void load_earlyret_value(TosState state);
// Interpreter-specific registers

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2017, 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
@ -65,7 +65,7 @@ jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Hand
void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) {
address pc = _instructions->start() + pc_offset;
Handle obj = HotSpotObjectConstantImpl::object(constant);
Handle obj(THREAD, HotSpotObjectConstantImpl::object(constant));
jobject value = JNIHandles::make_local(obj());
if (HotSpotObjectConstantImpl::compressed(constant)) {
#ifdef _LP64

View File

@ -71,12 +71,6 @@ class MacroAssembler: public Assembler {
bool check_exceptions // whether to check for pending exceptions after return
);
// These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
// The implementation is only non-empty for the InterpreterMacroAssembler,
// as only the interpreter handles PopFrame and ForceEarlyReturn requests.
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions = true);
// helpers for FPU flag access
@ -87,6 +81,12 @@ class MacroAssembler: public Assembler {
public:
MacroAssembler(CodeBuffer* code) : Assembler(code) {}
// These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
// The implementation is only non-empty for the InterpreterMacroAssembler,
// as only the interpreter handles PopFrame and ForceEarlyReturn requests.
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
// Support for NULL-checks
//
// Generates code that causes a NULL OS exception if the content of reg is NULL.

View File

@ -1,124 +0,0 @@
/*
* Copyright (c) 2004, 2012, 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 "asm/macroAssembler.hpp"
#include "asm/codeBuffer.hpp"
#include "memory/metaspaceShared.hpp"
// Generate the self-patching vtable method:
//
// This method will be called (as any other Klass virtual method) with
// the Klass itself as the first argument. Example:
//
// oop obj;
// int size = obj->klass()->oop_size(this);
//
// for which the virtual method call is Klass::oop_size();
//
// The dummy method is called with the Klass object as the first
// operand, and an object as the second argument.
//
//=====================================================================
// All of the dummy methods in the vtable are essentially identical,
// differing only by an ordinal constant, and they bear no relationship
// to the original method which the caller intended. Also, there needs
// to be 'vtbl_list_size' instances of the vtable in order to
// differentiate between the 'vtable_list_size' original Klass objects.
#define __ masm->
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
void** vtable,
char** md_top,
char* md_end,
char** mc_top,
char* mc_end) {
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
*(intptr_t *)(*md_top) = vtable_bytes;
*md_top += sizeof(intptr_t);
void** dummy_vtable = (void**)*md_top;
*vtable = dummy_vtable;
*md_top += vtable_bytes;
// Get ready to generate dummy methods.
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
MacroAssembler* masm = new MacroAssembler(&cb);
Label common_code;
for (int i = 0; i < vtbl_list_size; ++i) {
for (int j = 0; j < num_virtuals; ++j) {
dummy_vtable[num_virtuals * i + j] = (void*)masm->pc();
// Load rax, with a value indicating vtable/offset pair.
// -- bits[ 7..0] (8 bits) which virtual method in table?
// -- bits[12..8] (5 bits) which virtual method table?
// -- must fit in 13-bit instruction immediate field.
__ movl(rax, (i << 8) + j);
__ jmp(common_code);
}
}
__ bind(common_code);
#ifdef WIN32
// Expecting to be called with "thiscall" conventions -- the arguments
// are on the stack, except that the "this" pointer is in rcx.
#else
// Expecting to be called with Unix conventions -- the arguments
// are on the stack, including the "this" pointer.
#endif
// In addition, rax was set (above) to the offset of the method in the
// table.
#ifdef WIN32
__ push(rcx); // save "this"
#endif
__ mov(rcx, rax);
__ shrptr(rcx, 8); // isolate vtable identifier.
__ shlptr(rcx, LogBytesPerWord);
Address index(noreg, rcx, Address::times_1);
ExternalAddress vtbl((address)vtbl_list);
__ movptr(rdx, ArrayAddress(vtbl, index)); // get correct vtable address.
#ifdef WIN32
__ pop(rcx); // restore "this"
#else
__ movptr(rcx, Address(rsp, BytesPerWord)); // fetch "this"
#endif
__ movptr(Address(rcx, 0), rdx); // update vtable pointer.
__ andptr(rax, 0x00ff); // isolate vtable method index
__ shlptr(rax, LogBytesPerWord);
__ addptr(rax, rdx); // address of real method pointer.
__ jmp(Address(rax, 0)); // get real method pointer.
__ flush();
*mc_top = (char*)__ pc();
}

View File

@ -1,114 +0,0 @@
/*
* Copyright (c) 2004, 2012, 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 "asm/macroAssembler.hpp"
#include "asm/codeBuffer.hpp"
#include "memory/metaspaceShared.hpp"
// Generate the self-patching vtable method:
//
// This method will be called (as any other Klass virtual method) with
// the Klass itself as the first argument. Example:
//
// oop obj;
// int size = obj->klass()->oop_size(this);
//
// for which the virtual method call is Klass::oop_size();
//
// The dummy method is called with the Klass object as the first
// operand, and an object as the second argument.
//
//=====================================================================
// All of the dummy methods in the vtable are essentially identical,
// differing only by an ordinal constant, and they bear no relationship
// to the original method which the caller intended. Also, there needs
// to be 'vtbl_list_size' instances of the vtable in order to
// differentiate between the 'vtable_list_size' original Klass objects.
#define __ masm->
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
void** vtable,
char** md_top,
char* md_end,
char** mc_top,
char* mc_end) {
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
*(intptr_t *)(*md_top) = vtable_bytes;
*md_top += sizeof(intptr_t);
void** dummy_vtable = (void**)*md_top;
*vtable = dummy_vtable;
*md_top += vtable_bytes;
// Get ready to generate dummy methods.
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
MacroAssembler* masm = new MacroAssembler(&cb);
Label common_code;
for (int i = 0; i < vtbl_list_size; ++i) {
for (int j = 0; j < num_virtuals; ++j) {
dummy_vtable[num_virtuals * i + j] = (void*)masm->pc();
// Load eax with a value indicating vtable/offset pair.
// -- bits[ 7..0] (8 bits) which virtual method in table?
// -- bits[12..8] (5 bits) which virtual method table?
// -- must fit in 13-bit instruction immediate field.
__ movl(rax, (i << 8) + j);
__ jmp(common_code);
}
}
__ bind(common_code);
// Expecting to be called with "thiscall" convections -- the arguments
// are on the stack and the "this" pointer is in c_rarg0. In addition, rax
// was set (above) to the offset of the method in the table.
__ push(c_rarg1); // save & free register
__ push(c_rarg0); // save "this"
__ mov(c_rarg0, rax);
__ shrptr(c_rarg0, 8); // isolate vtable identifier.
__ shlptr(c_rarg0, LogBytesPerWord);
__ lea(c_rarg1, ExternalAddress((address)vtbl_list)); // ptr to correct vtable list.
__ addptr(c_rarg1, c_rarg0); // ptr to list entry.
__ movptr(c_rarg1, Address(c_rarg1, 0)); // get correct vtable address.
__ pop(c_rarg0); // restore "this"
__ movptr(Address(c_rarg0, 0), c_rarg1); // update vtable pointer.
__ andptr(rax, 0x00ff); // isolate vtable method index
__ shlptr(rax, LogBytesPerWord);
__ addptr(rax, c_rarg1); // address of real method pointer.
__ pop(c_rarg1); // restore register.
__ movptr(rax, Address(rax, 0)); // get real method pointer.
__ jmp(rax); // jump to the real method.
__ flush();
*mc_top = (char*)__ pc();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2017, 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
@ -65,7 +65,7 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
Register obj, SystemDictionary::WKID klass_id,
const char* error_message) {
InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
Klass* klass = SystemDictionary::well_known_klass(klass_id);
Register temp = rdi;
Register temp2 = noreg;
LP64_ONLY(temp2 = rscratch1); // used by MacroAssembler::cmpptr

View File

@ -171,16 +171,6 @@ address TemplateInterpreterGenerator::generate_exception_handler_common(
return entry;
}
address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
address entry = __ pc();
// NULL last_sp until next java call
__ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
__ dispatch_next(state);
return entry;
}
address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
address entry = __ pc();
@ -230,6 +220,17 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
__ movl(flags, Address(cache, index, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
__ andl(flags, ConstantPoolCacheEntry::parameter_size_mask);
__ lea(rsp, Address(rsp, flags, Interpreter::stackElementScale()));
const Register java_thread = NOT_LP64(rcx) LP64_ONLY(r15_thread);
if (JvmtiExport::can_pop_frame()) {
NOT_LP64(__ get_thread(java_thread));
__ check_and_handle_popframe(java_thread);
}
if (JvmtiExport::can_force_early_return()) {
NOT_LP64(__ get_thread(java_thread));
__ check_and_handle_earlyret(java_thread);
}
__ dispatch_next(state, step);
return entry;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -36,16 +36,19 @@ import java.util.Map;
import jdk.tools.jaotc.binformat.Symbol.Binding;
import jdk.tools.jaotc.binformat.Symbol.Kind;
import jdk.tools.jaotc.binformat.elf.JELFRelocObject;
import jdk.tools.jaotc.binformat.macho.JMachORelocObject;
import jdk.tools.jaotc.binformat.pecoff.JPECoffRelocObject;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
import org.graalvm.compiler.options.OptionValues;
/**
* A format-agnostic container class that holds various components of a binary.
*
* <p>
* This class holds information necessary to create platform-specific binary containers such as
* ELFContainer for Linux and Solaris operating systems or yet-to be created MachOContainer for Mac
* OS or PEContainer for MS Windows operating systems.
* ELFContainer for Linux and Solaris operating systems or MachOContainer for Mac OS or PEContainer
* for MS Windows operating systems.
*
* <p>
* Method APIs provided by this class are used to construct and populate platform-independent
@ -56,6 +59,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
* Methods to record and access code section contents, symbols and relocations are provided.
*/
public class BinaryContainer implements SymbolTable {
private final OptionValues graalOptions;
private final int codeSegmentSize;
@ -257,36 +261,40 @@ public class BinaryContainer implements SymbolTable {
* Allocates a {@code BinaryContainer} object whose content will be generated in a file with the
* prefix {@code prefix}. It also initializes internal code container, symbol table and
* relocation tables.
*
* @param graalOptions
*/
public BinaryContainer(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) {
public BinaryContainer(OptionValues graalOptions, GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) {
this.graalOptions = graalOptions;
this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize;
this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment;
// read only, code
codeContainer = new CodeContainer(".text", this);
extLinkageContainer = new CodeContainer(".hotspot.linkage.plt", this);
extLinkageContainer = new CodeContainer(".hs.plt.linkage", this);
// read only, info
configContainer = new ReadOnlyDataContainer(".config", this);
metaspaceNamesContainer = new ReadOnlyDataContainer(".metaspace.names", this);
metaspaceNamesContainer = new ReadOnlyDataContainer(".meta.names", this);
methodsOffsetsContainer = new ReadOnlyDataContainer(".methods.offsets", this);
klassesOffsetsContainer = new ReadOnlyDataContainer(".klasses.offsets", this);
klassesDependenciesContainer = new ReadOnlyDataContainer(".klasses.dependencies", this);
klassesOffsetsContainer = new ReadOnlyDataContainer(".kls.offsets", this);
klassesDependenciesContainer = new ReadOnlyDataContainer(".kls.dependencies", this);
headerContainer = new HeaderContainer(jvmVersion, new ReadOnlyDataContainer(".header", this));
stubsOffsetsContainer = new ReadOnlyDataContainer(".stubs.offsets", this);
codeSegmentsContainer = new ReadOnlyDataContainer(".code.segments", this);
constantDataContainer = new ReadOnlyDataContainer(".method.constdata", this);
constantDataContainer = new ReadOnlyDataContainer(".meth.constdata", this);
// needs relocation patching at load time by the loader
methodMetadataContainer = new ReadOnlyDataContainer(".method.metadata", this);
methodMetadataContainer = new ReadOnlyDataContainer(".meth.metadata", this);
// writable sections
metaspaceGotContainer = new ByteContainer(".metaspace.got", this);
metaspaceGotContainer = new ByteContainer(".meta.got", this);
metadataGotContainer = new ByteContainer(".metadata.got", this);
methodStateContainer = new ByteContainer(".method.state", this);
methodStateContainer = new ByteContainer(".meth.state", this);
oopGotContainer = new ByteContainer(".oop.got", this);
extLinkageGOTContainer = new ByteContainer(".hotspot.linkage.got", this);
extLinkageGOTContainer = new ByteContainer(".hs.got.linkage", this);
addGlobalSymbols();
@ -303,17 +311,17 @@ public class BinaryContainer implements SymbolTable {
graalHotSpotVMConfig.useCMSGC,
graalHotSpotVMConfig.useTLAB,
graalHotSpotVMConfig.useBiasedLocking,
TieredAOT.getValue(),
TieredAOT.getValue(graalOptions),
graalHotSpotVMConfig.enableContended,
graalHotSpotVMConfig.restrictContended,
graphBuilderConfig.omitAssertions()
};
int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().shift,
graalHotSpotVMConfig.getKlassEncoding().shift,
int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().getShift(),
graalHotSpotVMConfig.getKlassEncoding().getShift(),
graalHotSpotVMConfig.contendedPaddingWidth,
graalHotSpotVMConfig.fieldsAllocationStyle,
1 << graalHotSpotVMConfig.getOopEncoding().alignment,
1 << graalHotSpotVMConfig.logMinObjAlignment(),
graalHotSpotVMConfig.codeSegmentSize,
};
// @formatter:on
@ -497,11 +505,20 @@ public class BinaryContainer implements SymbolTable {
switch (osName) {
case "Linux":
case "SunOS":
JELFRelocObject elfso = new JELFRelocObject(this, outputFileName, aotVersion);
elfso.createELFRelocObject(relocationTable, symbolTable.values());
JELFRelocObject elfobj = new JELFRelocObject(this, outputFileName, aotVersion);
elfobj.createELFRelocObject(relocationTable, symbolTable.values());
break;
case "Mac OS X":
JMachORelocObject machobj = new JMachORelocObject(this, outputFileName);
machobj.createMachORelocObject(relocationTable, symbolTable.values());
break;
default:
throw new InternalError("Unsupported platform: " + osName);
if (osName.startsWith("Windows")) {
JPECoffRelocObject pecoffobj = new JPECoffRelocObject(this, outputFileName, aotVersion);
pecoffobj.createPECoffRelocObject(relocationTable, symbolTable.values());
break;
} else
throw new InternalError("Unsupported platform: " + osName);
}
}
@ -742,11 +759,11 @@ public class BinaryContainer implements SymbolTable {
}
/**
* Add constant data as follows. - Adding the data to the method.constdata section
* Add constant data as follows. - Adding the data to the meth.constdata section
*
* @param data
* @param alignment
* @return the offset in the method.constdata of the data
* @return the offset in the meth.constdata of the data
*/
public int addConstantData(byte[] data, int alignment) {
// Get the current length of the metaspaceNameContainer

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -25,7 +25,7 @@ package jdk.tools.jaotc.binformat;
import jdk.tools.jaotc.binformat.Symbol.Binding;
import jdk.tools.jaotc.binformat.Symbol.Kind;
import jdk.tools.jaotc.jnilibelf.ELFContainer;
import jdk.tools.jaotc.binformat.Container;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
@ -41,7 +41,7 @@ import java.util.Arrays;
* The method {@code putIntAt} updates the content of {@code contentBytes}. Changes are not
* reflected in {@code contentStream}.
*/
public class ByteContainer implements ELFContainer {
public class ByteContainer implements Container {
/**
* {@code ByteBuffer} representation of {@code BinaryContainer}.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -21,9 +21,9 @@
* questions.
*/
package jdk.tools.jaotc.jnilibelf;
package jdk.tools.jaotc.binformat;
public interface ELFContainer {
public interface Container {
String getContainerName();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -21,27 +21,31 @@
* questions.
*/
package jdk.tools.jaotc.jnilibelf.sunos;
package jdk.tools.jaotc.binformat;
/**
* Represent Elf_Cmd enums defined in libelf.h on SunOS as they slightly different from libelf.h on
* Linux.
* This class represents ia native OS specific Symbol
*/
public enum Elf_Cmd {
/** Must be first, 0. */
ELF_C_NULL,
public abstract class NativeSymbol {
ELF_C_READ,
ELF_C_WRITE,
ELF_C_CLR,
ELF_C_SET,
ELF_C_FDDONE,
ELF_C_FDREAD,
ELF_C_RDWR,
ELF_C_WRIMAGE,
ELF_C_IMAGE,
/** String table index. */
private int index;
/** Must be last. */
ELF_C_NUM
public NativeSymbol(int index) {
this.index = index;
}
/**
* @return the index
*/
public int getIndex() {
return index;
}
/**
* @index
*/
public void setIndex(int index) {
this.index = index;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -25,7 +25,7 @@ package jdk.tools.jaotc.binformat;
import java.util.Objects;
import jdk.tools.jaotc.jnilibelf.ELFSymbol;
import jdk.tools.jaotc.binformat.NativeSymbol;
public class Symbol {
@ -51,7 +51,7 @@ public class Symbol {
private final Kind kind;
private ByteContainer section;
private ELFSymbol elfSymbol;
private NativeSymbol nativeSymbol;
/**
* Create symbol info.
@ -77,12 +77,12 @@ public class Symbol {
return name;
}
public ELFSymbol getElfSymbol() {
return elfSymbol;
public NativeSymbol getNativeSymbol() {
return nativeSymbol;
}
public void setElfSymbol(ELFSymbol elfSymbol) {
this.elfSymbol = elfSymbol;
public void setNativeSymbol(NativeSymbol nativeSym) {
this.nativeSymbol = nativeSym;
}
public Binding getBinding() {

View File

@ -0,0 +1,256 @@
/*
* Copyright (c) 2016, 2017, 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.
*/
package jdk.tools.jaotc.binformat.elf;
/**
*
* Support for the creation of Elf Object files.
* Current support is limited to 64 bit x86_64.
*
*/
public class Elf {
/**
* Elf64_Ehdr structure defines
*/
public enum Elf64_Ehdr {
e_ident( 0,16),
e_type(16, 2),
e_machine(18, 2),
e_version(20, 4),
e_entry(24, 8),
e_phoff(32, 8),
e_shoff(40, 8),
e_flags(48, 4),
e_ehsize(52, 2),
e_phentsize(54, 2),
e_phnum(56, 2),
e_shentsize(58, 2),
e_shnum(60, 2),
e_shstrndx(62, 2);
public final int off;
public final int sz;
Elf64_Ehdr(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 64;
/**
* Elf64_Ehdr defines
*/
/**
* e_ident
*/
public static final int EI_MAG0 = 0;
public static final byte ELFMAG0 = 0x7f;
public static final int EI_MAG1 = 1;
public static final byte ELFMAG1 = 0x45;
public static final int EI_MAG2 = 2;
public static final byte ELFMAG2 = 0x4c;
public static final int EI_MAG3 = 3;
public static final byte ELFMAG3 = 0x46;
public static final int EI_CLASS = 4;
public static final byte ELFCLASS64 = 0x2;
public static final int EI_DATA = 5;
public static final byte ELFDATA2LSB = 0x1;
public static final int EI_VERSION = 6;
public static final byte EV_CURRENT = 0x1;
public static final int EI_OSABI = 7;
public static final byte ELFOSABI_NONE = 0x0;
/**
* e_type
*/
public static final char ET_REL = 0x1;
/**
* e_machine
*/
public static final char EM_NONE = 0;
public static final char EM_X86_64 = 62;
public static final char EM_AARCH64 = 183;
/**
* e_version
*/
// public static final int EV_CURRENT = 1;
}
/**
* Elf64_Shdr structure defines
*/
public enum Elf64_Shdr {
sh_name( 0, 4),
sh_type( 4, 4),
sh_flags( 8, 8),
sh_addr(16, 8),
sh_offset(24, 8),
sh_size(32, 8),
sh_link(40, 4),
sh_info(44, 4),
sh_addralign(48, 8),
sh_entsize(56, 8);
public final int off;
public final int sz;
Elf64_Shdr(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 64;
/**
* Elf64_Shdr defines
*/
/**
* sh_type
*/
public static final int SHT_PROGBITS = 0x1;
public static final int SHT_SYMTAB = 0x2;
public static final int SHT_STRTAB = 0x3;
public static final int SHT_RELA = 0x4;
public static final int SHT_NOBITS = 0x8;
public static final int SHT_REL = 0x9;
public static final byte SHN_UNDEF = 0x0;
/**
* sh_flag
*/
public static final int SHF_WRITE = 0x1;
public static final int SHF_ALLOC = 0x2;
public static final int SHF_EXECINSTR = 0x4;
}
/**
* Symbol table entry definitions
*
* Elf64_Sym structure defines
*/
public enum Elf64_Sym {
st_name( 0, 4),
st_info( 4, 1),
st_other( 5, 1),
st_shndx( 6, 2),
st_value( 8, 8),
st_size(16, 8);
public final int off;
public final int sz;
Elf64_Sym(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 24;
/* ST_BIND is in bits 4-7 of st_info. ST_TYPE is in low 4 bits */
public static final byte STB_LOCAL = 0x0;
public static final byte STB_GLOBAL = 0x1;
public static final byte STT_NOTYPE = 0x0;
public static final byte STT_OBJECT = 0x1;
public static final byte STT_FUNC = 0x2;
public static byte ELF64_ST_INFO(byte bind, byte type) {
return (byte)(((bind) << 4) + ((type) & 0xf));
}
}
/**
* Elf64_Rel structure defines
*/
public enum Elf64_Rel {
r_offset( 0, 8),
r_info( 8, 8);
public final int off;
public final int sz;
Elf64_Rel(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 16;
/**
* Relocation types
*/
public static final int R_X86_64_NONE = 0x0;
public static final int R_X86_64_64 = 0x1;
public static final int R_X86_64_PC32 = 0x2;
public static final int R_X86_64_PLT32 = 0x4;
public static final int R_X86_64_GOTPCREL = 0x9;
}
/**
* Elf64_Rela structure defines
*/
public enum Elf64_Rela {
r_offset( 0, 8),
r_info( 8, 8),
r_addend(16, 8);
public final int off;
public final int sz;
Elf64_Rela(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 24;
public static final int R_X86_64_NONE = 0x0;
public static final int R_X86_64_64 = 0x1;
public static final int R_X86_64_PC32 = 0x2;
public static final int R_X86_64_PLT32 = 0x4;
public static final int R_X86_64_GOTPCREL = 0x9;
public static long ELF64_R_INFO(int symidx, int type) {
return (((long)symidx << 32) + ((long)type));
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -20,20 +20,24 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.salver.serialize;
import java.io.Flushable;
import java.io.IOException;
package jdk.tools.jaotc.binformat.elf;
import org.graalvm.compiler.salver.writer.DumpWriter;
public interface Serializer extends Flushable {
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
DumpWriter getWriter();
public class ElfByteBuffer {
void setWriter(DumpWriter writer);
public static ByteBuffer allocate(int size) {
ByteBuffer buf = ByteBuffer.allocate(size);
if (ElfTargetInfo.getElfEndian() == Elf64_Ehdr.ELFDATA2LSB)
buf.order(ByteOrder.LITTLE_ENDIAN);
else
buf.order(ByteOrder.BIG_ENDIAN);
return (buf);
}
Serializer serialize(Object obj) throws IOException;
void reset() throws IOException;
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2016, 2017, 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.
*/
package jdk.tools.jaotc.binformat.elf;
import java.io.File;
import java.io.FileOutputStream;
public class ElfContainer {
File outputFile;
FileOutputStream outputStream;
long fileOffset;
public ElfContainer(String fileName, String aotVersion) {
String baseName;
outputFile = new File(fileName);
if (outputFile.exists()) {
outputFile.delete();
}
try {
outputStream = new FileOutputStream(outputFile);
} catch (Exception e) {
System.out.println("ElfContainer: Can't create file " + fileName);
}
fileOffset = 0;
}
public void close() {
try {
outputStream.close();
} catch (Exception e) {
System.out.println("ElfContainer: close failed");
}
}
public void writeBytes(byte [] bytes) {
if (bytes == null) return;
try {
outputStream.write(bytes);
} catch (Exception e) {
System.out.println("ElfContainer: writeBytes failed");
}
fileOffset += bytes.length;
}
// Write bytes to output file with up front alignment padding
public void writeBytes(byte [] bytes, int alignment) {
if (bytes == null) return;
try {
// Pad to alignment
while ((fileOffset & (long)(alignment-1)) != 0) {
outputStream.write(0);
fileOffset++;
}
outputStream.write(bytes);
} catch (Exception e) {
System.out.println("ElfContainer: writeBytes failed");
}
fileOffset += bytes.length;
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.elf;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.elf.Elf;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr;
import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
public class ElfHeader {
ByteBuffer header;
public ElfHeader() {
header = ElfByteBuffer.allocate(Elf64_Ehdr.totalsize);
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG0, Elf64_Ehdr.ELFMAG0);
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG1, Elf64_Ehdr.ELFMAG1);
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG2, Elf64_Ehdr.ELFMAG2);
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_MAG3, Elf64_Ehdr.ELFMAG3);
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_CLASS, Elf64_Ehdr.ELFCLASS64);
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_DATA, Elf64_Ehdr.ELFDATA2LSB);
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_VERSION, Elf64_Ehdr.EV_CURRENT);
header.put(Elf64_Ehdr.e_ident.off+Elf64_Ehdr.EI_OSABI, Elf64_Ehdr.ELFOSABI_NONE);
header.putChar(Elf64_Ehdr.e_type.off, Elf64_Ehdr.ET_REL);
header.putChar(Elf64_Ehdr.e_machine.off, ElfTargetInfo.getElfArch());
header.putInt(Elf64_Ehdr.e_version.off, Elf64_Ehdr.EV_CURRENT);
header.putChar(Elf64_Ehdr.e_ehsize.off, (char)Elf64_Ehdr.totalsize);
header.putChar(Elf64_Ehdr.e_shentsize.off, (char)Elf64_Shdr.totalsize);
}
// Update header with file offset of first section
public void setSectionOff(int offset) {
header.putLong(Elf64_Ehdr.e_shoff.off, offset);
}
// Update header with the number of total sections
public void setSectionNum(int count) {
header.putChar(Elf64_Ehdr.e_shnum.off, (char)count);
}
// Update header with the section index containing the
// string table for section names
public void setSectionStrNdx(int index) {
header.putChar(Elf64_Ehdr.e_shstrndx.off, (char)index);
}
public byte[] getArray() {
return header.array();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -20,32 +20,32 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.salver.writer;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
package jdk.tools.jaotc.binformat.elf;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public interface DumpWriter extends Closeable, Flushable, AutoCloseable {
import jdk.tools.jaotc.binformat.elf.Elf;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
DumpWriter write(byte b) throws IOException;
public class ElfRelocEntry {
ByteBuffer entry;
DumpWriter write(byte[] arr) throws IOException;
public ElfRelocEntry(int offset, int symno, int type, int addend) {
DumpWriter write(ByteBuffer buf) throws IOException;
entry = ElfByteBuffer.allocate(Elf64_Rela.totalsize);
DumpWriter write(CharSequence csq) throws IOException;
entry.putLong(Elf64_Rela.r_offset.off, offset);
entry.putLong(Elf64_Rela.r_info.off, Elf64_Rela.ELF64_R_INFO(symno,type));
entry.putLong(Elf64_Rela.r_addend.off, addend);
}
DumpWriter writeChar(char v) throws IOException;
DumpWriter writeShort(short v) throws IOException;
DumpWriter writeInt(int v) throws IOException;
DumpWriter writeLong(long v) throws IOException;
DumpWriter writeFloat(float v) throws IOException;
DumpWriter writeDouble(double v) throws IOException;
public byte[] getArray() {
return entry.array();
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2016, 2017, 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.
*/
package jdk.tools.jaotc.binformat.elf;
import java.util.ArrayList;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.elf.ElfRelocEntry;
import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
public class ElfRelocTable {
ArrayList<ArrayList<ElfRelocEntry>> relocEntries;
public ElfRelocTable(int numsects) {
relocEntries = new ArrayList<ArrayList<ElfRelocEntry>>(numsects);
for (int i = 0; i < numsects; i++)
relocEntries.add(new ArrayList<ElfRelocEntry>());
}
public void createRelocationEntry(int sectindex,
int offset,
int symno,
int type,
int addend) {
ElfRelocEntry entry = new ElfRelocEntry(offset,
symno,
type,
addend);
relocEntries.get(sectindex).add(entry);
}
public int getNumRelocs(int section_index) {
return relocEntries.get(section_index).size();
}
// Return the relocation entries for a single section
// or null if no entries added to section
public byte [] getRelocData(int section_index) {
ArrayList<ElfRelocEntry> entryList = relocEntries.get(section_index);
if (entryList.size() == 0)
return null;
ByteBuffer relocData = ElfByteBuffer.allocate(entryList.size() * Elf64_Rela.totalsize);
// Copy each entry to a single ByteBuffer
for (int i = 0; i < entryList.size(); i++) {
ElfRelocEntry entry = entryList.get(i);
relocData.put(entry.getArray());
}
return (relocData.array());
}
}

View File

@ -0,0 +1,181 @@
/*
* Copyright (c) 2016, 2017, 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.
*/
package jdk.tools.jaotc.binformat.elf;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.elf.Elf;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rel;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
public class ElfSection {
String name;
ByteBuffer section;
byte [] data;
boolean hasrelocations;
int sectionIndex;
/**
* String holding section name strings
*/
private static StringBuilder sectNameTab = new StringBuilder();
/**
* Keeps track of bytes in section string table since strTabContent.length()
* is number of chars, not bytes.
*/
private static int shStrTabNrOfBytes = 0;
public ElfSection(String sectName, byte [] sectData, int sectFlags,
int sectType, boolean hasRelocations, int sectIndex) {
long align;
section = ElfByteBuffer.allocate(Elf64_Shdr.totalsize);
// Return all 0's for NULL section
if (sectIndex == 0) {
sectNameTab.append('\0');
shStrTabNrOfBytes += 1;
data = null;
hasrelocations = false;
sectionIndex = 0;
return;
}
section.putInt(Elf64_Shdr.sh_name.off, shStrTabNrOfBytes);
sectNameTab.append(sectName).append('\0');
shStrTabNrOfBytes += (sectName.getBytes().length + 1);
name = sectName;
section.putInt(Elf64_Shdr.sh_type.off, sectType);
section.putLong(Elf64_Shdr.sh_flags.off, sectFlags);
section.putLong(Elf64_Shdr.sh_addr.off, 0);
section.putLong(Elf64_Shdr.sh_offset.off, 0);
if (sectName.equals(".shstrtab")) {
section.putLong(Elf64_Shdr.sh_size.off, shStrTabNrOfBytes);
data = sectNameTab.toString().getBytes();
}
else {
data = sectData;
section.putLong(Elf64_Shdr.sh_size.off, sectData.length);
}
section.putLong(Elf64_Shdr.sh_entsize.off, 0);
// Determine the alignment and entrysize
// based on type of section
switch (sectType) {
case Elf64_Shdr.SHT_PROGBITS:
if ((sectFlags & Elf64_Shdr.SHF_EXECINSTR) != 0)
align = 16;
else
align = 4;
break;
case Elf64_Shdr.SHT_SYMTAB:
align = 8;
section.putLong(Elf64_Shdr.sh_entsize.off, Elf64_Sym.totalsize);
break;
case Elf64_Shdr.SHT_STRTAB:
align = 1;
break;
case Elf64_Shdr.SHT_RELA:
align = 8;
section.putLong(Elf64_Shdr.sh_entsize.off, Elf64_Rela.totalsize);
break;
case Elf64_Shdr.SHT_REL:
align = 8;
section.putLong(Elf64_Shdr.sh_entsize.off, Elf64_Rel.totalsize);
break;
case Elf64_Shdr.SHT_NOBITS:
align = 4;
break;
default:
align = 8;
break;
}
section.putLong(Elf64_Shdr.sh_addralign.off, align);
hasrelocations = hasRelocations;
sectionIndex = sectIndex;
}
public String getName() {
return name;
}
public long getSize() {
return section.getLong(Elf64_Shdr.sh_size.off);
}
public int getDataAlign() {
return ((int)section.getLong(Elf64_Shdr.sh_addralign.off));
}
// Alignment requirements for the Elf64_Shdr structures
public static int getShdrAlign() {
return (4);
}
public byte[] getArray() {
return section.array();
}
public byte[] getDataArray() {
return data;
}
public void setOffset(long offset) {
section.putLong(Elf64_Shdr.sh_offset.off, offset);
}
public void setLink(int link) {
section.putInt(Elf64_Shdr.sh_link.off, link);
}
public void setInfo(int info) {
section.putInt(Elf64_Shdr.sh_info.off, info);
}
public long getOffset() {
return (section.getLong(Elf64_Shdr.sh_offset.off));
}
public boolean hasRelocations() {
return hasrelocations;
}
public int getSectionId() {
return sectionIndex;
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.elf;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.NativeSymbol;
import jdk.tools.jaotc.binformat.elf.Elf;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
public class ElfSymbol extends NativeSymbol {
ByteBuffer sym;
public ElfSymbol(int symbolindex, int strindex, byte type, byte bind,
byte sectindex, long offset, long size) {
super(symbolindex);
sym = ElfByteBuffer.allocate(Elf64_Sym.totalsize);
sym.putInt(Elf64_Sym.st_name.off, strindex);
sym.put(Elf64_Sym.st_info.off, Elf64_Sym.ELF64_ST_INFO(bind, type));
sym.put(Elf64_Sym.st_other.off, (byte)0);
// Section indexes start at 1 but we manage the index internally
// as 0 relative
sym.putChar(Elf64_Sym.st_shndx.off, (char)(sectindex));
sym.putLong(Elf64_Sym.st_value.off, offset);
sym.putLong(Elf64_Sym.st_size.off, size);
}
public byte[] getArray() {
return sym.array();
}
}

View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.elf;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import jdk.tools.jaotc.binformat.elf.Elf;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
import jdk.tools.jaotc.binformat.elf.ElfSymbol;
import jdk.tools.jaotc.binformat.elf.ElfByteBuffer;
public class ElfSymtab {
ArrayList<ElfSymbol>localSymbols = new ArrayList<ElfSymbol>();
ArrayList<ElfSymbol>globalSymbols = new ArrayList<ElfSymbol>();
/**
* number of symbols added
*/
int symbolCount;
/**
* String holding symbol table strings
*/
private StringBuilder strTabContent = new StringBuilder();
/**
* Keeps track of bytes in string table since strTabContent.length()
* is number of chars, not bytes.
*/
private int strTabNrOfBytes = 0;
public ElfSymtab() {
symbolCount = 0;
}
public ElfSymbol addSymbolEntry(String name, byte type, byte bind,
byte secHdrIndex, long offset, long size) {
// Get the current symbol index and append symbol name to string table.
int index;
ElfSymbol sym;
if (name.isEmpty()) {
index = 0;
strTabContent.append('\0');
strTabNrOfBytes += 1;
sym = new ElfSymbol(symbolCount, index, type, bind, secHdrIndex, offset, size);
localSymbols.add(sym);
} else {
// We can't trust strTabContent.length() since that is
// chars (UTF16), keep track of bytes on our own.
index = strTabNrOfBytes;
// strTabContent.append("_").append(name).append('\0');
strTabContent.append(name).append('\0');
// + 1 for null, + 1 for "_"
//strTabNrOfBytes += (name.getBytes().length + 1 + 1);
strTabNrOfBytes += (name.getBytes().length + 1);
sym = new ElfSymbol(symbolCount, index, type, bind, secHdrIndex, offset, size);
if ((bind & Elf64_Sym.STB_GLOBAL) != 0)
globalSymbols.add(sym);
else
localSymbols.add(sym);
}
symbolCount++;
return (sym);
}
// Update the symbol indexes once all symbols have been added.
// This is required since we'll be reordering the symbols in the
// file to be in the order of Local then global.
public void updateIndexes() {
int index = 0;
// Update the local symbol indexes
for (int i = 0; i < localSymbols.size(); i++ ) {
ElfSymbol sym = localSymbols.get(i);
sym.setIndex(index++);
}
// Update the global symbol indexes
for (int i = 0; i < globalSymbols.size(); i++ ) {
ElfSymbol sym = globalSymbols.get(i);
sym.setIndex(index++);
}
}
public int getNumLocalSyms() { return localSymbols.size(); }
public int getNumGlobalSyms() { return globalSymbols.size(); }
// Create a single byte array that contains the symbol table entries
public byte[] getSymtabArray() {
int index = 0;
ByteBuffer symtabData = ElfByteBuffer.allocate(symbolCount*Elf64_Sym.totalsize);
byte [] retarray;
updateIndexes();
// Add the local symbols
for (int i = 0; i < localSymbols.size(); i++ ) {
ElfSymbol sym = localSymbols.get(i);
byte [] arr = sym.getArray();
symtabData.put(arr);
}
// Add the global symbols
for (int i = 0; i < globalSymbols.size(); i++ ) {
ElfSymbol sym = globalSymbols.get(i);
byte [] arr = sym.getArray();
symtabData.put(arr);
}
retarray = symtabData.array();
return (retarray);
}
// Return the string table array
public byte[] getStrtabArray() {
byte [] strs = strTabContent.toString().getBytes();
return (strs);
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2016, 2017, 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.
*/
package jdk.tools.jaotc.binformat.elf;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.elf.Elf;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
/**
* Class that abstracts MACH-O target details.
*
*/
public class ElfTargetInfo {
/**
* Target architecture.
*/
private static final char arch;
/**
* Architecture endian-ness.
*/
private static final int endian = Elf64_Ehdr.ELFDATA2LSB;
/**
* Target OS string.
*/
private static String osName;
static {
// Find the target arch details
String archStr = System.getProperty("os.arch").toLowerCase();
if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) {
System.out.println("Only Little Endian byte order supported!");
}
if (archStr.equals("amd64") || archStr.equals("x86_64")) {
arch = Elf64_Ehdr.EM_X86_64;
} else {
System.out.println("Unsupported architecture " + archStr);
arch = Elf64_Ehdr.EM_NONE;
}
osName = System.getProperty("os.name").toLowerCase();
if (!osName.equals("linux") && !osName.equals("sunos")) {
System.out.println("Unsupported Operating System " + osName);
osName = "Unknown";
}
}
public static char getElfArch() {
return arch;
}
public static int getElfEndian() {
return endian;
}
public static String getOsName() {
return osName;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -30,6 +30,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import jdk.tools.jaotc.binformat.Container;
import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.ByteContainer;
import jdk.tools.jaotc.binformat.CodeContainer;
@ -37,36 +38,60 @@ import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
import jdk.tools.jaotc.binformat.Relocation;
import jdk.tools.jaotc.binformat.Relocation.RelocType;
import jdk.tools.jaotc.binformat.Symbol;
import jdk.tools.jaotc.binformat.NativeSymbol;
import jdk.tools.jaotc.binformat.Symbol.Binding;
import jdk.tools.jaotc.binformat.Symbol.Kind;
import jdk.tools.jaotc.jnilibelf.ELFContainer;
import jdk.tools.jaotc.jnilibelf.ELFSymbol;
import jdk.tools.jaotc.jnilibelf.JNIELFContainer;
import jdk.tools.jaotc.jnilibelf.JNIELFRelocation;
import jdk.tools.jaotc.jnilibelf.JNIELFTargetInfo;
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.ELF;
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Cmd;
import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Type;
import jdk.tools.jaotc.jnilibelf.Pointer;
import jdk.tools.jaotc.binformat.elf.Elf;
import jdk.tools.jaotc.binformat.elf.ElfSymbol;
import jdk.tools.jaotc.binformat.elf.ElfTargetInfo;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rel;
import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela;
public class JELFRelocObject {
private final BinaryContainer binContainer;
private final JNIELFContainer elfContainer;
private final ElfContainer elfContainer;
private final int segmentSize;
public JELFRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) {
this.binContainer = binContainer;
this.elfContainer = new JNIELFContainer(outputFileName, aotVersion);
this.elfContainer = new ElfContainer(outputFileName, aotVersion);
this.segmentSize = binContainer.getCodeSegmentSize();
}
private void createByteSection(ByteContainer c, int scnFlags) {
private ElfSection createByteSection(ArrayList<ElfSection>sections,
String sectName,
byte [] scnData,
boolean hasRelocs,
int scnFlags,
int scnType) {
ElfSection sect = new ElfSection(sectName,
scnData,
scnFlags,
scnType,
hasRelocs,
sections.size());
// Add this section to our list
sections.add(sect);
return (sect);
}
private void createByteSection(ArrayList<ElfSection>sections,
ByteContainer c, int scnFlags) {
ElfSection sect;
boolean hasRelocs = c.hasRelocations();
byte[] scnData = c.getByteArray();
int scnType = ELF.SHT_PROGBITS;
boolean zeros = !c.hasRelocations();
int scnType = Elf64_Shdr.SHT_PROGBITS;
boolean zeros = hasRelocs;
if (zeros) {
for (byte b : scnData) {
if (b != 0) {
@ -75,30 +100,30 @@ public class JELFRelocObject {
}
}
if (zeros) {
scnType = ELF.SHT_NOBITS;
scnType = Elf64_Shdr.SHT_NOBITS;
}
}
int sectionId = elfContainer.createSection(c.getContainerName(), scnData, Elf_Type.ELF_T_BYTE, segmentSize, scnType, scnFlags, ELF.SHN_UNDEF, 0);
c.setSectionId(sectionId);
// Clear out code section data to allow for GC
c.clear();
sect = createByteSection(sections, c.getContainerName(),
scnData, hasRelocs,
scnFlags, scnType);
c.setSectionId(sect.getSectionId());
}
private void createCodeSection(CodeContainer c) {
createByteSection(c, ELF.SHF_ALLOC | ELF.SHF_EXECINSTR);
private void createCodeSection(ArrayList<ElfSection>sections, CodeContainer c) {
createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_EXECINSTR);
}
private void createReadOnlySection(ReadOnlyDataContainer c) {
createByteSection(c, ELF.SHF_ALLOC);
private void createReadOnlySection(ArrayList<ElfSection>sections, ReadOnlyDataContainer c) {
createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC);
}
private void createReadWriteSection(ByteContainer c) {
createByteSection(c, ELF.SHF_ALLOC | ELF.SHF_WRITE);
private void createReadWriteSection(ArrayList<ElfSection>sections, ByteContainer c) {
createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_WRITE);
}
/**
* Create an ELF relocatable object using jdk.tools.jaotc.jnilibelf API.
* Create an ELF relocatable object
*
* @param relocationTable
* @param symbols
@ -106,145 +131,171 @@ public class JELFRelocObject {
*/
public void createELFRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException {
// Allocate ELF Header
elfContainer.createELFHeader(ELF.ET_REL);
ElfHeader eh = new ElfHeader();
ArrayList<ElfSection> sections = new ArrayList<ElfSection>();
// Create the null section
createByteSection(sections, null, null, false, 0, 0);
// Create text section
createCodeSection(binContainer.getCodeContainer());
createReadOnlySection(binContainer.getMetaspaceNamesContainer());
createReadOnlySection(binContainer.getKlassesOffsetsContainer());
createReadOnlySection(binContainer.getMethodsOffsetsContainer());
createReadOnlySection(binContainer.getKlassesDependenciesContainer());
createReadWriteSection(binContainer.getMetaspaceGotContainer());
createReadWriteSection(binContainer.getMetadataGotContainer());
createReadWriteSection(binContainer.getMethodStateContainer());
createReadWriteSection(binContainer.getOopGotContainer());
createReadWriteSection(binContainer.getMethodMetadataContainer());
createReadOnlySection(binContainer.getStubsOffsetsContainer());
createReadOnlySection(binContainer.getHeaderContainer().getContainer());
createReadOnlySection(binContainer.getCodeSegmentsContainer());
createReadOnlySection(binContainer.getConstantDataContainer());
createReadOnlySection(binContainer.getConfigContainer());
createCodeSection(sections, binContainer.getCodeContainer());
createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer());
createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer());
createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer());
createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer());
createReadWriteSection(sections, binContainer.getMetaspaceGotContainer());
createReadWriteSection(sections, binContainer.getMetadataGotContainer());
createReadWriteSection(sections, binContainer.getMethodStateContainer());
createReadWriteSection(sections, binContainer.getOopGotContainer());
createReadWriteSection(sections, binContainer.getMethodMetadataContainer());
createReadOnlySection(sections, binContainer.getStubsOffsetsContainer());
createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer());
createReadOnlySection(sections, binContainer.getCodeSegmentsContainer());
createReadOnlySection(sections, binContainer.getConstantDataContainer());
createReadOnlySection(sections, binContainer.getConfigContainer());
// createExternalLinkage();
createCodeSection(binContainer.getExtLinkageContainer());
createReadWriteSection(binContainer.getExtLinkageGOTContainer());
createCodeSection(sections, binContainer.getExtLinkageContainer());
createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
// Get ELF symbol data from BinaryContainer object's symbol tables
createELFSymbolTables(symbols);
ElfSymtab symtab = createELFSymbolTables(sections, symbols);
// Create string table section and symbol table sections in
// that order since symtab section needs to set the index of strtab in sh_link field
int strTabSectionIndex = elfContainer.createSection(".strtab", elfContainer.getStrTabContent().getBytes(StandardCharsets.UTF_8), Elf_Type.ELF_T_BYTE, 1, ELF.SHT_STRTAB, 0, ELF.SHN_UNDEF, 0);
// that order since symtab section needs to set the index of
// strtab in sh_link field
ElfSection strTabSection = createByteSection(sections,
".strtab",
symtab.getStrtabArray(),
false,
0,
Elf64_Shdr.SHT_STRTAB);
// Now create .symtab section with the symtab data constructed. On Linux, sh_link of symtab
// contains the index of string table its symbols reference and
// sh_info contains the index of first non-local symbol
int scnInfo = elfContainer.getFirstNonLocalSymbolIndex();
int symTabSectionIndex = elfContainer.createSection(".symtab", getELFSymbolTableData(), Elf_Type.ELF_T_SYM, 8, ELF.SHT_SYMTAB, ELF.SHF_ALLOC, strTabSectionIndex, scnInfo);
// Now create .symtab section with the symtab data constructed.
// On Linux, sh_link of symtab contains the index of string table
// its symbols reference and sh_info contains the index of first
// non-local symbol
ElfSection symTabSection = createByteSection(sections,
".symtab",
symtab.getSymtabArray(),
false,
0,
Elf64_Shdr.SHT_SYMTAB);
symTabSection.setLink(strTabSection.getSectionId());
symTabSection.setInfo(symtab.getNumLocalSyms());
buildRelocations(relocationTable, symTabSectionIndex);
ElfRelocTable elfRelocTable = createElfRelocTable(sections,
relocationTable);
createElfRelocSections(sections, elfRelocTable, symTabSection.getSectionId());
// Now, finally, after creating all sections, create shstrtab section
elfContainer.createSection(".shstrtab", elfContainer.getShStrTabContent().getBytes(StandardCharsets.UTF_8), Elf_Type.ELF_T_BYTE, 1, ELF.SHT_STRTAB, 0, ELF.SHN_UNDEF, 0);
ElfSection shStrTabSection = createByteSection(sections,
".shstrtab",
null,
false,
0,
Elf64_Shdr.SHT_STRTAB);
eh.setSectionStrNdx(shStrTabSection.getSectionId());
// Run elf_update
elfContainer.elfUpdate(Elf_Cmd.ELF_C_NULL);
// Update all section offsets and the Elf header section offset
// Write the Header followed by the contents of each section
// and then the section structures (section table).
int file_offset = Elf64_Ehdr.totalsize;
// Run elfUpdate again to write it out.
elfContainer.elfUpdate(Elf_Cmd.ELF_C_WRITE);
// Finish ELF processing
elfContainer.elfEnd();
// and round it up
file_offset = (file_offset + (sections.get(1).getDataAlign()-1)) &
~((sections.get(1).getDataAlign()-1));
// Calc file offsets for section data skipping null section
for (int i = 1; i < sections.size(); i++) {
ElfSection sect = sections.get(i);
file_offset = (file_offset + (sect.getDataAlign()-1)) &
~((sect.getDataAlign()-1));
sect.setOffset(file_offset);
file_offset += sect.getSize();
}
// Align the section table
file_offset = (file_offset + (ElfSection.getShdrAlign()-1)) &
~((ElfSection.getShdrAlign()-1));
// Update the Elf Header with the offset of the first Elf64_Shdr
// and the number of sections.
eh.setSectionOff(file_offset);
eh.setSectionNum(sections.size());
// Write out the Header
elfContainer.writeBytes(eh.getArray());
// Write out each section contents skipping null section
for (int i = 1; i < sections.size(); i++) {
ElfSection sect = sections.get(i);
elfContainer.writeBytes(sect.getDataArray(), sect.getDataAlign());
}
// Write out the section table
for (int i = 0; i < sections.size(); i++) {
ElfSection sect = sections.get(i);
elfContainer.writeBytes(sect.getArray(), ElfSection.getShdrAlign());
}
elfContainer.close();
}
private void buildRelocations(Map<Symbol, List<Relocation>> relocationTable, final int symTabSectionIndex) {
/*
* Create relocation sections. This needs to be done after symbol table sections were
* created since relocation entries will need indices of sections to which they apply.
*/
createELFRelocationTables(relocationTable);
createAllRelocationSections(new SymTabELFContainer(symTabSectionIndex));
}
/**
* Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF
* symbol table and ELF symbol table are created from BinaryContainer's symbol info.
*
* @param symbols
*/
private void createELFSymbolTables(Collection<Symbol> symbols) {
private ElfSymtab createELFSymbolTables(ArrayList<ElfSection> sections, Collection<Symbol> symbols) {
ElfSymtab symtab = new ElfSymtab();
// First, create the initial null symbol. This is a local symbol.
elfContainer.createELFSymbolEntry("", 0, 0, ELF.SHN_UNDEF, 0, 0, true);
symtab.addSymbolEntry("", (byte)0, (byte)0, Elf64_Shdr.SHN_UNDEF, 0, 0);
// Now create ELF symbol entries for all symbols.
for (Symbol symbol : symbols) {
// Get the index of section this symbol is defined in.
int secHdrIndex = symbol.getSection().getSectionId();
boolean isLocal = (symbol.getBinding() == Binding.LOCAL);
ELFSymbol elfSymbol = elfContainer.createELFSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), secHdrIndex, symbol.getSize(), symbol.getOffset(), isLocal);
symbol.setElfSymbol(elfSymbol);
ElfSymbol elfSymbol = symtab.addSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), (byte)secHdrIndex, symbol.getOffset(), symbol.getSize());
symbol.setNativeSymbol((NativeSymbol)elfSymbol);
}
return (symtab);
}
/**
* Construct ELF symbol data from BinaryContainer object's symbol tables.
*
* @return a byte array containing the symbol table
*/
private byte[] getELFSymbolTableData() {
final int entrySize = JNIELFTargetInfo.sizeOfSymtabEntry();
// First, add all local symbols.
List<ELFSymbol> localSymbols = elfContainer.getLocalSymbols();
List<ELFSymbol> globalSymbols = elfContainer.getGlobalSymbols();
int localSymCount = localSymbols.size();
int globalSymCount = globalSymbols.size();
byte[] sectionDataArray = new byte[(localSymCount + globalSymCount) * entrySize];
for (int i = 0; i < localSymCount; i++) {
ELFSymbol symbol = localSymbols.get(i);
Pointer address = symbol.getAddress();
address.copyBytesTo(sectionDataArray, entrySize, i * entrySize);
}
// Next, add all global symbols.
for (int i = 0; i < globalSymCount; i++) {
ELFSymbol symbol = globalSymbols.get(i);
Pointer address = symbol.getAddress();
address.copyBytesTo(sectionDataArray, entrySize, (localSymCount + i) * entrySize);
}
return sectionDataArray;
}
private static int getELFTypeOf(Symbol sym) {
private static byte getELFTypeOf(Symbol sym) {
Kind kind = sym.getKind();
if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) {
return ELF.STT_FUNC;
return Elf64_Sym.STT_FUNC;
} else if (kind == Symbol.Kind.OBJECT) {
return ELF.STT_OBJECT;
return Elf64_Sym.STT_OBJECT;
}
return ELF.STT_NOTYPE;
return Elf64_Sym.STT_NOTYPE;
}
private static int getELFBindOf(Symbol sym) {
private static byte getELFBindOf(Symbol sym) {
Binding binding = sym.getBinding();
if (binding == Symbol.Binding.GLOBAL) {
return ELF.STB_GLOBAL;
return Elf64_Sym.STB_GLOBAL;
}
return ELF.STB_LOCAL;
return Elf64_Sym.STB_LOCAL;
}
/**
* Construct ELF relocation section data from BinaryContainer object's relocation tables.
* Construct a Elf relocation table from BinaryContainer object's relocation tables.
*
* @param sections
* @param relocationTable
*/
private void createELFRelocationTables(Map<Symbol, List<Relocation>> relocationTable) {
private ElfRelocTable createElfRelocTable(ArrayList<ElfSection> sections,
Map<Symbol, List<Relocation>> relocationTable) {
ElfRelocTable elfRelocTable = new ElfRelocTable(sections.size());
/*
* For each of the symbols with associated relocation records, create an ELF relocation
* For each of the symbols with associated relocation records, create a Elf relocation
* entry.
*/
for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
@ -252,18 +303,26 @@ public class JELFRelocObject {
Symbol symbol = entry.getKey();
for (Relocation reloc : relocs) {
createRelocation(symbol, reloc);
createRelocation(symbol, reloc, elfRelocTable);
}
}
for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) {
createRelocation(entry.getKey(), entry.getValue());
createRelocation(entry.getKey(), entry.getValue(), elfRelocTable);
}
return (elfRelocTable);
}
private void createRelocation(Symbol symbol, Relocation reloc) {
private void createRelocation(Symbol symbol, Relocation reloc, ElfRelocTable elfRelocTable) {
RelocType relocType = reloc.getType();
int elfRelocType = getELFRelocationType(relocType);
ElfSymbol sym = (ElfSymbol)symbol.getNativeSymbol();
int symno = sym.getIndex();
int sectindex = reloc.getSection().getSectionId();
int offset = reloc.getOffset();
int addend = 0;
switch (relocType) {
case FOREIGN_CALL_DIRECT:
@ -271,85 +330,89 @@ public class JELFRelocObject {
case STUB_CALL_DIRECT:
case FOREIGN_CALL_INDIRECT_GOT: {
// Create relocation entry
int addend = -4; // Size in bytes of the patch location
// System.out.println("getELFRelocationType: PLT relocation type using X86_64_RELOC_BRANCH");
addend = -4; // Size in bytes of the patch location
// Relocation should be applied at the location after call operand
int offset = reloc.getOffset() + reloc.getSize() + addend;
elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
offset = offset + reloc.getSize() + addend;
break;
}
case FOREIGN_CALL_DIRECT_FAR: {
// Create relocation entry
int addend = -8; // Size in bytes of the patch location
addend = -8; // Size in bytes of the patch location
// Relocation should be applied at the location after call operand
// 10 = 2 (jmp [r]) + 8 (imm64)
int offset = reloc.getOffset() + reloc.getSize() + addend - 2;
elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
offset = offset + reloc.getSize() + addend - 2;
break;
}
case FOREIGN_CALL_INDIRECT:
case JAVA_CALL_INDIRECT:
case STUB_CALL_INDIRECT: {
// Do nothing.
break;
return;
}
case EXTERNAL_DATA_REFERENCE_FAR: {
// Create relocation entry
int addend = -4; // Size of 32-bit address of the GOT
addend = -4; // Size of 32-bit address of the GOT
/*
* Relocation should be applied before the test instruction to the move instruction.
* reloc.getOffset() points to the test instruction after the instruction that loads
* offset points to the test instruction after the instruction that loads
* the address of polling page. So set the offset appropriately.
*/
int offset = reloc.getOffset() + addend;
elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
offset = offset + addend;
break;
}
case METASPACE_GOT_REFERENCE:
case EXTERNAL_PLT_TO_GOT:
case STATIC_STUB_TO_STATIC_METHOD:
case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: {
int addend = -4; // Size of 32-bit address of the GOT
addend = -4; // Size of 32-bit address of the GOT
/*
* Relocation should be applied before the test instruction to the move instruction.
* reloc.getOffset() points to the test instruction after the instruction that loads
* the address of polling page. So set the offset appropriately.
* Relocation should be applied before the test instruction to
* the move instruction. reloc.getOffset() points to the
* test instruction after the instruction that loads the
* address of polling page. So set the offset appropriately.
*/
int offset = reloc.getOffset() + addend;
elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol());
offset = offset + addend;
break;
}
case EXTERNAL_GOT_TO_PLT:
case LOADTIME_ADDRESS: {
// this is load time relocations
elfContainer.createELFRelocationEntry(reloc.getSection(), reloc.getOffset(), elfRelocType, 0, symbol.getElfSymbol());
break;
}
default:
throw new InternalError("Unhandled relocation type: " + relocType);
}
elfRelocTable.createRelocationEntry(sectindex, offset, symno, elfRelocType, addend);
}
// TODO: Populate the mapping of RelocType to ELF relocation types
private static int getELFRelocationType(RelocType relocType) {
int elfRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH
switch (JNIELFTargetInfo.getELFArch()) {
case ELF.EM_X64_64:
switch (ElfTargetInfo.getElfArch()) {
case Elf64_Ehdr.EM_X86_64:
// Return R_X86_64_* entries based on relocType
if (relocType == RelocType.FOREIGN_CALL_DIRECT || relocType == RelocType.JAVA_CALL_DIRECT || relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PLT32;
if (relocType == RelocType.FOREIGN_CALL_DIRECT ||
relocType == RelocType.JAVA_CALL_DIRECT ||
relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
elfRelocType = Elf64_Rela.R_X86_64_PLT32;
} else if (relocType == RelocType.STUB_CALL_DIRECT) {
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PC32;
elfRelocType = Elf64_Rela.R_X86_64_PC32;
} else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) {
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_64;
} else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || relocType == RelocType.JAVA_CALL_INDIRECT || relocType == RelocType.STUB_CALL_INDIRECT) {
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_NONE;
elfRelocType = Elf64_Rela.R_X86_64_64;
} else if (relocType == RelocType.FOREIGN_CALL_INDIRECT ||
relocType == RelocType.JAVA_CALL_INDIRECT ||
relocType == RelocType.STUB_CALL_INDIRECT) {
elfRelocType = Elf64_Rela.R_X86_64_NONE;
} else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) {
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_GOTPCREL;
} else if (relocType == RelocType.METASPACE_GOT_REFERENCE || relocType == RelocType.EXTERNAL_PLT_TO_GOT || relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PC32;
} else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || relocType == RelocType.LOADTIME_ADDRESS) {
elfRelocType = JNIELFRelocation.X86_64.R_X86_64_64;
elfRelocType = Elf64_Rela.R_X86_64_GOTPCREL;
} else if (relocType == RelocType.METASPACE_GOT_REFERENCE ||
relocType == RelocType.EXTERNAL_PLT_TO_GOT ||
relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
elfRelocType = Elf64_Rela.R_X86_64_PC32;
} else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT ||
relocType == RelocType.LOADTIME_ADDRESS) {
elfRelocType = Elf64_Rela.R_X86_64_64;
} else {
assert false : "Unhandled relocation type: " + relocType;
}
@ -360,61 +423,26 @@ public class JELFRelocObject {
return elfRelocType;
}
private void createAllRelocationSections(ELFContainer symtab) {
for (Map.Entry<ELFContainer, ArrayList<Pointer>> entry : elfContainer.getRelocTables().entrySet()) {
createRelocationSection(entry.getKey(), entry.getValue(), symtab);
}
}
private void createElfRelocSections(ArrayList<ElfSection> sections,
ElfRelocTable elfRelocTable,
int symtabsectidx) {
private void createRelocationSection(ELFContainer container, ArrayList<Pointer> relocations, ELFContainer symtab) {
String secName = container.getContainerName();
int entrySize = JNIELFTargetInfo.sizeOfRelocEntry();
int numEntries = relocations.size();
byte[] sectionDataBytes = new byte[numEntries * entrySize];
// Grab count before we create new sections
int count = sections.size();
for (int index = 0; index < relocations.size(); index++) {
Pointer entry = relocations.get(index);
entry.copyBytesTo(sectionDataBytes, entrySize, index * entrySize);
}
String fullSecName;
// If relocDat is non-null create section
if (sectionDataBytes.length > 0) {
int scnType;
Elf_Type dataType;
if (JNIELFTargetInfo.createReloca() == 0) {
scnType = ELF.SHT_REL;
dataType = Elf_Type.ELF_T_REL;
fullSecName = ".rel" + secName;
} else {
scnType = ELF.SHT_RELA;
dataType = Elf_Type.ELF_T_RELA;
fullSecName = ".rela" + secName;
for (int i = 0; i < count; i++) {
if (elfRelocTable.getNumRelocs(i) > 0) {
ElfSection sect = sections.get(i);
String relname = ".rela" + sect.getName();
ElfSection relocSection = createByteSection(sections,
relname,
elfRelocTable.getRelocData(i),
false,
0,
Elf64_Shdr.SHT_RELA);
relocSection.setLink(symtabsectidx);
relocSection.setInfo(sect.getSectionId());
}
// assert compareBytes(relocData.toByteArray(), sectionDataBytes) : "******* Bad array
// copy";
// sh_link holds the index of section header of symbol table associated with this
// relocation table.
// sh_info holds the index of section header to which this relocation table applies
// to.
elfContainer.createSection(fullSecName, sectionDataBytes, dataType, 8, scnType, ELF.SHF_ALLOC, symtab.getSectionId(), container.getSectionId());
}
}
private static class SymTabELFContainer implements ELFContainer {
private final int symTabSectionIndex;
public SymTabELFContainer(int symTabSectionIndex) {
this.symTabSectionIndex = symTabSectionIndex;
}
@Override
public String getContainerName() {
return ".symtab";
}
@Override
public int getSectionId() {
return symTabSectionIndex;
}
}
}

View File

@ -0,0 +1,474 @@
/*
* Copyright (c) 2017, 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.
*/
/*
*
* File Layout generated by JMachORelocObject
*
* MachO Header
* Load Commands
* LC_SEGMENT_64
* - Sections
* LC_VERSION_MIN_MAX
* LC_SYMTAB
* LC_DYSYMTAB
* Section Data
* Relocation entries
* Symbol table
*
*/
package jdk.tools.jaotc.binformat.macho;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.ByteContainer;
import jdk.tools.jaotc.binformat.CodeContainer;
import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
import jdk.tools.jaotc.binformat.Relocation;
import jdk.tools.jaotc.binformat.Relocation.RelocType;
import jdk.tools.jaotc.binformat.Symbol;
import jdk.tools.jaotc.binformat.NativeSymbol;
import jdk.tools.jaotc.binformat.Symbol.Binding;
import jdk.tools.jaotc.binformat.Symbol.Kind;
import jdk.tools.jaotc.binformat.macho.MachO;
import jdk.tools.jaotc.binformat.macho.MachO.section_64;
import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
import jdk.tools.jaotc.binformat.macho.MachO.segment_command_64;
import jdk.tools.jaotc.binformat.macho.MachO.version_min_command;
import jdk.tools.jaotc.binformat.macho.MachO.symtab_command;
import jdk.tools.jaotc.binformat.macho.MachO.dysymtab_command;
import jdk.tools.jaotc.binformat.macho.MachO.nlist_64;
import jdk.tools.jaotc.binformat.macho.MachO.reloc_info;
import jdk.tools.jaotc.binformat.macho.MachOContainer;
import jdk.tools.jaotc.binformat.macho.MachOTargetInfo;
import jdk.tools.jaotc.binformat.macho.MachOSymtab;
import jdk.tools.jaotc.binformat.macho.MachORelocTable;
public class JMachORelocObject {
private final BinaryContainer binContainer;
private final MachOContainer machoContainer;
private final int segmentSize;
public JMachORelocObject(BinaryContainer binContainer, String outputFileName) {
this.binContainer = binContainer;
this.machoContainer = new MachOContainer(outputFileName);
this.segmentSize = binContainer.getCodeSegmentSize();
}
private void createByteSection(ArrayList<MachOSection>sections,
ByteContainer c, String sectName, String segName, int scnFlags) {
if (c.getByteArray().length == 0) {
// System.out.println("Skipping creation of " + sectName + " section, no data\n");
}
MachOSection sect = new MachOSection(sectName,
segName,
c.getByteArray(),
scnFlags,
c.hasRelocations());
// Add this section to our list
sections.add(sect);
// Record the section Id (0 relative)
c.setSectionId(sections.size()-1);
// TODO: Clear out code section data to allow for GC
// c.clear();
}
private void createCodeSection(ArrayList<MachOSection>sections, CodeContainer c) {
createByteSection(sections, c, /*c.getContainerName()*/ "__text", "__TEXT",
section_64.S_ATTR_PURE_INSTRUCTIONS|
section_64.S_ATTR_SOME_INSTRUCTIONS);
}
private void createReadOnlySection(ArrayList<MachOSection>sections, ReadOnlyDataContainer c) {
createByteSection(sections, c, c.getContainerName(), "__TEXT",
section_64.S_ATTR_SOME_INSTRUCTIONS);
}
private void createReadWriteSection(ArrayList<MachOSection>sections, ByteContainer c) {
createByteSection(sections, c, c.getContainerName(), "__DATA", section_64.S_REGULAR);
}
/**
* Create an MachO relocatable object
*
* @param relocationTable
* @param symbols
* @throws IOException throws {@code IOException} as a result of file system access failures.
*/
public void createMachORelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException {
// Allocate MachO Header
// with 4 load commands
// LC_SEGMENT_64
// LC_VERSION_MIN_MACOSX
// LC_SYMTAB
// LC_DYSYMTAB
MachOHeader mh = new MachOHeader();
ArrayList<MachOSection> sections = new ArrayList<MachOSection>();
// Create Sections contained in the main Segment LC_SEGMENT_64
createCodeSection(sections, binContainer.getCodeContainer());
createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer());
createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer());
createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer());
createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer());
createReadWriteSection(sections, binContainer.getMetaspaceGotContainer());
createReadWriteSection(sections, binContainer.getMetadataGotContainer());
createReadWriteSection(sections, binContainer.getMethodStateContainer());
createReadWriteSection(sections, binContainer.getOopGotContainer());
createReadWriteSection(sections, binContainer.getMethodMetadataContainer());
createReadOnlySection(sections, binContainer.getStubsOffsetsContainer());
createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer());
createReadOnlySection(sections, binContainer.getCodeSegmentsContainer());
createReadOnlySection(sections, binContainer.getConstantDataContainer());
createReadOnlySection(sections, binContainer.getConfigContainer());
// createExternalLinkage();
createCodeSection(sections, binContainer.getExtLinkageContainer());
createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
// Update the Header sizeofcmds size.
// This doesn't include the Header struct size
mh.setCmdSizes(4, segment_command_64.totalsize +
(section_64.totalsize * sections.size()) +
version_min_command.totalsize +
symtab_command.totalsize +
dysymtab_command.totalsize);
// Initialize file offset for data past commands
int file_offset = mach_header_64.totalsize + mh.getCmdSize();
// and round it up
file_offset = (file_offset + (sections.get(0).getAlign()-1)) & ~((sections.get(0).getAlign()-1));
long address = 0;
int segment_offset = file_offset;
for (int i = 0; i < sections.size(); i++) {
MachOSection sect = sections.get(i);
file_offset = (file_offset + (sect.getAlign()-1)) & ~((sect.getAlign()-1));
address = (address + (sect.getAlign()-1)) & ~((sect.getAlign()-1));
sect.setOffset(file_offset);
sect.setAddr(address);
file_offset += sect.getSize();
address += sect.getSize();
}
// File size for Segment data
int segment_size = file_offset - segment_offset;
// Create the LC_SEGMENT_64 Segment which contains the MachOSections
MachOSegment seg = new MachOSegment(segment_command_64.totalsize +
(section_64.totalsize * sections.size()),
segment_offset,
segment_size,
sections.size());
MachOVersion vers = new MachOVersion();
// Get symbol data from BinaryContainer object's symbol tables
MachOSymtab symtab = createMachOSymbolTables(sections, symbols);
// Create LC_DYSYMTAB command
MachODySymtab dysymtab = new MachODySymtab(symtab.getNumLocalSyms(),
symtab.getNumGlobalSyms(),
symtab.getNumUndefSyms());
// Create the Relocation Tables
MachORelocTable machORelocs = createMachORelocTable(sections, relocationTable, symtab);
// Calculate file offset for relocation data
file_offset = (file_offset + (machORelocs.getAlign()-1)) & ~((machORelocs.getAlign()-1));
// Update relocation sizing information in each section
for (int i = 0; i < sections.size(); i++) {
MachOSection sect = sections.get(i);
if (sect.hasRelocations()) {
int nreloc = machORelocs.getNumRelocs(i);
sect.setReloff(file_offset);
sect.setRelcount(nreloc);
file_offset += (nreloc * reloc_info.totalsize);
}
}
// Calculate and set file offset for symbol table data
file_offset = (file_offset + (symtab.getAlign()-1)) & ~((symtab.getAlign()-1));
symtab.setOffset(file_offset);
// Write Out Header
machoContainer.writeBytes(mh.getArray());
// Write out first Segment
machoContainer.writeBytes(seg.getArray());
// Write out sections within first Segment
for (int i = 0; i < sections.size(); i++) {
MachOSection sect = sections.get(i);
machoContainer.writeBytes(sect.getArray());
}
// Write out LC_VERSION_MIN_MACOSX command
machoContainer.writeBytes(vers.getArray());
// Write out LC_SYMTAB command
symtab.calcSizes();
machoContainer.writeBytes(symtab.getCmdArray());
// Write out LC_DYSYMTAB command
machoContainer.writeBytes(dysymtab.getArray());
// Write out data associated with each Section
for (int i = 0; i < sections.size(); i++) {
MachOSection sect = sections.get(i);
machoContainer.writeBytes(sect.getDataArray(), sect.getAlign());
}
// Write out the relocation tables for all sections
for (int i = 0; i < sections.size(); i++) {
if (machORelocs.getNumRelocs(i) > 0)
machoContainer.writeBytes(machORelocs.getRelocData(i), machORelocs.getAlign());
}
// Write out data associated with LC_SYMTAB
machoContainer.writeBytes(symtab.getDataArray(), symtab.getAlign());
machoContainer.close();
}
/**
* Construct MachO symbol data from BinaryContainer object's symbol tables. Both dynamic MachO
* symbol table and MachO symbol table are created from BinaryContainer's symbol info.
*
* @param symbols
* @param symtab
*/
private MachOSymtab createMachOSymbolTables(ArrayList<MachOSection>sections,
Collection<Symbol> symbols) {
MachOSymtab symtab = new MachOSymtab();
// First, create the initial null symbol. This is a local symbol.
symtab.addSymbolEntry("", (byte)nlist_64.N_UNDF, (byte)0, (long)0);
// Now create MachO symbol entries for all symbols.
for (Symbol symbol : symbols) {
int sectionId = symbol.getSection().getSectionId();
// Symbol offsets are relative to the section memory addr
long sectionAddr = sections.get(sectionId).getAddr();
MachOSymbol machoSymbol = symtab.addSymbolEntry(symbol.getName(),
getMachOTypeOf(symbol),
(byte)sectionId,
symbol.getOffset() + sectionAddr);
symbol.setNativeSymbol((NativeSymbol)machoSymbol);
}
// Now that all symbols are enterred, update the
// symbol indexes. This is necessary since they will
// be reordered based on local, global and undefined.
symtab.updateIndexes();
return (symtab);
}
private static byte getMachOTypeOf(Symbol sym) {
Kind kind = sym.getKind();
byte type = nlist_64.N_UNDF;
// Global or Local
if (sym.getBinding() == Symbol.Binding.GLOBAL)
type = nlist_64.N_EXT;
// If Function or Data, add section type
if (kind == Symbol.Kind.NATIVE_FUNCTION ||
kind == Symbol.Kind.JAVA_FUNCTION ||
kind == Symbol.Kind.OBJECT) {
type |= (nlist_64.N_SECT);
}
return (type);
}
/**
* Construct a MachO relocation table from BinaryContainer object's relocation tables.
*
* @param sections
* @param relocationTable
* @param symtab
*/
private MachORelocTable createMachORelocTable(ArrayList<MachOSection> sections,
Map<Symbol, List<Relocation>> relocationTable,
MachOSymtab symtab) {
MachORelocTable machORelocTable = new MachORelocTable(sections.size());
/*
* For each of the symbols with associated relocation records, create a MachO relocation
* entry.
*/
for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
List<Relocation> relocs = entry.getValue();
Symbol symbol = entry.getKey();
for (Relocation reloc : relocs) {
createRelocation(symbol, reloc, machORelocTable);
}
}
for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) {
createRelocation(entry.getKey(), entry.getValue(), machORelocTable);
}
return (machORelocTable);
}
private void createRelocation(Symbol symbol, Relocation reloc, MachORelocTable machORelocTable) {
RelocType relocType = reloc.getType();
int machORelocType = getMachORelocationType(relocType);
MachOSymbol sym = (MachOSymbol)symbol.getNativeSymbol();
int symno = sym.getIndex();
int sectindex = reloc.getSection().getSectionId();
int offset = reloc.getOffset();
int pcrel = 0;
int length = 0;
int isextern = 1;
/*
System.out.println("reloctype: " + relocType + " size is " +
reloc.getSize() + " offset is " + offset +
" Section Index is " + (sectindex) +
" Symbol Index is " + symno +
" Symbol Name is " + symbol.getName() + "\n");
*/
switch (relocType) {
case FOREIGN_CALL_DIRECT:
case JAVA_CALL_DIRECT:
case STUB_CALL_DIRECT:
case FOREIGN_CALL_INDIRECT_GOT: {
// Create relocation entry
// System.out.println("getMachORelocationType: PLT relocation type using X86_64_RELOC_BRANCH");
int addend = -4; // Size in bytes of the patch location
// Relocation should be applied at the location after call operand
offset = offset + reloc.getSize() + addend;
pcrel = 1; length = 2;
break;
}
case FOREIGN_CALL_DIRECT_FAR: {
// Create relocation entry
int addend = -8; // Size in bytes of the patch location
// Relocation should be applied at the location after call operand
// 10 = 2 (jmp [r]) + 8 (imm64)
offset = offset + reloc.getSize() + addend - 2;
pcrel = 0; length = 3;
break;
}
case FOREIGN_CALL_INDIRECT:
case JAVA_CALL_INDIRECT:
case STUB_CALL_INDIRECT: {
// Do nothing.
return;
}
case EXTERNAL_DATA_REFERENCE_FAR: {
// Create relocation entry
int addend = -4; // Size of 32-bit address of the GOT
/*
* Relocation should be applied before the test instruction to the move instruction.
* offset points to the test instruction after the instruction that loads
* the address of polling page. So set the offset appropriately.
*/
offset = offset + addend;
pcrel = 0; length = 2;
break;
}
case METASPACE_GOT_REFERENCE:
case EXTERNAL_PLT_TO_GOT:
case STATIC_STUB_TO_STATIC_METHOD:
case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: {
int addend = -4; // Size of 32-bit address of the GOT
/*
* Relocation should be applied before the test instruction to
* the move instruction. reloc.getOffset() points to the
* test instruction after the instruction that loads the
* address of polling page. So set the offset appropriately.
*/
offset = offset + addend;
pcrel = 1; length = 2;
break;
}
case EXTERNAL_GOT_TO_PLT:
case LOADTIME_ADDRESS: {
// this is load time relocations
pcrel = 0; length = 3;
break;
}
default:
throw new InternalError("Unhandled relocation type: " + relocType);
}
machORelocTable.createRelocationEntry(sectindex, offset, symno,
pcrel, length, isextern,
machORelocType);
}
private static int getMachORelocationType(RelocType relocType) {
int machORelocType = 0;
switch (MachOTargetInfo.getMachOArch()) {
case mach_header_64.CPU_TYPE_X86_64:
// Return X86_64_RELOC_* entries based on relocType
if (relocType == RelocType.FOREIGN_CALL_DIRECT || relocType == RelocType.JAVA_CALL_DIRECT || relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
machORelocType = reloc_info.X86_64_RELOC_BRANCH;
} else if (relocType == RelocType.STUB_CALL_DIRECT) {
machORelocType = reloc_info.X86_64_RELOC_BRANCH;
} else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) {
machORelocType = reloc_info.X86_64_RELOC_UNSIGNED;
} else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || relocType == RelocType.JAVA_CALL_INDIRECT || relocType == RelocType.STUB_CALL_INDIRECT) {
machORelocType = reloc_info.X86_64_RELOC_NONE;
} else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) {
machORelocType = reloc_info.X86_64_RELOC_GOT;
} else if (relocType == RelocType.METASPACE_GOT_REFERENCE || relocType == RelocType.EXTERNAL_PLT_TO_GOT || relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
machORelocType = reloc_info.X86_64_RELOC_BRANCH;
} else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || relocType == RelocType.LOADTIME_ADDRESS) {
machORelocType = reloc_info.X86_64_RELOC_UNSIGNED;
} else {
assert false : "Unhandled relocation type: " + relocType;
}
break;
default:
System.out.println("Relocation Type mapping: Unhandled architecture");
}
return machORelocType;
}
}

View File

@ -0,0 +1,307 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.macho;
/**
*
* Support for the creation of Mach-o Object files.
* Current support is limited to 64 bit x86_64.
*
* File Format Overview:
*
* mach_header
* load_commands
* Typical Mac OSX 64-bit object files have these 4 load_commands
* (LC_SEGMENT_64, LC_SYMTAB, LC_VERSIN_MIN_MACOSX, LC_DYSYMTAB)
* Segments corresponding to load_commands
* (which each include multiple Sections)
*/
public class MachO {
/**
* mach_header_64 structure defines
*/
public enum mach_header_64 {
magic( 0, 4),
cputype( 4, 4),
cpusubtype( 8, 4),
filetype(12, 4),
ncmds(16, 4),
sizeofcmds(20, 4),
flags(24, 4),
reserved(28, 4);
public final int off;
public final int sz;
mach_header_64(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 32;
/**
* mach_header_64 defines
*/
public static final int MH_MAGIC = 0xfeedface;
public static final int MH_MAGIC_64 = 0xfeedfacf;
public static final int MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000;
/**
* filetype
*/
public static final int MH_OBJECT = 0x1;
/**
* cputype
*/
public static final int CPU_TYPE_ANY = -1;
public static final int CPU_ARCH_ABI64 = 0x1000000;
public static final int CPU_TYPE_X86_64 = 0x1000007;
public static final int CPU_TYPE_ARM64 = 0x100000c;
/**
* cpusubtype
*/
public static final int CPU_SUBTYPE_I386_ALL = 3;
public static final int CPU_SUBTYPE_ARM64_ALL = 0;
public static final int CPU_SUBTYPE_LITTLE_ENDIAN = 0;
public static final int CPU_SUBTYPE_BIG_ENDIAN = 1;
}
/**
* segment_command_64 structure defines
*/
public enum segment_command_64 {
cmd( 0, 4),
cmdsize( 4, 4),
segname( 8,16),
vmaddr(24, 8),
vmsize(32, 8),
fileoff(40, 8),
filesize(48, 8),
maxprot(56, 4),
initprot(60, 4),
nsects(64, 4),
flags(68, 4);
public final int off;
public final int sz;
segment_command_64(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 72;
public static final int LC_SEGMENT_64 = 0x19;
}
/**
* section_64 structure defines
*/
public enum section_64 {
sectname( 0,16),
segname(16,16),
addr(32, 8),
size(40, 8),
offset(48, 4),
align(52, 4),
reloff(56, 4),
nreloc(60, 4),
flags(64, 4),
reserved1(68, 4),
reserved2(72, 4),
reserved3(76, 4);
public final int off;
public final int sz;
section_64(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 80;
public static int S_REGULAR = 0x0;
public static int S_CSTRING_LITERALS = 0x2;
public static int S_ATTR_PURE_INSTRUCTIONS = 0x80000000;
public static int S_ATTR_SOME_INSTRUCTIONS = 0x400;
}
/**
* version_min_command structure defines
*/
public enum version_min_command {
cmd( 0, 4),
cmdsize( 4, 4),
version( 8, 4),
sdk(12, 4);
public final int off;
public final int sz;
version_min_command(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 16;
public static final int LC_VERSION_MIN_MACOSX = 0x24;
public static final int LC_VERSION_MIN_IPHONEOS = 0x25;
}
/**
* symtab_command structure defines
*/
public enum symtab_command {
cmd( 0, 4),
cmdsize( 4, 4),
symoff( 8, 4),
nsyms(12, 4),
stroff(16, 4),
strsize(20, 4);
public final int off;
public final int sz;
symtab_command(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 24;
public static final int LC_SYMTAB = 0x2;
}
/**
* Symbol table entry definitions
*
* nlist_64 structure defines
*/
public enum nlist_64 {
n_strx( 0, 4),
n_type( 4, 1),
n_sect( 5, 1),
n_desc( 6, 2),
n_value( 8, 8);
public final int off;
public final int sz;
nlist_64(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 16;
public static final int N_EXT = 0x1;
public static final int N_TYPE = 0xe;
public static final int N_UNDF = 0x0;
public static final int N_SECT = 0xe;
}
/**
* dysymtab_command structure defines
*/
public enum dysymtab_command {
cmd( 0, 4),
cmdsize( 4, 4),
ilocalsym( 8, 4),
nlocalsym(12, 4),
iextdefsym(16, 4),
nextdefsym(20, 4),
iundefsym(24, 4),
nundefsym(28, 4),
tocoff(32, 4),
ntoc(36, 4),
modtaboff(40, 4),
nmodtab(44, 4),
extrefsymoff(48, 4),
nextrefsyms(52, 4),
indirectsymoff(56, 4),
nindirectsyms(60, 4),
extreloff(64, 4),
nextrel(68, 4),
locreloff(72, 4),
nlocrel(76, 4);
public final int off;
public final int sz;
dysymtab_command(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 80;
public static final int LC_DYSYMTAB = 0xb;
}
/**
* relocation_info structure defines
*/
public enum reloc_info {
r_address( 0, 4),
r_relocinfo( 4, 4);
public final int off;
public final int sz;
reloc_info(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 8;
public static final int REL_SYMNUM_MASK = 0xffffff;
public static final int REL_SYMNUM_SHIFT = 0x0;
public static final int REL_PCREL_MASK = 0x1;
public static final int REL_PCREL_SHIFT = 0x18;
public static final int REL_LENGTH_MASK = 0x3;
public static final int REL_LENGTH_SHIFT = 0x19;
public static final int REL_EXTERN_MASK = 0x1;
public static final int REL_EXTERN_SHIFT = 0x1b;
public static final int REL_TYPE_MASK = 0xf;
public static final int REL_TYPE_SHIFT = 0x1c;
/* reloc_type_x86_64 defines */
public static final int X86_64_RELOC_NONE = 0x0;
public static final int X86_64_RELOC_BRANCH = 0x2;
public static final int X86_64_RELOC_GOT = 0x4;
public static final int X86_64_RELOC_GOT_LOAD = 0x3;
public static final int X86_64_RELOC_SIGNED = 0x1;
public static final int X86_64_RELOC_UNSIGNED = 0x0;
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.macho;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.macho.MachOTargetInfo;
import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
public class MachOByteBuffer {
public static ByteBuffer allocate(int size) {
ByteBuffer buf = ByteBuffer.allocate(size);
if (MachOTargetInfo.getMachOEndian() ==
MachO.mach_header_64.CPU_SUBTYPE_LITTLE_ENDIAN)
buf.order(ByteOrder.LITTLE_ENDIAN);
else
buf.order(ByteOrder.BIG_ENDIAN);
return (buf);
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.macho;
import java.io.File;
import java.io.FileOutputStream;
public class MachOContainer {
File outputFile;
FileOutputStream outputStream;
long fileOffset;
public MachOContainer(String fileName) {
String baseName;
outputFile = new File(fileName);
if (outputFile.exists()) {
outputFile.delete();
}
try {
outputStream = new FileOutputStream(outputFile);
} catch (Exception e) {
System.out.println("MachOContainer: Can't create file " + fileName);
}
fileOffset = 0;
}
public void close() {
try {
outputStream.close();
} catch (Exception e) {
System.out.println("MachOContainer: close failed");
}
}
public void writeBytes(byte [] bytes) {
try {
outputStream.write(bytes);
} catch (Exception e) {
System.out.println("MachOContainer: writeBytes failed");
}
fileOffset += bytes.length;
}
// Write bytes to output file with up front alignment padding
public void writeBytes(byte [] bytes, int alignment) {
try {
// Pad to alignment
while ((fileOffset & (long)(alignment-1)) != 0) {
outputStream.write(0);
fileOffset++;
}
outputStream.write(bytes);
} catch (Exception e) {
System.out.println("MachOContainer: writeBytes failed");
}
fileOffset += bytes.length;
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.macho;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.macho.MachO;
import jdk.tools.jaotc.binformat.macho.MachO.dysymtab_command;
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
public class MachODySymtab {
ByteBuffer dysymtab;
public MachODySymtab(int nlocal, int nglobal, int nundef) {
dysymtab = MachOByteBuffer.allocate(dysymtab_command.totalsize);
dysymtab.putInt(dysymtab_command.cmd.off, dysymtab_command.LC_DYSYMTAB);
dysymtab.putInt(dysymtab_command.cmdsize.off, dysymtab_command.totalsize);
dysymtab.putInt(dysymtab_command.ilocalsym.off, 0);
dysymtab.putInt(dysymtab_command.nlocalsym.off, nlocal);
dysymtab.putInt(dysymtab_command.iextdefsym.off, nlocal);
dysymtab.putInt(dysymtab_command.nextdefsym.off, nglobal);
dysymtab.putInt(dysymtab_command.iundefsym.off, nlocal+nglobal);
dysymtab.putInt(dysymtab_command.nundefsym.off, nundef);
}
public byte[] getArray() {
return dysymtab.array();
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.macho;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.macho.MachO;
import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
import jdk.tools.jaotc.binformat.macho.MachOTargetInfo;
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
public class MachOHeader {
ByteBuffer header;
public MachOHeader() {
header = MachOByteBuffer.allocate(mach_header_64.totalsize);
header.putInt(mach_header_64.magic.off, mach_header_64.MH_MAGIC_64);
header.putInt(mach_header_64.cputype.off, MachOTargetInfo.getMachOArch());
header.putInt(mach_header_64.cpusubtype.off, MachOTargetInfo.getMachOSubArch());
header.putInt(mach_header_64.flags.off, 0x2000);
header.putInt(mach_header_64.filetype.off, mach_header_64.MH_OBJECT);
}
public void setCmdSizes(int ncmds, int sizeofcmds) {
header.putInt(mach_header_64.ncmds.off, ncmds);
header.putInt(mach_header_64.sizeofcmds.off, sizeofcmds);
}
public int getCmdSize() {
return (header.getInt(mach_header_64.sizeofcmds.off));
}
public byte[] getArray() {
return header.array();
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.macho;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.macho.MachO;
import jdk.tools.jaotc.binformat.macho.MachO.reloc_info;
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
public class MachORelocEntry {
ByteBuffer entry;
public MachORelocEntry(int offset,
int symno,
int pcrel,
int length,
int isextern,
int type) {
entry = MachOByteBuffer.allocate(reloc_info.totalsize);
entry.putInt(reloc_info.r_address.off, offset);
// Encode and store the relocation entry bitfields
entry.putInt(reloc_info.r_relocinfo.off,
((symno & reloc_info.REL_SYMNUM_MASK)
<< reloc_info.REL_SYMNUM_SHIFT) |
((pcrel & reloc_info.REL_PCREL_MASK)
<< reloc_info.REL_PCREL_SHIFT) |
((length & reloc_info.REL_LENGTH_MASK)
<< reloc_info.REL_LENGTH_SHIFT) |
((isextern & reloc_info.REL_EXTERN_MASK)
<< reloc_info.REL_EXTERN_SHIFT) |
((type & reloc_info.REL_TYPE_MASK)
<< reloc_info.REL_TYPE_SHIFT));
}
public byte[] getArray() {
return entry.array();
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.macho;
import java.util.ArrayList;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.macho.MachORelocEntry;
import jdk.tools.jaotc.binformat.macho.MachOTargetInfo;
import jdk.tools.jaotc.binformat.macho.MachO.reloc_info;
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
public class MachORelocTable {
ArrayList<ArrayList<MachORelocEntry>> relocEntries;
int fileOffset;
public MachORelocTable(int numsects) {
relocEntries = new ArrayList<ArrayList<MachORelocEntry>>(numsects);
for (int i = 0; i < numsects; i++)
relocEntries.add(new ArrayList<MachORelocEntry>());
}
public void createRelocationEntry(int sectindex,
int offset,
int symno,
int pcrel,
int length,
int isextern,
int type) {
MachORelocEntry entry = new MachORelocEntry(offset,
symno,
pcrel,
length,
isextern,
type);
relocEntries.get(sectindex).add(entry);
}
public int getAlign() {
return (4);
}
public int getNumRelocs(int section_index) {
return relocEntries.get(section_index).size();
}
// Return the relocation entries for a single section
// or null if no entries added to section
public byte [] getRelocData(int section_index) {
ArrayList<MachORelocEntry> entryList = relocEntries.get(section_index);
if (entryList.size() == 0)
return null;
ByteBuffer relocData = MachOByteBuffer.allocate(entryList.size() * reloc_info.totalsize);
// Copy each entry to a single ByteBuffer
for (int i = 0; i < entryList.size(); i++) {
MachORelocEntry entry = entryList.get(i);
relocData.put(entry.getArray());
}
return (relocData.array());
}
}

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.macho;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.macho.MachO;
import jdk.tools.jaotc.binformat.macho.MachO.section_64;
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
public class MachOSection {
ByteBuffer section;
byte [] data;
boolean hasrelocations;
public MachOSection(String sectName, String segName, byte [] sectData, int sectFlags, boolean hasRelocations) {
section = MachOByteBuffer.allocate(section_64.totalsize);
// TODO: Hotspot uses long section names.
// They are getting truncated.
// Is this a problem??
byte[] sectNameBytes = sectName.getBytes();
int sectNameMax = section_64.sectname.sz < sectNameBytes.length ?
section_64.sectname.sz : sectNameBytes.length;
for (int i = 0; i < sectNameMax; i++)
section.put(section_64.sectname.off+i, sectNameBytes[i]);
byte[] segNameBytes = segName.getBytes();
int segNameMax = section_64.segname.sz < segNameBytes.length ?
section_64.segname.sz : segNameBytes.length;
for (int i = 0; i < segNameMax; i++)
section.put(section_64.segname.off+i, segNameBytes[i]);
section.putLong(section_64.size.off, sectData.length);
// For now use 8 byte alignment
section.putInt(section_64.align.off, 3);
section.putInt(section_64.flags.off, sectFlags);
data = sectData;
hasrelocations = hasRelocations;
}
public long getSize() {
return section.getLong(section_64.size.off);
}
public int getAlign() {
return (1 << section.getInt(section_64.align.off));
}
public byte[] getArray() {
return section.array();
}
public byte[] getDataArray() {
return data;
}
public void setAddr(long addr) {
section.putLong(section_64.addr.off, addr);
}
public long getAddr() {
return (section.getLong(section_64.addr.off));
}
public void setOffset(int offset) {
section.putInt(section_64.offset.off, offset);
}
public int getOffset() {
return (section.getInt(section_64.offset.off));
}
public void setReloff(int offset) {
section.putInt(section_64.reloff.off, offset);
}
public void setRelcount(int count) {
section.putInt(section_64.nreloc.off, count);
}
public boolean hasRelocations() {
return hasrelocations;
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.macho;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.macho.MachO;
import jdk.tools.jaotc.binformat.macho.MachO.segment_command_64;
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
public class MachOSegment {
ByteBuffer segment;
public MachOSegment(int size, int fileoff, int filesize, int nsects) {
segment = MachOByteBuffer.allocate(segment_command_64.totalsize);
segment.putInt(segment_command_64.cmd.off, segment_command_64.LC_SEGMENT_64);
segment.putInt(segment_command_64.cmdsize.off, size);
segment.putInt(segment_command_64.maxprot.off, 7);
segment.putInt(segment_command_64.initprot.off, 7);
segment.putInt(segment_command_64.nsects.off, nsects);
segment.putInt(segment_command_64.flags.off, 0);
segment.putLong(segment_command_64.vmaddr.off, 0);
segment.putLong(segment_command_64.vmsize.off, filesize);
segment.putLong(segment_command_64.fileoff.off, fileoff);
segment.putLong(segment_command_64.filesize.off, filesize);
}
public byte[] getArray() {
return segment.array();
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.macho;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.NativeSymbol;
import jdk.tools.jaotc.binformat.macho.MachO;
import jdk.tools.jaotc.binformat.macho.MachO.nlist_64;
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
public class MachOSymbol extends NativeSymbol {
ByteBuffer sym;
public MachOSymbol(int symbolindex, int strindex, byte type, byte sectindex, long offset) {
super(symbolindex);
sym = MachOByteBuffer.allocate(nlist_64.totalsize);
sym.putInt(nlist_64.n_strx.off, strindex);
sym.put(nlist_64.n_type.off, type);
// Section indexes start at 1 but we manage the index internally
// as 0 relative
sym.put(nlist_64.n_sect.off, (byte)(sectindex+1));
sym.putChar(nlist_64.n_desc.off, (char )0);
sym.putLong(nlist_64.n_value.off, offset);
}
public byte[] getArray() {
return sym.array();
}
}

View File

@ -0,0 +1,211 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.macho;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import jdk.tools.jaotc.binformat.macho.MachO;
import jdk.tools.jaotc.binformat.macho.MachO.symtab_command;
import jdk.tools.jaotc.binformat.macho.MachO.nlist_64;
import jdk.tools.jaotc.binformat.macho.MachOSymbol;
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
public class MachOSymtab {
/**
* ByteBuffer holding the LC_SYMTAB command contents
*/
ByteBuffer symtabCmd;
/**
* ByteBuffer holding the symbol table entries and strings
*/
ByteBuffer symtabData;
int symtabDataSize;
ArrayList<MachOSymbol>localSymbols = new ArrayList<MachOSymbol>();
ArrayList<MachOSymbol>globalSymbols = new ArrayList<MachOSymbol>();
ArrayList<MachOSymbol>undefSymbols = new ArrayList<MachOSymbol>();
/**
* number of symbols added
*/
int symbolCount;
/**
* String holding symbol table strings
*/
private StringBuilder strTabContent = new StringBuilder();
/**
* Keeps track of bytes in string table since strTabContent.length()
* is number of chars, not bytes.
*/
private int strTabNrOfBytes = 0;
public MachOSymtab() {
symtabCmd = MachOByteBuffer.allocate(symtab_command.totalsize);
symtabCmd.putInt(symtab_command.cmd.off, symtab_command.LC_SYMTAB);
symtabCmd.putInt(symtab_command.cmdsize.off, symtab_command.totalsize);
symbolCount = 0;
}
public int getAlign() {
return (4);
}
public MachOSymbol addSymbolEntry(String name, byte type, byte secHdrIndex, long offset) {
// Get the current symbol index and append symbol name to string table.
int index;
MachOSymbol sym;
if (name.isEmpty()) {
index = 0;
strTabContent.append('\0');
strTabNrOfBytes += 1;
sym = new MachOSymbol(symbolCount, index, type, secHdrIndex, offset);
localSymbols.add(sym);
} else {
// We can't trust strTabContent.length() since that is
// chars (UTF16), keep track of bytes on our own.
index = strTabNrOfBytes;
strTabContent.append("_").append(name).append('\0');
// + 1 for null, + 1 for "_"
strTabNrOfBytes += (name.getBytes().length + 1 + 1);
sym = new MachOSymbol(symbolCount, index, type, secHdrIndex, offset);
switch (type) {
case nlist_64.N_EXT:
undefSymbols.add(sym);
break;
case nlist_64.N_SECT:
case nlist_64.N_UNDF: // null symbol
localSymbols.add(sym);
break;
case nlist_64.N_SECT|nlist_64.N_EXT:
globalSymbols.add(sym);
break;
default:
System.out.println("Unsupported Symbol type " + type);
break;
}
}
symbolCount++;
return (sym);
}
public void setOffset(int symoff) {
symtabCmd.putInt(symtab_command.symoff.off, symoff);
}
// Update the symbol indexes once all symbols have been added.
// This is required since we'll be reordering the symbols in the
// file to be in the order of Local, global and Undefined.
public void updateIndexes() {
int index = 0;
// Update the local symbol indexes
for (int i = 0; i < localSymbols.size(); i++ ) {
MachOSymbol sym = localSymbols.get(i);
sym.setIndex(index++);
}
// Update the global symbol indexes
for (int i = 0; i < globalSymbols.size(); i++ ) {
MachOSymbol sym = globalSymbols.get(i);
sym.setIndex(index++);
}
// Update the undefined symbol indexes
for (int i = index; i < undefSymbols.size(); i++ ) {
MachOSymbol sym = undefSymbols.get(i);
sym.setIndex(index++);
}
}
// Update LC_SYMTAB command fields based on the number of symbols added
// return the file size taken up by symbol table entries and strings
public int calcSizes() {
int stroff;
stroff = symtabCmd.getInt(symtab_command.symoff.off) + (nlist_64.totalsize * symbolCount);
symtabCmd.putInt(symtab_command.nsyms.off, symbolCount);
symtabCmd.putInt(symtab_command.stroff.off, stroff);
symtabCmd.putInt(symtab_command.strsize.off, strTabNrOfBytes);
symtabDataSize = (nlist_64.totalsize * symbolCount) + strTabNrOfBytes;
return (symtabDataSize);
}
public int getNumLocalSyms() { return localSymbols.size(); }
public int getNumGlobalSyms() { return globalSymbols.size(); }
public int getNumUndefSyms() { return undefSymbols.size(); }
public byte[] getCmdArray() {
return symtabCmd.array();
}
// Create a single byte array that contains the symbol table entries
// and string table
public byte[] getDataArray() {
int index = 0;
symtabData = MachOByteBuffer.allocate(symtabDataSize);
byte [] retarray;
// Add the local symbols
for (int i = 0; i < localSymbols.size(); i++ ) {
MachOSymbol sym = localSymbols.get(i);
byte [] arr = sym.getArray();
symtabData.put(arr);
}
// Add the global symbols
for (int i = 0; i < globalSymbols.size(); i++ ) {
MachOSymbol sym = globalSymbols.get(i);
byte [] arr = sym.getArray();
symtabData.put(arr);
}
// Add the undefined symbols
for (int i = 0; i < undefSymbols.size(); i++ ) {
MachOSymbol sym = undefSymbols.get(i);
byte [] arr = sym.getArray();
symtabData.put(arr);
}
// Add the stringtable
byte [] strs = strTabContent.toString().getBytes();
symtabData.put(strs);
retarray = symtabData.array();
return (retarray);
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.macho;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.macho.MachO;
import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64;
/**
* Class that abstracts MACH-O target details.
*
*/
public class MachOTargetInfo {
/**
* Target architecture and subtype.
*/
private static final int arch;
private static final int subarch;
/**
* Architecture endian-ness.
*/
private static final int endian = mach_header_64.CPU_SUBTYPE_LITTLE_ENDIAN;
/**
* Target OS string.
*/
private static final String osName;
static {
// Find the target arch details
String archStr = System.getProperty("os.arch").toLowerCase();
if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) {
System.out.println("Only Little Endian byte order supported!");
}
if (archStr.equals("amd64") || archStr.equals("x86_64")) {
arch = mach_header_64.CPU_TYPE_X86_64;
subarch = mach_header_64.CPU_SUBTYPE_I386_ALL;
} else {
System.out.println("Unsupported architecture " + archStr);
arch = mach_header_64.CPU_TYPE_ANY;
subarch = 0;
}
osName = System.getProperty("os.name").toLowerCase();
}
public static int getMachOArch() {
return arch;
}
public static int getMachOSubArch() {
return subarch;
}
public static int getMachOEndian() {
return endian;
}
public static String getOsName() {
return osName;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -20,36 +20,30 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.api.collections;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
package jdk.tools.jaotc.binformat.macho;
/**
* A default implementation of {@link CollectionsProvider} that creates standard JDK collection
* class objects.
*/
public class DefaultCollectionsProvider implements CollectionsProvider {
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@Override
public <E> Set<E> newIdentitySet() {
return Collections.newSetFromMap(newIdentityMap());
import jdk.tools.jaotc.binformat.macho.MachO;
import jdk.tools.jaotc.binformat.macho.MachO.version_min_command;
import jdk.tools.jaotc.binformat.macho.MachOByteBuffer;
public class MachOVersion {
ByteBuffer version;
public MachOVersion() {
version = MachOByteBuffer.allocate(version_min_command.totalsize);
version.putInt(version_min_command.cmd.off, version_min_command.LC_VERSION_MIN_MACOSX);
version.putInt(version_min_command.cmdsize.off, version_min_command.totalsize);
version.putInt(version_min_command.version.off, (10 << 16) | (10 << 8)); /* MacOSX 10.10 */
version.putInt(version_min_command.sdk.off, 0); /* N/A SDK */
}
@Override
public <K, V> Map<K, V> newIdentityMap() {
return new IdentityHashMap<>();
}
@Override
public <K, V> Map<K, V> newIdentityMap(int expectedMaxSize) {
return new IdentityHashMap<>(expectedMaxSize);
}
@Override
public <K, V> Map<K, V> newIdentityMap(Map<K, V> initFrom) {
return new IdentityHashMap<>(initFrom);
public byte[] getArray() {
return version.array();
}
}

View File

@ -0,0 +1,422 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.pecoff;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import jdk.tools.jaotc.binformat.Container;
import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.ByteContainer;
import jdk.tools.jaotc.binformat.CodeContainer;
import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
import jdk.tools.jaotc.binformat.Relocation;
import jdk.tools.jaotc.binformat.Relocation.RelocType;
import jdk.tools.jaotc.binformat.Symbol;
import jdk.tools.jaotc.binformat.NativeSymbol;
import jdk.tools.jaotc.binformat.Symbol.Binding;
import jdk.tools.jaotc.binformat.Symbol.Kind;
import jdk.tools.jaotc.binformat.pecoff.PECoff;
import jdk.tools.jaotc.binformat.pecoff.PECoffSymbol;
import jdk.tools.jaotc.binformat.pecoff.PECoffTargetInfo;
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER;
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SECTION_HEADER;
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL;
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION;
public class JPECoffRelocObject {
private final BinaryContainer binContainer;
private final PECoffContainer pecoffContainer;
private final int segmentSize;
public JPECoffRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) {
this.binContainer = binContainer;
this.pecoffContainer = new PECoffContainer(outputFileName, aotVersion);
this.segmentSize = binContainer.getCodeSegmentSize();
}
private PECoffSection createByteSection(ArrayList<PECoffSection>sections,
String sectName,
byte [] scnData,
boolean hasRelocs,
int scnFlags) {
PECoffSection sect = new PECoffSection(sectName,
scnData,
scnFlags,
hasRelocs,
sections.size());
// Add this section to our list
sections.add(sect);
return (sect);
}
private void createByteSection(ArrayList<PECoffSection>sections,
ByteContainer c, int scnFlags) {
PECoffSection sect;
boolean hasRelocs = c.hasRelocations();
byte[] scnData = c.getByteArray();
sect = createByteSection(sections, c.getContainerName(),
scnData, hasRelocs,
scnFlags);
c.setSectionId(sect.getSectionId());
}
private void createCodeSection(ArrayList<PECoffSection>sections, CodeContainer c) {
createByteSection(sections, c, IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ |
IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_EXECUTE |
IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_16BYTES |
IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_CODE);
}
private void createReadOnlySection(ArrayList<PECoffSection>sections, ReadOnlyDataContainer c) {
createByteSection(sections, c, IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ |
IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_16BYTES |
IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA);
}
private void createReadWriteSection(ArrayList<PECoffSection>sections, ByteContainer c) {
int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ |
IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_WRITE |
IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_8BYTES;
if (c.getByteArray().length > 0)
scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA;
else
scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_UNINITIALIZED_DATA;
createByteSection(sections, c, scnFlags);
}
/**
* Create an PECoff relocatable object
*
* @param relocationTable
* @param symbols
* @throws IOException throws {@code IOException} as a result of file system access failures.
*/
public void createPECoffRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException {
ArrayList<PECoffSection> sections = new ArrayList<PECoffSection>();
// Create text section
createCodeSection(sections, binContainer.getCodeContainer());
createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer());
createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer());
createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer());
createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer());
createReadWriteSection(sections, binContainer.getMetaspaceGotContainer());
createReadWriteSection(sections, binContainer.getMetadataGotContainer());
createReadWriteSection(sections, binContainer.getMethodStateContainer());
createReadWriteSection(sections, binContainer.getOopGotContainer());
createReadWriteSection(sections, binContainer.getMethodMetadataContainer());
createReadOnlySection(sections, binContainer.getStubsOffsetsContainer());
createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer());
createReadOnlySection(sections, binContainer.getCodeSegmentsContainer());
createReadOnlySection(sections, binContainer.getConstantDataContainer());
createReadOnlySection(sections, binContainer.getConfigContainer());
// createExternalLinkage();
createCodeSection(sections, binContainer.getExtLinkageContainer());
createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer());
// Allocate PECoff Header
PECoffHeader header = new PECoffHeader();
// Get PECoff symbol data from BinaryContainer object's symbol tables
PECoffSymtab symtab = createPECoffSymbolTables(sections, symbols);
// Add Linker Directives Section
createByteSection(sections, ".drectve",
symtab.getDirectiveArray(), false,
IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_INFO |
IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_REMOVE |
IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_1BYTES);
// Create the Relocation Tables
PECoffRelocTable pecoffRelocs = createPECoffRelocTable(sections, relocationTable);
// File Output Order
//
// HEADER (Need address of Symbol Table + symbol count)
// SECTIONS (Need pointer to Section Data, Relocation Table)
// DIRECTIVES
// SYMBOL TABLE
// SYMBOLS
// SECTION DATA
// RELOCATION TABLE
// Calculate Offset for Symbol table
int file_offset = IMAGE_FILE_HEADER.totalsize +
(IMAGE_SECTION_HEADER.totalsize*sections.size());
// Update Header fields
header.setSectionCount(sections.size());
header.setSymbolCount(symtab.getSymtabCount());
header.setSymbolOff(file_offset);
// Calculate file offset for first section
file_offset += ((symtab.getSymtabCount() * IMAGE_SYMBOL.totalsize) +
symtab.getStrtabSize());
// And round it up
file_offset = (file_offset + (sections.get(0).getDataAlign()-1)) &
~((sections.get(0).getDataAlign()-1));
// Calc file offsets for section data
for (int i = 0; i < sections.size(); i++) {
PECoffSection sect = sections.get(i);
file_offset = (file_offset + (sect.getDataAlign()-1)) &
~((sect.getDataAlign()-1));
sect.setOffset(file_offset);
file_offset += sect.getSize();
}
// Update relocation sizing information in each section
for (int i = 0; i < sections.size(); i++) {
PECoffSection sect = sections.get(i);
if (sect.hasRelocations()) {
int nreloc = pecoffRelocs.getNumRelocs(i);
sect.setReloff(file_offset);
sect.setRelcount(nreloc);
// extended relocations add an addition entry
if (nreloc > 0xFFFF) nreloc++;
file_offset += (nreloc * IMAGE_RELOCATION.totalsize);
}
}
// Write out the Header
pecoffContainer.writeBytes(header.getArray());
// Write out the section table
for (int i = 0; i < sections.size(); i++) {
PECoffSection sect = sections.get(i);
pecoffContainer.writeBytes(sect.getArray(), PECoffSection.getShdrAlign());
}
// Write out the symbol table and string table
pecoffContainer.writeBytes(symtab.getSymtabArray(), 4);
pecoffContainer.writeBytes(symtab.getStrtabArray(), 1);
// Write out each section contents
for (int i = 0; i < sections.size(); i++) {
PECoffSection sect = sections.get(i);
pecoffContainer.writeBytes(sect.getDataArray(), sect.getDataAlign());
}
// Write out Relocation Tables
for (int i = 0; i < sections.size(); i++) {
if (pecoffRelocs.getNumRelocs(i) > 0) {
pecoffContainer.writeBytes(pecoffRelocs.getRelocData(i));
}
}
pecoffContainer.close();
}
/**
* Construct PECoff symbol data from BinaryContainer object's symbol tables. Both dynamic PECoff
* symbol table and PECoff symbol table are created from BinaryContainer's symbol info.
*
* @param symbols
*/
private PECoffSymtab createPECoffSymbolTables(ArrayList<PECoffSection> sections, Collection<Symbol> symbols) {
PECoffSymtab symtab = new PECoffSymtab();
// First, create the initial null symbol. This is a local symbol.
// symtab.addSymbolEntry("", (byte)0, (byte)0, (byte)0, 0, 0);
// Now create PECoff symbol entries for all symbols.
for (Symbol symbol : symbols) {
// Get the index of section this symbol is defined in.
int secHdrIndex = symbol.getSection().getSectionId();
PECoffSymbol pecoffSymbol = symtab.addSymbolEntry(symbol.getName(), getPECoffTypeOf(symbol), getPECoffClassOf(symbol), (byte)secHdrIndex, symbol.getOffset(), symbol.getSize());
symbol.setNativeSymbol((NativeSymbol)pecoffSymbol);
}
return (symtab);
}
private static byte getPECoffTypeOf(Symbol sym) {
Kind kind = sym.getKind();
if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) {
return IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION;
}
return IMAGE_SYMBOL.IMAGE_SYM_DTYPE_NONE;
}
private static byte getPECoffClassOf(Symbol sym) {
Binding binding = sym.getBinding();
if (binding == Symbol.Binding.GLOBAL) {
return IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL;
}
return IMAGE_SYMBOL.IMAGE_SYM_CLASS_STATIC;
}
/**
* Construct a PECoff relocation table from BinaryContainer object's relocation tables.
*
* @param sections
* @param relocationTable
*/
private PECoffRelocTable createPECoffRelocTable(ArrayList<PECoffSection> sections,
Map<Symbol, List<Relocation>> relocationTable) {
PECoffRelocTable pecoffRelocTable = new PECoffRelocTable(sections.size());
/*
* For each of the symbols with associated relocation records, create a PECoff relocation
* entry.
*/
for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) {
List<Relocation> relocs = entry.getValue();
Symbol symbol = entry.getKey();
for (Relocation reloc : relocs) {
createRelocation(symbol, reloc, pecoffRelocTable);
}
}
for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) {
createRelocation(entry.getKey(), entry.getValue(), pecoffRelocTable);
}
return (pecoffRelocTable);
}
private void createRelocation(Symbol symbol, Relocation reloc, PECoffRelocTable pecoffRelocTable) {
RelocType relocType = reloc.getType();
int pecoffRelocType = getPECoffRelocationType(relocType);
PECoffSymbol sym = (PECoffSymbol)symbol.getNativeSymbol();
int symno = sym.getIndex();
int sectindex = reloc.getSection().getSectionId();
int offset = reloc.getOffset();
int addend = 0;
switch (relocType) {
case FOREIGN_CALL_DIRECT:
case JAVA_CALL_DIRECT:
case STUB_CALL_DIRECT:
case FOREIGN_CALL_INDIRECT_GOT: {
// Create relocation entry
addend = -4; // Size in bytes of the patch location
// Relocation should be applied at the location after call operand
offset = offset + reloc.getSize() + addend;
break;
}
case FOREIGN_CALL_DIRECT_FAR: {
// Create relocation entry
addend = -8; // Size in bytes of the patch location
// Relocation should be applied at the location after call operand
// 10 = 2 (jmp [r]) + 8 (imm64)
offset = offset + reloc.getSize() + addend - 2;
break;
}
case FOREIGN_CALL_INDIRECT:
case JAVA_CALL_INDIRECT:
case STUB_CALL_INDIRECT: {
// Do nothing.
return;
}
case EXTERNAL_DATA_REFERENCE_FAR: {
// Create relocation entry
addend = -4; // Size of 32-bit address of the GOT
/*
* Relocation should be applied before the test instruction to the move instruction.
* offset points to the test instruction after the instruction that loads
* the address of polling page. So set the offset appropriately.
*/
offset = offset + addend;
break;
}
case METASPACE_GOT_REFERENCE:
case EXTERNAL_PLT_TO_GOT:
case STATIC_STUB_TO_STATIC_METHOD:
case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: {
addend = -4; // Size of 32-bit address of the GOT
/*
* Relocation should be applied before the test instruction to
* the move instruction. reloc.getOffset() points to the
* test instruction after the instruction that loads the
* address of polling page. So set the offset appropriately.
*/
offset = offset + addend;
break;
}
case EXTERNAL_GOT_TO_PLT:
case LOADTIME_ADDRESS: {
// this is load time relocations
break;
}
default:
throw new InternalError("Unhandled relocation type: " + relocType);
}
pecoffRelocTable.createRelocationEntry(sectindex, offset, symno, pecoffRelocType);
}
// Return IMAGE_RELOCATION Type based on relocType
private static int getPECoffRelocationType(RelocType relocType) {
int pecoffRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH
switch (PECoffTargetInfo.getPECoffArch()) {
case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
if (relocType == RelocType.FOREIGN_CALL_DIRECT ||
relocType == RelocType.JAVA_CALL_DIRECT ||
relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) {
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
} else if (relocType == RelocType.STUB_CALL_DIRECT) {
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
} else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) {
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64;
} else if (relocType == RelocType.FOREIGN_CALL_INDIRECT ||
relocType == RelocType.JAVA_CALL_INDIRECT ||
relocType == RelocType.STUB_CALL_INDIRECT) {
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ABSOLUTE;
} else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) {
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
} else if (relocType == RelocType.METASPACE_GOT_REFERENCE ||
relocType == RelocType.EXTERNAL_PLT_TO_GOT ||
relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD ||
relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) {
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32;
} else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT ||
relocType == RelocType.LOADTIME_ADDRESS) {
pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64;
} else {
assert false : "Unhandled relocation type: " + relocType;
}
break;
default:
System.out.println("Relocation Type mapping: Unhandled architecture");
}
return pecoffRelocType;
}
}

View File

@ -0,0 +1,200 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.pecoff;
/**
*
* Support for the creation of Coff files.
* Current support is limited to 64 bit x86_64.
*
*/
public class PECoff {
/**
* IMAGE_FILE_HEADER structure defines
*/
public enum IMAGE_FILE_HEADER {
Machine( 0, 2),
NumberOfSections( 2, 2),
TimeDateStamp( 4, 4),
PointerToSymbolTable( 8, 4),
NumberOfSymbols(12, 4),
SizeOfOptionalHeader(16, 2),
Characteristics(18, 2);
public final int off;
public final int sz;
IMAGE_FILE_HEADER(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 20;
/**
* IMAGE_FILE_HEADER defines
*/
/**
* Machine
*/
public static final char IMAGE_FILE_MACHINE_UNKNOWN = 0x0;
public static final char IMAGE_FILE_MACHINE_AMD64 = 0x8664;
}
/**
* IMAGE_SECTION_HEADER structure defines
*/
public enum IMAGE_SECTION_HEADER {
Name( 0, 8),
PhysicalAddress( 8, 4),
VirtualSize( 8, 4),
VirtualAddress(12, 4),
SizeOfRawData(16, 4),
PointerToRawData(20, 4),
PointerToRelocations(24, 4),
PointerToLinenumbers(28, 4),
NumberOfRelocations(32, 2),
NumberOfLinenumbers(34, 2),
Characteristics(36, 4);
public final int off;
public final int sz;
IMAGE_SECTION_HEADER(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 40;
/**
* IMAGE_SECTION_HEADER defines
*/
/**
* Characteristics
*/
public static final int IMAGE_SCN_CNT_CODE = 0x20;
public static final int IMAGE_SCN_CNT_INITIALIZED_DATA = 0x40;
public static final int IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x80;
public static final int IMAGE_SCN_LNK_COMDAT = 0x1000;
public static final int IMAGE_SCN_LNK_INFO = 0x200;
public static final int IMAGE_SCN_LNK_REMOVE = 0x800;
public static final int IMAGE_SCN_ALIGN_1BYTES = 0x100000;
public static final int IMAGE_SCN_ALIGN_2BYTES = 0x200000;
public static final int IMAGE_SCN_ALIGN_4BYTES = 0x300000;
public static final int IMAGE_SCN_ALIGN_8BYTES = 0x400000;
public static final int IMAGE_SCN_ALIGN_16BYTES = 0x500000;
public static final int IMAGE_SCN_ALIGN_MASK = 0xf00000;
public static final int IMAGE_SCN_ALIGN_SHIFT = 20;
public static final int IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000;
public static final int IMAGE_SCN_MEM_SHARED = 0x10000000;
public static final int IMAGE_SCN_MEM_EXECUTE = 0x20000000;
public static final int IMAGE_SCN_MEM_READ = 0x40000000;
public static final int IMAGE_SCN_MEM_WRITE = 0x80000000;
}
/**
* Symbol table entry definitions
*
* IMAGE_SYMBOL structure defines
*/
public enum IMAGE_SYMBOL {
ShortName( 0, 8),
Short( 0, 4),
Long( 4, 4),
Value( 8, 4),
SectionNumber(12, 2),
Type(14, 2),
StorageClass(16, 1),
NumberOfAuxSymbols(17, 1);
public final int off;
public final int sz;
IMAGE_SYMBOL(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 18;
/**
* Type
*/
public static final int IMAGE_SYM_DTYPE_NONE = 0x0;
public static final int IMAGE_SYM_DTYPE_FUNCTION = 0x20;
/**
* StorageClass
*/
public static final int IMAGE_SYM_CLASS_NULL = 0x0;
public static final int IMAGE_SYM_CLASS_EXTERNAL = 0x2;
public static final int IMAGE_SYM_CLASS_STATIC = 0x3;
public static final int IMAGE_SYM_CLASS_LABEL = 0x6;
}
/**
* IMAGE_RELOCATION structure defines
*/
public enum IMAGE_RELOCATION {
VirtualAddress( 0, 4),
SymbolTableIndex( 4, 4),
Type( 8, 2);
public final int off;
public final int sz;
IMAGE_RELOCATION(int offset, int size) {
this.off = offset;
this.sz = size;
}
public static int totalsize = 10;
/**
* Relocation types
*/
public static final int IMAGE_REL_AMD64_ABSOLUTE = 0x0;
public static final int IMAGE_REL_AMD64_ADDR32 = 0x2;
public static final int IMAGE_REL_AMD64_ADDR64 = 0x1;
public static final int IMAGE_REL_AMD64_REL32 = 0x4;
public static final int IMAGE_REL_AMD64_REL32_1 = 0x5;
public static final int IMAGE_REL_AMD64_REL32_2 = 0x6;
public static final int IMAGE_REL_AMD64_REL32_3 = 0x7;
public static final int IMAGE_REL_AMD64_REL32_4 = 0x8;
public static final int IMAGE_REL_AMD64_REL32_5 = 0x9;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -20,11 +20,19 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.salver.data;
import java.util.LinkedHashMap;
package jdk.tools.jaotc.binformat.pecoff;
public class DataDict extends LinkedHashMap<Object, Object> {
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class PECoffByteBuffer {
public static ByteBuffer allocate(int size) {
ByteBuffer buf = ByteBuffer.allocate(size);
// Only support Little Endian on Windows
buf.order(ByteOrder.LITTLE_ENDIAN);
return (buf);
}
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.pecoff;
import java.io.File;
import java.io.FileOutputStream;
public class PECoffContainer {
File outputFile;
FileOutputStream outputStream;
long fileOffset;
public PECoffContainer(String fileName, String aotVersion) {
String baseName;
outputFile = new File(fileName);
if (outputFile.exists()) {
outputFile.delete();
}
try {
outputStream = new FileOutputStream(outputFile);
} catch (Exception e) {
System.out.println("PECoffContainer: Can't create file " + fileName);
}
fileOffset = 0;
}
public void close() {
try {
outputStream.close();
} catch (Exception e) {
System.out.println("PECoffContainer: close failed");
}
}
public void writeBytes(byte [] bytes) {
if (bytes == null) return;
try {
outputStream.write(bytes);
} catch (Exception e) {
System.out.println("PECoffContainer: writeBytes failed");
}
fileOffset += bytes.length;
}
// Write bytes to output file with up front alignment padding
public void writeBytes(byte [] bytes, int alignment) {
if (bytes == null) return;
try {
// Pad to alignment
while ((fileOffset & (long)(alignment-1)) != 0) {
outputStream.write(0);
fileOffset++;
}
outputStream.write(bytes);
} catch (Exception e) {
System.out.println("PECoffContainer: writeBytes failed");
}
fileOffset += bytes.length;
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.pecoff;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.pecoff.PECoff;
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER;
import jdk.tools.jaotc.binformat.pecoff.PECoffTargetInfo;
import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
public class PECoffHeader {
ByteBuffer header;
public PECoffHeader() {
header = PECoffByteBuffer.allocate(IMAGE_FILE_HEADER.totalsize);
header.putChar(IMAGE_FILE_HEADER.Machine.off, IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64);
header.putInt(IMAGE_FILE_HEADER.TimeDateStamp.off, (int)(System.currentTimeMillis()/1000));
header.putInt(IMAGE_FILE_HEADER.PointerToSymbolTable.off, 0);
header.putInt(IMAGE_FILE_HEADER.NumberOfSymbols.off, 0);
header.putChar(IMAGE_FILE_HEADER.SizeOfOptionalHeader.off, (char)0);
header.putChar(IMAGE_FILE_HEADER.Characteristics.off, (char)0);
}
// Update header with the number of total sections
public void setSectionCount(int count) {
header.putChar(IMAGE_FILE_HEADER.NumberOfSections.off, (char)count);
}
// Update header with the number of total symbols
public void setSymbolCount(int count) {
header.putInt(IMAGE_FILE_HEADER.NumberOfSymbols.off, count);
}
// Update header with the offset of symbol table
public void setSymbolOff(int offset) {
header.putInt(IMAGE_FILE_HEADER.PointerToSymbolTable.off, offset);
}
public byte[] getArray() {
return header.array();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -20,38 +20,30 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.common.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
package jdk.tools.jaotc.binformat.pecoff;
/**
* Mimic a set implementation with an ArrayList. Beneficial for small sets (compared to
* {@link HashSet}).
*/
public class ArraySet<E> extends ArrayList<E> implements Set<E> {
private static final long serialVersionUID = 4476957522387436654L;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public ArraySet() {
super();
import jdk.tools.jaotc.binformat.pecoff.PECoff;
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION;
import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
public class PECoffRelocEntry {
ByteBuffer entry;
public PECoffRelocEntry(int offset, int symno, int type) {
entry = PECoffByteBuffer.allocate(IMAGE_RELOCATION.totalsize);
entry.putInt(IMAGE_RELOCATION.VirtualAddress.off, offset);
entry.putInt(IMAGE_RELOCATION.SymbolTableIndex.off, symno);
entry.putChar(IMAGE_RELOCATION.Type.off, (char)type);
}
public ArraySet(int i) {
super(i);
}
public ArraySet(Collection<? extends E> c) {
super(c);
}
@Override
public boolean add(E e) {
// avoid duplicated entries
if (contains(e)) {
return false;
}
return super.add(e);
public byte[] getArray() {
return entry.array();
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.pecoff;
import java.util.ArrayList;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.pecoff.PECoff;
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION;
import jdk.tools.jaotc.binformat.pecoff.PECoffRelocEntry;
import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
public class PECoffRelocTable {
ArrayList<ArrayList<PECoffRelocEntry>> relocEntries;
public PECoffRelocTable(int numsects) {
relocEntries = new ArrayList<ArrayList<PECoffRelocEntry>>(numsects);
for (int i = 0; i < numsects; i++)
relocEntries.add(new ArrayList<PECoffRelocEntry>());
}
public void createRelocationEntry(int sectindex,
int offset,
int symno,
int type) {
PECoffRelocEntry entry = new PECoffRelocEntry(offset,
symno,
type);
relocEntries.get(sectindex).add(entry);
}
public int getAlign() { return (4); }
public int getNumRelocs(int section_index) {
return relocEntries.get(section_index).size();
}
// Return the relocation entries for a single section
// or null if no entries added to section
public byte [] getRelocData(int section_index) {
ArrayList<PECoffRelocEntry> entryList = relocEntries.get(section_index);
int entryCount = entryList.size();
int allocCount = entryCount;
if (entryCount == 0)
return null;
if (entryCount > 0xFFFF)
allocCount++;
ByteBuffer relocData = PECoffByteBuffer.allocate(allocCount * IMAGE_RELOCATION.totalsize);
// If number of relocs exceeds 65K, add the real size
// in a dummy first reloc entry
if (entryCount > 0xFFFF) {
PECoffRelocEntry entry = new PECoffRelocEntry(allocCount, 0, 0);
relocData.put(entry.getArray());
}
// Copy each entry to a single ByteBuffer
for (int i = 0; i < entryCount; i++) {
PECoffRelocEntry entry = entryList.get(i);
relocData.put(entry.getArray());
}
return (relocData.array());
}
}

View File

@ -0,0 +1,140 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.pecoff;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.pecoff.PECoff;
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SECTION_HEADER;
import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
public class PECoffSection {
ByteBuffer section;
byte [] data;
boolean hasrelocations;
int sectionIndex;
int align;
public PECoffSection(String sectName, byte [] sectData, int sectFlags,
boolean hasRelocations, int sectIndex) {
section = PECoffByteBuffer.allocate(IMAGE_SECTION_HEADER.totalsize);
// bug: If JVM.oop.got section is empty, VM exits since JVM.oop.got
// symbol ends up as external forwarded reference.
if (sectData.length == 0) sectData = new byte[8];
// Copy only Max allowed bytes to Section Entry
byte [] Name = sectName.getBytes();
int max = Name.length <= IMAGE_SECTION_HEADER.Name.sz ?
Name.length : IMAGE_SECTION_HEADER.Name.sz;
section.put(Name, IMAGE_SECTION_HEADER.Name.off, max);
section.putInt(IMAGE_SECTION_HEADER.VirtualSize.off, 0);
section.putInt(IMAGE_SECTION_HEADER.VirtualAddress.off, 0);
section.putInt(IMAGE_SECTION_HEADER.SizeOfRawData.off, sectData.length);
section.putInt(IMAGE_SECTION_HEADER.PointerToLinenumbers.off, 0);
section.putChar(IMAGE_SECTION_HEADER.NumberOfLinenumbers.off, (char)0);
section.putInt(IMAGE_SECTION_HEADER.Characteristics.off, sectFlags);
// Extract alignment from Characteristics field
int alignshift = (sectFlags & IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_MASK) >>
IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_SHIFT;
// Use 8 byte alignment if not specified
if (alignshift == 0)
alignshift = 3;
else
--alignshift;
align = 1 << alignshift;
data = sectData;
hasrelocations = hasRelocations;
sectionIndex = sectIndex;
}
public long getSize() {
return section.getInt(IMAGE_SECTION_HEADER.SizeOfRawData.off);
}
public int getDataAlign() {
return (align);
}
// Alignment requirements for the IMAGE_SECTION_HEADER structures
public static int getShdrAlign() {
return (4);
}
public byte[] getArray() {
return section.array();
}
public byte[] getDataArray() {
return data;
}
public void setOffset(long offset) {
section.putInt(IMAGE_SECTION_HEADER.PointerToRawData.off, (int)offset);
}
public long getOffset() {
return (section.getInt(IMAGE_SECTION_HEADER.PointerToRawData.off));
}
public void setReloff(int offset) {
section.putInt(IMAGE_SECTION_HEADER.PointerToRelocations.off, offset);
}
public void setRelcount(int count) {
// If the number of relocs is larger than 65K, then set
// the overflow bit. The real count will be written to
// the first reloc entry for this section.
if (count > 0xFFFF) {
int flags;
section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char)0xFFFF);
flags = section.getInt(IMAGE_SECTION_HEADER.Characteristics.off);
flags |= IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_NRELOC_OVFL;
section.putInt(IMAGE_SECTION_HEADER.Characteristics.off, flags);
}
else {
section.putChar(IMAGE_SECTION_HEADER.NumberOfRelocations.off, (char)count);
}
}
public boolean hasRelocations() {
return hasrelocations;
}
public int getSectionId() {
return sectionIndex;
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.pecoff;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.tools.jaotc.binformat.NativeSymbol;
import jdk.tools.jaotc.binformat.pecoff.PECoff;
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL;
import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
public class PECoffSymbol extends NativeSymbol {
ByteBuffer sym;
public PECoffSymbol(int symbolindex, int strindex, byte type, byte storageclass,
byte sectindex, long offset, long size) {
super(symbolindex);
sym = PECoffByteBuffer.allocate(IMAGE_SYMBOL.totalsize);
// We don't use short names
sym.putInt(IMAGE_SYMBOL.Short.off, 0);
sym.putInt(IMAGE_SYMBOL.Long.off, strindex);
sym.putInt(IMAGE_SYMBOL.Value.off, (int)offset);
// Section indexes start at 1 but we manage the index internally
// as 0 relative except in this structure
sym.putChar(IMAGE_SYMBOL.SectionNumber.off, (char)(sectindex+1));
sym.putChar(IMAGE_SYMBOL.Type.off, (char)type);
sym.put(IMAGE_SYMBOL.StorageClass.off, storageclass);
sym.put(IMAGE_SYMBOL.NumberOfAuxSymbols.off, (byte)0);
}
public byte[] getArray() {
return sym.array();
}
}

View File

@ -0,0 +1,151 @@
/*
* Copyright (c) 2017, 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.
*/
package jdk.tools.jaotc.binformat.pecoff;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import jdk.tools.jaotc.binformat.pecoff.PECoff;
import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL;
import jdk.tools.jaotc.binformat.pecoff.PECoffSymbol;
import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
public class PECoffSymtab {
ArrayList<PECoffSymbol>symbols = new ArrayList<PECoffSymbol>();
/**
* number of symbols added
*/
int symbolCount;
/**
* String holding symbol table strings
*/
private StringBuilder strTabContent;
/**
* Keeps track of bytes in string table since strTabContent.length()
* is number of chars, not bytes.
*/
private int strTabNrOfBytes;
/**
* String holding Linker Directives
*/
private StringBuilder directives;
public PECoffSymtab() {
symbolCount = 0;
strTabContent = new StringBuilder();
directives = new StringBuilder();
// The first 4 bytes of the string table contain
// the length of the table (including this length field).
strTabNrOfBytes = 4;
// Make room for the 4 byte length field
strTabContent.append('\0').append('\0').append('\0').append('\0');
// Linker Directives start with 3 spaces to signify ANSI
directives.append(" ");
}
public PECoffSymbol addSymbolEntry(String name, byte type, byte storageclass,
byte secHdrIndex, long offset, long size) {
// Get the current symbol index and append symbol name to string table.
int index;
PECoffSymbol sym;
if (name.isEmpty()) {
index = 0;
strTabContent.append('\0');
strTabNrOfBytes += 1;
sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset, size);
symbols.add(sym);
} else {
int nameSize = name.getBytes().length;
// We can't trust strTabContent.length() since that is
// chars (UTF16), keep track of bytes on our own.
index = strTabNrOfBytes;
// strTabContent.append('_').append(name).append('\0');
strTabContent.append(name).append('\0');
strTabNrOfBytes += (nameSize + 1);
sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset, size);
symbols.add(sym);
if (storageclass == IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL)
addDirective(name, type);
}
symbolCount++;
return (sym);
}
private void addDirective(String name, byte type) {
directives.append("/EXPORT:" + name);
if(type != IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION) {
directives.append(",DATA");
}
directives.append(" ");
}
public int getSymtabCount() {
return symbolCount;
}
public int getStrtabSize() {
return strTabNrOfBytes;
}
// Return a byte array that contains the symbol table entries
public byte[] getSymtabArray() {
ByteBuffer symtabData = PECoffByteBuffer.allocate(symbolCount*IMAGE_SYMBOL.totalsize);
symtabData.order(ByteOrder.LITTLE_ENDIAN);
// copy all symbols
for (int i = 0; i < symbolCount; i++ ) {
PECoffSymbol sym = symbols.get(i);
byte [] arr = sym.getArray();
symtabData.put(arr);
}
return (symtabData.array());
}
// Return the string table array
public byte[] getStrtabArray() {
byte [] strs = strTabContent.toString().getBytes();
// Update the size of the string table
ByteBuffer buff = ByteBuffer.wrap(strs);
buff.order(ByteOrder.LITTLE_ENDIAN);
buff.putInt(0, strTabNrOfBytes);
return (strs);
}
public byte[] getDirectiveArray() {
return (directives.toString().getBytes());
}
}

Some files were not shown because too many files have changed in this diff Show More