< prev index next >
src/share/vm/runtime/sharedRuntime.cpp
Print this page
@@ -37,11 +37,14 @@
#include "gc/shared/gcLocker.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "logging/log.hpp"
#include "memory/universe.inline.hpp"
+#include "oops/fieldStreams.hpp"
+#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
+#include "oops/valueKlass.hpp"
#include "prims/forte.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiRedefineClassesTrace.hpp"
#include "prims/methodHandles.hpp"
#include "prims/nativeLookup.hpp"
@@ -1153,11 +1156,12 @@
bc = bytecode.invoke_code();
}
bool has_receiver = bc != Bytecodes::_invokestatic &&
bc != Bytecodes::_invokedynamic &&
- bc != Bytecodes::_invokehandle;
+ bc != Bytecodes::_invokehandle &&
+ bc != Bytecodes::_invokedirect;
// Find receiver for non-static call
if (has_receiver) {
// This register map must be update since we need to find the receiver for
// compiled frames. The receiver might be in a register.
@@ -1365,13 +1369,13 @@
#ifdef ASSERT
address dest_entry_point = callee_nm == NULL ? 0 : callee_nm->entry_point(); // used below
#endif
if (is_virtual) {
- assert(receiver.not_null() || invoke_code == Bytecodes::_invokehandle, "sanity check");
+ assert(receiver.not_null() || invoke_code == Bytecodes::_invokehandle || invoke_code == Bytecodes::_invokedirect, "sanity check");
bool static_bound = call_info.resolved_method()->can_be_statically_bound();
- KlassHandle h_klass(THREAD, invoke_code == Bytecodes::_invokehandle ? NULL : receiver->klass());
+ KlassHandle h_klass(THREAD, (invoke_code == Bytecodes::_invokehandle || invoke_code == Bytecodes::_invokedirect) ? NULL : receiver->klass());
CompiledIC::compute_monomorphic_entry(callee_method, h_klass,
is_optimized, static_bound, virtual_call_info,
CHECK_(methodHandle()));
} else {
// static call
@@ -2497,19 +2501,74 @@
address c2i_entry,
address c2i_unverified_entry) {
return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
}
+// Value type arguments are not passed by reference, instead each
+// field of the value type is passed as an argument. This helper
+// function collects the fields of the value types (including embedded
+// value type's fields) in a list. Included with the field's type is
+// the offset of each field in the value type: i2c and c2i adapters
+// need that to load or store fields. Finally, the list of fields is
+// sorted in order of increasing offsets: the adapters and the
+// compiled code need and agreed upon order of fields.
+//
+// The list of basic type that is returned starts with a T_VALUETYPE
+// and ends with an extra T_VOID. T_VALUETYPE/T_VOID are used as
+// delimiters. Every entry between the two is a field of the value
+// type. If there's an embedded value type in the list, it also starts
+// with a T_VALUETYPE and ends with a T_VOID. This is so we can
+// generate a unique fingerprint for the method's adapters and we can
+// generate the list of basic types from the interpreter point of view
+// (value types passed as reference: iterate on the list until a
+// T_VALUETYPE, drop everything until and including the closing
+// T_VOID) or the compiler point of view (each field of the value
+// types is an argument: drop all T_VALUETYPE/T_VOID from the list).
+static GrowableArray<SigEntry> collect_fields(ValueKlass* vk, int base_off = 0) {
+ GrowableArray<SigEntry> sig;
+ sig.push(SigEntry(T_VALUETYPE, base_off));
+ for (JavaFieldStream fs(vk); !fs.done(); fs.next()) {
+ if (fs.access_flags().is_static()) continue;
+ fieldDescriptor& fd = fs.field_descriptor();
+ BasicType bt = fd.field_type();
+ int offset = base_off + fd.offset() - (base_off > 0 ? vk->first_field_offset() : 0);
+ if (bt == T_VALUETYPE) {
+ Symbol* signature = fd.signature();
+ JavaThread* THREAD = JavaThread::current();
+ oop loader = vk->class_loader();
+ oop protection_domain = vk->protection_domain();
+ Klass* klass = SystemDictionary::resolve_or_null(signature,
+ Handle(THREAD, loader), Handle(THREAD, protection_domain),
+ THREAD);
+ assert(klass != NULL && !HAS_PENDING_EXCEPTION, "lookup shouldn't fail");
+ const GrowableArray<SigEntry>& embedded = collect_fields(ValueKlass::cast(klass), offset);
+ sig.appendAll(&embedded);
+ } else {
+ sig.push(SigEntry(bt, offset));
+ if (bt == T_LONG || bt == T_DOUBLE) {
+ sig.push(SigEntry(T_VOID, offset));
+ }
+ }
+ }
+ int offset = base_off + vk->size_helper()*HeapWordSize - (base_off > 0 ? vk->first_field_offset() : 0);
+ sig.push(SigEntry(T_VOID, offset)); // hack: use T_VOID to mark end of value type fields
+ if (base_off == 0) {
+ sig.sort(SigEntry::compare);
+ }
+ assert(sig.at(0)._bt == T_VALUETYPE && sig.at(sig.length()-1)._bt == T_VOID, "broken structure");
+ return sig;
+}
+
AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) {
// Use customized signature handler. Need to lock around updates to
// the AdapterHandlerTable (it is not safe for concurrent readers
// and a single writer: this could be fixed if it becomes a
// problem).
ResourceMark rm;
- NOT_PRODUCT(int insts_size);
+ NOT_PRODUCT(int insts_size = 0);
AdapterBlob* new_adapter = NULL;
AdapterHandlerEntry* entry = NULL;
AdapterFingerPrint* fingerprint = NULL;
{
MutexLocker mu(AdapterHandlerLibrary_lock);
@@ -2528,26 +2587,82 @@
if (method->is_abstract()) {
return _abstract_method_handler;
}
// Fill in the signature array, for the calling-convention call.
- int total_args_passed = method->size_of_parameters(); // All args on stack
+ GrowableArray<SigEntry> sig;
+ {
+ MutexUnlocker mul(AdapterHandlerLibrary_lock);
+ Thread* THREAD = Thread::current();
+ Handle class_loader(THREAD, method->method_holder()->class_loader());
+ Handle protection_domain(THREAD, method->method_holder()->protection_domain());
+ GrowableArray<BasicType> sig_bt_tmp;
+ int value_klasses = 0;
- BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed);
- VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed);
int i = 0;
- if (!method->is_static()) // Pass in receiver first
- sig_bt[i++] = T_OBJECT;
+ if (!method->is_static()) { // Pass in receiver first
+ Klass* holder = method->method_holder();
+ if (ValueTypePassFieldsAsArgs && holder->is_value()) {
+ value_klasses++;
+ ValueKlass* vk = ValueKlass::cast(holder);
+ const GrowableArray<SigEntry>& sig_vk = collect_fields(vk);
+ sig.appendAll(&sig_vk);
+ } else {
+ sig.push(SigEntry(T_OBJECT));
+ }
+ }
for (SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) {
- sig_bt[i++] = ss.type(); // Collect remaining bits of signature
- if (ss.type() == T_LONG || ss.type() == T_DOUBLE)
- sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots
+ if (ValueTypePassFieldsAsArgs && ss.type() == T_VALUETYPE) {
+ value_klasses++;
+ Klass* k = ss.as_klass(class_loader, protection_domain, SignatureStream::ReturnNull, THREAD);
+ assert(k != NULL && !HAS_PENDING_EXCEPTION, "");
+ ValueKlass* vk = ValueKlass::cast(k);
+ const GrowableArray<SigEntry>& sig_vk = collect_fields(vk);
+ sig.appendAll(&sig_vk);
+ } else {
+ sig.push(SigEntry(ss.type()));
+ if (ss.type() == T_LONG || ss.type() == T_DOUBLE) {
+ sig.push(SigEntry(T_VOID));
+ }
+ }
+ }
}
- assert(i == total_args_passed, "");
+
+ int values = 0;
+ if (ValueTypePassFieldsAsArgs) {
+ for (int i = 0; i < sig.length(); i++) {
+ if (sig.at(i)._bt == T_VALUETYPE) {
+ values++;
+ }
+ }
+ }
+ int total_args_passed_cc = sig.length() - 2 * values;
+ BasicType* sig_bt_cc = NEW_RESOURCE_ARRAY(BasicType, total_args_passed_cc);
+
+ int j = 0;
+ for (int i = 0; i < sig.length(); i++) {
+ if (!ValueTypePassFieldsAsArgs) {
+ sig_bt_cc[j++] = sig.at(i)._bt;
+ } else if (sig.at(i)._bt != T_VALUETYPE &&
+ (sig.at(i)._bt != T_VOID ||
+ sig.at(i-1)._bt == T_LONG ||
+ sig.at(i-1)._bt == T_DOUBLE)) {
+ sig_bt_cc[j++] = sig.at(i)._bt;
+ }
+ }
+ assert(j == total_args_passed_cc, "");
+
+ int total_args_passed_fp = sig.length();
+ BasicType* sig_bt_fp = NEW_RESOURCE_ARRAY(BasicType, total_args_passed_fp);
+ for (int i = 0; i < sig.length(); i++) {
+ sig_bt_fp[i] = sig.at(i)._bt;
+ }
+
+ VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed_cc);
// Lookup method signature's fingerprint
- entry = _adapters->lookup(total_args_passed, sig_bt);
+ entry = _adapters->lookup(total_args_passed_fp, sig_bt_fp);
#ifdef ASSERT
AdapterHandlerEntry* shared_entry = NULL;
// Start adapter sharing verification only after the VM is booted.
if (VerifyAdapterSharing && (entry != NULL)) {
@@ -2559,14 +2674,14 @@
if (entry != NULL) {
return entry;
}
// Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage
- int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false);
+ int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt_cc, regs, total_args_passed_cc, false);
// Make a C heap allocated version of the fingerprint to store in the adapter
- fingerprint = new AdapterFingerPrint(total_args_passed, sig_bt);
+ fingerprint = new AdapterFingerPrint(total_args_passed_fp, sig_bt_fp);
// StubRoutines::code2() is initialized after this function can be called. As a result,
// VerifyAdapterCalls and VerifyAdapterSharing can fail if we re-use code that generated
// prior to StubRoutines::code2() being set. Checks refer to checks generated in an I2C
// stub that ensure that an I2C stub is called from an interpreter frame.
@@ -2578,17 +2693,18 @@
CodeBuffer buffer(buf);
short buffer_locs[20];
buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs,
sizeof(buffer_locs)/sizeof(relocInfo));
+
MacroAssembler _masm(&buffer);
entry = SharedRuntime::generate_i2c2i_adapters(&_masm,
- total_args_passed,
comp_args_on_stack,
- sig_bt,
+ sig,
regs,
- fingerprint);
+ fingerprint,
+ new_adapter);
#ifdef ASSERT
if (VerifyAdapterSharing) {
if (shared_entry != NULL) {
assert(shared_entry->compare_code(buf->code_begin(), buffer.insts_size()), "code must match");
// Release the one just created and return the original
@@ -2598,11 +2714,10 @@
entry->save_code(buf->code_begin(), buffer.insts_size());
}
}
#endif
- new_adapter = AdapterBlob::create(&buffer);
NOT_PRODUCT(insts_size = buffer.insts_size());
}
if (new_adapter == NULL) {
// CodeCache is full, disable compilation
// Ought to log this but compile log is only per compile thread
@@ -3072,5 +3187,52 @@
}
}
return activation;
}
+// We are at a compiled code to interpreter call. We need backing
+// buffers for all value type arguments. Allocate an object array to
+// hold them (convenient because once we're done with it we don't have
+// to worry about freeing it).
+JRT_ENTRY(void, SharedRuntime::allocate_value_types(JavaThread* thread))
+{
+ assert(ValueTypePassFieldsAsArgs, "no reason to call this");
+ ResourceMark rm;
+ JavaThread* THREAD = thread;
+ vframeStream vfst(thread);
+ methodHandle caller(thread, vfst.method());
+ int bci = vfst.bci();
+ Bytecode_invoke bytecode(caller, bci);
+ methodHandle callee = bytecode.static_target(CHECK);
+
+ int nb_slots = 0;
+ if (!callee->is_static() && callee->method_holder()->is_value()) {
+ nb_slots++;
+ }
+ Handle class_loader(THREAD, callee->method_holder()->class_loader());
+ Handle protection_domain(THREAD, callee->method_holder()->protection_domain());
+ for (SignatureStream ss(callee->signature()); !ss.at_return_type(); ss.next()) {
+ if (ss.type() == T_VALUETYPE) {
+ nb_slots++;
+ }
+ }
+ objArrayHandle array = ObjArrayKlass::cast(Universe::objectArrayKlassObj())->allocate(nb_slots, CHECK);
+ int i = 0;
+ if (!callee->is_static() && callee->method_holder()->is_value()) {
+ ValueKlass* vk = ValueKlass::cast(callee->method_holder());
+ oop res = vk->allocate_instance(CHECK);
+ array->obj_at_put(i, res);
+ i++;
+ }
+ for (SignatureStream ss(callee->signature()); !ss.at_return_type(); ss.next()) {
+ if (ss.type() == T_VALUETYPE) {
+ Klass* k = ss.as_klass(class_loader, protection_domain, SignatureStream::ReturnNull, THREAD);
+ assert(k != NULL && !HAS_PENDING_EXCEPTION, "");
+ ValueKlass* vk = ValueKlass::cast(k);
+ oop res = vk->allocate_instance(CHECK);
+ array->obj_at_put(i, res);
+ i++;
+ }
+ }
+ thread->set_vm_result(array());
+}
+JRT_END
< prev index next >