blob: 86a6aea053589749e7698e6bd2d6bc1dc2640da7 [file] [log] [blame]
Sebastien Hertz8ece0502013-08-07 11:26:41 +02001/*
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