blob: e185c9cb0a8018f6d5e2111bfbaf493a0f6ad8c5 [file] [log] [blame]
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001/*
2 * Copyright (C) 2011 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 "abstract_method.h"
18
19#include "abstract_method-inl.h"
20#include "class-inl.h"
21#include "base/stringpiece.h"
22#include "gc/card_table-inl.h"
23#include "interpreter/interpreter.h"
24#include "jni_internal.h"
25#include "object-inl.h"
26#include "object_array.h"
27#include "object_array-inl.h"
28#include "string.h"
29#include "object_utils.h"
30
31namespace art {
32namespace mirror {
33
Jeff Hao5d917302013-02-27 17:57:33 -080034extern "C" void art_quick_invoke_stub(AbstractMethod*, uint32_t*, uint32_t,
35 Thread*, JValue*, JValue*);
36
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080037// TODO: get global references for these
38Class* AbstractMethod::java_lang_reflect_Constructor_ = NULL;
39Class* AbstractMethod::java_lang_reflect_Method_ = NULL;
40
41InvokeType AbstractMethod::GetInvokeType() const {
42 // TODO: kSuper?
43 if (GetDeclaringClass()->IsInterface()) {
44 return kInterface;
45 } else if (IsStatic()) {
46 return kStatic;
47 } else if (IsDirect()) {
48 return kDirect;
49 } else {
50 return kVirtual;
51 }
52}
53
54void AbstractMethod::SetClasses(Class* java_lang_reflect_Constructor, Class* java_lang_reflect_Method) {
55 CHECK(java_lang_reflect_Constructor_ == NULL);
56 CHECK(java_lang_reflect_Constructor != NULL);
57 java_lang_reflect_Constructor_ = java_lang_reflect_Constructor;
58
59 CHECK(java_lang_reflect_Method_ == NULL);
60 CHECK(java_lang_reflect_Method != NULL);
61 java_lang_reflect_Method_ = java_lang_reflect_Method;
62}
63
64void AbstractMethod::ResetClasses() {
65 CHECK(java_lang_reflect_Constructor_ != NULL);
66 java_lang_reflect_Constructor_ = NULL;
67
68 CHECK(java_lang_reflect_Method_ != NULL);
69 java_lang_reflect_Method_ = NULL;
70}
71
72ObjectArray<String>* AbstractMethod::GetDexCacheStrings() const {
73 return GetFieldObject<ObjectArray<String>*>(
74 OFFSET_OF_OBJECT_MEMBER(AbstractMethod, dex_cache_strings_), false);
75}
76
77void AbstractMethod::SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) {
78 SetFieldObject(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, dex_cache_strings_),
79 new_dex_cache_strings, false);
80}
81
82ObjectArray<AbstractMethod>* AbstractMethod::GetDexCacheResolvedMethods() const {
83 return GetFieldObject<ObjectArray<AbstractMethod>*>(
84 OFFSET_OF_OBJECT_MEMBER(AbstractMethod, dex_cache_resolved_methods_), false);
85}
86
87void AbstractMethod::SetDexCacheResolvedMethods(ObjectArray<AbstractMethod>* new_dex_cache_methods) {
88 SetFieldObject(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, dex_cache_resolved_methods_),
89 new_dex_cache_methods, false);
90}
91
92ObjectArray<Class>* AbstractMethod::GetDexCacheResolvedTypes() const {
93 return GetFieldObject<ObjectArray<Class>*>(
94 OFFSET_OF_OBJECT_MEMBER(AbstractMethod, dex_cache_resolved_types_), false);
95}
96
97void AbstractMethod::SetDexCacheResolvedTypes(ObjectArray<Class>* new_dex_cache_classes) {
98 SetFieldObject(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, dex_cache_resolved_types_),
99 new_dex_cache_classes, false);
100}
101
102ObjectArray<StaticStorageBase>* AbstractMethod::GetDexCacheInitializedStaticStorage() const {
103 return GetFieldObject<ObjectArray<StaticStorageBase>*>(
104 OFFSET_OF_OBJECT_MEMBER(AbstractMethod, dex_cache_initialized_static_storage_),
105 false);
106}
107
108void AbstractMethod::SetDexCacheInitializedStaticStorage(ObjectArray<StaticStorageBase>* new_value) {
109 SetFieldObject(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, dex_cache_initialized_static_storage_),
110 new_value, false);
111}
112
113size_t AbstractMethod::NumArgRegisters(const StringPiece& shorty) {
114 CHECK_LE(1, shorty.length());
115 uint32_t num_registers = 0;
116 for (int i = 1; i < shorty.length(); ++i) {
117 char ch = shorty[i];
118 if (ch == 'D' || ch == 'J') {
119 num_registers += 2;
120 } else {
121 num_registers += 1;
122 }
123 }
124 return num_registers;
125}
126
127bool AbstractMethod::IsProxyMethod() const {
128 return GetDeclaringClass()->IsProxyClass();
129}
130
131AbstractMethod* AbstractMethod::FindOverriddenMethod() const {
132 if (IsStatic()) {
133 return NULL;
134 }
135 Class* declaring_class = GetDeclaringClass();
136 Class* super_class = declaring_class->GetSuperClass();
137 uint16_t method_index = GetMethodIndex();
138 ObjectArray<AbstractMethod>* super_class_vtable = super_class->GetVTable();
139 AbstractMethod* result = NULL;
140 // Did this method override a super class method? If so load the result from the super class'
141 // vtable
142 if (super_class_vtable != NULL && method_index < super_class_vtable->GetLength()) {
143 result = super_class_vtable->Get(method_index);
144 } else {
145 // Method didn't override superclass method so search interfaces
146 if (IsProxyMethod()) {
147 result = GetDexCacheResolvedMethods()->Get(GetDexMethodIndex());
148 CHECK_EQ(result,
149 Runtime::Current()->GetClassLinker()->FindMethodForProxy(GetDeclaringClass(), this));
150 } else {
151 MethodHelper mh(this);
152 MethodHelper interface_mh;
153 IfTable* iftable = GetDeclaringClass()->GetIfTable();
154 for (size_t i = 0; i < iftable->Count() && result == NULL; i++) {
155 Class* interface = iftable->GetInterface(i);
156 for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
157 AbstractMethod* interface_method = interface->GetVirtualMethod(j);
158 interface_mh.ChangeMethod(interface_method);
159 if (mh.HasSameNameAndSignature(&interface_mh)) {
160 result = interface_method;
161 break;
162 }
163 }
164 }
165 }
166 }
167#ifndef NDEBUG
168 MethodHelper result_mh(result);
169 DCHECK(result == NULL || MethodHelper(this).HasSameNameAndSignature(&result_mh));
170#endif
171 return result;
172}
173
174static const void* GetOatCode(const AbstractMethod* m)
175 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
176 Runtime* runtime = Runtime::Current();
177 const void* code = m->GetCode();
178 // Peel off any method tracing trampoline.
179 if (runtime->IsMethodTracingActive() && runtime->GetInstrumentation()->GetSavedCodeFromMap(m) != NULL) {
180 code = runtime->GetInstrumentation()->GetSavedCodeFromMap(m);
181 }
182 // Peel off any resolution stub.
183 if (code == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData()) {
184 code = runtime->GetClassLinker()->GetOatCodeFor(m);
185 }
186 return code;
187}
188
189uintptr_t AbstractMethod::NativePcOffset(const uintptr_t pc) const {
190 return pc - reinterpret_cast<uintptr_t>(GetOatCode(this));
191}
192
193// Find the lowest-address native safepoint pc for a given dex pc
194uintptr_t AbstractMethod::ToFirstNativeSafepointPc(const uint32_t dex_pc) const {
Ian Rogersc928de92013-02-27 14:30:44 -0800195#if !defined(ART_USE_PORTABLE_COMPILER)
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800196 const uint32_t* mapping_table = GetPcToDexMappingTable();
197 if (mapping_table == NULL) {
198 DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this);
199 return DexFile::kDexNoIndex; // Special no mapping case
200 }
201 size_t mapping_table_length = GetPcToDexMappingTableLength();
202 for (size_t i = 0; i < mapping_table_length; i += 2) {
203 if (mapping_table[i + 1] == dex_pc) {
204 return mapping_table[i] + reinterpret_cast<uintptr_t>(GetOatCode(this));
205 }
206 }
207 LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc
208 << " in " << PrettyMethod(this);
209 return 0;
210#else
211 // Compiler LLVM doesn't use the machine pc, we just use dex pc instead.
212 return static_cast<uint32_t>(dex_pc);
213#endif
214}
215
216uint32_t AbstractMethod::ToDexPc(const uintptr_t pc) const {
Ian Rogersc928de92013-02-27 14:30:44 -0800217#if !defined(ART_USE_PORTABLE_COMPILER)
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800218 const uint32_t* mapping_table = GetPcToDexMappingTable();
219 if (mapping_table == NULL) {
220 DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this);
221 return DexFile::kDexNoIndex; // Special no mapping case
222 }
223 size_t mapping_table_length = GetPcToDexMappingTableLength();
224 uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(GetOatCode(this));
225 for (size_t i = 0; i < mapping_table_length; i += 2) {
226 if (mapping_table[i] == sought_offset) {
227 return mapping_table[i + 1];
228 }
229 }
230 LOG(ERROR) << "Failed to find Dex offset for PC offset " << reinterpret_cast<void*>(sought_offset)
231 << "(PC " << reinterpret_cast<void*>(pc) << ") in " << PrettyMethod(this);
232 return DexFile::kDexNoIndex;
233#else
234 // Compiler LLVM doesn't use the machine pc, we just use dex pc instead.
235 return static_cast<uint32_t>(pc);
236#endif
237}
238
239uintptr_t AbstractMethod::ToNativePc(const uint32_t dex_pc) const {
240 const uint32_t* mapping_table = GetDexToPcMappingTable();
241 if (mapping_table == NULL) {
242 DCHECK_EQ(dex_pc, 0U);
243 return 0; // Special no mapping/pc == 0 case
244 }
245 size_t mapping_table_length = GetDexToPcMappingTableLength();
246 for (size_t i = 0; i < mapping_table_length; i += 2) {
247 uint32_t map_offset = mapping_table[i];
248 uint32_t map_dex_offset = mapping_table[i + 1];
249 if (map_dex_offset == dex_pc) {
250 return reinterpret_cast<uintptr_t>(GetOatCode(this)) + map_offset;
251 }
252 }
253 LOG(FATAL) << "Looking up Dex PC not contained in method, 0x" << std::hex << dex_pc
254 << " in " << PrettyMethod(this);
255 return 0;
256}
257
258uint32_t AbstractMethod::FindCatchBlock(Class* exception_type, uint32_t dex_pc) const {
259 MethodHelper mh(this);
260 const DexFile::CodeItem* code_item = mh.GetCodeItem();
261 // Iterate over the catch handlers associated with dex_pc
262 for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) {
263 uint16_t iter_type_idx = it.GetHandlerTypeIndex();
264 // Catch all case
265 if (iter_type_idx == DexFile::kDexNoIndex16) {
266 return it.GetHandlerAddress();
267 }
268 // Does this catch exception type apply?
269 Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx);
270 if (iter_exception_type == NULL) {
271 // The verifier should take care of resolving all exception classes early
272 LOG(WARNING) << "Unresolved exception class when finding catch block: "
273 << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx);
274 } else if (iter_exception_type->IsAssignableFrom(exception_type)) {
275 return it.GetHandlerAddress();
276 }
277 }
278 // Handler not found
279 return DexFile::kDexNoIndex;
280}
281
Jeff Hao5d917302013-02-27 17:57:33 -0800282void AbstractMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
283 JValue* float_result) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800284 if (kIsDebugBuild) {
285 self->AssertThreadSuspensionIsAllowable();
286 CHECK_EQ(kRunnable, self->GetState());
287 }
288
289 // Push a transition back into managed code onto the linked list in thread.
290 ManagedStack fragment;
291 self->PushManagedStackFragment(&fragment);
292
293 // Call the invoke stub associated with the method.
294 // Pass everything as arguments.
295 AbstractMethod::InvokeStub* stub = GetInvokeStub();
296
297 if (UNLIKELY(!Runtime::Current()->IsStarted())){
298 LOG(INFO) << "Not invoking " << PrettyMethod(this) << " for a runtime that isn't started";
299 if (result != NULL) {
300 result->SetJ(0);
Jeff Hao5d917302013-02-27 17:57:33 -0800301 float_result->SetJ(0);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800302 }
303 } else {
304 bool interpret = self->ReadFlag(kEnterInterpreter) && !IsNative() && !IsProxyMethod();
305 const bool kLogInvocationStartAndReturn = false;
Jeff Hao5d917302013-02-27 17:57:33 -0800306 if (GetCode() != NULL) {
307 if (!interpret) {
308 if (kLogInvocationStartAndReturn) {
309 LOG(INFO) << StringPrintf("Invoking '%s' code=%p stub=%p",
310 PrettyMethod(this).c_str(), GetCode(), stub);
311 }
312 // TODO: Temporary to keep portable working while stubs are removed from quick.
313#ifdef ART_USE_PORTABLE_COMPILER
314 MethodHelper mh(this);
315 const char* shorty = mh.GetShorty();
316 uint32_t shorty_len = mh.GetShortyLength();
317 UniquePtr<JValue[]> jvalue_args(new JValue[shorty_len - 1]);
318 Object* receiver = NULL;
319 uint32_t* ptr = args;
320 if (!this->IsStatic()) {
321 receiver = reinterpret_cast<Object*>(*ptr);
322 ptr++;
323 }
324 for (uint32_t i = 1; i < shorty_len; i++) {
325 if ((shorty[i] == 'J') || (shorty[i] == 'D')) {
326 jvalue_args[i - 1].SetJ(*((uint64_t*)ptr));
327 ptr++;
328 } else {
329 jvalue_args[i - 1].SetI(*ptr);
330 }
331 ptr++;
332 }
333 if (mh.IsReturnFloatOrDouble()) {
334 (*stub)(this, receiver, self, jvalue_args.get(), float_result);
335 } else {
336 (*stub)(this, receiver, self, jvalue_args.get(), result);
337 }
338#else
339 (*art_quick_invoke_stub)(this, args, args_size, self, result, float_result);
340#endif
341 if (UNLIKELY(reinterpret_cast<int32_t>(self->GetException()) == -1)) {
342 // Unusual case where we were running LLVM generated code and an
343 // exception was thrown to force the activations to be removed from the
344 // stack. Continue execution in the interpreter.
345 JValue value;
346 self->ClearException();
347 ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(&value);
348 self->SetTopOfShadowStack(shadow_frame);
349 interpreter::EnterInterpreterFromLLVM(self, shadow_frame, result);
350 }
351 if (kLogInvocationStartAndReturn) {
352 LOG(INFO) << StringPrintf("Returned '%s' code=%p stub=%p",
353 PrettyMethod(this).c_str(), GetCode(), stub);
354 }
355 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800356 if (kLogInvocationStartAndReturn) {
357 LOG(INFO) << "Interpreting " << PrettyMethod(this) << "'";
358 }
Jeff Hao5d917302013-02-27 17:57:33 -0800359 if (this->IsStatic()) {
360 art::interpreter::EnterInterpreterFromInvoke(self, this, NULL, args,
361 result, float_result);
362 } else {
363 Object* receiver = reinterpret_cast<Object*>(args[0]);
364 art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args + 1,
365 result, float_result);
366 }
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800367 if (kLogInvocationStartAndReturn) {
368 LOG(INFO) << "Returned '" << PrettyMethod(this) << "'";
369 }
Jeff Hao5d917302013-02-27 17:57:33 -0800370 }
371 } else {
372 LOG(INFO) << "Not invoking '" << PrettyMethod(this)
373 << "' code=" << reinterpret_cast<const void*>(GetCode())
374 << " stub=" << reinterpret_cast<void*>(stub);
375 if (result != NULL) {
376 result->SetJ(0);
377 float_result->SetJ(0);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800378 }
379 }
380 }
381
382 // Pop transition.
383 self->PopManagedStackFragment(fragment);
384}
385
386bool AbstractMethod::IsRegistered() const {
387 void* native_method = GetFieldPtr<void*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, native_method_), false);
388 CHECK(native_method != NULL);
389 void* jni_stub = Runtime::Current()->GetJniDlsymLookupStub()->GetData();
390 return native_method != jni_stub;
391}
392
393void AbstractMethod::RegisterNative(Thread* self, const void* native_method) {
394 DCHECK(Thread::Current() == self);
395 CHECK(IsNative()) << PrettyMethod(this);
396 CHECK(native_method != NULL) << PrettyMethod(this);
397 if (!self->GetJniEnv()->vm->work_around_app_jni_bugs) {
398 SetNativeMethod(native_method);
399 } else {
400 // We've been asked to associate this method with the given native method but are working
401 // around JNI bugs, that include not giving Object** SIRT references to native methods. Direct
402 // the native method to runtime support and store the target somewhere runtime support will
403 // find it.
Ian Rogersc928de92013-02-27 14:30:44 -0800404#if defined(__arm__) && !defined(ART_USE_PORTABLE_COMPILER)
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800405 SetNativeMethod(native_method);
406#else
407 UNIMPLEMENTED(FATAL);
408#endif
409 SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, native_gc_map_),
410 reinterpret_cast<const uint8_t*>(native_method), false);
411 }
412}
413
414void AbstractMethod::UnregisterNative(Thread* self) {
415 CHECK(IsNative()) << PrettyMethod(this);
416 // restore stub to lookup native pointer via dlsym
417 RegisterNative(self, Runtime::Current()->GetJniDlsymLookupStub()->GetData());
418}
419
420void AbstractMethod::SetNativeMethod(const void* native_method) {
421 SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, native_method_),
422 native_method, false);
423}
424
425} // namespace mirror
426} // namespace art