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
diff --git a/src/invoke_arg_array_builder.h b/src/invoke_arg_array_builder.h
new file mode 100644
index 0000000..e965a1a
--- /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_