diff options
| author | 2012-10-17 00:10:17 -0700 | |
|---|---|---|
| committer | 2012-10-26 16:12:59 -0700 | |
| commit | 2fa6b2e2fc3d2a2fc27808ce518dc76b80ce369a (patch) | |
| tree | daba5f5e64409452e31ae42e3b1b6b6491ccb007 | |
| parent | 6ed960d260d0ec3cbbef455c646ccd47f4e78119 (diff) | |
Interpreter.
The opcodes filled-new-array and packed-switch aren't implemented but
are trivial given that they are variants of implemented opcodes.
Refactor Field::Get routines to take the declaring class in the case of
static field accesses. This avoids a check on every use of a field.
Refactor arg array builder to be shared by JNI invokes and invocations
into the interpreter.
Fix benign bug in const decoding in the verifier.
Change-Id: I8dee6c1f4b7f033e6c003422c56e9471cfaccda8
| -rw-r--r-- | build/Android.common.mk | 1 | ||||
| -rw-r--r-- | src/class_linker.cc | 4 | ||||
| -rw-r--r-- | src/class_linker_test.cc | 54 | ||||
| -rw-r--r-- | src/common_test.h | 1 | ||||
| -rw-r--r-- | src/compiler_llvm/runtime_support_llvm.cc | 24 | ||||
| -rw-r--r-- | src/debugger.cc | 2 | ||||
| -rw-r--r-- | src/dex_file.cc | 20 | ||||
| -rw-r--r-- | src/dex_instruction.h | 5 | ||||
| -rw-r--r-- | src/interpreter/interpreter.cc | 1500 | ||||
| -rw-r--r-- | src/interpreter/interpreter.h | 38 | ||||
| -rw-r--r-- | src/invoke_arg_array_builder.h | 213 | ||||
| -rw-r--r-- | src/jni_internal.cc | 173 | ||||
| -rw-r--r-- | src/jni_internal.h | 1 | ||||
| -rw-r--r-- | src/native/java_lang_reflect_Field.cc | 2 | ||||
| -rw-r--r-- | src/oat/jni/arm/jni_internal_arm.cc | 1 | ||||
| -rw-r--r-- | src/oat/jni/mips/jni_internal_mips.cc | 1 | ||||
| -rw-r--r-- | src/oat/jni/x86/jni_internal_x86.cc | 1 | ||||
| -rw-r--r-- | src/oat/runtime/support_cast.cc | 4 | ||||
| -rw-r--r-- | src/oat/runtime/support_field.cc | 24 | ||||
| -rw-r--r-- | src/object.cc | 121 | ||||
| -rw-r--r-- | src/object.h | 25 | ||||
| -rw-r--r-- | src/object_test.cc | 10 | ||||
| -rw-r--r-- | src/object_utils.h | 21 | ||||
| -rw-r--r-- | src/runtime.cc | 11 | ||||
| -rw-r--r-- | src/stack.h | 80 | ||||
| -rw-r--r-- | src/verifier/method_verifier.cc | 12 |
26 files changed, 2080 insertions, 269 deletions
diff --git a/build/Android.common.mk b/build/Android.common.mk index d14114908b..0d31237766 100644 --- a/build/Android.common.mk +++ b/build/Android.common.mk @@ -154,6 +154,7 @@ LIBART_COMMON_SRC_FILES := \ src/image_writer.cc \ src/indirect_reference_table.cc \ src/intern_table.cc \ + src/interpreter/interpreter.cc \ src/jdwp/jdwp_event.cc \ src/jdwp/jdwp_expand_buf.cc \ src/jdwp/jdwp_handler.cc \ diff --git a/src/class_linker.cc b/src/class_linker.cc index d28d729826..75f0f38158 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -2355,8 +2355,8 @@ Class* ClassLinker::CreateProxyClass(String* name, ObjectArray<Class>* interface } { ObjectLock lock(self, klass.get()); // Must hold lock on object when initializing. - interfaces_sfield->SetObject(NULL, interfaces); - throws_sfield->SetObject(NULL, throws); + interfaces_sfield->SetObject(klass.get(), interfaces); + throws_sfield->SetObject(klass.get(), throws); klass->SetStatus(Class::kStatusInitialized); } diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc index 1c41f3bef2..d32e91e98a 100644 --- a/src/class_linker_test.cc +++ b/src/class_linker_test.cc @@ -871,68 +871,68 @@ TEST_F(ClassLinkerTest, StaticFields) { FieldHelper fh(s0); EXPECT_STREQ(ClassHelper(s0->GetClass()).GetDescriptor(), "Ljava/lang/reflect/Field;"); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimBoolean); - EXPECT_EQ(true, s0->GetBoolean(NULL)); - s0->SetBoolean(NULL, false); + EXPECT_EQ(true, s0->GetBoolean(statics)); + s0->SetBoolean(statics, false); Field* s1 = statics->FindStaticField("s1", "B"); fh.ChangeField(s1); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimByte); - EXPECT_EQ(5, s1->GetByte(NULL)); - s1->SetByte(NULL, 6); + EXPECT_EQ(5, s1->GetByte(statics)); + s1->SetByte(statics, 6); Field* s2 = statics->FindStaticField("s2", "C"); fh.ChangeField(s2); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimChar); - EXPECT_EQ('a', s2->GetChar(NULL)); - s2->SetChar(NULL, 'b'); + EXPECT_EQ('a', s2->GetChar(statics)); + s2->SetChar(statics, 'b'); Field* s3 = statics->FindStaticField("s3", "S"); fh.ChangeField(s3); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimShort); - EXPECT_EQ(-536, s3->GetShort(NULL)); - s3->SetShort(NULL, -535); + EXPECT_EQ(-536, s3->GetShort(statics)); + s3->SetShort(statics, -535); Field* s4 = statics->FindStaticField("s4", "I"); fh.ChangeField(s4); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimInt); - EXPECT_EQ(2000000000, s4->GetInt(NULL)); - s4->SetInt(NULL, 2000000001); + EXPECT_EQ(2000000000, s4->GetInt(statics)); + s4->SetInt(statics, 2000000001); Field* s5 = statics->FindStaticField("s5", "J"); fh.ChangeField(s5); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimLong); - EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(NULL)); - s5->SetLong(NULL, 0x34567890abcdef12LL); + EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(statics)); + s5->SetLong(statics, 0x34567890abcdef12LL); Field* s6 = statics->FindStaticField("s6", "F"); fh.ChangeField(s6); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimFloat); - EXPECT_EQ(0.5, s6->GetFloat(NULL)); - s6->SetFloat(NULL, 0.75); + EXPECT_EQ(0.5, s6->GetFloat(statics)); + s6->SetFloat(statics, 0.75); Field* s7 = statics->FindStaticField("s7", "D"); fh.ChangeField(s7); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimDouble); - EXPECT_EQ(16777217, s7->GetDouble(NULL)); - s7->SetDouble(NULL, 16777219); + EXPECT_EQ(16777217, s7->GetDouble(statics)); + s7->SetDouble(statics, 16777219); Field* s8 = statics->FindStaticField("s8", "Ljava/lang/String;"); fh.ChangeField(s8); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimNot); - EXPECT_TRUE(s8->GetObject(NULL)->AsString()->Equals("android")); - s8->SetObject(NULL, String::AllocFromModifiedUtf8(soa.Self(), "robot")); + EXPECT_TRUE(s8->GetObject(statics)->AsString()->Equals("android")); + s8->SetObject(s8->GetDeclaringClass(), String::AllocFromModifiedUtf8(soa.Self(), "robot")); // TODO: Remove EXPECT_FALSE when GCC can handle EXPECT_EQ // http://code.google.com/p/googletest/issues/detail?id=322 - EXPECT_FALSE( s0->GetBoolean(NULL)); - EXPECT_EQ(6, s1->GetByte(NULL)); - EXPECT_EQ('b', s2->GetChar(NULL)); - EXPECT_EQ(-535, s3->GetShort(NULL)); - EXPECT_EQ(2000000001, s4->GetInt(NULL)); - EXPECT_EQ(0x34567890abcdef12LL, s5->GetLong(NULL)); - EXPECT_EQ(0.75, s6->GetFloat(NULL)); - EXPECT_EQ(16777219, s7->GetDouble(NULL)); - EXPECT_TRUE(s8->GetObject(NULL)->AsString()->Equals("robot")); + EXPECT_FALSE( s0->GetBoolean(statics)); + EXPECT_EQ(6, s1->GetByte(statics)); + EXPECT_EQ('b', s2->GetChar(statics)); + EXPECT_EQ(-535, s3->GetShort(statics)); + EXPECT_EQ(2000000001, s4->GetInt(statics)); + EXPECT_EQ(0x34567890abcdef12LL, s5->GetLong(statics)); + EXPECT_EQ(0.75, s6->GetFloat(statics)); + EXPECT_EQ(16777219, s7->GetDouble(statics)); + EXPECT_TRUE(s8->GetObject(statics)->AsString()->Equals("robot")); } TEST_F(ClassLinkerTest, Interfaces) { diff --git a/src/common_test.h b/src/common_test.h index 964db64c69..273d70efa9 100644 --- a/src/common_test.h +++ b/src/common_test.h @@ -306,6 +306,7 @@ class CommonTest : public testing::Test { #error unsupported OS #endif setenv("ANDROID_ROOT", root.c_str(), 1); + setenv("LD_LIBRARY_PATH", ":", 0); // Required by java.lang.System.<clinit>. } // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of art-cache diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc index 668712f6e7..e9726f8a7f 100644 --- a/src/compiler_llvm/runtime_support_llvm.cc +++ b/src/compiler_llvm/runtime_support_llvm.cc @@ -367,13 +367,13 @@ int32_t art_set32_static_from_code(uint32_t field_idx, AbstractMethod* referrer, SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(uint32_t)); if (LIKELY(field != NULL)) { - field->Set32(NULL, new_value); + field->Set32(field->GetDeclaringClass(), new_value); return 0; } field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(), StaticPrimitiveWrite, sizeof(uint32_t)); if (LIKELY(field != NULL)) { - field->Set32(NULL, new_value); + field->Set32(field->GetDeclaringClass(), new_value); return 0; } return -1; @@ -383,13 +383,13 @@ int32_t art_set64_static_from_code(uint32_t field_idx, AbstractMethod* referrer, SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(uint64_t)); if (LIKELY(field != NULL)) { - field->Set64(NULL, new_value); + field->Set64(field->GetDeclaringClass(), new_value); return 0; } field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(), StaticPrimitiveWrite, sizeof(uint64_t)); if (LIKELY(field != NULL)) { - field->Set64(NULL, new_value); + field->Set64(field->GetDeclaringClass(), new_value); return 0; } return -1; @@ -399,13 +399,13 @@ int32_t art_set_obj_static_from_code(uint32_t field_idx, AbstractMethod* referre SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Field* field = FindFieldFast(field_idx, referrer, StaticObjectWrite, sizeof(Object*)); if (LIKELY(field != NULL)) { - field->SetObj(NULL, new_value); + field->SetObj(field->GetDeclaringClass(), new_value); return 0; } field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(), StaticObjectWrite, sizeof(Object*)); if (LIKELY(field != NULL)) { - field->SetObj(NULL, new_value); + field->SetObj(field->GetDeclaringClass(), new_value); return 0; } return -1; @@ -415,12 +415,12 @@ int32_t art_get32_static_from_code(uint32_t field_idx, AbstractMethod* referrer) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint32_t)); if (LIKELY(field != NULL)) { - return field->Get32(NULL); + return field->Get32(field->GetDeclaringClass()); } field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(), StaticPrimitiveRead, sizeof(uint32_t)); if (LIKELY(field != NULL)) { - return field->Get32(NULL); + return field->Get32(field->GetDeclaringClass()); } return 0; } @@ -429,12 +429,12 @@ int64_t art_get64_static_from_code(uint32_t field_idx, AbstractMethod* referrer) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint64_t)); if (LIKELY(field != NULL)) { - return field->Get64(NULL); + return field->Get64(field->GetDeclaringClass()); } field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(), StaticPrimitiveRead, sizeof(uint64_t)); if (LIKELY(field != NULL)) { - return field->Get64(NULL); + return field->Get64(field->GetDeclaringClass()); } return 0; } @@ -443,12 +443,12 @@ Object* art_get_obj_static_from_code(uint32_t field_idx, AbstractMethod* referre SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Field* field = FindFieldFast(field_idx, referrer, StaticObjectRead, sizeof(Object*)); if (LIKELY(field != NULL)) { - return field->GetObj(NULL); + return field->GetObj(field->GetDeclaringClass()); } field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(), StaticObjectRead, sizeof(Object*)); if (LIKELY(field != NULL)) { - return field->GetObj(NULL); + return field->GetObj(field->GetDeclaringClass()); } return 0; } diff --git a/src/debugger.cc b/src/debugger.cc index a34f690026..7de675c4d2 100644 --- a/src/debugger.cc +++ b/src/debugger.cc @@ -1172,7 +1172,7 @@ void Dbg::OutputVariableTable(JDWP::RefTypeId, JDWP::MethodId methodId, bool wit // arg_count considers doubles and longs to take 2 units. // variable_count considers everything to take 1 unit. std::string shorty(mh.GetShorty()); - expandBufAdd4BE(pReply, m->NumArgRegisters(shorty)); + expandBufAdd4BE(pReply, AbstractMethod::NumArgRegisters(shorty)); // We don't know the total number of variables yet, so leave a blank and update it later. size_t variable_count_offset = expandBufGetLength(pReply); diff --git a/src/dex_file.cc b/src/dex_file.cc index c433f3dc48..b7cefe300b 100644 --- a/src/dex_file.cc +++ b/src/dex_file.cc @@ -978,18 +978,18 @@ void EncodedStaticFieldValueIterator::Next() { void EncodedStaticFieldValueIterator::ReadValueToField(Field* field) const { switch (type_) { - case kBoolean: field->SetBoolean(NULL, jval_.z); break; - case kByte: field->SetByte(NULL, jval_.b); break; - case kShort: field->SetShort(NULL, jval_.s); break; - case kChar: field->SetChar(NULL, jval_.c); break; - case kInt: field->SetInt(NULL, jval_.i); break; - case kLong: field->SetLong(NULL, jval_.j); break; - case kFloat: field->SetFloat(NULL, jval_.f); break; - case kDouble: field->SetDouble(NULL, jval_.d); break; - case kNull: field->SetObject(NULL, NULL); break; + case kBoolean: field->SetBoolean(field->GetDeclaringClass(), jval_.z); break; + case kByte: field->SetByte(field->GetDeclaringClass(), jval_.b); break; + case kShort: field->SetShort(field->GetDeclaringClass(), jval_.s); break; + case kChar: field->SetChar(field->GetDeclaringClass(), jval_.c); break; + case kInt: field->SetInt(field->GetDeclaringClass(), jval_.i); break; + case kLong: field->SetLong(field->GetDeclaringClass(), jval_.j); break; + case kFloat: field->SetFloat(field->GetDeclaringClass(), jval_.f); break; + case kDouble: field->SetDouble(field->GetDeclaringClass(), jval_.d); break; + case kNull: field->SetObject(field->GetDeclaringClass(), NULL); break; case kString: { String* resolved = linker_->ResolveString(dex_file_, jval_.i, dex_cache_); - field->SetObject(NULL, resolved); + field->SetObject(field->GetDeclaringClass(), resolved); break; } case kType: { diff --git a/src/dex_instruction.h b/src/dex_instruction.h index 90dca6999f..486bbf5ce8 100644 --- a/src/dex_instruction.h +++ b/src/dex_instruction.h @@ -253,6 +253,11 @@ class Instruction { kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgRange | kVerifyError)); } + // Get the dex PC of this instruction as a offset in code units from the beginning of insns. + uint32_t GetDexPc(const uint16_t* insns) const { + return (reinterpret_cast<const uint16_t*>(this) - insns); + } + // Dump decoded version of instruction std::string DumpString(const DexFile*) const; diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc new file mode 100644 index 0000000000..550c6ee106 --- /dev/null +++ b/src/interpreter/interpreter.cc @@ -0,0 +1,1500 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "interpreter.h" + +#include <math.h> + +#include "common_throws.h" +#include "dex_instruction.h" +#include "invoke_arg_array_builder.h" +#include "logging.h" +#include "object.h" +#include "object_utils.h" +#include "runtime_support.h" +#include "ScopedLocalRef.h" +#include "scoped_thread_state_change.h" +#include "thread.h" + +namespace art { +namespace interpreter { + +static void DoMonitorEnter(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS { + ref->MonitorEnter(self); +} + +static void DoMonitorExit(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS { + ref->MonitorExit(self); +} + +static void DoInvoke(Thread* self, MethodHelper& mh, ShadowFrame& shadow_frame, + const DecodedInstruction& dec_insn, InvokeType type, bool is_range, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Object* receiver; + if (type == kStatic) { + receiver = NULL; + } else { + receiver = shadow_frame.GetReference(dec_insn.vC); + if (UNLIKELY(receiver == NULL)) { + ThrowNullPointerExceptionForMethodAccess(shadow_frame.GetMethod(), dec_insn.vB, type); + result->SetJ(0); + return; + } + } + uint32_t method_idx = dec_insn.vB; + AbstractMethod* target_method = FindMethodFromCode(method_idx, receiver, + shadow_frame.GetMethod(), self, true, + type); + if (UNLIKELY(target_method == NULL)) { + CHECK(self->IsExceptionPending()); + result->SetJ(0); + return; + } + mh.ChangeMethod(target_method); + ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength()); + if (is_range) { + arg_array.BuildArgArray(shadow_frame, dec_insn.vC + (type != kStatic ? 1 : 0)); + } else { + arg_array.BuildArgArray(shadow_frame, dec_insn.arg + (type != kStatic ? 1 : 0)); + } + target_method->Invoke(self, receiver, arg_array.get(), result); + if (!mh.GetReturnType()->IsPrimitive() && result->GetL() != NULL) { + CHECK(mh.GetReturnType()->IsAssignableFrom(result->GetL()->GetClass())); + } + mh.ChangeMethod(shadow_frame.GetMethod()); +} + +static void DoFieldGet(Thread* self, ShadowFrame& shadow_frame, + const DecodedInstruction& dec_insn, FindFieldType find_type, + Primitive::Type field_type) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead); + uint32_t field_idx = is_static ? dec_insn.vB : dec_insn.vC; + Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self, + find_type, Primitive::FieldSize(field_type)); + if (LIKELY(f != NULL)) { + Object* obj; + if (is_static) { + obj = f->GetDeclaringClass(); + } else { + obj = shadow_frame.GetReference(dec_insn.vB); + if (UNLIKELY(obj == NULL)) { + ThrowNullPointerExceptionForFieldAccess(f, true); + } + } + switch (field_type) { + case Primitive::kPrimBoolean: + shadow_frame.SetVReg(dec_insn.vA, f->GetBoolean(obj)); + break; + case Primitive::kPrimByte: + shadow_frame.SetVReg(dec_insn.vA, f->GetByte(obj)); + break; + case Primitive::kPrimChar: + shadow_frame.SetVReg(dec_insn.vA, f->GetChar(obj)); + break; + case Primitive::kPrimShort: + shadow_frame.SetVReg(dec_insn.vA, f->GetShort(obj)); + break; + case Primitive::kPrimInt: + shadow_frame.SetVReg(dec_insn.vA, f->GetInt(obj)); + break; + case Primitive::kPrimLong: + shadow_frame.SetVRegLong(dec_insn.vA, f->GetLong(obj)); + break; + case Primitive::kPrimNot: + shadow_frame.SetReferenceAndVReg(dec_insn.vA, f->GetObject(obj)); + break; + default: + LOG(FATAL) << "Unreachable: " << field_type; + } + } +} + +static void DoFieldPut(Thread* self, ShadowFrame& shadow_frame, + const DecodedInstruction& dec_insn, FindFieldType find_type, + Primitive::Type field_type) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite); + uint32_t field_idx = is_static ? dec_insn.vB : dec_insn.vC; + Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self, + find_type, Primitive::FieldSize(field_type)); + if (LIKELY(f != NULL)) { + Object* obj; + if (is_static) { + obj = f->GetDeclaringClass(); + } else { + obj = shadow_frame.GetReference(dec_insn.vB); + if (UNLIKELY(obj == NULL)) { + ThrowNullPointerExceptionForFieldAccess(f, false); + } + } + switch (field_type) { + case Primitive::kPrimBoolean: + f->SetBoolean(obj, shadow_frame.GetVReg(dec_insn.vA)); + break; + case Primitive::kPrimByte: + f->SetByte(obj, shadow_frame.GetVReg(dec_insn.vA)); + shadow_frame.SetVReg(dec_insn.vA, f->GetByte(obj)); + break; + case Primitive::kPrimChar: + f->SetChar(obj, shadow_frame.GetVReg(dec_insn.vA)); + shadow_frame.SetVReg(dec_insn.vA, f->GetChar(obj)); + break; + case Primitive::kPrimShort: + f->SetShort(obj, shadow_frame.GetVReg(dec_insn.vA)); + shadow_frame.SetVReg(dec_insn.vA, f->GetShort(obj)); + break; + case Primitive::kPrimInt: + f->SetInt(obj, shadow_frame.GetVReg(dec_insn.vA)); + shadow_frame.SetVReg(dec_insn.vA, f->GetInt(obj)); + break; + case Primitive::kPrimLong: + f->SetLong(obj, shadow_frame.GetVRegLong(dec_insn.vA)); + shadow_frame.SetVRegLong(dec_insn.vA, f->GetLong(obj)); + break; + case Primitive::kPrimNot: + f->SetObj(obj, shadow_frame.GetReference(dec_insn.vA)); + break; + default: + LOG(FATAL) << "Unreachable: " << field_type; + } + } +} + +static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, + ShadowFrame& shadow_frame) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const uint16_t* insns = code_item->insns_; + const Instruction* inst = Instruction::At(insns + shadow_frame.GetDexPC()); + JValue result_register; + while (true) { + shadow_frame.SetDexPC(inst->GetDexPc(insns)); + DecodedInstruction dec_insn(inst); + const bool kTracing = true; + if (kTracing) { + LOG(INFO) << PrettyMethod(shadow_frame.GetMethod()) + << StringPrintf("\n0x%x: %s\nReferences:", + inst->GetDexPc(insns), inst->DumpString(&mh.GetDexFile()).c_str()); + for (size_t i = 0; i < shadow_frame.NumberOfReferences(); ++i) { + Object* o = shadow_frame.GetReference(i); + if (o != NULL) { + if (o->GetClass()->IsStringClass() && o->AsString()->GetCharArray() != NULL) { + LOG(INFO) << i << ": java.lang.String " << static_cast<void*>(o) + << " \"" << o->AsString()->ToModifiedUtf8() << "\""; + } else { + LOG(INFO) << i << ": " << PrettyTypeOf(o) << " " << static_cast<void*>(o); + } + } else { + LOG(INFO) << i << ": null"; + } + } + LOG(INFO) << "vregs:"; + for (size_t i = 0; i < shadow_frame.NumberOfReferences(); ++i) { + LOG(INFO) << StringPrintf("%d: %08x", i, shadow_frame.GetVReg(i)); + } + } + const Instruction* next_inst = inst->Next(); + switch (dec_insn.opcode) { + case Instruction::NOP: + break; + case Instruction::MOVE: + case Instruction::MOVE_FROM16: + case Instruction::MOVE_16: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::MOVE_WIDE: + case Instruction::MOVE_WIDE_FROM16: + case Instruction::MOVE_WIDE_16: + shadow_frame.SetVRegLong(dec_insn.vA, shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::MOVE_OBJECT: + case Instruction::MOVE_OBJECT_FROM16: + case Instruction::MOVE_OBJECT_16: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB)); + shadow_frame.SetReference(dec_insn.vA, shadow_frame.GetReference(dec_insn.vB)); + break; + case Instruction::MOVE_RESULT: + shadow_frame.SetVReg(dec_insn.vA, result_register.GetI()); + break; + case Instruction::MOVE_RESULT_WIDE: + shadow_frame.SetVRegLong(dec_insn.vA, result_register.GetJ()); + break; + case Instruction::MOVE_RESULT_OBJECT: + shadow_frame.SetReferenceAndVReg(dec_insn.vA, result_register.GetL()); + break; + case Instruction::MOVE_EXCEPTION: { + Throwable* exception = self->GetException(); + self->ClearException(); + shadow_frame.SetReferenceAndVReg(dec_insn.vA, exception); + break; + } + case Instruction::RETURN_VOID: { + JValue result; + result.SetJ(0); + return result; + } + case Instruction::RETURN: { + JValue result; + result.SetJ(0); + result.SetI(shadow_frame.GetVReg(dec_insn.vA)); + return result; + } + case Instruction::RETURN_WIDE: { + JValue result; + result.SetJ(shadow_frame.GetVRegLong(dec_insn.vA)); + return result; + } + case Instruction::RETURN_OBJECT: { + JValue result; + result.SetJ(0); + result.SetL(shadow_frame.GetReference(dec_insn.vA)); + return result; + } + case Instruction::CONST_4: { + int32_t val = (dec_insn.vB << 28) >> 28; + shadow_frame.SetVReg(dec_insn.vA, val); + if (val == 0) { + shadow_frame.SetReference(dec_insn.vA, NULL); + } + break; + } + case Instruction::CONST_16: { + int32_t val = static_cast<int16_t>(dec_insn.vB); + shadow_frame.SetVReg(dec_insn.vA, val); + if (val == 0) { + shadow_frame.SetReference(dec_insn.vA, NULL); + } + break; + } + case Instruction::CONST: { + int32_t val = dec_insn.vB; + shadow_frame.SetVReg(dec_insn.vA, val); + if (val == 0) { + shadow_frame.SetReference(dec_insn.vA, NULL); + } + break; + } + case Instruction::CONST_HIGH16: { + int32_t val = dec_insn.vB << 16; + shadow_frame.SetVReg(dec_insn.vA, val); + if (val == 0) { + shadow_frame.SetReference(dec_insn.vA, NULL); + } + break; + } + case Instruction::CONST_WIDE_16: { + int64_t val = static_cast<int16_t>(dec_insn.vB); + shadow_frame.SetVReg(dec_insn.vA, val); + shadow_frame.SetVReg(dec_insn.vA + 1, val >> 32); + break; + } + case Instruction::CONST_WIDE_32: { + int64_t val = static_cast<int32_t>(dec_insn.vB); + shadow_frame.SetVReg(dec_insn.vA, val); + shadow_frame.SetVReg(dec_insn.vA + 1, val >> 32); + break; + } + case Instruction::CONST_WIDE: + shadow_frame.SetVReg(dec_insn.vA, dec_insn.vB_wide); + shadow_frame.SetVReg(dec_insn.vA + 1, dec_insn.vB_wide >> 32); + break; + case Instruction::CONST_WIDE_HIGH16: + shadow_frame.SetVRegLong(dec_insn.vA + 1, static_cast<uint64_t>(dec_insn.vB) << 48); + break; + case Instruction::CONST_STRING: + case Instruction::CONST_STRING_JUMBO: { + if (UNLIKELY(!String::GetJavaLangString()->IsInitialized())) { + Runtime::Current()->GetClassLinker()->EnsureInitialized(String::GetJavaLangString(), + true, true); + } + String* s = mh.ResolveString(dec_insn.vB); + shadow_frame.SetReferenceAndVReg(dec_insn.vA, s); + break; + } + case Instruction::CONST_CLASS: + shadow_frame.SetReference(dec_insn.vA, mh.ResolveClass(dec_insn.vB)); + break; + case Instruction::MONITOR_ENTER: + DoMonitorEnter(self, shadow_frame.GetReference(dec_insn.vA)); + break; + case Instruction::MONITOR_EXIT: + DoMonitorExit(self, shadow_frame.GetReference(dec_insn.vA)); + break; + case Instruction::CHECK_CAST: { + Class* c = mh.ResolveClass(dec_insn.vB); + Object* obj = shadow_frame.GetReference(dec_insn.vA); + if (UNLIKELY(obj != NULL && !obj->InstanceOf(c))) { + self->ThrowNewExceptionF("Ljava/lang/ClassCastException;", + "%s cannot be cast to %s", + PrettyDescriptor(obj->GetClass()).c_str(), + PrettyDescriptor(c).c_str()); + } + break; + } + case Instruction::INSTANCE_OF: { + Class* c = mh.ResolveClass(dec_insn.vC); + Object* obj = shadow_frame.GetReference(dec_insn.vB); + shadow_frame.SetVReg(dec_insn.vA, (obj != NULL && obj->InstanceOf(c)) ? 1 : 0); + break; + } + case Instruction::ARRAY_LENGTH: { + Array* array = shadow_frame.GetReference(dec_insn.vB)->AsArray(); + if (UNLIKELY(array == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + shadow_frame.SetVReg(dec_insn.vA, array->GetLength()); + break; + } + case Instruction::NEW_INSTANCE: { + Object* obj = AllocObjectFromCode(dec_insn.vB, shadow_frame.GetMethod(), self, true); + shadow_frame.SetReferenceAndVReg(dec_insn.vA, obj); + break; + } + case Instruction::NEW_ARRAY: { + int32_t length = shadow_frame.GetVReg(dec_insn.vB); + Object* obj = AllocArrayFromCode(dec_insn.vC, shadow_frame.GetMethod(), length, self, true); + shadow_frame.SetReferenceAndVReg(dec_insn.vA, obj); + break; + } + case Instruction::FILLED_NEW_ARRAY: + case Instruction::FILLED_NEW_ARRAY_RANGE: + UNIMPLEMENTED(FATAL) << inst->DumpString(&mh.GetDexFile()); + break; + case Instruction::CMPL_FLOAT: { + float val1 = shadow_frame.GetVRegFloat(dec_insn.vB); + float val2 = shadow_frame.GetVRegFloat(dec_insn.vC); + int32_t result; + if (val1 == val2) { + result = 0; + } else if (val1 > val2) { + result = 1; + } else { + result = -1; + } + shadow_frame.SetVReg(dec_insn.vA, result); + break; + } + case Instruction::CMPG_FLOAT: { + float val1 = shadow_frame.GetVRegFloat(dec_insn.vB); + float val2 = shadow_frame.GetVRegFloat(dec_insn.vC); + int32_t result; + if (val1 == val2) { + result = 0; + } else if (val1 < val2) { + result = -1; + } else { + result = 1; + } + shadow_frame.SetVReg(dec_insn.vA, result); + break; + } + case Instruction::CMPL_DOUBLE: { + double val1 = shadow_frame.GetVRegDouble(dec_insn.vB); + double val2 = shadow_frame.GetVRegDouble(dec_insn.vC); + int32_t result; + if (val1 == val2) { + result = 0; + } else if (val1 > val2) { + result = 1; + } else { + result = -1; + } + shadow_frame.SetVReg(dec_insn.vA, result); + break; + } + + case Instruction::CMPG_DOUBLE: { + double val1 = shadow_frame.GetVRegDouble(dec_insn.vB); + double val2 = shadow_frame.GetVRegDouble(dec_insn.vC); + int32_t result; + if (val1 == val2) { + result = 0; + } else if (val1 < val2) { + result = -1; + } else { + result = 1; + } + shadow_frame.SetVReg(dec_insn.vA, result); + break; + } + case Instruction::CMP_LONG: { + int64_t val1 = shadow_frame.GetVRegLong(dec_insn.vB); + int64_t val2 = shadow_frame.GetVRegLong(dec_insn.vC); + int32_t result; + if (val1 < val2) { + result = -1; + } else if (val1 == val2) { + result = 0; + } else { + result = 1; + } + shadow_frame.SetVReg(dec_insn.vA, result); + break; + } + case Instruction::THROW: { + Throwable* t = shadow_frame.GetReference(dec_insn.vA)->AsThrowable(); + self->SetException(t); + break; + } + case Instruction::GOTO: + case Instruction::GOTO_16: + case Instruction::GOTO_32: { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vA); + break; + } + case Instruction::PACKED_SWITCH: + UNIMPLEMENTED(FATAL) << inst->DumpString(&mh.GetDexFile()); + break; + case Instruction::SPARSE_SWITCH: { + uint32_t dex_pc = inst->GetDexPc(insns); + const uint16_t* switchData = insns + dex_pc + dec_insn.vB; + int32_t testVal = shadow_frame.GetVReg(dec_insn.vA); + CHECK_EQ(switchData[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature)); + uint16_t size = switchData[1]; + CHECK_GT(size, 0); + const int32_t* keys = reinterpret_cast<const int32_t*>(&switchData[2]); + CHECK(IsAligned<4>(keys)); + const int32_t* entries = keys + size; + CHECK(IsAligned<4>(entries)); + int lo = 0; + int hi = size - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + int32_t foundVal = keys[mid]; + if (testVal < foundVal) { + hi = mid - 1; + } else if (testVal > foundVal) { + lo = mid + 1; + } else { + next_inst = Instruction::At(insns + dex_pc + entries[mid]); + break; + } + } + break; + } + case Instruction::FILL_ARRAY_DATA: { + Array* array = shadow_frame.GetReference(dec_insn.vA)->AsArray(); + if (UNLIKELY(array == NULL)) { + Thread::Current()->ThrowNewExceptionF("Ljava/lang/NullPointerException;", + "null array in FILL_ARRAY_DATA"); + break; + } + DCHECK(array->IsArrayInstance() && !array->IsObjectArray()); + uint32_t dex_pc = inst->GetDexPc(insns); + const Instruction::ArrayDataPayload* payload = + reinterpret_cast<const Instruction::ArrayDataPayload*>(insns + dex_pc + dec_insn.vB); + if (UNLIKELY(static_cast<int32_t>(payload->element_count) > array->GetLength())) { + Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;", + "failed FILL_ARRAY_DATA; length=%d, index=%d", + array->GetLength(), payload->element_count); + break; + } + uint32_t size_in_bytes = payload->element_count * payload->element_width; + memcpy(array->GetRawData(payload->element_width), payload->data, size_in_bytes); + break; + } + case Instruction::IF_EQ: { + if (shadow_frame.GetVReg(dec_insn.vA) == shadow_frame.GetVReg(dec_insn.vB)) { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vC); + } + break; + } + case Instruction::IF_NE: { + if (shadow_frame.GetVReg(dec_insn.vA) != shadow_frame.GetVReg(dec_insn.vB)) { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vC); + } + break; + } + case Instruction::IF_LT: { + if (shadow_frame.GetVReg(dec_insn.vA) < shadow_frame.GetVReg(dec_insn.vB)) { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vC); + } + break; + } + case Instruction::IF_GE: { + if (shadow_frame.GetVReg(dec_insn.vA) >= shadow_frame.GetVReg(dec_insn.vB)) { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vC); + } + break; + } + case Instruction::IF_GT: { + if (shadow_frame.GetVReg(dec_insn.vA) > shadow_frame.GetVReg(dec_insn.vB)) { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vC); + } + break; + } + case Instruction::IF_LE: { + if (shadow_frame.GetVReg(dec_insn.vA) <= shadow_frame.GetVReg(dec_insn.vB)) { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vC); + } + break; + } + case Instruction::IF_EQZ: { + if (shadow_frame.GetVReg(dec_insn.vA) == 0) { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vB); + } + break; + } + case Instruction::IF_NEZ: { + if (shadow_frame.GetVReg(dec_insn.vA) != 0) { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vB); + } + break; + } + case Instruction::IF_LTZ: { + if (shadow_frame.GetVReg(dec_insn.vA) < 0) { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vB); + } + break; + } + case Instruction::IF_GEZ: { + if (shadow_frame.GetVReg(dec_insn.vA) >= 0) { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vB); + } + break; + } + case Instruction::IF_GTZ: { + if (shadow_frame.GetVReg(dec_insn.vA) > 0) { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vB); + } + break; + } + case Instruction::IF_LEZ: { + if (shadow_frame.GetVReg(dec_insn.vA) <= 0) { + uint32_t dex_pc = inst->GetDexPc(insns); + next_inst = Instruction::At(insns + dex_pc + dec_insn.vB); + } + break; + } + case Instruction::AGET_BOOLEAN: { + BooleanArray* a = shadow_frame.GetReference(dec_insn.vB)->AsBooleanArray(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + shadow_frame.SetVReg(dec_insn.vA, a->Get(index)); + break; + } + case Instruction::AGET_BYTE: { + ByteArray* a = shadow_frame.GetReference(dec_insn.vB)->AsByteArray(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + shadow_frame.SetVReg(dec_insn.vA, a->Get(index)); + break; + } + case Instruction::AGET_CHAR: { + CharArray* a = shadow_frame.GetReference(dec_insn.vB)->AsCharArray(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + shadow_frame.SetVReg(dec_insn.vA, a->Get(index)); + break; + } + case Instruction::AGET_SHORT: { + ShortArray* a = shadow_frame.GetReference(dec_insn.vB)->AsShortArray(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + shadow_frame.SetVReg(dec_insn.vA, a->Get(index)); + break; + } + case Instruction::AGET: { + IntArray* a = shadow_frame.GetReference(dec_insn.vB)->AsIntArray(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + shadow_frame.SetVReg(dec_insn.vA, a->Get(index)); + break; + } + case Instruction::AGET_WIDE: { + LongArray* a = shadow_frame.GetReference(dec_insn.vB)->AsLongArray(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + shadow_frame.SetVRegLong(dec_insn.vA, a->Get(index)); + break; + } + case Instruction::AGET_OBJECT: { + ObjectArray<Object>* a = shadow_frame.GetReference(dec_insn.vB)->AsObjectArray<Object>(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + Object* o = a->Get(index); + shadow_frame.SetReferenceAndVReg(dec_insn.vA, o); + break; + } + case Instruction::APUT_BOOLEAN: { + uint8_t val = shadow_frame.GetVReg(dec_insn.vA); + BooleanArray* a = shadow_frame.GetReference(dec_insn.vB)->AsBooleanArray(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + a->Set(index, val); + break; + } + case Instruction::APUT_BYTE: { + int8_t val = shadow_frame.GetVReg(dec_insn.vA); + ByteArray* a = shadow_frame.GetReference(dec_insn.vB)->AsByteArray(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + a->Set(index, val); + break; + } + case Instruction::APUT_CHAR: { + uint16_t val = shadow_frame.GetVReg(dec_insn.vA); + CharArray* a = shadow_frame.GetReference(dec_insn.vB)->AsCharArray(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + a->Set(index, val); + break; + } + case Instruction::APUT_SHORT: { + int16_t val = shadow_frame.GetVReg(dec_insn.vA); + ShortArray* a = shadow_frame.GetReference(dec_insn.vB)->AsShortArray(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + a->Set(index, val); + break; + } + case Instruction::APUT: { + int32_t val = shadow_frame.GetVReg(dec_insn.vA); + IntArray* a = shadow_frame.GetReference(dec_insn.vB)->AsIntArray(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + a->Set(index, val); + break; + } + case Instruction::APUT_WIDE: { + int64_t val = shadow_frame.GetVRegLong(dec_insn.vA); + LongArray* a = shadow_frame.GetReference(dec_insn.vB)->AsLongArray(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + a->Set(index, val); + break; + } + case Instruction::APUT_OBJECT: { + Object* val = shadow_frame.GetReference(dec_insn.vA); + ObjectArray<Object>* a = shadow_frame.GetReference(dec_insn.vB)->AsObjectArray<Object>(); + if (UNLIKELY(a == NULL)) { + ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns)); + break; + } + int32_t index = shadow_frame.GetVReg(dec_insn.vC); + a->Set(index, val); + break; + } + case Instruction::IGET_BOOLEAN: + DoFieldGet(self, shadow_frame, dec_insn, InstancePrimitiveRead, Primitive::kPrimBoolean); + break; + case Instruction::IGET_BYTE: + DoFieldGet(self, shadow_frame, dec_insn, InstancePrimitiveRead, Primitive::kPrimByte); + break; + case Instruction::IGET_CHAR: + DoFieldGet(self, shadow_frame, dec_insn, InstancePrimitiveRead, Primitive::kPrimChar); + break; + case Instruction::IGET_SHORT: + DoFieldGet(self, shadow_frame, dec_insn, InstancePrimitiveRead, Primitive::kPrimShort); + break; + case Instruction::IGET: + DoFieldGet(self, shadow_frame, dec_insn, InstancePrimitiveRead, Primitive::kPrimInt); + break; + case Instruction::IGET_WIDE: + DoFieldGet(self, shadow_frame, dec_insn, InstancePrimitiveRead, Primitive::kPrimLong); + break; + case Instruction::IGET_OBJECT: + DoFieldGet(self, shadow_frame, dec_insn, InstanceObjectRead, Primitive::kPrimNot); + break; + case Instruction::SGET_BOOLEAN: + DoFieldGet(self, shadow_frame, dec_insn, StaticPrimitiveRead, Primitive::kPrimBoolean); + break; + case Instruction::SGET_BYTE: + DoFieldGet(self, shadow_frame, dec_insn, StaticPrimitiveRead, Primitive::kPrimByte); + break; + case Instruction::SGET_CHAR: + DoFieldGet(self, shadow_frame, dec_insn, StaticPrimitiveRead, Primitive::kPrimChar); + break; + case Instruction::SGET_SHORT: + DoFieldGet(self, shadow_frame, dec_insn, StaticPrimitiveRead, Primitive::kPrimShort); + break; + case Instruction::SGET: + DoFieldGet(self, shadow_frame, dec_insn, StaticPrimitiveRead, Primitive::kPrimInt); + break; + case Instruction::SGET_WIDE: + DoFieldGet(self, shadow_frame, dec_insn, StaticPrimitiveRead, Primitive::kPrimLong); + break; + case Instruction::SGET_OBJECT: + DoFieldGet(self, shadow_frame, dec_insn, StaticObjectRead, Primitive::kPrimNot); + break; + case Instruction::IPUT_BOOLEAN: + DoFieldPut(self, shadow_frame, dec_insn, InstancePrimitiveWrite, Primitive::kPrimBoolean); + break; + case Instruction::IPUT_BYTE: + DoFieldPut(self, shadow_frame, dec_insn, InstancePrimitiveWrite, Primitive::kPrimByte); + break; + case Instruction::IPUT_CHAR: + DoFieldPut(self, shadow_frame, dec_insn, InstancePrimitiveWrite, Primitive::kPrimChar); + break; + case Instruction::IPUT_SHORT: + DoFieldPut(self, shadow_frame, dec_insn, InstancePrimitiveWrite, Primitive::kPrimShort); + break; + case Instruction::IPUT: + DoFieldPut(self, shadow_frame, dec_insn, InstancePrimitiveWrite, Primitive::kPrimInt); + break; + case Instruction::IPUT_WIDE: + DoFieldPut(self, shadow_frame, dec_insn, InstancePrimitiveWrite, Primitive::kPrimLong); + break; + case Instruction::IPUT_OBJECT: + DoFieldPut(self, shadow_frame, dec_insn, InstanceObjectWrite, Primitive::kPrimNot); + break; + case Instruction::SPUT_BOOLEAN: + DoFieldPut(self, shadow_frame, dec_insn, StaticPrimitiveWrite, Primitive::kPrimBoolean); + break; + case Instruction::SPUT_BYTE: + DoFieldPut(self, shadow_frame, dec_insn, StaticPrimitiveWrite, Primitive::kPrimByte); + break; + case Instruction::SPUT_CHAR: + DoFieldPut(self, shadow_frame, dec_insn, StaticPrimitiveWrite, Primitive::kPrimChar); + break; + case Instruction::SPUT_SHORT: + DoFieldPut(self, shadow_frame, dec_insn, StaticPrimitiveWrite, Primitive::kPrimShort); + break; + case Instruction::SPUT: + DoFieldPut(self, shadow_frame, dec_insn, StaticPrimitiveWrite, Primitive::kPrimInt); + break; + case Instruction::SPUT_WIDE: + DoFieldPut(self, shadow_frame, dec_insn, StaticPrimitiveWrite, Primitive::kPrimLong); + break; + case Instruction::SPUT_OBJECT: + DoFieldPut(self, shadow_frame, dec_insn, StaticObjectWrite, Primitive::kPrimNot); + break; + case Instruction::INVOKE_VIRTUAL: + DoInvoke(self, mh, shadow_frame, dec_insn, kVirtual, false, &result_register); + break; + case Instruction::INVOKE_VIRTUAL_RANGE: + DoInvoke(self, mh, shadow_frame, dec_insn, kVirtual, true, &result_register); + break; + case Instruction::INVOKE_SUPER: + DoInvoke(self, mh, shadow_frame, dec_insn, kSuper, false, &result_register); + break; + case Instruction::INVOKE_SUPER_RANGE: + DoInvoke(self, mh, shadow_frame, dec_insn, kSuper, true, &result_register); + break; + case Instruction::INVOKE_DIRECT: + DoInvoke(self, mh, shadow_frame, dec_insn, kDirect, false, &result_register); + break; + case Instruction::INVOKE_DIRECT_RANGE: + DoInvoke(self, mh, shadow_frame, dec_insn, kDirect, true, &result_register); + break; + case Instruction::INVOKE_INTERFACE: + DoInvoke(self, mh, shadow_frame, dec_insn, kInterface, false, &result_register); + break; + case Instruction::INVOKE_INTERFACE_RANGE: + DoInvoke(self, mh, shadow_frame, dec_insn, kInterface, true, &result_register); + break; + case Instruction::INVOKE_STATIC: + DoInvoke(self, mh, shadow_frame, dec_insn, kStatic, false, &result_register); + break; + case Instruction::INVOKE_STATIC_RANGE: + DoInvoke(self, mh, shadow_frame, dec_insn, kStatic, true, &result_register); + break; + case Instruction::NEG_INT: + shadow_frame.SetVReg(dec_insn.vA, -shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::NOT_INT: + shadow_frame.SetVReg(dec_insn.vA, 0 ^ shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::NEG_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, -shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::NOT_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, 0 ^ shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::NEG_FLOAT: + shadow_frame.SetVRegFloat(dec_insn.vA, -shadow_frame.GetVRegFloat(dec_insn.vB)); + break; + case Instruction::NEG_DOUBLE: + shadow_frame.SetVRegDouble(dec_insn.vA, -shadow_frame.GetVRegDouble(dec_insn.vB)); + break; + case Instruction::INT_TO_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::INT_TO_FLOAT: + shadow_frame.SetVRegFloat(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::INT_TO_DOUBLE: + shadow_frame.SetVRegDouble(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::LONG_TO_INT: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::LONG_TO_FLOAT: + shadow_frame.SetVRegFloat(dec_insn.vA, shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::LONG_TO_DOUBLE: + shadow_frame.SetVRegDouble(dec_insn.vA, shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::FLOAT_TO_INT: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVRegFloat(dec_insn.vB)); + break; + case Instruction::FLOAT_TO_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, shadow_frame.GetVRegFloat(dec_insn.vB)); + break; + case Instruction::FLOAT_TO_DOUBLE: + shadow_frame.SetVRegDouble(dec_insn.vA, shadow_frame.GetVRegFloat(dec_insn.vB)); + break; + case Instruction::DOUBLE_TO_INT: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVRegDouble(dec_insn.vB)); + break; + case Instruction::DOUBLE_TO_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, shadow_frame.GetVRegDouble(dec_insn.vB)); + break; + case Instruction::DOUBLE_TO_FLOAT: + shadow_frame.SetVRegFloat(dec_insn.vA, shadow_frame.GetVRegDouble(dec_insn.vB)); + break; + case Instruction::INT_TO_BYTE: + shadow_frame.SetVReg(dec_insn.vA, static_cast<int8_t>(shadow_frame.GetVReg(dec_insn.vB))); + break; + case Instruction::INT_TO_CHAR: + shadow_frame.SetVReg(dec_insn.vA, static_cast<uint16_t>(shadow_frame.GetVReg(dec_insn.vB))); + break; + case Instruction::INT_TO_SHORT: + shadow_frame.SetVReg(dec_insn.vA, static_cast<int16_t>(shadow_frame.GetVReg(dec_insn.vB))); + break; + case Instruction::ADD_INT: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vB) + shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::SUB_INT: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vB) - shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::MUL_INT: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vB) * shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::REM_INT: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vB) % shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::DIV_INT: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vB) / shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::SHL_INT: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vB) << shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::SHR_INT: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vB) >> shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::USHR_INT: + shadow_frame.SetVReg(dec_insn.vA, + static_cast<uint32_t>(shadow_frame.GetVReg(dec_insn.vB)) >> + shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::AND_INT: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vB) & shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::OR_INT: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vB) | shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::XOR_INT: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vB) ^ shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::ADD_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vB) + + shadow_frame.GetVRegLong(dec_insn.vC)); + break; + case Instruction::SUB_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vB) - + shadow_frame.GetVRegLong(dec_insn.vC)); + break; + case Instruction::MUL_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vB) * + shadow_frame.GetVRegLong(dec_insn.vC)); + break; + case Instruction::DIV_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vB) / + shadow_frame.GetVRegLong(dec_insn.vC)); + break; + case Instruction::REM_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vB) % + shadow_frame.GetVRegLong(dec_insn.vC)); + break; + case Instruction::AND_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vB) & + shadow_frame.GetVRegLong(dec_insn.vC)); + break; + case Instruction::OR_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vB) | + shadow_frame.GetVRegLong(dec_insn.vC)); + break; + case Instruction::XOR_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vB) ^ + shadow_frame.GetVRegLong(dec_insn.vC)); + break; + case Instruction::SHL_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vB) << + shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::SHR_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vB) >> + shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::USHR_LONG: + shadow_frame.SetVRegLong(dec_insn.vA, + static_cast<uint64_t>(shadow_frame.GetVRegLong(dec_insn.vB)) >> + shadow_frame.GetVReg(dec_insn.vC)); + break; + case Instruction::ADD_FLOAT: + shadow_frame.SetVRegFloat(dec_insn.vA, + shadow_frame.GetVRegFloat(dec_insn.vB) + + shadow_frame.GetVRegFloat(dec_insn.vC)); + break; + case Instruction::SUB_FLOAT: + shadow_frame.SetVRegFloat(dec_insn.vA, + shadow_frame.GetVRegFloat(dec_insn.vB) - + shadow_frame.GetVRegFloat(dec_insn.vC)); + break; + case Instruction::MUL_FLOAT: + shadow_frame.SetVRegFloat(dec_insn.vA, + shadow_frame.GetVRegFloat(dec_insn.vB) * + shadow_frame.GetVRegFloat(dec_insn.vC)); + break; + case Instruction::DIV_FLOAT: + shadow_frame.SetVRegFloat(dec_insn.vA, + shadow_frame.GetVRegFloat(dec_insn.vB) / + shadow_frame.GetVRegFloat(dec_insn.vC)); + break; + case Instruction::REM_FLOAT: + shadow_frame.SetVRegFloat(dec_insn.vA, + fmodf(shadow_frame.GetVRegFloat(dec_insn.vB), + shadow_frame.GetVRegFloat(dec_insn.vC))); + break; + case Instruction::ADD_DOUBLE: + shadow_frame.SetVRegDouble(dec_insn.vA, + shadow_frame.GetVRegDouble(dec_insn.vB) + + shadow_frame.GetVRegDouble(dec_insn.vC)); + break; + case Instruction::SUB_DOUBLE: + shadow_frame.SetVRegDouble(dec_insn.vA, + shadow_frame.GetVRegDouble(dec_insn.vB) - + shadow_frame.GetVRegDouble(dec_insn.vC)); + break; + case Instruction::MUL_DOUBLE: + shadow_frame.SetVRegDouble(dec_insn.vA, + shadow_frame.GetVRegDouble(dec_insn.vB) * + shadow_frame.GetVRegDouble(dec_insn.vC)); + break; + case Instruction::DIV_DOUBLE: + shadow_frame.SetVRegDouble(dec_insn.vA, + shadow_frame.GetVRegDouble(dec_insn.vB) / + shadow_frame.GetVRegDouble(dec_insn.vC)); + break; + case Instruction::REM_DOUBLE: + shadow_frame.SetVRegDouble(dec_insn.vA, + fmod(shadow_frame.GetVRegDouble(dec_insn.vB), + shadow_frame.GetVRegDouble(dec_insn.vC))); + break; + case Instruction::ADD_INT_2ADDR: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vA) + shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::SUB_INT_2ADDR: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vA) - shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::MUL_INT_2ADDR: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vA) * shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::REM_INT_2ADDR: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vA) % shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::SHL_INT_2ADDR: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vA) << shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::SHR_INT_2ADDR: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vA) >> shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::USHR_INT_2ADDR: + shadow_frame.SetVReg(dec_insn.vA, + static_cast<uint32_t>(shadow_frame.GetVReg(dec_insn.vA)) >> + shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::AND_INT_2ADDR: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vA) & shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::OR_INT_2ADDR: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vA) | shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::XOR_INT_2ADDR: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vA) ^ shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::DIV_INT_2ADDR: + shadow_frame.SetVReg(dec_insn.vA, + shadow_frame.GetVReg(dec_insn.vA) / shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::ADD_LONG_2ADDR: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vA) + + shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::SUB_LONG_2ADDR: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vA) - + shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::MUL_LONG_2ADDR: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vA) + + shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::DIV_LONG_2ADDR: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vA) / + shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::REM_LONG_2ADDR: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vA) % + shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::AND_LONG_2ADDR: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vA) & + shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::OR_LONG_2ADDR: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vA) | + shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::XOR_LONG_2ADDR: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vA) ^ + shadow_frame.GetVRegLong(dec_insn.vB)); + break; + case Instruction::SHL_LONG_2ADDR: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vA) << + shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::SHR_LONG_2ADDR: + shadow_frame.SetVRegLong(dec_insn.vA, + shadow_frame.GetVRegLong(dec_insn.vA) >> + shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::USHR_LONG_2ADDR: + shadow_frame.SetVRegLong(dec_insn.vA, + static_cast<uint64_t>(shadow_frame.GetVRegLong(dec_insn.vA)) >> + shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::ADD_FLOAT_2ADDR: + shadow_frame.SetVRegFloat(dec_insn.vA, + shadow_frame.GetVRegFloat(dec_insn.vA) + + shadow_frame.GetVRegFloat(dec_insn.vB)); + break; + case Instruction::SUB_FLOAT_2ADDR: + shadow_frame.SetVRegFloat(dec_insn.vA, + shadow_frame.GetVRegFloat(dec_insn.vA) - + shadow_frame.GetVRegFloat(dec_insn.vB)); + break; + case Instruction::MUL_FLOAT_2ADDR: + shadow_frame.SetVRegFloat(dec_insn.vA, + shadow_frame.GetVRegFloat(dec_insn.vA) * + shadow_frame.GetVRegFloat(dec_insn.vB)); + break; + case Instruction::DIV_FLOAT_2ADDR: + shadow_frame.SetVRegFloat(dec_insn.vA, + shadow_frame.GetVRegFloat(dec_insn.vA) / + shadow_frame.GetVRegFloat(dec_insn.vB)); + break; + case Instruction::REM_FLOAT_2ADDR: + shadow_frame.SetVRegFloat(dec_insn.vA, + fmodf(shadow_frame.GetVRegFloat(dec_insn.vA), + shadow_frame.GetVRegFloat(dec_insn.vB))); + break; + case Instruction::ADD_DOUBLE_2ADDR: + shadow_frame.SetVRegDouble(dec_insn.vA, + shadow_frame.GetVRegDouble(dec_insn.vA) + + shadow_frame.GetVRegDouble(dec_insn.vB)); + break; + case Instruction::SUB_DOUBLE_2ADDR: + shadow_frame.SetVRegDouble(dec_insn.vA, + shadow_frame.GetVRegDouble(dec_insn.vA) - + shadow_frame.GetVRegDouble(dec_insn.vB)); + break; + case Instruction::MUL_DOUBLE_2ADDR: + shadow_frame.SetVRegDouble(dec_insn.vA, + shadow_frame.GetVRegDouble(dec_insn.vA) * + shadow_frame.GetVRegDouble(dec_insn.vB)); + break; + case Instruction::DIV_DOUBLE_2ADDR: + shadow_frame.SetVRegDouble(dec_insn.vA, + shadow_frame.GetVRegDouble(dec_insn.vA) / + shadow_frame.GetVRegDouble(dec_insn.vB)); + break; + case Instruction::REM_DOUBLE_2ADDR: + shadow_frame.SetVRegDouble(dec_insn.vA, + fmod(shadow_frame.GetVRegDouble(dec_insn.vA), + shadow_frame.GetVRegDouble(dec_insn.vB))); + break; + case Instruction::ADD_INT_LIT16: + case Instruction::ADD_INT_LIT8: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB) + dec_insn.vC); + break; + case Instruction::RSUB_INT: + case Instruction::RSUB_INT_LIT8: + shadow_frame.SetVReg(dec_insn.vA, dec_insn.vC - shadow_frame.GetVReg(dec_insn.vB)); + break; + case Instruction::MUL_INT_LIT16: + case Instruction::MUL_INT_LIT8: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB) * dec_insn.vC); + break; + case Instruction::DIV_INT_LIT16: + case Instruction::DIV_INT_LIT8: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB) / dec_insn.vC); + break; + case Instruction::REM_INT_LIT16: + case Instruction::REM_INT_LIT8: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB) % dec_insn.vC); + break; + case Instruction::AND_INT_LIT16: + case Instruction::AND_INT_LIT8: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB) & dec_insn.vC); + break; + case Instruction::OR_INT_LIT16: + case Instruction::OR_INT_LIT8: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB) | dec_insn.vC); + break; + case Instruction::XOR_INT_LIT16: + case Instruction::XOR_INT_LIT8: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB) ^ dec_insn.vC); + break; + case Instruction::SHL_INT_LIT8: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB) << dec_insn.vC); + break; + case Instruction::SHR_INT_LIT8: + shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB) >> dec_insn.vC); + break; + case Instruction::USHR_INT_LIT8: + shadow_frame.SetVReg(dec_insn.vA, + static_cast<uint32_t>(shadow_frame.GetVReg(dec_insn.vB)) >> + dec_insn.vC); + break; + default: + LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(&mh.GetDexFile()); + break; + } + if (UNLIKELY(self->IsExceptionPending())) { + uint32_t found_dex_pc = + shadow_frame.GetMethod()->FindCatchBlock(self->GetException()->GetClass(), + inst->GetDexPc(insns)); + if (found_dex_pc == DexFile::kDexNoIndex) { + JValue result; + result.SetJ(0); + return result; // Handler in caller. + } else { + next_inst = Instruction::At(insns + found_dex_pc); + } + } + inst = next_inst; + } +} + +void EnterInterpreterFromInvoke(Thread* self, AbstractMethod* method, Object* receiver, + JValue* args, JValue* result) { + MethodHelper mh(method); + 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 { + DCHECK(method->IsNative()); + num_regs = num_ins = AbstractMethod::NumArgRegisters(mh.GetShorty()); + if (!method->IsStatic()) { + num_regs++; + num_ins++; + } + } + // Set up shadow frame with matching number of reference slots to vregs. + ShadowFrame* last_shadow_frame = self->GetManagedStack()->GetTopShadowFrame(); + UniquePtr<ShadowFrame> shadow_frame(ShadowFrame::Create(num_regs, num_regs, + (last_shadow_frame == NULL) ? NULL : last_shadow_frame->GetLink(), + method, 0)); + self->PushShadowFrame(shadow_frame.get()); + size_t cur_reg = num_regs - num_ins; + if (!method->IsStatic()) { + CHECK(receiver != NULL); + shadow_frame->SetReferenceAndVReg(cur_reg, receiver); + ++cur_reg; + } else if (!method->GetDeclaringClass()->IsInitializing()) { + Runtime::Current()->GetClassLinker()->EnsureInitialized(method->GetDeclaringClass(), + true, true); + CHECK(method->GetDeclaringClass()->IsInitializing()); + } + StringPiece shorty(mh.GetShorty()); + size_t arg_pos = 0; + for (; cur_reg < num_regs; ++cur_reg, ++arg_pos) { + DCHECK_LT(arg_pos + 1, mh.GetShortyLength()); + switch (shorty[arg_pos + 1]) { + case 'L': { + Object* o = args[arg_pos].GetL(); + shadow_frame->SetReferenceAndVReg(cur_reg, o); + break; + } + case 'J': case 'D': + shadow_frame->SetVRegLong(cur_reg, args[arg_pos].GetJ()); + cur_reg++; + break; + default: + shadow_frame->SetVReg(cur_reg, args[arg_pos].GetI()); + break; + } + } + if (!method->IsNative()) { + JValue r = Execute(self, mh, code_item, *shadow_frame.get()); + if (result != NULL) { + *result = r; + } + } else { + // TODO: The following enters JNI code using a typedef-ed function rather than the JNI compiler, + // it should be removed and JNI compiled stubs used instead. + ScopedObjectAccessUnchecked soa(self); + if (method->IsStatic()) { + if (shorty == "L") { + typedef jobject (fnptr)(JNIEnv*, jclass); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedThreadStateChange tsc(self, kNative); + result->SetL(soa.Decode<Object*>(fn(soa.Env(), klass.get()))); + } else if (shorty == "V") { + typedef void (fnptr)(JNIEnv*, jclass); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedThreadStateChange tsc(self, kNative); + fn(soa.Env(), klass.get()); + } else if (shorty == "Z") { + typedef jboolean (fnptr)(JNIEnv*, jclass); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedThreadStateChange tsc(self, kNative); + result->SetZ(fn(soa.Env(), klass.get())); + } else if (shorty == "BI") { + typedef jbyte (fnptr)(JNIEnv*, jclass, jint); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedThreadStateChange tsc(self, kNative); + result->SetB(fn(soa.Env(), klass.get(), args[0].GetI())); + } else if (shorty == "II") { + typedef jint (fnptr)(JNIEnv*, jclass, jint); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedThreadStateChange tsc(self, kNative); + result->SetI(fn(soa.Env(), klass.get(), args[0].GetI())); + } else if (shorty == "LL") { + typedef jobject (fnptr)(JNIEnv*, jclass, jobject); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedLocalRef<jobject> arg0(soa.Env(), + soa.AddLocalReference<jobject>(args[0].GetL())); + ScopedThreadStateChange tsc(self, kNative); + result->SetL(soa.Decode<Object*>(fn(soa.Env(), klass.get(), arg0.get()))); + } else if (shorty == "IIZ") { + typedef jint (fnptr)(JNIEnv*, jclass, jint, jboolean); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedThreadStateChange tsc(self, kNative); + result->SetI(fn(soa.Env(), klass.get(), args[0].GetI(), args[1].GetZ())); + } else if (shorty == "ILI") { + typedef jint (fnptr)(JNIEnv*, jclass, jobject, jint); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedLocalRef<jobject> arg0(soa.Env(), + soa.AddLocalReference<jobject>(args[0].GetL())); + ScopedThreadStateChange tsc(self, kNative); + result->SetI(fn(soa.Env(), klass.get(), arg0.get(), args[1].GetI())); + } else if (shorty == "SIZ") { + typedef jshort (fnptr)(JNIEnv*, jclass, jint, jboolean); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedThreadStateChange tsc(self, kNative); + result->SetS(fn(soa.Env(), klass.get(), args[0].GetI(), args[1].GetZ())); + } else if (shorty == "VIZ") { + typedef void (fnptr)(JNIEnv*, jclass, jint, jboolean); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedThreadStateChange tsc(self, kNative); + fn(soa.Env(), klass.get(), args[0].GetI(), args[1].GetZ()); + } else if (shorty == "ZLL") { + typedef jboolean (fnptr)(JNIEnv*, jclass, jobject, jobject); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedLocalRef<jobject> arg0(soa.Env(), + soa.AddLocalReference<jobject>(args[0].GetL())); + ScopedLocalRef<jobject> arg1(soa.Env(), + soa.AddLocalReference<jobject>(args[1].GetL())); + ScopedThreadStateChange tsc(self, kNative); + result->SetZ(fn(soa.Env(), klass.get(), arg0.get(), arg1.get())); + } else if (shorty == "ZILL") { + typedef jboolean (fnptr)(JNIEnv*, jclass, jint, jobject, jobject); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedLocalRef<jobject> arg1(soa.Env(), + soa.AddLocalReference<jobject>(args[1].GetL())); + ScopedLocalRef<jobject> arg2(soa.Env(), + soa.AddLocalReference<jobject>(args[2].GetL())); + ScopedThreadStateChange tsc(self, kNative); + result->SetZ(fn(soa.Env(), klass.get(), args[0].GetI(), arg1.get(), arg2.get())); + } else if (shorty == "VILII") { + typedef void (fnptr)(JNIEnv*, jclass, jint, jobject, jint, jint); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedLocalRef<jobject> arg1(soa.Env(), + soa.AddLocalReference<jobject>(args[1].GetL())); + ScopedThreadStateChange tsc(self, kNative); + fn(soa.Env(), klass.get(), args[0].GetI(), arg1.get(), args[2].GetI(), args[3].GetI()); + } else if (shorty == "VLILII") { + typedef void (fnptr)(JNIEnv*, jclass, jobject, jint, jobject, jint, jint); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jclass> klass(soa.Env(), + soa.AddLocalReference<jclass>(method->GetDeclaringClass())); + ScopedLocalRef<jobject> arg0(soa.Env(), + soa.AddLocalReference<jobject>(args[0].GetL())); + ScopedLocalRef<jobject> arg2(soa.Env(), + soa.AddLocalReference<jobject>(args[2].GetL())); + ScopedThreadStateChange tsc(self, kNative); + fn(soa.Env(), klass.get(), arg0.get(), args[1].GetI(), arg2.get(), args[3].GetI(), + args[4].GetI()); + } else { + LOG(FATAL) << "Do something with static native method: " << PrettyMethod(method) + << " shorty: " << shorty; + } + } else { + if (shorty == "L") { + typedef jobject (fnptr)(JNIEnv*, jobject); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jobject> rcvr(soa.Env(), + soa.AddLocalReference<jobject>(receiver)); + ScopedThreadStateChange tsc(self, kNative); + result->SetL(soa.Decode<Object*>(fn(soa.Env(), rcvr.get()))); + } else if (shorty == "LL") { + typedef jobject (fnptr)(JNIEnv*, jobject, jobject); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jobject> rcvr(soa.Env(), + soa.AddLocalReference<jobject>(receiver)); + ScopedLocalRef<jobject> arg0(soa.Env(), + soa.AddLocalReference<jobject>(args[0].GetL())); + ScopedThreadStateChange tsc(self, kNative); + result->SetL(soa.Decode<Object*>(fn(soa.Env(), rcvr.get(), arg0.get()))); + } else if (shorty == "III") { + typedef jint (fnptr)(JNIEnv*, jobject, jint, jint); + fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod()); + ScopedLocalRef<jobject> rcvr(soa.Env(), + soa.AddLocalReference<jobject>(receiver)); + ScopedThreadStateChange tsc(self, kNative); + result->SetI(fn(soa.Env(), rcvr.get(), args[0].GetI(), args[1].GetI())); + } else { + LOG(FATAL) << "Do something with native method: " << PrettyMethod(method) + << " shorty: " << shorty; + } + } + } + self->PopShadowFrame(); +} + +} // namespace interpreter +} // namespace art diff --git a/src/interpreter/interpreter.h b/src/interpreter/interpreter.h new file mode 100644 index 0000000000..ea07ce8ede --- /dev/null +++ b/src/interpreter/interpreter.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_INTERPRETER_INTERPRETER_H_ +#define ART_SRC_INTERPRETER_INTERPRETER_H_ + +#include "locks.h" + +namespace art { + +class AbstractMethod; +union JValue; +class Object; +class Thread; + +namespace interpreter { + +extern void EnterInterpreterFromInvoke(Thread* self, AbstractMethod* method, Object* receiver, + JValue* args, JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + +} // namespace interpreter +} // namespace art + +#endif // ART_SRC_INTERPRETER_INTERPRETER_H_ diff --git a/src/invoke_arg_array_builder.h b/src/invoke_arg_array_builder.h new file mode 100644 index 0000000000..e965a1ad18 --- /dev/null +++ b/src/invoke_arg_array_builder.h @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_INVOKE_ARG_ARRAY_BUILDER_H_ +#define ART_SRC_INVOKE_ARG_ARRAY_BUILDER_H_ + +#include "object.h" +#include "scoped_thread_state_change.h" + +namespace art { + +static inline size_t NumArgArrayBytes(const char* shorty, uint32_t shorty_len) { + size_t num_bytes = 0; + for (size_t i = 1; i < shorty_len; ++i) { + char ch = shorty[i]; + if (ch == 'D' || ch == 'J') { + num_bytes += 8; + } else if (ch == 'L') { + // Argument is a reference or an array. The shorty descriptor + // does not distinguish between these types. + num_bytes += sizeof(Object*); + } else { + num_bytes += 4; + } + } + return num_bytes; +} + +class ArgArray { + public: + explicit ArgArray(const char* shorty, uint32_t shorty_len) + : shorty_(shorty), shorty_len_(shorty_len) { + if (shorty_len - 1 < kSmallArgArraySize) { + arg_array_ = small_arg_array_; + } else { + large_arg_array_.reset(new JValue[shorty_len_ - 1]); + arg_array_ = large_arg_array_.get(); + } + } + + JValue* get() { + return arg_array_; + } + + void BuildArgArray(const ScopedObjectAccess& soa, va_list ap) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) { + switch (shorty_[i]) { + case 'Z': + arg_array_[offset].SetZ(va_arg(ap, jint)); + break; + case 'B': + arg_array_[offset].SetB(va_arg(ap, jint)); + break; + case 'C': + arg_array_[offset].SetC(va_arg(ap, jint)); + break; + case 'S': + arg_array_[offset].SetS(va_arg(ap, jint)); + break; + case 'I': + arg_array_[offset].SetI(va_arg(ap, jint)); + break; + case 'F': + arg_array_[offset].SetF(va_arg(ap, jdouble)); + break; + case 'L': + arg_array_[offset].SetL(soa.Decode<Object*>(va_arg(ap, jobject))); + break; + case 'D': + arg_array_[offset].SetD(va_arg(ap, jdouble)); + break; + case 'J': + arg_array_[offset].SetJ(va_arg(ap, jlong)); + break; + } + } + } + + void BuildArgArray(const ScopedObjectAccess& soa, jvalue* args) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) { + switch (shorty_[i]) { + case 'Z': + arg_array_[offset].SetZ(args[offset].z); + break; + case 'B': + arg_array_[offset].SetB(args[offset].b); + break; + case 'C': + arg_array_[offset].SetC(args[offset].c); + break; + case 'S': + arg_array_[offset].SetS(args[offset].s); + break; + case 'I': + arg_array_[offset].SetI(args[offset].i); + break; + case 'F': + arg_array_[offset].SetF(args[offset].f); + break; + case 'L': + arg_array_[offset].SetL(soa.Decode<Object*>(args[offset].l)); + break; + case 'D': + arg_array_[offset].SetD(args[offset].d); + break; + case 'J': + arg_array_[offset].SetJ(args[offset].j); + break; + } + } + } + + void BuildArgArray(const ShadowFrame& shadow_frame, uint32_t range_start) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + for (size_t i = 1, offset = range_start; i < shorty_len_; ++i, ++offset) { + switch (shorty_[i]) { + case 'Z': + arg_array_[offset].SetZ(shadow_frame.GetVReg(offset)); + break; + case 'B': + arg_array_[offset].SetB(shadow_frame.GetVReg(offset)); + break; + case 'C': + arg_array_[offset].SetC(shadow_frame.GetVReg(offset)); + break; + case 'S': + arg_array_[offset].SetS(shadow_frame.GetVReg(offset)); + break; + case 'I': + arg_array_[offset].SetI(shadow_frame.GetVReg(offset)); + break; + case 'F': + arg_array_[offset].SetF(shadow_frame.GetVRegFloat(offset)); + break; + case 'L': + arg_array_[offset].SetL(shadow_frame.GetReference(offset)); + break; + case 'D': + arg_array_[offset].SetD(shadow_frame.GetVRegDouble(offset)); + offset++; + break; + case 'J': + arg_array_[offset].SetJ(shadow_frame.GetVRegLong(offset)); + offset++; + break; + } + } + } + + void BuildArgArray(const ShadowFrame& shadow_frame, const uint32_t* arg_regs) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) { + switch (shorty_[i]) { + case 'Z': + arg_array_[offset].SetZ(shadow_frame.GetVReg(arg_regs[offset])); + break; + case 'B': + arg_array_[offset].SetB(shadow_frame.GetVReg(arg_regs[offset])); + break; + case 'C': + arg_array_[offset].SetC(shadow_frame.GetVReg(arg_regs[offset])); + break; + case 'S': + arg_array_[offset].SetS(shadow_frame.GetVReg(arg_regs[offset])); + break; + case 'I': + arg_array_[offset].SetI(shadow_frame.GetVReg(arg_regs[offset])); + break; + case 'F': + arg_array_[offset].SetF(shadow_frame.GetVRegFloat(arg_regs[offset])); + break; + case 'L': + arg_array_[offset].SetL(shadow_frame.GetReference(arg_regs[offset])); + break; + case 'D': + arg_array_[offset].SetD(shadow_frame.GetVRegDouble(arg_regs[offset])); + offset++; + break; + case 'J': + arg_array_[offset].SetJ(shadow_frame.GetVRegLong(arg_regs[offset])); + offset++; + break; + } + } + } + + private: + enum { kSmallArgArraySize = 16 }; + const char* const shorty_; + const uint32_t shorty_len_; + JValue* arg_array_; + JValue small_arg_array_[kSmallArgArraySize]; + UniquePtr<JValue[]> large_arg_array_; +}; + +} // namespace art + +#endif // ART_SRC_INVOKE_ARG_ARRAY_BUILDER_H_ diff --git a/src/jni_internal.cc b/src/jni_internal.cc index 60b49de83f..097d5878c7 100644 --- a/src/jni_internal.cc +++ b/src/jni_internal.cc @@ -24,6 +24,7 @@ #include "class_linker.h" #include "class_loader.h" +#include "invoke_arg_array_builder.h" #include "jni.h" #include "logging.h" #include "mutex.h" @@ -74,120 +75,6 @@ void SetJniGlobalsMax(size_t max) { } } -size_t NumArgArrayBytes(const char* shorty, uint32_t shorty_len) { - size_t num_bytes = 0; - for (size_t i = 1; i < shorty_len; ++i) { - char ch = shorty[i]; - if (ch == 'D' || ch == 'J') { - num_bytes += 8; - } else if (ch == 'L') { - // Argument is a reference or an array. The shorty descriptor - // does not distinguish between these types. - num_bytes += sizeof(Object*); - } else { - num_bytes += 4; - } - } - return num_bytes; -} - -class ArgArray { - public: - explicit ArgArray(AbstractMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - MethodHelper mh(method); - shorty_ = mh.GetShorty(); - shorty_len_ = mh.GetShortyLength(); - if (shorty_len_ - 1 < kSmallArgArraySize) { - arg_array_ = small_arg_array_; - } else { - large_arg_array_.reset(new JValue[shorty_len_ - 1]); - arg_array_ = large_arg_array_.get(); - } - } - - JValue* get() { - return arg_array_; - } - - void BuildArgArray(const ScopedObjectAccess& soa, va_list ap) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) { - switch (shorty_[i]) { - case 'Z': - arg_array_[offset].SetZ(va_arg(ap, jint)); - break; - case 'B': - arg_array_[offset].SetB(va_arg(ap, jint)); - break; - case 'C': - arg_array_[offset].SetC(va_arg(ap, jint)); - break; - case 'S': - arg_array_[offset].SetS(va_arg(ap, jint)); - break; - case 'I': - arg_array_[offset].SetI(va_arg(ap, jint)); - break; - case 'F': - arg_array_[offset].SetF(va_arg(ap, jdouble)); - break; - case 'L': - arg_array_[offset].SetL(soa.Decode<Object*>(va_arg(ap, jobject))); - break; - case 'D': - arg_array_[offset].SetD(va_arg(ap, jdouble)); - break; - case 'J': - arg_array_[offset].SetJ(va_arg(ap, jlong)); - break; - } - } - } - - void BuildArgArray(const ScopedObjectAccess& soa, jvalue* args) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) { - switch (shorty_[i]) { - case 'Z': - arg_array_[offset].SetZ(args[offset].z); - break; - case 'B': - arg_array_[offset].SetB(args[offset].b); - break; - case 'C': - arg_array_[offset].SetC(args[offset].c); - break; - case 'S': - arg_array_[offset].SetS(args[offset].s); - break; - case 'I': - arg_array_[offset].SetI(args[offset].i); - break; - case 'F': - arg_array_[offset].SetF(args[offset].f); - break; - case 'L': - arg_array_[offset].SetL(soa.Decode<Object*>(args[offset].l)); - break; - case 'D': - arg_array_[offset].SetD(args[offset].d); - break; - case 'J': - arg_array_[offset].SetJ(args[offset].j); - break; - } - } - } - - private: - enum { kSmallArgArraySize = 16 }; - const char* shorty_; - uint32_t shorty_len_; - JValue* arg_array_; - JValue small_arg_array_[kSmallArgArraySize]; - UniquePtr<JValue[]> large_arg_array_; -}; - static jweak AddWeakGlobalReference(ScopedObjectAccess& soa, Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (obj == NULL) { @@ -253,7 +140,8 @@ static JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj, SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Object* receiver = soa.Decode<Object*>(obj); AbstractMethod* method = soa.DecodeMethod(mid); - ArgArray arg_array(method); + MethodHelper mh(method); + ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength()); arg_array.BuildArgArray(soa, args); return InvokeWithArgArray(soa, receiver, method, arg_array.get()); } @@ -268,7 +156,8 @@ static JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccess& soa, SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Object* receiver = soa.Decode<Object*>(obj); AbstractMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid)); - ArgArray arg_array(method); + MethodHelper mh(method); + ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength()); arg_array.BuildArgArray(soa, args); return InvokeWithArgArray(soa, receiver, method, arg_array.get()); } @@ -278,7 +167,8 @@ static JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccess& soa, SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Object* receiver = soa.Decode<Object*>(obj); AbstractMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid)); - ArgArray arg_array(method); + MethodHelper mh(method); + ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength()); arg_array.BuildArgArray(soa, args); return InvokeWithArgArray(soa, receiver, method, arg_array.get()); } @@ -670,7 +560,8 @@ JValue InvokeWithJValues(const ScopedObjectAccess& soa, jobject obj, jmethodID m jvalue* args) { Object* receiver = soa.Decode<Object*>(obj); AbstractMethod* method = soa.DecodeMethod(mid); - ArgArray arg_array(method); + MethodHelper mh(method); + ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength()); arg_array.BuildArgArray(soa, args); return InvokeWithArgArray(soa, receiver, method, arg_array.get()); } @@ -1415,7 +1306,7 @@ class JNI { static jobject GetStaticObjectField(JNIEnv* env, jclass, jfieldID fid) { ScopedObjectAccess soa(env); Field* f = soa.DecodeField(fid); - return soa.AddLocalReference<jobject>(f->GetObject(NULL)); + return soa.AddLocalReference<jobject>(f->GetObject(f->GetDeclaringClass())); } static void SetObjectField(JNIEnv* env, jobject java_object, jfieldID fid, jobject java_value) { @@ -1430,7 +1321,7 @@ class JNI { ScopedObjectAccess soa(env); Object* v = soa.Decode<Object*>(java_value); Field* f = soa.DecodeField(fid); - f->SetObject(NULL, v); + f->SetObject(f->GetDeclaringClass(), v); } #define GET_PRIMITIVE_FIELD(fn, instance) \ @@ -1439,12 +1330,22 @@ class JNI { Field* f = soa.DecodeField(fid); \ return f->fn(o) +#define GET_STATIC_PRIMITIVE_FIELD(fn) \ + ScopedObjectAccess soa(env); \ + Field* f = soa.DecodeField(fid); \ + return f->fn(f->GetDeclaringClass()) + #define SET_PRIMITIVE_FIELD(fn, instance, value) \ ScopedObjectAccess soa(env); \ Object* o = soa.Decode<Object*>(instance); \ Field* f = soa.DecodeField(fid); \ f->fn(o, value) +#define SET_STATIC_PRIMITIVE_FIELD(fn, value) \ + ScopedObjectAccess soa(env); \ + Field* f = soa.DecodeField(fid); \ + f->fn(f->GetDeclaringClass(), value) + static jboolean GetBooleanField(JNIEnv* env, jobject obj, jfieldID fid) { GET_PRIMITIVE_FIELD(GetBoolean, obj); } @@ -1478,35 +1379,35 @@ class JNI { } static jboolean GetStaticBooleanField(JNIEnv* env, jclass, jfieldID fid) { - GET_PRIMITIVE_FIELD(GetBoolean, NULL); + GET_STATIC_PRIMITIVE_FIELD(GetBoolean); } static jbyte GetStaticByteField(JNIEnv* env, jclass, jfieldID fid) { - GET_PRIMITIVE_FIELD(GetByte, NULL); + GET_STATIC_PRIMITIVE_FIELD(GetByte); } static jchar GetStaticCharField(JNIEnv* env, jclass, jfieldID fid) { - GET_PRIMITIVE_FIELD(GetChar, NULL); + GET_STATIC_PRIMITIVE_FIELD(GetChar); } static jshort GetStaticShortField(JNIEnv* env, jclass, jfieldID fid) { - GET_PRIMITIVE_FIELD(GetShort, NULL); + GET_STATIC_PRIMITIVE_FIELD(GetShort); } static jint GetStaticIntField(JNIEnv* env, jclass, jfieldID fid) { - GET_PRIMITIVE_FIELD(GetInt, NULL); + GET_STATIC_PRIMITIVE_FIELD(GetInt); } static jlong GetStaticLongField(JNIEnv* env, jclass, jfieldID fid) { - GET_PRIMITIVE_FIELD(GetLong, NULL); + GET_STATIC_PRIMITIVE_FIELD(GetLong); } static jfloat GetStaticFloatField(JNIEnv* env, jclass, jfieldID fid) { - GET_PRIMITIVE_FIELD(GetFloat, NULL); + GET_STATIC_PRIMITIVE_FIELD(GetFloat); } static jdouble GetStaticDoubleField(JNIEnv* env, jclass, jfieldID fid) { - GET_PRIMITIVE_FIELD(GetDouble, NULL); + GET_STATIC_PRIMITIVE_FIELD(GetDouble); } static void SetBooleanField(JNIEnv* env, jobject obj, jfieldID fid, jboolean v) { @@ -1542,35 +1443,35 @@ class JNI { } static void SetStaticBooleanField(JNIEnv* env, jclass, jfieldID fid, jboolean v) { - SET_PRIMITIVE_FIELD(SetBoolean, NULL, v); + SET_STATIC_PRIMITIVE_FIELD(SetBoolean, v); } static void SetStaticByteField(JNIEnv* env, jclass, jfieldID fid, jbyte v) { - SET_PRIMITIVE_FIELD(SetByte, NULL, v); + SET_STATIC_PRIMITIVE_FIELD(SetByte, v); } static void SetStaticCharField(JNIEnv* env, jclass, jfieldID fid, jchar v) { - SET_PRIMITIVE_FIELD(SetChar, NULL, v); + SET_STATIC_PRIMITIVE_FIELD(SetChar, v); } static void SetStaticFloatField(JNIEnv* env, jclass, jfieldID fid, jfloat v) { - SET_PRIMITIVE_FIELD(SetFloat, NULL, v); + SET_STATIC_PRIMITIVE_FIELD(SetFloat, v); } static void SetStaticDoubleField(JNIEnv* env, jclass, jfieldID fid, jdouble v) { - SET_PRIMITIVE_FIELD(SetDouble, NULL, v); + SET_STATIC_PRIMITIVE_FIELD(SetDouble, v); } static void SetStaticIntField(JNIEnv* env, jclass, jfieldID fid, jint v) { - SET_PRIMITIVE_FIELD(SetInt, NULL, v); + SET_STATIC_PRIMITIVE_FIELD(SetInt, v); } static void SetStaticLongField(JNIEnv* env, jclass, jfieldID fid, jlong v) { - SET_PRIMITIVE_FIELD(SetLong, NULL, v); + SET_STATIC_PRIMITIVE_FIELD(SetLong, v); } static void SetStaticShortField(JNIEnv* env, jclass, jfieldID fid, jshort v) { - SET_PRIMITIVE_FIELD(SetShort, NULL, v); + SET_STATIC_PRIMITIVE_FIELD(SetShort, v); } static jobject CallStaticObjectMethod(JNIEnv* env, jclass, jmethodID mid, ...) { diff --git a/src/jni_internal.h b/src/jni_internal.h index c683464cde..95bc281ca7 100644 --- a/src/jni_internal.h +++ b/src/jni_internal.h @@ -52,7 +52,6 @@ void* FindNativeMethod(Thread* thread); void RegisterNativeMethods(JNIEnv* env, const char* jni_class_name, const JNINativeMethod* methods, size_t method_count); -size_t NumArgArrayBytes(const char* shorty, uint32_t shorty_len); JValue InvokeWithJValues(const ScopedObjectAccess&, jobject obj, jmethodID mid, jvalue* args) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); JValue InvokeWithJValues(const ScopedObjectAccess&, Object* receiver, AbstractMethod* m, JValue* args) diff --git a/src/native/java_lang_reflect_Field.cc b/src/native/java_lang_reflect_Field.cc index c82e5034b7..d99ccb33f2 100644 --- a/src/native/java_lang_reflect_Field.cc +++ b/src/native/java_lang_reflect_Field.cc @@ -76,7 +76,7 @@ static bool CheckReceiver(const ScopedObjectAccess& soa, jobject javaObj, Field* Object*& o) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (f->IsStatic()) { - o = NULL; + o = f->GetDeclaringClass(); return true; } diff --git a/src/oat/jni/arm/jni_internal_arm.cc b/src/oat/jni/arm/jni_internal_arm.cc index 61f29afed8..48d649d194 100644 --- a/src/oat/jni/arm/jni_internal_arm.cc +++ b/src/oat/jni/arm/jni_internal_arm.cc @@ -21,6 +21,7 @@ #include "asm_support.h" #include "compiled_method.h" #include "compiler.h" +#include "invoke_arg_array_builder.h" #include "jni_internal.h" #include "oat/utils/arm/assembler_arm.h" #include "oat/utils/assembler.h" diff --git a/src/oat/jni/mips/jni_internal_mips.cc b/src/oat/jni/mips/jni_internal_mips.cc index a1fc0bf16c..dd66be9db0 100644 --- a/src/oat/jni/mips/jni_internal_mips.cc +++ b/src/oat/jni/mips/jni_internal_mips.cc @@ -21,6 +21,7 @@ #include "asm_support.h" #include "compiled_method.h" #include "compiler.h" +#include "invoke_arg_array_builder.h" #include "jni_internal.h" #include "oat/utils/mips/assembler_mips.h" #include "oat/utils/assembler.h" diff --git a/src/oat/jni/x86/jni_internal_x86.cc b/src/oat/jni/x86/jni_internal_x86.cc index c34112bc2e..ca4a6ab5c1 100644 --- a/src/oat/jni/x86/jni_internal_x86.cc +++ b/src/oat/jni/x86/jni_internal_x86.cc @@ -16,6 +16,7 @@ #include "compiled_method.h" #include "compiler.h" +#include "invoke_arg_array_builder.h" #include "jni_internal.h" #include "oat/utils/assembler.h" #include "oat/utils/x86/assembler_x86.h" diff --git a/src/oat/runtime/support_cast.cc b/src/oat/runtime/support_cast.cc index 16eddc4bd1..0db743b16c 100644 --- a/src/oat/runtime/support_cast.cc +++ b/src/oat/runtime/support_cast.cc @@ -37,7 +37,7 @@ extern "C" int artCheckCastFromCode(const Class* a, const Class* b, Thread* self return 0; // Success } else { FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); - Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassCastException;", + self->ThrowNewExceptionF("Ljava/lang/ClassCastException;", "%s cannot be cast to %s", PrettyDescriptor(a).c_str(), PrettyDescriptor(b).c_str()); @@ -58,7 +58,7 @@ extern "C" int artCanPutArrayElementFromCode(const Object* element, const Class* return 0; // Success } else { FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); - Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;", + self->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;", "%s cannot be stored in an array of type %s", PrettyDescriptor(element_class).c_str(), PrettyDescriptor(array_class).c_str()); diff --git a/src/oat/runtime/support_field.cc b/src/oat/runtime/support_field.cc index 53b53b27c4..93362473c1 100644 --- a/src/oat/runtime/support_field.cc +++ b/src/oat/runtime/support_field.cc @@ -26,12 +26,12 @@ extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const AbstractMet SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(int32_t)); if (LIKELY(field != NULL)) { - return field->Get32(NULL); + return field->Get32(field->GetDeclaringClass()); } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int32_t)); if (LIKELY(field != NULL)) { - return field->Get32(NULL); + return field->Get32(field->GetDeclaringClass()); } return 0; // Will throw exception by checking with Thread::Current } @@ -41,12 +41,12 @@ extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, const AbstractMet SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(int64_t)); if (LIKELY(field != NULL)) { - return field->Get64(NULL); + return field->Get64(field->GetDeclaringClass()); } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int64_t)); if (LIKELY(field != NULL)) { - return field->Get64(NULL); + return field->Get64(field->GetDeclaringClass()); } return 0; // Will throw exception by checking with Thread::Current } @@ -56,12 +56,12 @@ extern "C" Object* artGetObjStaticFromCode(uint32_t field_idx, const AbstractMet SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Field* field = FindFieldFast(field_idx, referrer, StaticObjectRead, sizeof(Object*)); if (LIKELY(field != NULL)) { - return field->GetObj(NULL); + return field->GetObj(field->GetDeclaringClass()); } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode(field_idx, referrer, self, StaticObjectRead, sizeof(Object*)); if (LIKELY(field != NULL)) { - return field->GetObj(NULL); + return field->GetObj(field->GetDeclaringClass()); } return NULL; // Will throw exception by checking with Thread::Current } @@ -132,13 +132,13 @@ extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value, SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int32_t)); if (LIKELY(field != NULL)) { - field->Set32(NULL, new_value); + field->Set32(field->GetDeclaringClass(), new_value); return 0; // success } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int32_t)); if (LIKELY(field != NULL)) { - field->Set32(NULL, new_value); + field->Set32(field->GetDeclaringClass(), new_value); return 0; // success } return -1; // failure @@ -149,13 +149,13 @@ extern "C" int artSet64StaticFromCode(uint32_t field_idx, const AbstractMethod* SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int64_t)); if (LIKELY(field != NULL)) { - field->Set64(NULL, new_value); + field->Set64(field->GetDeclaringClass(), new_value); return 0; // success } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int64_t)); if (LIKELY(field != NULL)) { - field->Set64(NULL, new_value); + field->Set64(field->GetDeclaringClass(), new_value); return 0; // success } return -1; // failure @@ -168,14 +168,14 @@ extern "C" int artSetObjStaticFromCode(uint32_t field_idx, Object* new_value, Field* field = FindFieldFast(field_idx, referrer, StaticObjectWrite, sizeof(Object*)); if (LIKELY(field != NULL)) { if (LIKELY(!FieldHelper(field).IsPrimitiveType())) { - field->SetObj(NULL, new_value); + field->SetObj(field->GetDeclaringClass(), new_value); return 0; // success } } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode(field_idx, referrer, self, StaticObjectWrite, sizeof(Object*)); if (LIKELY(field != NULL)) { - field->SetObj(NULL, new_value); + field->SetObj(field->GetDeclaringClass(), new_value); return 0; // success } return -1; // failure diff --git a/src/object.cc b/src/object.cc index 5fdea71e04..9189f034fc 100644 --- a/src/object.cc +++ b/src/object.cc @@ -29,6 +29,7 @@ #include "dex_file.h" #include "globals.h" #include "heap.h" +#include "interpreter/interpreter.h" #include "intern_table.h" #include "logging.h" #include "monitor.h" @@ -42,11 +43,52 @@ namespace art { +BooleanArray* Object::AsBooleanArray() { + DCHECK(GetClass()->IsArrayClass()); + DCHECK(GetClass()->GetComponentType()->IsPrimitiveBoolean()); + return down_cast<BooleanArray*>(this); +} + +ByteArray* Object::AsByteArray() { + DCHECK(GetClass()->IsArrayClass()); + DCHECK(GetClass()->GetComponentType()->IsPrimitiveByte()); + return down_cast<ByteArray*>(this); +} + +CharArray* Object::AsCharArray() { + DCHECK(GetClass()->IsArrayClass()); + DCHECK(GetClass()->GetComponentType()->IsPrimitiveChar()); + return down_cast<CharArray*>(this); +} + +ShortArray* Object::AsShortArray() { + DCHECK(GetClass()->IsArrayClass()); + DCHECK(GetClass()->GetComponentType()->IsPrimitiveShort()); + return down_cast<ShortArray*>(this); +} + +IntArray* Object::AsIntArray() { + DCHECK(GetClass()->IsArrayClass()); + DCHECK(GetClass()->GetComponentType()->IsPrimitiveInt()); + return down_cast<IntArray*>(this); +} + +LongArray* Object::AsLongArray() { + DCHECK(GetClass()->IsArrayClass()); + DCHECK(GetClass()->GetComponentType()->IsPrimitiveLong()); + return down_cast<LongArray*>(this); +} + String* Object::AsString() { DCHECK(GetClass()->IsStringClass()); return down_cast<String*>(this); } +Throwable* Object::AsThrowable() { + DCHECK(GetClass()->IsThrowableClass()); + return down_cast<Throwable*>(this); +} + Object* Object::Clone(Thread* self) { Class* c = GetClass(); DCHECK(!c->IsClassClass()); @@ -188,50 +230,38 @@ void Field::SetOffset(MemberOffset num_bytes) { } uint32_t Field::Get32(const Object* object) const { - CHECK((object == NULL) == IsStatic()) << PrettyField(this); - if (IsStatic()) { - object = declaring_class_; - } + DCHECK(object != NULL) << PrettyField(this); + DCHECK(IsStatic() == (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted()); return object->GetField32(GetOffset(), IsVolatile()); } void Field::Set32(Object* object, uint32_t new_value) const { - CHECK((object == NULL) == IsStatic()) << PrettyField(this); - if (IsStatic()) { - object = declaring_class_; - } + DCHECK(object != NULL) << PrettyField(this); + DCHECK(IsStatic() == (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted()); object->SetField32(GetOffset(), new_value, IsVolatile()); } uint64_t Field::Get64(const Object* object) const { - CHECK((object == NULL) == IsStatic()) << PrettyField(this); - if (IsStatic()) { - object = declaring_class_; - } + DCHECK(object != NULL) << PrettyField(this); + DCHECK(IsStatic() == (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted()); return object->GetField64(GetOffset(), IsVolatile()); } void Field::Set64(Object* object, uint64_t new_value) const { - CHECK((object == NULL) == IsStatic()) << PrettyField(this); - if (IsStatic()) { - object = declaring_class_; - } + DCHECK(object != NULL) << PrettyField(this); + DCHECK(IsStatic() == (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted()); object->SetField64(GetOffset(), new_value, IsVolatile()); } Object* Field::GetObj(const Object* object) const { - CHECK((object == NULL) == IsStatic()) << PrettyField(this); - if (IsStatic()) { - object = declaring_class_; - } + DCHECK(object != NULL) << PrettyField(this); + DCHECK(IsStatic() == (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted()); return object->GetFieldObject<Object*>(GetOffset(), IsVolatile()); } void Field::SetObj(Object* object, const Object* new_value) const { - CHECK((object == NULL) == IsStatic()) << PrettyField(this); - if (IsStatic()) { - object = declaring_class_; - } + DCHECK(object != NULL) << PrettyField(this); + DCHECK(IsStatic() == (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted()); object->SetFieldObject(GetOffset(), new_value, IsVolatile()); } @@ -603,7 +633,7 @@ uint32_t AbstractMethod::FindCatchBlock(Class* exception_type, uint32_t dex_pc) return DexFile::kDexNoIndex; } -void AbstractMethod::Invoke(Thread* self, Object* receiver, JValue* args, JValue* result) const { +void AbstractMethod::Invoke(Thread* self, Object* receiver, JValue* args, JValue* result) { if (kIsDebugBuild) { self->AssertThreadSuspensionIsAllowable(); CHECK_EQ(kRunnable, self->GetState()); @@ -617,26 +647,35 @@ void AbstractMethod::Invoke(Thread* self, Object* receiver, JValue* args, JValue // Pass everything as arguments. AbstractMethod::InvokeStub* stub = GetInvokeStub(); - bool have_executable_code = (GetCode() != NULL); - if (Runtime::Current()->IsStarted() && have_executable_code && stub != NULL) { - bool log = false; - if (log) { - LOG(INFO) << StringPrintf("invoking %s code=%p stub=%p", - PrettyMethod(this).c_str(), GetCode(), stub); - } - (*stub)(this, receiver, self, args, result); - if (log) { - LOG(INFO) << StringPrintf("returned %s code=%p stub=%p", - PrettyMethod(this).c_str(), GetCode(), stub); - } - } else { - LOG(INFO) << StringPrintf("not invoking %s code=%p stub=%p started=%s", - PrettyMethod(this).c_str(), GetCode(), stub, - Runtime::Current()->IsStarted() ? "true" : "false"); + if (UNLIKELY(!Runtime::Current()->IsStarted())){ + LOG(INFO) << "Not invoking " << PrettyMethod(this) << " for a runtime that isn't started."; if (result != NULL) { result->SetJ(0); } + } else { + if (GetCode() != NULL && stub != NULL) { + bool log = false; + if (log) { + LOG(INFO) << StringPrintf("invoking %s code=%p stub=%p", + PrettyMethod(this).c_str(), GetCode(), stub); + } + (*stub)(this, receiver, self, args, result); + if (log) { + LOG(INFO) << StringPrintf("returned %s code=%p stub=%p", + PrettyMethod(this).c_str(), GetCode(), stub); + } + } else { + LOG(INFO) << "Not invoking " << PrettyMethod(this) + << " code=" << reinterpret_cast<const void*>(GetCode()) + << " stub=" << reinterpret_cast<void*>(stub); + const bool kInterpretMethodsWithNoCode = false; + if (kInterpretMethodsWithNoCode) { + art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args, result); + } else if (result != NULL) { + result->SetJ(0); + } + } } // Pop transition. diff --git a/src/object.h b/src/object.h index 43aed33183..61fa3357dd 100644 --- a/src/object.h +++ b/src/object.h @@ -247,8 +247,17 @@ class MANAGED Object { return down_cast<const Array*>(this); } + BooleanArray* AsBooleanArray(); + ByteArray* AsByteArray(); + CharArray* AsCharArray(); + ShortArray* AsShortArray(); + IntArray* AsIntArray(); + LongArray* AsLongArray(); + String* AsString(); + Throwable* AsThrowable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsMethod() const; AbstractMethod* AsMethod() { @@ -668,7 +677,7 @@ class MANAGED AbstractMethod : public Object { // Find the method that this method overrides AbstractMethod* FindOverriddenMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void Invoke(Thread* self, Object* receiver, JValue* args, JValue* result) const + void Invoke(Thread* self, Object* receiver, JValue* args, JValue* result) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const void* GetCode() const { @@ -1749,6 +1758,14 @@ class MANAGED Class : public StaticStorageBase { return GetVTable()->Get(method->GetMethodIndex()); } + // Given a method implemented by this class' super class, return the specific implementation + // method for this class. + AbstractMethod* FindVirtualMethodForSuper(AbstractMethod* method) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(!method->GetDeclaringClass()->IsInterface()); + return GetSuperClass()->GetVTable()->Get(method->GetMethodIndex()); + } + // Given a method implemented by this class, but potentially from a // super class or interface, return the specific implementation // method for this class. @@ -2358,7 +2375,6 @@ class MANAGED PrimitiveArray : public Array { } void Set(int32_t i, T value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - // TODO: ArrayStoreException if (IsValidIndex(i)) { GetData()[i] = value; } @@ -2397,10 +2413,7 @@ class MANAGED String : public Object { } const CharArray* GetCharArray() const { - const CharArray* result = GetFieldObject<const CharArray*>( - ValueOffset(), false); - DCHECK(result != NULL); - return result; + return GetFieldObject<const CharArray*>(ValueOffset(), false); } int32_t GetOffset() const { diff --git a/src/object_test.cc b/src/object_test.cc index 9ad0534f5f..e0443d0d18 100644 --- a/src/object_test.cc +++ b/src/object_test.cc @@ -238,15 +238,15 @@ TEST_F(ObjectTest, StaticFieldFromCode) { Field* field = FindFieldFromCode(field_idx, clinit, Thread::Current(), StaticObjectRead, sizeof(Object*)); - Object* s0 = field->GetObj(NULL); + Object* s0 = field->GetObj(klass); EXPECT_EQ(NULL, s0); SirtRef<CharArray> char_array(soa.Self(), CharArray::Alloc(soa.Self(), 0)); - field->SetObj(NULL, char_array.get()); - EXPECT_EQ(char_array.get(), field->GetObj(NULL)); + field->SetObj(field->GetDeclaringClass(), char_array.get()); + EXPECT_EQ(char_array.get(), field->GetObj(klass)); - field->SetObj(NULL, NULL); - EXPECT_EQ(NULL, field->GetObj(NULL)); + field->SetObj(field->GetDeclaringClass(), NULL); + EXPECT_EQ(NULL, field->GetObj(klass)); // TODO: more exhaustive tests of all 6 cases of Field::*FromCode } diff --git a/src/object_utils.h b/src/object_utils.h index c6e71c3ae1..661773a346 100644 --- a/src/object_utils.h +++ b/src/object_utils.h @@ -647,7 +647,7 @@ class MethodHelper { Class* GetDexCacheResolvedType(uint16_t type_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return GetDexCache()->GetResolvedType(type_idx); + return method_->GetDexCacheResolvedTypes()->Get(type_idx); } const DexFile& GetDexFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -669,11 +669,26 @@ class MethodHelper { return result; } + String* ResolveString(uint32_t string_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + String* s = method_->GetDexCacheStrings()->Get(string_idx); + if (UNLIKELY(s == NULL)) { + s = GetClassLinker()->ResolveString(GetDexFile(), string_idx, GetDexCache()); + } + return s; + } + + Class* ResolveClass(uint16_t type_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Class* c = GetDexCacheResolvedType(type_idx); + if (UNLIKELY(c == NULL)) { + c = GetClassLinker()->ResolveType(GetDexFile(), type_idx, GetDexCache(), GetClassLoader()); + } + return c; + } + private: // Set the method_ field, for proxy methods looking up the interface method via the resolved // methods table. - void SetMethod(const AbstractMethod* method) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + void SetMethod(const AbstractMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (method != NULL) { Class* klass = method->GetDeclaringClass(); if (klass->IsProxyClass()) { diff --git a/src/runtime.cc b/src/runtime.cc index 7bc1b70881..79d1fb2604 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -191,7 +191,8 @@ struct AbortState { if (!tll_already_held || !ml_already_held) { os << "Dumping all threads without appropriate locks held:" << (!tll_already_held ? " thread list lock" : "") - << (!ml_already_held ? " mutator lock" : ""); + << (!ml_already_held ? " mutator lock" : "") + << "\n"; } os << "All threads:\n"; Runtime::Current()->GetThreadList()->DumpLocked(os); @@ -717,8 +718,12 @@ void Runtime::StartDaemonThreads() { CHECK_EQ(self->GetState(), kNative); JNIEnv* env = self->GetJniEnv(); - env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons, WellKnownClasses::java_lang_Daemons_start); - CHECK(!env->ExceptionCheck()); + env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons, + WellKnownClasses::java_lang_Daemons_start); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + LOG(FATAL) << "Error starting java.lang.Daemons"; + } VLOG(startup) << "Runtime::StartDaemonThreads exiting"; } diff --git a/src/stack.h b/src/stack.h index 845b840904..3cf85773a3 100644 --- a/src/stack.h +++ b/src/stack.h @@ -37,6 +37,14 @@ class Thread; class ShadowFrame { public: + static ShadowFrame* Create(uint16_t num_refs, uint16_t num_vregs, ShadowFrame* link, + AbstractMethod* method, uint32_t dex_pc) { + size_t sz = sizeof(ShadowFrame) + (sizeof(Object*) * num_refs) + (sizeof(uint32_t) * num_vregs); + uint8_t* memory = new uint8_t[sz]; + return new (memory) ShadowFrame(num_refs, num_vregs, link, method, dex_pc); + } + ~ShadowFrame() {} + uint32_t NumberOfReferences() const { return number_of_references_; } @@ -76,6 +84,59 @@ class ShadowFrame { references_[i] = object; } + int32_t GetVReg(size_t i) const { + DCHECK_LT(i, number_of_vregs_); + const int8_t* vregs = reinterpret_cast<const int8_t*>(this) + VRegsOffset(); + return reinterpret_cast<const int32_t*>(vregs)[i]; + } + + float GetVRegFloat(size_t i) const { + DCHECK_LT(i, number_of_vregs_); + const int8_t* vregs = reinterpret_cast<const int8_t*>(this) + VRegsOffset(); + return reinterpret_cast<const float*>(vregs)[i]; + } + + int64_t GetVRegLong(size_t i) const { + const int8_t* vregs = reinterpret_cast<const int8_t*>(this) + VRegsOffset(); + const int32_t* low_half = &reinterpret_cast<const int32_t*>(vregs)[i]; + return *reinterpret_cast<const int64_t*>(low_half); + } + + double GetVRegDouble(size_t i) const { + const int8_t* vregs = reinterpret_cast<const int8_t*>(this) + VRegsOffset(); + const int32_t* low_half = &reinterpret_cast<const int32_t*>(vregs)[i]; + return *reinterpret_cast<const double*>(low_half); + } + + void SetVReg(size_t i, int32_t val) { + DCHECK_LT(i, number_of_vregs_); + int8_t* vregs = reinterpret_cast<int8_t*>(this) + VRegsOffset(); + reinterpret_cast<int32_t*>(vregs)[i] = val; + } + + void SetVRegFloat(size_t i, float val) { + DCHECK_LT(i, number_of_vregs_); + int8_t* vregs = reinterpret_cast<int8_t*>(this) + VRegsOffset(); + reinterpret_cast<float*>(vregs)[i] = val; + } + + void SetVRegLong(size_t i, int64_t val) { + int8_t* vregs = reinterpret_cast<int8_t*>(this) + VRegsOffset(); + int32_t* low_half = &reinterpret_cast<int32_t*>(vregs)[i]; + *reinterpret_cast<int64_t*>(low_half) = val; + } + + void SetVRegDouble(size_t i, double val) { + int8_t* vregs = reinterpret_cast<int8_t*>(this) + VRegsOffset(); + int32_t* low_half = &reinterpret_cast<int32_t*>(vregs)[i]; + *reinterpret_cast<double*>(low_half) = val; + } + + void SetReferenceAndVReg(size_t i, Object* val) { + SetReference(i, val); + SetVReg(i, reinterpret_cast<int32_t>(val)); + } + AbstractMethod* GetMethod() const { DCHECK_NE(method_, static_cast<void*>(NULL)); return method_; @@ -126,22 +187,31 @@ class ShadowFrame { return OFFSETOF_MEMBER(ShadowFrame, references_); } - size_t VRegsOffset() { + size_t VRegsOffset() const { return ReferencesOffset() + (sizeof(Object*) * NumberOfReferences()); } private: - // ShadowFrame should be allocated by the generated code directly. - // We should not create new shadow stack in the runtime support function. - ~ShadowFrame() {} + ShadowFrame(uint16_t num_refs, uint16_t num_vregs, ShadowFrame* link, AbstractMethod* method, + uint32_t dex_pc) + : number_of_references_ (num_refs), number_of_vregs_(num_vregs), link_(link), + method_(method), dex_pc_(dex_pc) { + for (size_t i = 0; i < num_refs; ++i) { + SetReference(i, NULL); + } + for (size_t i = 0; i < num_vregs; ++i) { + SetVReg(i, 0); + } + } + // TODO: make the majority of these fields const. uint16_t number_of_references_; uint16_t number_of_vregs_; // Link to previous shadow frame or NULL. ShadowFrame* link_; AbstractMethod* method_; uint32_t dex_pc_; - Object* references_[]; + Object* references_[0]; DISALLOW_IMPLICIT_CONSTRUCTORS(ShadowFrame); }; diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc index bd77a3cbbc..9a933bf7bc 100644 --- a/src/verifier/method_verifier.cc +++ b/src/verifier/method_verifier.cc @@ -1501,15 +1501,23 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { break; case Instruction::CONST_4: + /* could be boolean, int, float, or a null reference */ + work_line_->SetRegisterType(dec_insn.vA, + reg_types_.FromCat1Const((dec_insn.vB << 28) >> 28)); + break; case Instruction::CONST_16: + /* could be boolean, int, float, or a null reference */ + work_line_->SetRegisterType(dec_insn.vA, + reg_types_.FromCat1Const(static_cast<int16_t>(dec_insn.vB))); + break; case Instruction::CONST: /* could be boolean, int, float, or a null reference */ - work_line_->SetRegisterType(dec_insn.vA, reg_types_.FromCat1Const((int32_t) dec_insn.vB)); + work_line_->SetRegisterType(dec_insn.vA, reg_types_.FromCat1Const(dec_insn.vB)); break; case Instruction::CONST_HIGH16: /* could be boolean, int, float, or a null reference */ work_line_->SetRegisterType(dec_insn.vA, - reg_types_.FromCat1Const((int32_t) dec_insn.vB << 16)); + reg_types_.FromCat1Const(dec_insn.vB << 16)); break; case Instruction::CONST_WIDE_16: case Instruction::CONST_WIDE_32: |