aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm/interpreter
diff options
context:
space:
mode:
authorjrose <none@none>2009-04-21 23:21:04 -0700
committerjrose <none@none>2009-04-21 23:21:04 -0700
commite95fc1b19ae2eaca9a91d9e27f09a248bbe3da50 (patch)
tree5704ad3778987120bc8ca1f9c313b6006813d54e /src/share/vm/interpreter
parent4c08465f35c8d3e10b19d956893e3b94069a3718 (diff)
downloadjdk8u_hotspot-e95fc1b19ae2eaca9a91d9e27f09a248bbe3da50.tar.gz
6655646: dynamic languages need dynamically linked call sites
Summary: invokedynamic instruction (JSR 292 RI) Reviewed-by: twisti, never
Diffstat (limited to 'src/share/vm/interpreter')
-rw-r--r--src/share/vm/interpreter/abstractInterpreter.hpp67
-rw-r--r--src/share/vm/interpreter/bytecode.cpp13
-rw-r--r--src/share/vm/interpreter/bytecode.hpp35
-rw-r--r--src/share/vm/interpreter/bytecodeStream.hpp26
-rw-r--r--src/share/vm/interpreter/bytecodeTracer.cpp120
-rw-r--r--src/share/vm/interpreter/bytecodes.cpp2
-rw-r--r--src/share/vm/interpreter/bytecodes.hpp2
-rw-r--r--src/share/vm/interpreter/interpreterRuntime.cpp127
-rw-r--r--src/share/vm/interpreter/interpreterRuntime.hpp9
-rw-r--r--src/share/vm/interpreter/linkResolver.cpp25
-rw-r--r--src/share/vm/interpreter/linkResolver.hpp1
-rw-r--r--src/share/vm/interpreter/rewriter.cpp193
-rw-r--r--src/share/vm/interpreter/rewriter.hpp41
-rw-r--r--src/share/vm/interpreter/templateInterpreter.cpp37
-rw-r--r--src/share/vm/interpreter/templateInterpreter.hpp10
-rw-r--r--src/share/vm/interpreter/templateInterpreterGenerator.hpp5
-rw-r--r--src/share/vm/interpreter/templateTable.cpp2
-rw-r--r--src/share/vm/interpreter/templateTable.hpp1
18 files changed, 594 insertions, 122 deletions
diff --git a/src/share/vm/interpreter/abstractInterpreter.hpp b/src/share/vm/interpreter/abstractInterpreter.hpp
index 782a91bb4..260288b09 100644
--- a/src/share/vm/interpreter/abstractInterpreter.hpp
+++ b/src/share/vm/interpreter/abstractInterpreter.hpp
@@ -217,6 +217,73 @@ class AbstractInterpreter: AllStatic {
stackElementSize()) + tag_offset_in_bytes();
}
+ // access to stacked values according to type:
+ static oop* oop_addr_in_slot(intptr_t* slot_addr) {
+ return (oop*) slot_addr;
+ }
+ static jint* int_addr_in_slot(intptr_t* slot_addr) {
+ if ((int) sizeof(jint) < wordSize && !Bytes::is_Java_byte_ordering_different())
+ // big-endian LP64
+ return (jint*)(slot_addr + 1) - 1;
+ else
+ return (jint*) slot_addr;
+ }
+ static jlong long_in_slot(intptr_t* slot_addr) {
+ if (sizeof(intptr_t) >= sizeof(jlong)) {
+ return *(jlong*) slot_addr;
+ } else if (!TaggedStackInterpreter) {
+ return Bytes::get_native_u8((address)slot_addr);
+ } else {
+ assert(sizeof(intptr_t) * 2 == sizeof(jlong), "ILP32");
+ // assemble the long in memory order (not arithmetic order)
+ union { jlong j; jint i[2]; } u;
+ u.i[0] = (jint) slot_addr[0*stackElementSize()];
+ u.i[1] = (jint) slot_addr[1*stackElementSize()];
+ return u.j;
+ }
+ }
+ static void set_long_in_slot(intptr_t* slot_addr, jlong value) {
+ if (sizeof(intptr_t) >= sizeof(jlong)) {
+ *(jlong*) slot_addr = value;
+ } else if (!TaggedStackInterpreter) {
+ Bytes::put_native_u8((address)slot_addr, value);
+ } else {
+ assert(sizeof(intptr_t) * 2 == sizeof(jlong), "ILP32");
+ // assemble the long in memory order (not arithmetic order)
+ union { jlong j; jint i[2]; } u;
+ u.j = value;
+ slot_addr[0*stackElementSize()] = (intptr_t) u.i[0];
+ slot_addr[1*stackElementSize()] = (intptr_t) u.i[1];
+ }
+ }
+ static void get_jvalue_in_slot(intptr_t* slot_addr, BasicType type, jvalue* value) {
+ switch (type) {
+ case T_BOOLEAN: value->z = *int_addr_in_slot(slot_addr); break;
+ case T_CHAR: value->c = *int_addr_in_slot(slot_addr); break;
+ case T_BYTE: value->b = *int_addr_in_slot(slot_addr); break;
+ case T_SHORT: value->s = *int_addr_in_slot(slot_addr); break;
+ case T_INT: value->i = *int_addr_in_slot(slot_addr); break;
+ case T_LONG: value->j = long_in_slot(slot_addr); break;
+ case T_FLOAT: value->f = *(jfloat*)int_addr_in_slot(slot_addr); break;
+ case T_DOUBLE: value->d = jdouble_cast(long_in_slot(slot_addr)); break;
+ case T_OBJECT: value->l = (jobject)*oop_addr_in_slot(slot_addr); break;
+ default: ShouldNotReachHere();
+ }
+ }
+ static void set_jvalue_in_slot(intptr_t* slot_addr, BasicType type, jvalue* value) {
+ switch (type) {
+ case T_BOOLEAN: *int_addr_in_slot(slot_addr) = (value->z != 0); break;
+ case T_CHAR: *int_addr_in_slot(slot_addr) = value->c; break;
+ case T_BYTE: *int_addr_in_slot(slot_addr) = value->b; break;
+ case T_SHORT: *int_addr_in_slot(slot_addr) = value->s; break;
+ case T_INT: *int_addr_in_slot(slot_addr) = value->i; break;
+ case T_LONG: set_long_in_slot(slot_addr, value->j); break;
+ case T_FLOAT: *(jfloat*)int_addr_in_slot(slot_addr) = value->f; break;
+ case T_DOUBLE: set_long_in_slot(slot_addr, jlong_cast(value->d)); break;
+ case T_OBJECT: *oop_addr_in_slot(slot_addr) = (oop) value->l; break;
+ default: ShouldNotReachHere();
+ }
+ }
};
//------------------------------------------------------------------------------------------------------------------------
diff --git a/src/share/vm/interpreter/bytecode.cpp b/src/share/vm/interpreter/bytecode.cpp
index ea46acbc5..f91d5667e 100644
--- a/src/share/vm/interpreter/bytecode.cpp
+++ b/src/share/vm/interpreter/bytecode.cpp
@@ -34,12 +34,6 @@ void Bytecode::set_code(Bytecodes::Code code) {
}
-void Bytecode::set_fast_index(int i) {
- assert(0 <= i && i < 0x10000, "illegal index value");
- Bytes::put_native_u2(addr_at(1), (jushort)i);
-}
-
-
bool Bytecode::check_must_rewrite() const {
assert(Bytecodes::can_rewrite(code()), "post-check only");
@@ -118,7 +112,12 @@ methodHandle Bytecode_invoke::static_target(TRAPS) {
int Bytecode_invoke::index() const {
- return Bytes::get_Java_u2(bcp() + 1);
+ // Note: Rewriter::rewrite changes the Java_u2 of an invokedynamic to a native_u4,
+ // at the same time it allocates per-call-site CP cache entries.
+ if (has_giant_index())
+ return Bytes::get_native_u4(bcp() + 1);
+ else
+ return Bytes::get_Java_u2(bcp() + 1);
}
diff --git a/src/share/vm/interpreter/bytecode.hpp b/src/share/vm/interpreter/bytecode.hpp
index b9f65b21d..64941d8d5 100644
--- a/src/share/vm/interpreter/bytecode.hpp
+++ b/src/share/vm/interpreter/bytecode.hpp
@@ -65,14 +65,6 @@ class ThisRelativeObj VALUE_OBJ_CLASS_SPEC {
// The base class for different kinds of bytecode abstractions.
// Provides the primitive operations to manipulate code relative
// to an objects 'this' pointer.
-//
-// Note: Even though it seems that the fast_index & set_fast_index
-// functions are machine specific, they're not. They only use
-// the natural way to store a 16bit index on a given machine,
-// independent of the particular byte ordering. Since all other
-// places in the system that refer to these indices use the
-// same method (the natural byte ordering on the platform)
-// this will always work and be machine-independent).
class Bytecode: public ThisRelativeObj {
protected:
@@ -83,24 +75,40 @@ class Bytecode: public ThisRelativeObj {
// Attributes
address bcp() const { return addr_at(0); }
address next_bcp() const { return addr_at(0) + Bytecodes::length_at(bcp()); }
+ int instruction_size() const { return Bytecodes::length_at(bcp()); }
Bytecodes::Code code() const { return Bytecodes::code_at(addr_at(0)); }
Bytecodes::Code java_code() const { return Bytecodes::java_code(code()); }
bool must_rewrite() const { return Bytecodes::can_rewrite(code()) && check_must_rewrite(); }
bool is_active_breakpoint() const { return Bytecodes::is_active_breakpoint_at(bcp()); }
- int one_byte_index() const { return byte_at(1); }
- int two_byte_index() const { return (byte_at(1) << 8) + byte_at(2); }
+ int one_byte_index() const { assert_index_size(1); return byte_at(1); }
+ int two_byte_index() const { assert_index_size(2); return (byte_at(1) << 8) + byte_at(2); }
+
int offset() const { return (two_byte_index() << 16) >> 16; }
address destination() const { return bcp() + offset(); }
- int fast_index() const { return Bytes::get_native_u2(addr_at(1)); }
// Attribute modification
void set_code(Bytecodes::Code code);
- void set_fast_index(int i);
// Creation
inline friend Bytecode* Bytecode_at(address bcp);
+
+ private:
+ void assert_index_size(int required_size) const {
+#ifdef ASSERT
+ int isize = instruction_size() - 1;
+ if (isize == 2 && code() == Bytecodes::_iinc)
+ isize = 1;
+ else if (isize <= 2)
+ ; // no change
+ else if (code() == Bytecodes::_invokedynamic)
+ isize = 4;
+ else
+ isize = 2;
+ assert(isize = required_size, "wrong index size");
+#endif
+ }
};
inline Bytecode* Bytecode_at(address bcp) {
@@ -195,6 +203,9 @@ class Bytecode_invoke: public ResourceObj {
bool is_invokevirtual() const { return adjusted_invoke_code() == Bytecodes::_invokevirtual; }
bool is_invokestatic() const { return adjusted_invoke_code() == Bytecodes::_invokestatic; }
bool is_invokespecial() const { return adjusted_invoke_code() == Bytecodes::_invokespecial; }
+ bool is_invokedynamic() const { return adjusted_invoke_code() == Bytecodes::_invokedynamic; }
+
+ bool has_giant_index() const { return is_invokedynamic(); }
bool is_valid() const { return is_invokeinterface() ||
is_invokevirtual() ||
diff --git a/src/share/vm/interpreter/bytecodeStream.hpp b/src/share/vm/interpreter/bytecodeStream.hpp
index 3616c9dc6..7a3a0125e 100644
--- a/src/share/vm/interpreter/bytecodeStream.hpp
+++ b/src/share/vm/interpreter/bytecodeStream.hpp
@@ -109,6 +109,7 @@ class RawBytecodeStream: StackObj {
Bytecodes::Code code() const { return _code; }
bool is_wide() const { return _is_wide; }
+ int instruction_size() const { return (_next_bci - _bci); }
bool is_last_bytecode() const { return _next_bci >= _end_bci; }
address bcp() const { return method()->code_base() + _bci; }
@@ -122,8 +123,29 @@ class RawBytecodeStream: StackObj {
int dest_w() const { return bci() + (int )Bytes::get_Java_u4(bcp() + 1); }
// Unsigned indices, widening
- int get_index() const { return (is_wide()) ? Bytes::get_Java_u2(bcp() + 2) : bcp()[1]; }
- int get_index_big() const { return (int)Bytes::get_Java_u2(bcp() + 1); }
+ int get_index() const { assert_index_size(is_wide() ? 2 : 1);
+ return (is_wide()) ? Bytes::get_Java_u2(bcp() + 2) : bcp()[1]; }
+ int get_index_big() const { assert_index_size(2);
+ return (int)Bytes::get_Java_u2(bcp() + 1); }
+ int get_index_int() const { return has_giant_index() ? get_index_giant() : get_index_big(); }
+ int get_index_giant() const { assert_index_size(4); return Bytes::get_native_u4(bcp() + 1); }
+ int has_giant_index() const { return (code() == Bytecodes::_invokedynamic); }
+
+ private:
+ void assert_index_size(int required_size) const {
+#ifdef ASSERT
+ int isize = instruction_size() - (int)_is_wide - 1;
+ if (isize == 2 && code() == Bytecodes::_iinc)
+ isize = 1;
+ else if (isize <= 2)
+ ; // no change
+ else if (has_giant_index())
+ isize = 4;
+ else
+ isize = 2;
+ assert(isize = required_size, "wrong index size");
+#endif
+ }
};
// In BytecodeStream, non-java bytecodes will be translated into the
diff --git a/src/share/vm/interpreter/bytecodeTracer.cpp b/src/share/vm/interpreter/bytecodeTracer.cpp
index 7ac0eafc7..018cb207c 100644
--- a/src/share/vm/interpreter/bytecodeTracer.cpp
+++ b/src/share/vm/interpreter/bytecodeTracer.cpp
@@ -48,12 +48,15 @@ class BytecodePrinter: public BytecodeClosure {
int get_index() { return *(address)_next_pc++; }
int get_big_index() { int i=Bytes::get_Java_u2(_next_pc); _next_pc+=2; return i; }
+ int get_giant_index() { int i=Bytes::get_native_u4(_next_pc); _next_pc+=4; return i; }
int get_index_special() { return (is_wide()) ? get_big_index() : get_index(); }
methodOop method() { return _current_method; }
bool is_wide() { return _is_wide; }
+ bool check_index(int i, bool in_cp_cache, int& cp_index, outputStream* st = tty);
void print_constant(int i, outputStream* st = tty);
+ void print_field_or_method(int i, outputStream* st = tty);
void print_attributes(Bytecodes::Code code, int bci, outputStream* st = tty);
void bytecode_epilog(int bci, outputStream* st = tty);
@@ -182,7 +185,71 @@ void print_oop(oop value, outputStream* st) {
}
}
+bool BytecodePrinter::check_index(int i, bool in_cp_cache, int& cp_index, outputStream* st) {
+ constantPoolOop constants = method()->constants();
+ int ilimit = constants->length(), climit = 0;
+
+ constantPoolCacheOop cache = NULL;
+ if (in_cp_cache) {
+ cache = constants->cache();
+ if (cache != NULL) {
+ //climit = cache->length(); // %%% private!
+ size_t size = cache->size() * HeapWordSize;
+ size -= sizeof(constantPoolCacheOopDesc);
+ size /= sizeof(ConstantPoolCacheEntry);
+ climit = (int) size;
+ }
+ }
+
+ if (in_cp_cache && constantPoolCacheOopDesc::is_secondary_index(i)) {
+ i = constantPoolCacheOopDesc::decode_secondary_index(i);
+ st->print(" secondary cache[%d] of", i);
+ if (i >= 0 && i < climit) {
+ if (!cache->entry_at(i)->is_secondary_entry()) {
+ st->print_cr(" not secondary entry?", i);
+ return false;
+ }
+ i = cache->entry_at(i)->main_entry_index();
+ goto check_cache_index;
+ } else {
+ st->print_cr(" not in cache[*]?", i);
+ return false;
+ }
+ }
+
+ if (cache != NULL) {
+ i = Bytes::swap_u2(i);
+ if (WizardMode) st->print(" (swap=%d)", i);
+ goto check_cache_index;
+ }
+
+ check_cp_index:
+ if (i >= 0 && i < ilimit) {
+ if (WizardMode) st->print(" cp[%d]", i);
+ cp_index = i;
+ return true;
+ }
+
+ st->print_cr(" CP[%d] not in CP", i);
+ return false;
+
+ check_cache_index:
+ if (i >= 0 && i < climit) {
+ if (cache->entry_at(i)->is_secondary_entry()) {
+ st->print_cr(" secondary entry?");
+ return false;
+ }
+ i = cache->entry_at(i)->constant_pool_index();
+ goto check_cp_index;
+ }
+ st->print_cr(" not in CP[*]?", i);
+ return false;
+}
+
void BytecodePrinter::print_constant(int i, outputStream* st) {
+ int orig_i = i;
+ if (!check_index(orig_i, false, i, st)) return;
+
constantPoolOop constants = method()->constants();
constantTag tag = constants->tag_at(i);
@@ -203,13 +270,36 @@ void BytecodePrinter::print_constant(int i, outputStream* st) {
st->print_cr(" %s", constants->resolved_klass_at(i)->klass_part()->external_name());
} else if (tag.is_unresolved_klass()) {
st->print_cr(" <unresolved klass at %d>", i);
- } else ShouldNotReachHere();
+ } else {
+ st->print_cr(" bad tag=%d at %d", tag.value(), i);
+ }
+}
+
+void BytecodePrinter::print_field_or_method(int i, outputStream* st) {
+ int orig_i = i;
+ if (!check_index(orig_i, true, i, st)) return;
+
+ constantPoolOop constants = method()->constants();
+ constantTag tag = constants->tag_at(i);
+
+ switch (tag.value()) {
+ case JVM_CONSTANT_InterfaceMethodref:
+ case JVM_CONSTANT_Methodref:
+ case JVM_CONSTANT_Fieldref:
+ break;
+ default:
+ st->print_cr(" bad tag=%d at %d", tag.value(), i);
+ return;
+ }
+
+ symbolOop name = constants->name_ref_at(orig_i);
+ symbolOop signature = constants->signature_ref_at(orig_i);
+ st->print_cr(" %d <%s> <%s> ", i, name->as_C_string(), signature->as_C_string());
}
void BytecodePrinter::print_attributes(Bytecodes::Code code, int bci, outputStream* st) {
// Show attributes of pre-rewritten codes
- code = Bytecodes::java_code(code);
// If the code doesn't have any fields there's nothing to print.
// note this is ==1 because the tableswitch and lookupswitch are
// zero size (for some reason) and we want to print stuff out for them.
@@ -354,36 +444,28 @@ void BytecodePrinter::print_attributes(Bytecodes::Code code, int bci, outputStre
case Bytecodes::_putstatic:
case Bytecodes::_getstatic:
case Bytecodes::_putfield:
- case Bytecodes::_getfield: {
- int i = get_big_index();
- constantPoolOop constants = method()->constants();
- symbolOop field = constants->name_ref_at(i);
- st->print_cr(" %d <%s>", i, field->as_C_string());
- }
+ case Bytecodes::_getfield:
+ print_field_or_method(get_big_index(), st);
break;
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
- { int i = get_big_index();
- constantPoolOop constants = method()->constants();
- symbolOop name = constants->name_ref_at(i);
- symbolOop signature = constants->signature_ref_at(i);
- st->print_cr(" %d <%s> <%s> ", i, name->as_C_string(), signature->as_C_string());
- }
+ print_field_or_method(get_big_index(), st);
break;
case Bytecodes::_invokeinterface:
{ int i = get_big_index();
int n = get_index();
- get_index();
- constantPoolOop constants = method()->constants();
- symbolOop name = constants->name_ref_at(i);
- symbolOop signature = constants->signature_ref_at(i);
- st->print_cr(" %d <%s> <%s> %d", i, name->as_C_string(), signature->as_C_string(), n);
+ get_index(); // ignore zero byte
+ print_field_or_method(i, st);
}
break;
+ case Bytecodes::_invokedynamic:
+ print_field_or_method(get_giant_index(), st);
+ break;
+
case Bytecodes::_new:
case Bytecodes::_checkcast:
case Bytecodes::_instanceof:
diff --git a/src/share/vm/interpreter/bytecodes.cpp b/src/share/vm/interpreter/bytecodes.cpp
index 5f8759441..56a89b398 100644
--- a/src/share/vm/interpreter/bytecodes.cpp
+++ b/src/share/vm/interpreter/bytecodes.cpp
@@ -357,7 +357,7 @@ void Bytecodes::initialize() {
def(_invokespecial , "invokespecial" , "bjj" , NULL , T_ILLEGAL, -1, true);
def(_invokestatic , "invokestatic" , "bjj" , NULL , T_ILLEGAL, 0, true);
def(_invokeinterface , "invokeinterface" , "bjj__", NULL , T_ILLEGAL, -1, true);
- def(_xxxunusedxxx , "xxxunusedxxx" , NULL , NULL , T_VOID , 0, false);
+ def(_invokedynamic , "invokedynamic" , "bjjjj", NULL , T_ILLEGAL, -1, true );
def(_new , "new" , "bii" , NULL , T_OBJECT , 1, true );
def(_newarray , "newarray" , "bc" , NULL , T_OBJECT , 0, true );
def(_anewarray , "anewarray" , "bii" , NULL , T_OBJECT , 0, true );
diff --git a/src/share/vm/interpreter/bytecodes.hpp b/src/share/vm/interpreter/bytecodes.hpp
index 609591c3f..bf8887259 100644
--- a/src/share/vm/interpreter/bytecodes.hpp
+++ b/src/share/vm/interpreter/bytecodes.hpp
@@ -218,7 +218,7 @@ class Bytecodes: AllStatic {
_invokespecial = 183, // 0xb7
_invokestatic = 184, // 0xb8
_invokeinterface = 185, // 0xb9
- _xxxunusedxxx = 186, // 0xba
+ _invokedynamic = 186, // 0xba // if EnableInvokeDynamic
_new = 187, // 0xbb
_newarray = 188, // 0xbc
_anewarray = 189, // 0xbd
diff --git a/src/share/vm/interpreter/interpreterRuntime.cpp b/src/share/vm/interpreter/interpreterRuntime.cpp
index 5d4a1640a..f50fd2bfc 100644
--- a/src/share/vm/interpreter/interpreterRuntime.cpp
+++ b/src/share/vm/interpreter/interpreterRuntime.cpp
@@ -681,6 +681,133 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes
IRT_END
+// First time execution: Resolve symbols, create a permanent CallSiteImpl object.
+IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
+ ResourceMark rm(thread);
+
+ assert(EnableInvokeDynamic, "");
+
+ const Bytecodes::Code bytecode = Bytecodes::_invokedynamic;
+
+ methodHandle caller_method(thread, method(thread));
+
+ // first determine if there is a bootstrap method
+ {
+ KlassHandle caller_klass(thread, caller_method->method_holder());
+ Handle bootm = SystemDictionary::find_bootstrap_method(caller_klass, KlassHandle(), CHECK);
+ if (bootm.is_null()) {
+ // If there is no bootstrap method, throw IncompatibleClassChangeError.
+ // This is a valid generic error type for resolution (JLS 12.3.3).
+ char buf[200];
+ jio_snprintf(buf, sizeof(buf), "Class %s has not declared a bootstrap method for invokedynamic",
+ (Klass::cast(caller_klass()))->external_name());
+ THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
+ }
+ }
+
+ constantPoolHandle pool(thread, caller_method->constants());
+ pool->set_invokedynamic(); // mark header to flag active call sites
+
+ int raw_index = four_byte_index(thread);
+ assert(constantPoolCacheOopDesc::is_secondary_index(raw_index), "invokedynamic indexes marked specially");
+
+ // there are two CPC entries that are of interest:
+ int site_index = constantPoolCacheOopDesc::decode_secondary_index(raw_index);
+ int main_index = pool->cache()->entry_at(site_index)->main_entry_index();
+ // and there is one CP entry, a NameAndType:
+ int nt_index = pool->map_instruction_operand_to_index(raw_index);
+
+ // first resolve the signature to a MH.invoke methodOop
+ if (!pool->cache()->entry_at(main_index)->is_resolved(bytecode)) {
+ JvmtiHideSingleStepping jhss(thread);
+ CallInfo info;
+ LinkResolver::resolve_invoke(info, Handle(), pool,
+ raw_index, bytecode, CHECK);
+ // The main entry corresponds to a JVM_CONSTANT_NameAndType, and serves
+ // as a common reference point for all invokedynamic call sites with
+ // that exact call descriptor. We will link it in the CP cache exactly
+ // as if it were an invokevirtual of MethodHandle.invoke.
+ pool->cache()->entry_at(main_index)->set_method(
+ bytecode,
+ info.resolved_method(),
+ info.vtable_index());
+ assert(pool->cache()->entry_at(main_index)->is_vfinal(), "f2 must be a methodOop");
+ }
+
+ // The method (f2 entry) of the main entry is the MH.invoke for the
+ // invokedynamic target call signature.
+ intptr_t f2_value = pool->cache()->entry_at(main_index)->f2();
+ methodHandle mh_invdyn(THREAD, (methodOop) f2_value);
+ assert(mh_invdyn.not_null() && mh_invdyn->is_method() && mh_invdyn->is_method_handle_invoke(),
+ "correct result from LinkResolver::resolve_invokedynamic");
+
+ symbolHandle call_site_name(THREAD, pool->nt_name_ref_at(nt_index));
+ Handle call_site
+ = SystemDictionary::make_dynamic_call_site(caller_method->method_holder(),
+ caller_method->method_idnum(),
+ caller_method->bci_from(bcp(thread)),
+ call_site_name,
+ mh_invdyn,
+ CHECK);
+
+ // In the secondary entry, the f1 field is the call site, and the f2 (index)
+ // field is some data about the invoke site.
+ int extra_data = 0;
+ pool->cache()->entry_at(site_index)->set_dynamic_call(call_site(), extra_data);
+}
+IRT_END
+
+
+// Called on first time execution, and also whenever the CallSite.target is null.
+// FIXME: Do more of this in Java code.
+IRT_ENTRY(void, InterpreterRuntime::bootstrap_invokedynamic(JavaThread* thread, oopDesc* call_site)) {
+ methodHandle mh_invdyn(thread, (methodOop) sun_dyn_CallSiteImpl::vmmethod(call_site));
+ Handle mh_type(thread, mh_invdyn->method_handle_type());
+ objArrayHandle mh_ptypes(thread, java_dyn_MethodType::ptypes(mh_type()));
+
+ // squish the arguments down to a single array
+ int nargs = mh_ptypes->length();
+ objArrayHandle arg_array;
+ {
+ objArrayOop aaoop = oopFactory::new_objArray(SystemDictionary::object_klass(), nargs, CHECK);
+ arg_array = objArrayHandle(thread, aaoop);
+ }
+ frame fr = thread->last_frame();
+ assert(fr.interpreter_frame_bcp() != NULL, "sanity");
+ int tos_offset = 0;
+ for (int i = nargs; --i >= 0; ) {
+ intptr_t* slot_addr = fr.interpreter_frame_tos_at(tos_offset++);
+ oop ptype = mh_ptypes->obj_at(i);
+ oop arg = NULL;
+ if (!java_lang_Class::is_primitive(ptype)) {
+ arg = *(oop*) slot_addr;
+ } else {
+ BasicType bt = java_lang_Class::primitive_type(ptype);
+ assert(frame::interpreter_frame_expression_stack_direction() < 0, "else reconsider this code");
+ jvalue value;
+ Interpreter::get_jvalue_in_slot(slot_addr, bt, &value);
+ tos_offset += type2size[bt]-1;
+ arg = java_lang_boxing_object::create(bt, &value, CHECK);
+ // FIXME: These boxing objects are not canonicalized under
+ // the Java autoboxing rules. They should be...
+ // The best approach would be to push the arglist creation into Java.
+ // The JVM should use a lower-level interface to communicate argument lists.
+ }
+ arg_array->obj_at_put(i, arg);
+ }
+
+ // now find the bootstrap method
+ oop bootstrap_mh_oop = instanceKlass::cast(fr.interpreter_frame_method()->method_holder())->bootstrap_method();
+ assert(bootstrap_mh_oop != NULL, "resolve_invokedynamic ensures a BSM");
+
+ // return the bootstrap method and argument array via vm_result/_2
+ thread->set_vm_result(bootstrap_mh_oop);
+ thread->set_vm_result_2(arg_array());
+}
+IRT_END
+
+
+
//------------------------------------------------------------------------------------------------------------------------
// Miscellaneous
diff --git a/src/share/vm/interpreter/interpreterRuntime.hpp b/src/share/vm/interpreter/interpreterRuntime.hpp
index 1c05bc9f4..bfc75699c 100644
--- a/src/share/vm/interpreter/interpreterRuntime.hpp
+++ b/src/share/vm/interpreter/interpreterRuntime.hpp
@@ -42,8 +42,11 @@ class InterpreterRuntime: AllStatic {
static bool already_resolved(JavaThread *thread) { return cache_entry(thread)->is_resolved(code(thread)); }
static int one_byte_index(JavaThread *thread) { return bcp(thread)[1]; }
static int two_byte_index(JavaThread *thread) { return Bytes::get_Java_u2(bcp(thread) + 1); }
+ static int four_byte_index(JavaThread *thread) { return Bytes::get_native_u4(bcp(thread) + 1); }
static int number_of_dimensions(JavaThread *thread) { return bcp(thread)[3]; }
- static ConstantPoolCacheEntry* cache_entry(JavaThread *thread) { return method(thread)->constants()->cache()->entry_at(Bytes::get_native_u2(bcp(thread) + 1)); }
+
+ static ConstantPoolCacheEntry* cache_entry_at(JavaThread *thread, int i) { return method(thread)->constants()->cache()->entry_at(i); }
+ static ConstantPoolCacheEntry* cache_entry(JavaThread *thread) { return cache_entry_at(thread, Bytes::get_native_u2(bcp(thread) + 1)); }
static void note_trap(JavaThread *thread, int reason, TRAPS);
public:
@@ -83,7 +86,9 @@ class InterpreterRuntime: AllStatic {
static void new_illegal_monitor_state_exception(JavaThread* thread);
// Calls
- static void resolve_invoke (JavaThread* thread, Bytecodes::Code bytecode);
+ static void resolve_invoke (JavaThread* thread, Bytecodes::Code bytecode);
+ static void resolve_invokedynamic(JavaThread* thread);
+ static void bootstrap_invokedynamic(JavaThread* thread, oopDesc* call_site);
// Breakpoints
static void _breakpoint(JavaThread* thread, methodOopDesc* method, address bcp);
diff --git a/src/share/vm/interpreter/linkResolver.cpp b/src/share/vm/interpreter/linkResolver.cpp
index 05cd97b0c..c9a2c13c5 100644
--- a/src/share/vm/interpreter/linkResolver.cpp
+++ b/src/share/vm/interpreter/linkResolver.cpp
@@ -947,6 +947,7 @@ void LinkResolver::resolve_invoke(CallInfo& result, Handle recv, constantPoolHan
case Bytecodes::_invokestatic : resolve_invokestatic (result, pool, index, CHECK); break;
case Bytecodes::_invokespecial : resolve_invokespecial (result, pool, index, CHECK); break;
case Bytecodes::_invokevirtual : resolve_invokevirtual (result, recv, pool, index, CHECK); break;
+ case Bytecodes::_invokedynamic : resolve_invokedynamic (result, pool, index, CHECK); break;
case Bytecodes::_invokeinterface: resolve_invokeinterface(result, recv, pool, index, CHECK); break;
}
return;
@@ -1008,6 +1009,30 @@ void LinkResolver::resolve_invokeinterface(CallInfo& result, Handle recv, consta
resolve_interface_call(result, recv, recvrKlass, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK);
}
+
+void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle pool, int raw_index, TRAPS) {
+ assert(EnableInvokeDynamic, "");
+
+ // This guy is reached from InterpreterRuntime::resolve_invokedynamic.
+
+ assert(constantPoolCacheOopDesc::is_secondary_index(raw_index), "must be secondary index");
+ int nt_index = pool->map_instruction_operand_to_index(raw_index);
+
+ // At this point, we only need the signature, and can ignore the name.
+ symbolHandle method_signature(THREAD, pool->nt_signature_ref_at(nt_index));
+ symbolHandle method_name = vmSymbolHandles::invoke_name();
+ KlassHandle resolved_klass = SystemDictionaryHandles::MethodHandle_klass();
+
+ // JSR 292: this must be an implicitly generated method MethodHandle.invoke(*...)
+ // The extra MH receiver will be inserted into the stack on every call.
+ methodHandle resolved_method;
+ lookup_implicit_method(resolved_method, resolved_klass, method_name, method_signature, CHECK);
+ if (resolved_method.is_null()) {
+ THROW(vmSymbols::java_lang_InternalError());
+ }
+ result.set_virtual(resolved_klass, KlassHandle(), resolved_method, resolved_method, resolved_method->vtable_index(), CHECK);
+}
+
//------------------------------------------------------------------------------------------------------------------------
#ifndef PRODUCT
diff --git a/src/share/vm/interpreter/linkResolver.hpp b/src/share/vm/interpreter/linkResolver.hpp
index f52197b05..a95873b4c 100644
--- a/src/share/vm/interpreter/linkResolver.hpp
+++ b/src/share/vm/interpreter/linkResolver.hpp
@@ -167,6 +167,7 @@ class LinkResolver: AllStatic {
static void resolve_invokespecial (CallInfo& result, constantPoolHandle pool, int index, TRAPS);
static void resolve_invokevirtual (CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS);
static void resolve_invokeinterface(CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS);
+ static void resolve_invokedynamic (CallInfo& result, constantPoolHandle pool, int index, TRAPS);
static void resolve_invoke (CallInfo& result, Handle recv, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS);
};
diff --git a/src/share/vm/interpreter/rewriter.cpp b/src/share/vm/interpreter/rewriter.cpp
index 778153895..b2451cd0e 100644
--- a/src/share/vm/interpreter/rewriter.cpp
+++ b/src/share/vm/interpreter/rewriter.cpp
@@ -25,39 +25,50 @@
# include "incls/_precompiled.incl"
# include "incls/_rewriter.cpp.incl"
-
-// Computes an index_map (new_index -> original_index) for contant pool entries
+// Computes a CPC map (new_index -> original_index) for constant pool entries
// that are referred to by the interpreter at runtime via the constant pool cache.
-void Rewriter::compute_index_maps(constantPoolHandle pool, intArray*& index_map, intStack*& inverse_index_map) {
- const int length = pool->length();
- index_map = new intArray(length, -1);
- // Choose an initial value large enough that we don't get frequent
- // calls to grow().
- inverse_index_map = new intStack(length / 2);
+// Also computes a CP map (original_index -> new_index).
+// Marks entries in CP which require additional processing.
+void Rewriter::compute_index_maps() {
+ const int length = _pool->length();
+ init_cp_map(length);
for (int i = 0; i < length; i++) {
- switch (pool->tag_at(i).value()) {
+ int tag = _pool->tag_at(i).value();
+ switch (tag) {
+ case JVM_CONSTANT_InterfaceMethodref:
case JVM_CONSTANT_Fieldref : // fall through
case JVM_CONSTANT_Methodref : // fall through
- case JVM_CONSTANT_InterfaceMethodref: {
- index_map->at_put(i, inverse_index_map->length());
- inverse_index_map->append(i);
- }
+ add_cp_cache_entry(i);
+ break;
}
}
+
+ guarantee((int)_cp_cache_map.length()-1 <= (int)((u2)-1),
+ "all cp cache indexes fit in a u2");
}
-// Creates a constant pool cache given an inverse_index_map
+int Rewriter::add_extra_cp_cache_entry(int main_entry) {
+ // Hack: We put it on the map as an encoded value.
+ // The only place that consumes this is ConstantPoolCacheEntry::set_initial_state
+ int encoded = constantPoolCacheOopDesc::encode_secondary_index(main_entry);
+ int plain_secondary_index = _cp_cache_map.append(encoded);
+ return constantPoolCacheOopDesc::encode_secondary_index(plain_secondary_index);
+}
+
+
+
+// Creates a constant pool cache given a CPC map
// This creates the constant pool cache initially in a state
// that is unsafe for concurrent GC processing but sets it to
// a safe mode before the constant pool cache is returned.
-constantPoolCacheHandle Rewriter::new_constant_pool_cache(intArray& inverse_index_map, TRAPS) {
- const int length = inverse_index_map.length();
- constantPoolCacheOop cache = oopFactory::new_constantPoolCache(length,
- methodOopDesc::IsUnsafeConc,
- CHECK_(constantPoolCacheHandle()));
- cache->initialize(inverse_index_map);
- return constantPoolCacheHandle(THREAD, cache);
+void Rewriter::make_constant_pool_cache(TRAPS) {
+ const int length = _cp_cache_map.length();
+ constantPoolCacheOop cache =
+ oopFactory::new_constantPoolCache(length, methodOopDesc::IsUnsafeConc, CHECK);
+ cache->initialize(_cp_cache_map);
+ _pool->set_cache(cache);
+ cache->set_constant_pool(_pool());
}
@@ -101,8 +112,38 @@ void Rewriter::rewrite_Object_init(methodHandle method, TRAPS) {
}
+// Rewrite a classfile-order CP index into a native-order CPC index.
+int Rewriter::rewrite_member_reference(address bcp, int offset) {
+ address p = bcp + offset;
+ int cp_index = Bytes::get_Java_u2(p);
+ int cache_index = cp_entry_to_cp_cache(cp_index);
+ Bytes::put_native_u2(p, cache_index);
+ return cp_index;
+}
+
+
+void Rewriter::rewrite_invokedynamic(address bcp, int offset, int delete_me) {
+ address p = bcp + offset;
+ assert(p[-1] == Bytecodes::_invokedynamic, "");
+ int cp_index = Bytes::get_Java_u2(p);
+ int cpc = maybe_add_cp_cache_entry(cp_index); // add lazily
+ int cpc2 = add_extra_cp_cache_entry(cpc);
+
+ // Replace the trailing four bytes with a CPC index for the dynamic
+ // call site. Unlike other CPC entries, there is one per bytecode,
+ // not just one per distinct CP entry. In other words, the
+ // CPC-to-CP relation is many-to-one for invokedynamic entries.
+ // This means we must use a larger index size than u2 to address
+ // all these entries. That is the main reason invokedynamic
+ // must have a five-byte instruction format. (Of course, other JVM
+ // implementations can use the bytes for other purposes.)
+ Bytes::put_native_u4(p, cpc2);
+ // Note: We use native_u4 format exclusively for 4-byte indexes.
+}
+
+
// Rewrites a method given the index_map information
-methodHandle Rewriter::rewrite_method(methodHandle method, intArray& index_map, TRAPS) {
+void Rewriter::scan_method(methodOop method) {
int nof_jsrs = 0;
bool has_monitor_bytecodes = false;
@@ -121,6 +162,7 @@ methodHandle Rewriter::rewrite_method(methodHandle method, intArray& index_map,
int bc_length;
for (int bci = 0; bci < code_length; bci += bc_length) {
address bcp = code_base + bci;
+ int prefix_length = 0;
c = (Bytecodes::Code)(*bcp);
// Since we have the code, see if we can get the length
@@ -135,6 +177,7 @@ methodHandle Rewriter::rewrite_method(methodHandle method, intArray& index_map,
// by 'wide'. We don't currently examine any of the bytecodes
// modified by wide, but in case we do in the future...
if (c == Bytecodes::_wide) {
+ prefix_length = 1;
c = (Bytecodes::Code)bcp[1];
}
}
@@ -159,12 +202,13 @@ methodHandle Rewriter::rewrite_method(methodHandle method, intArray& index_map,
case Bytecodes::_putfield : // fall through
case Bytecodes::_invokevirtual : // fall through
case Bytecodes::_invokespecial : // fall through
- case Bytecodes::_invokestatic : // fall through
- case Bytecodes::_invokeinterface: {
- address p = bcp + 1;
- Bytes::put_native_u2(p, index_map[Bytes::get_Java_u2(p)]);
+ case Bytecodes::_invokestatic :
+ case Bytecodes::_invokeinterface:
+ rewrite_member_reference(bcp, prefix_length+1);
+ break;
+ case Bytecodes::_invokedynamic:
+ rewrite_invokedynamic(bcp, prefix_length+1, int(sizeof"@@@@DELETE ME"));
break;
- }
case Bytecodes::_jsr : // fall through
case Bytecodes::_jsr_w : nof_jsrs++; break;
case Bytecodes::_monitorenter : // fall through
@@ -182,53 +226,56 @@ methodHandle Rewriter::rewrite_method(methodHandle method, intArray& index_map,
// have to be rewritten, so we run the oopMapGenerator on the method
if (nof_jsrs > 0) {
method->set_has_jsrs();
- ResolveOopMapConflicts romc(method);
- methodHandle original_method = method;
- method = romc.do_potential_rewrite(CHECK_(methodHandle()));
- if (method() != original_method()) {
- // Insert invalid bytecode into original methodOop and set
- // interpreter entrypoint, so that a executing this method
- // will manifest itself in an easy recognizable form.
- address bcp = original_method->bcp_from(0);
- *bcp = (u1)Bytecodes::_shouldnotreachhere;
- int kind = Interpreter::method_kind(original_method);
- original_method->set_interpreter_kind(kind);
- }
+ // Second pass will revisit this method.
+ assert(method->has_jsrs(), "");
+ }
+}
- // Update monitor matching info.
- if (romc.monitor_safe()) {
- method->set_guaranteed_monitor_matching();
- }
+// After constant pool is created, revisit methods containing jsrs.
+methodHandle Rewriter::rewrite_jsrs(methodHandle method, TRAPS) {
+ ResolveOopMapConflicts romc(method);
+ methodHandle original_method = method;
+ method = romc.do_potential_rewrite(CHECK_(methodHandle()));
+ if (method() != original_method()) {
+ // Insert invalid bytecode into original methodOop and set
+ // interpreter entrypoint, so that a executing this method
+ // will manifest itself in an easy recognizable form.
+ address bcp = original_method->bcp_from(0);
+ *bcp = (u1)Bytecodes::_shouldnotreachhere;
+ int kind = Interpreter::method_kind(original_method);
+ original_method->set_interpreter_kind(kind);
}
- // Setup method entrypoints for compiler and interpreter
- method->link_method(method, CHECK_(methodHandle()));
+ // Update monitor matching info.
+ if (romc.monitor_safe()) {
+ method->set_guaranteed_monitor_matching();
+ }
return method;
}
void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) {
- // gather starting points
ResourceMark rm(THREAD);
- constantPoolHandle pool (THREAD, klass->constants());
- objArrayHandle methods (THREAD, klass->methods());
- assert(pool->cache() == NULL, "constant pool cache must not be set yet");
+ Rewriter rw(klass, CHECK);
+ // (That's all, folks.)
+}
- // determine index maps for methodOop rewriting
- intArray* index_map = NULL;
- intStack* inverse_index_map = NULL;
- compute_index_maps(pool, index_map, inverse_index_map);
+Rewriter::Rewriter(instanceKlassHandle klass, TRAPS)
+ : _klass(klass),
+ // gather starting points
+ _pool( THREAD, klass->constants()),
+ _methods(THREAD, klass->methods())
+{
+ assert(_pool->cache() == NULL, "constant pool cache must not be set yet");
- // allocate constant pool cache
- constantPoolCacheHandle cache = new_constant_pool_cache(*inverse_index_map, CHECK);
- pool->set_cache(cache());
- cache->set_constant_pool(pool());
+ // determine index maps for methodOop rewriting
+ compute_index_maps();
- if (RegisterFinalizersAtInit && klass->name() == vmSymbols::java_lang_Object()) {
- int i = methods->length();
+ if (RegisterFinalizersAtInit && _klass->name() == vmSymbols::java_lang_Object()) {
+ int i = _methods->length();
while (i-- > 0) {
- methodOop method = (methodOop)methods->obj_at(i);
+ methodOop method = (methodOop)_methods->obj_at(i);
if (method->intrinsic_id() == vmIntrinsics::_Object_init) {
// rewrite the return bytecodes of Object.<init> to register the
// object for finalization if needed.
@@ -239,13 +286,27 @@ void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) {
}
}
- // rewrite methods
- { int i = methods->length();
- while (i-- > 0) {
- methodHandle m(THREAD, (methodOop)methods->obj_at(i));
- m = rewrite_method(m, *index_map, CHECK);
+ // rewrite methods, in two passes
+ int i, len = _methods->length();
+
+ for (i = len; --i >= 0; ) {
+ methodOop method = (methodOop)_methods->obj_at(i);
+ scan_method(method);
+ }
+
+ // allocate constant pool cache, now that we've seen all the bytecodes
+ make_constant_pool_cache(CHECK);
+
+ for (i = len; --i >= 0; ) {
+ methodHandle m(THREAD, (methodOop)_methods->obj_at(i));
+
+ if (m->has_jsrs()) {
+ m = rewrite_jsrs(m, CHECK);
// Method might have gotten rewritten.
- methods->obj_at_put(i, m());
+ _methods->obj_at_put(i, m());
}
+
+ // Set up method entry points for compiler and interpreter.
+ m->link_method(m, CHECK);
}
}
diff --git a/src/share/vm/interpreter/rewriter.hpp b/src/share/vm/interpreter/rewriter.hpp
index 847dad078..4b8ff7e60 100644
--- a/src/share/vm/interpreter/rewriter.hpp
+++ b/src/share/vm/interpreter/rewriter.hpp
@@ -25,13 +25,44 @@
// The Rewriter adds caches to the constant pool and rewrites bytecode indices
// pointing into the constant pool for better interpreter performance.
-class Rewriter: public AllStatic {
+class Rewriter: public StackObj {
private:
- static void compute_index_maps(constantPoolHandle pool, intArray*& index_map, intStack*& inverse_index_map);
- static constantPoolCacheHandle new_constant_pool_cache(intArray& inverse_index_map, TRAPS);
- static methodHandle rewrite_method(methodHandle method, intArray& index_map, TRAPS);
- static void rewrite_Object_init(methodHandle method, TRAPS);
+ instanceKlassHandle _klass;
+ constantPoolHandle _pool;
+ objArrayHandle _methods;
+ intArray _cp_map;
+ intStack _cp_cache_map;
+
+ void init_cp_map(int length) {
+ _cp_map.initialize(length, -1);
+ // Choose an initial value large enough that we don't get frequent
+ // calls to grow().
+ _cp_cache_map.initialize(length / 2);
+ }
+ int cp_entry_to_cp_cache(int i) { assert(has_cp_cache(i), "oob"); return _cp_map[i]; }
+ bool has_cp_cache(int i) { return (uint)i < (uint)_cp_map.length() && _cp_map[i] >= 0; }
+ int maybe_add_cp_cache_entry(int i) { return has_cp_cache(i) ? _cp_map[i] : add_cp_cache_entry(i); }
+ int add_cp_cache_entry(int cp_index) {
+ assert(_cp_map[cp_index] == -1, "not twice on same cp_index");
+ int cache_index = _cp_cache_map.append(cp_index);
+ _cp_map.at_put(cp_index, cache_index);
+ assert(cp_entry_to_cp_cache(cp_index) == cache_index, "");
+ return cache_index;
+ }
+ int add_extra_cp_cache_entry(int main_entry);
+
+ // All the work goes in here:
+ Rewriter(instanceKlassHandle klass, TRAPS);
+
+ void compute_index_maps();
+ void make_constant_pool_cache(TRAPS);
+ void scan_method(methodOop m);
+ methodHandle rewrite_jsrs(methodHandle m, TRAPS);
+ void rewrite_Object_init(methodHandle m, TRAPS);
+ int rewrite_member_reference(address bcp, int offset);
+ void rewrite_invokedynamic(address bcp, int offset, int cp_index);
public:
+ // Driver routine:
static void rewrite(instanceKlassHandle klass, TRAPS);
};
diff --git a/src/share/vm/interpreter/templateInterpreter.cpp b/src/share/vm/interpreter/templateInterpreter.cpp
index bdbd45682..437561732 100644
--- a/src/share/vm/interpreter/templateInterpreter.cpp
+++ b/src/share/vm/interpreter/templateInterpreter.cpp
@@ -178,12 +178,14 @@ EntryPoint TemplateInterpreter::_trace_code;
#endif // !PRODUCT
EntryPoint TemplateInterpreter::_return_entry[TemplateInterpreter::number_of_return_entries];
EntryPoint TemplateInterpreter::_earlyret_entry;
+EntryPoint TemplateInterpreter::_return_unbox_entry;
EntryPoint TemplateInterpreter::_deopt_entry [TemplateInterpreter::number_of_deopt_entries ];
EntryPoint TemplateInterpreter::_continuation_entry;
EntryPoint TemplateInterpreter::_safept_entry;
address TemplateInterpreter::_return_3_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
address TemplateInterpreter::_return_5_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
+address TemplateInterpreter::_return_5_unbox_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
DispatchTable TemplateInterpreter::_active_table;
DispatchTable TemplateInterpreter::_normal_table;
@@ -251,6 +253,22 @@ void TemplateInterpreterGenerator::generate_all() {
}
}
+ if (EnableInvokeDynamic) {
+ CodeletMark cm(_masm, "unboxing return entry points");
+ Interpreter::_return_unbox_entry =
+ EntryPoint(
+ generate_return_unbox_entry_for(btos, 5),
+ generate_return_unbox_entry_for(ctos, 5),
+ generate_return_unbox_entry_for(stos, 5),
+ generate_return_unbox_entry_for(atos, 5), // cast conversion
+ generate_return_unbox_entry_for(itos, 5),
+ generate_return_unbox_entry_for(ltos, 5),
+ generate_return_unbox_entry_for(ftos, 5),
+ generate_return_unbox_entry_for(dtos, 5),
+ Interpreter::_return_entry[5].entry(vtos) // no unboxing for void
+ );
+ }
+
{ CodeletMark cm(_masm, "earlyret entry points");
Interpreter::_earlyret_entry =
EntryPoint(
@@ -298,8 +316,11 @@ void TemplateInterpreterGenerator::generate_all() {
for (int j = 0; j < number_of_states; j++) {
const TosState states[] = {btos, ctos, stos, itos, ltos, ftos, dtos, atos, vtos};
- Interpreter::_return_3_addrs_by_index[Interpreter::TosState_as_index(states[j])] = Interpreter::return_entry(states[j], 3);
- Interpreter::_return_5_addrs_by_index[Interpreter::TosState_as_index(states[j])] = Interpreter::return_entry(states[j], 5);
+ int index = Interpreter::TosState_as_index(states[j]);
+ Interpreter::_return_3_addrs_by_index[index] = Interpreter::return_entry(states[j], 3);
+ Interpreter::_return_5_addrs_by_index[index] = Interpreter::return_entry(states[j], 5);
+ if (EnableInvokeDynamic)
+ Interpreter::_return_5_unbox_addrs_by_index[index] = Interpreter::return_unbox_entry(states[j], 5);
}
{ CodeletMark cm(_masm, "continuation entry points");
@@ -526,6 +547,18 @@ address TemplateInterpreter::return_entry(TosState state, int length) {
}
+address TemplateInterpreter::return_unbox_entry(TosState state, int length) {
+ assert(EnableInvokeDynamic, "");
+ if (state == vtos) {
+ // no unboxing to do, actually
+ return return_entry(state, length);
+ } else {
+ assert(length == 5, "unboxing entries generated for invokedynamic only");
+ return _return_unbox_entry.entry(state);
+ }
+}
+
+
address TemplateInterpreter::deopt_entry(TosState state, int length) {
guarantee(0 <= length && length < Interpreter::number_of_deopt_entries, "illegal length");
return _deopt_entry[length].entry(state);
diff --git a/src/share/vm/interpreter/templateInterpreter.hpp b/src/share/vm/interpreter/templateInterpreter.hpp
index 680ce5189..2c78e31fc 100644
--- a/src/share/vm/interpreter/templateInterpreter.hpp
+++ b/src/share/vm/interpreter/templateInterpreter.hpp
@@ -83,9 +83,9 @@ class TemplateInterpreter: public AbstractInterpreter {
public:
enum MoreConstants {
- number_of_return_entries = 9, // number of return entry points
- number_of_deopt_entries = 9, // number of deoptimization entry points
- number_of_return_addrs = 9 // number of return addresses
+ number_of_return_entries = number_of_states, // number of return entry points
+ number_of_deopt_entries = number_of_states, // number of deoptimization entry points
+ number_of_return_addrs = number_of_states // number of return addresses
};
protected:
@@ -110,12 +110,14 @@ class TemplateInterpreter: public AbstractInterpreter {
#endif // !PRODUCT
static EntryPoint _return_entry[number_of_return_entries]; // entry points to return to from a call
static EntryPoint _earlyret_entry; // entry point to return early from a call
+ static EntryPoint _return_unbox_entry; // entry point to unbox a return value from a call
static EntryPoint _deopt_entry[number_of_deopt_entries]; // entry points to return to from a deoptimization
static EntryPoint _continuation_entry;
static EntryPoint _safept_entry;
static address _return_3_addrs_by_index[number_of_return_addrs]; // for invokevirtual return entries
static address _return_5_addrs_by_index[number_of_return_addrs]; // for invokeinterface return entries
+ static address _return_5_unbox_addrs_by_index[number_of_return_addrs]; // for invokedynamic bootstrap methods
static DispatchTable _active_table; // the active dispatch table (used by the interpreter for dispatch)
static DispatchTable _normal_table; // the normal dispatch table (used to set the active table in normal mode)
@@ -157,10 +159,12 @@ class TemplateInterpreter: public AbstractInterpreter {
// Support for invokes
static address* return_3_addrs_by_index_table() { return _return_3_addrs_by_index; }
static address* return_5_addrs_by_index_table() { return _return_5_addrs_by_index; }
+ static address* return_5_unbox_addrs_by_index_table() { return _return_5_unbox_addrs_by_index; }
static int TosState_as_index(TosState state); // computes index into return_3_entry_by_index table
static address return_entry (TosState state, int length);
static address deopt_entry (TosState state, int length);
+ static address return_unbox_entry(TosState state, int length);
// Safepoint support
static void notice_safepoints(); // stops the thread when reaching a safepoint
diff --git a/src/share/vm/interpreter/templateInterpreterGenerator.hpp b/src/share/vm/interpreter/templateInterpreterGenerator.hpp
index 676e76272..9d5b69404 100644
--- a/src/share/vm/interpreter/templateInterpreterGenerator.hpp
+++ b/src/share/vm/interpreter/templateInterpreterGenerator.hpp
@@ -51,7 +51,10 @@ class TemplateInterpreterGenerator: public AbstractInterpreterGenerator {
address generate_WrongMethodType_handler();
address generate_ArrayIndexOutOfBounds_handler(const char* name);
address generate_continuation_for(TosState state);
- address generate_return_entry_for(TosState state, int step);
+ address generate_return_entry_for(TosState state, int step, bool unbox = false);
+ address generate_return_unbox_entry_for(TosState state, int step) {
+ return generate_return_entry_for(state, step, true);
+ }
address generate_earlyret_entry_for(TosState state);
address generate_deopt_entry_for(TosState state, int step);
address generate_safept_entry_for(TosState state, address runtime_entry);
diff --git a/src/share/vm/interpreter/templateTable.cpp b/src/share/vm/interpreter/templateTable.cpp
index 756b3f665..8e116ae77 100644
--- a/src/share/vm/interpreter/templateTable.cpp
+++ b/src/share/vm/interpreter/templateTable.cpp
@@ -442,6 +442,7 @@ void TemplateTable::initialize() {
def(Bytecodes::_invokespecial , ubcp|disp|clvm|____, vtos, vtos, invokespecial , 1 );
def(Bytecodes::_invokestatic , ubcp|disp|clvm|____, vtos, vtos, invokestatic , 1 );
def(Bytecodes::_invokeinterface , ubcp|disp|clvm|____, vtos, vtos, invokeinterface , 1 );
+ def(Bytecodes::_invokedynamic , ubcp|disp|clvm|____, vtos, vtos, invokedynamic , 1 );
def(Bytecodes::_new , ubcp|____|clvm|____, vtos, atos, _new , _ );
def(Bytecodes::_newarray , ubcp|____|clvm|____, itos, atos, newarray , _ );
def(Bytecodes::_anewarray , ubcp|____|clvm|____, itos, atos, anewarray , _ );
@@ -503,7 +504,6 @@ void TemplateTable::initialize() {
def(Bytecodes::_fast_invokevfinal , ubcp|disp|clvm|____, vtos, vtos, fast_invokevfinal , 2 );
-
def(Bytecodes::_fast_linearswitch , ubcp|disp|____|____, itos, vtos, fast_linearswitch , _ );
def(Bytecodes::_fast_binaryswitch , ubcp|disp|____|____, itos, vtos, fast_binaryswitch , _ );
diff --git a/src/share/vm/interpreter/templateTable.hpp b/src/share/vm/interpreter/templateTable.hpp
index af6bf870d..41d82d5e6 100644
--- a/src/share/vm/interpreter/templateTable.hpp
+++ b/src/share/vm/interpreter/templateTable.hpp
@@ -261,6 +261,7 @@ class TemplateTable: AllStatic {
static void invokespecial(int byte_no);
static void invokestatic(int byte_no);
static void invokeinterface(int byte_no);
+ static void invokedynamic(int byte_no);
static void fast_invokevfinal(int byte_no);
static void getfield_or_static(int byte_no, bool is_static);