8151956: Support non-continuous CodeBlobs in HotSpot

Reviewed-by: iveresov, thartmann, simonis
This commit is contained in:
Rickard Bäckman 2016-04-26 10:28:51 +02:00
parent 67ff4391ec
commit b853eb7f5c
100 changed files with 2486 additions and 1868 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2016, 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.
*
@ -221,21 +221,19 @@ bool frame::safe_for_sender(JavaThread *thread) {
return jcw_safe;
}
if (sender_blob->is_nmethod()) {
nmethod* nm = sender_blob->as_nmethod_or_null();
if (nm != NULL) {
if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) ||
nm->method()->is_method_handle_intrinsic()) {
return false;
}
}
CompiledMethod* nm = sender_blob->as_compiled_method_or_null();
if (nm != NULL) {
if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) ||
nm->method()->is_method_handle_intrinsic()) {
return false;
}
}
// If the frame size is 0 something (or less) is bad because every nmethod has a non-zero frame size
// because the return address counts against the callee's frame.
if (sender_blob->frame_size() <= 0) {
assert(!sender_blob->is_nmethod(), "should count return address at least");
assert(!sender_blob->is_compiled(), "should count return address at least");
return false;
}
@ -244,7 +242,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
// should not be anything but the call stub (already covered), the interpreter (already covered)
// or an nmethod.
if (!sender_blob->is_nmethod()) {
if (!sender_blob->is_compiled()) {
return false;
}
@ -286,7 +284,7 @@ void frame::patch_pc(Thread* thread, address pc) {
assert(_pc == *pc_addr || pc == *pc_addr, "must be");
*pc_addr = pc;
_cb = CodeCache::find_blob(pc);
address original_pc = nmethod::get_deopt_original_pc(this);
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
assert(original_pc == _pc, "expected original PC to be stored before patching");
_deopt_state = is_deoptimized;
@ -371,7 +369,7 @@ frame frame::sender_for_entry_frame(RegisterMap* map) const {
// Verifies the calculated original PC of a deoptimization PC for the
// given unextended SP.
#ifdef ASSERT
void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) {
void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp) {
frame fr;
// This is ugly but it's better than to change {get,set}_original_pc
@ -391,12 +389,14 @@ void frame::adjust_unextended_sp() {
// as any other call site. Therefore, no special action is needed when we are
// returning to any of these call sites.
nmethod* sender_nm = (_cb == NULL) ? NULL : _cb->as_nmethod_or_null();
if (sender_nm != NULL) {
// If the sender PC is a deoptimization point, get the original PC.
if (sender_nm->is_deopt_entry(_pc) ||
sender_nm->is_deopt_mh_entry(_pc)) {
DEBUG_ONLY(verify_deopt_original_pc(sender_nm, _unextended_sp));
if (_cb != NULL) {
CompiledMethod* sender_cm = _cb->as_compiled_method_or_null();
if (sender_cm != NULL) {
// If the sender PC is a deoptimization point, get the original PC.
if (sender_cm->is_deopt_entry(_pc) ||
sender_cm->is_deopt_mh_entry(_pc)) {
DEBUG_ONLY(verify_deopt_original_pc(sender_cm, _unextended_sp));
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2016, 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.
*
@ -124,7 +124,7 @@
#ifdef ASSERT
// Used in frame::sender_for_{interpreter,compiled}_frame
static void verify_deopt_original_pc( nmethod* nm, intptr_t* unextended_sp);
static void verify_deopt_original_pc( CompiledMethod* nm, intptr_t* unextended_sp);
#endif
public:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2016, 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.
*
@ -55,7 +55,7 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
_cb = CodeCache::find_blob(pc);
adjust_unextended_sp();
address original_pc = nmethod::get_deopt_original_pc(this);
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
_deopt_state = is_deoptimized;
@ -79,10 +79,10 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
_cb = CodeCache::find_blob(pc);
adjust_unextended_sp();
address original_pc = nmethod::get_deopt_original_pc(this);
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
assert(((nmethod*)_cb)->insts_contains(_pc), "original PC must be in nmethod");
assert(((CompiledMethod*)_cb)->insts_contains(_pc), "original PC must be in CompiledMethod");
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;
@ -111,7 +111,7 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) {
_cb = CodeCache::find_blob(_pc);
adjust_unextended_sp();
address original_pc = nmethod::get_deopt_original_pc(this);
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
_deopt_state = is_deoptimized;

View File

@ -99,7 +99,7 @@ address NativeCall::get_trampoline() {
address bl_destination
= MacroAssembler::pd_call_destination(call_addr);
if (code->content_contains(bl_destination) &&
if (code->contains(bl_destination) &&
is_NativeCallTrampolineStub_at(bl_destination))
return bl_destination;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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.
*
@ -40,7 +40,7 @@ inline void frame::find_codeblob_and_set_pc_and_deopt_state(address pc) {
_fp = (intptr_t*)own_abi()->callers_sp;
address original_pc = nmethod::get_deopt_original_pc(this);
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
_deopt_state = is_deoptimized;

View File

@ -137,7 +137,7 @@ address NativeCall::get_trampoline() {
return NULL;
address bl_destination = Assembler::bxx_destination(call_addr);
if (code->content_contains(bl_destination) &&
if (code->contains(bl_destination) &&
is_NativeCallTrampolineStub_at(bl_destination))
return bl_destination;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -212,7 +212,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
// ok. adapter blobs never have a frame complete and are never ok.
if (!_cb->is_frame_complete_at(_pc)) {
if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
if (_cb->is_compiled() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
return false;
}
}
@ -304,7 +304,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
// because you must allocate window space
if (sender_blob->frame_size() <= 0) {
assert(!sender_blob->is_nmethod(), "should count return address at least");
assert(!sender_blob->is_compiled(), "should count return address at least");
return false;
}
@ -315,7 +315,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
// the stack unwalkable. pd_get_top_frame_for_signal_handler tries to recover from this by unwinding
// that initial frame and retrying.
if (!sender_blob->is_nmethod()) {
if (!sender_blob->is_compiled()) {
return false;
}
@ -358,9 +358,9 @@ void frame::init(intptr_t* sp, address pc, CodeBlob* cb) {
}
_deopt_state = unknown;
#ifdef ASSERT
if ( _cb != NULL && _cb->is_nmethod()) {
if ( _cb != NULL && _cb->is_compiled()) {
// Without a valid unextended_sp() we can't convert the pc to "original"
assert(!((nmethod*)_cb)->is_deopt_pc(_pc), "invariant broken");
assert(!((CompiledMethod*)_cb)->is_deopt_pc(_pc), "invariant broken");
}
#endif // ASSERT
}
@ -393,7 +393,7 @@ frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_is_interpret
// Check for MethodHandle call sites.
if (_cb != NULL) {
nmethod* nm = _cb->as_nmethod_or_null();
CompiledMethod* nm = _cb->as_compiled_method_or_null();
if (nm != NULL) {
if (nm->is_deopt_mh_entry(_pc) || nm->is_method_handle_return(_pc)) {
_sp_adjustment_by_callee = (intptr_t*) ((intptr_t) sp[L7_mh_SP_save->sp_offset_in_saved_window()] + STACK_BIAS) - sp;
@ -413,7 +413,7 @@ frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_is_interpret
// this lookup as get_deopt_original_pc() needs a correct value for
// unextended_sp() which uses _sp_adjustment_by_callee.
if (_pc != NULL) {
address original_pc = nmethod::get_deopt_original_pc(this);
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
_deopt_state = is_deoptimized;
@ -547,7 +547,7 @@ void frame::patch_pc(Thread* thread, address pc) {
_cb = CodeCache::find_blob(pc);
*O7_addr() = pc - pc_return_offset;
_cb = CodeCache::find_blob(_pc);
address original_pc = nmethod::get_deopt_original_pc(this);
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
assert(original_pc == _pc, "expected original to be stored before patching");
_deopt_state = is_deoptimized;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -95,7 +95,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
// ok. adapter blobs never have a frame complete and are never ok.
if (!_cb->is_frame_complete_at(_pc)) {
if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
if (_cb->is_compiled() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
return false;
}
}
@ -220,13 +220,11 @@ bool frame::safe_for_sender(JavaThread *thread) {
return jcw_safe;
}
if (sender_blob->is_nmethod()) {
nmethod* nm = sender_blob->as_nmethod_or_null();
if (nm != NULL) {
if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) ||
nm->method()->is_method_handle_intrinsic()) {
return false;
}
CompiledMethod* nm = sender_blob->as_compiled_method_or_null();
if (nm != NULL) {
if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) ||
nm->method()->is_method_handle_intrinsic()) {
return false;
}
}
@ -234,7 +232,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
// because the return address counts against the callee's frame.
if (sender_blob->frame_size() <= 0) {
assert(!sender_blob->is_nmethod(), "should count return address at least");
assert(!sender_blob->is_compiled(), "should count return address at least");
return false;
}
@ -243,7 +241,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
// should not be anything but the call stub (already covered), the interpreter (already covered)
// or an nmethod.
if (!sender_blob->is_nmethod()) {
if (!sender_blob->is_compiled()) {
return false;
}
@ -286,7 +284,7 @@ void frame::patch_pc(Thread* thread, address pc) {
assert(_pc == *pc_addr || pc == *pc_addr, "must be");
*pc_addr = pc;
_cb = CodeCache::find_blob(pc);
address original_pc = nmethod::get_deopt_original_pc(this);
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
assert(original_pc == _pc, "expected original PC to be stored before patching");
_deopt_state = is_deoptimized;
@ -372,7 +370,7 @@ frame frame::sender_for_entry_frame(RegisterMap* map) const {
// Verifies the calculated original PC of a deoptimization PC for the
// given unextended SP.
#ifdef ASSERT
void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) {
void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp) {
frame fr;
// This is ugly but it's better than to change {get,set}_original_pc
@ -381,7 +379,7 @@ void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) {
fr._unextended_sp = unextended_sp;
address original_pc = nm->get_original_pc(&fr);
assert(nm->insts_contains(original_pc), "original PC must be in nmethod");
assert(nm->insts_contains(original_pc), "original PC must be in CompiledMethod");
}
#endif
@ -392,12 +390,14 @@ void frame::adjust_unextended_sp() {
// as any other call site. Therefore, no special action is needed when we are
// returning to any of these call sites.
nmethod* sender_nm = (_cb == NULL) ? NULL : _cb->as_nmethod_or_null();
if (sender_nm != NULL) {
// If the sender PC is a deoptimization point, get the original PC.
if (sender_nm->is_deopt_entry(_pc) ||
sender_nm->is_deopt_mh_entry(_pc)) {
DEBUG_ONLY(verify_deopt_original_pc(sender_nm, _unextended_sp));
if (_cb != NULL) {
CompiledMethod* sender_cm = _cb->as_compiled_method_or_null();
if (sender_cm != NULL) {
// If the sender PC is a deoptimization point, get the original PC.
if (sender_cm->is_deopt_entry(_pc) ||
sender_cm->is_deopt_mh_entry(_pc)) {
DEBUG_ONLY(verify_deopt_original_pc(sender_cm, _unextended_sp));
}
}
}
}

View File

@ -124,7 +124,7 @@
#ifdef ASSERT
// Used in frame::sender_for_{interpreter,compiled}_frame
static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp);
static void verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp);
#endif
public:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -50,7 +50,7 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
_cb = CodeCache::find_blob(pc);
adjust_unextended_sp();
address original_pc = nmethod::get_deopt_original_pc(this);
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
_deopt_state = is_deoptimized;
@ -72,10 +72,10 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
_cb = CodeCache::find_blob(pc);
adjust_unextended_sp();
address original_pc = nmethod::get_deopt_original_pc(this);
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
assert(((nmethod*)_cb)->insts_contains(_pc), "original PC must be in nmethod");
assert(((CompiledMethod*)_cb)->insts_contains(_pc), "original PC must be in CompiledMethod");
_deopt_state = is_deoptimized;
} else {
if (_cb->is_deoptimization_stub()) {
@ -106,7 +106,7 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) {
_cb = CodeCache::find_blob(_pc);
adjust_unextended_sp();
address original_pc = nmethod::get_deopt_original_pc(this);
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
_deopt_state = is_deoptimized;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright 2007, 2008, 2009, 2010 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -59,7 +59,7 @@ inline frame::frame(ZeroFrame* zf, intptr_t* sp) {
case ZeroFrame::SHARK_FRAME: {
_pc = zero_sharkframe()->pc();
_cb = CodeCache::find_blob_unsafe(pc());
address original_pc = nmethod::get_deopt_original_pc(this);
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
_deopt_state = is_deoptimized;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
@ -29,7 +29,7 @@ import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
public class AdapterBlob extends CodeBlob {
public class AdapterBlob extends RuntimeBlob {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 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
@ -29,7 +29,7 @@ import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
public class BufferBlob extends CodeBlob {
public class BufferBlob extends RuntimeBlob {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -19,84 +19,142 @@
* 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 sun.jvm.hotspot.code;
import java.io.*;
import java.util.*;
import sun.jvm.hotspot.compiler.ImmutableOopMap;
import sun.jvm.hotspot.compiler.ImmutableOopMapSet;
import sun.jvm.hotspot.debugger.Address;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.runtime.VMObject;
import sun.jvm.hotspot.types.AddressField;
import sun.jvm.hotspot.types.CIntegerField;
import sun.jvm.hotspot.types.Type;
import sun.jvm.hotspot.types.TypeDataBase;
import sun.jvm.hotspot.utilities.Assert;
import sun.jvm.hotspot.compiler.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;
import java.io.PrintStream;
import java.util.Observable;
import java.util.Observer;
public class CodeBlob extends VMObject {
private static AddressField nameField;
private static AddressField nameField;
private static CIntegerField sizeField;
private static CIntegerField headerSizeField;
private static CIntegerField relocationSizeField;
private static CIntegerField contentOffsetField;
private static CIntegerField codeOffsetField;
private static AddressField contentBeginField;
private static AddressField codeBeginField;
private static AddressField codeEndField;
private static AddressField dataEndField;
private static CIntegerField frameCompleteOffsetField;
private static CIntegerField dataOffsetField;
private static CIntegerField frameSizeField;
private static AddressField oopMapsField;
// Only used by server compiler on x86; computed over in SA rather
// than relying on computation in target VM
private static final int NOT_YET_COMPUTED = -2;
private static final int UNDEFINED = -1;
private int linkOffset = NOT_YET_COMPUTED;
private static int matcherInterpreterFramePointerReg;
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
public CodeBlob(Address addr) {
super(addr);
}
protected static int matcherInterpreterFramePointerReg;
private static void initialize(TypeDataBase db) {
Type type = db.lookupType("CodeBlob");
nameField = type.getAddressField("_name");
sizeField = type.getCIntegerField("_size");
headerSizeField = type.getCIntegerField("_header_size");
relocationSizeField = type.getCIntegerField("_relocation_size");
frameCompleteOffsetField = type.getCIntegerField("_frame_complete_offset");
contentOffsetField = type.getCIntegerField("_content_offset");
codeOffsetField = type.getCIntegerField("_code_offset");
contentBeginField = type.getAddressField("_content_begin");
codeBeginField = type.getAddressField("_code_begin");
codeEndField = type.getAddressField("_code_end");
dataEndField = type.getAddressField("_data_end");
dataOffsetField = type.getCIntegerField("_data_offset");
frameSizeField = type.getCIntegerField("_frame_size");
oopMapsField = type.getAddressField("_oop_maps");
if (VM.getVM().isServerCompiler()) {
matcherInterpreterFramePointerReg =
db.lookupIntConstant("Matcher::interpreter_frame_pointer_reg").intValue();
db.lookupIntConstant("Matcher::interpreter_frame_pointer_reg").intValue();
}
}
public CodeBlob(Address addr) {
super(addr);
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
public Address headerBegin() { return getAddress(); }
public Address headerEnd() { return getAddress().addOffsetTo(getHeaderSize()); }
public Address contentBegin() { return contentBeginField.getValue(addr); }
public Address contentEnd() { return headerBegin().addOffsetTo(getDataOffset()); }
public Address codeBegin() { return codeBeginField.getValue(addr); }
public Address codeEnd() { return codeEndField.getValue(addr); }
public Address dataBegin() { return headerBegin().addOffsetTo(getDataOffset()); }
public Address dataEnd() { return dataEndField.getValue(addr); }
public long getFrameCompleteOffset() { return frameCompleteOffsetField.getValue(addr); }
public int getDataOffset() { return (int) dataOffsetField.getValue(addr); }
// Sizes
public int getSize() { return (int) sizeField.getValue(addr); }
public int getHeaderSize() { return (int) headerSizeField.getValue(addr); }
public long getFrameSizeWords() {
return (int) frameSizeField.getValue(addr);
}
public String getName() {
return getName();
}
/** OopMap for frame; can return null if none available */
public ImmutableOopMapSet getOopMaps() {
Address value = oopMapsField.getValue(addr);
if (value == null) {
return null;
}
return new ImmutableOopMapSet(value);
}
// Typing
public boolean isBufferBlob() { return false; }
public boolean isAOT() { return false; }
public boolean isCompiled() { return false; }
public boolean isNMethod() { return false; }
public boolean isRuntimeStub() { return false; }
public boolean isDeoptimizationStub() { return false; }
public boolean isUncommonTrapStub() { return false; }
public boolean isExceptionStub() { return false; }
public boolean isSafepointStub() { return false; }
public boolean isAdapterBlob() { return false; }
// Fine grain nmethod support: isNmethod() == isJavaMethod() || isNativeMethod() || isOSRMethod()
public boolean isJavaMethod() { return false; }
public boolean isNativeMethod() { return false; }
/** On-Stack Replacement method */
public boolean isOSRMethod() { return false; }
@ -105,81 +163,32 @@ public class CodeBlob extends VMObject {
return null;
}
// Boundaries
public Address headerBegin() {
return addr;
}
public Address headerEnd() {
return addr.addOffsetTo(headerSizeField.getValue(addr));
}
// FIXME: add RelocInfo
// public RelocInfo relocationBegin();
// public RelocInfo relocationEnd();
public Address contentBegin() {
return headerBegin().addOffsetTo(contentOffsetField.getValue(addr));
}
public Address contentEnd() {
return headerBegin().addOffsetTo(dataOffsetField.getValue(addr));
}
public Address codeBegin() {
return headerBegin().addOffsetTo(contentOffsetField.getValue(addr));
}
public Address codeEnd() {
return headerBegin().addOffsetTo(dataOffsetField.getValue(addr));
}
public Address dataBegin() {
return headerBegin().addOffsetTo(dataOffsetField.getValue(addr));
}
public Address dataEnd() {
return headerBegin().addOffsetTo(sizeField.getValue(addr));
}
// Offsets
public int getRelocationOffset() { return (int) headerSizeField .getValue(addr); }
public int getContentOffset() { return (int) contentOffsetField.getValue(addr); }
public int getCodeOffset() { return (int) codeOffsetField .getValue(addr); }
public int getDataOffset() { return (int) dataOffsetField .getValue(addr); }
// Sizes
public int getSize() { return (int) sizeField .getValue(addr); }
public int getHeaderSize() { return (int) headerSizeField.getValue(addr); }
// FIXME: add getRelocationSize()
public int getContentSize() { return (int) contentEnd().minus(contentBegin()); }
public int getCodeSize() { return (int) codeEnd() .minus(codeBegin()); }
public int getDataSize() { return (int) dataEnd() .minus(dataBegin()); }
// Containment
public boolean blobContains(Address addr) { return headerBegin() .lessThanOrEqual(addr) && dataEnd() .greaterThan(addr); }
// FIXME: add relocationContains
public boolean contentContains(Address addr) { return contentBegin().lessThanOrEqual(addr) && contentEnd().greaterThan(addr); }
public boolean codeContains(Address addr) { return codeBegin() .lessThanOrEqual(addr) && codeEnd() .greaterThan(addr); }
public boolean dataContains(Address addr) { return dataBegin() .lessThanOrEqual(addr) && dataEnd() .greaterThan(addr); }
public boolean contains(Address addr) { return contentContains(addr); }
public boolean isFrameCompleteAt(Address a) { return codeContains(a) && a.minus(codeBegin()) >= frameCompleteOffsetField.getValue(addr); }
public boolean isFrameCompleteAt(Address a) { return codeContains(a) && a.minus(codeBegin()) >= getFrameCompleteOffset(); }
// Reclamation support (really only used by the nmethods, but in order to get asserts to work
// in the CodeCache they are defined virtual here)
public boolean isZombie() { return false; }
public boolean isLockedByVM() { return false; }
/** OopMap for frame; can return null if none available */
public ImmutableOopMapSet getOopMaps() {
Address oopMapsAddr = oopMapsField.getValue(addr);
if (oopMapsAddr == null) {
return null;
}
return new ImmutableOopMapSet(oopMapsAddr);
}
// FIXME: not yet implementable
// void set_oop_maps(ImmutableOopMapSet* p);
public boolean isLockedByVM() { return false; }
public ImmutableOopMap getOopMapForReturnAddress(Address returnAddress, boolean debugging) {
Address pc = returnAddress;
@ -189,25 +198,14 @@ public class CodeBlob extends VMObject {
return getOopMaps().findMapAtOffset(pc.minus(codeBegin()), debugging);
}
// virtual void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, void f(oop*)) { ShouldNotReachHere(); }
// FIXME;
/** NOTE: this returns a size in BYTES in this system! */
public long getFrameSize() {
return VM.getVM().getAddressSize() * frameSizeField.getValue(addr);
return VM.getVM().getAddressSize() * getFrameSizeWords();
}
// Returns true, if the next frame is responsible for GC'ing oops passed as arguments
public boolean callerMustGCArguments() { return false; }
public String getName() {
return CStringUtilities.getString(nameField.getValue(addr));
}
// FIXME: NOT FINISHED
// FIXME: add more accessors
public void print() {
printOn(System.out);
}

View File

@ -0,0 +1,74 @@
/*
* 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.
*
* 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 sun.jvm.hotspot.code;
import java.util.*;
import sun.jvm.hotspot.debugger.Address;
import sun.jvm.hotspot.oops.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;
public abstract class CompiledMethod extends CodeBlob {
private static AddressField methodField;
private static AddressField deoptHandlerBeginField;
private static AddressField deoptMhHandlerBeginField;
private static AddressField scopesDataBeginField;
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
private static void initialize(TypeDataBase db) {
Type type = db.lookupType("CompiledMethod");
methodField = type.getAddressField("_method");
deoptHandlerBeginField = type.getAddressField("_deopt_handler_begin");
deoptMhHandlerBeginField = type.getAddressField("_deopt_mh_handler_begin");
scopesDataBeginField = type.getAddressField("_scopes_data_begin");
}
public CompiledMethod(Address addr) {
super(addr);
}
public Method getMethod() {
return (Method)Metadata.instantiateWrapperFor(methodField.getValue(addr));
}
public Address deoptHandlerBegin() { return deoptHandlerBeginField.getValue(addr); }
public Address deoptMhHandlerBegin() { return deoptMhHandlerBeginField.getValue(addr); }
public Address scopesDataBegin() { return scopesDataBeginField.getValue(addr); }
public static int getMethodOffset() { return (int) methodField.getOffset(); }
@Override
public boolean isCompiled() {
return true;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 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
@ -27,15 +27,13 @@ package sun.jvm.hotspot.code;
import java.io.*;
import java.util.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.memory.*;
import sun.jvm.hotspot.oops.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;
public class NMethod extends CodeBlob {
public class NMethod extends CompiledMethod {
private static long pcDescSize;
private static AddressField methodField;
/** != InvocationEntryBci if this nmethod is an on-stack replacement method */
private static CIntegerField entryBCIField;
/** To support simple linked-list chaining of nmethods */
@ -45,13 +43,10 @@ public class NMethod extends CodeBlob {
/** Offsets for different nmethod parts */
private static CIntegerField exceptionOffsetField;
private static CIntegerField deoptOffsetField;
private static CIntegerField deoptMhOffsetField;
private static CIntegerField origPCOffsetField;
private static CIntegerField stubOffsetField;
private static CIntegerField oopsOffsetField;
private static CIntegerField metadataOffsetField;
private static CIntegerField scopesDataOffsetField;
private static CIntegerField scopesPCsOffsetField;
private static CIntegerField dependenciesOffsetField;
private static CIntegerField handlerTableOffsetField;
@ -91,20 +86,16 @@ public class NMethod extends CodeBlob {
private static void initialize(TypeDataBase db) {
Type type = db.lookupType("nmethod");
methodField = type.getAddressField("_method");
entryBCIField = type.getCIntegerField("_entry_bci");
osrLinkField = type.getAddressField("_osr_link");
scavengeRootLinkField = type.getAddressField("_scavenge_root_link");
scavengeRootStateField = type.getJByteField("_scavenge_root_state");
exceptionOffsetField = type.getCIntegerField("_exception_offset");
deoptOffsetField = type.getCIntegerField("_deoptimize_offset");
deoptMhOffsetField = type.getCIntegerField("_deoptimize_mh_offset");
origPCOffsetField = type.getCIntegerField("_orig_pc_offset");
stubOffsetField = type.getCIntegerField("_stub_offset");
oopsOffsetField = type.getCIntegerField("_oops_offset");
metadataOffsetField = type.getCIntegerField("_metadata_offset");
scopesDataOffsetField = type.getCIntegerField("_scopes_data_offset");
scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset");
dependenciesOffsetField = type.getCIntegerField("_dependencies_offset");
handlerTableOffsetField = type.getCIntegerField("_handler_table_offset");
@ -123,16 +114,11 @@ public class NMethod extends CodeBlob {
super(addr);
}
// Accessors
public Address getAddress() {
return addr;
}
public Method getMethod() {
return (Method)Metadata.instantiateWrapperFor(methodField.getValue(addr));
}
// Type info
public boolean isNMethod() { return true; }
public boolean isJavaMethod() { return !getMethod().isNative(); }
@ -145,15 +131,12 @@ public class NMethod extends CodeBlob {
public Address instsBegin() { return codeBegin(); }
public Address instsEnd() { return headerBegin().addOffsetTo(getStubOffset()); }
public Address exceptionBegin() { return headerBegin().addOffsetTo(getExceptionOffset()); }
public Address deoptHandlerBegin() { return headerBegin().addOffsetTo(getDeoptOffset()); }
public Address deoptMhHandlerBegin() { return headerBegin().addOffsetTo(getDeoptMhOffset()); }
public Address stubBegin() { return headerBegin().addOffsetTo(getStubOffset()); }
public Address stubEnd() { return headerBegin().addOffsetTo(getOopsOffset()); }
public Address oopsBegin() { return headerBegin().addOffsetTo(getOopsOffset()); }
public Address oopsEnd() { return headerBegin().addOffsetTo(getMetadataOffset()); }
public Address metadataBegin() { return headerBegin().addOffsetTo(getMetadataOffset()); }
public Address metadataEnd() { return headerBegin().addOffsetTo(getScopesDataOffset()); }
public Address scopesDataBegin() { return headerBegin().addOffsetTo(getScopesDataOffset()); }
public Address metadataEnd() { return scopesDataBegin(); }
public Address scopesDataEnd() { return headerBegin().addOffsetTo(getScopesPCsOffset()); }
public Address scopesPCsBegin() { return headerBegin().addOffsetTo(getScopesPCsOffset()); }
public Address scopesPCsEnd() { return headerBegin().addOffsetTo(getDependenciesOffset()); }
@ -462,8 +445,6 @@ public class NMethod extends CodeBlob {
public static int getVerifiedEntryPointOffset() { return (int) verifiedEntryPointField.getOffset(); }
public static int getOSREntryPointOffset() { return (int) osrEntryPointField.getOffset(); }
public static int getEntryBCIOffset() { return (int) entryBCIField.getOffset(); }
/** NOTE: renamed from "method_offset_in_bytes" */
public static int getMethodOffset() { return (int) methodField.getOffset(); }
public void print() {
printOn(System.out);
@ -541,12 +522,9 @@ public class NMethod extends CodeBlob {
private int getEntryBCI() { return (int) entryBCIField .getValue(addr); }
private int getExceptionOffset() { return (int) exceptionOffsetField .getValue(addr); }
private int getDeoptOffset() { return (int) deoptOffsetField .getValue(addr); }
private int getDeoptMhOffset() { return (int) deoptMhOffsetField .getValue(addr); }
private int getStubOffset() { return (int) stubOffsetField .getValue(addr); }
private int getOopsOffset() { return (int) oopsOffsetField .getValue(addr); }
private int getMetadataOffset() { return (int) metadataOffsetField .getValue(addr); }
private int getScopesDataOffset() { return (int) scopesDataOffsetField .getValue(addr); }
private int getScopesPCsOffset() { return (int) scopesPCsOffsetField .getValue(addr); }
private int getDependenciesOffset() { return (int) dependenciesOffsetField.getValue(addr); }
private int getHandlerTableOffset() { return (int) handlerTableOffsetField.getValue(addr); }

View File

@ -0,0 +1,58 @@
/*
* 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.
*
* 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 sun.jvm.hotspot.code;
import java.util.*;
import sun.jvm.hotspot.compiler.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;
public class RuntimeBlob extends CodeBlob {
// Only used by server compiler on x86; computed over in SA rather
// than relying on computation in target VM
private static final int NOT_YET_COMPUTED = -2;
private static final int UNDEFINED = -1;
private int linkOffset = NOT_YET_COMPUTED;
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
private static void initialize(TypeDataBase db) {
Type type = db.lookupType("RuntimeBlob");
}
public RuntimeBlob(Address addr) {
super(addr);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 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
@ -29,7 +29,7 @@ import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
public class RuntimeStub extends CodeBlob {
public class RuntimeStub extends RuntimeBlob {
private static CIntegerField callerMustGCArgumentsField;
static {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 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
@ -29,7 +29,7 @@ import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
public class SingletonBlob extends CodeBlob {
public class SingletonBlob extends RuntimeBlob {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {

View File

@ -1230,7 +1230,7 @@ public class HotSpotVMConfig {
@HotSpotVMField(name = "Method::_method_counters", type = "MethodCounters*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCountersOffset;
@HotSpotVMField(name = "Method::_method_data", type = "MethodData*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOffset;
@HotSpotVMField(name = "Method::_from_compiled_entry", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCompiledEntryOffset;
@HotSpotVMField(name = "Method::_code", type = "nmethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCodeOffset;
@HotSpotVMField(name = "Method::_code", type = "CompiledMethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCodeOffset;
@HotSpotVMConstant(name = "Method::_jfr_towrite") @Stable public int methodFlagsJfrTowrite;
@HotSpotVMConstant(name = "Method::_caller_sensitive") @Stable public int methodFlagsCallerSensitive;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -256,8 +256,9 @@ int generateJvmOffsets(GEN_variant gen_variant) {
GEN_OFFS(CodeBlob, _name);
GEN_OFFS(CodeBlob, _header_size);
GEN_OFFS(CodeBlob, _content_offset);
GEN_OFFS(CodeBlob, _code_offset);
GEN_OFFS(CodeBlob, _content_begin);
GEN_OFFS(CodeBlob, _code_begin);
GEN_OFFS(CodeBlob, _code_end);
GEN_OFFS(CodeBlob, _data_offset);
GEN_OFFS(CodeBlob, _frame_size);
printf("\n");
@ -265,10 +266,10 @@ int generateJvmOffsets(GEN_variant gen_variant) {
GEN_OFFS(nmethod, _method);
GEN_OFFS(nmethod, _dependencies_offset);
GEN_OFFS(nmethod, _metadata_offset);
GEN_OFFS(nmethod, _scopes_data_offset);
GEN_OFFS(nmethod, _scopes_data_begin);
GEN_OFFS(nmethod, _scopes_pcs_offset);
GEN_OFFS(nmethod, _handler_table_offset);
GEN_OFFS(nmethod, _deoptimize_offset);
GEN_OFFS(nmethod, _deopt_handler_begin);
GEN_OFFS(nmethod, _orig_pc_offset);
GEN_OFFS(PcDesc, _pc_offset);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -124,10 +124,10 @@ typedef struct Nmethod_t {
uint64_t pc_desc;
int32_t orig_pc_offset; /* _orig_pc_offset */
int32_t instrs_beg; /* _code_offset */
int32_t instrs_end;
int32_t deopt_beg; /* _deoptimize_offset */
int32_t scopes_data_beg; /* _scopes_data_offset */
uint64_t instrs_beg; /* _code_offset */
uint64_t instrs_end;
uint64_t deopt_beg; /* _deoptimize_offset */
uint64_t scopes_data_beg; /* _scopes_data_offset */
int32_t scopes_data_end;
int32_t metadata_beg; /* _metadata_offset */
int32_t metadata_end;
@ -617,11 +617,12 @@ static int nmethod_info(Nmethod_t *N)
fprintf(stderr, "\t nmethod_info: BEGIN \n");
/* Instructions */
err = ps_pread(J->P, nm + OFFSET_CodeBlob_code_offset, &N->instrs_beg, SZ32);
err = read_pointer(J, base + OFFSET_VMStructEntryaddress, &vmp->address);
err = read_pointer(J, nm + OFFSET_CodeBlob_code_begin, &N->instrs_beg);
CHECK_FAIL(err);
err = ps_pread(J->P, nm + OFFSET_CodeBlob_data_offset, &N->instrs_end, SZ32);
err = read_pointer(J, nm + OFFSET_CodeBlob_code_end, &N->instrs_end);
CHECK_FAIL(err);
err = ps_pread(J->P, nm + OFFSET_nmethod_deoptimize_offset, &N->deopt_beg, SZ32);
err = read_pointer(J, nm + OFFSET_nmethod_deopt_handler_begin, &N->deopt_beg);
CHECK_FAIL(err);
err = ps_pread(J->P, nm + OFFSET_nmethod_orig_pc_offset, &N->orig_pc_offset, SZ32);
CHECK_FAIL(err);
@ -639,7 +640,7 @@ static int nmethod_info(Nmethod_t *N)
CHECK_FAIL(err);
/* scopes_data */
err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->scopes_data_beg, SZ32);
err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_begin, &N->scopes_data_beg, POINTER_SIZE);
CHECK_FAIL(err);
if (debug > 2 ) {
@ -868,7 +869,7 @@ get_real_pc(Nmethod_t *N, uint64_t pc_desc, uint64_t *real_pc)
err = ps_pread(N->J->P, pc_desc + OFFSET_PcDesc_pc_offset, &pc_offset, SZ32);
CHECK_FAIL(err);
*real_pc = N->nm + N->instrs_beg + pc_offset;
*real_pc = N->instrs_beg + pc_offset;
if (debug > 2) {
fprintf(stderr, "\t\t get_real_pc: pc_offset: %lx, real_pc: %llx\n",
pc_offset, *real_pc);
@ -942,7 +943,7 @@ scope_desc_at(Nmethod_t *N, int32_t decode_offset, Vframe_t *vf)
fprintf(stderr, "\t\t scope_desc_at: BEGIN \n");
}
buffer = N->nm + N->scopes_data_beg + decode_offset;
buffer = N->scopes_data_beg + decode_offset;
err = raw_read_int(N->J, &buffer, &vf->sender_decode_offset);
CHECK_FAIL(err);
@ -1052,11 +1053,11 @@ name_for_nmethod(jvm_agent_t* J,
CHECK_FAIL(err);
if (debug) {
fprintf(stderr, "name_for_nmethod: pc: %#llx, deopt_pc: %#llx\n",
pc, N->nm + N->deopt_beg);
pc, N->deopt_beg);
}
/* check for a deoptimized frame */
if ( pc == N->nm + N->deopt_beg) {
if ( pc == N->deopt_beg) {
uint64_t base;
if (debug) {
fprintf(stderr, "name_for_nmethod: found deoptimized frame\n");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -251,8 +251,9 @@ int generateJvmOffsets(GEN_variant gen_variant) {
GEN_OFFS(CodeBlob, _name);
GEN_OFFS(CodeBlob, _header_size);
GEN_OFFS(CodeBlob, _content_offset);
GEN_OFFS(CodeBlob, _code_offset);
GEN_OFFS(CodeBlob, _content_begin);
GEN_OFFS(CodeBlob, _code_begin);
GEN_OFFS(CodeBlob, _code_end);
GEN_OFFS(CodeBlob, _data_offset);
GEN_OFFS(CodeBlob, _frame_size);
printf("\n");
@ -260,10 +261,10 @@ int generateJvmOffsets(GEN_variant gen_variant) {
GEN_OFFS(nmethod, _method);
GEN_OFFS(nmethod, _dependencies_offset);
GEN_OFFS(nmethod, _metadata_offset);
GEN_OFFS(nmethod, _scopes_data_offset);
GEN_OFFS(nmethod, _scopes_data_begin);
GEN_OFFS(nmethod, _scopes_pcs_offset);
GEN_OFFS(nmethod, _handler_table_offset);
GEN_OFFS(nmethod, _deoptimize_offset);
GEN_OFFS(nmethod, _deopt_handler_begin);
GEN_OFFS(nmethod, _orig_pc_offset);
GEN_OFFS(PcDesc, _pc_offset);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -124,10 +124,10 @@ typedef struct Nmethod_t {
uint64_t pc_desc;
int32_t orig_pc_offset; /* _orig_pc_offset */
int32_t instrs_beg; /* _code_offset */
int32_t instrs_end;
int32_t deopt_beg; /* _deoptimize_offset */
int32_t scopes_data_beg; /* _scopes_data_offset */
uint64_t instrs_beg; /* _code_offset */
uint64_t instrs_end;
uint64_t deopt_beg; /* _deoptimize_offset */
uint64_t scopes_data_beg; /* _scopes_data_begin */
int32_t scopes_data_end;
int32_t metadata_beg; /* _metadata_offset */
int32_t metadata_end;
@ -617,11 +617,11 @@ static int nmethod_info(Nmethod_t *N)
fprintf(stderr, "\t nmethod_info: BEGIN \n");
/* Instructions */
err = ps_pread(J->P, nm + OFFSET_CodeBlob_code_offset, &N->instrs_beg, SZ32);
err = read_pointer(J, nm + OFFSET_CodeBlob_code_begin, &N->instrs_beg);
CHECK_FAIL(err);
err = ps_pread(J->P, nm + OFFSET_CodeBlob_data_offset, &N->instrs_end, SZ32);
err = read_pointer(J, nm + OFFSET_CodeBlob_code_end, &N->instrs_end);
CHECK_FAIL(err);
err = ps_pread(J->P, nm + OFFSET_nmethod_deoptimize_offset, &N->deopt_beg, SZ32);
err = read_pointer(J, nm + OFFSET_nmethod_deopt_handler_begin, &N->deopt_beg);
CHECK_FAIL(err);
err = ps_pread(J->P, nm + OFFSET_nmethod_orig_pc_offset, &N->orig_pc_offset, SZ32);
CHECK_FAIL(err);
@ -629,7 +629,7 @@ static int nmethod_info(Nmethod_t *N)
/* Metadata */
err = ps_pread(J->P, nm + OFFSET_nmethod_metadata_offset, &N->metadata_beg, SZ32);
CHECK_FAIL(err);
err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->metadata_end, SZ32);
err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_begin, &N->metadata_end, SZ32);
CHECK_FAIL(err);
/* scopes_pcs */
@ -639,7 +639,7 @@ static int nmethod_info(Nmethod_t *N)
CHECK_FAIL(err);
/* scopes_data */
err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->scopes_data_beg, SZ32);
err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_begin, &N->scopes_data_beg, POINTER_SIZE);
CHECK_FAIL(err);
if (debug > 2 ) {
@ -868,7 +868,7 @@ get_real_pc(Nmethod_t *N, uint64_t pc_desc, uint64_t *real_pc)
err = ps_pread(N->J->P, pc_desc + OFFSET_PcDesc_pc_offset, &pc_offset, SZ32);
CHECK_FAIL(err);
*real_pc = N->nm + N->instrs_beg + pc_offset;
*real_pc = N->instrs_beg + pc_offset;
if (debug > 2) {
fprintf(stderr, "\t\t get_real_pc: pc_offset: %lx, real_pc: %llx\n",
pc_offset, *real_pc);
@ -942,7 +942,7 @@ scope_desc_at(Nmethod_t *N, int32_t decode_offset, Vframe_t *vf)
fprintf(stderr, "\t\t scope_desc_at: BEGIN \n");
}
buffer = N->nm + N->scopes_data_beg + decode_offset;
buffer = N->scopes_data_beg + decode_offset;
err = raw_read_int(N->J, &buffer, &vf->sender_decode_offset);
CHECK_FAIL(err);
@ -1052,11 +1052,11 @@ name_for_nmethod(jvm_agent_t* J,
CHECK_FAIL(err);
if (debug) {
fprintf(stderr, "name_for_nmethod: pc: %#llx, deopt_pc: %#llx\n",
pc, N->nm + N->deopt_beg);
pc, N->deopt_beg);
}
/* check for a deoptimized frame */
if ( pc == N->nm + N->deopt_beg) {
if ( pc == N->deopt_beg) {
uint64_t base;
if (debug) {
fprintf(stderr, "name_for_nmethod: found deoptimized frame\n");

View File

@ -390,7 +390,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
// BugId 4454115: A read from a MappedByteBuffer can fault here if the
// underlying file has been truncated. Do not crash the VM in such a case.
CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
nmethod* nm = cb->is_nmethod() ? (nmethod*)cb : NULL;
CompiledMethod* nm = cb->as_compiled_method_or_null();
if (nm != NULL && nm->has_unsafe_access()) {
// We don't really need a stub here! Just set the pending exeption and
// continue at the next instruction after the faulting read. Returning

View File

@ -582,7 +582,7 @@ JVM_handle_bsd_signal(int sig,
// here if the underlying file has been truncated.
// Do not crash the VM in such a case.
CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
nmethod* nm = (cb != NULL && cb->is_nmethod()) ? (nmethod*)cb : NULL;
CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL;
if (nm != NULL && nm->has_unsafe_access()) {
stub = StubRoutines::handler_for_unsafe_access();
}

View File

@ -385,7 +385,7 @@ JVM_handle_linux_signal(int sig,
// here if the underlying file has been truncated.
// Do not crash the VM in such a case.
CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
nmethod* nm = (cb != NULL && cb->is_nmethod()) ? (nmethod*)cb : NULL;
CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL;
if (nm != NULL && nm->has_unsafe_access()) {
stub = handle_unsafe_access(thread, pc);
}

View File

@ -315,7 +315,7 @@ JVM_handle_linux_signal(int sig,
((NativeInstruction*)pc)->is_safepoint_poll() &&
CodeCache::contains((void*) pc) &&
((cb = CodeCache::find_blob(pc)) != NULL) &&
cb->is_nmethod()) {
cb->is_compiled()) {
if (TraceTraps) {
tty->print_cr("trap: safepoint_poll at " INTPTR_FORMAT " (SIGSEGV)", p2i(pc));
}
@ -364,7 +364,7 @@ JVM_handle_linux_signal(int sig,
// BugId 4454115: A read from a MappedByteBuffer can fault here if the
// underlying file has been truncated. Do not crash the VM in such a case.
CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
nmethod* nm = (cb != NULL && cb->is_nmethod()) ? (nmethod*)cb : NULL;
CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL;
if (nm != NULL && nm->has_unsafe_access()) {
// We don't really need a stub here! Just set the pending exeption and
// continue at the next instruction after the faulting read. Returning

View File

@ -438,7 +438,7 @@ inline static bool checkByteBuffer(address pc, address* stub) {
// here if the underlying file has been truncated.
// Do not crash the VM in such a case.
CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
nmethod* nm = cb->is_nmethod() ? (nmethod*)cb : NULL;
CompiledMethod* nm = cb->as_compiled_method_or_null();
if (nm != NULL && nm->has_unsafe_access()) {
*stub = StubRoutines::handler_for_unsafe_access();
return true;

View File

@ -418,7 +418,7 @@ JVM_handle_linux_signal(int sig,
// here if the underlying file has been truncated.
// Do not crash the VM in such a case.
CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
nmethod* nm = (cb != NULL && cb->is_nmethod()) ? (nmethod*)cb : NULL;
CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL;
if (nm != NULL && nm->has_unsafe_access()) {
stub = StubRoutines::handler_for_unsafe_access();
}

View File

@ -478,7 +478,7 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
// here if the underlying file has been truncated.
// Do not crash the VM in such a case.
CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
nmethod* nm = cb->is_nmethod() ? (nmethod*)cb : NULL;
CompiledMethod* nm = cb->as_compiled_method_or_null();
if (nm != NULL && nm->has_unsafe_access()) {
stub = StubRoutines::handler_for_unsafe_access();
}

View File

@ -518,7 +518,7 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
// Do not crash the VM in such a case.
CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
if (cb != NULL) {
nmethod* nm = cb->is_nmethod() ? (nmethod*)cb : NULL;
CompiledMethod* nm = cb->as_compiled_method_or_null();
if (nm != NULL && nm->has_unsafe_access()) {
stub = StubRoutines::handler_for_unsafe_access();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -604,7 +604,7 @@ void CodeBuffer::finalize_oop_references(const methodHandle& mh) {
csize_t CodeBuffer::total_offset_of(CodeSection* cs) const {
csize_t CodeBuffer::total_offset_of(const CodeSection* cs) const {
csize_t size_so_far = 0;
for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) {
const CodeSection* cur_cs = code_section(n);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -468,9 +468,11 @@ class CodeBuffer: public StackObj {
// construction.
void initialize(csize_t code_size, csize_t locs_size);
CodeSection* consts() { return &_consts; }
CodeSection* insts() { return &_insts; }
CodeSection* stubs() { return &_stubs; }
CodeSection* consts() { return &_consts; }
CodeSection* insts() { return &_insts; }
CodeSection* stubs() { return &_stubs; }
const CodeSection* insts() const { return &_insts; }
// present sections in order; return NULL at end; consts is #0, etc.
CodeSection* code_section(int n) {
@ -547,7 +549,7 @@ class CodeBuffer: public StackObj {
// Combined offset (relative to start of first section) of given
// section, as eventually found in the final CodeBlob.
csize_t total_offset_of(CodeSection* cs) const;
csize_t total_offset_of(const CodeSection* cs) const;
// allocated size of all relocation data, including index, rounded up
csize_t total_relocation_size() const;

View File

@ -1055,14 +1055,14 @@ void ciEnv::register_method(ciMethod* target,
if (entry_bci == InvocationEntryBci) {
if (TieredCompilation) {
// If there is an old version we're done with it
nmethod* old = method->code();
CompiledMethod* old = method->code();
if (TraceMethodReplacement && old != NULL) {
ResourceMark rm;
char *method_name = method->name_and_sig_as_C_string();
tty->print_cr("Replacing method %s", method_name);
}
if (old != NULL) {
old->make_not_entrant();
old->make_not_used();
}
}
if (TraceNMethodInstalls) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 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
@ -1115,7 +1115,7 @@ bool ciMethod::has_compiled_code() {
int ciMethod::comp_level() {
check_is_loaded();
VM_ENTRY_MARK;
nmethod* nm = get_Method()->code();
CompiledMethod* nm = get_Method()->code();
if (nm != NULL) return nm->comp_level();
return 0;
}
@ -1150,7 +1150,7 @@ int ciMethod::code_size_for_inlining() {
int ciMethod::instructions_size() {
if (_instructions_size == -1) {
GUARDED_VM_ENTRY(
nmethod* code = get_Method()->code();
CompiledMethod* code = get_Method()->code();
if (code != NULL && (code->comp_level() == CompLevel_full_optimization)) {
_instructions_size = code->insts_end() - code->verified_entry_point();
} else {
@ -1165,7 +1165,7 @@ int ciMethod::instructions_size() {
// ciMethod::log_nmethod_identity
void ciMethod::log_nmethod_identity(xmlStream* log) {
GUARDED_VM_ENTRY(
nmethod* code = get_Method()->code();
CompiledMethod* code = get_Method()->code();
if (code != NULL) {
code->log_identity(log);
}

View File

@ -546,7 +546,7 @@ class CompileReplay : public StackObj {
}
}
// Make sure the existence of a prior compile doesn't stop this one
nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code();
CompiledMethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code();
if (nm != NULL) {
nm->make_not_entrant();
}

View File

@ -1651,7 +1651,7 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
}
if (TieredCompilation && TieredStopAtLevel >= CompLevel_full_optimization) {
// Clobber the first compile and force second tier compilation
nmethod* nm = m->code();
CompiledMethod* nm = m->code();
if (nm != NULL && !m->is_method_handle_intrinsic()) {
// Throw out the code so that the code cache doesn't fill up
nm->make_not_entrant();
@ -1670,7 +1670,7 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
tty->print_cr("CompileTheWorld (%d) : Skipping method: %s", _compile_the_world_class_counter, m->name_and_sig_as_C_string());
}
nmethod* nm = m->code();
CompiledMethod* nm = m->code();
if (nm != NULL && !m->is_method_handle_intrinsic()) {
// Throw out the code so that the code cache doesn't fill up
nm->make_not_entrant();

View File

@ -1798,7 +1798,7 @@ static void print_stack_element_to_stream(outputStream* st, Handle mirror, int m
// Neither sourcename nor linenumber
sprintf(buf + (int)strlen(buf), "Unknown Source)");
}
nmethod* nm = method->code();
CompiledMethod* nm = method->code();
if (WizardMode && nm != NULL) {
sprintf(buf + (int)strlen(buf), "(nmethod " INTPTR_FORMAT ")", (intptr_t)nm);
}
@ -1920,7 +1920,7 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHand
int total_count = 0;
RegisterMap map(thread, false);
int decode_offset = 0;
nmethod* nm = NULL;
CompiledMethod* nm = NULL;
bool skip_fillInStackTrace_check = false;
bool skip_throwableInit_check = false;
bool skip_hidden = !ShowHiddenFrames;
@ -1948,10 +1948,10 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHand
// HMMM QQQ might be nice to have frame return nm as NULL if cb is non-NULL
// but non nmethod
fr = fr.sender(&map);
if (cb == NULL || !cb->is_nmethod()) {
if (cb == NULL || !cb->is_compiled()) {
continue;
}
nm = (nmethod*)cb;
nm = cb->as_compiled_method();
if (nm->method()->is_native()) {
method = nm->method();
bci = 0;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
@ -56,7 +56,7 @@ MetadataOnStackMark::MetadataOnStackMark(bool redefinition_walk) {
if (redefinition_walk) {
Threads::metadata_do(Metadata::mark_on_stack);
CodeCache::alive_nmethods_do(nmethod::mark_on_stack);
CodeCache::metadata_do(Metadata::mark_on_stack);
CompileBroker::mark_on_stack();
JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack);
ThreadService::metadata_do(Metadata::mark_on_stack);

View File

@ -65,12 +65,67 @@ unsigned int CodeBlob::allocation_size(CodeBuffer* cb, int header_size) {
return size;
}
CodeBlob::CodeBlob(const char* name, const CodeBlobLayout& layout, int frame_complete_offset, int frame_size, ImmutableOopMapSet* oop_maps, bool caller_must_gc_arguments) :
_name(name),
_size(layout.size()),
_header_size(layout.header_size()),
_frame_complete_offset(frame_complete_offset),
_data_offset(layout.data_offset()),
_frame_size(frame_size),
_strings(CodeStrings()),
_oop_maps(oop_maps),
_caller_must_gc_arguments(caller_must_gc_arguments),
_code_begin(layout.code_begin()),
_code_end(layout.code_end()),
_data_end(layout.data_end()),
_relocation_begin(layout.relocation_begin()),
_relocation_end(layout.relocation_end()),
_content_begin(layout.content_begin())
{
assert(layout.size() == round_to(layout.size(), oopSize), "unaligned size");
assert(layout.header_size() == round_to(layout.header_size(), oopSize), "unaligned size");
assert(layout.relocation_size() == round_to(layout.relocation_size(), oopSize), "unaligned size");
assert(layout.code_end() == layout.content_end(), "must be the same - see code_end()");
#ifdef COMPILER1
// probably wrong for tiered
assert(_frame_size >= -1, "must use frame size or -1 for runtime stubs");
#endif // COMPILER1
}
CodeBlob::CodeBlob(const char* name, const CodeBlobLayout& layout, CodeBuffer* cb, int frame_complete_offset, int frame_size, OopMapSet* oop_maps, bool caller_must_gc_arguments) :
_name(name),
_size(layout.size()),
_header_size(layout.header_size()),
_frame_complete_offset(frame_complete_offset),
_data_offset(layout.data_offset()),
_frame_size(frame_size),
_strings(CodeStrings()),
_caller_must_gc_arguments(caller_must_gc_arguments),
_code_begin(layout.code_begin()),
_code_end(layout.code_end()),
_data_end(layout.data_end()),
_relocation_begin(layout.relocation_begin()),
_relocation_end(layout.relocation_end()),
_content_begin(layout.content_begin())
{
assert(_size == round_to(_size, oopSize), "unaligned size");
assert(_header_size == round_to(_header_size, oopSize), "unaligned size");
assert(_data_offset <= _size, "codeBlob is too small");
assert(layout.code_end() == layout.content_end(), "must be the same - see code_end()");
set_oop_maps(oop_maps);
#ifdef COMPILER1
// probably wrong for tiered
assert(_frame_size >= -1, "must use frame size or -1 for runtime stubs");
#endif // COMPILER1
}
// Creates a simple CodeBlob. Sets up the size of the different regions.
CodeBlob::CodeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size) {
assert(size == round_to(size, oopSize), "unaligned size");
RuntimeBlob::RuntimeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size)
: CodeBlob(name, CodeBlobLayout((address) this, size, header_size, locs_size, size), frame_complete, 0, NULL, false /* caller_must_gc_arguments */)
{
assert(locs_size == round_to(locs_size, oopSize), "unaligned size");
assert(header_size == round_to(header_size, oopSize), "unaligned size");
assert(!UseRelocIndex, "no space allocated for reloc index yet");
// Note: If UseRelocIndex is enabled, there needs to be (at least) one
@ -79,55 +134,31 @@ CodeBlob::CodeBlob(const char* name, int header_size, int size, int frame_comple
// mentation is not easily understandable and thus it is not clear
// what exactly the format is supposed to be. For now, we just turn
// off the use of this table (gri 7/6/2000).
_name = name;
_size = size;
_frame_complete_offset = frame_complete;
_header_size = header_size;
_relocation_size = locs_size;
_content_offset = align_code_offset(header_size + _relocation_size);
_code_offset = _content_offset;
_data_offset = size;
_frame_size = 0;
set_oop_maps(NULL);
_strings = CodeStrings();
}
// Creates a CodeBlob from a CodeBuffer. Sets up the size of the different regions,
// Creates a RuntimeBlob from a CodeBuffer
// and copy code and relocation info.
CodeBlob::CodeBlob(
RuntimeBlob::RuntimeBlob(
const char* name,
CodeBuffer* cb,
int header_size,
int size,
int frame_complete,
int frame_size,
OopMapSet* oop_maps
) {
assert(size == round_to(size, oopSize), "unaligned size");
assert(header_size == round_to(header_size, oopSize), "unaligned size");
_name = name;
_size = size;
_frame_complete_offset = frame_complete;
_header_size = header_size;
_relocation_size = round_to(cb->total_relocation_size(), oopSize);
_content_offset = align_code_offset(header_size + _relocation_size);
_code_offset = _content_offset + cb->total_offset_of(cb->insts());
_data_offset = _content_offset + round_to(cb->total_content_size(), oopSize);
assert(_data_offset <= size, "codeBlob is too small");
_strings = CodeStrings();
OopMapSet* oop_maps,
bool caller_must_gc_arguments
) : CodeBlob(name, CodeBlobLayout((address) this, size, header_size, cb), cb, frame_complete, frame_size, oop_maps, caller_must_gc_arguments) {
cb->copy_code_and_locs_to(this);
set_oop_maps(oop_maps);
_frame_size = frame_size;
#ifdef COMPILER1
// probably wrong for tiered
assert(_frame_size >= -1, "must use frame size or -1 for runtime stubs");
#endif // COMPILER1
}
void CodeBlob::flush() {
if (_oop_maps) {
FREE_C_HEAP_ARRAY(unsigned char, _oop_maps);
_oop_maps = NULL;
}
_strings.free();
}
void CodeBlob::set_oop_maps(OopMapSet* p) {
// Danger Will Robinson! This method allocates a big
@ -140,7 +171,7 @@ void CodeBlob::set_oop_maps(OopMapSet* p) {
}
void CodeBlob::trace_new_stub(CodeBlob* stub, const char* name1, const char* name2) {
void RuntimeBlob::trace_new_stub(RuntimeBlob* stub, const char* name1, const char* name2) {
// Do not hold the CodeCache lock during name formatting.
assert(!CodeCache_lock->owned_by_self(), "release CodeCache before registering the stub");
@ -167,19 +198,9 @@ void CodeBlob::trace_new_stub(CodeBlob* stub, const char* name1, const char* nam
MemoryService::track_code_cache_memory_usage();
}
void CodeBlob::flush() {
if (_oop_maps) {
FREE_C_HEAP_ARRAY(unsigned char, _oop_maps);
_oop_maps = NULL;
}
_strings.free();
}
const ImmutableOopMap* CodeBlob::oop_map_for_return_address(address return_address) {
assert(oop_maps() != NULL, "nope");
return oop_maps()->find_map_at_offset((intptr_t) return_address - (intptr_t) code_begin());
assert(_oop_maps != NULL, "nope");
return _oop_maps->find_map_at_offset((intptr_t) return_address - (intptr_t) code_begin());
}
void CodeBlob::print_code() {
@ -193,7 +214,7 @@ void CodeBlob::print_code() {
BufferBlob::BufferBlob(const char* name, int size)
: CodeBlob(name, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, /*locs_size:*/ 0)
: RuntimeBlob(name, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, /*locs_size:*/ 0)
{}
BufferBlob* BufferBlob::create(const char* name, int buffer_size) {
@ -203,7 +224,7 @@ BufferBlob* BufferBlob::create(const char* name, int buffer_size) {
unsigned int size = sizeof(BufferBlob);
CodeCacheExtensions::size_blob(name, &buffer_size);
// align the size to CodeEntryAlignment
size = align_code_offset(size);
size = CodeBlob::align_code_offset(size);
size += round_to(buffer_size, oopSize);
assert(name != NULL, "must provide a name");
{
@ -218,14 +239,14 @@ BufferBlob* BufferBlob::create(const char* name, int buffer_size) {
BufferBlob::BufferBlob(const char* name, int size, CodeBuffer* cb)
: CodeBlob(name, cb, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, 0, NULL)
: RuntimeBlob(name, cb, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, 0, NULL)
{}
BufferBlob* BufferBlob::create(const char* name, CodeBuffer* cb) {
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
BufferBlob* blob = NULL;
unsigned int size = allocation_size(cb, sizeof(BufferBlob));
unsigned int size = CodeBlob::allocation_size(cb, sizeof(BufferBlob));
assert(name != NULL, "must provide a name");
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
@ -246,7 +267,7 @@ void BufferBlob::free(BufferBlob *blob) {
blob->flush();
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
CodeCache::free((CodeBlob*)blob);
CodeCache::free((RuntimeBlob*)blob);
}
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();
@ -265,7 +286,7 @@ AdapterBlob* AdapterBlob::create(CodeBuffer* cb) {
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
AdapterBlob* blob = NULL;
unsigned int size = allocation_size(cb, sizeof(AdapterBlob));
unsigned int size = CodeBlob::allocation_size(cb, sizeof(AdapterBlob));
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
blob = new (size) AdapterBlob(size, cb);
@ -287,7 +308,7 @@ MethodHandlesAdapterBlob* MethodHandlesAdapterBlob::create(int buffer_size) {
unsigned int size = sizeof(MethodHandlesAdapterBlob);
CodeCacheExtensions::size_blob("MethodHandles adapters", &buffer_size);
// align the size to CodeEntryAlignment
size = align_code_offset(size);
size = CodeBlob::align_code_offset(size);
size += round_to(buffer_size, oopSize);
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
@ -314,12 +335,10 @@ RuntimeStub::RuntimeStub(
OopMapSet* oop_maps,
bool caller_must_gc_arguments
)
: CodeBlob(name, cb, sizeof(RuntimeStub), size, frame_complete, frame_size, oop_maps)
: RuntimeBlob(name, cb, sizeof(RuntimeStub), size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments)
{
_caller_must_gc_arguments = caller_must_gc_arguments;
}
RuntimeStub* RuntimeStub::new_runtime_stub(const char* stub_name,
CodeBuffer* cb,
int frame_complete,
@ -332,7 +351,7 @@ RuntimeStub* RuntimeStub::new_runtime_stub(const char* stub_name,
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));
unsigned int size = CodeBlob::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);
@ -392,7 +411,7 @@ DeoptimizationBlob* DeoptimizationBlob::create(
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
unsigned int size = allocation_size(cb, sizeof(DeoptimizationBlob));
unsigned int size = CodeBlob::allocation_size(cb, sizeof(DeoptimizationBlob));
blob = new (size) DeoptimizationBlob(cb,
size,
oop_maps,
@ -431,7 +450,7 @@ UncommonTrapBlob* UncommonTrapBlob::create(
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
unsigned int size = allocation_size(cb, sizeof(UncommonTrapBlob));
unsigned int size = CodeBlob::allocation_size(cb, sizeof(UncommonTrapBlob));
blob = new (size) UncommonTrapBlob(cb, size, oop_maps, frame_size);
}
@ -467,7 +486,7 @@ ExceptionBlob* ExceptionBlob::create(
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
unsigned int size = allocation_size(cb, sizeof(ExceptionBlob));
unsigned int size = CodeBlob::allocation_size(cb, sizeof(ExceptionBlob));
blob = new (size) ExceptionBlob(cb, size, oop_maps, frame_size);
}
@ -502,7 +521,7 @@ SafepointBlob* SafepointBlob::create(
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
unsigned int size = allocation_size(cb, sizeof(SafepointBlob));
unsigned int size = CodeBlob::allocation_size(cb, sizeof(SafepointBlob));
blob = new (size) SafepointBlob(cb, size, oop_maps, frame_size);
}
@ -515,10 +534,6 @@ SafepointBlob* SafepointBlob::create(
//----------------------------------------------------------------------------------------------------
// Verification and printing
void CodeBlob::verify() {
ShouldNotReachHere();
}
void CodeBlob::print_on(outputStream* st) const {
st->print_cr("[CodeBlob (" INTPTR_FORMAT ")]", p2i(this));
st->print_cr("Framesize: %d", _frame_size);
@ -528,12 +543,16 @@ void CodeBlob::print_value_on(outputStream* st) const {
st->print_cr("[CodeBlob]");
}
void RuntimeBlob::verify() {
ShouldNotReachHere();
}
void BufferBlob::verify() {
// unimplemented
}
void BufferBlob::print_on(outputStream* st) const {
CodeBlob::print_on(st);
RuntimeBlob::print_on(st);
print_value_on(st);
}
@ -547,10 +566,10 @@ void RuntimeStub::verify() {
void RuntimeStub::print_on(outputStream* st) const {
ttyLocker ttyl;
CodeBlob::print_on(st);
RuntimeBlob::print_on(st);
st->print("Runtime Stub (" INTPTR_FORMAT "): ", p2i(this));
st->print_cr("%s", name());
Disassembler::decode((CodeBlob*)this, st);
Disassembler::decode((RuntimeBlob*)this, st);
}
void RuntimeStub::print_value_on(outputStream* st) const {
@ -563,9 +582,9 @@ void SingletonBlob::verify() {
void SingletonBlob::print_on(outputStream* st) const {
ttyLocker ttyl;
CodeBlob::print_on(st);
RuntimeBlob::print_on(st);
st->print_cr("%s", name());
Disassembler::decode((CodeBlob*)this, st);
Disassembler::decode((RuntimeBlob*)this, st);
}
void SingletonBlob::print_value_on(outputStream* st) const {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 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
@ -45,12 +45,14 @@ struct CodeBlobType {
// CodeBlob - superclass for all entries in the CodeCache.
//
// Suptypes are:
// nmethod : Compiled Java methods (include method that calls to native code)
// RuntimeStub : Call to VM runtime methods
// DeoptimizationBlob : Used for deoptimizatation
// ExceptionBlob : Used for stack unrolling
// SafepointBlob : Used to handle illegal instruction exceptions
// Subtypes are:
// CompiledMethod : Compiled Java methods (include method that calls to native code)
// nmethod : JIT Compiled Java methods
// RuntimeBlob : Non-compiled method code; generated glue code
// RuntimeStub : Call to VM runtime methods
// DeoptimizationBlob : Used for deoptimization
// ExceptionBlob : Used for stack unrolling
// SafepointBlob : Used to handle illegal instruction exceptions
//
//
// Layout:
@ -59,90 +61,79 @@ struct CodeBlobType {
// - content space
// - instruction space
// - data space
class DeoptimizationBlob;
class CodeBlobLayout;
class CodeBlob VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
friend class JVMCIVMStructs;
friend class CodeCacheDumper;
private:
protected:
const char* _name;
int _size; // total size of CodeBlob in bytes
int _header_size; // size of header (depends on subclass)
int _relocation_size; // size of relocation
int _content_offset; // offset to where content region begins (this includes consts, insts, stubs)
int _code_offset; // offset to where instructions region begins (this includes insts, stubs)
int _frame_complete_offset; // instruction offsets in [0.._frame_complete_offset) have
// not finished setting up their frame. Beware of pc's in
// that range. There is a similar range(s) on returns
// which we don't detect.
int _data_offset; // offset to where data region begins
int _frame_size; // size of stack frame
ImmutableOopMapSet* _oop_maps; // OopMap for this CodeBlob
CodeStrings _strings;
public:
address _code_begin;
address _code_end;
address _content_begin; // address to where content region begins (this includes consts, insts, stubs)
// address _content_end - not required, for all CodeBlobs _code_end == _content_end for now
address _data_end;
address _relocation_begin;
address _relocation_end;
ImmutableOopMapSet* _oop_maps; // OopMap for this CodeBlob
bool _caller_must_gc_arguments;
CodeStrings _strings;
CodeBlob(const char* name, const CodeBlobLayout& layout, int frame_complete_offset, int frame_size, ImmutableOopMapSet* oop_maps, bool caller_must_gc_arguments);
CodeBlob(const char* name, const CodeBlobLayout& layout, CodeBuffer* cb, int frame_complete_offset, int frame_size, OopMapSet* oop_maps, bool caller_must_gc_arguments);
public:
// Returns the space needed for CodeBlob
static unsigned int allocation_size(CodeBuffer* cb, int header_size);
static unsigned int align_code_offset(int offset);
// Creation
// a) simple CodeBlob
// frame_complete is the offset from the beginning of the instructions
// to where the frame setup (from stackwalk viewpoint) is complete.
CodeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size);
// b) full CodeBlob
CodeBlob(
const char* name,
CodeBuffer* cb,
int header_size,
int size,
int frame_complete,
int frame_size,
OopMapSet* oop_maps
);
// Deletion
void flush();
virtual void flush();
// Typing
virtual bool is_buffer_blob() const { return false; }
virtual bool is_nmethod() const { return false; }
virtual bool is_runtime_stub() const { return false; }
virtual bool is_deoptimization_stub() const { return false; }
virtual bool is_uncommon_trap_stub() const { return false; }
virtual bool is_exception_stub() const { return false; }
virtual bool is_buffer_blob() const { return false; }
virtual bool is_nmethod() const { return false; }
virtual bool is_runtime_stub() const { return false; }
virtual bool is_deoptimization_stub() const { return false; }
virtual bool is_uncommon_trap_stub() const { return false; }
virtual bool is_exception_stub() const { return false; }
virtual bool is_safepoint_stub() const { return false; }
virtual bool is_adapter_blob() const { return false; }
virtual bool is_method_handles_adapter_blob() const { return false; }
virtual bool is_compiled() const { return false; }
virtual bool is_compiled_by_c2() const { return false; }
virtual bool is_compiled_by_c1() const { return false; }
virtual bool is_compiled_by_jvmci() const { return false; }
// Casting
nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : NULL; }
nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : NULL; }
nmethod* as_nmethod() { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; }
CompiledMethod* as_compiled_method_or_null() { return is_compiled() ? (CompiledMethod*) this : NULL; }
CompiledMethod* as_compiled_method() { assert(is_compiled(), "must be compiled"); return (CompiledMethod*) this; }
// Boundaries
address header_begin() const { return (address) this; }
address header_end() const { return ((address) this) + _header_size; };
relocInfo* relocation_begin() const { return (relocInfo*) header_end(); };
relocInfo* relocation_end() const { return (relocInfo*)(header_end() + _relocation_size); }
address content_begin() const { return (address) header_begin() + _content_offset; }
address content_end() const { return (address) header_begin() + _data_offset; }
address code_begin() const { return (address) header_begin() + _code_offset; }
address code_end() const { return (address) header_begin() + _data_offset; }
address data_begin() const { return (address) header_begin() + _data_offset; }
address data_end() const { return (address) header_begin() + _size; }
// Offsets
int relocation_offset() const { return _header_size; }
int content_offset() const { return _content_offset; }
int code_offset() const { return _code_offset; }
int data_offset() const { return _data_offset; }
address header_begin() const { return (address) this; }
relocInfo* relocation_begin() const { return (relocInfo*) _relocation_begin; };
relocInfo* relocation_end() const { return (relocInfo*) _relocation_end; }
address content_begin() const { return _content_begin; }
address content_end() const { return _code_end; } // _code_end == _content_end is true for all types of blobs for now, it is also checked in the constructor
address code_begin() const { return _code_begin; }
address code_end() const { return _code_end; }
address data_end() const { return _data_end; }
// Sizes
int size() const { return _size; }
@ -150,17 +141,12 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
int relocation_size() const { return (address) relocation_end() - (address) relocation_begin(); }
int content_size() const { return content_end() - content_begin(); }
int code_size() const { return code_end() - code_begin(); }
int data_size() const { return data_end() - data_begin(); }
// Containment
bool blob_contains(address addr) const { return header_begin() <= addr && addr < data_end(); }
bool relocation_contains(relocInfo* addr) const{ return relocation_begin() <= addr && addr < relocation_end(); }
bool content_contains(address addr) const { return content_begin() <= addr && addr < content_end(); }
bool code_contains(address addr) const { return code_begin() <= addr && addr < code_end(); }
bool data_contains(address addr) const { return data_begin() <= addr && addr < data_end(); }
bool contains(address addr) const { return content_contains(addr); }
bool is_frame_complete_at(address addr) const { return code_contains(addr) &&
addr >= code_begin() + _frame_complete_offset; }
bool contains(address addr) const { return content_begin() <= addr && addr < content_end(); }
bool is_frame_complete_at(address addr) const { return code_contains(addr) && addr >= code_begin() + _frame_complete_offset; }
// CodeCache support: really only used by the nmethods, but in order to get
// asserts and certain bookkeeping to work in the CodeCache they are defined
@ -178,29 +164,26 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
ImmutableOopMapSet* oop_maps() const { return _oop_maps; }
void set_oop_maps(OopMapSet* p);
const ImmutableOopMap* oop_map_for_return_address(address return_address);
virtual void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { ShouldNotReachHere(); }
virtual void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) = 0;
// Frame support
int frame_size() const { return _frame_size; }
void set_frame_size(int size) { _frame_size = size; }
// Returns true, if the next frame is responsible for GC'ing oops passed as arguments
virtual bool caller_must_gc_arguments(JavaThread* thread) const { return false; }
bool caller_must_gc_arguments(JavaThread* thread) const { return _caller_must_gc_arguments; }
// Naming
const char* name() const { return _name; }
void set_name(const char* name) { _name = name; }
// Debugging
virtual void verify();
void print() const { print_on(tty); }
virtual void verify() = 0;
virtual void print() const { print_on(tty); };
virtual void print_on(outputStream* st) const;
virtual void print_value_on(outputStream* st) const;
void print_code();
// Deal with Disassembler, VTune, Forte, JvmtiExport, MemoryService.
static void trace_new_stub(CodeBlob* blob, const char* name1, const char* name2 = "");
// Print the comment associated with offset on stream, if there is one
virtual void print_block_comment(outputStream* stream, address block_begin) const {
intptr_t offset = (intptr_t)(block_begin - code_begin());
@ -221,11 +204,142 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
}
};
class CodeBlobLayout : public StackObj {
private:
int _size;
int _header_size;
int _relocation_size;
int _content_offset;
int _code_offset;
int _data_offset;
address _code_begin;
address _code_end;
address _content_begin;
address _content_end;
address _data_end;
address _relocation_begin;
address _relocation_end;
public:
CodeBlobLayout(address code_begin, address code_end, address content_begin, address content_end, address data_end, address relocation_begin, address relocation_end) :
_size(0),
_header_size(0),
_relocation_size(0),
_content_offset(0),
_code_offset(0),
_data_offset(0),
_content_begin(content_begin),
_content_end(content_end),
_code_begin(code_begin),
_code_end(code_end),
_data_end(data_end),
_relocation_begin(relocation_begin),
_relocation_end(relocation_end)
{
}
CodeBlobLayout(const address start, int size, int header_size, int relocation_size, int data_offset) :
_size(size),
_header_size(header_size),
_relocation_size(relocation_size),
_content_offset(CodeBlob::align_code_offset(_header_size + _relocation_size)),
_code_offset(_content_offset),
_data_offset(data_offset)
{
assert(_relocation_size == round_to(_relocation_size, oopSize), "unaligned size");
_code_begin = (address) start + _code_offset;
_code_end = (address) start + _data_offset;
_content_begin = (address) start + _content_offset;
_content_end = (address) start + _data_offset;
_data_end = (address) start + _size;
_relocation_begin = (address) start + _header_size;
_relocation_end = _relocation_begin + _relocation_size;
}
CodeBlobLayout(const address start, int size, int header_size, const CodeBuffer* cb) :
_size(size),
_header_size(header_size),
_relocation_size(round_to(cb->total_relocation_size(), oopSize)),
_content_offset(CodeBlob::align_code_offset(_header_size + _relocation_size)),
_code_offset(_content_offset + cb->total_offset_of(cb->insts())),
_data_offset(_content_offset + round_to(cb->total_content_size(), oopSize))
{
assert(_relocation_size == round_to(_relocation_size, oopSize), "unaligned size");
_code_begin = (address) start + _code_offset;
_code_end = (address) start + _data_offset;
_content_begin = (address) start + _content_offset;
_content_end = (address) start + _data_offset;
_data_end = (address) start + _size;
_relocation_begin = (address) start + _header_size;
_relocation_end = _relocation_begin + _relocation_size;
}
int size() const { return _size; }
int header_size() const { return _header_size; }
int relocation_size() const { return _relocation_size; }
int content_offset() const { return _content_offset; }
int code_offset() const { return _code_offset; }
int data_offset() const { return _data_offset; }
address code_begin() const { return _code_begin; }
address code_end() const { return _code_end; }
address data_end() const { return _data_end; }
address relocation_begin() const { return _relocation_begin; }
address relocation_end() const { return _relocation_end; }
address content_begin() const { return _content_begin; }
address content_end() const { return _content_end; }
};
class RuntimeBlob : public CodeBlob {
friend class VMStructs;
public:
// Creation
// a) simple CodeBlob
// frame_complete is the offset from the beginning of the instructions
// to where the frame setup (from stackwalk viewpoint) is complete.
RuntimeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size);
// b) full CodeBlob
RuntimeBlob(
const char* name,
CodeBuffer* cb,
int header_size,
int size,
int frame_complete,
int frame_size,
OopMapSet* oop_maps,
bool caller_must_gc_arguments = false
);
// GC support
virtual bool is_alive() const = 0;
void verify();
// OopMap for frame
virtual void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { ShouldNotReachHere(); }
// Debugging
void print() const { print_on(tty); }
virtual void print_on(outputStream* st) const { CodeBlob::print_on(st); }
virtual void print_value_on(outputStream* st) const { CodeBlob::print_value_on(st); }
// Deal with Disassembler, VTune, Forte, JvmtiExport, MemoryService.
static void trace_new_stub(RuntimeBlob* blob, const char* name1, const char* name2 = "");
};
class WhiteBox;
//----------------------------------------------------------------------------------------------------
// BufferBlob: used to hold non-relocatable machine code such as the interpreter, stubroutines, etc.
class BufferBlob: public CodeBlob {
class BufferBlob: public RuntimeBlob {
friend class VMStructs;
friend class AdapterBlob;
friend class MethodHandlesAdapterBlob;
@ -293,11 +407,9 @@ public:
//----------------------------------------------------------------------------------------------------
// RuntimeStub: describes stubs used by compiled code to call a (static) C++ runtime routine
class RuntimeStub: public CodeBlob {
class RuntimeStub: public RuntimeBlob {
friend class VMStructs;
private:
bool _caller_must_gc_arguments;
// Creation support
RuntimeStub(
const char* name,
@ -325,10 +437,7 @@ class RuntimeStub: public CodeBlob {
// Typing
bool is_runtime_stub() const { return true; }
// GC support
bool caller_must_gc_arguments(JavaThread* thread) const { return _caller_must_gc_arguments; }
address entry_point() { return code_begin(); }
address entry_point() const { return code_begin(); }
// GC/Verification support
void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* nothing to do */ }
@ -343,7 +452,7 @@ class RuntimeStub: public CodeBlob {
//----------------------------------------------------------------------------------------------------
// Super-class for all blobs that exist in only one instance. Implements default behaviour.
class SingletonBlob: public CodeBlob {
class SingletonBlob: public RuntimeBlob {
friend class VMStructs;
protected:
@ -358,13 +467,15 @@ class SingletonBlob: public CodeBlob {
int frame_size,
OopMapSet* oop_maps
)
: CodeBlob(name, cb, header_size, size, CodeOffsets::frame_never_safe, frame_size, oop_maps)
: RuntimeBlob(name, cb, header_size, size, CodeOffsets::frame_never_safe, frame_size, oop_maps)
{};
address entry_point() { return code_begin(); }
bool is_alive() const { return true; }
// GC/Verification support
void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* nothing to do */ }
void verify(); // does nothing
void print_on(outputStream* st) const;
void print_value_on(outputStream* st) const;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -561,12 +561,12 @@ CodeBlob* CodeCache::find_blob(void* start) {
// what you are doing)
CodeBlob* CodeCache::find_blob_unsafe(void* start) {
// NMT can walk the stack before code cache is created
if (_heaps == NULL || _heaps->is_empty()) return NULL;
FOR_ALL_HEAPS(heap) {
CodeBlob* result = (CodeBlob*) (*heap)->find_start(start);
if (result != NULL && result->blob_contains((address)start)) {
return result;
if (_heaps != NULL && !_heaps->is_empty()) {
FOR_ALL_HEAPS(heap) {
CodeBlob* result = (CodeBlob*) (*heap)->find_start(start);
if (result != NULL && result->blob_contains((address)start)) {
return result;
}
}
}
return NULL;
@ -595,11 +595,11 @@ void CodeCache::nmethods_do(void f(nmethod* nm)) {
}
}
void CodeCache::alive_nmethods_do(void f(nmethod* nm)) {
void CodeCache::metadata_do(void f(Metadata* m)) {
assert_locked_or_safepoint(CodeCache_lock);
NMethodIterator iter;
while(iter.next_alive()) {
f(iter.method());
iter.method()->metadata_do(f);
}
}
@ -614,7 +614,7 @@ int CodeCache::alignment_offset() {
// Mark nmethods for unloading if they contain otherwise unreachable oops.
void CodeCache::do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred) {
assert_locked_or_safepoint(CodeCache_lock);
NMethodIterator iter;
CompiledMethodIterator iter;
while(iter.next_alive()) {
iter.method()->do_unloading(is_alive, unloading_occurred);
}
@ -841,17 +841,18 @@ void CodeCache::gc_prologue() {
void CodeCache::gc_epilogue() {
assert_locked_or_safepoint(CodeCache_lock);
NOT_DEBUG(if (needs_cache_clean())) {
NMethodIterator iter;
CompiledMethodIterator iter;
while(iter.next_alive()) {
nmethod* nm = iter.method();
assert(!nm->is_unloaded(), "Tautology");
CompiledMethod* cm = iter.method();
assert(!cm->is_unloaded(), "Tautology");
DEBUG_ONLY(if (needs_cache_clean())) {
nm->cleanup_inline_caches();
cm->cleanup_inline_caches();
}
DEBUG_ONLY(nm->verify());
DEBUG_ONLY(nm->verify_oop_relocations());
DEBUG_ONLY(cm->verify());
DEBUG_ONLY(cm->verify_oop_relocations());
}
}
set_needs_cache_clean(false);
prune_scavenge_root_nmethods();
@ -1036,7 +1037,7 @@ int CodeCache::number_of_nmethods_with_dependencies() {
void CodeCache::clear_inline_caches() {
assert_locked_or_safepoint(CodeCache_lock);
NMethodIterator iter;
CompiledMethodIterator iter;
while(iter.next_alive()) {
iter.method()->clear_inline_caches();
}
@ -1083,6 +1084,11 @@ int CodeCache::mark_for_deoptimization(KlassDepChange& changes) {
return number_of_marked_CodeBlobs;
}
CompiledMethod* CodeCache::find_compiled(void* start) {
CodeBlob *cb = find_blob(start);
assert(cb == NULL || cb->is_compiled(), "did not find an compiled_method");
return (CompiledMethod*)cb;
}
#ifdef HOTSWAP
int CodeCache::mark_for_evol_deoptimization(instanceKlassHandle dependee) {
@ -1094,16 +1100,16 @@ int CodeCache::mark_for_evol_deoptimization(instanceKlassHandle dependee) {
for (int i = 0; i < old_methods->length(); i++) {
ResourceMark rm;
Method* old_method = old_methods->at(i);
nmethod *nm = old_method->code();
CompiledMethod* nm = old_method->code();
if (nm != NULL) {
nm->mark_for_deoptimization();
number_of_marked_CodeBlobs++;
}
}
NMethodIterator iter;
CompiledMethodIterator iter;
while(iter.next_alive()) {
nmethod* nm = iter.method();
CompiledMethod* nm = iter.method();
if (nm->is_marked_for_deoptimization()) {
// ...Already marked in the previous pass; don't count it again.
} else if (nm->is_evol_dependent_on(dependee())) {
@ -1124,9 +1130,9 @@ int CodeCache::mark_for_evol_deoptimization(instanceKlassHandle dependee) {
// Deoptimize all methods
void CodeCache::mark_all_nmethods_for_deoptimization() {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
NMethodIterator iter;
CompiledMethodIterator iter;
while(iter.next_alive()) {
nmethod* nm = iter.method();
CompiledMethod* nm = iter.method();
if (!nm->method()->is_method_handle_intrinsic()) {
nm->mark_for_deoptimization();
}
@ -1137,9 +1143,9 @@ int CodeCache::mark_for_deoptimization(Method* dependee) {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
int number_of_marked_CodeBlobs = 0;
NMethodIterator iter;
CompiledMethodIterator iter;
while(iter.next_alive()) {
nmethod* nm = iter.method();
CompiledMethod* nm = iter.method();
if (nm->is_dependent_on_method(dependee)) {
ResourceMark rm;
nm->mark_for_deoptimization();
@ -1152,9 +1158,9 @@ int CodeCache::mark_for_deoptimization(Method* dependee) {
void CodeCache::make_marked_nmethods_not_entrant() {
assert_locked_or_safepoint(CodeCache_lock);
NMethodIterator iter;
CompiledMethodIterator iter;
while(iter.next_alive()) {
nmethod* nm = iter.method();
CompiledMethod* nm = iter.method();
if (nm->is_marked_for_deoptimization()) {
nm->make_not_entrant();
}
@ -1549,3 +1555,36 @@ void CodeCache::log_state(outputStream* st) {
blob_count(), nmethod_count(), adapter_count(),
unallocated_capacity());
}
// Initialize iterator to given compiled method
void CompiledMethodIterator::initialize(CompiledMethod* cm) {
_code_blob = (CodeBlob*)cm;
if (!SegmentedCodeCache) {
// Iterate over all CodeBlobs
_code_blob_type = CodeBlobType::All;
} else if (cm != NULL) {
_code_blob_type = CodeCache::get_code_blob_type(cm);
} else {
// Only iterate over method code heaps, starting with non-profiled
_code_blob_type = CodeBlobType::MethodNonProfiled;
}
}
// Advance iterator to the next compiled method in the current code heap
bool CompiledMethodIterator::next_compiled_method() {
// Get first method CodeBlob
if (_code_blob == NULL) {
_code_blob = CodeCache::first_blob(_code_blob_type);
if (_code_blob == NULL) {
return false;
} else if (_code_blob->is_nmethod()) {
return true;
}
}
// Search for next method CodeBlob
_code_blob = CodeCache::next_blob(_code_blob);
while (_code_blob != NULL && !_code_blob->is_compiled()) {
_code_blob = CodeCache::next_blob(_code_blob);
}
return _code_blob != NULL;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -78,6 +78,7 @@ class CodeCache : AllStatic {
friend class VMStructs;
friend class JVMCIVMStructs;
friend class NMethodIterator;
friend class CompiledMethodIterator;
friend class WhiteBox;
friend class CodeCacheLoader;
private:
@ -134,12 +135,13 @@ class CodeCache : AllStatic {
static void blobs_do(void f(CodeBlob* cb)); // iterates over all CodeBlobs
static void blobs_do(CodeBlobClosure* f); // iterates over all CodeBlobs
static void nmethods_do(void f(nmethod* nm)); // iterates over all nmethods
static void alive_nmethods_do(void f(nmethod* nm)); // iterates over all alive nmethods
static void metadata_do(void f(Metadata* m)); // iterates over metadata in alive nmethods
// Lookup
static CodeBlob* find_blob(void* start); // Returns the CodeBlob containing the given address
static CodeBlob* find_blob_unsafe(void* start); // Same as find_blob but does not fail if looking up a zombie method
static nmethod* find_nmethod(void* start); // Returns the nmethod containing the given address
static CompiledMethod* find_compiled(void* start);
static int blob_count(); // Returns the total number of CodeBlobs in the cache
static int blob_count(int code_blob_type);
@ -207,8 +209,8 @@ class CodeCache : AllStatic {
static bool heap_available(int code_blob_type);
// Returns the CodeBlobType for the given nmethod
static int get_code_blob_type(nmethod* nm) {
return get_code_heap(nm)->code_blob_type();
static int get_code_blob_type(CompiledMethod* cm) {
return get_code_heap(cm)->code_blob_type();
}
// Returns the CodeBlobType for the given compilation level
@ -337,4 +339,53 @@ private:
}
};
// Iterator to iterate over compiled methods in the CodeCache.
class CompiledMethodIterator : public StackObj {
private:
CodeBlob* _code_blob; // Current CodeBlob
int _code_blob_type; // Refers to current CodeHeap
public:
CompiledMethodIterator() {
initialize(NULL); // Set to NULL, initialized by first call to next()
}
CompiledMethodIterator(CompiledMethod* cm) {
initialize(cm);
}
// Advance iterator to next compiled method
bool next() {
assert_locked_or_safepoint(CodeCache_lock);
assert(_code_blob_type < CodeBlobType::NumTypes, "end reached");
bool result = next_compiled_method();
while (!result && (_code_blob_type < CodeBlobType::MethodProfiled)) {
// Advance to next code heap if segmented code cache
_code_blob_type++;
result = next_compiled_method();
}
return result;
}
// Advance iterator to next alive compiled method
bool next_alive() {
bool result = next();
while(result && !_code_blob->is_alive()) {
result = next();
}
return result;
}
bool end() const { return _code_blob == NULL; }
CompiledMethod* method() const { return (_code_blob != NULL) ? _code_blob->as_compiled_method() : NULL; }
private:
// Initialize iterator to given compiled method
void initialize(CompiledMethod* cm);
// Advance iterator to the next compiled method in the current code heap
bool next_compiled_method();
};
#endif // SHARE_VM_CODE_CODECACHE_HPP

View File

@ -103,7 +103,7 @@ void CompiledIC::internal_set_ic_destination(address entry_point, bool is_icstub
MutexLockerEx pl(SafepointSynchronize::is_at_safepoint() ? NULL : Patching_lock, Mutex::_no_safepoint_check_flag);
#ifdef ASSERT
CodeBlob* cb = CodeCache::find_blob_unsafe(_ic_call);
assert(cb != NULL && cb->is_nmethod(), "must be nmethod");
assert(cb != NULL && cb->is_compiled(), "must be compiled");
#endif
_ic_call->set_destination_mt_safe(entry_point);
}
@ -182,17 +182,17 @@ void CompiledIC::initialize_from_iter(RelocIterator* iter) {
}
}
CompiledIC::CompiledIC(nmethod* nm, NativeCall* call)
CompiledIC::CompiledIC(CompiledMethod* cm, NativeCall* call)
: _ic_call(call)
{
address ic_call = _ic_call->instruction_address();
assert(ic_call != NULL, "ic_call address must be set");
assert(nm != NULL, "must pass nmethod");
assert(nm->contains(ic_call), "must be in nmethod");
assert(cm != NULL, "must pass compiled method");
assert(cm->contains(ic_call), "must be in compiled method");
// Search for the ic_call at the given address.
RelocIterator iter(nm, ic_call, ic_call+1);
RelocIterator iter(cm, ic_call, ic_call+1);
bool ret = iter.next();
assert(ret == true, "relocInfo must exist at this address");
assert(iter.addr() == ic_call, "must find ic_call");
@ -205,10 +205,10 @@ CompiledIC::CompiledIC(RelocIterator* iter)
{
address ic_call = _ic_call->instruction_address();
nmethod* nm = iter->code();
CompiledMethod* nm = iter->code();
assert(ic_call != NULL, "ic_call address must be set");
assert(nm != NULL, "must pass nmethod");
assert(nm->contains(ic_call), "must be in nmethod");
assert(nm != NULL, "must pass compiled method");
assert(nm->contains(ic_call), "must be in compiled method");
initialize_from_iter(iter);
}
@ -278,7 +278,7 @@ bool CompiledIC::is_call_to_compiled() const {
// method is guaranteed to still exist, since we only remove methods after all inline caches
// has been cleaned up
CodeBlob* cb = CodeCache::find_blob_unsafe(ic_destination());
bool is_monomorphic = (cb != NULL && cb->is_nmethod());
bool is_monomorphic = (cb != NULL && cb->is_compiled());
// Check that the cached_value is a klass for non-optimized monomorphic calls
// This assertion is invalid for compiler1: a call that does not look optimized (no static stub) can be used
// for calling directly to vep without using the inline cache (i.e., cached_value == NULL).
@ -423,7 +423,7 @@ void CompiledIC::set_to_monomorphic(CompiledICInfo& info) {
bool static_bound = info.is_optimized() || (info.cached_metadata() == NULL);
#ifdef ASSERT
CodeBlob* cb = CodeCache::find_blob_unsafe(info.entry());
assert (cb->is_nmethod(), "must be compiled!");
assert (cb->is_compiled(), "must be compiled!");
#endif /* ASSERT */
// This is MT safe if we come from a clean-cache and go through a
@ -469,9 +469,11 @@ void CompiledIC::compute_monomorphic_entry(const methodHandle& method,
bool static_bound,
CompiledICInfo& info,
TRAPS) {
nmethod* method_code = method->code();
CompiledMethod* method_code = method->code();
address entry = NULL;
if (method_code != NULL && method_code->is_in_use()) {
assert(method_code->is_compiled(), "must be compiled");
// Call to compiled code
if (static_bound || is_optimized) {
entry = method_code->verified_entry_point();
@ -520,6 +522,7 @@ void CompiledIC::compute_monomorphic_entry(const methodHandle& method,
info.set_interpreter_entry(method()->get_c2i_entry(), method());
} else {
// Use icholder entry
assert(method_code == NULL || method_code->is_compiled(), "must be compiled");
CompiledICHolder* holder = new CompiledICHolder(method(), receiver_klass());
info.set_icholder_entry(method()->get_c2i_unverified_entry(), holder);
}
@ -557,7 +560,7 @@ void CompiledStaticCall::set_to_clean() {
MutexLockerEx pl(SafepointSynchronize::is_at_safepoint() ? NULL : Patching_lock, Mutex::_no_safepoint_check_flag);
#ifdef ASSERT
CodeBlob* cb = CodeCache::find_blob_unsafe(this);
assert(cb != NULL && cb->is_nmethod(), "must be nmethod");
assert(cb != NULL && cb->is_compiled(), "must be compiled");
#endif
set_destination_mt_safe(SharedRuntime::get_resolve_static_call_stub());
@ -579,8 +582,8 @@ bool CompiledStaticCall::is_call_to_compiled() const {
bool CompiledStaticCall::is_call_to_interpreted() const {
// It is a call to interpreted, if it calls to a stub. Hence, the destination
// must be in the stub part of the nmethod that contains the call
nmethod* nm = CodeCache::find_nmethod(instruction_address());
return nm->stub_contains(destination());
CompiledMethod* cm = CodeCache::find_compiled(instruction_address());
return cm->stub_contains(destination());
}
void CompiledStaticCall::set(const StaticCallInfo& info) {
@ -612,7 +615,7 @@ void CompiledStaticCall::set(const StaticCallInfo& info) {
// Compute settings for a CompiledStaticCall. Since we might have to set
// the stub when calling to the interpreter, we need to return arguments.
void CompiledStaticCall::compute_entry(const methodHandle& m, StaticCallInfo& info) {
nmethod* m_code = m->code();
CompiledMethod* m_code = m->code();
info._callee = m;
if (m_code != NULL && m_code->is_in_use()) {
info._to_interpreter = false;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -135,7 +135,7 @@ class CompiledIC: public ResourceObj {
NativeMovConstReg* _value; // patchable value cell for this IC
bool _is_optimized; // an optimized virtual call (i.e., no compiled IC)
CompiledIC(nmethod* nm, NativeCall* ic_call);
CompiledIC(CompiledMethod* cm, NativeCall* ic_call);
CompiledIC(RelocIterator* iter);
void initialize_from_iter(RelocIterator* iter);
@ -169,8 +169,8 @@ class CompiledIC: public ResourceObj {
public:
// conversion (machine PC to CompiledIC*)
friend CompiledIC* CompiledIC_before(nmethod* nm, address return_addr);
friend CompiledIC* CompiledIC_at(nmethod* nm, address call_site);
friend CompiledIC* CompiledIC_before(CompiledMethod* nm, address return_addr);
friend CompiledIC* CompiledIC_at(CompiledMethod* nm, address call_site);
friend CompiledIC* CompiledIC_at(Relocation* call_site);
friend CompiledIC* CompiledIC_at(RelocIterator* reloc_iter);
@ -234,13 +234,13 @@ class CompiledIC: public ResourceObj {
void verify() PRODUCT_RETURN;
};
inline CompiledIC* CompiledIC_before(nmethod* nm, address return_addr) {
inline CompiledIC* CompiledIC_before(CompiledMethod* nm, address return_addr) {
CompiledIC* c_ic = new CompiledIC(nm, nativeCall_before(return_addr));
c_ic->verify();
return c_ic;
}
inline CompiledIC* CompiledIC_at(nmethod* nm, address call_site) {
inline CompiledIC* CompiledIC_at(CompiledMethod* nm, address call_site) {
CompiledIC* c_ic = new CompiledIC(nm, nativeCall_at(call_site));
c_ic->verify();
return c_ic;

View File

@ -0,0 +1,707 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "code/compiledIC.hpp"
#include "code/scopeDesc.hpp"
#include "code/codeCache.hpp"
#include "prims/methodHandles.hpp"
#include "interpreter/bytecode.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/mutexLocker.hpp"
CompiledMethod::CompiledMethod(Method* method, const char* name, const CodeBlobLayout& layout, int frame_complete_offset, int frame_size, ImmutableOopMapSet* oop_maps, bool caller_must_gc_arguments)
: CodeBlob(name, layout, frame_complete_offset, frame_size, oop_maps, caller_must_gc_arguments),
_method(method), _mark_for_deoptimization_status(not_marked) {
init_defaults();
}
CompiledMethod::CompiledMethod(Method* method, const char* name, int size, int header_size, CodeBuffer* cb, int frame_complete_offset, int frame_size, OopMapSet* oop_maps, bool caller_must_gc_arguments)
: CodeBlob(name, CodeBlobLayout((address) this, size, header_size, cb), cb, frame_complete_offset, frame_size, oop_maps, caller_must_gc_arguments),
_method(method), _mark_for_deoptimization_status(not_marked) {
init_defaults();
}
void CompiledMethod::init_defaults() {
_has_unsafe_access = 0;
_has_method_handle_invokes = 0;
_lazy_critical_native = 0;
_has_wide_vectors = 0;
_unloading_clock = 0;
}
bool CompiledMethod::is_method_handle_return(address return_pc) {
if (!has_method_handle_invokes()) return false;
PcDesc* pd = pc_desc_at(return_pc);
if (pd == NULL)
return false;
return pd->is_method_handle_invoke();
}
// When using JVMCI the address might be off by the size of a call instruction.
bool CompiledMethod::is_deopt_entry(address pc) {
return pc == deopt_handler_begin()
#if INCLUDE_JVMCI
|| pc == (deopt_handler_begin() + NativeCall::instruction_size)
#endif
;
}
// Returns a string version of the method state.
const char* CompiledMethod::state() const {
int state = get_state();
switch (state) {
case in_use:
return "in use";
case not_used:
return "not_used";
case not_entrant:
return "not_entrant";
case zombie:
return "zombie";
case unloaded:
return "unloaded";
default:
fatal("unexpected method state: %d", state);
return NULL;
}
}
//-----------------------------------------------------------------------------
void CompiledMethod::add_exception_cache_entry(ExceptionCache* new_entry) {
assert(ExceptionCache_lock->owned_by_self(),"Must hold the ExceptionCache_lock");
assert(new_entry != NULL,"Must be non null");
assert(new_entry->next() == NULL, "Must be null");
ExceptionCache *ec = exception_cache();
if (ec != NULL) {
new_entry->set_next(ec);
}
release_set_exception_cache(new_entry);
}
void CompiledMethod::clean_exception_cache(BoolObjectClosure* is_alive) {
ExceptionCache* prev = NULL;
ExceptionCache* curr = exception_cache();
while (curr != NULL) {
ExceptionCache* next = curr->next();
Klass* ex_klass = curr->exception_type();
if (ex_klass != NULL && !ex_klass->is_loader_alive(is_alive)) {
if (prev == NULL) {
set_exception_cache(next);
} else {
prev->set_next(next);
}
delete curr;
// prev stays the same.
} else {
prev = curr;
}
curr = next;
}
}
// public method for accessing the exception cache
// These are the public access methods.
address CompiledMethod::handler_for_exception_and_pc(Handle exception, address pc) {
// We never grab a lock to read the exception cache, so we may
// have false negatives. This is okay, as it can only happen during
// the first few exception lookups for a given nmethod.
ExceptionCache* ec = exception_cache();
while (ec != NULL) {
address ret_val;
if ((ret_val = ec->match(exception,pc)) != NULL) {
return ret_val;
}
ec = ec->next();
}
return NULL;
}
void CompiledMethod::add_handler_for_exception_and_pc(Handle exception, address pc, address handler) {
// There are potential race conditions during exception cache updates, so we
// must own the ExceptionCache_lock before doing ANY modifications. Because
// we don't lock during reads, it is possible to have several threads attempt
// to update the cache with the same data. We need to check for already inserted
// copies of the current data before adding it.
MutexLocker ml(ExceptionCache_lock);
ExceptionCache* target_entry = exception_cache_entry_for_exception(exception);
if (target_entry == NULL || !target_entry->add_address_and_handler(pc,handler)) {
target_entry = new ExceptionCache(exception,pc,handler);
add_exception_cache_entry(target_entry);
}
}
//-------------end of code for ExceptionCache--------------
// private method for handling exception cache
// These methods are private, and used to manipulate the exception cache
// directly.
ExceptionCache* CompiledMethod::exception_cache_entry_for_exception(Handle exception) {
ExceptionCache* ec = exception_cache();
while (ec != NULL) {
if (ec->match_exception_with_space(exception)) {
return ec;
}
ec = ec->next();
}
return NULL;
}
bool CompiledMethod::is_at_poll_return(address pc) {
RelocIterator iter(this, pc, pc+1);
while (iter.next()) {
if (iter.type() == relocInfo::poll_return_type)
return true;
}
return false;
}
bool CompiledMethod::is_at_poll_or_poll_return(address pc) {
RelocIterator iter(this, pc, pc+1);
while (iter.next()) {
relocInfo::relocType t = iter.type();
if (t == relocInfo::poll_return_type || t == relocInfo::poll_type)
return true;
}
return false;
}
void CompiledMethod::verify_oop_relocations() {
// Ensure sure that the code matches the current oop values
RelocIterator iter(this, NULL, NULL);
while (iter.next()) {
if (iter.type() == relocInfo::oop_type) {
oop_Relocation* reloc = iter.oop_reloc();
if (!reloc->oop_is_immediate()) {
reloc->verify_oop_relocation();
}
}
}
}
ScopeDesc* CompiledMethod::scope_desc_at(address pc) {
PcDesc* pd = pc_desc_at(pc);
guarantee(pd != NULL, "scope must be present");
return new ScopeDesc(this, pd->scope_decode_offset(),
pd->obj_decode_offset(), pd->should_reexecute(), pd->rethrow_exception(),
pd->return_oop());
}
void CompiledMethod::cleanup_inline_caches(bool clean_all/*=false*/) {
assert_locked_or_safepoint(CompiledIC_lock);
// If the method is not entrant or zombie then a JMP is plastered over the
// first few bytes. If an oop in the old code was there, that oop
// should not get GC'd. Skip the first few bytes of oops on
// not-entrant methods.
address low_boundary = verified_entry_point();
if (!is_in_use() && is_nmethod()) {
low_boundary += NativeJump::instruction_size;
// %%% Note: On SPARC we patch only a 4-byte trap, not a full NativeJump.
// This means that the low_boundary is going to be a little too high.
// This shouldn't matter, since oops of non-entrant methods are never used.
// In fact, why are we bothering to look at oops in a non-entrant method??
}
// Find all calls in an nmethod and clear the ones that point to non-entrant,
// zombie and unloaded nmethods.
ResourceMark rm;
RelocIterator iter(this, low_boundary);
while(iter.next()) {
switch(iter.type()) {
case relocInfo::virtual_call_type:
case relocInfo::opt_virtual_call_type: {
CompiledIC *ic = CompiledIC_at(&iter);
// Ok, to lookup references to zombies here
CodeBlob *cb = CodeCache::find_blob_unsafe(ic->ic_destination());
if( cb != NULL && cb->is_compiled() ) {
CompiledMethod* nm = cb->as_compiled_method();
// Clean inline caches pointing to zombie, non-entrant and unloaded methods
if (clean_all || !nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean(is_alive());
}
break;
}
case relocInfo::static_call_type: {
CompiledStaticCall *csc = compiledStaticCall_at(iter.reloc());
CodeBlob *cb = CodeCache::find_blob_unsafe(csc->destination());
if( cb != NULL && cb->is_compiled() ) {
CompiledMethod* cm = cb->as_compiled_method();
// Clean inline caches pointing to zombie, non-entrant and unloaded methods
if (clean_all || !cm->is_in_use() || (cm->method()->code() != cm)) {
csc->set_to_clean();
}
}
break;
}
}
}
}
int CompiledMethod::verify_icholder_relocations() {
ResourceMark rm;
int count = 0;
RelocIterator iter(this);
while(iter.next()) {
if (iter.type() == relocInfo::virtual_call_type) {
if (CompiledIC::is_icholder_call_site(iter.virtual_call_reloc())) {
CompiledIC *ic = CompiledIC_at(&iter);
if (TraceCompiledIC) {
tty->print("noticed icholder " INTPTR_FORMAT " ", p2i(ic->cached_icholder()));
ic->print();
}
assert(ic->cached_icholder() != NULL, "must be non-NULL");
count++;
}
}
}
return count;
}
// Method that knows how to preserve outgoing arguments at call. This method must be
// called with a frame corresponding to a Java invoke
void CompiledMethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) {
#ifndef SHARK
if (method() != NULL && !method()->is_native()) {
address pc = fr.pc();
SimpleScopeDesc ssd(this, pc);
Bytecode_invoke call(ssd.method(), ssd.bci());
bool has_receiver = call.has_receiver();
bool has_appendix = call.has_appendix();
Symbol* signature = call.signature();
// The method attached by JIT-compilers should be used, if present.
// Bytecode can be inaccurate in such case.
Method* callee = attached_method_before_pc(pc);
if (callee != NULL) {
has_receiver = !(callee->access_flags().is_static());
has_appendix = false;
signature = callee->signature();
}
fr.oops_compiled_arguments_do(signature, has_receiver, has_appendix, reg_map, f);
}
#endif // !SHARK
}
// -----------------------------------------------------------------------------
// CompiledMethod::get_deopt_original_pc
//
// Return the original PC for the given PC if:
// (a) the given PC belongs to a nmethod and
// (b) it is a deopt PC
address CompiledMethod::get_deopt_original_pc(const frame* fr) {
if (fr->cb() == NULL) return NULL;
CompiledMethod* cm = fr->cb()->as_compiled_method_or_null();
if (cm != NULL && cm->is_deopt_pc(fr->pc()))
return cm->get_original_pc(fr);
return NULL;
}
Method* CompiledMethod::attached_method(address call_instr) {
assert(code_contains(call_instr), "not part of the nmethod");
RelocIterator iter(this, call_instr, call_instr + 1);
while (iter.next()) {
if (iter.addr() == call_instr) {
switch(iter.type()) {
case relocInfo::static_call_type: return iter.static_call_reloc()->method_value();
case relocInfo::opt_virtual_call_type: return iter.opt_virtual_call_reloc()->method_value();
case relocInfo::virtual_call_type: return iter.virtual_call_reloc()->method_value();
}
}
}
return NULL; // not found
}
Method* CompiledMethod::attached_method_before_pc(address pc) {
if (NativeCall::is_call_before(pc)) {
NativeCall* ncall = nativeCall_before(pc);
return attached_method(ncall->instruction_address());
}
return NULL; // not a call
}
void CompiledMethod::clear_inline_caches() {
assert(SafepointSynchronize::is_at_safepoint(), "cleaning of IC's only allowed at safepoint");
if (is_zombie()) {
return;
}
RelocIterator iter(this);
while (iter.next()) {
iter.reloc()->clear_inline_cache();
}
}
// Clear ICStubs of all compiled ICs
void CompiledMethod::clear_ic_stubs() {
assert_locked_or_safepoint(CompiledIC_lock);
RelocIterator iter(this);
while(iter.next()) {
if (iter.type() == relocInfo::virtual_call_type) {
CompiledIC* ic = CompiledIC_at(&iter);
ic->clear_ic_stub();
}
}
}
#ifdef ASSERT
class CheckClass : AllStatic {
static BoolObjectClosure* _is_alive;
// Check class_loader is alive for this bit of metadata.
static void check_class(Metadata* md) {
Klass* klass = NULL;
if (md->is_klass()) {
klass = ((Klass*)md);
} else if (md->is_method()) {
klass = ((Method*)md)->method_holder();
} else if (md->is_methodData()) {
klass = ((MethodData*)md)->method()->method_holder();
} else {
md->print();
ShouldNotReachHere();
}
assert(klass->is_loader_alive(_is_alive), "must be alive");
}
public:
static void do_check_class(BoolObjectClosure* is_alive, CompiledMethod* nm) {
assert(SafepointSynchronize::is_at_safepoint(), "this is only ok at safepoint");
_is_alive = is_alive;
nm->metadata_do(check_class);
}
};
// This is called during a safepoint so can use static data
BoolObjectClosure* CheckClass::_is_alive = NULL;
#endif // ASSERT
void CompiledMethod::clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_alive) {
if (ic->is_icholder_call()) {
// The only exception is compiledICHolder oops which may
// yet be marked below. (We check this further below).
CompiledICHolder* cichk_oop = ic->cached_icholder();
if (cichk_oop->holder_method()->method_holder()->is_loader_alive(is_alive) &&
cichk_oop->holder_klass()->is_loader_alive(is_alive)) {
return;
}
} else {
Metadata* ic_oop = ic->cached_metadata();
if (ic_oop != NULL) {
if (ic_oop->is_klass()) {
if (((Klass*)ic_oop)->is_loader_alive(is_alive)) {
return;
}
} else if (ic_oop->is_method()) {
if (((Method*)ic_oop)->method_holder()->is_loader_alive(is_alive)) {
return;
}
} else {
ShouldNotReachHere();
}
}
}
ic->set_to_clean();
}
unsigned char CompiledMethod::_global_unloading_clock = 0;
void CompiledMethod::increase_unloading_clock() {
_global_unloading_clock++;
if (_global_unloading_clock == 0) {
// _nmethods are allocated with _unloading_clock == 0,
// so 0 is never used as a clock value.
_global_unloading_clock = 1;
}
}
void CompiledMethod::set_unloading_clock(unsigned char unloading_clock) {
OrderAccess::release_store((volatile jubyte*)&_unloading_clock, unloading_clock);
}
unsigned char CompiledMethod::unloading_clock() {
return (unsigned char)OrderAccess::load_acquire((volatile jubyte*)&_unloading_clock);
}
// Processing of oop references should have been sufficient to keep
// all strong references alive. Any weak references should have been
// cleared as well. Visit all the metadata and ensure that it's
// really alive.
void CompiledMethod::verify_metadata_loaders(address low_boundary, BoolObjectClosure* is_alive) {
#ifdef ASSERT
RelocIterator iter(this, low_boundary);
while (iter.next()) {
// static_stub_Relocations may have dangling references to
// Method*s so trim them out here. Otherwise it looks like
// compiled code is maintaining a link to dead metadata.
address static_call_addr = NULL;
if (iter.type() == relocInfo::opt_virtual_call_type) {
CompiledIC* cic = CompiledIC_at(&iter);
if (!cic->is_call_to_interpreted()) {
static_call_addr = iter.addr();
}
} else if (iter.type() == relocInfo::static_call_type) {
CompiledStaticCall* csc = compiledStaticCall_at(iter.reloc());
if (!csc->is_call_to_interpreted()) {
static_call_addr = iter.addr();
}
}
if (static_call_addr != NULL) {
RelocIterator sciter(this, low_boundary);
while (sciter.next()) {
if (sciter.type() == relocInfo::static_stub_type &&
sciter.static_stub_reloc()->static_call() == static_call_addr) {
sciter.static_stub_reloc()->clear_inline_cache();
}
}
}
}
// Check that the metadata embedded in the nmethod is alive
CheckClass::do_check_class(is_alive, this);
#endif
}
// This is called at the end of the strong tracing/marking phase of a
// GC to unload an nmethod if it contains otherwise unreachable
// oops.
void CompiledMethod::do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred) {
// Make sure the oop's ready to receive visitors
assert(!is_zombie() && !is_unloaded(),
"should not call follow on zombie or unloaded nmethod");
// If the method is not entrant then a JMP is plastered over the
// first few bytes. If an oop in the old code was there, that oop
// should not get GC'd. Skip the first few bytes of oops on
// not-entrant methods.
address low_boundary = verified_entry_point();
if (is_not_entrant()) {
low_boundary += NativeJump::instruction_size;
// %%% Note: On SPARC we patch only a 4-byte trap, not a full NativeJump.
// (See comment above.)
}
// The RedefineClasses() API can cause the class unloading invariant
// to no longer be true. See jvmtiExport.hpp for details.
// Also, leave a debugging breadcrumb in local flag.
if (JvmtiExport::has_redefined_a_class()) {
// This set of the unloading_occurred flag is done before the
// call to post_compiled_method_unload() so that the unloading
// of this nmethod is reported.
unloading_occurred = true;
}
// Exception cache
clean_exception_cache(is_alive);
// If class unloading occurred we first iterate over all inline caches and
// clear ICs where the cached oop is referring to an unloaded klass or method.
// The remaining live cached oops will be traversed in the relocInfo::oop_type
// iteration below.
if (unloading_occurred) {
RelocIterator iter(this, low_boundary);
while(iter.next()) {
if (iter.type() == relocInfo::virtual_call_type) {
CompiledIC *ic = CompiledIC_at(&iter);
clean_ic_if_metadata_is_dead(ic, is_alive);
}
}
}
if (do_unloading_oops(low_boundary, is_alive, unloading_occurred)) {
return;
}
#if INCLUDE_JVMCI
if (do_unloading_jvmci(is_alive, unloading_occurred)) {
return;
}
#endif
// Ensure that all metadata is still alive
verify_metadata_loaders(low_boundary, is_alive);
}
template <class CompiledICorStaticCall>
static bool clean_if_nmethod_is_unloaded(CompiledICorStaticCall *ic, address addr, BoolObjectClosure *is_alive, CompiledMethod* from) {
// Ok, to lookup references to zombies here
CodeBlob *cb = CodeCache::find_blob_unsafe(addr);
CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL;
if (nm != NULL) {
if (nm->unloading_clock() != CompiledMethod::global_unloading_clock()) {
// The nmethod has not been processed yet.
return true;
}
// Clean inline caches pointing to both zombie and not_entrant methods
if (!nm->is_in_use() || (nm->method()->code() != nm)) {
ic->set_to_clean();
assert(ic->is_clean(), "nmethod " PTR_FORMAT "not clean %s", p2i(from), from->method()->name_and_sig_as_C_string());
}
}
return false;
}
static bool clean_if_nmethod_is_unloaded(CompiledIC *ic, BoolObjectClosure *is_alive, CompiledMethod* from) {
return clean_if_nmethod_is_unloaded(ic, ic->ic_destination(), is_alive, from);
}
static bool clean_if_nmethod_is_unloaded(CompiledStaticCall *csc, BoolObjectClosure *is_alive, CompiledMethod* from) {
return clean_if_nmethod_is_unloaded(csc, csc->destination(), is_alive, from);
}
bool CompiledMethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_occurred) {
ResourceMark rm;
// Make sure the oop's ready to receive visitors
assert(!is_zombie() && !is_unloaded(),
"should not call follow on zombie or unloaded nmethod");
// If the method is not entrant then a JMP is plastered over the
// first few bytes. If an oop in the old code was there, that oop
// should not get GC'd. Skip the first few bytes of oops on
// not-entrant methods.
address low_boundary = verified_entry_point();
if (is_not_entrant()) {
low_boundary += NativeJump::instruction_size;
// %%% Note: On SPARC we patch only a 4-byte trap, not a full NativeJump.
// (See comment above.)
}
// The RedefineClasses() API can cause the class unloading invariant
// to no longer be true. See jvmtiExport.hpp for details.
// Also, leave a debugging breadcrumb in local flag.
if (JvmtiExport::has_redefined_a_class()) {
// This set of the unloading_occurred flag is done before the
// call to post_compiled_method_unload() so that the unloading
// of this nmethod is reported.
unloading_occurred = true;
}
// Exception cache
clean_exception_cache(is_alive);
bool postponed = false;
RelocIterator iter(this, low_boundary);
while(iter.next()) {
switch (iter.type()) {
case relocInfo::virtual_call_type:
if (unloading_occurred) {
// If class unloading occurred we first iterate over all inline caches and
// clear ICs where the cached oop is referring to an unloaded klass or method.
clean_ic_if_metadata_is_dead(CompiledIC_at(&iter), is_alive);
}
postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this);
break;
case relocInfo::opt_virtual_call_type:
postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this);
break;
case relocInfo::static_call_type:
postponed |= clean_if_nmethod_is_unloaded(compiledStaticCall_at(iter.reloc()), is_alive, this);
break;
case relocInfo::oop_type:
// handled by do_unloading_oops below
break;
case relocInfo::metadata_type:
break; // nothing to do.
}
}
if (do_unloading_oops(low_boundary, is_alive, unloading_occurred)) {
return postponed;
}
#if INCLUDE_JVMCI
if (do_unloading_jvmci(is_alive, unloading_occurred)) {
return postponed;
}
#endif
// Ensure that all metadata is still alive
verify_metadata_loaders(low_boundary, is_alive);
return postponed;
}
void CompiledMethod::do_unloading_parallel_postponed(BoolObjectClosure* is_alive, bool unloading_occurred) {
ResourceMark rm;
// Make sure the oop's ready to receive visitors
assert(!is_zombie(),
"should not call follow on zombie nmethod");
// If the method is not entrant then a JMP is plastered over the
// first few bytes. If an oop in the old code was there, that oop
// should not get GC'd. Skip the first few bytes of oops on
// not-entrant methods.
address low_boundary = verified_entry_point();
if (is_not_entrant()) {
low_boundary += NativeJump::instruction_size;
// %%% Note: On SPARC we patch only a 4-byte trap, not a full NativeJump.
// (See comment above.)
}
RelocIterator iter(this, low_boundary);
while(iter.next()) {
switch (iter.type()) {
case relocInfo::virtual_call_type:
clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this);
break;
case relocInfo::opt_virtual_call_type:
clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this);
break;
case relocInfo::static_call_type:
clean_if_nmethod_is_unloaded(compiledStaticCall_at(iter.reloc()), is_alive, this);
break;
}
}
}

View File

@ -0,0 +1,391 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_CODE_COMPILEDMETHOD_HPP
#define SHARE_VM_CODE_COMPILEDMETHOD_HPP
#include "code/codeBlob.hpp"
#include "code/pcDesc.hpp"
#include "oops/metadata.hpp"
class Dependencies;
class ExceptionHandlerTable;
class ImplicitExceptionTable;
class AbstractCompiler;
class xmlStream;
class CompiledStaticCall;
// This class is used internally by nmethods, to cache
// exception/pc/handler information.
class ExceptionCache : public CHeapObj<mtCode> {
friend class VMStructs;
private:
enum { cache_size = 16 };
Klass* _exception_type;
address _pc[cache_size];
address _handler[cache_size];
volatile int _count;
ExceptionCache* _next;
address pc_at(int index) { assert(index >= 0 && index < count(),""); return _pc[index]; }
void set_pc_at(int index, address a) { assert(index >= 0 && index < cache_size,""); _pc[index] = a; }
address handler_at(int index) { assert(index >= 0 && index < count(),""); return _handler[index]; }
void set_handler_at(int index, address a) { assert(index >= 0 && index < cache_size,""); _handler[index] = a; }
int count() { return OrderAccess::load_acquire(&_count); }
// increment_count is only called under lock, but there may be concurrent readers.
void increment_count() { OrderAccess::release_store(&_count, _count + 1); }
public:
ExceptionCache(Handle exception, address pc, address handler);
Klass* exception_type() { return _exception_type; }
ExceptionCache* next() { return _next; }
void set_next(ExceptionCache *ec) { _next = ec; }
address match(Handle exception, address pc);
bool match_exception_with_space(Handle exception) ;
address test_address(address addr);
bool add_address_and_handler(address addr, address handler) ;
};
class nmethod;
// cache pc descs found in earlier inquiries
class PcDescCache VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
private:
enum { cache_size = 4 };
// The array elements MUST be volatile! Several threads may modify
// and read from the cache concurrently. find_pc_desc_internal has
// returned wrong results. C++ compiler (namely xlC12) may duplicate
// C++ field accesses if the elements are not volatile.
typedef PcDesc* PcDescPtr;
volatile PcDescPtr _pc_descs[cache_size]; // last cache_size pc_descs found
public:
PcDescCache() { debug_only(_pc_descs[0] = NULL); }
void reset_to(PcDesc* initial_pc_desc);
PcDesc* find_pc_desc(int pc_offset, bool approximate);
void add_pc_desc(PcDesc* pc_desc);
PcDesc* last_pc_desc() { return _pc_descs[0]; }
};
class PcDescSearch {
private:
address _code_begin;
PcDesc* _lower;
PcDesc* _upper;
public:
PcDescSearch(address code, PcDesc* lower, PcDesc* upper) :
_code_begin(code), _lower(lower), _upper(upper)
{
}
address code_begin() const { return _code_begin; }
PcDesc* scopes_pcs_begin() const { return _lower; }
PcDesc* scopes_pcs_end() const { return _upper; }
};
class PcDescContainer VALUE_OBJ_CLASS_SPEC {
private:
PcDescCache _pc_desc_cache;
public:
PcDescContainer() {}
PcDesc* find_pc_desc_internal(address pc, bool approximate, const PcDescSearch& search);
void reset_to(PcDesc* initial_pc_desc) { _pc_desc_cache.reset_to(initial_pc_desc); }
PcDesc* find_pc_desc(address pc, bool approximate, const PcDescSearch& search) {
address base_address = search.code_begin();
PcDesc* desc = _pc_desc_cache.last_pc_desc();
if (desc != NULL && desc->pc_offset() == pc - base_address) {
return desc;
}
return find_pc_desc_internal(pc, approximate, search);
}
};
class CompiledMethod : public CodeBlob {
friend class VMStructs;
friend class NMethodSweeper;
void init_defaults();
protected:
enum MarkForDeoptimizationStatus {
not_marked,
deoptimize,
deoptimize_noupdate
};
MarkForDeoptimizationStatus _mark_for_deoptimization_status; // Used for stack deoptimization
bool _is_far_code; // Code is far from CodeCache.
// Have to use far call instructions to call it from code in CodeCache.
// set during construction
unsigned int _has_unsafe_access:1; // May fault due to unsafe access.
unsigned int _has_method_handle_invokes:1; // Has this method MethodHandle invokes?
unsigned int _lazy_critical_native:1; // Lazy JNI critical native
unsigned int _has_wide_vectors:1; // Preserve wide vectors at safepoints
Method* _method;
address _scopes_data_begin;
// All deoptee's will resume execution at this location described by
// this address.
address _deopt_handler_begin;
// All deoptee's at a MethodHandle call site will resume execution
// at this location described by this offset.
address _deopt_mh_handler_begin;
PcDescContainer _pc_desc_container;
ExceptionCache * volatile _exception_cache;
virtual void flush() = 0;
protected:
CompiledMethod(Method* method, const char* name, const CodeBlobLayout& layout, int frame_complete_offset, int frame_size, ImmutableOopMapSet* oop_maps, bool caller_must_gc_arguments);
CompiledMethod(Method* method, const char* name, int size, int header_size, CodeBuffer* cb, int frame_complete_offset, int frame_size, OopMapSet* oop_maps, bool caller_must_gc_arguments);
public:
virtual bool is_compiled() const { return true; }
bool has_unsafe_access() const { return _has_unsafe_access; }
void set_has_unsafe_access(bool z) { _has_unsafe_access = z; }
bool has_method_handle_invokes() const { return _has_method_handle_invokes; }
void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; }
bool is_lazy_critical_native() const { return _lazy_critical_native; }
void set_lazy_critical_native(bool z) { _lazy_critical_native = z; }
bool has_wide_vectors() const { return _has_wide_vectors; }
void set_has_wide_vectors(bool z) { _has_wide_vectors = z; }
enum { in_use = 0, // executable nmethod
not_used = 1, // not entrant, but revivable
not_entrant = 2, // marked for deoptimization but activations may still exist,
// will be transformed to zombie when all activations are gone
zombie = 3, // no activations exist, nmethod is ready for purge
unloaded = 4 // there should be no activations, should not be called,
// will be transformed to zombie immediately
};
virtual AbstractCompiler* compiler() const = 0;
virtual bool is_in_use() const = 0;
virtual int comp_level() const = 0;
virtual int compile_id() const = 0;
virtual address verified_entry_point() const = 0;
virtual void log_identity(xmlStream* log) const = 0;
virtual void log_state_change() const = 0;
virtual bool make_not_used() = 0;
virtual bool make_not_entrant() = 0;
virtual bool make_entrant() = 0;
virtual address entry_point() const = 0;
virtual bool make_zombie() = 0;
virtual bool is_osr_method() const = 0;
virtual int osr_entry_bci() const = 0;
Method* method() const { return _method; }
virtual void print_pcs() = 0;
bool is_native_method() const { return _method != NULL && _method->is_native(); }
bool is_java_method() const { return _method != NULL && !_method->is_native(); }
// ScopeDesc retrieval operation
PcDesc* pc_desc_at(address pc) { return find_pc_desc(pc, false); }
// pc_desc_near returns the first PcDesc at or after the givne pc.
PcDesc* pc_desc_near(address pc) { return find_pc_desc(pc, true); }
// ScopeDesc for an instruction
ScopeDesc* scope_desc_at(address pc);
bool is_at_poll_return(address pc);
bool is_at_poll_or_poll_return(address pc);
bool is_marked_for_deoptimization() const { return _mark_for_deoptimization_status != not_marked; }
void mark_for_deoptimization(bool inc_recompile_counts = true) {
_mark_for_deoptimization_status = (inc_recompile_counts ? deoptimize : deoptimize_noupdate);
}
bool update_recompile_counts() const {
// Update recompile counts when either the update is explicitly requested (deoptimize)
// or the nmethod is not marked for deoptimization at all (not_marked).
// The latter happens during uncommon traps when deoptimized nmethod is made not entrant.
return _mark_for_deoptimization_status != deoptimize_noupdate;
}
// tells whether frames described by this nmethod can be deoptimized
// note: native wrappers cannot be deoptimized.
bool can_be_deoptimized() const { return is_java_method(); }
virtual oop oop_at(int index) const = 0;
virtual Metadata* metadata_at(int index) const = 0;
address scopes_data_begin() const { return _scopes_data_begin; }
virtual address scopes_data_end() const = 0;
int scopes_data_size() const { return scopes_data_end() - scopes_data_begin(); }
virtual PcDesc* scopes_pcs_begin() const = 0;
virtual PcDesc* scopes_pcs_end() const = 0;
int scopes_pcs_size() const { return (intptr_t) scopes_pcs_end() - (intptr_t) scopes_pcs_begin(); }
address insts_begin() const { return code_begin(); }
address insts_end() const { return stub_begin(); }
bool insts_contains(address addr) const { return insts_begin() <= addr && addr < insts_end(); }
int insts_size() const { return insts_end() - insts_begin(); }
virtual address consts_begin() const = 0;
virtual address consts_end() const = 0;
bool consts_contains(address addr) const { return consts_begin() <= addr && addr < consts_end(); }
int consts_size() const { return consts_end() - consts_begin(); }
virtual address stub_begin() const = 0;
virtual address stub_end() const = 0;
bool stub_contains(address addr) const { return stub_begin() <= addr && addr < stub_end(); }
int stub_size() const { return stub_end() - stub_begin(); }
virtual address handler_table_begin() const = 0;
virtual address handler_table_end() const = 0;
bool handler_table_contains(address addr) const { return handler_table_begin() <= addr && addr < handler_table_end(); }
int handler_table_size() const { return handler_table_end() - handler_table_begin(); }
virtual address nul_chk_table_begin() const = 0;
virtual address nul_chk_table_end() const = 0;
bool nul_chk_table_contains(address addr) const { return nul_chk_table_begin() <= addr && addr < nul_chk_table_end(); }
int nul_chk_table_size() const { return nul_chk_table_end() - nul_chk_table_begin(); }
virtual oop* oop_addr_at(int index) const = 0;
virtual Metadata** metadata_addr_at(int index) const = 0;
virtual void set_original_pc(const frame* fr, address pc) = 0;
// Exception cache support
// Note: _exception_cache may be read concurrently. We rely on memory_order_consume here.
ExceptionCache* exception_cache() const { return _exception_cache; }
void set_exception_cache(ExceptionCache *ec) { _exception_cache = ec; }
void release_set_exception_cache(ExceptionCache *ec) { OrderAccess::release_store_ptr(&_exception_cache, ec); }
address handler_for_exception_and_pc(Handle exception, address pc);
void add_handler_for_exception_and_pc(Handle exception, address pc, address handler);
void clean_exception_cache(BoolObjectClosure* is_alive);
void add_exception_cache_entry(ExceptionCache* new_entry);
ExceptionCache* exception_cache_entry_for_exception(Handle exception);
// MethodHandle
bool is_method_handle_return(address return_pc);
address deopt_mh_handler_begin() const { return _deopt_mh_handler_begin; }
address deopt_handler_begin() const { return _deopt_handler_begin; }
virtual address get_original_pc(const frame* fr) = 0;
// Deopt
// Return true is the PC is one would expect if the frame is being deopted.
bool is_deopt_pc (address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); }
bool is_deopt_mh_entry(address pc) { return pc == deopt_mh_handler_begin(); }
bool is_deopt_entry(address pc);
virtual bool can_convert_to_zombie() = 0;
virtual const char* compile_kind() const = 0;
virtual int get_state() const = 0;
const char* state() const;
bool is_far_code() const { return _is_far_code; }
bool inlinecache_check_contains(address addr) const {
return (addr >= code_begin() && addr < verified_entry_point());
}
void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f);
// implicit exceptions support
virtual address continuation_for_implicit_exception(address pc) { return NULL; }
static address get_deopt_original_pc(const frame* fr);
// Inline cache support
void cleanup_inline_caches(bool clean_all = false);
virtual void clear_inline_caches();
void clear_ic_stubs();
// Verify and count cached icholder relocations.
int verify_icholder_relocations();
void verify_oop_relocations();
virtual bool is_evol_dependent_on(Klass* dependee) = 0;
// Fast breakpoint support. Tells if this compiled method is
// dependent on the given method. Returns true if this nmethod
// corresponds to the given method as well.
virtual bool is_dependent_on_method(Method* dependee) = 0;
Method* attached_method(address call_pc);
Method* attached_method_before_pc(address pc);
virtual void metadata_do(void f(Metadata*)) = 0;
// GC support
void set_unloading_next(CompiledMethod* next) { _unloading_next = next; }
CompiledMethod* unloading_next() { return _unloading_next; }
void static clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_alive);
// Check that all metadata is still alive
void verify_metadata_loaders(address low_boundary, BoolObjectClosure* is_alive);
virtual void do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred);
// The parallel versions are used by G1.
virtual bool do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_occurred);
virtual void do_unloading_parallel_postponed(BoolObjectClosure* is_alive, bool unloading_occurred);
static unsigned char global_unloading_clock() { return _global_unloading_clock; }
static void increase_unloading_clock();
void set_unloading_clock(unsigned char unloading_clock);
unsigned char unloading_clock();
protected:
virtual bool do_unloading_oops(address low_boundary, BoolObjectClosure* is_alive, bool unloading_occurred) = 0;
#if INCLUDE_JVMCI
virtual bool do_unloading_jvmci(BoolObjectClosure* is_alive, bool unloading_occurred) = 0;
#endif
private:
// GC support to help figure out if an nmethod has been
// cleaned/unloaded by the current GC.
static unsigned char _global_unloading_clock;
volatile unsigned char _unloading_clock; // Incremented after GC unloaded/cleaned the nmethod
PcDesc* find_pc_desc(address pc, bool approximate) {
return _pc_desc_container.find_pc_desc(pc, approximate, PcDescSearch(code_begin(), scopes_pcs_begin(), scopes_pcs_end()));
}
protected:
union {
// Used by G1 to chain nmethods.
CompiledMethod* _unloading_next;
// Used by non-G1 GCs to chain nmethods.
nmethod* _scavenge_root_link; // from CodeCache::scavenge_root_nmethods
};
};
#endif //SHARE_VM_CODE_COMPILEDMETHOD_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -261,11 +261,11 @@ class MonitorValue: public ResourceObj {
class DebugInfoReadStream : public CompressedReadStream {
private:
const nmethod* _code;
const nmethod* code() const { return _code; }
const CompiledMethod* _code;
const CompiledMethod* code() const { return _code; }
GrowableArray<ScopeValue*>* _obj_pool;
public:
DebugInfoReadStream(const nmethod* code, int offset, GrowableArray<ScopeValue*>* obj_pool = NULL) :
DebugInfoReadStream(const CompiledMethod* code, int offset, GrowableArray<ScopeValue*>* obj_pool = NULL) :
CompressedReadStream(code->scopes_data_begin(), offset) {
_code = code;
_obj_pool = obj_pool;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 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
@ -65,9 +65,9 @@ ExceptionHandlerTable::ExceptionHandlerTable(int initial_size) {
}
ExceptionHandlerTable::ExceptionHandlerTable(const nmethod* nm) {
_table = (HandlerTableEntry*)nm->handler_table_begin();
_length = nm->handler_table_size() / sizeof(HandlerTableEntry);
ExceptionHandlerTable::ExceptionHandlerTable(const CompiledMethod* cm) {
_table = (HandlerTableEntry*)cm->handler_table_begin();
_length = cm->handler_table_size() / sizeof(HandlerTableEntry);
_size = 0; // no space allocated by ExeptionHandlerTable!
}
@ -98,9 +98,9 @@ void ExceptionHandlerTable::add_subtable(
}
void ExceptionHandlerTable::copy_to(nmethod* nm) {
assert(size_in_bytes() == nm->handler_table_size(), "size of space allocated in nmethod incorrect");
copy_bytes_to(nm->handler_table_begin());
void ExceptionHandlerTable::copy_to(CompiledMethod* cm) {
assert(size_in_bytes() == cm->handler_table_size(), "size of space allocated in compiled method incorrect");
copy_bytes_to(cm->handler_table_begin());
}
void ExceptionHandlerTable::copy_bytes_to(address addr) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 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
@ -98,7 +98,7 @@ class ExceptionHandlerTable VALUE_OBJ_CLASS_SPEC {
ExceptionHandlerTable(int initial_size = 8);
// (run-time) construction from nmethod
ExceptionHandlerTable(const nmethod* nm);
ExceptionHandlerTable(const CompiledMethod* nm);
// (compile-time) add entries
void add_subtable(
@ -115,7 +115,7 @@ class ExceptionHandlerTable VALUE_OBJ_CLASS_SPEC {
// nmethod support
int size_in_bytes() const { return round_to(_length * sizeof(HandlerTableEntry), oopSize); }
void copy_to(nmethod* nm);
void copy_to(CompiledMethod* nm);
void copy_bytes_to(address addr);
// lookup

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -49,8 +49,8 @@ int InlineCacheBuffer::_pending_count = 0;
void ICStub::finalize() {
if (!is_empty()) {
ResourceMark rm;
CompiledIC *ic = CompiledIC_at(CodeCache::find_nmethod(ic_site()), ic_site());
assert(CodeCache::find_nmethod(ic->instruction_address()) != NULL, "inline cache in non-nmethod?");
CompiledIC *ic = CompiledIC_at(CodeCache::find_compiled(ic_site()), ic_site());
assert(CodeCache::find_compiled(ic->instruction_address()) != NULL, "inline cache in non-compiled?");
assert(this == ICStub_from_destination_address(ic->stub_address()), "wrong owner of ic buffer");
ic->set_ic_destination_and_value(destination(), cached_value());

File diff suppressed because it is too large Load Diff

View File

@ -25,68 +25,11 @@
#ifndef SHARE_VM_CODE_NMETHOD_HPP
#define SHARE_VM_CODE_NMETHOD_HPP
#include "code/codeBlob.hpp"
#include "code/pcDesc.hpp"
#include "oops/metadata.hpp"
#include "code/compiledMethod.hpp"
class DepChange;
class DirectiveSet;
// This class is used internally by nmethods, to cache
// exception/pc/handler information.
class ExceptionCache : public CHeapObj<mtCode> {
friend class VMStructs;
private:
enum { cache_size = 16 };
Klass* _exception_type;
address _pc[cache_size];
address _handler[cache_size];
volatile int _count;
ExceptionCache* _next;
address pc_at(int index) { assert(index >= 0 && index < count(),""); return _pc[index]; }
void set_pc_at(int index, address a) { assert(index >= 0 && index < cache_size,""); _pc[index] = a; }
address handler_at(int index) { assert(index >= 0 && index < count(),""); return _handler[index]; }
void set_handler_at(int index, address a) { assert(index >= 0 && index < cache_size,""); _handler[index] = a; }
int count() { return OrderAccess::load_acquire(&_count); }
// increment_count is only called under lock, but there may be concurrent readers.
void increment_count() { OrderAccess::release_store(&_count, _count + 1); }
public:
ExceptionCache(Handle exception, address pc, address handler);
Klass* exception_type() { return _exception_type; }
ExceptionCache* next() { return _next; }
void set_next(ExceptionCache *ec) { _next = ec; }
address match(Handle exception, address pc);
bool match_exception_with_space(Handle exception) ;
address test_address(address addr);
bool add_address_and_handler(address addr, address handler) ;
};
// cache pc descs found in earlier inquiries
class PcDescCache VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
private:
enum { cache_size = 4 };
// The array elements MUST be volatile! Several threads may modify
// and read from the cache concurrently. find_pc_desc_internal has
// returned wrong results. C++ compiler (namely xlC12) may duplicate
// C++ field accesses if the elements are not volatile.
typedef PcDesc* PcDescPtr;
volatile PcDescPtr _pc_descs[cache_size]; // last cache_size pc_descs found
public:
PcDescCache() { debug_only(_pc_descs[0] = NULL); }
void reset_to(PcDesc* initial_pc_desc);
PcDesc* find_pc_desc(int pc_offset, bool approximate);
void add_pc_desc(PcDesc* pc_desc);
PcDesc* last_pc_desc() { return _pc_descs[0]; }
};
// nmethods (native methods) are the compiled code versions of Java methods.
//
// An nmethod contains:
@ -108,26 +51,14 @@ class PcDescCache VALUE_OBJ_CLASS_SPEC {
// [Implicit Null Pointer exception table]
// - implicit null table array
class DepChange;
class Dependencies;
class ExceptionHandlerTable;
class ImplicitExceptionTable;
class AbstractCompiler;
class xmlStream;
class nmethod : public CodeBlob {
class nmethod : public CompiledMethod {
friend class VMStructs;
friend class JVMCIVMStructs;
friend class NMethodSweeper;
friend class CodeCache; // scavengable oops
private:
// GC support to help figure out if an nmethod has been
// cleaned/unloaded by the current GC.
static unsigned char _global_unloading_clock;
// Shared fields for all nmethod's
Method* _method;
int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method
jmethodID _jmethod_id; // Cache of method()->jmethod_id()
@ -140,13 +71,6 @@ class nmethod : public CodeBlob {
// To support simple linked-list chaining of nmethods:
nmethod* _osr_link; // from InstanceKlass::osr_nmethods_head
union {
// Used by G1 to chain nmethods.
nmethod* _unloading_next;
// Used by non-G1 GCs to chain nmethods.
nmethod* _scavenge_root_link; // from CodeCache::scavenge_root_nmethods
};
static nmethod* volatile _oops_do_mark_nmethods;
nmethod* volatile _oops_do_mark_link;
@ -158,13 +82,7 @@ class nmethod : public CodeBlob {
address _osr_entry_point; // entry point for on stack replacement
// Offsets for different nmethod parts
int _exception_offset;
// All deoptee's will resume execution at this location described by
// this offset.
int _deoptimize_offset;
// All deoptee's at a MethodHandle call site will resume execution
// at this location described by this offset.
int _deoptimize_mh_offset;
int _exception_offset;
// Offset of the unwind handler if it exists
int _unwind_handler_offset;
@ -179,6 +97,8 @@ class nmethod : public CodeBlob {
int _nul_chk_table_offset;
int _nmethod_end_offset;
int code_offset() const { return (address) code_begin() - header_begin(); }
// location in frame (offset for sp) that deopt can store the original
// pc during a deopt.
int _orig_pc_offset;
@ -189,27 +109,12 @@ class nmethod : public CodeBlob {
// protected by CodeCache_lock
bool _has_flushed_dependencies; // Used for maintenance of dependencies (CodeCache_lock)
enum MarkForDeoptimizationStatus {
not_marked,
deoptimize,
deoptimize_noupdate };
MarkForDeoptimizationStatus _mark_for_deoptimization_status; // Used for stack deoptimization
// used by jvmti to track if an unload event has been posted for this nmethod.
bool _unload_reported;
// set during construction
unsigned int _has_unsafe_access:1; // May fault due to unsafe access.
unsigned int _has_method_handle_invokes:1; // Has this method MethodHandle invokes?
unsigned int _lazy_critical_native:1; // Lazy JNI critical native
unsigned int _has_wide_vectors:1; // Preserve wide vectors at safepoints
// Protected by Patching_lock
volatile unsigned char _state; // {in_use, not_entrant, zombie, unloaded}
volatile unsigned char _unloading_clock; // Incremented after GC unloaded/cleaned the nmethod
#ifdef ASSERT
bool _oops_are_stale; // indicates that it's no longer safe to access oops section
#endif
@ -242,9 +147,6 @@ class nmethod : public CodeBlob {
// counter is decreased (by 1) while sweeping.
int _hotness_counter;
ExceptionCache * volatile _exception_cache;
PcDescCache _pc_desc_cache;
// These are used for compiled synchronized native methods to
// locate the owner and stack slot for the BasicLock so that we can
// properly revoke the bias of the owner if necessary. They are
@ -302,18 +204,21 @@ class nmethod : public CodeBlob {
// Returns true if this thread changed the state of the nmethod or
// false if another thread performed the transition.
bool make_not_entrant_or_zombie(unsigned int state);
bool make_entrant() { Unimplemented(); return false; }
void inc_decompile_count();
// Used to manipulate the exception cache
void add_exception_cache_entry(ExceptionCache* new_entry);
ExceptionCache* exception_cache_entry_for_exception(Handle exception);
// Inform external interfaces that a compiled method has been unloaded
void post_compiled_method_unload();
// Initailize fields to their default values
void init_defaults();
// Offsets
int content_offset() const { return content_begin() - header_begin(); }
int data_offset() const { return _data_offset; }
address header_end() const { return (address) header_begin() + header_size(); }
public:
// create nmethod with entry_bci
static nmethod* new_nmethod(const methodHandle& method,
@ -334,7 +239,7 @@ class nmethod : public CodeBlob {
, Handle installed_code = Handle(),
Handle speculation_log = Handle()
#endif
);
);
static nmethod* new_native_nmethod(const methodHandle& method,
int compile_id,
@ -347,13 +252,10 @@ class nmethod : public CodeBlob {
OopMapSet* oop_maps);
// accessors
Method* method() const { return _method; }
AbstractCompiler* compiler() const { return _compiler; }
// type info
bool is_nmethod() const { return true; }
bool is_java_method() const { return !method()->is_native(); }
bool is_native_method() const { return method()->is_native(); }
bool is_osr_method() const { return _entry_bci != InvocationEntryBci; }
bool is_compiled_by_c1() const;
@ -363,22 +265,17 @@ class nmethod : public CodeBlob {
// boundaries for different parts
address consts_begin () const { return header_begin() + _consts_offset ; }
address consts_end () const { return header_begin() + code_offset() ; }
address insts_begin () const { return header_begin() + code_offset() ; }
address insts_end () const { return header_begin() + _stub_offset ; }
address consts_end () const { return code_begin() ; }
address stub_begin () const { return header_begin() + _stub_offset ; }
address stub_end () const { return header_begin() + _oops_offset ; }
address exception_begin () const { return header_begin() + _exception_offset ; }
address deopt_handler_begin () const { return header_begin() + _deoptimize_offset ; }
address deopt_mh_handler_begin() const { return header_begin() + _deoptimize_mh_offset ; }
address unwind_handler_begin () const { return _unwind_handler_offset != -1 ? (header_begin() + _unwind_handler_offset) : NULL; }
oop* oops_begin () const { return (oop*) (header_begin() + _oops_offset) ; }
oop* oops_end () const { return (oop*) (header_begin() + _metadata_offset) ; }
Metadata** metadata_begin () const { return (Metadata**) (header_begin() + _metadata_offset) ; }
Metadata** metadata_end () const { return (Metadata**) (header_begin() + _scopes_data_offset) ; }
Metadata** metadata_end () const { return (Metadata**) _scopes_data_begin; }
address scopes_data_begin () const { return header_begin() + _scopes_data_offset ; }
address scopes_data_end () const { return header_begin() + _scopes_pcs_offset ; }
PcDesc* scopes_pcs_begin () const { return (PcDesc*)(header_begin() + _scopes_pcs_offset ); }
PcDesc* scopes_pcs_end () const { return (PcDesc*)(header_begin() + _dependencies_offset) ; }
@ -390,16 +287,9 @@ class nmethod : public CodeBlob {
address nul_chk_table_end () const { return header_begin() + _nmethod_end_offset ; }
// Sizes
int consts_size () const { return consts_end () - consts_begin (); }
int insts_size () const { return insts_end () - insts_begin (); }
int stub_size () const { return stub_end () - stub_begin (); }
int oops_size () const { return (address) oops_end () - (address) oops_begin (); }
int metadata_size () const { return (address) metadata_end () - (address) metadata_begin (); }
int scopes_data_size () const { return scopes_data_end () - scopes_data_begin (); }
int scopes_pcs_size () const { return (intptr_t) scopes_pcs_end () - (intptr_t) scopes_pcs_begin (); }
int dependencies_size () const { return dependencies_end () - dependencies_begin (); }
int handler_table_size() const { return handler_table_end() - handler_table_begin(); }
int nul_chk_table_size() const { return nul_chk_table_end() - nul_chk_table_begin(); }
int oops_count() const { assert(oops_size() % oopSize == 0, ""); return (oops_size() / oopSize) + 1; }
int metadata_count() const { assert(metadata_size() % wordSize == 0, ""); return (metadata_size() / wordSize) + 1; }
@ -411,15 +301,10 @@ class nmethod : public CodeBlob {
int hotness_counter() const { return _hotness_counter; }
// Containment
bool consts_contains (address addr) const { return consts_begin () <= addr && addr < consts_end (); }
bool insts_contains (address addr) const { return insts_begin () <= addr && addr < insts_end (); }
bool stub_contains (address addr) const { return stub_begin () <= addr && addr < stub_end (); }
bool oops_contains (oop* addr) const { return oops_begin () <= addr && addr < oops_end (); }
bool metadata_contains (Metadata** addr) const { return metadata_begin () <= addr && addr < metadata_end (); }
bool scopes_data_contains (address addr) const { return scopes_data_begin () <= addr && addr < scopes_data_end (); }
bool scopes_pcs_contains (PcDesc* addr) const { return scopes_pcs_begin () <= addr && addr < scopes_pcs_end (); }
bool handler_table_contains(address addr) const { return handler_table_begin() <= addr && addr < handler_table_end(); }
bool nul_chk_table_contains(address addr) const { return nul_chk_table_begin() <= addr && addr < nul_chk_table_end(); }
// entry points
address entry_point() const { return _entry_point; } // normal entry point
@ -434,24 +319,11 @@ class nmethod : public CodeBlob {
// flag accessing and manipulation
bool is_in_use() const { return _state == in_use; }
bool is_alive() const { unsigned char s = _state; return s == in_use || s == not_entrant; }
bool is_alive() const { unsigned char s = _state; return s < zombie; }
bool is_not_entrant() const { return _state == not_entrant; }
bool is_zombie() const { return _state == zombie; }
bool is_unloaded() const { return _state == unloaded; }
// returns a string version of the nmethod state
const char* state() const {
switch(_state) {
case in_use: return "in use";
case not_entrant: return "not_entrant";
case zombie: return "zombie";
case unloaded: return "unloaded";
default:
fatal("unexpected nmethod state: %d", _state);
return NULL;
}
}
#if INCLUDE_RTM_OPT
// rtm state accessing and manipulating
RTMState rtm_state() const { return _rtm_state; }
@ -466,30 +338,15 @@ class nmethod : public CodeBlob {
assert(!method()->is_method_handle_intrinsic(), "Cannot make MH intrinsic not entrant");
return make_not_entrant_or_zombie(not_entrant);
}
bool make_not_used() { return make_not_entrant(); }
bool make_zombie() { return make_not_entrant_or_zombie(zombie); }
// used by jvmti to track if the unload event has been reported
bool unload_reported() { return _unload_reported; }
void set_unload_reported() { _unload_reported = true; }
void set_unloading_next(nmethod* next) { _unloading_next = next; }
nmethod* unloading_next() { return _unloading_next; }
static unsigned char global_unloading_clock() { return _global_unloading_clock; }
static void increase_unloading_clock();
void set_unloading_clock(unsigned char unloading_clock);
unsigned char unloading_clock();
bool is_marked_for_deoptimization() const { return _mark_for_deoptimization_status != not_marked; }
void mark_for_deoptimization(bool inc_recompile_counts = true) {
_mark_for_deoptimization_status = (inc_recompile_counts ? deoptimize : deoptimize_noupdate);
}
bool update_recompile_counts() const {
// Update recompile counts when either the update is explicitly requested (deoptimize)
// or the nmethod is not marked for deoptimization at all (not_marked).
// The latter happens during uncommon traps when deoptimized nmethod is made not entrant.
return _mark_for_deoptimization_status != deoptimize_noupdate;
int get_state() const {
return _state;
}
void make_unloaded(BoolObjectClosure* is_alive, oop cause);
@ -502,18 +359,6 @@ class nmethod : public CodeBlob {
_has_flushed_dependencies = 1;
}
bool has_unsafe_access() const { return _has_unsafe_access; }
void set_has_unsafe_access(bool z) { _has_unsafe_access = z; }
bool has_method_handle_invokes() const { return _has_method_handle_invokes; }
void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; }
bool is_lazy_critical_native() const { return _lazy_critical_native; }
void set_lazy_critical_native(bool z) { _lazy_critical_native = z; }
bool has_wide_vectors() const { return _has_wide_vectors; }
void set_has_wide_vectors(bool z) { _has_wide_vectors = z; }
int comp_level() const { return _comp_level; }
// Support for oops in scopes and relocs:
@ -538,9 +383,6 @@ class nmethod : public CodeBlob {
void copy_values(GrowableArray<jobject>* oops);
void copy_values(GrowableArray<Metadata*>* metadata);
Method* attached_method(address call_pc);
Method* attached_method_before_pc(address pc);
// Relocation support
private:
void fix_oop_relocations(address begin, address end, bool initialize_immediates);
@ -549,10 +391,6 @@ private:
public:
void fix_oop_relocations(address begin, address end) { fix_oop_relocations(begin, end, false); }
void fix_oop_relocations() { fix_oop_relocations(NULL, NULL, false); }
void verify_oop_relocations();
bool is_at_poll_return(address pc);
bool is_at_poll_or_poll_return(address pc);
// Scavengable oop support
bool on_scavenge_root_list() const { return (_scavenge_root_state & 1) != 0; }
@ -576,15 +414,6 @@ public:
long stack_traversal_mark() { return _stack_traversal_mark; }
void set_stack_traversal_mark(long l) { _stack_traversal_mark = l; }
// Exception cache support
// Note: _exception_cache may be read concurrently. We rely on memory_order_consume here.
ExceptionCache* exception_cache() const { return _exception_cache; }
void set_exception_cache(ExceptionCache *ec) { _exception_cache = ec; }
void release_set_exception_cache(ExceptionCache *ec) { OrderAccess::release_store_ptr(&_exception_cache, ec); }
address handler_for_exception_and_pc(Handle exception, address pc);
void add_handler_for_exception_and_pc(Handle exception, address pc, address handler);
void clean_exception_cache(BoolObjectClosure* is_alive);
// implicit exceptions support
address continuation_for_implicit_exception(address pc);
@ -595,24 +424,8 @@ public:
nmethod* osr_link() const { return _osr_link; }
void set_osr_link(nmethod *n) { _osr_link = n; }
// tells whether frames described by this nmethod can be deoptimized
// note: native wrappers cannot be deoptimized.
bool can_be_deoptimized() const { return is_java_method(); }
// Inline cache support
void clear_inline_caches();
void clear_ic_stubs();
void cleanup_inline_caches(bool clean_all = false);
bool inlinecache_check_contains(address addr) const {
return (addr >= code_begin() && addr < verified_entry_point());
}
// Verify calls to dead methods have been cleaned.
void verify_clean_inline_caches();
// Verify and count cached icholder relocations.
int verify_icholder_relocations();
// Check that all metadata is still alive
void verify_metadata_loaders(address low_boundary, BoolObjectClosure* is_alive);
// unlink and deallocate this nmethod
// Only NMethodSweeper class is expected to use this. NMethodSweeper is not
@ -653,20 +466,19 @@ public:
public:
#endif
// GC support
void do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred);
// The parallel versions are used by G1.
bool do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_occurred);
void do_unloading_parallel_postponed(BoolObjectClosure* is_alive, bool unloading_occurred);
protected:
virtual bool do_unloading_oops(address low_boundary, BoolObjectClosure* is_alive, bool unloading_occurred);
#if INCLUDE_JVMCI
virtual bool do_unloading_jvmci(BoolObjectClosure* is_alive, bool unloading_occurred);
#endif
private:
bool do_unloading_scopes(BoolObjectClosure* is_alive, bool unloading_occurred);
// Unload a nmethod if the *root object is dead.
bool can_unload(BoolObjectClosure* is_alive, oop* root, bool unloading_occurred);
bool unload_if_dead_at(RelocIterator *iter_at_oop, BoolObjectClosure* is_alive, bool unloading_occurred);
public:
void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map,
OopClosure* f);
void oops_do(OopClosure* f) { oops_do(f, false); }
void oops_do(OopClosure* f, bool allow_zombie);
bool detect_scavenge_root_oops();
@ -678,49 +490,20 @@ public:
static bool oops_do_marking_is_active() { return _oops_do_mark_nmethods != NULL; }
bool test_oops_do_mark() { return _oops_do_mark_link != NULL; }
// ScopeDesc for an instruction
ScopeDesc* scope_desc_at(address pc);
private:
ScopeDesc* scope_desc_in(address begin, address end);
address* orig_pc_addr(const frame* fr) { return (address*) ((address)fr->unextended_sp() + _orig_pc_offset); }
PcDesc* find_pc_desc_internal(address pc, bool approximate);
PcDesc* find_pc_desc(address pc, bool approximate) {
PcDesc* desc = _pc_desc_cache.last_pc_desc();
if (desc != NULL && desc->pc_offset() == pc - code_begin()) {
return desc;
}
return find_pc_desc_internal(pc, approximate);
}
public:
// ScopeDesc retrieval operation
PcDesc* pc_desc_at(address pc) { return find_pc_desc(pc, false); }
// pc_desc_near returns the first PcDesc at or after the givne pc.
PcDesc* pc_desc_near(address pc) { return find_pc_desc(pc, true); }
public:
// copying of debugging information
void copy_scopes_pcs(PcDesc* pcs, int count);
void copy_scopes_data(address buffer, int size);
// Deopt
// Return true is the PC is one would expect if the frame is being deopted.
bool is_deopt_pc (address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); }
bool is_deopt_entry (address pc);
bool is_deopt_mh_entry(address pc) { return pc == deopt_mh_handler_begin(); }
// Accessor/mutator for the original pc of a frame before a frame was deopted.
address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); }
void set_original_pc(const frame* fr, address pc) { *orig_pc_addr(fr) = pc; }
static address get_deopt_original_pc(const frame* fr);
// MethodHandle
bool is_method_handle_return(address return_pc);
// jvmti support:
void post_compiled_method_load_event();
jmethodID get_and_cache_jmethod_id();
@ -770,7 +553,7 @@ public:
// are numbered in an independent sequence if CICountOSR is true,
// and native method wrappers are also numbered independently if
// CICountNative is true.
int compile_id() const { return _compile_id; }
virtual int compile_id() const { return _compile_id; }
const char* compile_kind() const;
// tells if any of this method's dependencies have been invalidated
@ -789,7 +572,7 @@ public:
// Fast breakpoint support. Tells if this compiled method is
// dependent on the given method. Returns true if this nmethod
// corresponds to the given method as well.
bool is_dependent_on_method(Method* dependee);
virtual bool is_dependent_on_method(Method* dependee);
// is it ok to patch at address?
bool is_patchable_at(address instr_address);
@ -807,12 +590,7 @@ public:
static int osr_entry_point_offset() { return offset_of(nmethod, _osr_entry_point); }
static int state_offset() { return offset_of(nmethod, _state); }
// RedefineClasses support. Mark metadata in nmethods as on_stack so that
// redefine classes doesn't purge it.
static void mark_on_stack(nmethod* nm) {
nm->metadata_do(Metadata::mark_on_stack);
}
void metadata_do(void f(Metadata*));
virtual void metadata_do(void f(Metadata*));
};
// Locks an nmethod so its code will not get removed and it will not
@ -821,26 +599,43 @@ public:
// needs to be done, then lock_nmethod() is used directly to keep the
// generated code from being reused too early.
class nmethodLocker : public StackObj {
nmethod* _nm;
CompiledMethod* _nm;
public:
// note: nm can be NULL
// Only JvmtiDeferredEvent::compiled_method_unload_event()
// should pass zombie_ok == true.
static void lock_nmethod(nmethod* nm, bool zombie_ok = false);
static void unlock_nmethod(nmethod* nm); // (ditto)
static void lock_nmethod(CompiledMethod* nm, bool zombie_ok = false);
static void unlock_nmethod(CompiledMethod* nm); // (ditto)
nmethodLocker(address pc); // derive nm from pc
nmethodLocker(nmethod *nm) { _nm = nm; lock_nmethod(_nm); }
nmethodLocker() { _nm = NULL; }
~nmethodLocker() { unlock_nmethod(_nm); }
nmethodLocker(CompiledMethod *nm) {
_nm = nm;
lock(_nm);
}
nmethod* code() { return _nm; }
void set_code(nmethod* new_nm) {
unlock_nmethod(_nm); // note: This works even if _nm==new_nm.
static void lock(CompiledMethod* method) {
if (method == NULL) return;
lock_nmethod(method);
}
static void unlock(CompiledMethod* method) {
if (method == NULL) return;
unlock_nmethod(method);
}
nmethodLocker() { _nm = NULL; }
~nmethodLocker() {
unlock(_nm);
}
CompiledMethod* code() { return _nm; }
void set_code(CompiledMethod* new_nm) {
unlock(_nm); // note: This works even if _nm==new_nm.
_nm = new_nm;
lock_nmethod(_nm);
lock(_nm);
}
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -36,11 +36,11 @@ PcDesc::PcDesc(int pc_offset, int scope_decode_offset, int obj_decode_offset) {
_flags = 0;
}
address PcDesc::real_pc(const nmethod* code) const {
address PcDesc::real_pc(const CompiledMethod* code) const {
return code->code_begin() + pc_offset();
}
void PcDesc::print(nmethod* code) {
void PcDesc::print(CompiledMethod* code) {
#ifndef PRODUCT
ResourceMark rm;
tty->print_cr("PcDesc(pc=" PTR_FORMAT " offset=%x bits=%x):", p2i(real_pc(code)), pc_offset(), _flags);
@ -57,7 +57,7 @@ void PcDesc::print(nmethod* code) {
#endif
}
bool PcDesc::verify(nmethod* code) {
bool PcDesc::verify(CompiledMethod* code) {
//Unimplemented();
return true;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -30,7 +30,7 @@
// PcDescs map a physical PC (given as offset from start of nmethod) to
// the corresponding source scope and byte code index.
class nmethod;
class CompiledMethod;
class PcDesc VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
@ -91,10 +91,10 @@ class PcDesc VALUE_OBJ_CLASS_SPEC {
void set_return_oop(bool z) { set_flag(PCDESC_return_oop, z); }
// Returns the real pc
address real_pc(const nmethod* code) const;
address real_pc(const CompiledMethod* code) const;
void print(nmethod* code);
bool verify(nmethod* code);
void print(CompiledMethod* code);
bool verify(CompiledMethod* code);
};
#endif // SHARE_VM_CODE_PCDESC_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -81,7 +81,6 @@ relocInfo* relocInfo::finish_prefix(short* prefix_limit) {
return (relocInfo*)prefix_limit;
}
void relocInfo::set_type(relocType t) {
int old_offset = addr_offset();
int old_format = format();
@ -91,6 +90,9 @@ void relocInfo::set_type(relocType t) {
assert(format()==old_format, "sanity check");
}
nmethod* RelocIterator::code_as_nmethod() const {
return _code->as_nmethod();
}
void relocInfo::set_format(int f) {
int old_offset = addr_offset();
@ -121,13 +123,13 @@ void relocInfo::remove_reloc_info_for_address(RelocIterator *itr, address pc, re
// ----------------------------------------------------------------------------------------------------
// Implementation of RelocIterator
void RelocIterator::initialize(nmethod* nm, address begin, address limit) {
void RelocIterator::initialize(CompiledMethod* nm, address begin, address limit) {
initialize_misc();
if (nm == NULL && begin != NULL) {
// allow nmethod to be deduced from beginning address
CodeBlob* cb = CodeCache::find_blob(begin);
nm = cb->as_nmethod_or_null();
nm = cb->as_compiled_method_or_null();
}
assert(nm != NULL, "must be able to deduce nmethod from other arguments");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -28,6 +28,8 @@
#include "memory/allocation.hpp"
#include "runtime/os.hpp"
class nmethod;
class CompiledMethod;
class Metadata;
class NativeMovConstReg;
@ -539,7 +541,7 @@ class RelocIterator : public StackObj {
address _limit; // stop producing relocations after this _addr
relocInfo* _current; // the current relocation information
relocInfo* _end; // end marker; we're done iterating when _current == _end
nmethod* _code; // compiled method containing _addr
CompiledMethod* _code; // compiled method containing _addr
address _addr; // instruction to which the relocation applies
short _databuf; // spare buffer for compressed data
short* _data; // pointer to the relocation's data
@ -570,13 +572,13 @@ class RelocIterator : public StackObj {
void initialize_misc();
void initialize(nmethod* nm, address begin, address limit);
void initialize(CompiledMethod* nm, address begin, address limit);
RelocIterator() { initialize_misc(); }
public:
// constructor
RelocIterator(nmethod* nm, address begin = NULL, address limit = NULL);
RelocIterator(CompiledMethod* nm, address begin = NULL, address limit = NULL);
RelocIterator(CodeSection* cb, address begin = NULL, address limit = NULL);
// get next reloc info, return !eos
@ -611,7 +613,8 @@ class RelocIterator : public StackObj {
relocType type() const { return current()->type(); }
int format() const { return (relocInfo::have_format) ? current()->format() : 0; }
address addr() const { return _addr; }
nmethod* code() const { return _code; }
CompiledMethod* code() const { return _code; }
nmethod* code_as_nmethod() const;
short* data() const { return _data; }
int datalen() const { return _datalen; }
bool has_current() const { return _datalen >= 0; }
@ -810,9 +813,10 @@ class Relocation VALUE_OBJ_CLASS_SPEC {
public:
// accessors which only make sense for a bound Relocation
address addr() const { return binding()->addr(); }
nmethod* code() const { return binding()->code(); }
bool addr_in_const() const { return binding()->addr_in_const(); }
address addr() const { return binding()->addr(); }
CompiledMethod* code() const { return binding()->code(); }
nmethod* code_as_nmethod() const { return binding()->code_as_nmethod(); }
bool addr_in_const() const { return binding()->addr_in_const(); }
protected:
short* data() const { return binding()->data(); }
int datalen() const { return binding()->datalen(); }
@ -1371,7 +1375,7 @@ inline name##_Relocation* RelocIterator::name##_reloc() { \
APPLY_TO_RELOCATIONS(EACH_CASE);
#undef EACH_CASE
inline RelocIterator::RelocIterator(nmethod* nm, address begin, address limit) {
inline RelocIterator::RelocIterator(CompiledMethod* nm, address begin, address limit) {
initialize(nm, begin, limit);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -30,7 +30,7 @@
#include "oops/oop.inline.hpp"
#include "runtime/handles.inline.hpp"
ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop) {
ScopeDesc::ScopeDesc(const CompiledMethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop) {
_code = code;
_decode_offset = decode_offset;
_objects = decode_object_values(obj_decode_offset);
@ -40,7 +40,7 @@ ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offs
decode_body();
}
ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop) {
ScopeDesc::ScopeDesc(const CompiledMethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop) {
_code = code;
_decode_offset = decode_offset;
_objects = decode_object_values(DebugInformationRecorder::serialized_null);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -41,7 +41,7 @@ class SimpleScopeDesc : public StackObj {
int _bci;
public:
SimpleScopeDesc(nmethod* code, address pc) {
SimpleScopeDesc(CompiledMethod* code, address pc) {
PcDesc* pc_desc = code->pc_desc_at(pc);
assert(pc_desc != NULL, "Must be able to find matching PcDesc");
DebugInfoReadStream buffer(code, pc_desc->scope_decode_offset());
@ -60,12 +60,12 @@ class SimpleScopeDesc : public StackObj {
class ScopeDesc : public ResourceObj {
public:
// Constructor
ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop);
ScopeDesc(const CompiledMethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop);
// Calls above, giving default value of "serialized_null" to the
// "obj_decode_offset" argument. (We don't use a default argument to
// avoid a .hpp-.hpp dependency.)
ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop);
ScopeDesc(const CompiledMethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop);
// JVM state
Method* method() const { return _method; }
@ -110,7 +110,7 @@ class ScopeDesc : public ResourceObj {
GrowableArray<ScopeValue*>* _objects;
// Nmethod information
const nmethod* _code;
const CompiledMethod* _code;
// Decoding operations
void decode_body();

View File

@ -1075,10 +1075,10 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
if (osr_bci == InvocationEntryBci) {
// standard compilation
nmethod* method_code = method->code();
if (method_code != NULL) {
CompiledMethod* method_code = method->code();
if (method_code != NULL && method_code->is_nmethod()) {
if (compilation_is_complete(method, osr_bci, comp_level)) {
return method_code;
return (nmethod*) method_code;
}
}
if (method->is_not_compilable(comp_level)) {
@ -1184,7 +1184,12 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
// return requested nmethod
// We accept a higher level osr method
if (osr_bci == InvocationEntryBci) {
return method->code();
CompiledMethod* code = method->code();
if (code == NULL) {
return (nmethod*) code;
} else {
return code->as_nmethod_or_null();
}
}
return method->lookup_osr_nmethod_for(osr_bci, comp_level, false);
}
@ -1209,7 +1214,7 @@ bool CompileBroker::compilation_is_complete(const methodHandle& method,
if (method->is_not_compilable(comp_level)) {
return true;
} else {
nmethod* result = method->code();
CompiledMethod* result = method->code();
if (result == NULL) return false;
return comp_level == result->comp_level();
}

View File

@ -135,7 +135,11 @@ AbstractCompiler* CompileTask::compiler() {
//
nmethod* CompileTask::code() const {
if (_code_handle == NULL) return NULL;
return _code_handle->code();
CodeBlob *blob = _code_handle->code();
if (blob != NULL) {
return blob->as_nmethod();
}
return NULL;
}
void CompileTask::set_code(nmethod* nm) {

View File

@ -3776,12 +3776,12 @@ private:
const uint _num_workers;
// Variables used to claim nmethods.
nmethod* _first_nmethod;
volatile nmethod* _claimed_nmethod;
CompiledMethod* _first_nmethod;
volatile CompiledMethod* _claimed_nmethod;
// The list of nmethods that need to be processed by the second pass.
volatile nmethod* _postponed_list;
volatile uint _num_entered_barrier;
volatile CompiledMethod* _postponed_list;
volatile uint _num_entered_barrier;
public:
G1CodeCacheUnloadingTask(uint num_workers, BoolObjectClosure* is_alive, bool unloading_occurred) :
@ -3793,13 +3793,13 @@ private:
_postponed_list(NULL),
_num_entered_barrier(0)
{
nmethod::increase_unloading_clock();
CompiledMethod::increase_unloading_clock();
// Get first alive nmethod
NMethodIterator iter = NMethodIterator();
CompiledMethodIterator iter = CompiledMethodIterator();
if(iter.next_alive()) {
_first_nmethod = iter.method();
}
_claimed_nmethod = (volatile nmethod*)_first_nmethod;
_claimed_nmethod = (volatile CompiledMethod*)_first_nmethod;
}
~G1CodeCacheUnloadingTask() {
@ -3812,15 +3812,15 @@ private:
}
private:
void add_to_postponed_list(nmethod* nm) {
nmethod* old;
void add_to_postponed_list(CompiledMethod* nm) {
CompiledMethod* old;
do {
old = (nmethod*)_postponed_list;
old = (CompiledMethod*)_postponed_list;
nm->set_unloading_next(old);
} while ((nmethod*)Atomic::cmpxchg_ptr(nm, &_postponed_list, old) != old);
} while ((CompiledMethod*)Atomic::cmpxchg_ptr(nm, &_postponed_list, old) != old);
}
void clean_nmethod(nmethod* nm) {
void clean_nmethod(CompiledMethod* nm) {
bool postponed = nm->do_unloading_parallel(_is_alive, _unloading_occurred);
if (postponed) {
@ -3830,24 +3830,24 @@ private:
// Mark that this thread has been cleaned/unloaded.
// After this call, it will be safe to ask if this nmethod was unloaded or not.
nm->set_unloading_clock(nmethod::global_unloading_clock());
nm->set_unloading_clock(CompiledMethod::global_unloading_clock());
}
void clean_nmethod_postponed(nmethod* nm) {
void clean_nmethod_postponed(CompiledMethod* nm) {
nm->do_unloading_parallel_postponed(_is_alive, _unloading_occurred);
}
static const int MaxClaimNmethods = 16;
void claim_nmethods(nmethod** claimed_nmethods, int *num_claimed_nmethods) {
nmethod* first;
NMethodIterator last;
void claim_nmethods(CompiledMethod** claimed_nmethods, int *num_claimed_nmethods) {
CompiledMethod* first;
CompiledMethodIterator last;
do {
*num_claimed_nmethods = 0;
first = (nmethod*)_claimed_nmethod;
last = NMethodIterator(first);
first = (CompiledMethod*)_claimed_nmethod;
last = CompiledMethodIterator(first);
if (first != NULL) {
@ -3860,22 +3860,22 @@ private:
}
}
} while ((nmethod*)Atomic::cmpxchg_ptr(last.method(), &_claimed_nmethod, first) != first);
} while ((CompiledMethod*)Atomic::cmpxchg_ptr(last.method(), &_claimed_nmethod, first) != first);
}
nmethod* claim_postponed_nmethod() {
nmethod* claim;
nmethod* next;
CompiledMethod* claim_postponed_nmethod() {
CompiledMethod* claim;
CompiledMethod* next;
do {
claim = (nmethod*)_postponed_list;
claim = (CompiledMethod*)_postponed_list;
if (claim == NULL) {
return NULL;
}
next = claim->unloading_next();
} while ((nmethod*)Atomic::cmpxchg_ptr(next, &_postponed_list, claim) != claim);
} while ((CompiledMethod*)Atomic::cmpxchg_ptr(next, &_postponed_list, claim) != claim);
return claim;
}
@ -3911,7 +3911,7 @@ private:
}
int num_claimed_nmethods;
nmethod* claimed_nmethods[MaxClaimNmethods];
CompiledMethod* claimed_nmethods[MaxClaimNmethods];
while (true) {
claim_nmethods(claimed_nmethods, &num_claimed_nmethods);
@ -3927,7 +3927,7 @@ private:
}
void work_second_pass(uint worker_id) {
nmethod* nm;
CompiledMethod* nm;
// Take care of postponed nmethods.
while ((nm = claim_postponed_nmethod()) != NULL) {
clean_nmethod_postponed(nm);

View File

@ -992,7 +992,7 @@ C2V_VMENTRY(void, reprofile, (JNIEnv*, jobject, jobject jvmci_method))
}
NOT_PRODUCT(method->set_compiled_invocation_count(0));
nmethod* code = method->code();
CompiledMethod* code = method->code();
if (code != NULL) {
code->make_not_entrant();
}

View File

@ -546,7 +546,7 @@ JVMCIEnv::CodeInstallResult JVMCIEnv::register_method(
if (entry_bci == InvocationEntryBci) {
if (TieredCompilation) {
// If there is an old version we're done with it
nmethod* old = method->code();
CompiledMethod* old = method->code();
if (TraceMethodReplacement && old != NULL) {
ResourceMark rm;
char *method_name = method->name_and_sig_as_C_string();

View File

@ -220,15 +220,15 @@ extern void vm_exit(int code);
// been deoptimized. If that is the case we return the deopt blob
// unpack_with_exception entry instead. This makes life for the exception blob easier
// because making that same check and diverting is painful from assembly language.
JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* thread, oopDesc* ex, address pc, nmethod*& nm))
JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* thread, oopDesc* ex, address pc, CompiledMethod*& cm))
// Reset method handle flag.
thread->set_is_method_handle_return(false);
Handle exception(thread, ex);
nm = CodeCache::find_nmethod(pc);
assert(nm != NULL, "this is not a compiled method");
cm = CodeCache::find_compiled(pc);
assert(cm != NULL, "this is not a compiled method");
// Adjust the pc as needed/
if (nm->is_deopt_pc(pc)) {
if (cm->is_deopt_pc(pc)) {
RegisterMap map(thread, false);
frame exception_frame = thread->last_frame().sender(&map);
// if the frame isn't deopted then pc must not correspond to the caller of last_frame
@ -275,10 +275,10 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
// ExceptionCache is used only for exceptions at call sites and not for implicit exceptions
if (guard_pages_enabled) {
address fast_continuation = nm->handler_for_exception_and_pc(exception, pc);
address fast_continuation = cm->handler_for_exception_and_pc(exception, pc);
if (fast_continuation != NULL) {
// Set flag if return address is a method handle call site.
thread->set_is_method_handle_return(nm->is_method_handle_return(pc));
thread->set_is_method_handle_return(cm->is_method_handle_return(pc));
return fast_continuation;
}
}
@ -299,7 +299,7 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
stringStream tempst;
tempst.print("compiled method <%s>\n"
" at PC" INTPTR_FORMAT " for thread " INTPTR_FORMAT,
nm->method()->print_value_string(), p2i(pc), p2i(thread));
cm->method()->print_value_string(), p2i(pc), p2i(thread));
Exceptions::log_exception(exception, tempst);
}
// for AbortVMOnException flag
@ -311,19 +311,19 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
// normal bytecode execution.
thread->clear_exception_oop_and_pc();
continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false);
continuation = SharedRuntime::compute_compiled_exc_handler(cm, pc, exception, false, false);
// If an exception was thrown during exception dispatch, the exception oop may have changed
thread->set_exception_oop(exception());
thread->set_exception_pc(pc);
// the exception cache is used only by non-implicit exceptions
if (continuation != NULL && !SharedRuntime::deopt_blob()->contains(continuation)) {
nm->add_handler_for_exception_and_pc(exception, pc, continuation);
cm->add_handler_for_exception_and_pc(exception, pc, continuation);
}
}
// Set flag if return address is a method handle call site.
thread->set_is_method_handle_return(nm->is_method_handle_return(pc));
thread->set_is_method_handle_return(cm->is_method_handle_return(pc));
if (log_is_enabled(Info, exceptions)) {
ResourceMark rm;
@ -345,18 +345,18 @@ address JVMCIRuntime::exception_handler_for_pc(JavaThread* thread) {
address pc = thread->exception_pc();
// Still in Java mode
DEBUG_ONLY(ResetNoHandleMark rnhm);
nmethod* nm = NULL;
CompiledMethod* cm = NULL;
address continuation = NULL;
{
// Enter VM mode by calling the helper
ResetNoHandleMark rnhm;
continuation = exception_handler_for_pc_helper(thread, exception, pc, nm);
continuation = exception_handler_for_pc_helper(thread, exception, pc, cm);
}
// Back in JAVA, use no oops DON'T safepoint
// Now check to see if the compiled method we were called from is now deoptimized.
// If so we must return to the deopt blob and deoptimize the nmethod
if (nm != NULL && caller_is_deopted()) {
if (cm != NULL && caller_is_deopted()) {
continuation = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
}

View File

@ -186,7 +186,7 @@
nonstatic_field(Method, _vtable_index, int) \
nonstatic_field(Method, _intrinsic_id, u2) \
nonstatic_field(Method, _flags, u2) \
volatile_nonstatic_field(Method, _code, nmethod*) \
volatile_nonstatic_field(Method, _code, CompiledMethod*) \
volatile_nonstatic_field(Method, _from_compiled_entry, address) \
\
nonstatic_field(MethodCounters, _invocation_counter, InvocationCounter) \

View File

@ -746,7 +746,7 @@ void Method::set_native_function(address function, bool post_event_flag) {
// This function can be called more than once. We must make sure that we always
// use the latest registered method -> check if a stub already has been generated.
// If so, we have to make it not_entrant.
nmethod* nm = code(); // Put it into local variable to guard against concurrent updates
CompiledMethod* nm = code(); // Put it into local variable to guard against concurrent updates
if (nm != NULL) {
nm->make_not_entrant();
}
@ -1046,12 +1046,12 @@ address Method::verified_code_entry() {
// Not inline to avoid circular ref.
bool Method::check_code() const {
// cached in a register or local. There's a race on the value of the field.
nmethod *code = (nmethod *)OrderAccess::load_ptr_acquire(&_code);
CompiledMethod *code = (CompiledMethod *)OrderAccess::load_ptr_acquire(&_code);
return code == NULL || (code->method() == NULL) || (code->method() == (Method*)this && !code->is_osr_method());
}
// Install compiled code. Instantly it can execute.
void Method::set_code(methodHandle mh, nmethod *code) {
void Method::set_code(methodHandle mh, CompiledMethod *code) {
assert( code, "use clear_code to remove code" );
assert( mh->check_code(), "" );

View File

@ -58,6 +58,7 @@ class MethodCounters;
class ConstMethod;
class InlineTableSizes;
class KlassSizeStats;
class CompiledMethod;
class Method : public Metadata {
friend class VMStructs;
@ -101,7 +102,7 @@ class Method : public Metadata {
// field can come and go. It can transition from NULL to not-null at any
// time (whenever a compile completes). It can transition from not-null to
// NULL only at safepoints (because of a de-opt).
nmethod* volatile _code; // Points to the corresponding piece of native code
CompiledMethod* volatile _code; // Points to the corresponding piece of native code
volatile address _from_interpreted_entry; // Cache of _code ? _adapter->i2c_entry() : _i2i_entry
// Constructor
@ -431,9 +432,9 @@ class Method : public Metadata {
// nmethod/verified compiler entry
address verified_code_entry();
bool check_code() const; // Not inline to avoid circular ref
nmethod* volatile code() const { assert( check_code(), "" ); return (nmethod *)OrderAccess::load_ptr_acquire(&_code); }
CompiledMethod* volatile code() const { assert( check_code(), "" ); return (CompiledMethod *)OrderAccess::load_ptr_acquire(&_code); }
void clear_code(); // Clear out any compiled code
static void set_code(methodHandle mh, nmethod* code);
static void set_code(methodHandle mh, CompiledMethod* code);
void set_adapter_entry(AdapterHandlerEntry* adapter) {
constMethod()->set_adapter_entry(adapter);
}

View File

@ -565,7 +565,7 @@ uint Compile::scratch_emit_size(const Node* n) {
relocInfo* locs_buf = scratch_locs_memory();
address blob_begin = blob->content_begin();
address blob_end = (address)locs_buf;
assert(blob->content_contains(blob_end), "sanity");
assert(blob->contains(blob_end), "sanity");
CodeBuffer buf(blob_begin, blob_end - blob_begin);
buf.initialize_consts_size(_scratch_const_size);
buf.initialize_stubs_size(MAX_stubs_size);

View File

@ -1663,9 +1663,9 @@ static void trace_exception(outputStream* st, oop exception_oop, address excepti
exception_oop->print_value_on(&tempst);
tempst.print(" in ");
CodeBlob* blob = CodeCache::find_blob(exception_pc);
if (blob->is_nmethod()) {
nmethod* nm = blob->as_nmethod_or_null();
nm->method()->print_value_on(&tempst);
if (blob->is_compiled()) {
CompiledMethod* cm = blob->as_compiled_method_or_null();
cm->method()->print_value_on(&tempst);
} else if (blob->is_runtime_stub()) {
tempst.print("<runtime-stub>");
} else {

View File

@ -483,9 +483,9 @@ class VM_WhiteBoxDeoptimizeFrames : public VM_WhiteBoxOperation {
RegisterMap* reg_map = fst.register_map();
Deoptimization::deoptimize(t, *f, reg_map);
if (_make_not_entrant) {
nmethod* nm = CodeCache::find_nmethod(f->pc());
assert(nm != NULL, "sanity check");
nm->make_not_entrant();
CompiledMethod* cm = CodeCache::find_compiled(f->pc());
assert(cm != NULL, "sanity check");
cm->make_not_entrant();
}
++_result;
}
@ -533,7 +533,7 @@ WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method, j
CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
MutexLockerEx mu(Compile_lock);
methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code();
CompiledMethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code();
if (code == NULL) {
return JNI_FALSE;
}
@ -589,7 +589,7 @@ WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject meth
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
CHECK_JNI_EXCEPTION_(env, CompLevel_none);
methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code();
CompiledMethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code();
return (code != NULL ? code->comp_level() : CompLevel_none);
WB_END
@ -608,7 +608,7 @@ WB_ENTRY(jint, WB_GetMethodEntryBci(JNIEnv* env, jobject o, jobject method))
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
CHECK_JNI_EXCEPTION_(env, InvocationEntryBci);
methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
nmethod* code = mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false);
CompiledMethod* code = mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false);
return (code != NULL && code->is_osr_method() ? code->osr_entry_bci() : InvocationEntryBci);
WB_END
@ -1093,7 +1093,7 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
CHECK_JNI_EXCEPTION_(env, NULL);
methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code();
CompiledMethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code();
jobjectArray result = NULL;
if (code == NULL) {
return result;

View File

@ -496,7 +496,7 @@ void AdvancedThresholdPolicy::submit_compile(const methodHandle& mh, int bci, Co
// Handle the invocation event.
void AdvancedThresholdPolicy::method_invocation_event(const methodHandle& mh, const methodHandle& imh,
CompLevel level, nmethod* nm, JavaThread* thread) {
CompLevel level, CompiledMethod* nm, JavaThread* thread) {
if (should_create_mdo(mh(), level)) {
create_mdo(mh, thread);
}
@ -511,7 +511,7 @@ void AdvancedThresholdPolicy::method_invocation_event(const methodHandle& mh, co
// Handle the back branch event. Notice that we can compile the method
// with a regular entry from here.
void AdvancedThresholdPolicy::method_back_branch_event(const methodHandle& mh, const methodHandle& imh,
int bci, CompLevel level, nmethod* nm, JavaThread* thread) {
int bci, CompLevel level, CompiledMethod* nm, JavaThread* thread) {
if (should_create_mdo(mh(), level)) {
create_mdo(mh, thread);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 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
@ -216,9 +216,9 @@ protected:
virtual void submit_compile(const methodHandle& mh, int bci, CompLevel level, JavaThread* thread);
// event() from SimpleThresholdPolicy would call these.
virtual void method_invocation_event(const methodHandle& method, const methodHandle& inlinee,
CompLevel level, nmethod* nm, JavaThread* thread);
CompLevel level, CompiledMethod* nm, JavaThread* thread);
virtual void method_back_branch_event(const methodHandle& method, const methodHandle& inlinee,
int bci, CompLevel level, nmethod* nm, JavaThread* thread);
int bci, CompLevel level, CompiledMethod* nm, JavaThread* thread);
public:
AdvancedThresholdPolicy() : _start_time(0) { }
// Select task is called by CompileBroker. We should return a task or NULL.

View File

@ -379,7 +379,7 @@ bool NonTieredCompPolicy::is_mature(Method* method) {
}
nmethod* NonTieredCompPolicy::event(const methodHandle& method, const methodHandle& inlinee, int branch_bci,
int bci, CompLevel comp_level, nmethod* nm, JavaThread* thread) {
int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) {
assert(comp_level == CompLevel_none, "This should be only called from the interpreter");
NOT_PRODUCT(trace_frequency_counter_overflow(method, branch_bci, bci));
if (JvmtiExport::can_post_interpreter_events() && thread->is_interp_only_mode()) {
@ -484,7 +484,7 @@ void SimpleCompPolicy::method_invocation_event(const methodHandle& m, JavaThread
const char* comment = "count";
if (is_compilation_enabled() && can_be_compiled(m, comp_level)) {
nmethod* nm = m->code();
CompiledMethod* nm = m->code();
if (nm == NULL ) {
CompileBroker::compile_method(m, InvocationEntryBci, comp_level, m, hot_count, comment, thread);
}
@ -713,7 +713,7 @@ const char* StackWalkCompPolicy::shouldNotInline(const methodHandle& m) {
// note: we allow ik->is_abstract()
if (!m->method_holder()->is_initialized()) return (_msg = "method holder not initialized");
if (m->is_native()) return (_msg = "native method");
nmethod* m_code = m->code();
CompiledMethod* m_code = m->code();
if (m_code != NULL && m_code->code_size() > InlineSmallCode)
return (_msg = "already compiled into a big method");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 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
@ -68,7 +68,7 @@ public:
virtual int compiler_count(CompLevel comp_level) = 0;
// main notification entry, return a pointer to an nmethod if the OSR is required,
// returns NULL otherwise.
virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, nmethod* nm, JavaThread* thread) = 0;
virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) = 0;
// safepoint() is called at the end of the safepoint
virtual void do_safepoint_work() = 0;
// reprofile request
@ -109,7 +109,7 @@ public:
virtual bool is_mature(Method* method);
virtual void initialize();
virtual CompileTask* select_task(CompileQueue* compile_queue);
virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, nmethod* nm, JavaThread* thread);
virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread);
virtual void method_invocation_event(const methodHandle& m, JavaThread* thread) = 0;
virtual void method_back_branch_event(const methodHandle& m, int bci, JavaThread* thread) = 0;
};

View File

@ -168,9 +168,10 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
// Now get the deoptee with a valid map
frame deoptee = stub_frame.sender(&map);
// Set the deoptee nmethod
assert(thread->deopt_nmethod() == NULL, "Pending deopt!");
thread->set_deopt_nmethod(deoptee.cb()->as_nmethod_or_null());
bool skip_internal = thread->deopt_nmethod() != NULL && !thread->deopt_nmethod()->compiler()->is_jvmci();
assert(thread->deopt_compiled_method() == NULL, "Pending deopt!");
CompiledMethod* cm = deoptee.cb()->as_compiled_method_or_null();
thread->set_deopt_compiled_method(cm);
bool skip_internal = (cm != NULL) && !cm->is_compiled_by_jvmci();
if (VerifyStack) {
thread->validate_frame_layout();
@ -548,7 +549,7 @@ void Deoptimization::cleanup_deopt_info(JavaThread *thread,
delete thread->deopt_mark();
thread->set_deopt_mark(NULL);
thread->set_deopt_nmethod(NULL);
thread->set_deopt_compiled_method(NULL);
if (JvmtiExport::can_pop_frame()) {
@ -1292,14 +1293,14 @@ void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deopt
gather_statistics(reason, Action_none, Bytecodes::_illegal);
if (LogCompilation && xtty != NULL) {
nmethod* nm = fr.cb()->as_nmethod_or_null();
assert(nm != NULL, "only compiled methods can deopt");
CompiledMethod* cm = fr.cb()->as_compiled_method_or_null();
assert(cm != NULL, "only compiled methods can deopt");
ttyLocker ttyl;
xtty->begin_head("deoptimized thread='" UINTX_FORMAT "'", (uintx)thread->osthread()->thread_id());
nm->log_identity(xtty);
cm->log_identity(xtty);
xtty->end_head();
for (ScopeDesc* sd = nm->scope_desc_at(fr.pc()); ; sd = sd->sender()) {
for (ScopeDesc* sd = cm->scope_desc_at(fr.pc()); ; sd = sd->sender()) {
xtty->begin_elem("jvms bci='%d'", sd->bci());
xtty->method(sd->method());
xtty->end_elem();
@ -1480,7 +1481,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
vframe* vf = vframe::new_vframe(&fr, &reg_map, thread);
compiledVFrame* cvf = compiledVFrame::cast(vf);
nmethod* nm = cvf->code();
CompiledMethod* nm = cvf->code();
ScopeDesc* trap_scope = cvf->scope();
@ -1499,7 +1500,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
oop speculation = thread->pending_failed_speculation();
if (nm->is_compiled_by_jvmci()) {
if (speculation != NULL) {
oop speculation_log = nm->speculation_log();
oop speculation_log = nm->as_nmethod()->speculation_log();
if (speculation_log != NULL) {
if (TraceDeoptimization || TraceUncollectedSpeculations) {
if (HotSpotSpeculationLog::lastFailed(speculation_log) != NULL) {
@ -1615,19 +1616,21 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
nm->method()->print_short_name(tty);
tty->print(" compiler=%s compile_id=%d", nm->compiler() == NULL ? "" : nm->compiler()->name(), nm->compile_id());
#if INCLUDE_JVMCI
oop installedCode = nm->jvmci_installed_code();
if (installedCode != NULL) {
oop installedCodeName = NULL;
if (installedCode->is_a(InstalledCode::klass())) {
installedCodeName = InstalledCode::name(installedCode);
if (nm->is_nmethod()) {
oop installedCode = nm->as_nmethod()->jvmci_installed_code();
if (installedCode != NULL) {
oop installedCodeName = NULL;
if (installedCode->is_a(InstalledCode::klass())) {
installedCodeName = InstalledCode::name(installedCode);
}
if (installedCodeName != NULL) {
tty->print(" (JVMCI: installedCodeName=%s) ", java_lang_String::as_utf8_string(installedCodeName));
} else {
tty->print(" (JVMCI: installed code has no name) ");
}
} else if (nm->is_compiled_by_jvmci()) {
tty->print(" (JVMCI: no installed code) ");
}
if (installedCodeName != NULL) {
tty->print(" (JVMCI: installedCodeName=%s) ", java_lang_String::as_utf8_string(installedCodeName));
} else {
tty->print(" (JVMCI: installed code has no name) ");
}
} else if (nm->is_compiled_by_jvmci()) {
tty->print(" (JVMCI: no installed code) ");
}
#endif
tty->print(" (@" INTPTR_FORMAT ") thread=" UINTX_FORMAT " reason=%s action=%s unloaded_class_index=%d" JVMCI_ONLY(" debug_id=%d"),
@ -1867,7 +1870,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
// Assume that in new recompiled code the statistic could be different,
// for example, due to different inlining.
if ((reason != Reason_rtm_state_change) && (trap_mdo != NULL) &&
UseRTMDeopt && (nm->rtm_state() != ProfileRTM)) {
UseRTMDeopt && (nm->as_nmethod()->rtm_state() != ProfileRTM)) {
trap_mdo->atomic_set_rtm_state(ProfileRTM);
}
#endif

View File

@ -538,11 +538,12 @@ class adapterNode : public ProfilerNode {
class runtimeStubNode : public ProfilerNode {
private:
const CodeBlob* _stub;
const RuntimeStub* _stub;
const char* _symbol; // The name of the nearest VM symbol when ProfileVM is on. Points to a unique string.
public:
runtimeStubNode(const CodeBlob* stub, const char* name, TickPosition where) : ProfilerNode(), _stub(stub), _symbol(name) {
runtimeStubNode(const CodeBlob* stub, const char* name, TickPosition where) : ProfilerNode(), _stub(NULL), _symbol(name) {
assert(stub->is_runtime_stub(), "wrong code blob");
_stub = (RuntimeStub*) stub;
update(where);
}
@ -550,7 +551,7 @@ class runtimeStubNode : public ProfilerNode {
bool runtimeStub_match(const CodeBlob* stub, const char* name) const {
assert(stub->is_runtime_stub(), "wrong code blob");
return ((RuntimeStub*)_stub)->entry_point() == ((RuntimeStub*)stub)->entry_point() &&
return _stub->entry_point() == ((RuntimeStub*)stub)->entry_point() &&
(_symbol == name);
}
@ -571,7 +572,7 @@ class runtimeStubNode : public ProfilerNode {
}
void print_method_on(outputStream* st) {
st->print("%s", ((RuntimeStub*)_stub)->name());
st->print("%s", _stub->name());
print_symbol_on(st);
}
@ -588,18 +589,18 @@ class unknown_compiledNode : public ProfilerNode {
public:
unknown_compiledNode(const CodeBlob* cb, TickPosition where) : ProfilerNode() {
if ( cb->is_buffer_blob() )
_name = ((BufferBlob*)cb)->name();
_name = ((const BufferBlob*)cb)->name();
else
_name = ((SingletonBlob*)cb)->name();
_name = ((const SingletonBlob*)cb)->name();
update(where);
}
bool is_compiled() const { return true; }
bool unknown_compiled_match(const CodeBlob* cb) const {
if ( cb->is_buffer_blob() )
return !strcmp(((BufferBlob*)cb)->name(), _name);
return !strcmp(((const BufferBlob*)cb)->name(), _name);
else
return !strcmp(((SingletonBlob*)cb)->name(), _name);
return !strcmp(((const SingletonBlob*)cb)->name(), _name);
}
Method* method() { return NULL; }
@ -993,16 +994,15 @@ void ThreadProfiler::record_compiled_tick(JavaThread* thread, frame fr, TickPosi
CodeBlob* cb = fr.cb();
// For runtime stubs, record as native rather than as compiled
if (cb->is_runtime_stub()) {
RegisterMap map(thread, false);
fr = fr.sender(&map);
cb = fr.cb();
localwhere = tp_native;
}
Method* method = (cb->is_nmethod()) ? ((nmethod *)cb)->method() :
(Method*)NULL;
// For runtime stubs, record as native rather than as compiled
if (cb->is_runtime_stub()) {
RegisterMap map(thread, false);
fr = fr.sender(&map);
cb = fr.cb();
localwhere = tp_native;
}
Method* method = cb->is_compiled() ? cb->as_compiled_method()->method() : (Method*) NULL;
if (method == NULL) {
if (cb->is_runtime_stub())
runtime_stub_update(cb, name, localwhere);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -132,11 +132,11 @@ void RegisterMap::print() const {
address frame::raw_pc() const {
if (is_deoptimized_frame()) {
nmethod* nm = cb()->as_nmethod_or_null();
if (nm->is_method_handle_return(pc()))
return nm->deopt_mh_handler_begin() - pc_return_offset;
CompiledMethod* cm = cb()->as_compiled_method_or_null();
if (cm->is_method_handle_return(pc()))
return cm->deopt_mh_handler_begin() - pc_return_offset;
else
return nm->deopt_handler_begin() - pc_return_offset;
return cm->deopt_handler_begin() - pc_return_offset;
} else {
return (pc() - pc_return_offset);
}
@ -183,8 +183,8 @@ bool frame::is_java_frame() const {
bool frame::is_compiled_frame() const {
if (_cb != NULL &&
_cb->is_nmethod() &&
((nmethod*)_cb)->is_java_method()) {
_cb->is_compiled() &&
((CompiledMethod*)_cb)->is_java_method()) {
return true;
}
return false;
@ -228,8 +228,8 @@ JavaCallWrapper* frame::entry_frame_call_wrapper_if_safe(JavaThread* thread) con
bool frame::should_be_deoptimized() const {
if (_deopt_state == is_deoptimized ||
!is_compiled_frame() ) return false;
assert(_cb != NULL && _cb->is_nmethod(), "must be an nmethod");
nmethod* nm = (nmethod *)_cb;
assert(_cb != NULL && _cb->is_compiled(), "must be an nmethod");
CompiledMethod* nm = (CompiledMethod *)_cb;
if (TraceDependencies) {
tty->print("checking (%s) ", nm->is_marked_for_deoptimization() ? "true" : "false");
nm->print_value_on(tty);
@ -246,7 +246,7 @@ bool frame::should_be_deoptimized() const {
bool frame::can_be_deoptimized() const {
if (!is_compiled_frame()) return false;
nmethod* nm = (nmethod*)_cb;
CompiledMethod* nm = (CompiledMethod*)_cb;
if( !nm->can_be_deoptimized() )
return false;
@ -256,8 +256,7 @@ bool frame::can_be_deoptimized() const {
void frame::deoptimize(JavaThread* thread) {
// Schedule deoptimization of an nmethod activation with this frame.
assert(_cb != NULL && _cb->is_nmethod(), "must be");
nmethod* nm = (nmethod*)_cb;
assert(_cb != NULL && _cb->is_compiled(), "must be");
// This is a fix for register window patching race
if (NeedsDeoptSuspend && Thread::current() != thread) {
@ -316,12 +315,13 @@ void frame::deoptimize(JavaThread* thread) {
// If the call site is a MethodHandle call site use the MH deopt
// handler.
address deopt = nm->is_method_handle_return(pc()) ?
nm->deopt_mh_handler_begin() :
nm->deopt_handler_begin();
CompiledMethod* cm = (CompiledMethod*) _cb;
address deopt = cm->is_method_handle_return(pc()) ?
cm->deopt_mh_handler_begin() :
cm->deopt_handler_begin();
// Save the original pc before we patch in the new one
nm->set_original_pc(this, pc());
cm->set_original_pc(this, pc());
patch_pc(thread, deopt);
#ifdef ASSERT
@ -661,13 +661,16 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose
}
} else if (_cb->is_buffer_blob()) {
st->print("v ~BufferBlob::%s", ((BufferBlob *)_cb)->name());
} else if (_cb->is_nmethod()) {
nmethod* nm = (nmethod*)_cb;
Method* m = nm->method();
} else if (_cb->is_compiled()) {
CompiledMethod* cm = (CompiledMethod*)_cb;
Method* m = cm->method();
if (m != NULL) {
st->print("J %d%s", nm->compile_id(), (nm->is_osr_method() ? "%" : ""));
if (nm->compiler() != NULL) {
st->print(" %s", nm->compiler()->name());
if (cm->is_nmethod()) {
nmethod* nm = cm->as_nmethod();
st->print("J %d%s", nm->compile_id(), (nm->is_osr_method() ? "%" : ""));
if (nm->compiler() != NULL) {
st->print(" %s", nm->compiler()->name());
}
}
m->name_and_sig_as_C_string(buf, buflen);
st->print(" %s", buf);
@ -681,9 +684,12 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose
st->print(" (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]",
m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin());
#if INCLUDE_JVMCI
char* jvmciName = nm->jvmci_installed_code_name(buf, buflen);
if (jvmciName != NULL) {
st->print(" (%s)", jvmciName);
if (cm->is_nmethod()) {
nmethod* nm = cm->as_nmethod();
char* jvmciName = nm->jvmci_installed_code_name(buf, buflen);
if (jvmciName != NULL) {
st->print(" (%s)", jvmciName);
}
}
#endif
} else {
@ -1244,10 +1250,10 @@ void frame::describe(FrameValues& values, int frame_no) {
values.describe(-1, info_address, err_msg("#%d entry frame", frame_no), 2);
} else if (is_compiled_frame()) {
// For now just label the frame
nmethod* nm = cb()->as_nmethod_or_null();
CompiledMethod* cm = (CompiledMethod*)cb();
values.describe(-1, info_address,
FormatBuffer<1024>("#%d nmethod " INTPTR_FORMAT " for method %s%s", frame_no,
p2i(nm), nm->method()->name_and_sig_as_C_string(),
p2i(cm), cm->method()->name_and_sig_as_C_string(),
(_deopt_state == is_deoptimized) ?
" (deoptimized)" :
((_deopt_state == unknown) ? " (state unknown)" : "")),

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -127,7 +127,7 @@ int InterpretedRFrame::cost() const {
}
int CompiledRFrame::cost() const {
nmethod* nm = top_method()->code();
CompiledMethod* nm = top_method()->code();
if (nm != NULL) {
return nm->insts_size();
} else {
@ -139,7 +139,7 @@ void CompiledRFrame::init() {
RegisterMap map(thread(), false);
vframe* vf = vframe::new_vframe(&_fr, &map, thread());
assert(vf->is_compiled_frame(), "must be compiled");
_nm = compiledVFrame::cast(vf)->code();
_nm = compiledVFrame::cast(vf)->code()->as_nmethod();
vf = vf->top();
_vf = javaVFrame::cast(vf);
_method = CodeCache::find_nmethod(_fr.pc())->method();

View File

@ -1010,8 +1010,8 @@ void ThreadSafepointState::handle_polling_page_exception() {
address real_return_addr = thread()->saved_exception_pc();
CodeBlob *cb = CodeCache::find_blob(real_return_addr);
assert(cb != NULL && cb->is_nmethod(), "return address should be in nmethod");
nmethod* nm = (nmethod*)cb;
assert(cb != NULL && cb->is_compiled(), "return address should be in nmethod");
CompiledMethod* nm = (CompiledMethod*)cb;
// Find frame of caller
frame stub_fr = thread()->last_frame();

View File

@ -540,10 +540,10 @@ address SharedRuntime::get_poll_stub(address pc) {
CodeBlob *cb = CodeCache::find_blob(pc);
// Should be an nmethod
assert(cb && cb->is_nmethod(), "safepoint polling: pc must refer to an nmethod");
assert(cb && cb->is_compiled(), "safepoint polling: pc must refer to an nmethod");
// Look up the relocation information
assert(((nmethod*)cb)->is_at_poll_or_poll_return(pc),
assert(((CompiledMethod*)cb)->is_at_poll_or_poll_return(pc),
"safepoint polling: type must be poll");
#ifdef ASSERT
@ -554,8 +554,8 @@ address SharedRuntime::get_poll_stub(address pc) {
}
#endif
bool at_poll_return = ((nmethod*)cb)->is_at_poll_return(pc);
bool has_wide_vectors = ((nmethod*)cb)->has_wide_vectors();
bool at_poll_return = ((CompiledMethod*)cb)->is_at_poll_return(pc);
bool has_wide_vectors = ((CompiledMethod*)cb)->has_wide_vectors();
if (at_poll_return) {
assert(SharedRuntime::polling_page_return_handler_blob() != NULL,
"polling page return stub not created yet");
@ -630,22 +630,22 @@ JRT_END
// ret_pc points into caller; we are returning caller's exception handler
// for given exception
address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, Handle& exception,
address SharedRuntime::compute_compiled_exc_handler(CompiledMethod* cm, address ret_pc, Handle& exception,
bool force_unwind, bool top_frame_only) {
assert(nm != NULL, "must exist");
assert(cm != NULL, "must exist");
ResourceMark rm;
#if INCLUDE_JVMCI
if (nm->is_compiled_by_jvmci()) {
if (cm->is_compiled_by_jvmci()) {
// lookup exception handler for this pc
int catch_pco = ret_pc - nm->code_begin();
ExceptionHandlerTable table(nm);
int catch_pco = ret_pc - cm->code_begin();
ExceptionHandlerTable table(cm);
HandlerTableEntry *t = table.entry_for(catch_pco, -1, 0);
if (t != NULL) {
return nm->code_begin() + t->pco();
return cm->code_begin() + t->pco();
} else {
// there is no exception handler for this pc => deoptimize
nm->make_not_entrant();
cm->make_not_entrant();
// Use Deoptimization::deoptimize for all of its side-effects:
// revoking biases of monitors, gathering traps statistics, logging...
@ -662,6 +662,7 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc,
}
#endif // INCLUDE_JVMCI
nmethod* nm = cm->as_nmethod();
ScopeDesc* sd = nm->scope_desc_at(ret_pc);
// determine handler bci, if any
EXCEPTION_MARK;
@ -797,7 +798,7 @@ void SharedRuntime::throw_StackOverflowError_common(JavaThread* thread, bool del
}
#if INCLUDE_JVMCI
address SharedRuntime::deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason) {
address SharedRuntime::deoptimize_for_implicit_exception(JavaThread* thread, address pc, CompiledMethod* nm, int deopt_reason) {
assert(deopt_reason > Deoptimization::Reason_none && deopt_reason < Deoptimization::Reason_LIMIT, "invalid deopt reason");
thread->set_jvmci_implicit_exception_pc(pc);
thread->set_pending_deoptimization(Deoptimization::make_trap_request((Deoptimization::DeoptReason)deopt_reason, Deoptimization::Action_reinterpret));
@ -871,7 +872,7 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread,
// 2. Inline-cache check in nmethod, or
// 3. Implicit null exception in nmethod
if (!cb->is_nmethod()) {
if (!cb->is_compiled()) {
bool is_in_blob = cb->is_adapter_blob() || cb->is_method_handles_adapter_blob();
if (!is_in_blob) {
// Allow normal crash reporting to handle this
@ -882,9 +883,9 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread,
return StubRoutines::throw_NullPointerException_at_call_entry();
}
// Otherwise, it's an nmethod. Consult its exception handlers.
nmethod* nm = (nmethod*)cb;
if (nm->inlinecache_check_contains(pc)) {
// Otherwise, it's a compiled method. Consult its exception handlers.
CompiledMethod* cm = (CompiledMethod*)cb;
if (cm->inlinecache_check_contains(pc)) {
// exception happened inside inline-cache check code
// => the nmethod is not yet active (i.e., the frame
// is not set up yet) => use return address pushed by
@ -893,7 +894,7 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread,
return StubRoutines::throw_NullPointerException_at_call_entry();
}
if (nm->method()->is_method_handle_intrinsic()) {
if (cm->method()->is_method_handle_intrinsic()) {
// exception happened inside MH dispatch code, similar to a vtable stub
Events::log_exception(thread, "NullPointerException in MH adapter " INTPTR_FORMAT, p2i(pc));
return StubRoutines::throw_NullPointerException_at_call_entry();
@ -903,15 +904,15 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread,
_implicit_null_throws++;
#endif
#if INCLUDE_JVMCI
if (nm->is_compiled_by_jvmci() && nm->pc_desc_at(pc) != NULL) {
if (cm->is_compiled_by_jvmci() && cm->pc_desc_at(pc) != NULL) {
// If there's no PcDesc then we'll die way down inside of
// deopt instead of just getting normal error reporting,
// so only go there if it will succeed.
return deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_null_check);
return deoptimize_for_implicit_exception(thread, pc, cm, Deoptimization::Reason_null_check);
} else {
#endif // INCLUDE_JVMCI
assert (nm->is_nmethod(), "Expect nmethod");
target_pc = nm->continuation_for_implicit_exception(pc);
assert (cm->is_nmethod(), "Expect nmethod");
target_pc = ((nmethod*)cm)->continuation_for_implicit_exception(pc);
#if INCLUDE_JVMCI
}
#endif // INCLUDE_JVMCI
@ -925,17 +926,17 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread,
case IMPLICIT_DIVIDE_BY_ZERO: {
nmethod* nm = CodeCache::find_nmethod(pc);
guarantee(nm != NULL, "must have containing compiled method for implicit division-by-zero exceptions");
CompiledMethod* cm = CodeCache::find_compiled(pc);
guarantee(cm != NULL, "must have containing compiled method for implicit division-by-zero exceptions");
#ifndef PRODUCT
_implicit_div0_throws++;
#endif
#if INCLUDE_JVMCI
if (nm->is_compiled_by_jvmci() && nm->pc_desc_at(pc) != NULL) {
return deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_div0_check);
if (cm->is_compiled_by_jvmci() && cm->pc_desc_at(pc) != NULL) {
return deoptimize_for_implicit_exception(thread, pc, cm, Deoptimization::Reason_div0_check);
} else {
#endif // INCLUDE_JVMCI
target_pc = nm->continuation_for_implicit_exception(pc);
target_pc = cm->continuation_for_implicit_exception(pc);
#if INCLUDE_JVMCI
}
#endif // INCLUDE_JVMCI
@ -1084,14 +1085,14 @@ Handle SharedRuntime::find_callee_info(JavaThread* thread, Bytecodes::Code& bc,
}
methodHandle SharedRuntime::extract_attached_method(vframeStream& vfst) {
nmethod* caller_nm = vfst.nm();
CompiledMethod* caller = vfst.nm();
nmethodLocker caller_lock(caller_nm);
nmethodLocker caller_lock(caller);
address pc = vfst.frame_pc();
{ // Get call instruction under lock because another thread may be busy patching it.
MutexLockerEx ml_patch(Patching_lock, Mutex::_no_safepoint_check_flag);
return caller_nm->attached_method_before_pc(pc);
return caller->attached_method_before_pc(pc);
}
return NULL;
}
@ -1283,8 +1284,8 @@ methodHandle SharedRuntime::resolve_sub_helper(JavaThread *thread,
frame caller_frame = thread->last_frame().sender(&cbl_map);
CodeBlob* caller_cb = caller_frame.cb();
guarantee(caller_cb != NULL && caller_cb->is_nmethod(), "must be called from nmethod");
nmethod* caller_nm = caller_cb->as_nmethod_or_null();
guarantee(caller_cb != NULL && caller_cb->is_compiled(), "must be called from compiled method");
CompiledMethod* caller_nm = caller_cb->as_compiled_method_or_null();
// make sure caller is not getting deoptimized
// and removed before we are done with it.
@ -1347,14 +1348,19 @@ methodHandle SharedRuntime::resolve_sub_helper(JavaThread *thread,
// Make sure the callee nmethod does not get deoptimized and removed before
// we are done patching the code.
nmethod* callee_nm = callee_method->code();
if (callee_nm != NULL && !callee_nm->is_in_use()) {
// Patch call site to C2I adapter if callee nmethod is deoptimized or unloaded.
callee_nm = NULL;
CompiledMethod* callee = callee_method->code();
if (callee != NULL) {
assert(callee->is_compiled(), "must be nmethod for patching");
}
nmethodLocker nl_callee(callee_nm);
if (callee != NULL && !callee->is_in_use()) {
// Patch call site to C2I adapter if callee nmethod is deoptimized or unloaded.
callee = NULL;
}
nmethodLocker nl_callee(callee);
#ifdef ASSERT
address dest_entry_point = callee_nm == NULL ? 0 : callee_nm->entry_point(); // used below
address dest_entry_point = callee == NULL ? 0 : callee->entry_point(); // used below
#endif
if (is_virtual) {
@ -1382,12 +1388,12 @@ methodHandle SharedRuntime::resolve_sub_helper(JavaThread *thread,
// which may happen when multiply alive nmethod (tiered compilation)
// will be supported.
if (!callee_method->is_old() &&
(callee_nm == NULL || callee_nm->is_in_use() && (callee_method->code() == callee_nm))) {
(callee == NULL || callee->is_in_use() && (callee_method->code() == callee))) {
#ifdef ASSERT
// We must not try to patch to jump to an already unloaded method.
if (dest_entry_point != 0) {
CodeBlob* cb = CodeCache::find_blob(dest_entry_point);
assert((cb != NULL) && cb->is_nmethod() && (((nmethod*)cb) == callee_nm),
assert((cb != NULL) && cb->is_compiled() && (((CompiledMethod*)cb) == callee),
"should not call unloaded nmethod");
}
#endif
@ -1582,8 +1588,9 @@ methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) {
RegisterMap reg_map(thread, false);
frame caller_frame = thread->last_frame().sender(&reg_map);
CodeBlob* cb = caller_frame.cb();
if (cb->is_nmethod()) {
CompiledIC* inline_cache = CompiledIC_before(((nmethod*)cb), caller_frame.pc());
CompiledMethod* caller_nm = cb->as_compiled_method_or_null();
if (cb->is_compiled()) {
CompiledIC* inline_cache = CompiledIC_before(((CompiledMethod*)cb), caller_frame.pc());
bool should_be_mono = false;
if (inline_cache->is_optimized()) {
if (TraceCallFixup) {
@ -1667,7 +1674,7 @@ methodHandle SharedRuntime::reresolve_call_site(JavaThread *thread, TRAPS) {
// Check for static or virtual call
bool is_static_call = false;
nmethod* caller_nm = CodeCache::find_nmethod(pc);
CompiledMethod* caller_nm = CodeCache::find_compiled(pc);
// Default call_addr is the location of the "basic" call.
// Determine the address of the call we a reresolving. With
@ -1802,12 +1809,12 @@ IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address cal
// ask me how I know this...
CodeBlob* cb = CodeCache::find_blob(caller_pc);
if (!cb->is_nmethod() || entry_point == moop->get_c2i_entry()) {
if (!cb->is_compiled() || entry_point == moop->get_c2i_entry()) {
return;
}
// The check above makes sure this is a nmethod.
nmethod* nm = cb->as_nmethod_or_null();
CompiledMethod* nm = cb->as_compiled_method_or_null();
assert(nm, "must be");
// Get the return PC for the passed caller PC.

View File

@ -188,7 +188,7 @@ class SharedRuntime: AllStatic {
#endif // INCLUDE_ALL_GCS
// exception handling and implicit exceptions
static address compute_compiled_exc_handler(nmethod* nm, address ret_pc, Handle& exception,
static address compute_compiled_exc_handler(CompiledMethod* nm, address ret_pc, Handle& exception,
bool force_unwind, bool top_frame_only);
enum ImplicitExceptionKind {
IMPLICIT_NULL,
@ -207,7 +207,7 @@ class SharedRuntime: AllStatic {
address faulting_pc,
ImplicitExceptionKind exception_kind);
#if INCLUDE_JVMCI
static address deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason);
static address deoptimize_for_implicit_exception(JavaThread* thread, address pc, CompiledMethod* nm, int deopt_reason);
#endif
static void enable_stack_reserved_zone(JavaThread* thread);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 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
@ -192,7 +192,7 @@ void SimpleThresholdPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) {
}
nmethod* SimpleThresholdPolicy::event(const methodHandle& method, const methodHandle& inlinee,
int branch_bci, int bci, CompLevel comp_level, nmethod* nm, JavaThread* thread) {
int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread) {
if (comp_level == CompLevel_none &&
JvmtiExport::can_post_interpreter_events() &&
thread->is_interp_only_mode()) {
@ -392,7 +392,7 @@ CompLevel SimpleThresholdPolicy::loop_event(Method* method, CompLevel cur_level)
// Handle the invocation event.
void SimpleThresholdPolicy::method_invocation_event(const methodHandle& mh, const methodHandle& imh,
CompLevel level, nmethod* nm, JavaThread* thread) {
CompLevel level, CompiledMethod* nm, JavaThread* thread) {
if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) {
CompLevel next_level = call_event(mh(), level);
if (next_level != level) {
@ -404,7 +404,7 @@ void SimpleThresholdPolicy::method_invocation_event(const methodHandle& mh, cons
// Handle the back branch event. Notice that we can compile the method
// with a regular entry from here.
void SimpleThresholdPolicy::method_back_branch_event(const methodHandle& mh, const methodHandle& imh,
int bci, CompLevel level, nmethod* nm, JavaThread* thread) {
int bci, CompLevel level, CompiledMethod* nm, JavaThread* thread) {
// If the method is already compiling, quickly bail out.
if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh)) {
// Use loop event as an opportunity to also check there's been

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 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
@ -81,16 +81,16 @@ protected:
// Get a compilation level for a given method.
static CompLevel comp_level(Method* method) {
nmethod *nm = method->code();
CompiledMethod *nm = method->code();
if (nm != NULL && nm->is_in_use()) {
return (CompLevel)nm->comp_level();
}
return CompLevel_none;
}
virtual void method_invocation_event(const methodHandle& method, const methodHandle& inlinee,
CompLevel level, nmethod* nm, JavaThread* thread);
CompLevel level, CompiledMethod* nm, JavaThread* thread);
virtual void method_back_branch_event(const methodHandle& method, const methodHandle& inlinee,
int bci, CompLevel level, nmethod* nm, JavaThread* thread);
int bci, CompLevel level, CompiledMethod* nm, JavaThread* thread);
public:
SimpleThresholdPolicy() : _c1_count(0), _c2_count(0) { }
virtual int compiler_count(CompLevel comp_level) {
@ -104,7 +104,7 @@ public:
virtual void disable_compilation(Method* method) { }
virtual void reprofile(ScopeDesc* trap_scope, bool is_osr);
virtual nmethod* event(const methodHandle& method, const methodHandle& inlinee,
int branch_bci, int bci, CompLevel comp_level, nmethod* nm, JavaThread* thread);
int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, JavaThread* thread);
// Select task is called by CompileBroker. We should return a task or NULL.
virtual CompileTask* select_task(CompileQueue* compile_queue);
// Tell the runtime if we think a given method is adequately profiled.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -254,8 +254,8 @@ class StubRoutines: AllStatic {
(_code2 != NULL && _code2->blob_contains(addr)) ;
}
static CodeBlob* code1() { return _code1; }
static CodeBlob* code2() { return _code2; }
static RuntimeBlob* code1() { return _code1; }
static RuntimeBlob* code2() { return _code2; }
// Debugging
static jint verify_oop_count() { return _verify_oop_count; }

View File

@ -109,13 +109,13 @@ void NMethodSweeper::report_events() {
}
}
void NMethodSweeper::record_sweep(nmethod* nm, int line) {
void NMethodSweeper::record_sweep(CompiledMethod* nm, int line) {
if (_records != NULL) {
_records[_sweep_index].traversal = _traversals;
_records[_sweep_index].traversal_mark = nm->_stack_traversal_mark;
_records[_sweep_index].traversal_mark = nm->is_nmethod() ? ((nmethod*)nm)->_stack_traversal_mark : 0;
_records[_sweep_index].compile_id = nm->compile_id();
_records[_sweep_index].kind = nm->compile_kind();
_records[_sweep_index].state = nm->_state;
_records[_sweep_index].state = nm->get_state();
_records[_sweep_index].vep = nm->verified_entry_point();
_records[_sweep_index].uep = nm->entry_point();
_records[_sweep_index].line = line;
@ -134,7 +134,7 @@ void NMethodSweeper::init_sweeper_log() {
#define SWEEP(nm)
#endif
NMethodIterator NMethodSweeper::_current; // Current nmethod
CompiledMethodIterator NMethodSweeper::_current; // Current compiled method
long NMethodSweeper::_traversals = 0; // Stack scan count, also sweep ID.
long NMethodSweeper::_total_nof_code_cache_sweeps = 0; // Total number of full sweeps of the code cache
long NMethodSweeper::_time_counter = 0; // Virtual time used to periodically invoke sweeper
@ -210,10 +210,17 @@ void NMethodSweeper::mark_active_nmethods() {
_time_counter++;
// Check for restart
assert(CodeCache::find_blob_unsafe(_current.method()) == _current.method(), "Sweeper nmethod cached state invalid");
if (_current.method() != NULL) {
if (_current.method()->is_nmethod()) {
assert(CodeCache::find_blob_unsafe(_current.method()) == _current.method(), "Sweeper nmethod cached state invalid");
} else {
ShouldNotReachHere();
}
}
if (wait_for_stack_scanning()) {
_seen = 0;
_current = NMethodIterator();
_current = CompiledMethodIterator();
// Initialize to first nmethod
_current.next();
_traversals += 1;
@ -415,14 +422,15 @@ void NMethodSweeper::sweep_code_cache() {
// Since we will give up the CodeCache_lock, always skip ahead
// to the next nmethod. Other blobs can be deleted by other
// threads but nmethods are only reclaimed by the sweeper.
nmethod* nm = _current.method();
CompiledMethod* nm = _current.method();
_current.next();
// Now ready to process nmethod and give up CodeCache_lock
{
MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
// Save information before potentially flushing the nmethod
int size = nm->total_size();
// Only flushing nmethods so size only matters for them.
int size = nm->is_nmethod() ? ((nmethod*)nm)->total_size() : 0;
bool is_c2_method = nm->is_compiled_by_c2();
bool is_osr = nm->is_osr_method();
int compile_id = nm->compile_id();
@ -430,7 +438,7 @@ void NMethodSweeper::sweep_code_cache() {
const char* state_before = nm->state();
const char* state_after = "";
MethodStateChange type = process_nmethod(nm);
MethodStateChange type = process_compiled_method(nm);
switch (type) {
case Flushed:
state_after = "flushed";
@ -532,28 +540,28 @@ void NMethodSweeper::possibly_enable_sweeper() {
}
}
class NMethodMarker: public StackObj {
class CompiledMethodMarker: public StackObj {
private:
CodeCacheSweeperThread* _thread;
public:
NMethodMarker(nmethod* nm) {
CompiledMethodMarker(CompiledMethod* cm) {
JavaThread* current = JavaThread::current();
assert (current->is_Code_cache_sweeper_thread(), "Must be");
_thread = (CodeCacheSweeperThread*)current;
if (!nm->is_zombie() && !nm->is_unloaded()) {
if (!cm->is_zombie() && !cm->is_unloaded()) {
// Only expose live nmethods for scanning
_thread->set_scanned_nmethod(nm);
_thread->set_scanned_compiled_method(cm);
}
}
~NMethodMarker() {
_thread->set_scanned_nmethod(NULL);
~CompiledMethodMarker() {
_thread->set_scanned_compiled_method(NULL);
}
};
void NMethodSweeper::release_nmethod(nmethod* nm) {
void NMethodSweeper::release_compiled_method(CompiledMethod* nm) {
// Make sure the released nmethod is no longer referenced by the sweeper thread
CodeCacheSweeperThread* thread = (CodeCacheSweeperThread*)JavaThread::current();
thread->set_scanned_nmethod(NULL);
thread->set_scanned_compiled_method(NULL);
// Clean up any CompiledICHolders
{
@ -571,98 +579,100 @@ void NMethodSweeper::release_nmethod(nmethod* nm) {
nm->flush();
}
NMethodSweeper::MethodStateChange NMethodSweeper::process_nmethod(nmethod* nm) {
assert(nm != NULL, "sanity");
NMethodSweeper::MethodStateChange NMethodSweeper::process_compiled_method(CompiledMethod* cm) {
assert(cm != NULL, "sanity");
assert(!CodeCache_lock->owned_by_self(), "just checking");
MethodStateChange result = None;
// Make sure this nmethod doesn't get unloaded during the scan,
// since safepoints may happen during acquired below locks.
NMethodMarker nmm(nm);
SWEEP(nm);
CompiledMethodMarker nmm(cm);
SWEEP(cm);
// Skip methods that are currently referenced by the VM
if (nm->is_locked_by_vm()) {
if (cm->is_locked_by_vm()) {
// But still remember to clean-up inline caches for alive nmethods
if (nm->is_alive()) {
if (cm->is_alive()) {
// Clean inline caches that point to zombie/non-entrant/unloaded nmethods
MutexLocker cl(CompiledIC_lock);
nm->cleanup_inline_caches();
SWEEP(nm);
cm->cleanup_inline_caches();
SWEEP(cm);
}
return result;
}
if (nm->is_zombie()) {
if (cm->is_zombie()) {
// All inline caches that referred to this nmethod were cleaned in the
// previous sweeper cycle. Now flush the nmethod from the code cache.
assert(!nm->is_locked_by_vm(), "must not flush locked nmethods");
release_nmethod(nm);
assert(!cm->is_locked_by_vm(), "must not flush locked Compiled Methods");
release_compiled_method(cm);
assert(result == None, "sanity");
result = Flushed;
} else if (nm->is_not_entrant()) {
} else if (cm->is_not_entrant()) {
// If there are no current activations of this method on the
// stack we can safely convert it to a zombie method
if (nm->can_convert_to_zombie()) {
if (cm->can_convert_to_zombie()) {
// Clear ICStubs to prevent back patching stubs of zombie or flushed
// nmethods during the next safepoint (see ICStub::finalize).
{
MutexLocker cl(CompiledIC_lock);
nm->clear_ic_stubs();
cm->clear_ic_stubs();
}
// Code cache state change is tracked in make_zombie()
nm->make_zombie();
SWEEP(nm);
cm->make_zombie();
SWEEP(cm);
// The nmethod may have been locked by JVMTI after being made zombie (see
// JvmtiDeferredEvent::compiled_method_unload_event()). If so, we cannot
// flush the osr nmethod directly but have to wait for a later sweeper cycle.
if (nm->is_osr_method() && !nm->is_locked_by_vm()) {
if (cm->is_osr_method() && !cm->is_locked_by_vm()) {
// No inline caches will ever point to osr methods, so we can just remove it.
// Make sure that we unregistered the nmethod with the heap and flushed all
// dependencies before removing the nmethod (done in make_zombie()).
assert(nm->is_zombie(), "nmethod must be unregistered");
release_nmethod(nm);
assert(cm->is_zombie(), "nmethod must be unregistered");
release_compiled_method(cm);
assert(result == None, "sanity");
result = Flushed;
} else {
assert(result == None, "sanity");
result = MadeZombie;
assert(nm->is_zombie(), "nmethod must be zombie");
assert(cm->is_zombie(), "nmethod must be zombie");
}
} else {
// Still alive, clean up its inline caches
MutexLocker cl(CompiledIC_lock);
nm->cleanup_inline_caches();
SWEEP(nm);
cm->cleanup_inline_caches();
SWEEP(cm);
}
} else if (nm->is_unloaded()) {
} else if (cm->is_unloaded()) {
// Code is unloaded, so there are no activations on the stack.
// Convert the nmethod to zombie or flush it directly in the OSR case.
{
// Clean ICs of unloaded nmethods as well because they may reference other
// unloaded nmethods that may be flushed earlier in the sweeper cycle.
MutexLocker cl(CompiledIC_lock);
nm->cleanup_inline_caches();
cm->cleanup_inline_caches();
}
if (nm->is_osr_method()) {
SWEEP(nm);
if (cm->is_osr_method()) {
SWEEP(cm);
// No inline caches will ever point to osr methods, so we can just remove it
release_nmethod(nm);
release_compiled_method(cm);
assert(result == None, "sanity");
result = Flushed;
} else {
// Code cache state change is tracked in make_zombie()
nm->make_zombie();
SWEEP(nm);
cm->make_zombie();
SWEEP(cm);
assert(result == None, "sanity");
result = MadeZombie;
}
} else {
possibly_flush(nm);
if (cm->is_nmethod()) {
possibly_flush((nmethod*)cm);
}
// Clean inline caches that point to zombie/non-entrant/unloaded nmethods
MutexLocker cl(CompiledIC_lock);
nm->cleanup_inline_caches();
SWEEP(nm);
cm->cleanup_inline_caches();
SWEEP(cm);
}
return result;
}

View File

@ -66,7 +66,7 @@ class NMethodSweeper : public AllStatic {
static long _total_nof_code_cache_sweeps; // Total number of full sweeps of the code cache
static long _time_counter; // Virtual time used to periodically invoke sweeper
static long _last_sweep; // Value of _time_counter when the last sweep happened
static NMethodIterator _current; // Current nmethod
static CompiledMethodIterator _current; // Current compiled method
static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache
static volatile int _sweep_started; // Flag to control conc sweeper
@ -88,8 +88,8 @@ class NMethodSweeper : public AllStatic {
static Monitor* _stat_lock;
static MethodStateChange process_nmethod(nmethod *nm);
static void release_nmethod(nmethod* nm);
static MethodStateChange process_compiled_method(CompiledMethod *nm);
static void release_compiled_method(CompiledMethod* nm);
static void init_sweeper_log() NOT_DEBUG_RETURN;
static bool wait_for_stack_scanning();
@ -107,9 +107,8 @@ class NMethodSweeper : public AllStatic {
#ifdef ASSERT
static bool is_sweeping(nmethod* which) { return _current.method() == which; }
// Keep track of sweeper activity in the ring buffer
static void record_sweep(nmethod* nm, int line);
static void record_sweep(CompiledMethod* nm, int line);
static void report_events(int id, address entry);
static void report_events();
#endif

View File

@ -1432,7 +1432,7 @@ void JavaThread::initialize() {
set_vframe_array_last(NULL);
set_deferred_locals(NULL);
set_deopt_mark(NULL);
set_deopt_nmethod(NULL);
set_deopt_compiled_method(NULL);
clear_must_deopt_id();
set_monitor_chunks(NULL);
set_next(NULL);
@ -3300,26 +3300,26 @@ bool CompilerThread::can_call_java() const {
// Create sweeper thread
CodeCacheSweeperThread::CodeCacheSweeperThread()
: JavaThread(&sweeper_thread_entry) {
_scanned_nmethod = NULL;
_scanned_compiled_method = NULL;
}
void CodeCacheSweeperThread::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) {
JavaThread::oops_do(f, cld_f, cf);
if (_scanned_nmethod != NULL && cf != NULL) {
if (_scanned_compiled_method != NULL && cf != NULL) {
// Safepoints can occur when the sweeper is scanning an nmethod so
// process it here to make sure it isn't unloaded in the middle of
// a scan.
cf->do_code_blob(_scanned_nmethod);
cf->do_code_blob(_scanned_compiled_method);
}
}
void CodeCacheSweeperThread::nmethods_do(CodeBlobClosure* cf) {
JavaThread::nmethods_do(cf);
if (_scanned_nmethod != NULL && cf != NULL) {
if (_scanned_compiled_method != NULL && cf != NULL) {
// Safepoints can occur when the sweeper is scanning an nmethod so
// process it here to make sure it isn't unloaded in the middle of
// a scan.
cf->do_code_blob(_scanned_nmethod);
cf->do_code_blob(_scanned_compiled_method);
}
}
@ -4353,7 +4353,7 @@ void Threads::nmethods_do(CodeBlobClosure* cf) {
ALL_JAVA_THREADS(p) {
// This is used by the code cache sweeper to mark nmethods that are active
// on the stack of a Java thread. Ignore the sweeper thread itself to avoid
// marking CodeCacheSweeperThread::_scanned_nmethod as active.
// marking CodeCacheSweeperThread::_scanned_compiled_method as active.
if(!p->is_Code_cache_sweeper_thread()) {
p->nmethods_do(cf);
}

View File

@ -820,7 +820,7 @@ class JavaThread: public Thread {
intptr_t* _must_deopt_id; // id of frame that needs to be deopted once we
// transition out of native
nmethod* _deopt_nmethod; // nmethod that is currently being deoptimized
CompiledMethod* _deopt_nmethod; // CompiledMethod that is currently being deoptimized
vframeArray* _vframe_array_head; // Holds the heap of the active vframeArrays
vframeArray* _vframe_array_last; // Holds last vFrameArray we popped
// Because deoptimization is lazy we must save jvmti requests to set locals
@ -1298,8 +1298,8 @@ class JavaThread: public Thread {
void set_must_deopt_id(intptr_t* id) { _must_deopt_id = id; }
void clear_must_deopt_id() { _must_deopt_id = NULL; }
void set_deopt_nmethod(nmethod* nm) { _deopt_nmethod = nm; }
nmethod* deopt_nmethod() { return _deopt_nmethod; }
void set_deopt_compiled_method(CompiledMethod* nm) { _deopt_nmethod = nm; }
CompiledMethod* deopt_compiled_method() { return _deopt_nmethod; }
Method* callee_target() const { return _callee_target; }
void set_callee_target (Method* x) { _callee_target = x; }
@ -1980,13 +1980,13 @@ inline CompilerThread* JavaThread::as_CompilerThread() {
// Dedicated thread to sweep the code cache
class CodeCacheSweeperThread : public JavaThread {
nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper
CompiledMethod* _scanned_compiled_method; // nmethod being scanned by the sweeper
public:
CodeCacheSweeperThread();
// Track the nmethod currently being scanned by the sweeper
void set_scanned_nmethod(nmethod* nm) {
assert(_scanned_nmethod == NULL || nm == NULL, "should reset to NULL before writing a new value");
_scanned_nmethod = nm;
void set_scanned_compiled_method(CompiledMethod* cm) {
assert(_scanned_compiled_method == NULL || cm == NULL, "should reset to NULL before writing a new value");
_scanned_compiled_method = cm;
}
// Hide sweeper thread from external view.
@ -1994,7 +1994,7 @@ class CodeCacheSweeperThread : public JavaThread {
bool is_Code_cache_sweeper_thread() const { return true; }
// Prevent GC from unloading _scanned_nmethod
// Prevent GC from unloading _scanned_compiled_method
void oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf);
void nmethods_do(CodeBlobClosure* cf);
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -67,8 +67,8 @@ vframe* vframe::new_vframe(const frame* f, const RegisterMap* reg_map, JavaThrea
// Compiled frame
CodeBlob* cb = f->cb();
if (cb != NULL) {
if (cb->is_nmethod()) {
nmethod* nm = (nmethod*)cb;
if (cb->is_compiled()) {
CompiledMethod* nm = (CompiledMethod*)cb;
return new compiledVFrame(f, reg_map, thread, nm);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -66,9 +66,9 @@ class vframe: public ResourceObj {
// Accessors
frame fr() const { return _fr; }
CodeBlob* cb() const { return _fr.cb(); }
nmethod* nm() const {
assert( cb() != NULL && cb()->is_nmethod(), "usage");
return (nmethod*) cb();
CompiledMethod* nm() const {
assert( cb() != NULL && cb()->is_compiled(), "usage");
return (CompiledMethod*) cb();
}
// ???? Does this need to be a copy?
@ -326,9 +326,9 @@ class vframeStreamCommon : StackObj {
}
CodeBlob* cb() const { return _frame.cb(); }
nmethod* nm() const {
assert( cb() != NULL && cb()->is_nmethod(), "usage");
return (nmethod*) cb();
CompiledMethod* nm() const {
assert( cb() != NULL && cb()->is_compiled(), "usage");
return (CompiledMethod*) cb();
}
// Frame type
@ -449,7 +449,7 @@ inline bool vframeStreamCommon::fill_from_frame() {
// Compiled frame
if (cb() != NULL && cb()->is_nmethod()) {
if (cb() != NULL && cb()->is_compiled()) {
if (nm()->is_native_method()) {
// Do not rely on scopeDesc since the pc might be unprecise due to the _last_native_pc trick.
fill_from_compiled_native_frame();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -206,8 +206,8 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters,
// in which case bcp should point to the monitorenter since it is within the exception's range.
assert(*bcp != Bytecodes::_monitorenter || is_top_frame, "a _monitorenter must be a top frame");
assert(thread->deopt_nmethod() != NULL, "nmethod should be known");
guarantee(!(thread->deopt_nmethod()->is_compiled_by_c2() &&
assert(thread->deopt_compiled_method() != NULL, "compiled method should be known");
guarantee(!(thread->deopt_compiled_method()->is_compiled_by_c2() &&
*bcp == Bytecodes::_monitorenter &&
exec_mode == Deoptimization::Unpack_exception),
"shouldn't get exception during monitorenter");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -196,7 +196,7 @@ BasicLock* compiledVFrame::resolve_monitor_lock(Location location) const {
GrowableArray<MonitorInfo*>* compiledVFrame::monitors() const {
// Natives has no scope
if (scope() == NULL) {
nmethod* nm = code();
CompiledMethod* nm = code();
Method* method = nm->method();
assert(method->is_native(), "");
if (!method->is_synchronized()) {
@ -240,13 +240,13 @@ GrowableArray<MonitorInfo*>* compiledVFrame::monitors() const {
}
compiledVFrame::compiledVFrame(const frame* fr, const RegisterMap* reg_map, JavaThread* thread, nmethod* nm)
compiledVFrame::compiledVFrame(const frame* fr, const RegisterMap* reg_map, JavaThread* thread, CompiledMethod* nm)
: javaVFrame(fr, reg_map, thread) {
_scope = NULL;
// Compiled method (native stub or Java code)
// native wrappers have no scope data, it is implied
if (!nm->is_native_method()) {
_scope = nm->scope_desc_at(_fr.pc());
if (!nm->is_compiled() || !nm->as_compiled_method()->is_native_method()) {
_scope = nm->scope_desc_at(_fr.pc());
}
}
@ -264,15 +264,15 @@ bool compiledVFrame::is_top() const {
}
nmethod* compiledVFrame::code() const {
return CodeCache::find_nmethod(_fr.pc());
CompiledMethod* compiledVFrame::code() const {
return CodeCache::find_compiled(_fr.pc());
}
Method* compiledVFrame::method() const {
if (scope() == NULL) {
// native nmethods have no scope the method is implied
nmethod* nm = code();
nmethod* nm = code()->as_nmethod();
assert(nm->is_native_method(), "must be native");
return nm->method();
}
@ -289,7 +289,7 @@ int compiledVFrame::bci() const {
int compiledVFrame::raw_bci() const {
if (scope() == NULL) {
// native nmethods have no scope the method/bci is implied
nmethod* nm = code();
nmethod* nm = code()->as_nmethod();
assert(nm->is_native_method(), "must be native");
return 0;
}
@ -299,7 +299,7 @@ int compiledVFrame::raw_bci() const {
bool compiledVFrame::should_reexecute() const {
if (scope() == NULL) {
// native nmethods have no scope the method/bci is implied
nmethod* nm = code();
nmethod* nm = code()->as_nmethod();
assert(nm->is_native_method(), "must be native");
return false;
}
@ -310,7 +310,7 @@ vframe* compiledVFrame::sender() const {
const frame f = fr();
if (scope() == NULL) {
// native nmethods have no scope the method/bci is implied
nmethod* nm = code();
nmethod* nm = code()->as_nmethod();
assert(nm->is_native_method(), "must be native");
return vframe::sender();
} else {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -52,13 +52,13 @@ class compiledVFrame: public javaVFrame {
public:
// Constructors
compiledVFrame(const frame* fr, const RegisterMap* reg_map, JavaThread* thread, nmethod* nm);
compiledVFrame(const frame* fr, const RegisterMap* reg_map, JavaThread* thread, CompiledMethod* nm);
// Update a local in a compiled frame. Update happens when deopt occurs
void update_local(BasicType type, int index, jvalue value);
// Returns the active nmethod
nmethod* code() const;
CompiledMethod* code() const;
// Returns the scopeDesc
ScopeDesc* scope() const { return _scope; }

View File

@ -398,7 +398,7 @@ typedef CompactHashtable<Symbol*, char> SymbolCompactHashTable;
nonstatic_field(Method, _intrinsic_id, u2) \
nonstatic_field(Method, _flags, u2) \
nonproduct_nonstatic_field(Method, _compiled_invocation_count, int) \
volatile_nonstatic_field(Method, _code, nmethod*) \
volatile_nonstatic_field(Method, _code, CompiledMethod*) \
nonstatic_field(Method, _i2i_entry, address) \
volatile_nonstatic_field(Method, _from_compiled_entry, address) \
volatile_nonstatic_field(Method, _from_interpreted_entry, address) \
@ -915,40 +915,47 @@ typedef CompactHashtable<Symbol*, char> SymbolCompactHashTable;
/* CodeBlobs (NOTE: incomplete, but only a little) */ \
/***************************************************/ \
\
nonstatic_field(CodeBlob, _name, const char*) \
nonstatic_field(CodeBlob, _size, int) \
nonstatic_field(CodeBlob, _header_size, int) \
nonstatic_field(CodeBlob, _relocation_size, int) \
nonstatic_field(CodeBlob, _content_offset, int) \
nonstatic_field(CodeBlob, _code_offset, int) \
nonstatic_field(CodeBlob, _frame_complete_offset, int) \
nonstatic_field(CodeBlob, _data_offset, int) \
nonstatic_field(CodeBlob, _frame_size, int) \
nonstatic_field(CodeBlob, _oop_maps, ImmutableOopMapSet*) \
nonstatic_field(CodeBlob, _name, const char*) \
nonstatic_field(CodeBlob, _size, int) \
nonstatic_field(CodeBlob, _header_size, int) \
nonstatic_field(CodeBlob, _frame_complete_offset, int) \
nonstatic_field(CodeBlob, _data_offset, int) \
nonstatic_field(CodeBlob, _frame_size, int) \
nonstatic_field(CodeBlob, _oop_maps, ImmutableOopMapSet*) \
nonstatic_field(CodeBlob, _code_begin, address) \
nonstatic_field(CodeBlob, _code_end, address) \
nonstatic_field(CodeBlob, _content_begin, address) \
nonstatic_field(CodeBlob, _data_end, address) \
\
nonstatic_field(DeoptimizationBlob, _unpack_offset, int) \
\
nonstatic_field(RuntimeStub, _caller_must_gc_arguments, bool) \
\
/********************************************************/ \
/* CompiledMethod (NOTE: incomplete, but only a little) */ \
/********************************************************/ \
\
nonstatic_field(CompiledMethod, _method, Method*) \
volatile_nonstatic_field(CompiledMethod, _exception_cache, ExceptionCache*) \
nonstatic_field(CompiledMethod, _scopes_data_begin, address) \
nonstatic_field(CompiledMethod, _deopt_handler_begin, address) \
nonstatic_field(CompiledMethod, _deopt_mh_handler_begin, address) \
\
/**************************************************/ \
/* NMethods (NOTE: incomplete, but only a little) */ \
/**************************************************/ \
\
nonstatic_field(nmethod, _method, Method*) \
nonstatic_field(nmethod, _entry_bci, int) \
nonstatic_field(nmethod, _osr_link, nmethod*) \
nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \
nonstatic_field(nmethod, _scavenge_root_state, jbyte) \
nonstatic_field(nmethod, _state, volatile unsigned char) \
nonstatic_field(nmethod, _exception_offset, int) \
nonstatic_field(nmethod, _deoptimize_offset, int) \
nonstatic_field(nmethod, _deoptimize_mh_offset, int) \
nonstatic_field(nmethod, _orig_pc_offset, int) \
nonstatic_field(nmethod, _stub_offset, int) \
nonstatic_field(nmethod, _consts_offset, int) \
nonstatic_field(nmethod, _oops_offset, int) \
nonstatic_field(nmethod, _metadata_offset, int) \
nonstatic_field(nmethod, _scopes_data_offset, int) \
nonstatic_field(nmethod, _scopes_pcs_offset, int) \
nonstatic_field(nmethod, _dependencies_offset, int) \
nonstatic_field(nmethod, _handler_table_offset, int) \
@ -961,7 +968,6 @@ typedef CompactHashtable<Symbol*, char> SymbolCompactHashTable;
nonstatic_field(nmethod, _stack_traversal_mark, long) \
nonstatic_field(nmethod, _compile_id, int) \
nonstatic_field(nmethod, _comp_level, int) \
volatile_nonstatic_field(nmethod, _exception_cache, ExceptionCache*) \
\
unchecked_c2_static_field(Deoptimization, _trap_reason_name, void*) \
\
@ -1744,16 +1750,18 @@ typedef CompactHashtable<Symbol*, char> SymbolCompactHashTable;
declare_toplevel_type(SharedRuntime) \
\
declare_toplevel_type(CodeBlob) \
declare_type(BufferBlob, CodeBlob) \
declare_type(RuntimeBlob, CodeBlob) \
declare_type(BufferBlob, RuntimeBlob) \
declare_type(AdapterBlob, BufferBlob) \
declare_type(MethodHandlesAdapterBlob, BufferBlob) \
declare_type(nmethod, CodeBlob) \
declare_type(RuntimeStub, CodeBlob) \
declare_type(SingletonBlob, CodeBlob) \
declare_type(CompiledMethod, CodeBlob) \
declare_type(nmethod, CompiledMethod) \
declare_type(RuntimeStub, RuntimeBlob) \
declare_type(SingletonBlob, RuntimeBlob) \
declare_type(SafepointBlob, SingletonBlob) \
declare_type(DeoptimizationBlob, SingletonBlob) \
declare_c2_type(ExceptionBlob, SingletonBlob) \
declare_c2_type(UncommonTrapBlob, CodeBlob) \
declare_c2_type(UncommonTrapBlob, RuntimeBlob) \
\
/***************************************/ \
/* PcDesc and other compiled code info */ \
@ -2236,6 +2244,7 @@ typedef CompactHashtable<Symbol*, char> SymbolCompactHashTable;
declare_toplevel_type(BreakpointInfo) \
declare_toplevel_type(BreakpointInfo*) \
declare_toplevel_type(CodeBlob*) \
declare_toplevel_type(RuntimeBlob*) \
declare_toplevel_type(CompressedWriteStream*) \
declare_toplevel_type(ConstantPoolCacheEntry) \
declare_toplevel_type(elapsedTimer) \

View File

@ -1003,7 +1003,9 @@ class VM_Operation;
class VMOperationQueue;
class CodeBlob;
class nmethod;
class CompiledMethod;
class nmethod;
class RuntimeBlob;
class OSRAdapter;
class I2CAdapter;
class C2IAdapter;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@ -84,7 +84,7 @@ public class InitialAndMaxUsageTest {
Asserts.assertEQ(initialUsage, 0L, "Unexpected initial usage");
}
ArrayList<Long> blobs = new ArrayList<>();
long minAllocationUnit = CodeCacheUtils.MIN_ALLOCATION - headerSize;
long minAllocationUnit = Math.max(0, CodeCacheUtils.MIN_ALLOCATION - headerSize);
/* now filling code cache with large-sized allocation first, since
lots of small allocations takes too much time, so, just a small
optimization */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@ -67,7 +67,7 @@ public class UsageThresholdIncreasedTest {
protected void runTest() {
long headerSize = CodeCacheUtils.getHeaderSize(btype);
long allocationUnit = CodeCacheUtils.MIN_ALLOCATION - headerSize;
long allocationUnit = Math.max(0, CodeCacheUtils.MIN_ALLOCATION - headerSize);
MemoryPoolMXBean bean = btype.getMemoryPool();
long initialCount = bean.getUsageThresholdCount();
long initialSize = bean.getUsage().getUsed();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@ -58,9 +58,12 @@ public class UsageThresholdNotExceededTest {
MemoryPoolMXBean bean = btype.getMemoryPool();
long initialThresholdCount = bean.getUsageThresholdCount();
long initialUsage = bean.getUsage().getUsed();
bean.setUsageThreshold(initialUsage + 1 + CodeCacheUtils.MIN_ALLOCATION);
CodeCacheUtils.WB.allocateCodeBlob(CodeCacheUtils.MIN_ALLOCATION
- CodeCacheUtils.getHeaderSize(btype), btype.id);
long size = CodeCacheUtils.getHeaderSize(btype);
CodeCacheUtils.WB.allocateCodeBlob(Math.max(0, CodeCacheUtils.MIN_ALLOCATION
- size), btype.id);
// a gc cycle triggers usage threshold recalculation
CodeCacheUtils.WB.fullGC();
CodeCacheUtils.assertEQorGTE(btype, bean.getUsageThresholdCount(), initialThresholdCount,