提交 21b5cc64 编写于 作者: D dbuck

8174962: Better interface invocations

Reviewed-by: jrose, coleenp, ahgross, acorn, vlivanov
上级 6bcabbbc
/* /*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -40,10 +40,10 @@ public class CompiledICHolder extends VMObject { ...@@ -40,10 +40,10 @@ public class CompiledICHolder extends VMObject {
} }
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
Type type = db.lookupType("CompiledICHolder"); Type type = db.lookupType("CompiledICHolder");
holderMethod = new MetadataField(type.getAddressField("_holder_method"), 0); holderMetadata = new MetadataField(type.getAddressField("_holder_metadata"), 0);
holderKlass = new MetadataField(type.getAddressField("_holder_klass"), 0); holderKlass = new MetadataField(type.getAddressField("_holder_klass"), 0);
headerSize = type.getSize(); headerSize = type.getSize();
} }
public CompiledICHolder(Address addr) { public CompiledICHolder(Address addr) {
...@@ -55,12 +55,12 @@ public class CompiledICHolder extends VMObject { ...@@ -55,12 +55,12 @@ public class CompiledICHolder extends VMObject {
private static long headerSize; private static long headerSize;
// Fields // Fields
private static MetadataField holderMethod; private static MetadataField holderMetadata;
private static MetadataField holderKlass; private static MetadataField holderKlass;
// Accessors for declared fields // Accessors for declared fields
public Method getHolderMethod() { return (Method) holderMethod.getValue(this); } public Metadata getHolderMetadata() { return (Metadata) holderMetadata.getValue(this); }
public Klass getHolderKlass() { return (Klass) holderKlass.getValue(this); } public Klass getHolderKlass() { return (Klass) holderKlass.getValue(this); }
public void printValueOn(PrintStream tty) { public void printValueOn(PrintStream tty) {
tty.print("CompiledICHolder"); tty.print("CompiledICHolder");
......
/* /*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012, 2014 SAP AG. All rights reserved. * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
...@@ -1193,7 +1193,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm ...@@ -1193,7 +1193,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
// Argument is valid and klass is as expected, continue. // Argument is valid and klass is as expected, continue.
// Extract method from inline cache, verified entry point needs it. // Extract method from inline cache, verified entry point needs it.
__ ld(R19_method, CompiledICHolder::holder_method_offset(), ic); __ ld(R19_method, CompiledICHolder::holder_metadata_offset(), ic);
assert(R19_method == ic, "the inline cache register is dead here"); assert(R19_method == ic, "the inline cache register is dead here");
__ ld(code, method_(code)); __ ld(code, method_(code));
......
/* /*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -2183,9 +2183,10 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, ...@@ -2183,9 +2183,10 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
Register method_result, Register method_result,
Register scan_temp, Register scan_temp,
Register sethi_temp, Register sethi_temp,
Label& L_no_such_interface) { Label& L_no_such_interface,
bool return_method) {
assert_different_registers(recv_klass, intf_klass, method_result, scan_temp); assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
assert(itable_index.is_constant() || itable_index.as_register() == method_result, assert(!return_method || itable_index.is_constant() || itable_index.as_register() == method_result,
"caller must use same register for non-constant itable index as for method"); "caller must use same register for non-constant itable index as for method");
Label L_no_such_interface_restore; Label L_no_such_interface_restore;
...@@ -2229,11 +2230,13 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, ...@@ -2229,11 +2230,13 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
} }
add(recv_klass, scan_temp, scan_temp); add(recv_klass, scan_temp, scan_temp);
// Adjust recv_klass by scaled itable_index, so we can free itable_index. if (return_method) {
RegisterOrConstant itable_offset = itable_index; // Adjust recv_klass by scaled itable_index, so we can free itable_index.
itable_offset = regcon_sll_ptr(itable_index, exact_log2(itableMethodEntry::size() * wordSize), itable_offset); RegisterOrConstant itable_offset = itable_index;
itable_offset = regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes(), itable_offset); itable_offset = regcon_sll_ptr(itable_index, exact_log2(itableMethodEntry::size() * wordSize), itable_offset);
add(recv_klass, ensure_simm13_or_reg(itable_offset, sethi_temp), recv_klass); itable_offset = regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes(), itable_offset);
add(recv_klass, ensure_simm13_or_reg(itable_offset, sethi_temp), recv_klass);
}
// for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) { // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
// if (scan->interface() == intf) { // if (scan->interface() == intf) {
...@@ -2268,12 +2271,14 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, ...@@ -2268,12 +2271,14 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
bind(L_found_method); bind(L_found_method);
// Got a hit. if (return_method) {
int ito_offset = itableOffsetEntry::offset_offset_in_bytes(); // Got a hit.
// scan_temp[-scan_step] points to the vtable offset we need int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
ito_offset -= scan_step; // scan_temp[-scan_step] points to the vtable offset we need
lduw(scan_temp, ito_offset, scan_temp); ito_offset -= scan_step;
ld_ptr(recv_klass, scan_temp, method_result); lduw(scan_temp, ito_offset, scan_temp);
ld_ptr(recv_klass, scan_temp, method_result);
}
if (did_save) { if (did_save) {
Label L_done; Label L_done;
......
/* /*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -1347,7 +1347,8 @@ public: ...@@ -1347,7 +1347,8 @@ public:
RegisterOrConstant itable_index, RegisterOrConstant itable_index,
Register method_result, Register method_result,
Register temp_reg, Register temp2_reg, Register temp_reg, Register temp2_reg,
Label& no_such_interface); Label& no_such_interface,
bool return_method = true);
// virtual method calling // virtual method calling
void lookup_virtual_method(Register recv_klass, void lookup_virtual_method(Register recv_klass,
......
/* /*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -1045,7 +1045,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm ...@@ -1045,7 +1045,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
Label ok, ok2; Label ok, ok2;
__ brx(Assembler::equal, false, Assembler::pt, ok); __ brx(Assembler::equal, false, Assembler::pt, ok);
__ delayed()->ld_ptr(G5_method, CompiledICHolder::holder_method_offset(), G5_method); __ delayed()->ld_ptr(G5_method, CompiledICHolder::holder_metadata_offset(), G5_method);
__ jump_to(ic_miss, G3_scratch); __ jump_to(ic_miss, G3_scratch);
__ delayed()->nop(); __ delayed()->nop();
......
/* /*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -3165,15 +3165,15 @@ void TemplateTable::invokeinterface(int byte_no) { ...@@ -3165,15 +3165,15 @@ void TemplateTable::invokeinterface(int byte_no) {
assert(byte_no == f1_byte, "use this argument"); assert(byte_no == f1_byte, "use this argument");
const Register Rinterface = G1_scratch; const Register Rinterface = G1_scratch;
const Register Rmethod = Lscratch;
const Register Rret = G3_scratch; const Register Rret = G3_scratch;
const Register Rindex = Lscratch;
const Register O0_recv = O0; const Register O0_recv = O0;
const Register O1_flags = O1; const Register O1_flags = O1;
const Register O2_Klass = O2; const Register O2_Klass = O2;
const Register Rscratch = G4_scratch; const Register Rscratch = G4_scratch;
assert_different_registers(Rscratch, G5_method); assert_different_registers(Rscratch, G5_method);
prepare_invoke(byte_no, Rinterface, Rret, Rindex, O0_recv, O1_flags); prepare_invoke(byte_no, Rinterface, Rret, Rmethod, O0_recv, O1_flags);
// get receiver klass // get receiver klass
__ null_check(O0_recv, oopDesc::klass_offset_in_bytes()); __ null_check(O0_recv, oopDesc::klass_offset_in_bytes());
...@@ -3193,58 +3193,40 @@ void TemplateTable::invokeinterface(int byte_no) { ...@@ -3193,58 +3193,40 @@ void TemplateTable::invokeinterface(int byte_no) {
__ bind(notMethod); __ bind(notMethod);
__ profile_virtual_call(O2_Klass, O4);
//
// find entry point to call
//
// compute start of first itableOffsetEntry (which is at end of vtable)
const int base = InstanceKlass::vtable_start_offset() * wordSize;
Label search;
Register Rtemp = O1_flags; Register Rtemp = O1_flags;
__ ld(O2_Klass, InstanceKlass::vtable_length_offset() * wordSize, Rtemp); Label L_no_such_interface;
if (align_object_offset(1) > 1) {
__ round_to(Rtemp, align_object_offset(1));
}
__ sll(Rtemp, LogBytesPerWord, Rtemp); // Rscratch *= 4;
if (Assembler::is_simm13(base)) {
__ add(Rtemp, base, Rtemp);
} else {
__ set(base, Rscratch);
__ add(Rscratch, Rtemp, Rtemp);
}
__ add(O2_Klass, Rtemp, Rscratch);
__ bind(search); // Receiver subtype check against REFC.
__ lookup_interface_method(// inputs: rec. class, interface, itable index
O2_Klass, Rinterface, noreg,
// outputs: temp reg1, temp reg2, temp reg3
G5_method, Rscratch, Rtemp,
L_no_such_interface,
/*return_method=*/false);
__ ld_ptr(Rscratch, itableOffsetEntry::interface_offset_in_bytes(), Rtemp); __ profile_virtual_call(O2_Klass, O4);
{
Label ok;
// Check that entry is non-null. Null entries are probably a bytecode //
// problem. If the interface isn't implemented by the receiver class, // find entry point to call
// the VM should throw IncompatibleClassChangeError. linkResolver checks //
// this too but that's only if the entry isn't already resolved, so we
// need to check again.
__ br_notnull_short( Rtemp, Assembler::pt, ok);
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
__ should_not_reach_here();
__ bind(ok);
}
__ cmp(Rinterface, Rtemp); // Get declaring interface class from method
__ brx(Assembler::notEqual, true, Assembler::pn, search); __ ld_ptr(Rmethod, Method::const_offset(), Rinterface);
__ delayed()->add(Rscratch, itableOffsetEntry::size() * wordSize, Rscratch); __ ld_ptr(Rinterface, ConstMethod::constants_offset(), Rinterface);
__ ld_ptr(Rinterface, ConstantPool::pool_holder_offset_in_bytes(), Rinterface);
// entry found and Rscratch points to it // Get itable index from method
__ ld(Rscratch, itableOffsetEntry::offset_offset_in_bytes(), Rscratch); const Register Rindex = G5_method;
__ ld(Rmethod, Method::itable_index_offset(), Rindex);
__ sub(Rindex, Method::itable_index_max, Rindex);
__ neg(Rindex);
assert(itableMethodEntry::method_offset_in_bytes() == 0, "adjust instruction below"); __ lookup_interface_method(// inputs: rec. class, interface, itable index
__ sll(Rindex, exact_log2(itableMethodEntry::size() * wordSize), Rindex); // Rindex *= 8; O2_Klass, Rinterface, Rindex,
__ add(Rscratch, Rindex, Rscratch); // outputs: method, scan temp reg, temp reg
__ ld_ptr(O2_Klass, Rscratch, G5_method); G5_method, Rscratch, Rtemp,
L_no_such_interface);
// Check for abstract method error. // Check for abstract method error.
{ {
...@@ -3260,6 +3242,10 @@ void TemplateTable::invokeinterface(int byte_no) { ...@@ -3260,6 +3242,10 @@ void TemplateTable::invokeinterface(int byte_no) {
__ profile_arguments_type(G5_method, Rcall, Gargs, true); __ profile_arguments_type(G5_method, Rcall, Gargs, true);
__ call_from_interpreter(Rcall, Gargs, Rret); __ call_from_interpreter(Rcall, Gargs, Rret);
__ bind(L_no_such_interface);
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
__ should_not_reach_here();
} }
void TemplateTable::invokehandle(int byte_no) { void TemplateTable::invokehandle(int byte_no) {
......
/* /*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "code/vtableStubs.hpp" #include "code/vtableStubs.hpp"
#include "interp_masm_sparc.hpp" #include "interp_masm_sparc.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/compiledICHolder.hpp"
#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.hpp"
#include "oops/klassVtable.hpp" #include "oops/klassVtable.hpp"
#include "runtime/sharedRuntime.hpp" #include "runtime/sharedRuntime.hpp"
...@@ -140,7 +141,8 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { ...@@ -140,7 +141,8 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
MacroAssembler* masm = new MacroAssembler(&cb); MacroAssembler* masm = new MacroAssembler(&cb);
Register G3_Klass = G3_scratch; Register G3_Klass = G3_scratch;
Register G5_interface = G5; // Passed in as an argument Register G5_icholder = G5; // Passed in as an argument
Register G4_interface = G4_scratch;
Label search; Label search;
// Entry arguments: // Entry arguments:
...@@ -164,14 +166,26 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { ...@@ -164,14 +166,26 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
} }
#endif /* PRODUCT */ #endif /* PRODUCT */
Label throw_icce; Label L_no_such_interface;
Register L5_method = L5; Register L5_method = L5;
// Receiver subtype check against REFC.
__ ld_ptr(G5_icholder, CompiledICHolder::holder_klass_offset(), G4_interface);
__ lookup_interface_method(// inputs: rec. class, interface, itable index
G3_Klass, G4_interface, itable_index,
// outputs: scan temp. reg1, scan temp. reg2
L5_method, L2, L3,
L_no_such_interface,
/*return_method=*/ false);
// Get Method* and entrypoint for compiler
__ ld_ptr(G5_icholder, CompiledICHolder::holder_metadata_offset(), G4_interface);
__ lookup_interface_method(// inputs: rec. class, interface, itable index __ lookup_interface_method(// inputs: rec. class, interface, itable index
G3_Klass, G5_interface, itable_index, G3_Klass, G4_interface, itable_index,
// outputs: method, scan temp. reg // outputs: method, scan temp. reg
L5_method, L2, L3, L5_method, L2, L3,
throw_icce); L_no_such_interface);
#ifndef PRODUCT #ifndef PRODUCT
if (DebugVtables) { if (DebugVtables) {
...@@ -197,7 +211,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { ...@@ -197,7 +211,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
__ JMP(G3_scratch, 0); __ JMP(G3_scratch, 0);
__ delayed()->nop(); __ delayed()->nop();
__ bind(throw_icce); __ bind(L_no_such_interface);
AddressLiteral icce(StubRoutines::throw_IncompatibleClassChangeError_entry()); AddressLiteral icce(StubRoutines::throw_IncompatibleClassChangeError_entry());
__ jump_to(icce, G3_scratch); __ jump_to(icce, G3_scratch);
__ delayed()->restore(); __ delayed()->restore();
...@@ -232,7 +246,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { ...@@ -232,7 +246,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
MacroAssembler::instr_size_for_decode_klass_not_null() : 0); MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
return basic + slop; return basic + slop;
} else { } else {
const int basic = (28 LP64_ONLY(+ 6)) * BytesPerInstWord + const int basic = (48 LP64_ONLY(+ 6)) * BytesPerInstWord +
// shift;add for load_klass (only shift with zero heap based) // shift;add for load_klass (only shift with zero heap based)
(UseCompressedClassPointers ? (UseCompressedClassPointers ?
MacroAssembler::instr_size_for_decode_klass_not_null() : 0); MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
......
/* /*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -4853,8 +4853,13 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, ...@@ -4853,8 +4853,13 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
RegisterOrConstant itable_index, RegisterOrConstant itable_index,
Register method_result, Register method_result,
Register scan_temp, Register scan_temp,
Label& L_no_such_interface) { Label& L_no_such_interface,
assert_different_registers(recv_klass, intf_klass, method_result, scan_temp); bool return_method) {
assert_different_registers(recv_klass, intf_klass, scan_temp);
assert_different_registers(method_result, intf_klass, scan_temp);
assert(recv_klass != method_result || !return_method,
"recv_klass can be destroyed when method isn't needed");
assert(itable_index.is_constant() || itable_index.as_register() == method_result, assert(itable_index.is_constant() || itable_index.as_register() == method_result,
"caller must use same register for non-constant itable index as for method"); "caller must use same register for non-constant itable index as for method");
...@@ -4876,9 +4881,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, ...@@ -4876,9 +4881,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
round_to(scan_temp, BytesPerLong); round_to(scan_temp, BytesPerLong);
} }
// Adjust recv_klass by scaled itable_index, so we can free itable_index. if (return_method) {
assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below"); // Adjust recv_klass by scaled itable_index, so we can free itable_index.
lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off)); assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));
}
// for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) { // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
// if (scan->interface() == intf) { // if (scan->interface() == intf) {
...@@ -4912,9 +4919,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, ...@@ -4912,9 +4919,11 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
bind(found_method); bind(found_method);
// Got a hit. if (return_method) {
movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes())); // Got a hit.
movptr(method_result, Address(recv_klass, scan_temp, Address::times_1)); movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
movptr(method_result, Address(recv_klass, scan_temp, Address::times_1));
}
} }
......
/* /*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -525,7 +525,8 @@ class MacroAssembler: public Assembler { ...@@ -525,7 +525,8 @@ class MacroAssembler: public Assembler {
RegisterOrConstant itable_index, RegisterOrConstant itable_index,
Register method_result, Register method_result,
Register scan_temp, Register scan_temp,
Label& no_such_interface); Label& no_such_interface,
bool return_method = true);
// virtual method calling // virtual method calling
void lookup_virtual_method(Register recv_klass, void lookup_virtual_method(Register recv_klass,
......
/* /*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -955,7 +955,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm ...@@ -955,7 +955,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
Label missed; Label missed;
__ movptr(temp, Address(receiver, oopDesc::klass_offset_in_bytes())); __ movptr(temp, Address(receiver, oopDesc::klass_offset_in_bytes()));
__ cmpptr(temp, Address(holder, CompiledICHolder::holder_klass_offset())); __ cmpptr(temp, Address(holder, CompiledICHolder::holder_klass_offset()));
__ movptr(rbx, Address(holder, CompiledICHolder::holder_method_offset())); __ movptr(rbx, Address(holder, CompiledICHolder::holder_metadata_offset()));
__ jcc(Assembler::notEqual, missed); __ jcc(Assembler::notEqual, missed);
// Method might have been compiled since the call site was patched to // Method might have been compiled since the call site was patched to
// interpreted if that is the case treat it as a miss so we can get // interpreted if that is the case treat it as a miss so we can get
......
/* /*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -869,7 +869,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm ...@@ -869,7 +869,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
{ {
__ load_klass(temp, receiver); __ load_klass(temp, receiver);
__ cmpptr(temp, Address(holder, CompiledICHolder::holder_klass_offset())); __ cmpptr(temp, Address(holder, CompiledICHolder::holder_klass_offset()));
__ movptr(rbx, Address(holder, CompiledICHolder::holder_method_offset())); __ movptr(rbx, Address(holder, CompiledICHolder::holder_metadata_offset()));
__ jcc(Assembler::equal, ok); __ jcc(Assembler::equal, ok);
__ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
......
/* /*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -3099,11 +3099,11 @@ void TemplateTable::fast_invokevfinal(int byte_no) { ...@@ -3099,11 +3099,11 @@ void TemplateTable::fast_invokevfinal(int byte_no) {
void TemplateTable::invokeinterface(int byte_no) { void TemplateTable::invokeinterface(int byte_no) {
transition(vtos, vtos); transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument"); assert(byte_no == f1_byte, "use this argument");
prepare_invoke(byte_no, rax, rbx, // get f1 Klass*, f2 itable index prepare_invoke(byte_no, rax, rbx, // get f1 Klass*, f2 Method*
rcx, rdx); // recv, flags rcx, rdx); // recv, flags
// rax: interface klass (from f1) // rax: reference klass (from f1)
// rbx: itable index (from f2) // rbx: method (from f2)
// rcx: receiver // rcx: receiver
// rdx: flags // rdx: flags
...@@ -3124,10 +3124,29 @@ void TemplateTable::invokeinterface(int byte_no) { ...@@ -3124,10 +3124,29 @@ void TemplateTable::invokeinterface(int byte_no) {
__ null_check(rcx, oopDesc::klass_offset_in_bytes()); __ null_check(rcx, oopDesc::klass_offset_in_bytes());
__ load_klass(rdx, rcx); __ load_klass(rdx, rcx);
Label no_such_interface, no_such_method;
// Receiver subtype check against REFC.
// Superklass in rax. Subklass in rdx. Blows rcx, rdi.
__ lookup_interface_method(// inputs: rec. class, interface, itable index
rdx, rax, noreg,
// outputs: scan temp. reg, scan temp. reg
rsi, rdi,
no_such_interface,
/*return_method=*/false);
// profile this call // profile this call
__ restore_bcp(); // rbcp was destroyed by receiver type check
__ profile_virtual_call(rdx, rsi, rdi); __ profile_virtual_call(rdx, rsi, rdi);
Label no_such_interface, no_such_method; // Get declaring interface class from method, and itable index
__ movptr(rax, Address(rbx, Method::const_offset()));
__ movptr(rax, Address(rax, ConstMethod::constants_offset()));
__ movptr(rax, Address(rax, ConstantPool::pool_holder_offset_in_bytes()));
__ movl(rbx, Address(rbx, Method::itable_index_offset()));
__ subl(rbx, Method::itable_index_max);
__ negl(rbx);
__ lookup_interface_method(// inputs: rec. class, interface, itable index __ lookup_interface_method(// inputs: rec. class, interface, itable index
rdx, rax, rbx, rdx, rax, rbx,
......
/* /*
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -3150,11 +3150,11 @@ void TemplateTable::fast_invokevfinal(int byte_no) { ...@@ -3150,11 +3150,11 @@ void TemplateTable::fast_invokevfinal(int byte_no) {
void TemplateTable::invokeinterface(int byte_no) { void TemplateTable::invokeinterface(int byte_no) {
transition(vtos, vtos); transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument"); assert(byte_no == f1_byte, "use this argument");
prepare_invoke(byte_no, rax, rbx, // get f1 Klass*, f2 itable index prepare_invoke(byte_no, rax, rbx, // get f1 Klass*, f2 Method*
rcx, rdx); // recv, flags rcx, rdx); // recv, flags
// rax: interface klass (from f1) // rax: reference klass (from f1)
// rbx: itable index (from f2) // rbx: method (from f2)
// rcx: receiver // rcx: receiver
// rdx: flags // rdx: flags
...@@ -3175,10 +3175,28 @@ void TemplateTable::invokeinterface(int byte_no) { ...@@ -3175,10 +3175,28 @@ void TemplateTable::invokeinterface(int byte_no) {
__ null_check(rcx, oopDesc::klass_offset_in_bytes()); __ null_check(rcx, oopDesc::klass_offset_in_bytes());
__ load_klass(rdx, rcx); __ load_klass(rdx, rcx);
Label no_such_interface, no_such_method;
// Receiver subtype check against REFC.
// Superklass in rax. Subklass in rdx. Blows rcx, rdi.
__ lookup_interface_method(// inputs: rec. class, interface, itable index
rdx, rax, noreg,
// outputs: scan temp. reg, scan temp. reg
r13, r14,
no_such_interface,
/*return_method=*/false);
// profile this call // profile this call
__ restore_bcp(); // rbcp was destroyed by receiver type check
__ profile_virtual_call(rdx, r13, r14); __ profile_virtual_call(rdx, r13, r14);
Label no_such_interface, no_such_method; // Get declaring interface class from method, and itable index
__ movptr(rax, Address(rbx, Method::const_offset()));
__ movptr(rax, Address(rax, ConstMethod::constants_offset()));
__ movptr(rax, Address(rax, ConstantPool::pool_holder_offset_in_bytes()));
__ movl(rbx, Address(rbx, Method::itable_index_offset()));
__ subl(rbx, Method::itable_index_max);
__ negl(rbx);
__ lookup_interface_method(// inputs: rec. class, interface, itable index __ lookup_interface_method(// inputs: rec. class, interface, itable index
rdx, rax, rbx, rdx, rax, rbx,
......
/* /*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "code/vtableStubs.hpp" #include "code/vtableStubs.hpp"
#include "interp_masm_x86.hpp" #include "interp_masm_x86.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/compiledICHolder.hpp"
#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.hpp"
#include "oops/klassVtable.hpp" #include "oops/klassVtable.hpp"
#include "runtime/sharedRuntime.hpp" #include "runtime/sharedRuntime.hpp"
...@@ -147,7 +148,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { ...@@ -147,7 +148,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
MacroAssembler* masm = new MacroAssembler(&cb); MacroAssembler* masm = new MacroAssembler(&cb);
// Entry arguments: // Entry arguments:
// rax,: Interface // rax: CompiledICHolder
// rcx: Receiver // rcx: Receiver
#ifndef PRODUCT #ifndef PRODUCT
...@@ -155,25 +156,42 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { ...@@ -155,25 +156,42 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
__ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); __ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
} }
#endif /* PRODUCT */ #endif /* PRODUCT */
// get receiver (need to skip return address on top of stack)
assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx"); // Most registers are in use; we'll use rax, rbx, rsi, rdi
// (If we need to make rsi, rdi callee-save, do a push/pop here.)
const Register recv_klass_reg = rsi;
const Register holder_klass_reg = rax; // declaring interface klass (DECC)
const Register resolved_klass_reg = rbx; // resolved interface klass (REFC)
const Register temp_reg = rdi;
const Register icholder_reg = rax;
__ movptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset()));
__ movptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset()));
Label L_no_such_interface;
// get receiver klass (also an implicit null-check) // get receiver klass (also an implicit null-check)
address npe_addr = __ pc(); address npe_addr = __ pc();
__ movptr(rsi, Address(rcx, oopDesc::klass_offset_in_bytes())); assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx");
__ load_klass(recv_klass_reg, rcx);
// Most registers are in use; we'll use rax, rbx, rsi, rdi
// (If we need to make rsi, rdi callee-save, do a push/pop here.) // Receiver subtype check against REFC.
// Destroys recv_klass_reg value.
__ lookup_interface_method(// inputs: rec. class, interface
recv_klass_reg, resolved_klass_reg, noreg,
// outputs: scan temp. reg1, scan temp. reg2
recv_klass_reg, temp_reg,
L_no_such_interface,
/*return_method=*/false);
// Get selected method from declaring class and itable index
const Register method = rbx; const Register method = rbx;
Label throw_icce; __ load_klass(recv_klass_reg, rcx); // restore recv_klass_reg
// Get Method* and entrypoint for compiler
__ lookup_interface_method(// inputs: rec. class, interface, itable index __ lookup_interface_method(// inputs: rec. class, interface, itable index
rsi, rax, itable_index, recv_klass_reg, holder_klass_reg, itable_index,
// outputs: method, scan temp. reg // outputs: method, scan temp. reg
method, rdi, method, temp_reg,
throw_icce); L_no_such_interface);
// method (rbx): Method* // method (rbx): Method*
// rcx: receiver // rcx: receiver
...@@ -193,9 +211,10 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { ...@@ -193,9 +211,10 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
address ame_addr = __ pc(); address ame_addr = __ pc();
__ jmp(Address(method, Method::from_compiled_offset())); __ jmp(Address(method, Method::from_compiled_offset()));
__ bind(throw_icce); __ bind(L_no_such_interface);
__ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
masm->flush();
__ flush();
if (PrintMiscellaneous && (WizardMode || Verbose)) { if (PrintMiscellaneous && (WizardMode || Verbose)) {
tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d", tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
...@@ -220,7 +239,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { ...@@ -220,7 +239,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0); return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0);
} else { } else {
// Itable stub size // Itable stub size
return (DebugVtables ? 256 : 66) + (CountCompiledCalls ? 6 : 0); return (DebugVtables ? 256 : 116) + (CountCompiledCalls ? 6 : 0);
} }
// In order to tune these parameters, run the JVM with VM options // In order to tune these parameters, run the JVM with VM options
// +PrintMiscellaneous and +WizardMode to see information about // +PrintMiscellaneous and +WizardMode to see information about
......
/* /*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "code/vtableStubs.hpp" #include "code/vtableStubs.hpp"
#include "interp_masm_x86.hpp" #include "interp_masm_x86.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/compiledICHolder.hpp"
#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.hpp"
#include "oops/klassVtable.hpp" #include "oops/klassVtable.hpp"
#include "runtime/sharedRuntime.hpp" #include "runtime/sharedRuntime.hpp"
...@@ -149,36 +150,50 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { ...@@ -149,36 +150,50 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
#endif #endif
// Entry arguments: // Entry arguments:
// rax: Interface // rax: CompiledICHolder
// j_rarg0: Receiver // j_rarg0: Receiver
// Free registers (non-args) are rax (interface), rbx // Most registers are in use; we'll use rax, rbx, r10, r11
// (various calling sequences use r[cd]x, r[sd]i, r[89]; stay away from them)
const Register recv_klass_reg = r10;
const Register holder_klass_reg = rax; // declaring interface klass (DECC)
const Register resolved_klass_reg = rbx; // resolved interface klass (REFC)
const Register temp_reg = r11;
// get receiver (need to skip return address on top of stack) Label L_no_such_interface;
const Register icholder_reg = rax;
__ movptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset()));
__ movptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset()));
assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0");
// get receiver klass (also an implicit null-check) // get receiver klass (also an implicit null-check)
assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0");
address npe_addr = __ pc(); address npe_addr = __ pc();
__ load_klass(recv_klass_reg, j_rarg0);
// Most registers are in use; we'll use rax, rbx, r10, r11
// (various calling sequences use r[cd]x, r[sd]i, r[89]; stay away from them) // Receiver subtype check against REFC.
__ load_klass(r10, j_rarg0); // Destroys recv_klass_reg value.
__ lookup_interface_method(// inputs: rec. class, interface
recv_klass_reg, resolved_klass_reg, noreg,
// outputs: scan temp. reg1, scan temp. reg2
recv_klass_reg, temp_reg,
L_no_such_interface,
/*return_method=*/false);
// Get selected method from declaring class and itable index
const Register method = rbx;
__ load_klass(recv_klass_reg, j_rarg0); // restore recv_klass_reg
__ lookup_interface_method(// inputs: rec. class, interface, itable index
recv_klass_reg, holder_klass_reg, itable_index,
// outputs: method, scan temp. reg
method, temp_reg,
L_no_such_interface);
// If we take a trap while this arg is on the stack we will not // If we take a trap while this arg is on the stack we will not
// be able to walk the stack properly. This is not an issue except // be able to walk the stack properly. This is not an issue except
// when there are mistakes in this assembly code that could generate // when there are mistakes in this assembly code that could generate
// a spurious fault. Ask me how I know... // a spurious fault. Ask me how I know...
const Register method = rbx;
Label throw_icce;
// Get Method* and entrypoint for compiler
__ lookup_interface_method(// inputs: rec. class, interface, itable index
r10, rax, itable_index,
// outputs: method, scan temp. reg
method, r11,
throw_icce);
// method (rbx): Method* // method (rbx): Method*
// j_rarg0: receiver // j_rarg0: receiver
...@@ -199,7 +214,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { ...@@ -199,7 +214,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
address ame_addr = __ pc(); address ame_addr = __ pc();
__ jmp(Address(method, Method::from_compiled_offset())); __ jmp(Address(method, Method::from_compiled_offset()));
__ bind(throw_icce); __ bind(L_no_such_interface);
__ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
__ flush(); __ flush();
...@@ -226,8 +241,8 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { ...@@ -226,8 +241,8 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
(UseCompressedClassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0); (UseCompressedClassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
} else { } else {
// Itable stub size // Itable stub size
return (DebugVtables ? 512 : 74) + (CountCompiledCalls ? 13 : 0) + return (DebugVtables ? 512 : 140) + (CountCompiledCalls ? 13 : 0) +
(UseCompressedClassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0); (UseCompressedClassPointers ? 2 * MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
} }
// In order to tune these parameters, run the JVM with VM options // In order to tune these parameters, run the JVM with VM options
// +PrintMiscellaneous and +WizardMode to see information about // +PrintMiscellaneous and +WizardMode to see information about
......
/* /*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -228,10 +228,13 @@ bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecod ...@@ -228,10 +228,13 @@ bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecod
#ifdef ASSERT #ifdef ASSERT
int index = call_info->resolved_method()->itable_index(); int index = call_info->resolved_method()->itable_index();
assert(index == itable_index, "CallInfo pre-computes this"); assert(index == itable_index, "CallInfo pre-computes this");
#endif //ASSERT
InstanceKlass* k = call_info->resolved_method()->method_holder(); InstanceKlass* k = call_info->resolved_method()->method_holder();
assert(k->verify_itable_index(itable_index), "sanity check"); assert(k->verify_itable_index(itable_index), "sanity check");
InlineCacheBuffer::create_transition_stub(this, k, entry); #endif //ASSERT
CompiledICHolder* holder = new CompiledICHolder(call_info->resolved_method()->method_holder(),
call_info->resolved_klass()());
holder->claim();
InlineCacheBuffer::create_transition_stub(this, holder, entry);
} else { } else {
assert(call_info->call_kind() == CallInfo::vtable_call, "either itable or vtable"); assert(call_info->call_kind() == CallInfo::vtable_call, "either itable or vtable");
// Can be different than selected_method->vtable_index(), due to package-private etc. // Can be different than selected_method->vtable_index(), due to package-private etc.
...@@ -527,7 +530,14 @@ void CompiledIC::compute_monomorphic_entry(methodHandle method, ...@@ -527,7 +530,14 @@ void CompiledIC::compute_monomorphic_entry(methodHandle method,
bool CompiledIC::is_icholder_entry(address entry) { bool CompiledIC::is_icholder_entry(address entry) {
CodeBlob* cb = CodeCache::find_blob_unsafe(entry); CodeBlob* cb = CodeCache::find_blob_unsafe(entry);
return (cb != NULL && cb->is_adapter_blob()); if (cb != NULL && cb->is_adapter_blob()) {
return true;
}
// itable stubs also use CompiledICHolder
if (VtableStubs::is_entry_point(entry) && VtableStubs::stub_containing(entry)->is_itable_stub()) {
return true;
}
return false;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
......
/* /*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -59,11 +59,11 @@ ...@@ -59,11 +59,11 @@
// \ / \ / // \ / \ /
// [4] \ / [4] \->-/ // [4] \ / [4] \->-/
// \->- Megamorphic -<-/ // \->- Megamorphic -<-/
// (Method*) // (CompiledICHolder*)
// //
// The text in paranteses () refere to the value of the inline cache receiver (mov instruction) // The text in parentheses () refers to the value of the inline cache receiver (mov instruction)
// //
// The numbers in square brackets refere to the kind of transition: // The numbers in square brackets refer to the kind of transition:
// [1]: Initial fixup. Receiver it found from debug information // [1]: Initial fixup. Receiver it found from debug information
// [2]: Compilation of a method // [2]: Compilation of a method
// [3]: Recompilation of a method (note: only entry is changed. The Klass* must stay the same) // [3]: Recompilation of a method (note: only entry is changed. The Klass* must stay the same)
......
...@@ -1748,12 +1748,11 @@ void static clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_a ...@@ -1748,12 +1748,11 @@ void static clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_a
CompiledICHolder* cichk_oop = ic->cached_icholder(); CompiledICHolder* cichk_oop = ic->cached_icholder();
if (mark_on_stack) { if (mark_on_stack) {
Metadata::mark_on_stack(cichk_oop->holder_method()); Metadata::mark_on_stack(cichk_oop->holder_metadata());
Metadata::mark_on_stack(cichk_oop->holder_klass()); Metadata::mark_on_stack(cichk_oop->holder_klass());
} }
if (cichk_oop->holder_method()->method_holder()->is_loader_alive(is_alive) && if (cichk_oop->is_loader_alive(is_alive)) {
cichk_oop->holder_klass()->is_loader_alive(is_alive)) {
return; return;
} }
} else { } else {
...@@ -2180,7 +2179,7 @@ void nmethod::metadata_do(void f(Metadata*)) { ...@@ -2180,7 +2179,7 @@ void nmethod::metadata_do(void f(Metadata*)) {
CompiledIC *ic = CompiledIC_at(&iter); CompiledIC *ic = CompiledIC_at(&iter);
if (ic->is_icholder_call()) { if (ic->is_icholder_call()) {
CompiledICHolder* cichk = ic->cached_icholder(); CompiledICHolder* cichk = ic->cached_icholder();
f(cichk->holder_method()); f(cichk->holder_metadata());
f(cichk->holder_klass()); f(cichk->holder_klass());
} else { } else {
Metadata* ic_oop = ic->cached_metadata(); Metadata* ic_oop = ic->cached_metadata();
......
...@@ -786,6 +786,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes ...@@ -786,6 +786,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes
case CallInfo::itable_call: case CallInfo::itable_call:
cache_entry(thread)->set_itable_call( cache_entry(thread)->set_itable_call(
bytecode, bytecode,
info.resolved_klass(),
info.resolved_method(), info.resolved_method(),
info.itable_index()); info.itable_index());
break; break;
......
/* /*
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -32,12 +32,28 @@ volatile int CompiledICHolder::_live_count; ...@@ -32,12 +32,28 @@ volatile int CompiledICHolder::_live_count;
volatile int CompiledICHolder::_live_not_claimed_count; volatile int CompiledICHolder::_live_not_claimed_count;
bool CompiledICHolder::is_loader_alive(BoolObjectClosure* is_alive) {
if (_holder_metadata->is_method()) {
if (!((Method*)_holder_metadata)->method_holder()->is_loader_alive(is_alive)) {
return false;
}
} else if (_holder_metadata->is_klass()) {
if (!((Klass*)_holder_metadata)->is_loader_alive(is_alive)) {
return false;
}
}
if (!_holder_klass->is_loader_alive(is_alive)) {
return false;
}
return true;
}
// Printing // Printing
void CompiledICHolder::print_on(outputStream* st) const { void CompiledICHolder::print_on(outputStream* st) const {
st->print("%s", internal_name()); st->print("%s", internal_name());
st->print(" - method: "); holder_method()->print_value_on(st); st->cr(); st->print(" - metadata: "); holder_metadata()->print_value_on(st); st->cr();
st->print(" - klass: "); holder_klass()->print_value_on(st); st->cr(); st->print(" - klass: "); holder_klass()->print_value_on(st); st->cr();
} }
void CompiledICHolder::print_value_on(outputStream* st) const { void CompiledICHolder::print_value_on(outputStream* st) const {
...@@ -48,6 +64,6 @@ void CompiledICHolder::print_value_on(outputStream* st) const { ...@@ -48,6 +64,6 @@ void CompiledICHolder::print_value_on(outputStream* st) const {
// Verification // Verification
void CompiledICHolder::verify_on(outputStream* st) { void CompiledICHolder::verify_on(outputStream* st) {
guarantee(holder_method()->is_method(), "should be method"); guarantee(holder_metadata()->is_method() || holder_metadata()->is_klass(), "should be method or klass");
guarantee(holder_klass()->is_klass(), "should be klass"); guarantee(holder_klass()->is_klass(), "should be klass");
} }
/* /*
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -28,8 +28,9 @@ ...@@ -28,8 +28,9 @@
#include "oops/oop.hpp" #include "oops/oop.hpp"
// A CompiledICHolder* is a helper object for the inline cache implementation. // A CompiledICHolder* is a helper object for the inline cache implementation.
// It holds an intermediate value (method+klass pair) used when converting from // It holds:
// compiled to an interpreted call. // (1) (method+klass pair) when converting from compiled to an interpreted call
// (2) (klass+klass pair) when calling itable stub from megamorphic compiled call
// //
// These are always allocated in the C heap and are freed during a // These are always allocated in the C heap and are freed during a
// safepoint by the ICBuffer logic. It's unsafe to free them earlier // safepoint by the ICBuffer logic. It's unsafe to free them earlier
...@@ -44,14 +45,14 @@ class CompiledICHolder : public CHeapObj<mtCompiler> { ...@@ -44,14 +45,14 @@ class CompiledICHolder : public CHeapObj<mtCompiler> {
static volatile int _live_not_claimed_count; // allocated but not yet in use so not static volatile int _live_not_claimed_count; // allocated but not yet in use so not
// reachable by iterating over nmethods // reachable by iterating over nmethods
Method* _holder_method; Metadata* _holder_metadata;
Klass* _holder_klass; // to avoid name conflict with oopDesc::_klass Klass* _holder_klass; // to avoid name conflict with oopDesc::_klass
CompiledICHolder* _next; CompiledICHolder* _next;
public: public:
// Constructor // Constructor
CompiledICHolder(Method* method, Klass* klass) CompiledICHolder(Metadata* metadata, Klass* klass)
: _holder_method(method), _holder_klass(klass) { : _holder_metadata(metadata), _holder_klass(klass) {
#ifdef ASSERT #ifdef ASSERT
Atomic::inc(&_live_count); Atomic::inc(&_live_count);
Atomic::inc(&_live_not_claimed_count); Atomic::inc(&_live_not_claimed_count);
...@@ -69,19 +70,20 @@ class CompiledICHolder : public CHeapObj<mtCompiler> { ...@@ -69,19 +70,20 @@ class CompiledICHolder : public CHeapObj<mtCompiler> {
static int live_not_claimed_count() { return _live_not_claimed_count; } static int live_not_claimed_count() { return _live_not_claimed_count; }
// accessors // accessors
Method* holder_method() const { return _holder_method; }
Klass* holder_klass() const { return _holder_klass; } Klass* holder_klass() const { return _holder_klass; }
Metadata* holder_metadata() const { return _holder_metadata; }
void set_holder_method(Method* m) { _holder_method = m; } void set_holder_metadata(Metadata* m) { _holder_metadata = m; }
void set_holder_klass(Klass* k) { _holder_klass = k; } void set_holder_klass(Klass* k) { _holder_klass = k; }
// interpreter support (offsets in bytes) static int holder_metadata_offset() { return offset_of(CompiledICHolder, _holder_metadata); }
static int holder_method_offset() { return offset_of(CompiledICHolder, _holder_method); }
static int holder_klass_offset() { return offset_of(CompiledICHolder, _holder_klass); } static int holder_klass_offset() { return offset_of(CompiledICHolder, _holder_klass); }
CompiledICHolder* next() { return _next; } CompiledICHolder* next() { return _next; }
void set_next(CompiledICHolder* n) { _next = n; } void set_next(CompiledICHolder* n) { _next = n; }
bool is_loader_alive(BoolObjectClosure* is_alive);
// Verify // Verify
void verify_on(outputStream* st); void verify_on(outputStream* st);
......
/* /*
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -259,14 +259,16 @@ void ConstantPoolCacheEntry::set_vtable_call(Bytecodes::Code invoke_code, method ...@@ -259,14 +259,16 @@ void ConstantPoolCacheEntry::set_vtable_call(Bytecodes::Code invoke_code, method
set_direct_or_vtable_call(invoke_code, method, index, false); set_direct_or_vtable_call(invoke_code, method, index, false);
} }
void ConstantPoolCacheEntry::set_itable_call(Bytecodes::Code invoke_code, methodHandle method, int index) { void ConstantPoolCacheEntry::set_itable_call(Bytecodes::Code invoke_code,
KlassHandle referenced_klass,
methodHandle method, int index) {
assert(method->method_holder()->verify_itable_index(index), ""); assert(method->method_holder()->verify_itable_index(index), "");
assert(invoke_code == Bytecodes::_invokeinterface, ""); assert(invoke_code == Bytecodes::_invokeinterface, "");
InstanceKlass* interf = method->method_holder(); InstanceKlass* interf = method->method_holder();
assert(interf->is_interface(), "must be an interface"); assert(interf->is_interface(), "must be an interface");
assert(!method->is_final_method(), "interfaces do not have final methods; cannot link to one here"); assert(!method->is_final_method(), "interfaces do not have final methods; cannot link to one here");
set_f1(interf); set_f1(referenced_klass());
set_f2(index); set_f2((intx)method());
set_method_flags(as_TosState(method->result_type()), set_method_flags(as_TosState(method->result_type()),
0, // no option bits 0, // no option bits
method()->size_of_parameters()); method()->size_of_parameters());
...@@ -433,10 +435,27 @@ oop ConstantPoolCacheEntry::method_type_if_resolved(constantPoolHandle cpool) { ...@@ -433,10 +435,27 @@ oop ConstantPoolCacheEntry::method_type_if_resolved(constantPoolHandle cpool) {
#if INCLUDE_JVMTI #if INCLUDE_JVMTI
void log_adjust(const char* entry_type, Method* old_method, Method* new_method, bool* trace_name_printed) {
if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) {
if (!(*trace_name_printed)) {
// RC_TRACE_MESG macro has an embedded ResourceMark
RC_TRACE_MESG(("adjust: name=%s",
old_method->method_holder()->external_name()));
*trace_name_printed = true;
}
// RC_TRACE macro has an embedded ResourceMark
RC_TRACE(0x00400000, ("cpc %s entry update: %s(%s)",
entry_type,
new_method->name()->as_C_string(),
new_method->signature()->as_C_string()));
}
}
// RedefineClasses() API support: // RedefineClasses() API support:
// If this ConstantPoolCacheEntry refers to old_method then update it // If this ConstantPoolCacheEntry refers to old_method then update it
// to refer to new_method. // to refer to new_method.
bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method, void ConstantPoolCacheEntry::adjust_method_entry(Method* old_method,
Method* new_method, bool * trace_name_printed) { Method* new_method, bool * trace_name_printed) {
if (is_vfinal()) { if (is_vfinal()) {
...@@ -445,69 +464,34 @@ bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method, ...@@ -445,69 +464,34 @@ bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method,
// match old_method so need an update // match old_method so need an update
// NOTE: can't use set_f2_as_vfinal_method as it asserts on different values // NOTE: can't use set_f2_as_vfinal_method as it asserts on different values
_f2 = (intptr_t)new_method; _f2 = (intptr_t)new_method;
if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) {
if (!(*trace_name_printed)) {
// RC_TRACE_MESG macro has an embedded ResourceMark
RC_TRACE_MESG(("adjust: name=%s",
old_method->method_holder()->external_name()));
*trace_name_printed = true;
}
// RC_TRACE macro has an embedded ResourceMark
RC_TRACE(0x00400000, ("cpc vf-entry update: %s(%s)",
new_method->name()->as_C_string(),
new_method->signature()->as_C_string()));
}
return true;
} }
return;
// f1() is not used with virtual entries so bail out
return false;
} }
if (_f1 == NULL) { assert (_f1 != NULL, "should not call with uninteresting entry");
// NULL f1() means this is a virtual entry so bail out
// We are assuming that the vtable index does not need change.
return false;
}
if (_f1 == old_method) { if (!(_f1->is_method())) {
_f1 = new_method; // _f1 is a Klass* for an interface, _f2 is the method
if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { if (f2_as_interface_method() == old_method) {
if (!(*trace_name_printed)) { _f2 = (intptr_t)new_method;
// RC_TRACE_MESG macro has an embedded ResourceMark log_adjust("interface", old_method, new_method, trace_name_printed);
RC_TRACE_MESG(("adjust: name=%s",
old_method->method_holder()->external_name()));
*trace_name_printed = true;
}
// RC_TRACE macro has an embedded ResourceMark
RC_TRACE(0x00400000, ("cpc entry update: %s(%s)",
new_method->name()->as_C_string(),
new_method->signature()->as_C_string()));
} }
return true; } else if (_f1 == old_method) {
_f1 = new_method;
log_adjust("special, static or dynamic", old_method, new_method, trace_name_printed);
} }
return false;
} }
// a constant pool cache entry should never contain old or obsolete methods // a constant pool cache entry should never contain old or obsolete methods
bool ConstantPoolCacheEntry::check_no_old_or_obsolete_entries() { bool ConstantPoolCacheEntry::check_no_old_or_obsolete_entries() {
if (is_vfinal()) { Method* m = get_interesting_method_entry(NULL);
// virtual and final so _f2 contains method ptr instead of vtable index // return false if m refers to a non-deleted old or obsolete method
Metadata* f2 = (Metadata*)_f2; if (m != NULL) {
// Return false if _f2 refers to an old or an obsolete method. assert(m->is_valid() && m->is_method(), "m is a valid method");
// _f2 == NULL || !_f2->is_method() are just as unexpected here. return !m->is_old() && !m->is_obsolete(); // old is always set for old and obsolete
return (f2 != NULL NOT_PRODUCT(&& f2->is_valid()) && f2->is_method() && } else {
!((Method*)f2)->is_old() && !((Method*)f2)->is_obsolete());
} else if (_f1 == NULL ||
(NOT_PRODUCT(_f1->is_valid() &&) !_f1->is_method())) {
// _f1 == NULL || !_f1->is_method() are OK here
return true; return true;
} }
// return false if _f1 refers to a non-deleted old or obsolete method
return (NOT_PRODUCT(_f1->is_valid() &&) _f1->is_method() &&
(f1_as_method()->is_deleted() ||
(!f1_as_method()->is_old() && !f1_as_method()->is_obsolete())));
} }
Method* ConstantPoolCacheEntry::get_interesting_method_entry(Klass* k) { Method* ConstantPoolCacheEntry::get_interesting_method_entry(Klass* k) {
...@@ -524,10 +508,11 @@ Method* ConstantPoolCacheEntry::get_interesting_method_entry(Klass* k) { ...@@ -524,10 +508,11 @@ Method* ConstantPoolCacheEntry::get_interesting_method_entry(Klass* k) {
return NULL; return NULL;
} else { } else {
if (!(_f1->is_method())) { if (!(_f1->is_method())) {
// _f1 can also contain a Klass* for an interface // _f1 is a Klass* for an interface
return NULL; m = f2_as_interface_method();
} else {
m = f1_as_method();
} }
m = f1_as_method();
} }
assert(m != NULL && m->is_method(), "sanity check"); assert(m != NULL && m->is_method(), "sanity check");
if (m == NULL || !m->is_method() || (k != NULL && m->method_holder() != k)) { if (m == NULL || !m->is_method() || (k != NULL && m->method_holder() != k)) {
......
/* /*
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -248,6 +248,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { ...@@ -248,6 +248,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
void set_itable_call( void set_itable_call(
Bytecodes::Code invoke_code, // the bytecode used; must be invokeinterface Bytecodes::Code invoke_code, // the bytecode used; must be invokeinterface
KlassHandle referenced_klass, // the referenced klass in the InterfaceMethodref
methodHandle method, // the resolved interface method methodHandle method, // the resolved interface method
int itable_index // index into itable for the method int itable_index // index into itable for the method
); );
...@@ -344,6 +345,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { ...@@ -344,6 +345,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
bool is_f1_null() const { Metadata* f1 = f1_ord(); return f1 == NULL; } // classifies a CPC entry as unbound bool is_f1_null() const { Metadata* f1 = f1_ord(); return f1 == NULL; } // classifies a CPC entry as unbound
int f2_as_index() const { assert(!is_vfinal(), ""); return (int) _f2; } int f2_as_index() const { assert(!is_vfinal(), ""); return (int) _f2; }
Method* f2_as_vfinal_method() const { assert(is_vfinal(), ""); return (Method*)_f2; } Method* f2_as_vfinal_method() const { assert(is_vfinal(), ""); return (Method*)_f2; }
Method* f2_as_interface_method() const { assert(bytecode_1() == Bytecodes::_invokeinterface, ""); return (Method*)_f2; }
int field_index() const { assert(is_field_entry(), ""); return (_flags & field_index_mask); } int field_index() const { assert(is_field_entry(), ""); return (_flags & field_index_mask); }
int parameter_size() const { assert(is_method_entry(), ""); return (_flags & parameter_size_mask); } int parameter_size() const { assert(is_method_entry(), ""); return (_flags & parameter_size_mask); }
bool is_volatile() const { return (_flags & (1 << is_volatile_shift)) != 0; } bool is_volatile() const { return (_flags & (1 << is_volatile_shift)) != 0; }
...@@ -374,7 +376,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { ...@@ -374,7 +376,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
// trace_name_printed is set to true if the current call has // trace_name_printed is set to true if the current call has
// printed the klass name so that other routines in the adjust_* // printed the klass name so that other routines in the adjust_*
// group don't print the klass name. // group don't print the klass name.
bool adjust_method_entry(Method* old_method, Method* new_method, void adjust_method_entry(Method* old_method, Method* new_method,
bool* trace_name_printed); bool* trace_name_printed);
bool check_no_old_or_obsolete_entries(); bool check_no_old_or_obsolete_entries();
Method* get_interesting_method_entry(Klass* k); Method* get_interesting_method_entry(Klass* k);
......
...@@ -1204,7 +1204,6 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass ...@@ -1204,7 +1204,6 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
Array<Method*>* methods = InstanceKlass::cast(interf_h())->methods(); Array<Method*>* methods = InstanceKlass::cast(interf_h())->methods();
int nof_methods = methods->length(); int nof_methods = methods->length();
HandleMark hm; HandleMark hm;
assert(nof_methods > 0, "at least one method must exist for interface to be in vtable");
Handle interface_loader (THREAD, InstanceKlass::cast(interf_h())->class_loader()); Handle interface_loader (THREAD, InstanceKlass::cast(interf_h())->class_loader());
int ime_count = method_count_for_interface(interf_h()); int ime_count = method_count_for_interface(interf_h());
...@@ -1386,8 +1385,10 @@ void visit_all_interfaces(Array<Klass*>* transitive_intf, InterfaceVisiterClosur ...@@ -1386,8 +1385,10 @@ void visit_all_interfaces(Array<Klass*>* transitive_intf, InterfaceVisiterClosur
} }
} }
// Only count interfaces with at least one method // Visit all interfaces which either have any methods or can participate in receiver type check.
if (method_count > 0) { // We do not bother to count methods in transitive interfaces, although that would allow us to skip
// this step in the rare case of a zero-method interface extending another zero-method interface.
if (method_count > 0 || InstanceKlass::cast(intf)->transitive_interfaces()->length() > 0) {
blk->doit(intf, method_count); blk->doit(intf, method_count);
} }
} }
......
/* /*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -661,6 +661,7 @@ class Method : public Metadata { ...@@ -661,6 +661,7 @@ class Method : public Metadata {
static ByteSize from_interpreted_offset() { return byte_offset_of(Method, _from_interpreted_entry ); } static ByteSize from_interpreted_offset() { return byte_offset_of(Method, _from_interpreted_entry ); }
static ByteSize interpreter_entry_offset() { return byte_offset_of(Method, _i2i_entry ); } static ByteSize interpreter_entry_offset() { return byte_offset_of(Method, _i2i_entry ); }
static ByteSize signature_handler_offset() { return in_ByteSize(sizeof(Method) + wordSize); } static ByteSize signature_handler_offset() { return in_ByteSize(sizeof(Method) + wordSize); }
static ByteSize itable_index_offset() { return byte_offset_of(Method, _vtable_index ); }
// for code generation // for code generation
static int method_data_offset_in_bytes() { return offset_of(Method, _method_data); } static int method_data_offset_in_bytes() { return offset_of(Method, _method_data); }
......
...@@ -278,7 +278,7 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable; ...@@ -278,7 +278,7 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
volatile_nonstatic_field(ArrayKlass, _lower_dimension, Klass*) \ volatile_nonstatic_field(ArrayKlass, _lower_dimension, Klass*) \
nonstatic_field(ArrayKlass, _vtable_len, int) \ nonstatic_field(ArrayKlass, _vtable_len, int) \
nonstatic_field(ArrayKlass, _component_mirror, oop) \ nonstatic_field(ArrayKlass, _component_mirror, oop) \
nonstatic_field(CompiledICHolder, _holder_method, Method*) \ nonstatic_field(CompiledICHolder, _holder_metadata, Metadata*) \
nonstatic_field(CompiledICHolder, _holder_klass, Klass*) \ nonstatic_field(CompiledICHolder, _holder_klass, Klass*) \
nonstatic_field(ConstantPool, _tags, Array<u1>*) \ nonstatic_field(ConstantPool, _tags, Array<u1>*) \
nonstatic_field(ConstantPool, _cache, ConstantPoolCache*) \ nonstatic_field(ConstantPool, _cache, ConstantPoolCache*) \
......
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8174962
* @summary Redefine class with interface method call
* @library /testlibrary /test/lib
* @modules java.base/jdk.internal.misc
* @modules java.compiler
* java.instrument
* jdk.jartool/sun.tools.jar
* @run main RedefineClassHelper
* @run main/othervm -javaagent:redefineagent.jar RedefineInterfaceCall
*/
import static jdk.testlibrary.Asserts.assertEquals;
interface I1 { default int m() { return 0; } }
interface I2 extends I1 {}
public class RedefineInterfaceCall {
public static class C implements I2 {
public int test(I2 i) {
return i.m(); // invokeinterface cpCacheEntry
}
}
static String newI1 =
"interface I1 { default int m() { return 1; } }";
static String newC =
"public class RedefineInterfaceCall$C implements I2 { " +
" public int test(I2 i) { " +
" return i.m(); " +
" } " +
"} ";
static int test(I2 i) {
return i.m(); // invokeinterface cpCacheEntry
}
public static void main(String[] args) throws Exception {
C c = new C();
assertEquals(test(c), 0);
assertEquals(c.test(c), 0);
RedefineClassHelper.redefineClass(C.class, newC);
assertEquals(c.test(c), 0);
RedefineClassHelper.redefineClass(I1.class, newI1);
assertEquals(test(c), 1);
assertEquals(c.test(c), 1);
RedefineClassHelper.redefineClass(C.class, newC);
assertEquals(c.test(c), 1);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册