Improve interpreter to interpreter invokes.
The interpreter constructs a shadow frame instead of arg array to make
interpreter to interpreter transitions faster. This adds a pointer to
an entry for the interpreter to each method.
Change-Id: If48911d3aa3470847b8548a9e92090b829f4f254
diff --git a/src/class_linker.cc b/src/class_linker.cc
index e55fe78..759bc0c 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -74,6 +74,8 @@
namespace art {
+extern "C" JValue artInterpreterToQuickEntry(Thread* self, ShadowFrame* shadow_frame);
+
static void ThrowNoClassDefFoundError(const char* fmt, ...)
__attribute__((__format__(__printf__, 1, 2)))
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -1037,6 +1039,12 @@
// Check if object is a method without its code set and point it to the resolution trampoline.
if (obj->IsMethod()) {
mirror::AbstractMethod* method = obj->AsMethod();
+ // Install entry point from interpreter.
+ if (method->GetCode() == NULL && !method->IsNative() && !method->IsProxyMethod()) {
+ method->SetEntryPointFromInterpreter(interpreter::EnterInterpreterFromInterpreter);
+ } else {
+ method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry);
+ }
if (method->GetCode() == NULL) {
method->SetCode(GetResolutionTrampoline());
}
@@ -1598,6 +1606,13 @@
const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
oat_method.LinkMethod(method.get());
+ // Install entry point from interpreter.
+ if (method->GetCode() == NULL && !method->IsNative() && !method->IsProxyMethod()) {
+ method->SetEntryPointFromInterpreter(interpreter::EnterInterpreterFromInterpreter);
+ } else {
+ method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry);
+ }
+
Runtime* runtime = Runtime::Current();
if (method->IsAbstract()) {
method->SetCode(GetAbstractMethodErrorStub());
@@ -2551,6 +2566,7 @@
#else
method->SetCode(reinterpret_cast<void*>(art_portable_proxy_invoke_handler));
#endif
+ method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry);
return method;
}
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index c47ce4a..94ea9d7 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -471,18 +471,19 @@
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, dex_cache_strings_), "dexCacheStrings"));
// alphabetical 32-bit
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, access_flags_), "accessFlags"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, code_), "code"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, code_item_offset_), "codeItemOffset"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, core_spill_mask_), "coreSpillMask"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, fp_spill_mask_), "fpSpillMask"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, frame_size_in_bytes_), "frameSizeInBytes"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, native_gc_map_), "gcMap"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, mapping_table_), "mappingTable"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, method_dex_index_), "methodDexIndex"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, method_index_), "methodIndex"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, native_method_), "nativeMethod"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, vmap_table_), "vmapTable"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, access_flags_), "accessFlags"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, code_), "code"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, code_item_offset_), "codeItemOffset"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, core_spill_mask_), "coreSpillMask"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, entry_point_from_interpreter_), "entryPointFromInterpreter"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, fp_spill_mask_), "fpSpillMask"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, frame_size_in_bytes_), "frameSizeInBytes"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, gc_map_), "gcMap"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, mapping_table_), "mappingTable"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, method_dex_index_), "methodDexIndex"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, method_index_), "methodIndex"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, native_method_), "nativeMethod"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AbstractMethod, vmap_table_), "vmapTable"));
};
};
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index 5ddd0a6..6b7d9e6 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -492,7 +492,7 @@
bool CompilerDriver::IsImageClass(const std::string& descriptor) const {
if (image_classes_ == NULL) {
- return true;
+ return false;
}
return image_classes_->find(descriptor) != image_classes_->end();
}
@@ -1649,7 +1649,6 @@
} else if (code_item->insns_size_in_code_units_ < Runtime::Current()->GetSmallModeMethodDexSizeLimit()) {
// Do compile small methods.
dont_compile = false;
- LOG(INFO) << "Compiling a small method: " << PrettyMethod(method_idx, dex_file);
}
if (!dont_compile) {
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index b82c632..9f48e78 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -42,6 +42,7 @@
using namespace art::mirror;
namespace art {
+
namespace interpreter {
static const int32_t kMaxInt = std::numeric_limits<int32_t>::max();
@@ -50,13 +51,13 @@
static const int64_t kMinLong = std::numeric_limits<int64_t>::min();
static void UnstartedRuntimeInvoke(Thread* self, AbstractMethod* target_method,
- Object* receiver, uint32_t* args, JValue* result)
+ ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// In a runtime that's not started we intercept certain methods to avoid complicated dependency
// problems in core libraries.
std::string name(PrettyMethod(target_method));
if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
- std::string descriptor(DotToDescriptor(reinterpret_cast<Object*>(args[0])->AsString()->ToModifiedUtf8().c_str()));
+ std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str()));
ClassLoader* class_loader = NULL; // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
Class* found = Runtime::Current()->GetClassLinker()->FindClass(descriptor.c_str(),
class_loader);
@@ -64,7 +65,7 @@
<< PrettyDescriptor(descriptor);
result->SetL(found);
} else if (name == "java.lang.Object java.lang.Class.newInstance()") {
- Class* klass = receiver->AsClass();
+ Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
AbstractMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V");
CHECK(c != NULL);
Object* obj = klass->AllocObject(self);
@@ -74,8 +75,8 @@
} else if (name == "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") {
// Special managed code cut-out to allow field lookup in a un-started runtime that'd fail
// going the reflective Dex way.
- Class* klass = receiver->AsClass();
- String* name = reinterpret_cast<Object*>(args[0])->AsString();
+ Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
+ String* name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString();
Field* found = NULL;
FieldHelper fh;
ObjectArray<Field>* fields = klass->GetIFields();
@@ -104,25 +105,25 @@
result->SetL(found);
} else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)") {
// Special case array copying without initializing System.
- Class* ctype = reinterpret_cast<Object*>(args[0])->GetClass()->GetComponentType();
- jint srcPos = args[1];
- jint dstPos = args[3];
- jint length = args[4];
+ Class* ctype = shadow_frame->GetVRegReference(arg_offset)->GetClass()->GetComponentType();
+ jint srcPos = shadow_frame->GetVReg(arg_offset + 1);
+ jint dstPos = shadow_frame->GetVReg(arg_offset + 3);
+ jint length = shadow_frame->GetVReg(arg_offset + 4);
if (!ctype->IsPrimitive()) {
- ObjectArray<Object>* src = reinterpret_cast<Object*>(args[0])->AsObjectArray<Object>();
- ObjectArray<Object>* dst = reinterpret_cast<Object*>(args[2])->AsObjectArray<Object>();
+ ObjectArray<Object>* src = shadow_frame->GetVRegReference(arg_offset)->AsObjectArray<Object>();
+ ObjectArray<Object>* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsObjectArray<Object>();
for (jint i = 0; i < length; ++i) {
dst->Set(dstPos + i, src->Get(srcPos + i));
}
} else if (ctype->IsPrimitiveChar()) {
- CharArray* src = reinterpret_cast<Object*>(args[0])->AsCharArray();
- CharArray* dst = reinterpret_cast<Object*>(args[2])->AsCharArray();
+ CharArray* src = shadow_frame->GetVRegReference(arg_offset)->AsCharArray();
+ CharArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsCharArray();
for (jint i = 0; i < length; ++i) {
dst->Set(dstPos + i, src->Get(srcPos + i));
}
} else if (ctype->IsPrimitiveInt()) {
- IntArray* src = reinterpret_cast<Object*>(args[0])->AsIntArray();
- IntArray* dst = reinterpret_cast<Object*>(args[2])->AsIntArray();
+ IntArray* src = shadow_frame->GetVRegReference(arg_offset)->AsIntArray();
+ IntArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsIntArray();
for (jint i = 0; i < length; ++i) {
dst->Set(dstPos + i, src->Get(srcPos + i));
}
@@ -131,7 +132,7 @@
}
} else {
// Not special, continue with regular interpreter execution.
- EnterInterpreterFromInvoke(self, target_method, receiver, args, result);
+ result->SetJ(EnterInterpreterFromInterpreter(self, shadow_frame).GetJ());
}
}
@@ -402,21 +403,65 @@
return;
}
mh.ChangeMethod(target_method);
- ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
- if (is_range) {
- arg_array.BuildArgArray(shadow_frame, receiver, dec_insn.vC + (type != kStatic ? 1 : 0));
+
+ const DexFile::CodeItem* code_item = mh.GetCodeItem();
+ uint16_t num_regs;
+ uint16_t num_ins;
+ if (code_item != NULL) {
+ num_regs = code_item->registers_size_;
+ num_ins = code_item->ins_size_;
+ } else if (target_method->IsAbstract()) {
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ self->ThrowNewExceptionF(throw_location, "Ljava/lang/AbstractMethodError;",
+ "abstract method \"%s\"", PrettyMethod(target_method).c_str());
+ return;
} else {
- arg_array.BuildArgArray(shadow_frame, receiver, dec_insn.arg + (type != kStatic ? 1 : 0));
- }
- if (LIKELY(Runtime::Current()->IsStarted())) {
- target_method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result,
- mh.GetShorty()[0]);
- } else {
- uint32_t* args = arg_array.GetArray();
- if (type != kStatic) {
- args++;
+ DCHECK(target_method->IsNative() || target_method->IsProxyMethod());
+ num_regs = num_ins = AbstractMethod::NumArgRegisters(mh.GetShorty());
+ if (!target_method->IsStatic()) {
+ num_regs++;
+ num_ins++;
}
- UnstartedRuntimeInvoke(self, target_method, receiver, args, result);
+ }
+
+ Runtime* runtime = Runtime::Current();
+ UniquePtr<ShadowFrame> new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame,
+ target_method, 0));
+ size_t cur_reg = num_regs - num_ins;
+ if (receiver != NULL) {
+ new_shadow_frame->SetVRegReference(cur_reg, receiver);
+ ++cur_reg;
+ }
+
+ size_t arg_offset = (receiver == NULL) ? 0 : 1;
+ const char* shorty = mh.GetShorty();
+ for (size_t shorty_pos = 0; cur_reg < num_regs; ++shorty_pos, cur_reg++, arg_offset++) {
+ DCHECK_LT(shorty_pos + 1, mh.GetShortyLength());
+ size_t arg_pos = is_range ? dec_insn.vC + arg_offset : dec_insn.arg[arg_offset];
+ switch (shorty[shorty_pos + 1]) {
+ case 'L': {
+ Object* o = shadow_frame.GetVRegReference(arg_pos);
+ new_shadow_frame->SetVRegReference(cur_reg, o);
+ break;
+ }
+ case 'J': case 'D': {
+ uint64_t wide_value = (static_cast<uint64_t>(shadow_frame.GetVReg(arg_pos + 1)) << 32) |
+ static_cast<uint32_t>(shadow_frame.GetVReg(arg_pos));
+ new_shadow_frame->SetVRegLong(cur_reg, wide_value);
+ cur_reg++;
+ arg_offset++;
+ break;
+ }
+ default:
+ new_shadow_frame->SetVReg(cur_reg, shadow_frame.GetVReg(arg_pos));
+ break;
+ }
+ }
+
+ if (LIKELY(runtime->IsStarted())) {
+ result->SetJ((target_method->GetEntryPointFromInterpreter())(self, new_shadow_frame.get()).GetJ());
+ } else {
+ UnstartedRuntimeInvoke(self, target_method, new_shadow_frame.get(), result, num_regs - num_ins);
}
mh.ChangeMethod(shadow_frame.GetMethod());
}
@@ -1925,5 +1970,42 @@
return Execute(self, mh, code_item, shadow_frame, JValue());
}
+JValue EnterInterpreterFromInterpreter(Thread* self, ShadowFrame* shadow_frame)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (__builtin_frame_address(0) < self->GetStackEnd()) {
+ ThrowStackOverflowError(self);
+ return JValue();
+ }
+
+ AbstractMethod* method = shadow_frame->GetMethod();
+ if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(method->GetDeclaringClass(),
+ true, true)) {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return JValue();
+ }
+ CHECK(method->GetDeclaringClass()->IsInitializing());
+ }
+
+ self->PushShadowFrame(shadow_frame);
+
+ MethodHelper mh(method);
+ const DexFile::CodeItem* code_item = mh.GetCodeItem();
+ JValue result;
+ if (LIKELY(!method->IsNative())) {
+ result = Execute(self, mh, code_item, *shadow_frame, JValue());
+ } else {
+ // We don't expect to be asked to interpret native code (which is entered via a JNI compiler
+ // generated stub) except during testing and image writing.
+ CHECK(!Runtime::Current()->IsStarted());
+ Object* receiver = method->IsStatic() ? NULL : shadow_frame->GetVRegReference(0);
+ uint32_t* args = shadow_frame->GetVRegArgs(method->IsStatic() ? 0 : 1);
+ UnstartedRuntimeJni(self, method, receiver, args, &result);
+ }
+
+ self->PopShadowFrame();
+ return result;
+}
+
} // namespace interpreter
} // namespace art
diff --git a/src/interpreter/interpreter.h b/src/interpreter/interpreter.h
index cf47b68..94fdff1 100644
--- a/src/interpreter/interpreter.h
+++ b/src/interpreter/interpreter.h
@@ -47,6 +47,9 @@
ShadowFrame& shadow_frame)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+extern JValue EnterInterpreterFromInterpreter(Thread* self, ShadowFrame* shadow_frame)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
} // namespace interpreter
} // namespace art
diff --git a/src/invoke_arg_array_builder.h b/src/invoke_arg_array_builder.h
index a6e99a5..b57d60a 100644
--- a/src/invoke_arg_array_builder.h
+++ b/src/invoke_arg_array_builder.h
@@ -162,60 +162,10 @@
}
}
- void BuildArgArray(const ShadowFrame& shadow_frame, mirror::Object* receiver, uint32_t range_start)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- // Set receiver if non-null (method is not static)
- if (receiver != NULL) {
- Append(reinterpret_cast<int32_t>(receiver));
- }
- for (size_t i = 1, reg_offset = 0; i < shorty_len_; ++i, ++reg_offset) {
- switch (shorty_[i]) {
- case 'Z':
- case 'B':
- case 'C':
- case 'S':
- case 'I':
- case 'F':
- Append(shadow_frame.GetVReg(range_start + reg_offset));
- break;
- case 'L':
- Append(reinterpret_cast<int32_t>(shadow_frame.GetVRegReference(range_start + reg_offset)));
- break;
- case 'D':
- case 'J':
- AppendWide(shadow_frame.GetVRegLong(range_start + reg_offset));
- reg_offset++;
- break;
- }
- }
- }
-
- void BuildArgArray(const ShadowFrame& shadow_frame, mirror::Object* receiver, const uint32_t* arg_regs)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- // Set receiver if non-null (method is not static)
- if (receiver != NULL) {
- Append(reinterpret_cast<int32_t>(receiver));
- }
- for (size_t i = 1, reg_offset = 0; i < shorty_len_; ++i, ++reg_offset) {
- switch (shorty_[i]) {
- case 'Z':
- case 'B':
- case 'C':
- case 'S':
- case 'I':
- case 'F':
- Append(shadow_frame.GetVReg(arg_regs[reg_offset]));
- break;
- case 'L':
- Append(reinterpret_cast<int32_t>(shadow_frame.GetVRegReference(arg_regs[reg_offset])));
- break;
- case 'D':
- case 'J':
- AppendWide(shadow_frame.GetVRegLong(arg_regs[reg_offset]));
- reg_offset++;
- break;
- }
- }
+ void BuildArgArray(ShadowFrame* shadow_frame, uint32_t arg_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ arg_array_ = shadow_frame->GetVRegArgs(arg_offset);
+ num_bytes_ = (shadow_frame->NumberOfVRegs() - arg_offset) * 4;
}
private:
diff --git a/src/mirror/abstract_method.cc b/src/mirror/abstract_method.cc
index 559b558..c351ce8 100644
--- a/src/mirror/abstract_method.cc
+++ b/src/mirror/abstract_method.cc
@@ -344,7 +344,7 @@
#else
UNIMPLEMENTED(FATAL);
#endif
- SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, native_gc_map_),
+ SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, gc_map_),
reinterpret_cast<const uint8_t*>(native_method), false);
}
}
diff --git a/src/mirror/abstract_method.h b/src/mirror/abstract_method.h
index 9440915..e955376 100644
--- a/src/mirror/abstract_method.h
+++ b/src/mirror/abstract_method.h
@@ -31,11 +31,14 @@
struct MethodClassOffsets;
struct MethodOffsets;
class StringPiece;
+class ShadowFrame;
namespace mirror {
class StaticStorageBase;
+typedef JValue (EntryPointFromInterpreter)(Thread* self, ShadowFrame* shadow_frame);
+
// C++ mirror of java.lang.reflect.Method and java.lang.reflect.Constructor
class MANAGED AbstractMethod : public Object {
public:
@@ -189,6 +192,14 @@
void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, char result_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ EntryPointFromInterpreter* GetEntryPointFromInterpreter() const {
+ return GetFieldPtr<EntryPointFromInterpreter*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, entry_point_from_interpreter_), false);
+ }
+
+ void SetEntryPointFromInterpreter(EntryPointFromInterpreter* entry_point_from_interpreter) {
+ SetFieldPtr<EntryPointFromInterpreter*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, entry_point_from_interpreter_), entry_point_from_interpreter, false);
+ }
+
const void* GetCode() const {
return GetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, code_), false);
}
@@ -293,11 +304,10 @@
void SetOatVmapTableOffset(uint32_t vmap_table_offset);
const uint8_t* GetNativeGcMap() const {
- return GetFieldPtr<uint8_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, native_gc_map_), false);
+ return GetFieldPtr<uint8_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, gc_map_), false);
}
void SetNativeGcMap(const uint8_t* data) {
- SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, native_gc_map_), data,
- false);
+ SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, gc_map_), data, false);
}
// When building the oat need a convenient place to stuff the offset of the native GC map.
@@ -424,6 +434,7 @@
// Compiled code associated with this method for callers from managed code.
// May be compiled managed code or a bridge for invoking a native method.
+ // TODO: Break apart this into portable and quick.
const void* code_;
// Offset to the CodeItem.
@@ -432,14 +443,17 @@
// Architecture-dependent register spill mask
uint32_t core_spill_mask_;
+ // Called by the interpreter to execute this method.
+ EntryPointFromInterpreter* entry_point_from_interpreter_;
+
// Architecture-dependent register spill mask
uint32_t fp_spill_mask_;
// Total size in bytes of the frame
size_t frame_size_in_bytes_;
- // Garbage collection map of native PC offsets to reference bitmaps.
- const uint8_t* native_gc_map_;
+ // Garbage collection map of native PC offsets (quick) or dex PCs (portable) to reference bitmaps.
+ const uint8_t* gc_map_;
// Mapping from native pc to dex pc
const uint32_t* mapping_table_;
diff --git a/src/oat/runtime/support_interpreter.cc b/src/oat/runtime/support_interpreter.cc
index 3ab234f..6a65cea 100644
--- a/src/oat/runtime/support_interpreter.cc
+++ b/src/oat/runtime/support_interpreter.cc
@@ -18,6 +18,7 @@
#include "callee_save_frame.h"
#include "dex_file-inl.h"
#include "interpreter/interpreter.h"
+#include "invoke_arg_array_builder.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
@@ -108,4 +109,19 @@
return result.GetJ();
}
+extern "C" JValue artInterpreterToQuickEntry(Thread* self, ShadowFrame* shadow_frame)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::AbstractMethod* method = shadow_frame->GetMethod();
+ MethodHelper mh(method);
+ const DexFile::CodeItem* code_item = mh.GetCodeItem();
+
+ uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
+ ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+ arg_array.BuildArgArray(shadow_frame, arg_offset);
+ JValue result;
+ method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), &result, mh.GetShorty()[0]);
+
+ return result;
+}
+
} // namespace art
diff --git a/src/stack.h b/src/stack.h
index e2148a3..8e597b2 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -145,6 +145,11 @@
}
}
+ // Get view of vregs as range of consecutive arguments starting at i.
+ uint32_t* GetVRegArgs(size_t i) {
+ return &vregs_[i];
+ }
+
void SetVReg(size_t i, int32_t val) {
DCHECK_LT(i, NumberOfVRegs());
uint32_t* vreg = &vregs_[i];