interpreter_common.cc revision 8ece050d85fc244c72610244e440b0e00aa618fa
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "interpreter_common.h"
18
19namespace art {
20namespace interpreter {
21
22template<InvokeType type, bool is_range, bool do_access_check>
23bool DoInvoke(Thread* self, ShadowFrame& shadow_frame,
24              const Instruction* inst, JValue* result) {
25  uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
26  uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
27  Object* receiver = (type == kStatic) ? NULL : shadow_frame.GetVRegReference(vregC);
28  ArtMethod* method = FindMethodFromCode(method_idx, receiver, shadow_frame.GetMethod(), self,
29                                         do_access_check, type);
30  if (UNLIKELY(method == NULL)) {
31    CHECK(self->IsExceptionPending());
32    result->SetJ(0);
33    return false;
34  } else if (UNLIKELY(method->IsAbstract())) {
35    ThrowAbstractMethodError(method);
36    result->SetJ(0);
37    return false;
38  }
39
40  MethodHelper mh(method);
41  const DexFile::CodeItem* code_item = mh.GetCodeItem();
42  uint16_t num_regs;
43  uint16_t num_ins;
44  if (LIKELY(code_item != NULL)) {
45    num_regs = code_item->registers_size_;
46    num_ins = code_item->ins_size_;
47  } else {
48    DCHECK(method->IsNative() || method->IsProxyMethod());
49    num_regs = num_ins = ArtMethod::NumArgRegisters(mh.GetShorty());
50    if (!method->IsStatic()) {
51      num_regs++;
52      num_ins++;
53    }
54  }
55
56  void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
57  ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame, method, 0, memory));
58  size_t cur_reg = num_regs - num_ins;
59  if (receiver != NULL) {
60    new_shadow_frame->SetVRegReference(cur_reg, receiver);
61    ++cur_reg;
62  }
63
64  size_t arg_offset = (receiver == NULL) ? 0 : 1;
65  const char* shorty = mh.GetShorty();
66  uint32_t arg[5];
67  if (!is_range) {
68    inst->GetArgs(arg);
69  }
70  for (size_t shorty_pos = 0; cur_reg < num_regs; ++shorty_pos, cur_reg++, arg_offset++) {
71    DCHECK_LT(shorty_pos + 1, mh.GetShortyLength());
72    size_t arg_pos = is_range ? vregC + arg_offset : arg[arg_offset];
73    switch (shorty[shorty_pos + 1]) {
74      case 'L': {
75        Object* o = shadow_frame.GetVRegReference(arg_pos);
76        new_shadow_frame->SetVRegReference(cur_reg, o);
77        break;
78      }
79      case 'J': case 'D': {
80        uint64_t wide_value = (static_cast<uint64_t>(shadow_frame.GetVReg(arg_pos + 1)) << 32) |
81                              static_cast<uint32_t>(shadow_frame.GetVReg(arg_pos));
82        new_shadow_frame->SetVRegLong(cur_reg, wide_value);
83        cur_reg++;
84        arg_offset++;
85        break;
86      }
87      default:
88        new_shadow_frame->SetVReg(cur_reg, shadow_frame.GetVReg(arg_pos));
89        break;
90    }
91  }
92
93  if (LIKELY(Runtime::Current()->IsStarted())) {
94    (method->GetEntryPointFromInterpreter())(self, mh, code_item, new_shadow_frame, result);
95  } else {
96    UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, num_regs - num_ins);
97  }
98  return !self->IsExceptionPending();
99}
100
101template<bool is_range>
102bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame,
103                          const Instruction* inst, JValue* result) {
104  uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
105  Object* receiver = shadow_frame.GetVRegReference(vregC);
106  if (UNLIKELY(receiver == NULL)) {
107    // We lost the reference to the method index so we cannot get a more
108    // precised exception message.
109    ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
110    return false;
111  }
112  uint32_t vtable_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
113  // TODO: use ObjectArray<T>::GetWithoutChecks ?
114  ArtMethod* method = receiver->GetClass()->GetVTable()->Get(vtable_idx);
115  if (UNLIKELY(method == NULL)) {
116    CHECK(self->IsExceptionPending());
117    result->SetJ(0);
118    return false;
119  } else if (UNLIKELY(method->IsAbstract())) {
120    ThrowAbstractMethodError(method);
121    result->SetJ(0);
122    return false;
123  }
124
125  MethodHelper mh(method);
126  const DexFile::CodeItem* code_item = mh.GetCodeItem();
127  uint16_t num_regs;
128  uint16_t num_ins;
129  if (code_item != NULL) {
130    num_regs = code_item->registers_size_;
131    num_ins = code_item->ins_size_;
132  } else {
133    DCHECK(method->IsNative() || method->IsProxyMethod());
134    num_regs = num_ins = ArtMethod::NumArgRegisters(mh.GetShorty());
135    if (!method->IsStatic()) {
136      num_regs++;
137      num_ins++;
138    }
139  }
140
141  void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
142  ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame,
143                                                    method, 0, memory));
144  size_t cur_reg = num_regs - num_ins;
145  if (receiver != NULL) {
146    new_shadow_frame->SetVRegReference(cur_reg, receiver);
147    ++cur_reg;
148  }
149
150  size_t arg_offset = (receiver == NULL) ? 0 : 1;
151  const char* shorty = mh.GetShorty();
152  uint32_t arg[5];
153  if (!is_range) {
154    inst->GetArgs(arg);
155  }
156  for (size_t shorty_pos = 0; cur_reg < num_regs; ++shorty_pos, cur_reg++, arg_offset++) {
157    DCHECK_LT(shorty_pos + 1, mh.GetShortyLength());
158    size_t arg_pos = is_range ? vregC + arg_offset : arg[arg_offset];
159    switch (shorty[shorty_pos + 1]) {
160      case 'L': {
161        Object* o = shadow_frame.GetVRegReference(arg_pos);
162        new_shadow_frame->SetVRegReference(cur_reg, o);
163        break;
164      }
165      case 'J': case 'D': {
166        uint64_t wide_value = (static_cast<uint64_t>(shadow_frame.GetVReg(arg_pos + 1)) << 32) |
167                              static_cast<uint32_t>(shadow_frame.GetVReg(arg_pos));
168        new_shadow_frame->SetVRegLong(cur_reg, wide_value);
169        cur_reg++;
170        arg_offset++;
171        break;
172      }
173      default:
174        new_shadow_frame->SetVReg(cur_reg, shadow_frame.GetVReg(arg_pos));
175        break;
176    }
177  }
178
179  if (LIKELY(Runtime::Current()->IsStarted())) {
180    (method->GetEntryPointFromInterpreter())(self, mh, code_item, new_shadow_frame, result);
181  } else {
182    UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, num_regs - num_ins);
183  }
184  return !self->IsExceptionPending();
185}
186
187template <bool is_range, bool do_access_check>
188bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
189                      Thread* self, JValue* result) {
190  DCHECK(inst->Opcode() == Instruction::FILLED_NEW_ARRAY ||
191         inst->Opcode() == Instruction::FILLED_NEW_ARRAY_RANGE);
192  const int32_t length = is_range ? inst->VRegA_3rc() : inst->VRegA_35c();
193  if (!is_range) {
194    // Checks FILLED_NEW_ARRAY's length does not exceed 5 arguments.
195    CHECK_LE(length, 5);
196  }
197  if (UNLIKELY(length < 0)) {
198    ThrowNegativeArraySizeException(length);
199    return false;
200  }
201  uint16_t type_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
202  Class* arrayClass = ResolveVerifyAndClinit(type_idx, shadow_frame.GetMethod(),
203                                             self, false, do_access_check);
204  if (UNLIKELY(arrayClass == NULL)) {
205    DCHECK(self->IsExceptionPending());
206    return false;
207  }
208  CHECK(arrayClass->IsArrayClass());
209  Class* componentClass = arrayClass->GetComponentType();
210  if (UNLIKELY(componentClass->IsPrimitive() && !componentClass->IsPrimitiveInt())) {
211    if (componentClass->IsPrimitiveLong() || componentClass->IsPrimitiveDouble()) {
212      ThrowRuntimeException("Bad filled array request for type %s",
213                            PrettyDescriptor(componentClass).c_str());
214    } else {
215      self->ThrowNewExceptionF(shadow_frame.GetCurrentLocationForThrow(),
216                               "Ljava/lang/InternalError;",
217                               "Found type %s; filled-new-array not implemented for anything but \'int\'",
218                               PrettyDescriptor(componentClass).c_str());
219    }
220    return false;
221  }
222  Object* newArray = Array::Alloc(self, arrayClass, length);
223  if (UNLIKELY(newArray == NULL)) {
224    DCHECK(self->IsExceptionPending());
225    return false;
226  }
227  if (is_range) {
228    uint32_t vregC = inst->VRegC_3rc();
229    const bool is_primitive_int_component = componentClass->IsPrimitiveInt();
230    for (int32_t i = 0; i < length; ++i) {
231      if (is_primitive_int_component) {
232        newArray->AsIntArray()->Set(i, shadow_frame.GetVReg(vregC + i));
233      } else {
234        newArray->AsObjectArray<Object>()->Set(i, shadow_frame.GetVRegReference(vregC + i));
235      }
236    }
237  } else {
238    uint32_t arg[5];
239    inst->GetArgs(arg);
240    const bool is_primitive_int_component = componentClass->IsPrimitiveInt();
241    for (int32_t i = 0; i < length; ++i) {
242      if (is_primitive_int_component) {
243        newArray->AsIntArray()->Set(i, shadow_frame.GetVReg(arg[i]));
244      } else {
245        newArray->AsObjectArray<Object>()->Set(i, shadow_frame.GetVRegReference(arg[i]));
246      }
247    }
248  }
249
250  result->SetL(newArray);
251  return true;
252}
253
254void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
255                            const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
256                            JValue* result, size_t arg_offset) {
257  // In a runtime that's not started we intercept certain methods to avoid complicated dependency
258  // problems in core libraries.
259  std::string name(PrettyMethod(shadow_frame->GetMethod()));
260  if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
261    std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str()));
262    ClassLoader* class_loader = NULL;  // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
263    Class* found = Runtime::Current()->GetClassLinker()->FindClass(descriptor.c_str(),
264                                                                   class_loader);
265    CHECK(found != NULL) << "Class.forName failed in un-started runtime for class: "
266        << PrettyDescriptor(descriptor);
267    result->SetL(found);
268  } else if (name == "java.lang.Object java.lang.Class.newInstance()") {
269    Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
270    ArtMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V");
271    CHECK(c != NULL);
272    SirtRef<Object> obj(self, klass->AllocObject(self));
273    CHECK(obj.get() != NULL);
274    EnterInterpreterFromInvoke(self, c, obj.get(), NULL, NULL);
275    result->SetL(obj.get());
276  } else if (name == "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") {
277    // Special managed code cut-out to allow field lookup in a un-started runtime that'd fail
278    // going the reflective Dex way.
279    Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
280    String* name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString();
281    ArtField* found = NULL;
282    FieldHelper fh;
283    ObjectArray<ArtField>* fields = klass->GetIFields();
284    for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) {
285      ArtField* f = fields->Get(i);
286      fh.ChangeField(f);
287      if (name->Equals(fh.GetName())) {
288        found = f;
289      }
290    }
291    if (found == NULL) {
292      fields = klass->GetSFields();
293      for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) {
294        ArtField* f = fields->Get(i);
295        fh.ChangeField(f);
296        if (name->Equals(fh.GetName())) {
297          found = f;
298        }
299      }
300    }
301    CHECK(found != NULL)
302      << "Failed to find field in Class.getDeclaredField in un-started runtime. name="
303      << name->ToModifiedUtf8() << " class=" << PrettyDescriptor(klass);
304    // TODO: getDeclaredField calls GetType once the field is found to ensure a
305    //       NoClassDefFoundError is thrown if the field's type cannot be resolved.
306    Class* jlr_Field = self->DecodeJObject(WellKnownClasses::java_lang_reflect_Field)->AsClass();
307    SirtRef<Object> field(self, jlr_Field->AllocObject(self));
308    CHECK(field.get() != NULL);
309    ArtMethod* c = jlr_Field->FindDeclaredDirectMethod("<init>", "(Ljava/lang/reflect/ArtField;)V");
310    uint32_t args[1];
311    args[0] = reinterpret_cast<uint32_t>(found);
312    EnterInterpreterFromInvoke(self, c, field.get(), args, NULL);
313    result->SetL(field.get());
314  } else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)" ||
315             name == "void java.lang.System.arraycopy(char[], int, char[], int, int)") {
316    // Special case array copying without initializing System.
317    Class* ctype = shadow_frame->GetVRegReference(arg_offset)->GetClass()->GetComponentType();
318    jint srcPos = shadow_frame->GetVReg(arg_offset + 1);
319    jint dstPos = shadow_frame->GetVReg(arg_offset + 3);
320    jint length = shadow_frame->GetVReg(arg_offset + 4);
321    if (!ctype->IsPrimitive()) {
322      ObjectArray<Object>* src = shadow_frame->GetVRegReference(arg_offset)->AsObjectArray<Object>();
323      ObjectArray<Object>* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsObjectArray<Object>();
324      for (jint i = 0; i < length; ++i) {
325        dst->Set(dstPos + i, src->Get(srcPos + i));
326      }
327    } else if (ctype->IsPrimitiveChar()) {
328      CharArray* src = shadow_frame->GetVRegReference(arg_offset)->AsCharArray();
329      CharArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsCharArray();
330      for (jint i = 0; i < length; ++i) {
331        dst->Set(dstPos + i, src->Get(srcPos + i));
332      }
333    } else if (ctype->IsPrimitiveInt()) {
334      IntArray* src = shadow_frame->GetVRegReference(arg_offset)->AsIntArray();
335      IntArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsIntArray();
336      for (jint i = 0; i < length; ++i) {
337        dst->Set(dstPos + i, src->Get(srcPos + i));
338      }
339    } else {
340      UNIMPLEMENTED(FATAL) << "System.arraycopy of unexpected type: " << PrettyDescriptor(ctype);
341    }
342  } else {
343    // Not special, continue with regular interpreter execution.
344    artInterpreterToInterpreterBridge(self, mh, code_item, shadow_frame, result);
345  }
346}
347
348// Explicit DoInvoke template function declarations.
349#define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range_, _check) \
350  template bool DoInvoke<_type, _is_range_, _check>(Thread* self, ShadowFrame& shadow_frame, \
351                                                    const Instruction* inst, JValue* result)
352
353#define EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS(_type) \
354  EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, false); \
355  EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, true);  \
356  EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, true, false);  \
357  EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, true, true)
358
359EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS(kStatic);
360EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS(kDirect);
361EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS(kVirtual);
362EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS(kSuper);
363EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS(kInterface);
364
365#undef EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS
366#undef EXPLICIT_DO_INVOKE_TEMPLATE_DECL
367
368// Explicit DoInvokeVirtualQuick template function declarations.
369#define EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(_is_range)                       \
370template bool DoInvokeVirtualQuick<_is_range>(Thread* self, ShadowFrame& shadow_frame,  \
371                                              const Instruction* inst, JValue* result)
372
373EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(false);
374EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(true);
375#undef EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL
376
377// Explicit DoFilledNewArray template function declarations.
378#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check)                \
379  template bool DoFilledNewArray<_is_range_, _check>(const Instruction* inst,         \
380                                                     const ShadowFrame& shadow_frame, \
381                                                     Thread* self, JValue* result)
382EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, false);
383EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, true);
384EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, false);
385EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, true);
386#undef EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL
387
388}  // namespace interpreter
389}  // namespace art
390