7045513: JSR 292 inlining causes crashes in methodHandleWalk.cpp
Reviewed-by: jrose
This commit is contained in:
parent
4b893d695b
commit
c2f2cb75fc
@ -1028,7 +1028,12 @@ public class CommandProcessor {
|
||||
if (AddressOps.equal(val, value)) {
|
||||
if (!printed) {
|
||||
printed = true;
|
||||
blob.printOn(out);
|
||||
try {
|
||||
blob.printOn(out);
|
||||
} catch (Exception e) {
|
||||
out.println("Exception printing blob at " + base);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
out.println("found at " + base + "\n");
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class AdapterBlob extends CodeBlob {
|
||||
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("AdapterBlob");
|
||||
|
||||
// // FIXME: add any needed fields
|
||||
}
|
||||
|
||||
public AdapterBlob(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public boolean isAdapterBlob() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "AdapterBlob: " + super.getName();
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, 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
|
||||
@ -93,6 +93,8 @@ public class CodeBlob extends VMObject {
|
||||
public boolean isUncommonTrapStub() { return false; }
|
||||
public boolean isExceptionStub() { return false; }
|
||||
public boolean isSafepointStub() { return false; }
|
||||
public boolean isRicochetBlob() { return false; }
|
||||
public boolean isAdapterBlob() { return false; }
|
||||
|
||||
// Fine grain nmethod support: isNmethod() == isJavaMethod() || isNativeMethod() || isOSRMethod()
|
||||
public boolean isJavaMethod() { return false; }
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, 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
|
||||
@ -57,6 +57,8 @@ public class CodeCache {
|
||||
virtualConstructor.addMapping("BufferBlob", BufferBlob.class);
|
||||
virtualConstructor.addMapping("nmethod", NMethod.class);
|
||||
virtualConstructor.addMapping("RuntimeStub", RuntimeStub.class);
|
||||
virtualConstructor.addMapping("RicochetBlob", RicochetBlob.class);
|
||||
virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class);
|
||||
virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class);
|
||||
virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class);
|
||||
if (VM.getVM().isServerCompiler()) {
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
/** RicochetBlob (currently only used by Compiler 2) */
|
||||
|
||||
public class RicochetBlob extends SingletonBlob {
|
||||
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("RicochetBlob");
|
||||
|
||||
// FIXME: add any needed fields
|
||||
}
|
||||
|
||||
public RicochetBlob(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public boolean isRicochetBlob() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -389,7 +389,7 @@ void MethodHandles::load_stack_move(MacroAssembler* _masm,
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
#ifdef ASSERT
|
||||
void MethodHandles::RicochetFrame::verify_offsets() {
|
||||
// Check compatibility of this struct with the more generally used offsets of class frame:
|
||||
int ebp_off = sender_link_offset_in_bytes(); // offset from struct base to local rbp value
|
||||
|
@ -43,7 +43,7 @@ ciMethod* ciMethodHandle::get_adapter_impl(bool is_invokedynamic) const {
|
||||
methodHandle callee(_callee->get_methodOop());
|
||||
// We catch all exceptions here that could happen in the method
|
||||
// handle compiler and stop the VM.
|
||||
MethodHandleCompiler mhc(h, callee, _profile->count(), is_invokedynamic, THREAD);
|
||||
MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _profile->count(), is_invokedynamic, THREAD);
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
methodHandle m = mhc.compile(THREAD);
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
|
@ -203,11 +203,14 @@ void print_oop(oop value, outputStream* st) {
|
||||
if (value == NULL) {
|
||||
st->print_cr(" NULL");
|
||||
} else if (java_lang_String::is_instance(value)) {
|
||||
EXCEPTION_MARK;
|
||||
Handle h_value (THREAD, value);
|
||||
Symbol* sym = java_lang_String::as_symbol(h_value, CATCH);
|
||||
print_symbol(sym, st);
|
||||
sym->decrement_refcount();
|
||||
char buf[40];
|
||||
int len = java_lang_String::utf8_length(value);
|
||||
java_lang_String::as_utf8_string(value, buf, sizeof(buf));
|
||||
if (len >= (int)sizeof(buf)) {
|
||||
st->print_cr(" %s...[%d]", buf, len);
|
||||
} else {
|
||||
st->print_cr(" %s", buf);
|
||||
}
|
||||
} else {
|
||||
st->print_cr(" " PTR_FORMAT, (intptr_t) value);
|
||||
}
|
||||
|
@ -615,6 +615,7 @@ void IdealGraphPrinter::visit_node(Node *n, void *param) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
if (node->debug_orig() != NULL) {
|
||||
stringStream dorigStream;
|
||||
Node* dorig = node->debug_orig();
|
||||
@ -629,6 +630,7 @@ void IdealGraphPrinter::visit_node(Node *n, void *param) {
|
||||
}
|
||||
print_prop("debug_orig", dorigStream.as_string());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_chaitin && _chaitin != (PhaseChaitin *)0xdeadbeef) {
|
||||
buffer[0] = 0;
|
||||
|
@ -265,7 +265,7 @@ MethodHandleWalker::walk(TRAPS) {
|
||||
assert(dest == arg_state->_type, "");
|
||||
ArgToken arg = arg_state->_arg;
|
||||
ArgToken new_arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg, CHECK_(empty));
|
||||
assert(arg.token_type() >= tt_symbolic || arg.index() == new_arg.index(), "should be the same index");
|
||||
assert(!arg.has_index() || arg.index() == new_arg.index(), "should be the same index");
|
||||
debug_only(dest_klass = (klassOop)badOop);
|
||||
break;
|
||||
}
|
||||
@ -443,8 +443,10 @@ MethodHandleWalker::walk(TRAPS) {
|
||||
ret = make_conversion(T_OBJECT, rklass, Bytecodes::_checkcast, ret, CHECK_(empty));
|
||||
}
|
||||
}
|
||||
int ret_slot = arg_slot + (retain_original_args ? coll_slots : 0);
|
||||
change_argument(T_VOID, ret_slot, rtype, ret);
|
||||
if (rtype != T_VOID) {
|
||||
int ret_slot = arg_slot + (retain_original_args ? coll_slots : 0);
|
||||
change_argument(T_VOID, ret_slot, rtype, ret);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -690,9 +692,8 @@ void MethodHandleWalker::retype_raw_conversion(BasicType src, BasicType dst, boo
|
||||
// -----------------------------------------------------------------------------
|
||||
// MethodHandleCompiler
|
||||
|
||||
MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool is_invokedynamic, TRAPS)
|
||||
MethodHandleCompiler::MethodHandleCompiler(Handle root, Symbol* name, Symbol* signature, int invoke_count, bool is_invokedynamic, TRAPS)
|
||||
: MethodHandleWalker(root, is_invokedynamic, THREAD),
|
||||
_callee(callee),
|
||||
_invoke_count(invoke_count),
|
||||
_thread(THREAD),
|
||||
_bytecode(THREAD, 50),
|
||||
@ -706,8 +707,8 @@ MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int
|
||||
(void) _constants.append(NULL);
|
||||
|
||||
// Set name and signature index.
|
||||
_name_index = cpool_symbol_put(_callee->name());
|
||||
_signature_index = cpool_symbol_put(_callee->signature());
|
||||
_name_index = cpool_symbol_put(name);
|
||||
_signature_index = cpool_symbol_put(signature);
|
||||
|
||||
// Get return type klass.
|
||||
Handle first_mtype(THREAD, chain().method_type_oop());
|
||||
@ -715,7 +716,8 @@ MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int
|
||||
_rtype = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(first_mtype()), &_rklass);
|
||||
if (_rtype == T_ARRAY) _rtype = T_OBJECT;
|
||||
|
||||
int params = _callee->size_of_parameters(); // Incoming arguments plus receiver.
|
||||
ArgumentSizeComputer args(signature);
|
||||
int params = args.size() + 1; // Incoming arguments plus receiver.
|
||||
_num_params = for_invokedynamic() ? params - 1 : params; // XXX Check if callee is static?
|
||||
}
|
||||
|
||||
@ -733,7 +735,7 @@ methodHandle MethodHandleCompiler::compile(TRAPS) {
|
||||
}
|
||||
|
||||
|
||||
void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index, int args_size) {
|
||||
Bytecodes::check(op); // Are we legal?
|
||||
|
||||
switch (op) {
|
||||
@ -809,6 +811,14 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
case Bytecodes::_d2i:
|
||||
case Bytecodes::_d2l:
|
||||
case Bytecodes::_d2f:
|
||||
case Bytecodes::_iaload:
|
||||
case Bytecodes::_laload:
|
||||
case Bytecodes::_faload:
|
||||
case Bytecodes::_daload:
|
||||
case Bytecodes::_aaload:
|
||||
case Bytecodes::_baload:
|
||||
case Bytecodes::_caload:
|
||||
case Bytecodes::_saload:
|
||||
case Bytecodes::_ireturn:
|
||||
case Bytecodes::_lreturn:
|
||||
case Bytecodes::_freturn:
|
||||
@ -822,9 +832,14 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
// bi
|
||||
case Bytecodes::_ldc:
|
||||
assert(Bytecodes::format_bits(op, false) == (Bytecodes::_fmt_b|Bytecodes::_fmt_has_k), "wrong bytecode format");
|
||||
assert((char) index == index, "index does not fit in 8-bit");
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index);
|
||||
if (index == (index & 0xff)) {
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index);
|
||||
} else {
|
||||
_bytecode.push(Bytecodes::_ldc_w);
|
||||
_bytecode.push(index >> 8);
|
||||
_bytecode.push(index);
|
||||
}
|
||||
break;
|
||||
|
||||
case Bytecodes::_iload:
|
||||
@ -838,9 +853,16 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
case Bytecodes::_dstore:
|
||||
case Bytecodes::_astore:
|
||||
assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bi, "wrong bytecode format");
|
||||
assert((char) index == index, "index does not fit in 8-bit");
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index);
|
||||
if (index == (index & 0xff)) {
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index);
|
||||
} else {
|
||||
// doesn't fit in a u2
|
||||
_bytecode.push(Bytecodes::_wide);
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index >> 8);
|
||||
_bytecode.push(index);
|
||||
}
|
||||
break;
|
||||
|
||||
// bkk
|
||||
@ -848,7 +870,7 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
case Bytecodes::_ldc2_w:
|
||||
case Bytecodes::_checkcast:
|
||||
assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bkk, "wrong bytecode format");
|
||||
assert((short) index == index, "index does not fit in 16-bit");
|
||||
assert((unsigned short) index == index, "index does not fit in 16-bit");
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index >> 8);
|
||||
_bytecode.push(index);
|
||||
@ -859,12 +881,23 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
case Bytecodes::_invokespecial:
|
||||
case Bytecodes::_invokevirtual:
|
||||
assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bJJ, "wrong bytecode format");
|
||||
assert((short) index == index, "index does not fit in 16-bit");
|
||||
assert((unsigned short) index == index, "index does not fit in 16-bit");
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index >> 8);
|
||||
_bytecode.push(index);
|
||||
break;
|
||||
|
||||
case Bytecodes::_invokeinterface:
|
||||
assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bJJ, "wrong bytecode format");
|
||||
assert((unsigned short) index == index, "index does not fit in 16-bit");
|
||||
assert(args_size > 0, "valid args_size");
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index >> 8);
|
||||
_bytecode.push(index);
|
||||
_bytecode.push(args_size);
|
||||
_bytecode.push(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
@ -983,7 +1016,8 @@ MethodHandleCompiler::make_conversion(BasicType type, klassOop tk, Bytecodes::Co
|
||||
const ArgToken& src, TRAPS) {
|
||||
|
||||
BasicType srctype = src.basic_type();
|
||||
int index = src.index();
|
||||
TokenType tt = src.token_type();
|
||||
int index = -1;
|
||||
|
||||
switch (op) {
|
||||
case Bytecodes::_i2l:
|
||||
@ -1004,18 +1038,31 @@ MethodHandleCompiler::make_conversion(BasicType type, klassOop tk, Bytecodes::Co
|
||||
case Bytecodes::_d2i:
|
||||
case Bytecodes::_d2l:
|
||||
case Bytecodes::_d2f:
|
||||
emit_load(srctype, index);
|
||||
if (tt == tt_constant) {
|
||||
emit_load_constant(src);
|
||||
} else {
|
||||
emit_load(srctype, src.index());
|
||||
}
|
||||
stack_pop(srctype); // pop the src type
|
||||
emit_bc(op);
|
||||
stack_push(type); // push the dest value
|
||||
if (srctype != type)
|
||||
if (tt != tt_constant)
|
||||
index = src.index();
|
||||
if (srctype != type || index == -1)
|
||||
index = new_local_index(type);
|
||||
emit_store(type, index);
|
||||
break;
|
||||
|
||||
case Bytecodes::_checkcast:
|
||||
emit_load(srctype, index);
|
||||
if (tt == tt_constant) {
|
||||
emit_load_constant(src);
|
||||
} else {
|
||||
emit_load(srctype, src.index());
|
||||
index = src.index();
|
||||
}
|
||||
emit_bc(op, cpool_klass_put(tk));
|
||||
if (index == -1)
|
||||
index = new_local_index(type);
|
||||
emit_store(srctype, index);
|
||||
break;
|
||||
|
||||
@ -1058,6 +1105,11 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
|
||||
Symbol* name = m->name();
|
||||
Symbol* signature = m->signature();
|
||||
|
||||
// Count the number of arguments, not the size
|
||||
ArgumentCount asc(signature);
|
||||
assert(argc == asc.size() + ((op == Bytecodes::_invokestatic || op == Bytecodes::_invokedynamic) ? 0 : 1),
|
||||
"argc mismatch");
|
||||
|
||||
if (tailcall) {
|
||||
// Actually, in order to make these methods more recognizable,
|
||||
// let's put them in holder class MethodHandle. That way stack
|
||||
@ -1106,9 +1158,13 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
|
||||
case Bytecodes::_invokevirtual:
|
||||
emit_bc(op, methodref_index);
|
||||
break;
|
||||
case Bytecodes::_invokeinterface:
|
||||
Unimplemented();
|
||||
|
||||
case Bytecodes::_invokeinterface: {
|
||||
ArgumentSizeComputer asc(signature);
|
||||
emit_bc(op, methodref_index, asc.size() + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
@ -1117,6 +1173,7 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
|
||||
// Otherwise, make a recursive call to some helper routine.
|
||||
BasicType rbt = m->result_type();
|
||||
if (rbt == T_ARRAY) rbt = T_OBJECT;
|
||||
stack_push(rbt); // The return value is already pushed onto the stack.
|
||||
ArgToken ret;
|
||||
if (tailcall) {
|
||||
if (rbt != _rtype) {
|
||||
@ -1171,7 +1228,6 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
|
||||
ret = ArgToken(); // Dummy return value.
|
||||
}
|
||||
else {
|
||||
stack_push(rbt); // The return value is already pushed onto the stack.
|
||||
int index = new_local_index(rbt);
|
||||
switch (rbt) {
|
||||
case T_BOOLEAN: case T_BYTE: case T_CHAR: case T_SHORT:
|
||||
@ -1196,8 +1252,32 @@ MethodHandleCompiler::make_fetch(BasicType type, klassOop tk, Bytecodes::Code op
|
||||
const MethodHandleWalker::ArgToken& base,
|
||||
const MethodHandleWalker::ArgToken& offset,
|
||||
TRAPS) {
|
||||
Unimplemented();
|
||||
return ArgToken();
|
||||
switch (base.token_type()) {
|
||||
case tt_parameter:
|
||||
case tt_temporary:
|
||||
emit_load(base.basic_type(), base.index());
|
||||
break;
|
||||
case tt_constant:
|
||||
emit_load_constant(base);
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
switch (offset.token_type()) {
|
||||
case tt_parameter:
|
||||
case tt_temporary:
|
||||
emit_load(offset.basic_type(), offset.index());
|
||||
break;
|
||||
case tt_constant:
|
||||
emit_load_constant(offset);
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
emit_bc(op);
|
||||
int index = new_local_index(type);
|
||||
emit_store(type, index);
|
||||
return ArgToken(tt_temporary, type, index);
|
||||
}
|
||||
|
||||
|
||||
@ -1372,12 +1452,10 @@ private:
|
||||
return s;
|
||||
}
|
||||
ArgToken token(const char* str) {
|
||||
jvalue string_con;
|
||||
string_con.j = (intptr_t) str;
|
||||
return ArgToken(tt_symbolic, T_LONG, string_con);
|
||||
return ArgToken(str);
|
||||
}
|
||||
const char* string(ArgToken token) {
|
||||
return (const char*) (intptr_t) token.get_jlong();
|
||||
return token.str();
|
||||
}
|
||||
void start_params() {
|
||||
_param_state <<= 1;
|
||||
|
@ -126,26 +126,34 @@ public:
|
||||
Handle _handle;
|
||||
|
||||
public:
|
||||
ArgToken(TokenType tt = tt_illegal) : _tt(tt) {}
|
||||
ArgToken(TokenType tt, BasicType bt, jvalue value) : _tt(tt), _bt(bt), _value(value) {}
|
||||
ArgToken(TokenType tt = tt_illegal) : _tt(tt) {
|
||||
assert(tt == tt_illegal || tt == tt_void, "invalid token type");
|
||||
}
|
||||
|
||||
ArgToken(TokenType tt, BasicType bt, int index) : _tt(tt), _bt(bt) {
|
||||
assert(_tt == tt_parameter || _tt == tt_temporary, "must have index");
|
||||
_value.i = index;
|
||||
}
|
||||
|
||||
ArgToken(TokenType tt, BasicType bt, Handle value) : _tt(tt), _bt(bt) {
|
||||
_handle = value;
|
||||
ArgToken(BasicType bt, jvalue value) : _tt(tt_constant), _bt(bt), _value(value) {}
|
||||
ArgToken(BasicType bt, Handle value) : _tt(tt_constant), _bt(bt), _handle(value) {}
|
||||
|
||||
|
||||
ArgToken(const char* str) : _tt(tt_symbolic), _bt(T_LONG) {
|
||||
_value.j = (intptr_t)str;
|
||||
}
|
||||
|
||||
TokenType token_type() const { return _tt; }
|
||||
BasicType basic_type() const { return _bt; }
|
||||
int index() const { return _value.i; }
|
||||
Handle object() const { return _handle; }
|
||||
bool has_index() const { return _tt == tt_parameter || _tt == tt_temporary; }
|
||||
int index() const { assert(has_index(), "must have index");; return _value.i; }
|
||||
Handle object() const { assert(_tt == tt_constant, "value type"); return _handle; }
|
||||
const char* str() const { assert(_tt == tt_symbolic, "string type"); return (const char*)_value.j; }
|
||||
|
||||
jint get_jint() const { return _value.i; }
|
||||
jlong get_jlong() const { return _value.j; }
|
||||
jfloat get_jfloat() const { return _value.f; }
|
||||
jdouble get_jdouble() const { return _value.d; }
|
||||
jint get_jint() const { assert(_tt == tt_constant, "value types"); return _value.i; }
|
||||
jlong get_jlong() const { assert(_tt == tt_constant, "value types"); return _value.j; }
|
||||
jfloat get_jfloat() const { assert(_tt == tt_constant, "value types"); return _value.f; }
|
||||
jdouble get_jdouble() const { assert(_tt == tt_constant, "value types"); return _value.d; }
|
||||
};
|
||||
|
||||
// Abstract interpretation state:
|
||||
@ -256,7 +264,6 @@ public:
|
||||
// The IR happens to be JVM bytecodes.
|
||||
class MethodHandleCompiler : public MethodHandleWalker {
|
||||
private:
|
||||
methodHandle _callee;
|
||||
int _invoke_count; // count the original call site has been executed
|
||||
KlassHandle _rklass; // Return type for casting.
|
||||
BasicType _rtype;
|
||||
@ -404,7 +411,7 @@ private:
|
||||
return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index);
|
||||
}
|
||||
|
||||
void emit_bc(Bytecodes::Code op, int index = 0);
|
||||
void emit_bc(Bytecodes::Code op, int index = 0, int args_size = -1);
|
||||
void emit_load(BasicType bt, int index);
|
||||
void emit_store(BasicType bt, int index);
|
||||
void emit_load_constant(ArgToken arg);
|
||||
@ -414,10 +421,10 @@ private:
|
||||
}
|
||||
virtual ArgToken make_oop_constant(oop con, TRAPS) {
|
||||
Handle h(THREAD, con);
|
||||
return ArgToken(tt_constant, T_OBJECT, h);
|
||||
return ArgToken(T_OBJECT, h);
|
||||
}
|
||||
virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) {
|
||||
return ArgToken(tt_constant, type, *con);
|
||||
return ArgToken(type, *con);
|
||||
}
|
||||
|
||||
virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS);
|
||||
@ -431,7 +438,7 @@ private:
|
||||
methodHandle get_method_oop(TRAPS) const;
|
||||
|
||||
public:
|
||||
MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool for_invokedynamic, TRAPS);
|
||||
MethodHandleCompiler(Handle root, Symbol* name, Symbol* signature, int invoke_count, bool for_invokedynamic, TRAPS);
|
||||
|
||||
// Compile the given MH chain into bytecode.
|
||||
methodHandle compile(TRAPS);
|
||||
|
@ -25,9 +25,11 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/oopMapCache.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "prims/methodHandles.hpp"
|
||||
#include "prims/methodHandleWalk.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/reflection.hpp"
|
||||
#include "runtime/signature.hpp"
|
||||
@ -2599,6 +2601,50 @@ void MethodHandles::ensure_vmlayout_field(Handle target, TRAPS) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
|
||||
extern "C"
|
||||
void print_method_handle(oop mh);
|
||||
|
||||
static void stress_method_handle_walk_impl(Handle mh, TRAPS) {
|
||||
if (StressMethodHandleWalk) {
|
||||
// Exercise the MethodHandleWalk code in various ways and validate
|
||||
// the resulting method oop. Some of these produce output so they
|
||||
// are guarded under Verbose.
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
if (Verbose) {
|
||||
print_method_handle(mh());
|
||||
}
|
||||
TempNewSymbol name = SymbolTable::new_symbol("invoke", CHECK);
|
||||
Handle mt = java_lang_invoke_MethodHandle::type(mh());
|
||||
TempNewSymbol signature = java_lang_invoke_MethodType::as_signature(mt(), true, CHECK);
|
||||
MethodHandleCompiler mhc(mh, name, signature, 10000, false, CHECK);
|
||||
methodHandle m = mhc.compile(CHECK);
|
||||
if (Verbose) {
|
||||
m->print_codes();
|
||||
}
|
||||
InterpreterOopMap mask;
|
||||
OopMapCache::compute_one_oop_map(m, m->code_size() - 1, &mask);
|
||||
}
|
||||
}
|
||||
|
||||
static void stress_method_handle_walk(Handle mh, TRAPS) {
|
||||
stress_method_handle_walk_impl(mh, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
oop ex = PENDING_EXCEPTION;
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
tty->print("StressMethodHandleWalk: ");
|
||||
java_lang_Throwable::print(ex, tty);
|
||||
tty->cr();
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
static void stress_method_handle_walk(Handle mh, TRAPS) {}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Here are the native methods on sun.invoke.MethodHandleImpl.
|
||||
// They are the private interface between this JVM and the HotSpot-specific
|
||||
@ -2666,6 +2712,7 @@ JVM_ENTRY(void, MHN_init_DMH(JNIEnv *env, jobject igcls, jobject mh_jh,
|
||||
}
|
||||
|
||||
MethodHandles::init_DirectMethodHandle(mh, m, (do_dispatch != JNI_FALSE), CHECK);
|
||||
stress_method_handle_walk(mh, CHECK);
|
||||
}
|
||||
JVM_END
|
||||
|
||||
@ -2694,11 +2741,11 @@ JVM_ENTRY(void, MHN_init_BMH(JNIEnv *env, jobject igcls, jobject mh_jh,
|
||||
receiver_limit,
|
||||
decode_flags,
|
||||
CHECK);
|
||||
return;
|
||||
} else {
|
||||
// Build a BMH on top of a DMH or another BMH:
|
||||
MethodHandles::init_BoundMethodHandle(mh, target, argnum, CHECK);
|
||||
}
|
||||
|
||||
// Build a BMH on top of a DMH or another BMH:
|
||||
MethodHandles::init_BoundMethodHandle(mh, target, argnum, CHECK);
|
||||
stress_method_handle_walk(mh, CHECK);
|
||||
}
|
||||
JVM_END
|
||||
|
||||
@ -2716,6 +2763,7 @@ JVM_ENTRY(void, MHN_init_AMH(JNIEnv *env, jobject igcls, jobject mh_jh,
|
||||
assert(java_lang_invoke_MethodHandle::vmentry(mh()) == NULL, "must be safely null");
|
||||
|
||||
MethodHandles::init_AdapterMethodHandle(mh, target, argnum, CHECK);
|
||||
stress_method_handle_walk(mh, CHECK);
|
||||
}
|
||||
JVM_END
|
||||
|
||||
|
@ -3724,6 +3724,9 @@ class CommandLineFlags {
|
||||
diagnostic(bool, OptimizeMethodHandles, true, \
|
||||
"when constructing method handles, try to improve them") \
|
||||
\
|
||||
develop(bool, StressMethodHandleWalk, false, \
|
||||
"Process all method handles with MethodHandleWalk") \
|
||||
\
|
||||
diagnostic(bool, UseRicochetFrames, true, \
|
||||
"use ricochet stack frames for method handle combination, " \
|
||||
"if the platform supports them") \
|
||||
|
@ -2861,6 +2861,7 @@ void JavaThread::trace_frames() {
|
||||
}
|
||||
|
||||
|
||||
#ifdef ASSERT
|
||||
// Print or validate the layout of stack frames
|
||||
void JavaThread::print_frame_layout(int depth, bool validate_only) {
|
||||
ResourceMark rm;
|
||||
@ -2878,7 +2879,7 @@ void JavaThread::print_frame_layout(int depth, bool validate_only) {
|
||||
values.print();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void JavaThread::trace_stack_from(vframe* start_vf) {
|
||||
ResourceMark rm;
|
||||
|
@ -783,6 +783,7 @@ static inline uint64_t cast_uint64_t(size_t x)
|
||||
nonstatic_field(nmethod, _osr_link, nmethod*) \
|
||||
nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \
|
||||
nonstatic_field(nmethod, _scavenge_root_state, jbyte) \
|
||||
nonstatic_field(nmethod, _state, unsigned char) \
|
||||
nonstatic_field(nmethod, _exception_offset, int) \
|
||||
nonstatic_field(nmethod, _deoptimize_offset, int) \
|
||||
nonstatic_field(nmethod, _orig_pc_offset, int) \
|
||||
@ -800,6 +801,8 @@ static inline uint64_t cast_uint64_t(size_t x)
|
||||
nonstatic_field(nmethod, _osr_entry_point, address) \
|
||||
nonstatic_field(nmethod, _lock_count, jint) \
|
||||
nonstatic_field(nmethod, _stack_traversal_mark, long) \
|
||||
nonstatic_field(nmethod, _compile_id, int) \
|
||||
nonstatic_field(nmethod, _marked_for_deoptimization, bool) \
|
||||
\
|
||||
/********************************/ \
|
||||
/* JavaCalls (NOTE: incomplete) */ \
|
||||
@ -1310,11 +1313,13 @@ static inline uint64_t cast_uint64_t(size_t x)
|
||||
\
|
||||
declare_toplevel_type(CodeBlob) \
|
||||
declare_type(BufferBlob, CodeBlob) \
|
||||
declare_type(nmethod, CodeBlob) \
|
||||
declare_type(AdapterBlob, BufferBlob) \
|
||||
declare_type(nmethod, CodeBlob) \
|
||||
declare_type(RuntimeStub, CodeBlob) \
|
||||
declare_type(SingletonBlob, CodeBlob) \
|
||||
declare_type(SafepointBlob, SingletonBlob) \
|
||||
declare_type(DeoptimizationBlob, SingletonBlob) \
|
||||
declare_type(RicochetBlob, SingletonBlob) \
|
||||
declare_c2_type(ExceptionBlob, SingletonBlob) \
|
||||
declare_c2_type(UncommonTrapBlob, CodeBlob) \
|
||||
\
|
||||
|
Loading…
x
Reference in New Issue
Block a user