Merge "Prune away extraneous ART_USE_PORTABLE_COMPILER ifdefs." into dalvik-dev
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 9d41e01..d7d8365 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -408,7 +408,6 @@
AllFields \
CreateMethodSignature \
ExceptionHandle \
- IntMath \
Interfaces \
Main \
MyClass \
@@ -428,7 +427,6 @@
Main \
HelloWorld \
\
- IntMath \
ParallelGC \
ReferenceMap \
StackWalk \
diff --git a/src/base/mutex.h b/src/base/mutex.h
index 5cc021f..190e779 100644
--- a/src/base/mutex.h
+++ b/src/base/mutex.h
@@ -31,7 +31,7 @@
#if defined(__APPLE__)
#define ART_USE_FUTEXES 0
#else
-#define ART_USE_FUTEXES 1
+#define ART_USE_FUTEXES !defined(__mips__)
#endif
// Currently Darwin doesn't support locks with timeouts.
diff --git a/src/compiler/codegen/mips/fp_mips.cc b/src/compiler/codegen/mips/fp_mips.cc
index e718c5c..6ffc5e0 100644
--- a/src/compiler/codegen/mips/fp_mips.cc
+++ b/src/compiler/codegen/mips/fp_mips.cc
@@ -49,6 +49,8 @@
case Instruction::MUL_FLOAT:
op = kMipsFmuls;
break;
+ case Instruction::REM_FLOAT_2ADDR:
+ case Instruction::REM_FLOAT:
FlushAllRegs(cu); // Send everything to home location
CallRuntimeHelperRegLocationRegLocation(cu, ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2, false);
rl_result = GetReturn(cu, true);
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index 7d73249..2dcfba5 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -730,8 +730,9 @@
}
}
-// Handler for invocation on proxy methods. We create a boxed argument array. And we invoke
-// the invocation handler which is a field within the proxy object receiver.
+// Handler for invocation on proxy methods. Create a boxed argument array and invoke the invocation
+// handler which is a field within the proxy object receiver. The var args encode the arguments
+// with the last argument being a pointer to a JValue to store the result in.
void art_proxy_invoke_handler_from_code(AbstractMethod* proxy_method, ...)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
va_list ap;
@@ -740,141 +741,59 @@
Object* receiver = va_arg(ap, Object*);
Thread* self = va_arg(ap, Thread*);
MethodHelper proxy_mh(proxy_method);
- const size_t num_params = proxy_mh.NumArgs();
- // Start new JNI local reference state
+ // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
+ const char* old_cause =
+ self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
+ self->VerifyStack();
+
+ // Start new JNI local reference state.
JNIEnvExt* env = self->GetJniEnv();
ScopedObjectAccessUnchecked soa(env);
ScopedJniEnvLocalRefState env_state(env);
- // Create local ref. copies of the receiver
+ // Create local ref. copies of the receiver.
jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
- // Convert proxy method into expected interface method
+ // Convert proxy method into expected interface method.
AbstractMethod* interface_method = proxy_method->FindOverriddenMethod();
DCHECK(interface_method != NULL);
DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
+ jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
- // Set up arguments array and place in local IRT during boxing (which may allocate/GC)
- jvalue args_jobj[3];
- args_jobj[0].l = rcvr_jobj;
- args_jobj[1].l = soa.AddLocalReference<jobject>(interface_method);
- // Args array, if no arguments then NULL (don't include receiver in argument count)
- args_jobj[2].l = NULL;
- ObjectArray<Object>* args = NULL;
- if ((num_params - 1) > 0) {
- args = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(self, num_params - 1);
- if (args == NULL) {
- CHECK(self->IsExceptionPending());
- return;
- }
- args_jobj[2].l = soa.AddLocalReference<jobjectArray>(args);
- }
-
- // Get parameter types.
- const char* shorty = proxy_mh.GetShorty();
- ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes(self);
- if (param_types == NULL) {
- CHECK(self->IsExceptionPending());
- return;
- }
-
- // Box arguments.
- for (size_t i = 0; i < (num_params - 1);++i) {
- JValue val;
- switch (shorty[i+1]) {
- case 'Z':
- val.SetZ(va_arg(ap, jint));
+ // Record arguments and turn Object* arguments into jobject to survive GC.
+ std::vector<jvalue> args;
+ const size_t num_params = proxy_mh.NumArgs();
+ for (size_t i = 1; i < num_params; ++i) {
+ jvalue val;
+ switch (proxy_mh.GetParamPrimitiveType(i)) {
+ case Primitive::kPrimNot:
+ val.l = soa.AddLocalReference<jobject>(va_arg(ap, Object*));
break;
- case 'B':
- val.SetB(va_arg(ap, jint));
+ case Primitive::kPrimBoolean: // Fall-through.
+ case Primitive::kPrimByte: // Fall-through.
+ case Primitive::kPrimChar: // Fall-through.
+ case Primitive::kPrimShort: // Fall-through.
+ case Primitive::kPrimInt: // Fall-through.
+ val.i = va_arg(ap, jint);
break;
- case 'C':
- val.SetC(va_arg(ap, jint));
- break;
- case 'S':
- val.SetS(va_arg(ap, jint));
- break;
- case 'I':
- val.SetI(va_arg(ap, jint));
- break;
- case 'F':
- val.SetI(va_arg(ap, jint)); // TODO: is this right?
- break;
- case 'L':
- val.SetL(va_arg(ap, Object*));
+ case Primitive::kPrimFloat:
+ val.f = va_arg(ap, jfloat);
break;
case 'D':
+ val.d(va_arg(ap, jdouble));
+ break;
case 'J':
- val.SetJ(va_arg(ap, jlong)); // TODO: is this right for double?
+ val.j(va_arg(ap, jlong));
break;
}
- Class* param_type = param_types->Get(i);
- if (param_type->IsPrimitive()) {
- BoxPrimitive(param_type->GetPrimitiveType(), val);
- if (self->IsExceptionPending()) {
- return;
- }
- }
- args->Set(i, val.GetL());
+ args.push_back(val);
}
-
- DCHECK(env->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy));
-
- jobject inv_hand = env->GetObjectField(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy_h);
- // Call InvocationHandler.invoke
- jobject result = env->CallObjectMethodA(inv_hand, WellKnownClasses::java_lang_reflect_InvocationHandler_invoke, args_jobj);
-
- // Place result in stack args
- if (!self->IsExceptionPending()) {
- if (shorty[0] == 'V') {
- return;
- }
- Object* result_ref = self->DecodeJObject(result);
- JValue* result_unboxed = va_arg(ap, JValue*);
- if (result_ref == NULL) {
- result_unboxed->SetL(NULL);
- } else {
- bool unboxed_okay = UnboxPrimitiveForResult(result_ref, proxy_mh.GetReturnType(), *result_unboxed);
- if (!unboxed_okay) {
- self->ClearException();
- self->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
- "Couldn't convert result of type %s to %s",
- PrettyTypeOf(result_ref).c_str(),
- PrettyDescriptor(proxy_mh.GetReturnType()).c_str());
- return;
- }
- }
- } else {
- // In the case of checked exceptions that aren't declared, the exception must be wrapped by
- // a UndeclaredThrowableException.
- Throwable* exception = self->GetException();
- if (exception->IsCheckedException()) {
- SynthesizedProxyClass* proxy_class =
- down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
- int throws_index = -1;
- size_t num_virt_methods = proxy_class->NumVirtualMethods();
- for (size_t i = 0; i < num_virt_methods; i++) {
- if (proxy_class->GetVirtualMethod(i) == proxy_method) {
- throws_index = i;
- break;
- }
- }
- CHECK_NE(throws_index, -1);
- ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
- Class* exception_class = exception->GetClass();
- bool declares_exception = false;
- for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
- Class* declared_exception = declared_exceptions->Get(i);
- declares_exception = declared_exception->IsAssignableFrom(exception_class);
- }
- if (!declares_exception) {
- self->ThrowNewWrappedException("Ljava/lang/reflect/UndeclaredThrowableException;", NULL);
- }
- }
- }
-
+ self->EndAssertNoThreadSuspension(old_cause);
+ JValue* result_unboxed = va_arg(ap, JValue*);
va_end(ap);
+ *result_unboxed = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(),
+ rcvr_jobj, interface_method_jobj, args);
}
void* art_find_runtime_support_func(void* context, const char* name) {
diff --git a/src/native/java_lang_reflect_Field.cc b/src/native/java_lang_reflect_Field.cc
index d99ccb3..fde8f94 100644
--- a/src/native/java_lang_reflect_Field.cc
+++ b/src/native/java_lang_reflect_Field.cc
@@ -101,9 +101,8 @@
if (!GetFieldValue(soa, o, f, value, true)) {
return NULL;
}
- BoxPrimitive(FieldHelper(f).GetTypeAsPrimitiveType(), value);
-
- return soa.AddLocalReference<jobject>(value.GetL());
+ return
+ soa.AddLocalReference<jobject>(BoxPrimitive(FieldHelper(f).GetTypeAsPrimitiveType(), value));
}
static JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, char dst_descriptor) {
diff --git a/src/oat/runtime/argument_visitor.h b/src/oat/runtime/argument_visitor.h
new file mode 100644
index 0000000..06256ca
--- /dev/null
+++ b/src/oat/runtime/argument_visitor.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2013 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_OAT_RUNTIME_ARGUMENT_VISITOR_H_
+#define ART_SRC_OAT_RUNTIME_ARGUMENT_VISITOR_H_
+
+#include "object_utils.h"
+
+namespace art {
+
+// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame.
+class ArgumentVisitor {
+ public:
+// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame.
+// Size of Runtime::kRefAndArgs callee save frame.
+// Size of Method* and register parameters in out stack arguments.
+#if defined(__arm__)
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
+#define STACK_ARG_SKIP 16
+#elif defined(__mips__)
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
+#define STACK_ARG_SKIP 16
+#elif defined(__i386__)
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32
+#define STACK_ARG_SKIP 16
+#else
+#error "Unsupported architecture"
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0
+#define STACK_ARG_SKIP 0
+#endif
+
+ ArgumentVisitor(MethodHelper& caller_mh, AbstractMethod** sp)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
+ caller_mh_(caller_mh),
+ args_in_regs_(ComputeArgsInRegs(caller_mh)),
+ num_params_(caller_mh.NumArgs()),
+ reg_args_(reinterpret_cast<byte*>(sp) + CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET),
+ stack_args_(reinterpret_cast<byte*>(sp) + CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE
+ + STACK_ARG_SKIP),
+ cur_args_(reg_args_),
+ cur_arg_index_(0),
+ param_index_(0),
+ is_split_long_or_double_(false) {
+ }
+
+ virtual ~ArgumentVisitor() {}
+
+ virtual void Visit() = 0;
+
+ bool IsParamAReference() const {
+ return caller_mh_.IsParamAReference(param_index_);
+ }
+
+ bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return caller_mh_.IsParamALongOrDouble(param_index_);
+ }
+
+ Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return caller_mh_.GetParamPrimitiveType(param_index_);
+ }
+
+ byte* GetParamAddress() const {
+ return cur_args_ + (cur_arg_index_ * kPointerSize);
+ }
+
+ bool IsSplitLongOrDouble() const {
+ return is_split_long_or_double_;
+ }
+
+ uint64_t ReadSplitLongParam() const {
+ DCHECK(IsSplitLongOrDouble());
+ uint64_t low_half = *reinterpret_cast<uint32_t*>(GetParamAddress());
+ uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args_);
+ return (low_half & 0xffffffffULL) | (high_half << 32);
+
+ }
+
+ void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ for (cur_arg_index_ = 0; cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) {
+ is_split_long_or_double_ = (cur_arg_index_ == 2) && IsParamALongOrDouble();
+ Visit();
+ cur_arg_index_ += (caller_mh_.IsParamALongOrDouble(param_index_) ? 2 : 1);
+ param_index_++;
+ }
+ cur_args_ = stack_args_;
+ cur_arg_index_ = is_split_long_or_double_ ? 1 : 0;
+ is_split_long_or_double_ = false;
+ while (param_index_ < num_params_) {
+ Visit();
+ cur_arg_index_ += (caller_mh_.IsParamALongOrDouble(param_index_) ? 2 : 1);
+ param_index_++;
+ }
+ }
+
+ private:
+ static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ size_t args_in_regs = 0;
+ size_t num_params = mh.NumArgs();
+ for (size_t i = 0; i < num_params; i++) {
+ args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1);
+ if (args_in_regs > 3) {
+ args_in_regs = 3;
+ break;
+ }
+ }
+ return args_in_regs;
+ }
+ MethodHelper& caller_mh_;
+ const size_t args_in_regs_;
+ const size_t num_params_;
+ byte* const reg_args_;
+ byte* const stack_args_;
+ byte* cur_args_;
+ size_t cur_arg_index_;
+ size_t param_index_;
+ // Does a 64bit parameter straddle the register and stack arguments?
+ bool is_split_long_or_double_;
+};
+
+}
+
+#endif // ART_SRC_OAT_RUNTIME_ARGUMENT_VISITOR_H_
diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
index 7901c5f..dda1222 100644
--- a/src/oat/runtime/arm/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -754,18 +754,18 @@
.extern artProxyInvokeHandler
/*
* Called by managed code that is attempting to call a method on a proxy class. On entry
- * r0 holds the proxy method; r1, r2 and r3 may contain arguments.
+ * r0 holds the proxy method and r1 holds the receiver; r2 and r3 may contain arguments. The
+ * frame size of the invoked proxy method agrees with a ref and args callee save frame.
*/
ALIGN_FUNCTION_ENTRY
art_proxy_invoke_handler:
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
str r0, [sp, #0] @ place proxy method at bottom of frame
mov r2, r9 @ pass Thread::Current
- add r3, sp, #12 @ pointer to r2/r3/LR/caller's Method**/out-args as second arg
- blx artProxyInvokeHandler @ (Method* proxy method, receiver, Thread*, args...)
+ mov r3, sp @ pass SP
+ blx artProxyInvokeHandler @ (Method* proxy method, receiver, Thread*, SP)
ldr r12, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_
ldr lr, [sp, #44] @ restore lr
- ldrd r0, [sp, #12] @ load r0/r1 from r2/r3 that were overwritten with the out args
add sp, #48 @ pop frame
cmp r12, #0 @ success if no exception is pending
bxeq lr @ return on success
diff --git a/src/oat/runtime/mips/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S
index 4484cde..efd3ede 100644
--- a/src/oat/runtime/mips/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -853,11 +853,9 @@
sw $a0, 0($sp) # place proxy method at bottom of frame
move $a2, rSELF # pass Thread::Current
jal artProxyInvokeHandler # (Method* proxy method, receiver, Thread*, args...)
- addiu $a3, $sp, 8 # pointer to a2/a3/ra/caller's Method**/out-args as second arg
+ move $a3, $sp # pass $sp
lw $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
lw $ra, 44($sp) # restore $ra
- lw $v0, 8($sp)
- lw $v1, 12($sp)
bnez $t0, 1f
addiu $sp, $sp, 48 # pop frame
jr $ra
diff --git a/src/oat/runtime/support_proxy.cc b/src/oat/runtime/support_proxy.cc
index 1fdab2a..5bf3cde 100644
--- a/src/oat/runtime/support_proxy.cc
+++ b/src/oat/runtime/support_proxy.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "argument_visitor.h"
#include "object.h"
#include "object_utils.h"
#include "reflection.h"
@@ -24,42 +25,69 @@
#include "ScopedLocalRef.h"
-#if defined(__arm__)
-#define SP_OFFSET_IN_BYTES 12
-#define FRAME_SIZE_IN_BYTES 48u
-#define ARG2_OFFSET_IN_WORDS 11 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
-#elif defined(__mips__)
-#define SP_OFFSET_IN_BYTES 8
-#define FRAME_SIZE_IN_BYTES 48u
-#define ARG2_OFFSET_IN_WORDS 12 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
-#elif defined(__i386__)
-#define SP_OFFSET_IN_BYTES 8
-#define FRAME_SIZE_IN_BYTES 32u
-#define ARG2_OFFSET_IN_WORDS 8 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
-#else
-#error "Unsupported architecture"
-#define SP_OFFSET_IN_BYTES 0
-#define FRAME_SIZE_IN_BYTES 0
-#define ARG2_OFFSET_IN_WORDS 0
-#endif
-
namespace art {
+// Visits arguments on the stack placing them into the args vector, Object* arguments are converted
+// to jobjects.
+class BuildArgumentVisitor : public ArgumentVisitor {
+ public:
+ BuildArgumentVisitor(MethodHelper& caller_mh, AbstractMethod** sp,
+ ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) :
+ ArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {}
+
+ virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ jvalue val;
+ Primitive::Type type = GetParamPrimitiveType();
+ switch (type) {
+ case Primitive::kPrimNot: {
+ Object* obj = *reinterpret_cast<Object**>(GetParamAddress());
+ val.l = soa_.AddLocalReference<jobject>(obj);
+ break;
+ }
+ case Primitive::kPrimLong: // Fall-through.
+ case Primitive::kPrimDouble:
+ if (IsSplitLongOrDouble()) {
+ val.j = ReadSplitLongParam();
+ } else {
+ val.j = *reinterpret_cast<jlong*>(GetParamAddress());
+ }
+ break;
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimFloat:
+ val.i = *reinterpret_cast<jint*>(GetParamAddress());
+ break;
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "UNREACHABLE";
+ val.j = 0;
+ break;
+ }
+ args_.push_back(val);
+ }
+
+ private:
+ ScopedObjectAccessUnchecked& soa_;
+ std::vector<jvalue>& args_;
+};
+
// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
-// which is responsible for recording callee save registers. We explicitly handlerize incoming
-// reference arguments (so they survive GC) and create a boxed argument array. Finally we invoke
-// the invocation handler which is a field within the proxy object receiver.
-extern "C" void artProxyInvokeHandler(AbstractMethod* proxy_method, Object* receiver,
- Thread* self, byte* stack_args)
+// which is responsible for recording callee save registers. We explicitly place into jobjects the
+// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a
+// field within the proxy object, which will box the primitive arguments and deal with error cases.
+extern "C" uint64_t artProxyInvokeHandler(AbstractMethod* proxy_method, Object* receiver,
+ Thread* self, AbstractMethod** sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// Ensure we don't get thread suspension until the object arguments are safely in jobjects.
const char* old_cause =
self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
// Register the top of the managed stack, making stack crawlable.
- AbstractMethod** proxy_sp = reinterpret_cast<AbstractMethod**>(stack_args - SP_OFFSET_IN_BYTES);
- DCHECK_EQ(*proxy_sp, proxy_method);
- self->SetTopOfStack(proxy_sp, 0);
- DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), FRAME_SIZE_IN_BYTES);
+ DCHECK_EQ(*sp, proxy_method);
+ self->SetTopOfStack(sp, 0);
+ DCHECK_EQ(proxy_method->GetFrameSizeInBytes(),
+ Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
self->VerifyStack();
// Start new JNI local reference state.
JNIEnvExt* env = self->GetJniEnv();
@@ -67,173 +95,26 @@
ScopedJniEnvLocalRefState env_state(env);
// Create local ref. copies of proxy method and the receiver.
jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
- jobject proxy_method_jobj = soa.AddLocalReference<jobject>(proxy_method);
- // Placing into local references incoming arguments from the caller's register arguments,
- // replacing original Object* with jobject.
+ // Placing arguments into args vector and remove the receiver.
MethodHelper proxy_mh(proxy_method);
- const size_t num_params = proxy_mh.NumArgs();
- size_t args_in_regs = 0;
- for (size_t i = 1; i < num_params; i++) { // skip receiver
- args_in_regs = args_in_regs + (proxy_mh.IsParamALongOrDouble(i) ? 2 : 1);
- if (args_in_regs > 2) {
- args_in_regs = 2;
- break;
- }
- }
- size_t cur_arg = 0; // current stack location to read
- size_t param_index = 1; // skip receiver
- while (cur_arg < args_in_regs && param_index < num_params) {
- if (proxy_mh.IsParamAReference(param_index)) {
- Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
- jobject jobj = soa.AddLocalReference<jobject>(obj);
- *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
- }
- cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
- param_index++;
- }
- // Placing into local references incoming arguments from the caller's stack arguments.
- cur_arg += ARG2_OFFSET_IN_WORDS;
- while (param_index < num_params) {
- if (proxy_mh.IsParamAReference(param_index)) {
- Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
- jobject jobj = soa.AddLocalReference<jobject>(obj);
- *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
- }
- cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
- param_index++;
- }
- self->EndAssertNoThreadSuspension(old_cause);
- // Sanity check writing the jobjects over the Object*s in place didn't damage the stack.
- self->VerifyStack();
+ std::vector<jvalue> args;
+ BuildArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args);
+ local_ref_visitor.VisitArguments();
+ args.erase(args.begin());
- // Set up arguments array and place in local IRT during boxing (which may allocate/GC).
- jvalue args_jobj[3];
- args_jobj[0].l = rcvr_jobj;
- args_jobj[1].l = proxy_method_jobj;
- // Args array, if no arguments then NULL (don't include receiver in argument count).
- args_jobj[2].l = NULL;
- ObjectArray<Object>* args = NULL;
- if ((num_params - 1) > 0) {
- args = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(self, num_params - 1);
- if (args == NULL) {
- CHECK(self->IsExceptionPending());
- return;
- }
- args_jobj[2].l = soa.AddLocalReference<jobjectArray>(args);
- }
// Convert proxy method into expected interface method.
AbstractMethod* interface_method = proxy_method->FindOverriddenMethod();
DCHECK(interface_method != NULL);
DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
- args_jobj[1].l = soa.AddLocalReference<jobject>(interface_method);
- // Box primitive type arguments.
- cur_arg = 0; // Stack location to read to start.
- // Reset index, will index into param type array which doesn't include the receiver.
- param_index = 0;
- ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes(self);
- if (param_types == NULL) {
- CHECK(self->IsExceptionPending());
- return;
- }
- // Check number of parameter types agrees with number from the Method - less 1 for the receiver.
- DCHECK_EQ(static_cast<size_t>(param_types->GetLength()), num_params - 1);
- while (cur_arg < args_in_regs && param_index < (num_params - 1)) {
- Class* param_type = param_types->Get(param_index);
- Object* obj;
- if (!param_type->IsPrimitive()) {
- obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
- } else {
- JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
- if (cur_arg == 1 && (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble())) {
- // long/double split over regs and stack, mask in high half from stack arguments.
- uint64_t high_half =
- *reinterpret_cast<uint32_t*>(stack_args + ((ARG2_OFFSET_IN_WORDS + 2) * kPointerSize));
- val.SetJ((val.GetJ() & 0xffffffffULL) | (high_half << 32));
- }
- BoxPrimitive(param_type->GetPrimitiveType(), val);
- if (self->IsExceptionPending()) {
- return;
- }
- obj = val.GetL();
- }
- args->Set(param_index, obj);
- cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
- param_index++;
- }
- // Placing into local references incoming arguments from the caller's stack arguments.
- cur_arg += ARG2_OFFSET_IN_WORDS;
- while (param_index < (num_params - 1)) {
- Class* param_type = param_types->Get(param_index);
- Object* obj;
- if (!param_type->IsPrimitive()) {
- obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
- } else {
- JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
- BoxPrimitive(param_type->GetPrimitiveType(), val);
- if (self->IsExceptionPending()) {
- return;
- }
- obj = val.GetL();
- }
- args->Set(param_index, obj);
- cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
- param_index++;
- }
- // Get the InvocationHandler method and the field that holds it within the Proxy object.
- DCHECK(env->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy));
- jobject inv_hand = env->GetObjectField(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy_h);
- // Call InvocationHandler.invoke.
- jobject result =
- env->CallObjectMethodA(inv_hand, WellKnownClasses::java_lang_reflect_InvocationHandler_invoke,
- args_jobj);
- // Place result in stack args.
- if (!self->IsExceptionPending()) {
- Object* result_ref = self->DecodeJObject(result);
- if (result_ref != NULL) {
- JValue result_unboxed;
- bool unboxed_okay = UnboxPrimitiveForResult(result_ref, proxy_mh.GetReturnType(),
- result_unboxed);
- if (!unboxed_okay) {
- self->ClearException();
- self->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
- "Couldn't convert result of type %s to %s",
- PrettyTypeOf(result_ref).c_str(),
- PrettyDescriptor(proxy_mh.GetReturnType()).c_str());
- return;
- }
- *reinterpret_cast<JValue*>(stack_args) = result_unboxed;
- } else {
- *reinterpret_cast<jobject*>(stack_args) = NULL;
- }
- } else {
- // In the case of checked exceptions that aren't declared, the exception must be wrapped by
- // a UndeclaredThrowableException.
- Throwable* exception = self->GetException();
- if (exception->IsCheckedException()) {
- SynthesizedProxyClass* proxy_class =
- down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
- int throws_index = -1;
- size_t num_virt_methods = proxy_class->NumVirtualMethods();
- for (size_t i = 0; i < num_virt_methods; i++) {
- if (proxy_class->GetVirtualMethod(i) == proxy_method) {
- throws_index = i;
- break;
- }
- }
- CHECK_NE(throws_index, -1);
- ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
- Class* exception_class = exception->GetClass();
- bool declares_exception = false;
- for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
- Class* declared_exception = declared_exceptions->Get(i);
- declares_exception = declared_exception->IsAssignableFrom(exception_class);
- }
- if (!declares_exception) {
- self->ThrowNewWrappedException("Ljava/lang/reflect/UndeclaredThrowableException;", NULL);
- }
- }
- }
+ jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
+
+ // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
+ // that performs allocations.
+ self->EndAssertNoThreadSuspension(old_cause);
+ JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(),
+ rcvr_jobj, interface_method_jobj, args);
+ return result.GetJ();
}
} // namespace art
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index 379fcce..f2f9fa4 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -738,15 +738,14 @@
DEFINE_FUNCTION art_proxy_invoke_handler
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME // save frame
- lea 8(%esp), %ebx // pointer to r2/r3/LR/caller's Method**/out-args as second arg
- pushl %ebx // pass args
+ pushl %esp // pass SP
pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
pushl %ecx // pass receiver
pushl %eax // pass proxy method
- call SYMBOL(artProxyInvokeHandler) // (proxy method, receiver, Thread*, args...)
- mov 24(%esp), %eax // get ret0 which was written into r2 on the stack
- mov 28(%esp), %edx // get ret1 which was written into r3 on the stack
- movsd 24(%esp), %xmm0 // get ret0/ret1 from stack for floating point
+ call SYMBOL(artProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
+ movd %eax, %xmm0 // place return value also into floating point return value
+ movd %edx, %xmm1
+ punpckldq %xmm1, %xmm0
addl LITERAL(44), %esp // pop arguments
RETURN_OR_DELIVER_PENDING_EXCEPTION // return or deliver exception
diff --git a/src/object_utils.h b/src/object_utils.h
index dd5ff05..068dd66 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -566,8 +566,7 @@
return method_->GetDeclaringClass()->GetClassLoader();
}
- bool IsStatic()
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ bool IsStatic() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return method_->IsStatic();
}
@@ -581,28 +580,26 @@
return (IsStatic() ? 0 : 1) + GetShortyLength() - 1;
}
- // Is the specified parameter a long or double, where parameter 0 is 'this' for instance methods
- bool IsParamALongOrDouble(size_t param)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Get the primitive type associated with the given parameter.
+ Primitive::Type GetParamPrimitiveType(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
CHECK_LT(param, NumArgs());
if (IsStatic()) {
param++; // 0th argument must skip return value at start of the shorty
} else if (param == 0) {
- return false; // this argument
+ return Primitive::kPrimNot;
}
- char ch = GetShorty()[param];
- return (ch == 'J' || ch == 'D');
+ return Primitive::GetType(GetShorty()[param]);
}
- // Is the specified parameter a reference, where parameter 0 is 'this' for instance methods
+ // Is the specified parameter a long or double, where parameter 0 is 'this' for instance methods.
+ bool IsParamALongOrDouble(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Primitive::Type type = GetParamPrimitiveType(param);
+ return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
+ }
+
+ // Is the specified parameter a reference, where parameter 0 is 'this' for instance methods.
bool IsParamAReference(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- CHECK_LT(param, NumArgs());
- if (IsStatic()) {
- param++; // 0th argument must skip return value at start of the shorty
- } else if (param == 0) {
- return true; // this argument
- }
- return GetShorty()[param] == 'L'; // An array also has a shorty character of 'L' (not '[')
+ return GetParamPrimitiveType(param) == Primitive::kPrimNot;
}
bool HasSameNameAndSignature(MethodHelper* other)
diff --git a/src/reflection.cc b/src/reflection.cc
index c793d2c..1ffad3f 100644
--- a/src/reflection.cc
+++ b/src/reflection.cc
@@ -90,8 +90,7 @@
}
// Box if necessary and return.
- BoxPrimitive(mh.GetReturnType()->GetPrimitiveType(), value);
- return soa.AddLocalReference<jobject>(value.GetL());
+ return soa.AddLocalReference<jobject>(BoxPrimitive(mh.GetReturnType()->GetPrimitiveType(), value));
}
bool VerifyObjectInClass(Object* o, Class* c) {
@@ -195,9 +194,9 @@
return false;
}
-void BoxPrimitive(Primitive::Type src_class, JValue& value) {
+Object* BoxPrimitive(Primitive::Type src_class, const JValue& value) {
if (src_class == Primitive::kPrimNot) {
- return;
+ return value.GetL();
}
jmethodID m = NULL;
@@ -228,8 +227,7 @@
break;
case Primitive::kPrimVoid:
// There's no such thing as a void field, and void methods invoked via reflection return null.
- value.SetL(NULL);
- return;
+ return NULL;
default:
LOG(FATAL) << static_cast<int>(src_class);
}
@@ -239,7 +237,9 @@
CHECK_EQ(soa.Self()->GetState(), kRunnable);
}
JValue args[1] = { value };
- soa.DecodeMethod(m)->Invoke(soa.Self(), NULL, args, &value);
+ JValue result;
+ soa.DecodeMethod(m)->Invoke(soa.Self(), NULL, args, &result);
+ return result.GetL();
}
static std::string UnboxingFailureKind(AbstractMethod* m, int index, Field* f)
diff --git a/src/reflection.h b/src/reflection.h
index b61acda..601543f 100644
--- a/src/reflection.h
+++ b/src/reflection.h
@@ -29,10 +29,10 @@
class Object;
class ScopedObjectAccess;
-void BoxPrimitive(Primitive::Type src_class, JValue& value)
+Object* BoxPrimitive(Primitive::Type src_class, const JValue& value)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-bool UnboxPrimitiveForArgument(Object* o, Class* dst_class, JValue& unboxed_value, AbstractMethod* m,
- size_t index)
+bool UnboxPrimitiveForArgument(Object* o, Class* dst_class, JValue& unboxed_value,
+ AbstractMethod* m, size_t index)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool UnboxPrimitiveForField(Object* o, Class* dst_class, JValue& unboxed_value, Field* f)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 856e877..b276917 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -16,6 +16,8 @@
#include "runtime_support.h"
+#include "reflection.h"
+#include "scoped_thread_state_change.h"
#include "ScopedLocalRef.h"
#include "well_known_classes.h"
@@ -372,4 +374,103 @@
self->ResetDefaultStackEnd(); // Return to default stack size.
}
+JValue InvokeProxyInvocationHandler(ScopedObjectAccessUnchecked& soa, const char* shorty,
+ jobject rcvr_jobj, jobject interface_method_jobj,
+ std::vector<jvalue>& args) {
+ DCHECK(soa.Env()->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy));
+
+ // Build argument array possibly triggering GC.
+ soa.Self()->AssertThreadSuspensionIsAllowable();
+ jobjectArray args_jobj = NULL;
+ const JValue zero;
+ if (args.size() > 0) {
+ args_jobj = soa.Env()->NewObjectArray(args.size(), WellKnownClasses::java_lang_Object, NULL);
+ if (args_jobj == NULL) {
+ CHECK(soa.Self()->IsExceptionPending());
+ return zero;
+ }
+ for (size_t i = 0; i < args.size(); ++i) {
+ if (shorty[i + 1] == 'L') {
+ jobject val = args.at(i).l;
+ soa.Env()->SetObjectArrayElement(args_jobj, i, val);
+ } else {
+ JValue jv;
+ jv.SetJ(args.at(i).j);
+ Object* val = BoxPrimitive(Primitive::GetType(shorty[i + 1]), jv);
+ if (val == NULL) {
+ CHECK(soa.Self()->IsExceptionPending());
+ return zero;
+ }
+ soa.Decode<ObjectArray<Object>* >(args_jobj)->Set(i, val);
+ }
+ }
+ }
+
+ // Call InvocationHandler.invoke(Object proxy, Method method, Object[] args).
+ jobject inv_hand = soa.Env()->GetObjectField(rcvr_jobj,
+ WellKnownClasses::java_lang_reflect_Proxy_h);
+ jvalue invocation_args[3];
+ invocation_args[0].l = rcvr_jobj;
+ invocation_args[1].l = interface_method_jobj;
+ invocation_args[2].l = args_jobj;
+ jobject result =
+ soa.Env()->CallObjectMethodA(inv_hand,
+ WellKnownClasses::java_lang_reflect_InvocationHandler_invoke,
+ invocation_args);
+
+ // Unbox result and handle error conditions.
+ if (!soa.Self()->IsExceptionPending()) {
+ if (shorty[0] == 'V' || result == NULL) {
+ // Do nothing.
+ return zero;
+ } else {
+ JValue result_unboxed;
+ MethodHelper mh(soa.Decode<AbstractMethod*>(interface_method_jobj));
+ Class* result_type = mh.GetReturnType();
+ Object* result_ref = soa.Decode<Object*>(result);
+ bool unboxed_okay = UnboxPrimitiveForResult(result_ref, result_type, result_unboxed);
+ if (!unboxed_okay) {
+ soa.Self()->ThrowNewWrappedException("Ljava/lang/ClassCastException;",
+ StringPrintf("Couldn't convert result of type %s to %s",
+ PrettyTypeOf(result_ref).c_str(),
+ PrettyDescriptor(result_type).c_str()
+ ).c_str());
+ }
+ return result_unboxed;
+ }
+ } else {
+ // In the case of checked exceptions that aren't declared, the exception must be wrapped by
+ // a UndeclaredThrowableException.
+ Throwable* exception = soa.Self()->GetException();
+ if (exception->IsCheckedException()) {
+ Object* rcvr = soa.Decode<Object*>(rcvr_jobj);
+ SynthesizedProxyClass* proxy_class = down_cast<SynthesizedProxyClass*>(rcvr->GetClass());
+ AbstractMethod* interface_method = soa.Decode<AbstractMethod*>(interface_method_jobj);
+ AbstractMethod* proxy_method =
+ rcvr->GetClass()->FindVirtualMethodForInterface(interface_method);
+ int throws_index = -1;
+ size_t num_virt_methods = proxy_class->NumVirtualMethods();
+ for (size_t i = 0; i < num_virt_methods; i++) {
+ if (proxy_class->GetVirtualMethod(i) == proxy_method) {
+ throws_index = i;
+ break;
+ }
+ }
+ CHECK_NE(throws_index, -1);
+ ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
+ Class* exception_class = exception->GetClass();
+ bool declares_exception = false;
+ for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
+ Class* declared_exception = declared_exceptions->Get(i);
+ declares_exception = declared_exception->IsAssignableFrom(exception_class);
+ }
+ if (!declares_exception) {
+ soa.Self()->ThrowNewWrappedException("Ljava/lang/reflect/UndeclaredThrowableException;",
+ NULL);
+ }
+ }
+ return zero;
+ }
+}
+
} // namespace art
diff --git a/src/runtime_support.h b/src/runtime_support.h
index adeedb7..1c8d174 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -28,6 +28,7 @@
#include "thread.h"
#include "verifier/method_verifier.h"
+extern "C" void art_interpreter_invoke_handler();
extern "C" void art_proxy_invoke_handler();
extern "C" void art_work_around_app_jni_bugs();
@@ -282,8 +283,7 @@
}
}
-static inline void CheckSuspend(Thread* thread)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static inline void CheckSuspend(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
for (;;) {
if (thread->ReadFlag(kCheckpointRequest)) {
thread->RunCheckpointFunction();
@@ -296,6 +296,11 @@
}
}
+JValue InvokeProxyInvocationHandler(ScopedObjectAccessUnchecked& soa, const char* shorty,
+ jobject rcvr_jobj, jobject interface_method_jobj,
+ std::vector<jvalue>& args)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ;
+
} // namespace art
#endif // ART_SRC_RUNTIME_SUPPORT_H_
diff --git a/src/verifier/method_verifier_test.cc b/src/verifier/method_verifier_test.cc
index 9c9c745..8d4c513 100644
--- a/src/verifier/method_verifier_test.cc
+++ b/src/verifier/method_verifier_test.cc
@@ -55,13 +55,5 @@
VerifyDexFile(java_lang_dex_file_);
}
-TEST_F(MethodVerifierTest, IntMath) {
- ScopedObjectAccess soa(Thread::Current());
- jobject class_loader = LoadDex("IntMath");
- Class* klass = class_linker_->FindClass("LIntMath;", soa.Decode<ClassLoader*>(class_loader));
- std::string error_msg;
- ASSERT_TRUE(MethodVerifier::VerifyClass(klass, error_msg) == MethodVerifier::kNoFailure) << error_msg;
-}
-
} // namespace verifier
} // namespace art
diff --git a/src/well_known_classes.cc b/src/well_known_classes.cc
index caf42ee..9752c74 100644
--- a/src/well_known_classes.cc
+++ b/src/well_known_classes.cc
@@ -30,6 +30,7 @@
jclass WellKnownClasses::java_lang_ClassNotFoundException;
jclass WellKnownClasses::java_lang_Daemons;
jclass WellKnownClasses::java_lang_Error;
+jclass WellKnownClasses::java_lang_Object;
jclass WellKnownClasses::java_lang_reflect_InvocationHandler;
jclass WellKnownClasses::java_lang_reflect_AbstractMethod;
jclass WellKnownClasses::java_lang_reflect_Proxy;
@@ -123,6 +124,7 @@
java_lang_ClassLoader = CacheClass(env, "java/lang/ClassLoader");
java_lang_ClassNotFoundException = CacheClass(env, "java/lang/ClassNotFoundException");
java_lang_Daemons = CacheClass(env, "java/lang/Daemons");
+ java_lang_Object = CacheClass(env, "java/lang/Object");
java_lang_Error = CacheClass(env, "java/lang/Error");
java_lang_reflect_InvocationHandler = CacheClass(env, "java/lang/reflect/InvocationHandler");
java_lang_reflect_AbstractMethod = CacheClass(env, "java/lang/reflect/AbstractMethod");
diff --git a/src/well_known_classes.h b/src/well_known_classes.h
index 3dbf8a1..10afca9 100644
--- a/src/well_known_classes.h
+++ b/src/well_known_classes.h
@@ -42,6 +42,7 @@
static jclass java_lang_ClassNotFoundException;
static jclass java_lang_Daemons;
static jclass java_lang_Error;
+ static jclass java_lang_Object;
static jclass java_lang_reflect_InvocationHandler;
static jclass java_lang_reflect_AbstractMethod;
static jclass java_lang_reflect_Proxy;
diff --git a/test/107-int-math2/expected.txt b/test/107-int-math2/expected.txt
new file mode 100644
index 0000000..b131cc2
--- /dev/null
+++ b/test/107-int-math2/expected.txt
@@ -0,0 +1,35 @@
+divideLongByBillion PASSED
+unopTest PASSED
+shiftTest1 PASSED
+shiftTest2 PASSED
+unsignedShiftTest PASSED
+convTest PASSED
+charSubTest PASSED
+intOperTest PASSED
+lit16Test PASSED
+lit8Test PASSED
+intShiftTest PASSED
+longOperTest PASSED
+longShiftTest PASSED
+switchTest PASSED
+testIntCompare PASSED
+testLongCompare PASSED
+testFloatCompare PASSED
+testDoubleCompare PASSED
+fibonacci PASSED
+throwAndCatch PASSED
+testClassCast PASSED
+testArrayStore PASSED
+testStackOverflow PASSED
+testArrayAllocation PASSED
+manyArgs PASSED
+virtualCall PASSED
+testGetPut PASSED
+staticFieldTest PASSED
+catchBlock(1000) PASSED
+catchBlock(7000) PASSED
+catchBlockNoThrow PASSED
+superTest PASSED
+constClassTest PASSED
+constStringTest PASSED
+instanceTest PASSED
diff --git a/test/107-int-math2/info.txt b/test/107-int-math2/info.txt
new file mode 100644
index 0000000..2b1c485
--- /dev/null
+++ b/test/107-int-math2/info.txt
@@ -0,0 +1,2 @@
+A forked and extended version of IntMath from 003-omnibus-opcodes.
+TODO: fold back into 003-omnibus-opcodes.
diff --git a/test/IntMath/IntMath.java b/test/107-int-math2/src/Main.java
similarity index 98%
rename from test/IntMath/IntMath.java
rename to test/107-int-math2/src/Main.java
index 65894a3..d737ff5 100644
--- a/test/IntMath/IntMath.java
+++ b/test/107-int-math2/src/Main.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-class IntMath extends IntMathBase {
+class Main extends IntMathBase {
public static boolean mBoolean1, mBoolean2;
public static byte mByte1, mByte2;
@@ -29,12 +29,12 @@
private int foo_;
- public IntMath(int stuff) {
+ public Main(int stuff) {
super();
foo_ = stuff;
}
- public IntMath() {
+ public Main() {
super();
foo_ = 123;
}
@@ -66,7 +66,7 @@
static int instanceTest(int x) {
IntMathBase a = new IntMathBase();
- IntMath b = new IntMath();
+ Main b = new Main();
if (!(null instanceof IntMathBase)) {
x = x + 42;
@@ -76,7 +76,7 @@
x = x * 2;
}
- if (a instanceof IntMath) {
+ if (a instanceof Main) {
x = x + 13;
}
@@ -84,7 +84,7 @@
x = x -1;
}
- if (b instanceof IntMath) {
+ if (b instanceof Main) {
x = x + 1333;
}
return x;
@@ -96,8 +96,8 @@
}
static int superTest(int x) {
- IntMath instance = new IntMath();
- IntMath base = instance;
+ Main instance = new Main();
+ Main base = instance;
int val1 = instance.tryThing();
int val2 = base.tryThing();
return val1 + val2 + x;
@@ -770,14 +770,14 @@
static int staticCall(int a)
{
- IntMath foo = new IntMath();
+ Main foo = new Main();
return foo.virtualCall(a);
}
static int testIGetPut(int a)
{
- IntMath foo = new IntMath(99);
- IntMath foo123 = new IntMath();
+ Main foo = new Main(99);
+ Main foo123 = new Main();
int z = foo.getFoo();
z += a;
z += foo123.getFoo();