8087333: Optionally Pre-Generate the HotSpot Template Interpreter
Optional support for pregenerated template interpreter Reviewed-by: coleenp, dholmes, kvn
This commit is contained in:
parent
a7f0956201
commit
5aec2dc9fc
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 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
|
||||
@ -48,8 +48,13 @@ public class CodeCache {
|
||||
Type type = db.lookupType("CodeCache");
|
||||
|
||||
// Get array of CodeHeaps
|
||||
// Note: CodeHeap may be subclassed with optional private heap mechanisms.
|
||||
Type codeHeapType = db.lookupType("CodeHeap");
|
||||
VirtualBaseConstructor heapConstructor =
|
||||
new VirtualBaseConstructor(db, codeHeapType, "sun.jvm.hotspot.memory", CodeHeap.class);
|
||||
|
||||
AddressField heapsField = type.getAddressField("_heaps");
|
||||
heapArray = GrowableArray.create(heapsField.getValue(), new StaticBaseConstructor<CodeHeap>(CodeHeap.class));
|
||||
heapArray = GrowableArray.create(heapsField.getValue(), heapConstructor);
|
||||
|
||||
scavengeRootNMethodsField = type.getAddressField("_scavenge_root_nmethods");
|
||||
|
||||
@ -180,31 +185,9 @@ public class CodeCache {
|
||||
|
||||
public void iterate(CodeCacheVisitor visitor) {
|
||||
visitor.prologue(lowBound(), highBound());
|
||||
CodeBlob lastBlob = null;
|
||||
|
||||
for (int i = 0; i < heapArray.length(); ++i) {
|
||||
CodeHeap current_heap = heapArray.at(i);
|
||||
Address ptr = current_heap.begin();
|
||||
while (ptr != null && ptr.lessThan(current_heap.end())) {
|
||||
try {
|
||||
// Use findStart to get a pointer inside blob other findBlob asserts
|
||||
CodeBlob blob = findBlobUnsafe(current_heap.findStart(ptr));
|
||||
if (blob != null) {
|
||||
visitor.visit(blob);
|
||||
if (blob == lastBlob) {
|
||||
throw new InternalError("saw same blob twice");
|
||||
}
|
||||
lastBlob = blob;
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Address next = current_heap.nextBlock(ptr);
|
||||
if (next != null && next.lessThan(ptr)) {
|
||||
throw new InternalError("pointer moved backwards");
|
||||
}
|
||||
ptr = next;
|
||||
}
|
||||
current_heap.iterate(visitor, this);
|
||||
}
|
||||
visitor.epilogue();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 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
|
||||
@ -25,6 +25,7 @@
|
||||
package sun.jvm.hotspot.memory;
|
||||
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.code.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
@ -90,7 +91,7 @@ public class CodeHeap extends VMObject {
|
||||
return h.getAllocatedSpace();
|
||||
}
|
||||
|
||||
public Address nextBlock(Address ptr) {
|
||||
private Address nextBlock(Address ptr) {
|
||||
Address base = blockBase(ptr);
|
||||
if (base == null) {
|
||||
return null;
|
||||
@ -99,6 +100,31 @@ public class CodeHeap extends VMObject {
|
||||
return base.addOffsetTo(block.getLength() * (1 << getLog2SegmentSize()));
|
||||
}
|
||||
|
||||
public void iterate(CodeCacheVisitor visitor, CodeCache cache) {
|
||||
CodeBlob lastBlob = null;
|
||||
Address ptr = begin();
|
||||
while (ptr != null && ptr.lessThan(end())) {
|
||||
try {
|
||||
// Use findStart to get a pointer inside blob other findBlob asserts
|
||||
CodeBlob blob = cache.createCodeBlobWrapper(findStart(ptr));
|
||||
if (blob != null) {
|
||||
visitor.visit(blob);
|
||||
if (blob == lastBlob) {
|
||||
throw new InternalError("saw same blob twice");
|
||||
}
|
||||
lastBlob = blob;
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Address next = nextBlock(ptr);
|
||||
if (next != null && next.lessThan(ptr)) {
|
||||
throw new InternalError("pointer moved backwards");
|
||||
}
|
||||
ptr = next;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Internals only below this point
|
||||
//
|
||||
|
@ -118,7 +118,8 @@ SIMPLE_DIRS = \
|
||||
$(PLATFORM_DIR)/generated/dependencies \
|
||||
$(PLATFORM_DIR)/generated/adfiles \
|
||||
$(PLATFORM_DIR)/generated/jvmtifiles \
|
||||
$(PLATFORM_DIR)/generated/tracefiles
|
||||
$(PLATFORM_DIR)/generated/tracefiles \
|
||||
$(PLATFORM_DIR)/generated/extensions
|
||||
|
||||
TARGETS = debug fastdebug optimized product
|
||||
SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS))
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2003, 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
|
||||
@ -34,7 +34,7 @@ DEMANGLE = $(DEMANGLER) < $@ > .$@ && $(MV) -f .$@ $@
|
||||
CC_COMPILE = $(CC) $(CXXFLAGS) $(CFLAGS)
|
||||
CXX_COMPILE = $(CXX) $(CXXFLAGS) $(CFLAGS)
|
||||
|
||||
AS.S = $(AS) $(ASFLAGS)
|
||||
AS.S = $(AS) $(ASFLAGS)
|
||||
|
||||
COMPILE.CC = $(CC_COMPILE) -c
|
||||
GENASM.CC = $(CC_COMPILE) -S
|
||||
@ -170,6 +170,12 @@ endif
|
||||
$(QUIETLY) $(REMOVE_TARGET)
|
||||
$(QUIETLY) $(AS.S) $(DEPFLAGS) -o $@ $< $(COMPILE_DONE)
|
||||
|
||||
# gcc applies preprocessing if the file extension is .S instead of .s
|
||||
%.o: %.S
|
||||
@echo $(LOG_INFO) Preprocessing and assembling $<
|
||||
$(QUIETLY) $(REMOVE_TARGET)
|
||||
$(QUIETLY) $(AS.S) $(DEPFLAGS) -o $@ $< $(COMPILE_DONE)
|
||||
|
||||
%.s: %.cpp
|
||||
@echo $(LOG_INFO) Generating assembly for $<
|
||||
$(QUIETLY) $(GENASM.CXX) -o $@ $<
|
||||
|
@ -54,7 +54,7 @@ endif
|
||||
# Src_Dirs_V is everything in src/share/vm/*, plus the right os/*/vm and cpu/*/vm
|
||||
# The adfiles directory contains ad_<arch>.[ch]pp.
|
||||
# The jvmtifiles directory contains jvmti*.[ch]pp
|
||||
Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles $(GENERATED)/tracefiles
|
||||
Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles $(GENERATED)/tracefiles $(GENERATED)/extensions
|
||||
VPATH += $(Src_Dirs_V:%=%:)
|
||||
|
||||
# set INCLUDES for C preprocessor.
|
||||
@ -161,6 +161,8 @@ CORE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \
|
||||
fi)
|
||||
endif
|
||||
|
||||
CORE_PATHS+=$(GENERATED)/extensions
|
||||
|
||||
COMPILER1_PATHS := $(call altsrc,$(HS_COMMON_SRC)/share/vm/c1)
|
||||
COMPILER1_PATHS += $(HS_COMMON_SRC)/share/vm/c1
|
||||
|
||||
@ -207,6 +209,8 @@ ifeq ($(Platform_arch_model), x86_64)
|
||||
Src_Files_EXCLUDE += \*x86_32\*
|
||||
endif
|
||||
|
||||
Src_Files_BASE += \*.c \*.cpp \*.s
|
||||
|
||||
# Alternate vm.make
|
||||
# This has to be included here to allow changes to the source
|
||||
# directories and excluded files before they are expanded
|
||||
@ -216,13 +220,13 @@ endif
|
||||
# Locate all source files in the given directory, excluding files in Src_Files_EXCLUDE.
|
||||
define findsrc
|
||||
$(notdir $(shell find $(1)/. ! -name . -prune \
|
||||
-a \( -name \*.c -o -name \*.cpp -o -name \*.s \) \
|
||||
-a \( -name DUMMY $(addprefix -o -name ,$(Src_Files_BASE)) \) \
|
||||
-a ! \( -name DUMMY $(addprefix -o -name ,$(Src_Files_EXCLUDE)) \)))
|
||||
endef
|
||||
|
||||
Src_Files := $(foreach e,$(Src_Dirs),$(call findsrc,$(e)))
|
||||
|
||||
Obj_Files = $(sort $(addsuffix .o,$(basename $(Src_Files))))
|
||||
Obj_Files = $(sort $(addsuffix .o,$(basename $(Src_Files))) $(EXTENDED_JVM_OBJ_FILES))
|
||||
|
||||
JVM_OBJ_FILES = $(Obj_Files)
|
||||
|
||||
@ -244,10 +248,16 @@ VMDEF_PAT = ^_ZTV
|
||||
VMDEF_PAT := ^gHotSpotVM|$(VMDEF_PAT)
|
||||
VMDEF_PAT := ^UseSharedSpaces$$|$(VMDEF_PAT)
|
||||
VMDEF_PAT := ^_ZN9Arguments17SharedArchivePathE$$|$(VMDEF_PAT)
|
||||
ifneq ($(VMDEF_PAT_EXT),)
|
||||
VMDEF_PAT := $(VMDEF_PAT_EXT)|$(VMDEF_PAT)
|
||||
endif
|
||||
|
||||
vm.def: $(Res_Files) $(Obj_Files)
|
||||
vm.def: $(Res_Files) $(Obj_Files) $(VM_DEF_EXT)
|
||||
$(QUIETLY) $(NM) --defined-only $(Obj_Files) | sort -k3 -u | \
|
||||
awk '$$3 ~ /$(VMDEF_PAT)/ { print "\t" $$3 ";" }' > $@
|
||||
ifneq ($(VM_DEF_EXT),)
|
||||
cat $(VM_DEF_EXT) >> $@
|
||||
endif
|
||||
|
||||
mapfile_ext:
|
||||
rm -f $@
|
||||
|
@ -504,6 +504,7 @@ class CodeBuffer: public StackObj {
|
||||
|
||||
// Properties
|
||||
const char* name() const { return _name; }
|
||||
void set_name(const char* name) { _name = name; }
|
||||
CodeBuffer* before_expand() const { return _before_expand; }
|
||||
BufferBlob* blob() const { return _blob; }
|
||||
void set_blob(BufferBlob* blob);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "code/codeBlob.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "code/compiledIC.hpp"
|
||||
#include "code/pcDesc.hpp"
|
||||
#include "code/scopeDesc.hpp"
|
||||
@ -183,20 +184,25 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) {
|
||||
// create code buffer for code storage
|
||||
CodeBuffer code(buffer_blob);
|
||||
|
||||
Compilation::setup_code_buffer(&code, 0);
|
||||
|
||||
// create assembler for code generation
|
||||
StubAssembler* sasm = new StubAssembler(&code, name_for(id), id);
|
||||
// generate code for runtime stub
|
||||
OopMapSet* oop_maps;
|
||||
oop_maps = generate_code_for(id, sasm);
|
||||
assert(oop_maps == NULL || sasm->frame_size() != no_frame_size,
|
||||
"if stub has an oop map it must have a valid frame size");
|
||||
int frame_size;
|
||||
bool must_gc_arguments;
|
||||
|
||||
if (!CodeCacheExtensions::skip_compiler_support()) {
|
||||
// bypass useless code generation
|
||||
Compilation::setup_code_buffer(&code, 0);
|
||||
|
||||
// create assembler for code generation
|
||||
StubAssembler* sasm = new StubAssembler(&code, name_for(id), id);
|
||||
// generate code for runtime stub
|
||||
oop_maps = generate_code_for(id, sasm);
|
||||
assert(oop_maps == NULL || sasm->frame_size() != no_frame_size,
|
||||
"if stub has an oop map it must have a valid frame size");
|
||||
|
||||
#ifdef ASSERT
|
||||
// Make sure that stubs that need oopmaps have them
|
||||
switch (id) {
|
||||
// These stubs don't need to have an oopmap
|
||||
// Make sure that stubs that need oopmaps have them
|
||||
switch (id) {
|
||||
// These stubs don't need to have an oopmap
|
||||
case dtrace_object_alloc_id:
|
||||
case g1_pre_barrier_slow_id:
|
||||
case g1_post_barrier_slow_id:
|
||||
@ -209,23 +215,32 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) {
|
||||
#endif
|
||||
break;
|
||||
|
||||
// All other stubs should have oopmaps
|
||||
// All other stubs should have oopmaps
|
||||
default:
|
||||
assert(oop_maps != NULL, "must have an oopmap");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// align so printing shows nop's instead of random code at the end (SimpleStubs are aligned)
|
||||
sasm->align(BytesPerWord);
|
||||
// make sure all code is in code buffer
|
||||
sasm->flush();
|
||||
// align so printing shows nop's instead of random code at the end (SimpleStubs are aligned)
|
||||
sasm->align(BytesPerWord);
|
||||
// make sure all code is in code buffer
|
||||
sasm->flush();
|
||||
|
||||
frame_size = sasm->frame_size();
|
||||
must_gc_arguments = sasm->must_gc_arguments();
|
||||
} else {
|
||||
/* ignored values */
|
||||
oop_maps = NULL;
|
||||
frame_size = 0;
|
||||
must_gc_arguments = false;
|
||||
}
|
||||
// create blob - distinguish a few special cases
|
||||
CodeBlob* blob = RuntimeStub::new_runtime_stub(name_for(id),
|
||||
&code,
|
||||
CodeOffsets::frame_never_safe,
|
||||
sasm->frame_size(),
|
||||
frame_size,
|
||||
oop_maps,
|
||||
sasm->must_gc_arguments());
|
||||
must_gc_arguments);
|
||||
// install blob
|
||||
assert(blob != NULL, "blob must exist");
|
||||
_blobs[id] = blob;
|
||||
@ -399,7 +414,7 @@ static nmethod* counter_overflow_helper(JavaThread* THREAD, int branch_bci, Meth
|
||||
CompLevel level = (CompLevel)nm->comp_level();
|
||||
int bci = InvocationEntryBci;
|
||||
if (branch_bci != InvocationEntryBci) {
|
||||
// Compute desination bci
|
||||
// Compute destination bci
|
||||
address pc = method()->code_base() + branch_bci;
|
||||
Bytecodes::Code branch = Bytecodes::code_at(method(), pc);
|
||||
int offset = 0;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "code/codeBlob.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "code/relocInfo.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "interpreter/bytecode.hpp"
|
||||
@ -194,6 +195,7 @@ BufferBlob* BufferBlob::create(const char* name, int buffer_size) {
|
||||
|
||||
BufferBlob* blob = NULL;
|
||||
unsigned int size = sizeof(BufferBlob);
|
||||
CodeCacheExtensions::size_blob(name, &buffer_size);
|
||||
// align the size to CodeEntryAlignment
|
||||
size = align_code_offset(size);
|
||||
size += round_to(buffer_size, oopSize);
|
||||
@ -277,6 +279,7 @@ MethodHandlesAdapterBlob* MethodHandlesAdapterBlob::create(int buffer_size) {
|
||||
|
||||
MethodHandlesAdapterBlob* blob = NULL;
|
||||
unsigned int size = sizeof(MethodHandlesAdapterBlob);
|
||||
CodeCacheExtensions::size_blob("MethodHandles adapters", &buffer_size);
|
||||
// align the size to CodeEntryAlignment
|
||||
size = align_code_offset(size);
|
||||
size += round_to(buffer_size, oopSize);
|
||||
@ -317,11 +320,13 @@ RuntimeStub* RuntimeStub::new_runtime_stub(const char* stub_name,
|
||||
{
|
||||
RuntimeStub* stub = NULL;
|
||||
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
|
||||
{
|
||||
if (!CodeCacheExtensions::skip_code_generation()) {
|
||||
// bypass useless code generation
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
unsigned int size = allocation_size(cb, sizeof(RuntimeStub));
|
||||
stub = new (size) RuntimeStub(stub_name, cb, size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments);
|
||||
}
|
||||
stub = (RuntimeStub*) CodeCacheExtensions::handle_generated_blob(stub, stub_name);
|
||||
|
||||
trace_new_stub(stub, "RuntimeStub - ", stub_name);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 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
|
||||
@ -38,7 +38,8 @@ struct CodeBlobType {
|
||||
MethodProfiled = 1, // Execution level 2 and 3 (profiled) nmethods
|
||||
NonNMethod = 2, // Non-nmethods like Buffers, Adapters and Runtime Stubs
|
||||
All = 3, // All types (No code cache segmentation)
|
||||
NumTypes = 4 // Number of CodeBlobTypes
|
||||
Pregenerated = 4, // Special blobs, managed by CodeCacheExtensions
|
||||
NumTypes = 5 // Number of CodeBlobTypes
|
||||
};
|
||||
};
|
||||
|
||||
@ -63,6 +64,7 @@ class DeoptimizationBlob;
|
||||
class CodeBlob VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
friend class VMStructs;
|
||||
friend class CodeCacheDumper;
|
||||
|
||||
private:
|
||||
const char* _name;
|
||||
@ -206,6 +208,14 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
|
||||
void set_strings(CodeStrings& strings) {
|
||||
_strings.assign(strings);
|
||||
}
|
||||
|
||||
static ByteSize name_field_offset() {
|
||||
return byte_offset_of(CodeBlob, _name);
|
||||
}
|
||||
|
||||
static ByteSize oop_maps_field_offset() {
|
||||
return byte_offset_of(CodeBlob, _oop_maps);
|
||||
}
|
||||
};
|
||||
|
||||
class WhiteBox;
|
||||
|
@ -409,7 +409,7 @@ CodeBlob* CodeCache::allocate(int size, int code_blob_type, bool strict) {
|
||||
}
|
||||
if (PrintCodeCacheExtension) {
|
||||
ResourceMark rm;
|
||||
if (SegmentedCodeCache) {
|
||||
if (_heaps->length() >= 1) {
|
||||
tty->print("%s", heap->name());
|
||||
} else {
|
||||
tty->print("CodeCache");
|
||||
@ -1211,7 +1211,7 @@ void CodeCache::print_internals() {
|
||||
|
||||
int i = 0;
|
||||
FOR_ALL_HEAPS(heap) {
|
||||
if (SegmentedCodeCache && Verbose) {
|
||||
if ((_heaps->length() >= 1) && Verbose) {
|
||||
tty->print_cr("-- %s --", (*heap)->name());
|
||||
}
|
||||
FOR_ALL_BLOBS(cb, *heap) {
|
||||
@ -1360,7 +1360,7 @@ void CodeCache::print_summary(outputStream* st, bool detailed) {
|
||||
FOR_ALL_HEAPS(heap_iterator) {
|
||||
CodeHeap* heap = (*heap_iterator);
|
||||
size_t total = (heap->high_boundary() - heap->low_boundary());
|
||||
if (SegmentedCodeCache) {
|
||||
if (_heaps->length() >= 1) {
|
||||
st->print("%s:", heap->name());
|
||||
} else {
|
||||
st->print("CodeCache:");
|
||||
|
@ -78,6 +78,7 @@ class CodeCache : AllStatic {
|
||||
friend class VMStructs;
|
||||
friend class NMethodIterator;
|
||||
friend class WhiteBox;
|
||||
friend class CodeCacheLoader;
|
||||
private:
|
||||
// CodeHeaps of the cache
|
||||
static GrowableArray<CodeHeap*>* _heaps;
|
||||
|
52
hotspot/src/share/vm/code/codeCacheExtensions.hpp
Normal file
52
hotspot/src/share/vm/code/codeCacheExtensions.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_HPP
|
||||
#define SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class CodeCacheExtensionsSteps: AllStatic {
|
||||
public:
|
||||
enum Step {
|
||||
// Support for optional fine grain initialization hooks
|
||||
// Note: these hooks must support refining the granularity
|
||||
// (e.g. adding intermediate steps in the ordered enum
|
||||
// if needed for future features)
|
||||
Start,
|
||||
VMVersion,
|
||||
StubRoutines1,
|
||||
Universe,
|
||||
TemplateInterpreter,
|
||||
Interpreter,
|
||||
StubRoutines2,
|
||||
InitGlobals,
|
||||
CreateVM,
|
||||
LastStep
|
||||
};
|
||||
};
|
||||
|
||||
#include "code/codeCacheExtensions_ext.hpp"
|
||||
|
||||
#endif // SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_HPP
|
130
hotspot/src/share/vm/code/codeCacheExtensions_ext.hpp
Normal file
130
hotspot/src/share/vm/code/codeCacheExtensions_ext.hpp
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_EXT_HPP
|
||||
#define SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_EXT_HPP
|
||||
|
||||
#include "utilities/macros.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
|
||||
class AdapterHandlerEntry;
|
||||
class CodeBlob;
|
||||
class CodeBuffer;
|
||||
class InterpreterMacroAssembler;
|
||||
class Template;
|
||||
|
||||
// All the methods defined here are placeholders for possible extensions.
|
||||
|
||||
class CodeCacheExtensions: AllStatic {
|
||||
friend class CodeCacheDumper;
|
||||
|
||||
public:
|
||||
// init both code saving and loading
|
||||
// Must be called very early, before any code is generated.
|
||||
static void initialize() {}
|
||||
|
||||
// Check whether the generated interpreter will be saved.
|
||||
static bool saving_generated_interpreter() { return false; }
|
||||
|
||||
// Check whether a pregenerated interpreter is used.
|
||||
static bool use_pregenerated_interpreter() { return false; }
|
||||
|
||||
// Placeholder for additional VM initialization code
|
||||
static void complete_step(CodeCacheExtensionsSteps::Step phase) {}
|
||||
|
||||
// Return false for newly generated code, on systems where it is not
|
||||
// executable.
|
||||
static bool is_executable(void *pc) { return true; }
|
||||
|
||||
// Return whether dynamically generated code can be executable
|
||||
static bool support_dynamic_code() { return true; }
|
||||
|
||||
// Skip new code generation when known to be useless.
|
||||
static bool skip_code_generation() { return false; }
|
||||
|
||||
// Skip stubs used only for compiled code support.
|
||||
static bool skip_compiler_support() { return false; }
|
||||
|
||||
// Ignore UseFastSignatureHandlers when returning false
|
||||
static bool support_fast_signature_handlers() { return true; }
|
||||
|
||||
/////////////////////////
|
||||
// Handle generated code:
|
||||
// - allow newly generated code to be shared
|
||||
// - allow pregenerated code to be used in place of the newly generated one
|
||||
// (modifying pc).
|
||||
// - support remapping when doing both save and load
|
||||
// 'remap' can be set to false if the addresses handled are not referenced
|
||||
// from code generated later.
|
||||
|
||||
// Associate a name to a generated codelet and possibly modify the pc
|
||||
// Note: use instead the specialized versions when they exist:
|
||||
// - handle_generated_blob for CodeBlob
|
||||
// - handle_generated_handler for SignatureHandlers
|
||||
// See also the optimized calls below that handle several PCs at once.
|
||||
static void handle_generated_pc(address &pc, const char *name) {}
|
||||
|
||||
// Adds a safe definition of the codelet, for codelets used right after
|
||||
// generation (else we would need to immediately stop the JVM and convert
|
||||
// the generated code to executable format before being able to go further).
|
||||
static void handle_generated_pc(address &pc, const char *name, address default_entry) {}
|
||||
|
||||
// Special cases
|
||||
|
||||
// Special case for CodeBlobs, which may require blob specific actions.
|
||||
static CodeBlob* handle_generated_blob(CodeBlob* blob, const char *name = NULL) { return blob; }
|
||||
|
||||
// Special case for Signature Handlers.
|
||||
static void handle_generated_handler(address &handler_start, const char *name, address handler_end) {}
|
||||
|
||||
// Support for generating different variants of the interpreter
|
||||
// that can be dynamically selected after reload.
|
||||
//
|
||||
// - init_interpreter_assembler allows to configure the assembler for
|
||||
// the current variant
|
||||
//
|
||||
// - needs_other_interpreter_variant returns true as long as other
|
||||
// variants are needed.
|
||||
//
|
||||
// - skip_template_interpreter_entries returns true if new entries
|
||||
// need not be generated for this masm setup and this bytecode
|
||||
//
|
||||
// - completed_template_interpreter_entries is called after new
|
||||
// entries have been generated and installed, for any non skipped
|
||||
// bytecode.
|
||||
static void init_interpreter_assembler(InterpreterMacroAssembler* masm, CodeBuffer* code) {}
|
||||
static bool needs_other_interpreter_variant() { return false; }
|
||||
static bool skip_template_interpreter_entries(Bytecodes::Code code) { return false; }
|
||||
static void completed_template_interpreter_entries(InterpreterMacroAssembler* masm, Bytecodes::Code code) {}
|
||||
|
||||
// Code size optimization. May optimize the requested size.
|
||||
static void size_blob(const char* name, int *updatable_size) {}
|
||||
|
||||
// ergonomics
|
||||
static void set_ergonomics_flags() {}
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_EXT_HPP
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -261,3 +261,17 @@ void StubQueue::print() {
|
||||
stub_print(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Fixup for pregenerated code
|
||||
void StubQueue::fix_buffer(address buffer, address queue_end, address buffer_end, int number_of_stubs) {
|
||||
const int extra_bytes = CodeEntryAlignment;
|
||||
_stub_buffer = buffer;
|
||||
_queue_begin = 0;
|
||||
_queue_end = queue_end - buffer;
|
||||
_number_of_stubs = number_of_stubs;
|
||||
int size = buffer_end - buffer;
|
||||
// Note: _buffer_limit must differ from _queue_end in the iteration loops
|
||||
// => add extra space at the end (preserving alignment for asserts) if needed
|
||||
if (buffer_end == queue_end) size += extra_bytes;
|
||||
_buffer_limit = _buffer_size = size;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -216,6 +216,9 @@ class StubQueue: public CHeapObj<mtCode> {
|
||||
// Debugging/printing
|
||||
void verify(); // verifies the stub queue
|
||||
void print(); // prints information about the stub queue
|
||||
|
||||
// Fixup for pregenerated code
|
||||
void fix_buffer(address buffer, address queue_end, address buffer_end, int number_of_stubs);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CODE_STUBS_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -134,8 +134,10 @@ void AbstractInterpreter::print() {
|
||||
tty->print_cr("wasted space = %6dK bytes", (int)_code->available_space()/1024);
|
||||
tty->cr();
|
||||
tty->print_cr("# of codelets = %6d" , _code->number_of_stubs());
|
||||
tty->print_cr("avg codelet size = %6d bytes", _code->used_space() / _code->number_of_stubs());
|
||||
tty->cr();
|
||||
if (_code->number_of_stubs() != 0) {
|
||||
tty->print_cr("avg codelet size = %6d bytes", _code->used_space() / _code->number_of_stubs());
|
||||
tty->cr();
|
||||
}
|
||||
_code->print();
|
||||
tty->print_cr("----------------------------------------------------------------------");
|
||||
tty->cr();
|
||||
|
@ -45,6 +45,7 @@ class InterpreterMacroAssembler;
|
||||
|
||||
class InterpreterCodelet: public Stub {
|
||||
friend class VMStructs;
|
||||
friend class CodeCacheDumper; // possible extension [do not remove]
|
||||
private:
|
||||
int _size; // the size in bytes
|
||||
const char* _description; // a description of the codelet, for debugging & printing
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
@ -1178,6 +1179,7 @@ address SignatureHandlerLibrary::set_handler(CodeBuffer* buffer) {
|
||||
ICache::invalidate_range(handler, insts_size);
|
||||
_handler = handler + insts_size;
|
||||
}
|
||||
CodeCacheExtensions::handle_generated_handler(handler, buffer->name(), _handler);
|
||||
return handler;
|
||||
}
|
||||
|
||||
@ -1186,7 +1188,7 @@ void SignatureHandlerLibrary::add(methodHandle method) {
|
||||
// use slow signature handler if we can't do better
|
||||
int handler_index = -1;
|
||||
// check if we can use customized (fast) signature handler
|
||||
if (UseFastSignatureHandlers && method->size_of_parameters() <= Fingerprinter::max_size_of_parameters) {
|
||||
if (UseFastSignatureHandlers && CodeCacheExtensions::support_fast_signature_handlers() && method->size_of_parameters() <= Fingerprinter::max_size_of_parameters) {
|
||||
// use customized signature handler
|
||||
MutexLocker mu(SignatureHandlerLibrary_lock);
|
||||
// make sure data structure is initialized
|
||||
@ -1203,14 +1205,23 @@ void SignatureHandlerLibrary::add(methodHandle method) {
|
||||
round_to((intptr_t)_buffer, CodeEntryAlignment) - (address)_buffer;
|
||||
CodeBuffer buffer((address)(_buffer + align_offset),
|
||||
SignatureHandlerLibrary::buffer_size - align_offset);
|
||||
if (!CodeCacheExtensions::support_dynamic_code()) {
|
||||
// we need a name for the signature (for lookups or saving)
|
||||
const int SYMBOL_SIZE = 50;
|
||||
char *symbolName = NEW_RESOURCE_ARRAY(char, SYMBOL_SIZE);
|
||||
// support for named signatures
|
||||
jio_snprintf(symbolName, SYMBOL_SIZE,
|
||||
"native_" UINT64_FORMAT, fingerprint);
|
||||
buffer.set_name(symbolName);
|
||||
}
|
||||
InterpreterRuntime::SignatureHandlerGenerator(method, &buffer).generate(fingerprint);
|
||||
// copy into code heap
|
||||
address handler = set_handler(&buffer);
|
||||
if (handler == NULL) {
|
||||
// use slow signature handler
|
||||
// use slow signature handler (without memorizing it in the fingerprints)
|
||||
} else {
|
||||
// debugging suppport
|
||||
if (PrintSignatureHandlers) {
|
||||
if (PrintSignatureHandlers && (handler != Interpreter::slow_signature_handler())) {
|
||||
tty->cr();
|
||||
tty->print_cr("argument handler #%d for: %s %s (fingerprint = " UINT64_FORMAT ", %d bytes generated)",
|
||||
_handlers->length(),
|
||||
@ -1218,7 +1229,10 @@ void SignatureHandlerLibrary::add(methodHandle method) {
|
||||
method->name_and_sig_as_C_string(),
|
||||
fingerprint,
|
||||
buffer.insts_size());
|
||||
Disassembler::decode(handler, handler + buffer.insts_size());
|
||||
if (buffer.insts_size() > 0) {
|
||||
// buffer may be empty for pregenerated handlers
|
||||
Disassembler::decode(handler, handler + buffer.insts_size());
|
||||
}
|
||||
#ifndef PRODUCT
|
||||
address rh_begin = Interpreter::result_handler(method()->result_type());
|
||||
if (CodeCache::contains(rh_begin)) {
|
||||
@ -1277,6 +1291,37 @@ void SignatureHandlerLibrary::add(methodHandle method) {
|
||||
#endif // ASSERT
|
||||
}
|
||||
|
||||
void SignatureHandlerLibrary::add(uint64_t fingerprint, address handler) {
|
||||
int handler_index = -1;
|
||||
// use customized signature handler
|
||||
MutexLocker mu(SignatureHandlerLibrary_lock);
|
||||
// make sure data structure is initialized
|
||||
initialize();
|
||||
fingerprint = InterpreterRuntime::normalize_fast_native_fingerprint(fingerprint);
|
||||
handler_index = _fingerprints->find(fingerprint);
|
||||
// create handler if necessary
|
||||
if (handler_index < 0) {
|
||||
if (PrintSignatureHandlers && (handler != Interpreter::slow_signature_handler())) {
|
||||
tty->cr();
|
||||
tty->print_cr("argument handler #%d at "PTR_FORMAT" for fingerprint " UINT64_FORMAT,
|
||||
_handlers->length(),
|
||||
handler,
|
||||
fingerprint);
|
||||
}
|
||||
_fingerprints->append(fingerprint);
|
||||
_handlers->append(handler);
|
||||
} else {
|
||||
if (PrintSignatureHandlers) {
|
||||
tty->cr();
|
||||
tty->print_cr("duplicate argument handler #%d for fingerprint " UINT64_FORMAT "(old: "PTR_FORMAT", new : "PTR_FORMAT")",
|
||||
_handlers->length(),
|
||||
fingerprint,
|
||||
_handlers->at(handler_index),
|
||||
handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BufferBlob* SignatureHandlerLibrary::_handler_blob = NULL;
|
||||
address SignatureHandlerLibrary::_handler = NULL;
|
||||
|
@ -219,6 +219,7 @@ class SignatureHandlerLibrary: public AllStatic {
|
||||
|
||||
public:
|
||||
static void add(methodHandle method);
|
||||
static void add(uint64_t fingerprint, address handler);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_INTERPRETER_INTERPRETERRUNTIME_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/interpreterGenerator.hpp"
|
||||
#include "interpreter/interpreterRuntime.hpp"
|
||||
@ -49,10 +50,33 @@ void TemplateInterpreter::initialize() {
|
||||
TraceTime timer("Interpreter generation", TraceStartupTime);
|
||||
int code_size = InterpreterCodeSize;
|
||||
NOT_PRODUCT(code_size *= 4;) // debug uses extra interpreter code space
|
||||
#if INCLUDE_JVMTI
|
||||
if (CodeCacheExtensions::saving_generated_interpreter()) {
|
||||
// May requires several versions of the codelets.
|
||||
// Final size will automatically be optimized.
|
||||
code_size *= 2;
|
||||
}
|
||||
#endif
|
||||
_code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL,
|
||||
"Interpreter");
|
||||
InterpreterGenerator g(_code);
|
||||
if (PrintInterpreter) print();
|
||||
}
|
||||
if (PrintInterpreter) {
|
||||
if (CodeCacheExtensions::saving_generated_interpreter() &&
|
||||
CodeCacheExtensions::use_pregenerated_interpreter()) {
|
||||
ResourceMark rm;
|
||||
tty->print("Printing the newly generated interpreter first");
|
||||
print();
|
||||
tty->print("Printing the pregenerated interpreter next");
|
||||
}
|
||||
}
|
||||
|
||||
// Install the pregenerated interpreter code before printing it
|
||||
CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::TemplateInterpreter);
|
||||
|
||||
if (PrintInterpreter) {
|
||||
ResourceMark rm;
|
||||
print();
|
||||
}
|
||||
|
||||
// initialize dispatch table
|
||||
@ -214,194 +238,203 @@ static const BasicType types[Interpreter::number_of_result_handlers] = {
|
||||
};
|
||||
|
||||
void TemplateInterpreterGenerator::generate_all() {
|
||||
AbstractInterpreterGenerator::generate_all();
|
||||
// Loop, in case we need several variants of the interpreter entries
|
||||
do {
|
||||
if (!CodeCacheExtensions::skip_code_generation()) {
|
||||
// bypass code generation when useless
|
||||
AbstractInterpreterGenerator::generate_all();
|
||||
|
||||
{ CodeletMark cm(_masm, "error exits");
|
||||
_unimplemented_bytecode = generate_error_exit("unimplemented bytecode");
|
||||
_illegal_bytecode_sequence = generate_error_exit("illegal bytecode sequence - method not verified");
|
||||
}
|
||||
{ CodeletMark cm(_masm, "error exits");
|
||||
_unimplemented_bytecode = generate_error_exit("unimplemented bytecode");
|
||||
_illegal_bytecode_sequence = generate_error_exit("illegal bytecode sequence - method not verified");
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceBytecodes) {
|
||||
CodeletMark cm(_masm, "bytecode tracing support");
|
||||
Interpreter::_trace_code =
|
||||
EntryPoint(
|
||||
generate_trace_code(btos),
|
||||
generate_trace_code(ctos),
|
||||
generate_trace_code(stos),
|
||||
generate_trace_code(atos),
|
||||
generate_trace_code(itos),
|
||||
generate_trace_code(ltos),
|
||||
generate_trace_code(ftos),
|
||||
generate_trace_code(dtos),
|
||||
generate_trace_code(vtos)
|
||||
);
|
||||
}
|
||||
if (TraceBytecodes) {
|
||||
CodeletMark cm(_masm, "bytecode tracing support");
|
||||
Interpreter::_trace_code =
|
||||
EntryPoint(
|
||||
generate_trace_code(btos),
|
||||
generate_trace_code(ctos),
|
||||
generate_trace_code(stos),
|
||||
generate_trace_code(atos),
|
||||
generate_trace_code(itos),
|
||||
generate_trace_code(ltos),
|
||||
generate_trace_code(ftos),
|
||||
generate_trace_code(dtos),
|
||||
generate_trace_code(vtos)
|
||||
);
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
||||
{ CodeletMark cm(_masm, "return entry points");
|
||||
const int index_size = sizeof(u2);
|
||||
for (int i = 0; i < Interpreter::number_of_return_entries; i++) {
|
||||
Interpreter::_return_entry[i] =
|
||||
EntryPoint(
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(atos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(ltos, i, index_size),
|
||||
generate_return_entry_for(ftos, i, index_size),
|
||||
generate_return_entry_for(dtos, i, index_size),
|
||||
generate_return_entry_for(vtos, i, index_size)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "invoke return entry points");
|
||||
const TosState states[] = {itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos};
|
||||
const int invoke_length = Bytecodes::length_for(Bytecodes::_invokestatic);
|
||||
const int invokeinterface_length = Bytecodes::length_for(Bytecodes::_invokeinterface);
|
||||
const int invokedynamic_length = Bytecodes::length_for(Bytecodes::_invokedynamic);
|
||||
|
||||
for (int i = 0; i < Interpreter::number_of_return_addrs; i++) {
|
||||
TosState state = states[i];
|
||||
Interpreter::_invoke_return_entry[i] = generate_return_entry_for(state, invoke_length, sizeof(u2));
|
||||
Interpreter::_invokeinterface_return_entry[i] = generate_return_entry_for(state, invokeinterface_length, sizeof(u2));
|
||||
Interpreter::_invokedynamic_return_entry[i] = generate_return_entry_for(state, invokedynamic_length, sizeof(u4));
|
||||
}
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "earlyret entry points");
|
||||
Interpreter::_earlyret_entry =
|
||||
EntryPoint(
|
||||
generate_earlyret_entry_for(btos),
|
||||
generate_earlyret_entry_for(ctos),
|
||||
generate_earlyret_entry_for(stos),
|
||||
generate_earlyret_entry_for(atos),
|
||||
generate_earlyret_entry_for(itos),
|
||||
generate_earlyret_entry_for(ltos),
|
||||
generate_earlyret_entry_for(ftos),
|
||||
generate_earlyret_entry_for(dtos),
|
||||
generate_earlyret_entry_for(vtos)
|
||||
);
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "deoptimization entry points");
|
||||
for (int i = 0; i < Interpreter::number_of_deopt_entries; i++) {
|
||||
Interpreter::_deopt_entry[i] =
|
||||
EntryPoint(
|
||||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(atos, i),
|
||||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(ltos, i),
|
||||
generate_deopt_entry_for(ftos, i),
|
||||
generate_deopt_entry_for(dtos, i),
|
||||
generate_deopt_entry_for(vtos, i)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "result handlers for native calls");
|
||||
// The various result converter stublets.
|
||||
int is_generated[Interpreter::number_of_result_handlers];
|
||||
memset(is_generated, 0, sizeof(is_generated));
|
||||
|
||||
for (int i = 0; i < Interpreter::number_of_result_handlers; i++) {
|
||||
BasicType type = types[i];
|
||||
if (!is_generated[Interpreter::BasicType_as_index(type)]++) {
|
||||
Interpreter::_native_abi_to_tosca[Interpreter::BasicType_as_index(type)] = generate_result_handler_for(type);
|
||||
{ CodeletMark cm(_masm, "return entry points");
|
||||
const int index_size = sizeof(u2);
|
||||
for (int i = 0; i < Interpreter::number_of_return_entries; i++) {
|
||||
Interpreter::_return_entry[i] =
|
||||
EntryPoint(
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(atos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(ltos, i, index_size),
|
||||
generate_return_entry_for(ftos, i, index_size),
|
||||
generate_return_entry_for(dtos, i, index_size),
|
||||
generate_return_entry_for(vtos, i, index_size)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "continuation entry points");
|
||||
Interpreter::_continuation_entry =
|
||||
EntryPoint(
|
||||
generate_continuation_for(btos),
|
||||
generate_continuation_for(ctos),
|
||||
generate_continuation_for(stos),
|
||||
generate_continuation_for(atos),
|
||||
generate_continuation_for(itos),
|
||||
generate_continuation_for(ltos),
|
||||
generate_continuation_for(ftos),
|
||||
generate_continuation_for(dtos),
|
||||
generate_continuation_for(vtos)
|
||||
);
|
||||
}
|
||||
{ CodeletMark cm(_masm, "invoke return entry points");
|
||||
const TosState states[] = {itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos};
|
||||
const int invoke_length = Bytecodes::length_for(Bytecodes::_invokestatic);
|
||||
const int invokeinterface_length = Bytecodes::length_for(Bytecodes::_invokeinterface);
|
||||
const int invokedynamic_length = Bytecodes::length_for(Bytecodes::_invokedynamic);
|
||||
|
||||
{ CodeletMark cm(_masm, "safepoint entry points");
|
||||
Interpreter::_safept_entry =
|
||||
EntryPoint(
|
||||
generate_safept_entry_for(btos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(ctos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(stos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(atos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(itos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(ltos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(ftos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(dtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(vtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint))
|
||||
);
|
||||
}
|
||||
for (int i = 0; i < Interpreter::number_of_return_addrs; i++) {
|
||||
TosState state = states[i];
|
||||
Interpreter::_invoke_return_entry[i] = generate_return_entry_for(state, invoke_length, sizeof(u2));
|
||||
Interpreter::_invokeinterface_return_entry[i] = generate_return_entry_for(state, invokeinterface_length, sizeof(u2));
|
||||
Interpreter::_invokedynamic_return_entry[i] = generate_return_entry_for(state, invokedynamic_length, sizeof(u4));
|
||||
}
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "exception handling");
|
||||
// (Note: this is not safepoint safe because thread may return to compiled code)
|
||||
generate_throw_exception();
|
||||
}
|
||||
{ CodeletMark cm(_masm, "earlyret entry points");
|
||||
Interpreter::_earlyret_entry =
|
||||
EntryPoint(
|
||||
generate_earlyret_entry_for(btos),
|
||||
generate_earlyret_entry_for(ctos),
|
||||
generate_earlyret_entry_for(stos),
|
||||
generate_earlyret_entry_for(atos),
|
||||
generate_earlyret_entry_for(itos),
|
||||
generate_earlyret_entry_for(ltos),
|
||||
generate_earlyret_entry_for(ftos),
|
||||
generate_earlyret_entry_for(dtos),
|
||||
generate_earlyret_entry_for(vtos)
|
||||
);
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "throw exception entrypoints");
|
||||
Interpreter::_throw_ArrayIndexOutOfBoundsException_entry = generate_ArrayIndexOutOfBounds_handler("java/lang/ArrayIndexOutOfBoundsException");
|
||||
Interpreter::_throw_ArrayStoreException_entry = generate_klass_exception_handler("java/lang/ArrayStoreException" );
|
||||
Interpreter::_throw_ArithmeticException_entry = generate_exception_handler("java/lang/ArithmeticException" , "/ by zero");
|
||||
Interpreter::_throw_ClassCastException_entry = generate_ClassCastException_handler();
|
||||
Interpreter::_throw_NullPointerException_entry = generate_exception_handler("java/lang/NullPointerException" , NULL );
|
||||
Interpreter::_throw_StackOverflowError_entry = generate_StackOverflowError_handler();
|
||||
}
|
||||
{ CodeletMark cm(_masm, "deoptimization entry points");
|
||||
for (int i = 0; i < Interpreter::number_of_deopt_entries; i++) {
|
||||
Interpreter::_deopt_entry[i] =
|
||||
EntryPoint(
|
||||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(atos, i),
|
||||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(ltos, i),
|
||||
generate_deopt_entry_for(ftos, i),
|
||||
generate_deopt_entry_for(dtos, i),
|
||||
generate_deopt_entry_for(vtos, i)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "result handlers for native calls");
|
||||
// The various result converter stublets.
|
||||
int is_generated[Interpreter::number_of_result_handlers];
|
||||
memset(is_generated, 0, sizeof(is_generated));
|
||||
|
||||
for (int i = 0; i < Interpreter::number_of_result_handlers; i++) {
|
||||
BasicType type = types[i];
|
||||
if (!is_generated[Interpreter::BasicType_as_index(type)]++) {
|
||||
Interpreter::_native_abi_to_tosca[Interpreter::BasicType_as_index(type)] = generate_result_handler_for(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "continuation entry points");
|
||||
Interpreter::_continuation_entry =
|
||||
EntryPoint(
|
||||
generate_continuation_for(btos),
|
||||
generate_continuation_for(ctos),
|
||||
generate_continuation_for(stos),
|
||||
generate_continuation_for(atos),
|
||||
generate_continuation_for(itos),
|
||||
generate_continuation_for(ltos),
|
||||
generate_continuation_for(ftos),
|
||||
generate_continuation_for(dtos),
|
||||
generate_continuation_for(vtos)
|
||||
);
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "safepoint entry points");
|
||||
Interpreter::_safept_entry =
|
||||
EntryPoint(
|
||||
generate_safept_entry_for(btos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(ctos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(stos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(atos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(itos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(ltos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(ftos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(dtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(vtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint))
|
||||
);
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "exception handling");
|
||||
// (Note: this is not safepoint safe because thread may return to compiled code)
|
||||
generate_throw_exception();
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "throw exception entrypoints");
|
||||
Interpreter::_throw_ArrayIndexOutOfBoundsException_entry = generate_ArrayIndexOutOfBounds_handler("java/lang/ArrayIndexOutOfBoundsException");
|
||||
Interpreter::_throw_ArrayStoreException_entry = generate_klass_exception_handler("java/lang/ArrayStoreException" );
|
||||
Interpreter::_throw_ArithmeticException_entry = generate_exception_handler("java/lang/ArithmeticException" , "/ by zero");
|
||||
Interpreter::_throw_ClassCastException_entry = generate_ClassCastException_handler();
|
||||
Interpreter::_throw_NullPointerException_entry = generate_exception_handler("java/lang/NullPointerException" , NULL );
|
||||
Interpreter::_throw_StackOverflowError_entry = generate_StackOverflowError_handler();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define method_entry(kind) \
|
||||
{ CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \
|
||||
Interpreter::_entry_table[Interpreter::kind] = ((InterpreterGenerator*)this)->generate_method_entry(Interpreter::kind); \
|
||||
}
|
||||
#define method_entry(kind) \
|
||||
{ CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \
|
||||
Interpreter::_entry_table[Interpreter::kind] = ((InterpreterGenerator*)this)->generate_method_entry(Interpreter::kind); \
|
||||
}
|
||||
|
||||
// all non-native method kinds
|
||||
method_entry(zerolocals)
|
||||
method_entry(zerolocals_synchronized)
|
||||
method_entry(empty)
|
||||
method_entry(accessor)
|
||||
method_entry(abstract)
|
||||
method_entry(java_lang_math_sin )
|
||||
method_entry(java_lang_math_cos )
|
||||
method_entry(java_lang_math_tan )
|
||||
method_entry(java_lang_math_abs )
|
||||
method_entry(java_lang_math_sqrt )
|
||||
method_entry(java_lang_math_log )
|
||||
method_entry(java_lang_math_log10)
|
||||
method_entry(java_lang_math_exp )
|
||||
method_entry(java_lang_math_pow )
|
||||
method_entry(java_lang_ref_reference_get)
|
||||
// all non-native method kinds
|
||||
method_entry(zerolocals)
|
||||
method_entry(zerolocals_synchronized)
|
||||
method_entry(empty)
|
||||
method_entry(accessor)
|
||||
method_entry(abstract)
|
||||
method_entry(java_lang_math_sin )
|
||||
method_entry(java_lang_math_cos )
|
||||
method_entry(java_lang_math_tan )
|
||||
method_entry(java_lang_math_abs )
|
||||
method_entry(java_lang_math_sqrt )
|
||||
method_entry(java_lang_math_log )
|
||||
method_entry(java_lang_math_log10)
|
||||
method_entry(java_lang_math_exp )
|
||||
method_entry(java_lang_math_pow )
|
||||
method_entry(java_lang_ref_reference_get)
|
||||
|
||||
if (UseCRC32Intrinsics) {
|
||||
method_entry(java_util_zip_CRC32_update)
|
||||
method_entry(java_util_zip_CRC32_updateBytes)
|
||||
method_entry(java_util_zip_CRC32_updateByteBuffer)
|
||||
}
|
||||
if (UseCRC32Intrinsics) {
|
||||
method_entry(java_util_zip_CRC32_update)
|
||||
method_entry(java_util_zip_CRC32_updateBytes)
|
||||
method_entry(java_util_zip_CRC32_updateByteBuffer)
|
||||
}
|
||||
|
||||
initialize_method_handle_entries();
|
||||
initialize_method_handle_entries();
|
||||
|
||||
// all native method kinds (must be one contiguous block)
|
||||
Interpreter::_native_entry_begin = Interpreter::code()->code_end();
|
||||
method_entry(native)
|
||||
method_entry(native_synchronized)
|
||||
Interpreter::_native_entry_end = Interpreter::code()->code_end();
|
||||
// all native method kinds (must be one contiguous block)
|
||||
Interpreter::_native_entry_begin = Interpreter::code()->code_end();
|
||||
method_entry(native)
|
||||
method_entry(native_synchronized)
|
||||
Interpreter::_native_entry_end = Interpreter::code()->code_end();
|
||||
|
||||
#undef method_entry
|
||||
|
||||
// Bytecodes
|
||||
set_entry_points_for_all_bytes();
|
||||
// Bytecodes
|
||||
set_entry_points_for_all_bytes();
|
||||
}
|
||||
} while (CodeCacheExtensions::needs_other_interpreter_variant());
|
||||
|
||||
// installation of code in other places in the runtime
|
||||
// (ExcutableCodeManager calls not needed to copy the entries)
|
||||
set_safepoints_for_all_bytes();
|
||||
}
|
||||
|
||||
@ -445,6 +478,9 @@ void TemplateInterpreterGenerator::set_unimplemented(int i) {
|
||||
|
||||
|
||||
void TemplateInterpreterGenerator::set_entry_points(Bytecodes::Code code) {
|
||||
if (CodeCacheExtensions::skip_template_interpreter_entries(code)) {
|
||||
return;
|
||||
}
|
||||
CodeletMark cm(_masm, Bytecodes::name(code), code);
|
||||
// initialize entry points
|
||||
assert(_unimplemented_bytecode != NULL, "should have been generated before");
|
||||
@ -474,6 +510,7 @@ void TemplateInterpreterGenerator::set_entry_points(Bytecodes::Code code) {
|
||||
EntryPoint entry(bep, cep, sep, aep, iep, lep, fep, dep, vep);
|
||||
Interpreter::_normal_table.set_entry(code, entry);
|
||||
Interpreter::_wentry_point[code] = wep;
|
||||
CodeCacheExtensions::completed_template_interpreter_entries(_masm, code);
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,6 +87,7 @@ class TemplateInterpreter: public AbstractInterpreter {
|
||||
friend class TemplateInterpreterGenerator;
|
||||
friend class InterpreterGenerator;
|
||||
friend class TemplateTable;
|
||||
friend class CodeCacheExtensions;
|
||||
// friend class Interpreter;
|
||||
public:
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "code/codeBlob.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/virtualspace.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
// Blocks
|
||||
|
||||
@ -80,6 +81,7 @@ class FreeBlock: public HeapBlock {
|
||||
|
||||
class CodeHeap : public CHeapObj<mtCode> {
|
||||
friend class VMStructs;
|
||||
friend class PregeneratedCodeHeap;
|
||||
private:
|
||||
VirtualSpace _memory; // the memory holding the blocks
|
||||
VirtualSpace _segmap; // the memory holding the segment map
|
||||
@ -148,8 +150,8 @@ class CodeHeap : public CHeapObj<mtCode> {
|
||||
char* high() const { return _memory.high(); }
|
||||
char* high_boundary() const { return _memory.high_boundary(); }
|
||||
|
||||
bool contains(const void* p) const { return low_boundary() <= p && p < high(); }
|
||||
void* find_start(void* p) const; // returns the block containing p or NULL
|
||||
virtual bool contains(const void* p) const { return low_boundary() <= p && p < high(); }
|
||||
virtual void* find_start(void* p) const; // returns the block containing p or NULL
|
||||
size_t alignment_unit() const; // alignment of any block
|
||||
size_t alignment_offset() const; // offset of first byte of any block, within the enclosing alignment unit
|
||||
static size_t header_size(); // returns the header size for each heap block
|
||||
@ -158,9 +160,9 @@ class CodeHeap : public CHeapObj<mtCode> {
|
||||
int freelist_length() const { return _freelist_length; } // number of elements in the freelist
|
||||
|
||||
// returns the first block or NULL
|
||||
void* first() const { return next_used(first_block()); }
|
||||
virtual void* first() const { return next_used(first_block()); }
|
||||
// returns the next block given a block p or NULL
|
||||
void* next(void* p) const { return next_used(next_block(block_start(p))); }
|
||||
virtual void* next(void* p) const { return next_used(next_block(block_start(p))); }
|
||||
|
||||
// Statistics
|
||||
size_t capacity() const;
|
||||
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "memory/virtualspace.hpp"
|
||||
#include "oops/markOop.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
@ -603,7 +604,7 @@ ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, bool large)
|
||||
ReservedCodeSpace::ReservedCodeSpace(size_t r_size,
|
||||
size_t rs_align,
|
||||
bool large) :
|
||||
ReservedSpace(r_size, rs_align, large, /*executable*/ true) {
|
||||
ReservedSpace(r_size, rs_align, large, /*executable*/ CodeCacheExtensions::support_dynamic_code()) {
|
||||
MemTracker::record_virtual_memory_type((address)base(), mtCode);
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "opto/ad.hpp"
|
||||
#include "opto/compile.hpp"
|
||||
#include "opto/matcher.hpp"
|
||||
#include "opto/node.hpp"
|
||||
#include "opto/regmask.hpp"
|
||||
|
||||
#define RM_SIZE _RM_SIZE /* a constant private to the class RegMask */
|
||||
|
@ -65,6 +65,7 @@
|
||||
# include "classfile/vmSymbols.hpp"
|
||||
# include "code/codeBlob.hpp"
|
||||
# include "code/codeCache.hpp"
|
||||
# include "code/codeCacheExtensions.hpp"
|
||||
# include "code/compressedStream.hpp"
|
||||
# include "code/debugInfo.hpp"
|
||||
# include "code/debugInfoRec.hpp"
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
#include "classfile/stringTable.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/oopMapCache.hpp"
|
||||
@ -100,6 +101,7 @@ void MethodHandlesAdapterGenerator::generate() {
|
||||
StubCodeMark mark(this, "MethodHandle::interpreter_entry", vmIntrinsics::name_at(iid));
|
||||
address entry = MethodHandles::generate_method_handle_interpreter_entry(_masm, iid);
|
||||
if (entry != NULL) {
|
||||
CodeCacheExtensions::handle_generated_pc(entry, vmIntrinsics::name_at(iid));
|
||||
Interpreter::set_entry_for_kind(mk, entry);
|
||||
}
|
||||
// If the entry is not set, it will throw AbstractMethodError.
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "classfile/javaAssertions.hpp"
|
||||
#include "classfile/stringTable.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "compiler/compilerOracle.hpp"
|
||||
#include "gc/shared/cardTableRS.hpp"
|
||||
#include "gc/shared/genCollectedHeap.hpp"
|
||||
@ -1586,6 +1587,8 @@ void Arguments::set_ergonomics_flags() {
|
||||
|
||||
// Set up runtime image flags.
|
||||
set_runtime_image_flags();
|
||||
|
||||
CodeCacheExtensions::set_ergonomics_flags();
|
||||
}
|
||||
|
||||
void Arguments::set_parallel_gc_flags() {
|
||||
|
@ -224,6 +224,7 @@ class AgentLibraryList VALUE_OBJ_CLASS_SPEC {
|
||||
class Arguments : AllStatic {
|
||||
friend class VMStructs;
|
||||
friend class JvmtiExport;
|
||||
friend class CodeCacheExtensions;
|
||||
public:
|
||||
// Operation modi
|
||||
enum Mode {
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/stringTable.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "code/icBuffer.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
@ -101,15 +102,20 @@ jint init_globals() {
|
||||
classLoader_init();
|
||||
compilationPolicy_init();
|
||||
codeCache_init();
|
||||
CodeCacheExtensions::initialize();
|
||||
VM_Version_init();
|
||||
CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::VMVersion);
|
||||
os_init_globals();
|
||||
stubRoutines_init1();
|
||||
CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::StubRoutines1);
|
||||
jint status = universe_init(); // dependent on codeCache_init and
|
||||
// stubRoutines_init1 and metaspace_init.
|
||||
if (status != JNI_OK)
|
||||
return status;
|
||||
|
||||
CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::Universe);
|
||||
interpreter_init(); // before any methods loaded
|
||||
CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::Interpreter);
|
||||
invocationCounter_init(); // before any methods loaded
|
||||
marksweep_init();
|
||||
accessFlags_init();
|
||||
@ -137,6 +143,7 @@ jint init_globals() {
|
||||
}
|
||||
javaClasses_init(); // must happen after vtable initialization
|
||||
stubRoutines_init2(); // note: StubRoutines need 2-phase init
|
||||
CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::StubRoutines2);
|
||||
|
||||
#if INCLUDE_NMT
|
||||
// Solaris stack is walkable only after stubRoutines are set up.
|
||||
@ -150,6 +157,7 @@ jint init_globals() {
|
||||
CommandLineFlags::printFlags(tty, false, PrintFlagsRanges);
|
||||
}
|
||||
|
||||
CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::InitGlobals);
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/compiledIC.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "code/scopeDesc.hpp"
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "compiler/abstractCompiler.hpp"
|
||||
@ -2307,19 +2308,35 @@ BufferBlob* AdapterHandlerLibrary::buffer_blob() {
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
extern "C" void unexpected_adapter_call() {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
void AdapterHandlerLibrary::initialize() {
|
||||
if (_adapters != NULL) return;
|
||||
_adapters = new AdapterHandlerTable();
|
||||
|
||||
// Create a special handler for abstract methods. Abstract methods
|
||||
// are never compiled so an i2c entry is somewhat meaningless, but
|
||||
// throw AbstractMethodError just in case.
|
||||
// Pass wrong_method_abstract for the c2i transitions to return
|
||||
// AbstractMethodError for invalid invocations.
|
||||
address wrong_method_abstract = SharedRuntime::get_handle_wrong_method_abstract_stub();
|
||||
_abstract_method_handler = AdapterHandlerLibrary::new_entry(new AdapterFingerPrint(0, NULL),
|
||||
StubRoutines::throw_AbstractMethodError_entry(),
|
||||
wrong_method_abstract, wrong_method_abstract);
|
||||
if (!CodeCacheExtensions::skip_compiler_support()) {
|
||||
// Create a special handler for abstract methods. Abstract methods
|
||||
// are never compiled so an i2c entry is somewhat meaningless, but
|
||||
// throw AbstractMethodError just in case.
|
||||
// Pass wrong_method_abstract for the c2i transitions to return
|
||||
// AbstractMethodError for invalid invocations.
|
||||
address wrong_method_abstract = SharedRuntime::get_handle_wrong_method_abstract_stub();
|
||||
_abstract_method_handler = AdapterHandlerLibrary::new_entry(new AdapterFingerPrint(0, NULL),
|
||||
StubRoutines::throw_AbstractMethodError_entry(),
|
||||
wrong_method_abstract, wrong_method_abstract);
|
||||
} else {
|
||||
// Adapters are not supposed to be used.
|
||||
// Generate a special one to cause an error if used (and store this
|
||||
// singleton in place of the useless _abstract_method_error adapter).
|
||||
address entry = (address) &unexpected_adapter_call;
|
||||
_abstract_method_handler = AdapterHandlerLibrary::new_entry(new AdapterFingerPrint(0, NULL),
|
||||
entry,
|
||||
entry,
|
||||
entry);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint,
|
||||
@ -2346,6 +2363,15 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) {
|
||||
// make sure data structure is initialized
|
||||
initialize();
|
||||
|
||||
if (CodeCacheExtensions::skip_compiler_support()) {
|
||||
// adapters are useless and should not be used, including the
|
||||
// abstract_method_handler. However, some callers check that
|
||||
// an adapter was installed.
|
||||
// Return the singleton adapter, stored into _abstract_method_handler
|
||||
// and modified to cause an error if we ever call it.
|
||||
return _abstract_method_handler;
|
||||
}
|
||||
|
||||
if (method->is_abstract()) {
|
||||
return _abstract_method_handler;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -26,6 +26,7 @@
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/forte.hpp"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -67,14 +67,14 @@ class StubCodeDesc: public CHeapObj<mtCode> {
|
||||
static StubCodeDesc* desc_for_index(int); // returns the code descriptor for the index or NULL
|
||||
static const char* name_for(address pc); // returns the name of the code containing pc or NULL
|
||||
|
||||
StubCodeDesc(const char* group, const char* name, address begin) {
|
||||
StubCodeDesc(const char* group, const char* name, address begin, address end = NULL) {
|
||||
assert(name != NULL, "no name specified");
|
||||
_next = _list;
|
||||
_group = group;
|
||||
_name = name;
|
||||
_index = ++_count; // (never zero)
|
||||
_begin = begin;
|
||||
_end = NULL;
|
||||
_end = end;
|
||||
_list = this;
|
||||
};
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
@ -182,6 +183,12 @@ typedef void (*arraycopy_fn)(address src, address dst, int count);
|
||||
|
||||
// simple tests of generated arraycopy functions
|
||||
static void test_arraycopy_func(address func, int alignment) {
|
||||
if (CodeCacheExtensions::use_pregenerated_interpreter() || !CodeCacheExtensions::is_executable(func)) {
|
||||
// Exit safely if stubs were generated but cannot be used.
|
||||
// Also excluding pregenerated interpreter since the code may depend on
|
||||
// some registers being properly initialized (for instance Rthread)
|
||||
return;
|
||||
}
|
||||
int v = 0xcc;
|
||||
int v2 = 0x11;
|
||||
jlong lbuffer[8];
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "code/scopeDesc.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "gc/shared/gcLocker.inline.hpp"
|
||||
@ -3587,6 +3588,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
||||
}
|
||||
}
|
||||
|
||||
CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::CreateVM);
|
||||
|
||||
create_vm_timer.end();
|
||||
#ifdef ASSERT
|
||||
_vm_complete = true;
|
||||
|
@ -182,6 +182,8 @@
|
||||
#include "runtime/vmStructs_trace.hpp"
|
||||
#endif
|
||||
|
||||
#include "runtime/vmStructs_ext.hpp"
|
||||
|
||||
#ifdef COMPILER2
|
||||
#include "opto/addnode.hpp"
|
||||
#include "opto/block.hpp"
|
||||
@ -2961,6 +2963,9 @@ VMStructEntry VMStructs::localHotSpotVMStructs[] = {
|
||||
GENERATE_STATIC_VM_STRUCT_ENTRY)
|
||||
#endif
|
||||
|
||||
VM_STRUCTS_EXT(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
|
||||
GENERATE_STATIC_VM_STRUCT_ENTRY)
|
||||
|
||||
VM_STRUCTS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
|
||||
GENERATE_STATIC_VM_STRUCT_ENTRY,
|
||||
GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY,
|
||||
@ -3011,6 +3016,9 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = {
|
||||
GENERATE_TOPLEVEL_VM_TYPE_ENTRY)
|
||||
#endif
|
||||
|
||||
VM_TYPES_EXT(GENERATE_VM_TYPE_ENTRY,
|
||||
GENERATE_TOPLEVEL_VM_TYPE_ENTRY)
|
||||
|
||||
VM_TYPES_CPU(GENERATE_VM_TYPE_ENTRY,
|
||||
GENERATE_TOPLEVEL_VM_TYPE_ENTRY,
|
||||
GENERATE_OOP_VM_TYPE_ENTRY,
|
||||
@ -3120,6 +3128,9 @@ VMStructs::init() {
|
||||
CHECK_STATIC_VM_STRUCT_ENTRY);
|
||||
#endif
|
||||
|
||||
VM_STRUCTS_EXT(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
|
||||
CHECK_STATIC_VM_STRUCT_ENTRY);
|
||||
|
||||
VM_STRUCTS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
|
||||
CHECK_STATIC_VM_STRUCT_ENTRY,
|
||||
CHECK_NO_OP,
|
||||
@ -3166,6 +3177,9 @@ VMStructs::init() {
|
||||
CHECK_SINGLE_ARG_VM_TYPE_NO_OP);
|
||||
#endif
|
||||
|
||||
VM_TYPES_EXT(CHECK_VM_TYPE_ENTRY,
|
||||
CHECK_SINGLE_ARG_VM_TYPE_NO_OP);
|
||||
|
||||
VM_TYPES_CPU(CHECK_VM_TYPE_ENTRY,
|
||||
CHECK_SINGLE_ARG_VM_TYPE_NO_OP,
|
||||
CHECK_SINGLE_ARG_VM_TYPE_NO_OP,
|
||||
@ -3234,6 +3248,9 @@ VMStructs::init() {
|
||||
ENSURE_FIELD_TYPE_PRESENT));
|
||||
#endif
|
||||
|
||||
debug_only(VM_STRUCTS_EXT(ENSURE_FIELD_TYPE_PRESENT,
|
||||
ENSURE_FIELD_TYPE_PRESENT));
|
||||
|
||||
debug_only(VM_STRUCTS_CPU(ENSURE_FIELD_TYPE_PRESENT,
|
||||
ENSURE_FIELD_TYPE_PRESENT,
|
||||
CHECK_NO_OP,
|
||||
|
33
hotspot/src/share/vm/runtime/vmStructs_ext.hpp
Normal file
33
hotspot/src/share/vm/runtime/vmStructs_ext.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_RUNTIME_VMSTRUCTS_EXT_HPP
|
||||
#define SHARE_VM_RUNTIME_VMSTRUCTS_EXT_HPP
|
||||
|
||||
#define VM_STRUCTS_EXT(a, b)
|
||||
|
||||
#define VM_TYPES_EXT(a, b)
|
||||
|
||||
|
||||
#endif // SHARE_VM_RUNTIME_VMSTRUCTS_EXT_HPP
|
@ -26,6 +26,7 @@
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "compiler/compilerOracle.hpp"
|
||||
#include "gc/shared/isGCActiveMark.hpp"
|
||||
@ -369,6 +370,8 @@ volatile bool VM_Exit::_vm_exited = false;
|
||||
Thread * VM_Exit::_shutdown_thread = NULL;
|
||||
|
||||
int VM_Exit::set_vm_exited() {
|
||||
CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::LastStep);
|
||||
|
||||
Thread * thr_cur = ThreadLocalStorage::get_thread_slow();
|
||||
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint already");
|
||||
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
@ -155,6 +156,9 @@ const char* Abstract_VM_Version::vm_vendor() {
|
||||
|
||||
|
||||
const char* Abstract_VM_Version::vm_info_string() {
|
||||
if (CodeCacheExtensions::use_pregenerated_interpreter()) {
|
||||
return "interpreted mode, pregenerated";
|
||||
}
|
||||
switch (Arguments::mode()) {
|
||||
case Arguments::_int:
|
||||
return UseSharedSpaces ? "interpreted mode, sharing" : "interpreted mode";
|
||||
|
@ -1367,6 +1367,7 @@ template<class T> static void swap(T& a, T& b) {
|
||||
#define UINT32_FORMAT_W(width) "%" #width PRIu32
|
||||
|
||||
#define PTR32_FORMAT "0x%08" PRIx32
|
||||
#define PTR32_FORMAT_W(width) "0x%" #width PRIx32
|
||||
|
||||
// Format 64-bit quantities.
|
||||
#define INT64_FORMAT "%" PRId64
|
||||
|
Loading…
Reference in New Issue
Block a user