Elliott Hughes | 0f3c553 | 2012-03-30 14:51:51 -0700 | [diff] [blame] | 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 | */ |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 16 | |
| 17 | #include "class_linker.h" |
| 18 | #include "dex_verifier.h" |
| 19 | #include "object.h" |
| 20 | #include "object_utils.h" |
Shih-wei Liao | b1ab7df | 2012-03-29 13:53:46 -0700 | [diff] [blame] | 21 | #include "runtime_support.h" |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 22 | #include "runtime_support_llvm.h" |
Logan Chien | f7ad17e | 2012-03-15 03:10:03 +0800 | [diff] [blame] | 23 | #include "shadow_frame.h" |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 24 | #include "thread.h" |
Shih-wei Liao | 66adbb7 | 2012-03-07 01:31:50 -0800 | [diff] [blame] | 25 | #include "thread_list.h" |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 26 | |
Logan Chien | d23c5ad | 2012-03-30 17:46:04 +0800 | [diff] [blame] | 27 | #include <algorithm> |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 28 | #include <stdint.h> |
| 29 | |
| 30 | namespace art { |
| 31 | |
| 32 | //---------------------------------------------------------------------------- |
| 33 | // Thread |
| 34 | //---------------------------------------------------------------------------- |
| 35 | |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 36 | Thread* art_get_current_thread_from_code() { |
| 37 | return Thread::Current(); |
| 38 | } |
| 39 | |
| 40 | void art_set_current_thread_from_code(void* thread_object_addr) { |
Shih-wei Liao | 66adbb7 | 2012-03-07 01:31:50 -0800 | [diff] [blame] | 41 | // TODO: LLVM IR generating something like "r9 = thread_object_addr" |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 42 | UNIMPLEMENTED(WARNING); |
| 43 | } |
| 44 | |
Shih-wei Liao | 66adbb7 | 2012-03-07 01:31:50 -0800 | [diff] [blame] | 45 | void art_lock_object_from_code(Object* obj) { |
| 46 | Thread* thread = Thread::Current(); |
| 47 | DCHECK(obj != NULL); // Assumed to have been checked before entry |
| 48 | obj->MonitorEnter(thread); // May block |
| 49 | DCHECK(thread->HoldsLock(obj)); |
| 50 | // Only possible exception is NPE and is handled before entry |
| 51 | DCHECK(!thread->IsExceptionPending()); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 52 | } |
| 53 | |
Shih-wei Liao | 66adbb7 | 2012-03-07 01:31:50 -0800 | [diff] [blame] | 54 | void art_unlock_object_from_code(Object* obj) { |
| 55 | Thread* thread = Thread::Current(); |
| 56 | DCHECK(obj != NULL); // Assumed to have been checked before entry |
| 57 | // MonitorExit may throw exception |
| 58 | obj->MonitorExit(thread); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 59 | } |
| 60 | |
| 61 | void art_test_suspend_from_code() { |
Shih-wei Liao | 66adbb7 | 2012-03-07 01:31:50 -0800 | [diff] [blame] | 62 | Thread* thread = Thread::Current(); |
| 63 | Runtime::Current()->GetThreadList()->FullSuspendCheck(thread); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 64 | } |
| 65 | |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 66 | void art_push_shadow_frame_from_code(void* new_shadow_frame) { |
| 67 | Thread* thread = Thread::Current(); |
Logan Chien | f7ad17e | 2012-03-15 03:10:03 +0800 | [diff] [blame] | 68 | thread->PushShadowFrame(static_cast<ShadowFrame*>(new_shadow_frame)); |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | void art_pop_shadow_frame_from_code() { |
| 72 | Thread* thread = Thread::Current(); |
Logan Chien | f7ad17e | 2012-03-15 03:10:03 +0800 | [diff] [blame] | 73 | thread->PopShadowFrame(); |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 74 | } |
| 75 | |
| 76 | |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 77 | |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 78 | //---------------------------------------------------------------------------- |
| 79 | // Exception |
| 80 | //---------------------------------------------------------------------------- |
| 81 | |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 82 | bool art_is_exception_pending_from_code() { |
| 83 | return Thread::Current()->IsExceptionPending(); |
| 84 | } |
| 85 | |
| 86 | void art_throw_div_zero_from_code() { |
| 87 | Thread* thread = Thread::Current(); |
| 88 | thread->ThrowNewException("Ljava/lang/ArithmeticException;", |
| 89 | "divide by zero"); |
| 90 | } |
| 91 | |
| 92 | void art_throw_array_bounds_from_code(int32_t length, int32_t index) { |
| 93 | Thread* thread = Thread::Current(); |
| 94 | thread->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;", |
| 95 | "length=%d; index=%d", length, index); |
| 96 | } |
| 97 | |
| 98 | void art_throw_no_such_method_from_code(int32_t method_idx) { |
| 99 | Thread* thread = Thread::Current(); |
| 100 | // We need the calling method as context for the method_idx |
| 101 | Frame frame = thread->GetTopOfStack(); |
| 102 | frame.Next(); |
| 103 | Method* method = frame.GetMethod(); |
| 104 | thread->ThrowNewException("Ljava/lang/NoSuchMethodError;", |
| 105 | MethodNameFromIndex(method, |
| 106 | method_idx, |
| 107 | verifier::VERIFY_ERROR_REF_METHOD, |
| 108 | false).c_str()); |
| 109 | } |
| 110 | |
| 111 | void art_throw_null_pointer_exception_from_code() { |
| 112 | Thread* thread = Thread::Current(); |
| 113 | thread->ThrowNewException("Ljava/lang/NullPointerException;", NULL); |
| 114 | } |
| 115 | |
| 116 | void art_throw_stack_overflow_from_code(void*) { |
| 117 | Thread* thread = Thread::Current(); |
| 118 | thread->ThrowNewExceptionF("Ljava/lang/StackOverflowError;", |
| 119 | "stack size %zdkb; default stack size: %zdkb", |
| 120 | thread->GetStackSize() / KB, |
| 121 | Runtime::Current()->GetDefaultStackSize() / KB); |
| 122 | } |
| 123 | |
| 124 | void art_throw_exception_from_code(Object* exception) { |
| 125 | Thread* thread = Thread::Current(); |
| 126 | thread->SetException(static_cast<Throwable*>(exception)); |
| 127 | } |
| 128 | |
TDYa127 | 2d70217 | 2012-04-01 15:15:13 -0700 | [diff] [blame] | 129 | int32_t art_find_catch_block_from_code(Method* current_method, int32_t dex_pc) { |
| 130 | Thread* thread = Thread::Current(); |
| 131 | Class* exception_type = thread->GetException()->GetClass(); |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 132 | MethodHelper mh(current_method); |
| 133 | const DexFile::CodeItem* code_item = mh.GetCodeItem(); |
| 134 | int iter_index = 0; |
| 135 | // Iterate over the catch handlers associated with dex_pc |
| 136 | for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) { |
| 137 | uint16_t iter_type_idx = it.GetHandlerTypeIndex(); |
| 138 | // Catch all case |
| 139 | if (iter_type_idx == DexFile::kDexNoIndex16) { |
| 140 | return iter_index; |
| 141 | } |
| 142 | // Does this catch exception type apply? |
| 143 | Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx); |
| 144 | if (iter_exception_type == NULL) { |
| 145 | // The verifier should take care of resolving all exception classes early |
| 146 | LOG(WARNING) << "Unresolved exception class when finding catch block: " |
| 147 | << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx); |
| 148 | } else if (iter_exception_type->IsAssignableFrom(exception_type)) { |
| 149 | return iter_index; |
| 150 | } |
| 151 | ++iter_index; |
| 152 | } |
| 153 | // Handler not found |
| 154 | return -1; |
| 155 | } |
| 156 | |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 157 | |
| 158 | //---------------------------------------------------------------------------- |
| 159 | // Object Space |
| 160 | //---------------------------------------------------------------------------- |
| 161 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 162 | Object* art_alloc_object_from_code(uint32_t type_idx, Method* referrer) { |
| 163 | return AllocObjectFromCode(type_idx, referrer, Thread::Current(), false); |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 164 | } |
| 165 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 166 | Object* art_alloc_object_from_code_with_access_check(uint32_t type_idx, Method* referrer) { |
| 167 | return AllocObjectFromCode(type_idx, referrer, Thread::Current(), true); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 168 | } |
| 169 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 170 | Object* art_alloc_array_from_code(uint32_t type_idx, Method* referrer, uint32_t length) { |
| 171 | return AllocArrayFromCode(type_idx, referrer, length, Thread::Current(), false); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 172 | } |
| 173 | |
| 174 | Object* art_alloc_array_from_code_with_access_check(uint32_t type_idx, |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 175 | Method* referrer, |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 176 | uint32_t length) { |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 177 | return AllocArrayFromCode(type_idx, referrer, length, Thread::Current(), true); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | Object* art_check_and_alloc_array_from_code(uint32_t type_idx, |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 181 | Method* referrer, |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 182 | uint32_t length) { |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 183 | return CheckAndAllocArrayFromCode(type_idx, referrer, length, Thread::Current(), false); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 184 | } |
| 185 | |
| 186 | Object* art_check_and_alloc_array_from_code_with_access_check(uint32_t type_idx, |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 187 | Method* referrer, |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 188 | uint32_t length) { |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 189 | return CheckAndAllocArrayFromCode(type_idx, referrer, length, Thread::Current(), true); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 190 | } |
| 191 | |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 192 | static Method* FindMethodHelper(uint32_t method_idx, Object* this_object, Method* caller_method, |
Elliott Hughes | b25c3f6 | 2012-03-26 16:35:06 -0700 | [diff] [blame] | 193 | bool access_check, InvokeType type) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 194 | Method* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type); |
| 195 | if (UNLIKELY(method == NULL)) { |
| 196 | method = FindMethodFromCode(method_idx, this_object, caller_method, |
| 197 | Thread::Current(), access_check, type); |
| 198 | if (UNLIKELY(method == NULL)) { |
| 199 | CHECK(Thread::Current()->IsExceptionPending()); |
| 200 | return 0; // failure |
| 201 | } |
| 202 | } |
| 203 | DCHECK(!Thread::Current()->IsExceptionPending()); |
| 204 | return method; |
| 205 | } |
| 206 | |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 207 | Object* art_find_interface_method_from_code(uint32_t method_idx, |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 208 | Object* this_object, |
| 209 | Method* referrer) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 210 | return FindMethodHelper(method_idx, this_object, referrer, true, kInterface); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 211 | } |
| 212 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 213 | Object* art_find_virtual_method_from_code(uint32_t method_idx, |
| 214 | Object* this_object, |
| 215 | Method* referrer) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 216 | return FindMethodHelper(method_idx, this_object, referrer, true, kVirtual); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 217 | } |
| 218 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 219 | Object* art_find_super_method_from_code(uint32_t method_idx, |
| 220 | Object* this_object, |
| 221 | Method* referrer) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 222 | return FindMethodHelper(method_idx, this_object, referrer, true, kSuper); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 223 | } |
| 224 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 225 | Object* art_initialize_static_storage_from_code(uint32_t type_idx, Method* referrer) { |
| 226 | return ResolveVerifyAndClinit(type_idx, referrer, Thread::Current(), true, true); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 227 | } |
| 228 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 229 | Object* art_initialize_type_from_code(uint32_t type_idx, Method* referrer) { |
| 230 | return ResolveVerifyAndClinit(type_idx, referrer, Thread::Current(), false, false); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 231 | } |
| 232 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 233 | Object* art_initialize_type_and_verify_access_from_code(uint32_t type_idx, Method* referrer) { |
| 234 | // Called when caller isn't guaranteed to have access to a type and the dex cache may be |
| 235 | // unpopulated |
| 236 | return ResolveVerifyAndClinit(type_idx, referrer, Thread::Current(), false, true); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 237 | } |
| 238 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 239 | Object* art_resolve_string_from_code(Method* referrer, uint32_t string_idx) { |
| 240 | return ResolveStringFromCode(referrer, string_idx); |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 241 | } |
| 242 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 243 | int32_t art_set32_static_from_code(uint32_t field_idx, Method* referrer, int32_t new_value) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 244 | Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(uint32_t)); |
| 245 | if (LIKELY(field != NULL)) { |
| 246 | field->Set32(NULL, new_value); |
| 247 | return 0; |
| 248 | } |
| 249 | field = FindFieldFromCode(field_idx, referrer, Thread::Current(), |
| 250 | true, true, true, sizeof(uint32_t)); |
| 251 | if (LIKELY(field != NULL)) { |
| 252 | field->Set32(NULL, new_value); |
| 253 | return 0; |
| 254 | } |
| 255 | return -1; |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 256 | } |
| 257 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 258 | int32_t art_set64_static_from_code(uint32_t field_idx, Method* referrer, int64_t new_value) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 259 | Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(uint64_t)); |
| 260 | if (LIKELY(field != NULL)) { |
| 261 | field->Set64(NULL, new_value); |
| 262 | return 0; |
| 263 | } |
| 264 | field = FindFieldFromCode(field_idx, referrer, Thread::Current(), |
| 265 | true, true, true, sizeof(uint64_t)); |
| 266 | if (LIKELY(field != NULL)) { |
| 267 | field->Set64(NULL, new_value); |
| 268 | return 0; |
| 269 | } |
| 270 | return -1; |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 271 | } |
| 272 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 273 | int32_t art_set_obj_static_from_code(uint32_t field_idx, Method* referrer, Object* new_value) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 274 | Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*)); |
| 275 | if (LIKELY(field != NULL)) { |
| 276 | field->SetObj(NULL, new_value); |
| 277 | return 0; |
| 278 | } |
| 279 | field = FindFieldFromCode(field_idx, referrer, Thread::Current(), |
| 280 | true, false, true, sizeof(Object*)); |
| 281 | if (LIKELY(field != NULL)) { |
| 282 | field->SetObj(NULL, new_value); |
| 283 | return 0; |
| 284 | } |
| 285 | return -1; |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 286 | } |
| 287 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 288 | int32_t art_get32_static_from_code(uint32_t field_idx, Method* referrer) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 289 | Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(uint32_t)); |
| 290 | if (LIKELY(field != NULL)) { |
| 291 | return field->Get32(NULL); |
| 292 | } |
| 293 | field = FindFieldFromCode(field_idx, referrer, Thread::Current(), |
| 294 | true, true, false, sizeof(uint32_t)); |
| 295 | if (LIKELY(field != NULL)) { |
| 296 | return field->Get32(NULL); |
| 297 | } |
| 298 | return 0; |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 299 | } |
| 300 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 301 | int64_t art_get64_static_from_code(uint32_t field_idx, Method* referrer) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 302 | Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(uint64_t)); |
| 303 | if (LIKELY(field != NULL)) { |
| 304 | return field->Get64(NULL); |
| 305 | } |
| 306 | field = FindFieldFromCode(field_idx, referrer, Thread::Current(), |
| 307 | true, true, false, sizeof(uint64_t)); |
| 308 | if (LIKELY(field != NULL)) { |
| 309 | return field->Get64(NULL); |
| 310 | } |
| 311 | return 0; |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 312 | } |
| 313 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 314 | Object* art_get_obj_static_from_code(uint32_t field_idx, Method* referrer) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 315 | Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*)); |
| 316 | if (LIKELY(field != NULL)) { |
| 317 | return field->GetObj(NULL); |
| 318 | } |
| 319 | field = FindFieldFromCode(field_idx, referrer, Thread::Current(), |
| 320 | true, false, false, sizeof(Object*)); |
| 321 | if (LIKELY(field != NULL)) { |
| 322 | return field->GetObj(NULL); |
| 323 | } |
| 324 | return 0; |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 325 | } |
| 326 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 327 | int32_t art_set32_instance_from_code(uint32_t field_idx, Method* referrer, |
| 328 | Object* obj, uint32_t new_value) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 329 | Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(uint32_t)); |
| 330 | if (LIKELY(field != NULL)) { |
| 331 | field->Set32(obj, new_value); |
| 332 | return 0; |
| 333 | } |
| 334 | field = FindFieldFromCode(field_idx, referrer, Thread::Current(), |
| 335 | false, true, true, sizeof(uint32_t)); |
| 336 | if (LIKELY(field != NULL)) { |
| 337 | field->Set32(obj, new_value); |
| 338 | return 0; |
| 339 | } |
| 340 | return -1; |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 341 | } |
| 342 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 343 | int32_t art_set64_instance_from_code(uint32_t field_idx, Method* referrer, |
| 344 | Object* obj, int64_t new_value) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 345 | Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(uint64_t)); |
| 346 | if (LIKELY(field != NULL)) { |
| 347 | field->Set64(obj, new_value); |
| 348 | return 0; |
| 349 | } |
| 350 | field = FindFieldFromCode(field_idx, referrer, Thread::Current(), |
| 351 | false, true, true, sizeof(uint64_t)); |
| 352 | if (LIKELY(field != NULL)) { |
| 353 | field->Set64(obj, new_value); |
| 354 | return 0; |
| 355 | } |
| 356 | return -1; |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 357 | } |
| 358 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 359 | int32_t art_set_obj_instance_from_code(uint32_t field_idx, Method* referrer, |
| 360 | Object* obj, Object* new_value) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 361 | Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*)); |
| 362 | if (LIKELY(field != NULL)) { |
| 363 | field->SetObj(obj, new_value); |
| 364 | return 0; |
| 365 | } |
| 366 | field = FindFieldFromCode(field_idx, referrer, Thread::Current(), |
| 367 | false, false, true, sizeof(Object*)); |
| 368 | if (LIKELY(field != NULL)) { |
| 369 | field->SetObj(obj, new_value); |
| 370 | return 0; |
| 371 | } |
| 372 | return -1; |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 373 | } |
| 374 | |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 375 | int32_t art_get32_instance_from_code(uint32_t field_idx, Method* referrer, Object* obj) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 376 | Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(uint32_t)); |
| 377 | if (LIKELY(field != NULL)) { |
| 378 | return field->Get32(obj); |
| 379 | } |
| 380 | field = FindFieldFromCode(field_idx, referrer, Thread::Current(), |
| 381 | false, true, false, sizeof(uint32_t)); |
| 382 | if (LIKELY(field != NULL)) { |
| 383 | return field->Get32(obj); |
| 384 | } |
| 385 | return 0; |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 386 | } |
| 387 | |
| 388 | int64_t art_get64_instance_from_code(uint32_t field_idx, Method* referrer, Object* obj) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 389 | Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(uint64_t)); |
| 390 | if (LIKELY(field != NULL)) { |
| 391 | return field->Get64(obj); |
| 392 | } |
| 393 | field = FindFieldFromCode(field_idx, referrer, Thread::Current(), |
| 394 | false, true, false, sizeof(uint64_t)); |
| 395 | if (LIKELY(field != NULL)) { |
| 396 | return field->Get64(obj); |
| 397 | } |
| 398 | return 0; |
Shih-wei Liao | 399ed3f | 2012-03-08 01:27:04 -0800 | [diff] [blame] | 399 | } |
| 400 | |
| 401 | Object* art_get_obj_instance_from_code(uint32_t field_idx, Method* referrer, Object* obj) { |
Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 402 | Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*)); |
| 403 | if (LIKELY(field != NULL)) { |
| 404 | return field->GetObj(obj); |
| 405 | } |
| 406 | field = FindFieldFromCode(field_idx, referrer, Thread::Current(), |
| 407 | false, false, false, sizeof(Object*)); |
| 408 | if (LIKELY(field != NULL)) { |
| 409 | return field->GetObj(obj); |
| 410 | } |
| 411 | return 0; |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 412 | } |
| 413 | |
TDYa127 | 28f1a14 | 2012-03-15 21:51:52 -0700 | [diff] [blame] | 414 | Object* art_decode_jobject_in_thread(Thread* thread, jobject obj) { |
| 415 | if (thread->IsExceptionPending()) { |
| 416 | return NULL; |
| 417 | } |
| 418 | return thread->DecodeJObject(obj); |
| 419 | } |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 420 | |
| 421 | //---------------------------------------------------------------------------- |
Shih-wei Liao | 9e0e54d | 2012-04-02 19:22:28 -0700 | [diff] [blame] | 422 | // Type checking, in the nature of casting |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 423 | //---------------------------------------------------------------------------- |
| 424 | |
TDYa127 | 3de5ba3 | 2012-04-02 07:04:40 -0700 | [diff] [blame] | 425 | int32_t art_is_assignable_from_code(const Class* dest_type, const Class* src_type) { |
| 426 | DCHECK(dest_type != NULL); |
| 427 | DCHECK(src_type != NULL); |
| 428 | return dest_type->IsAssignableFrom(src_type) ? 1 : 0; |
Logan Chien | fc5bc67 | 2012-03-06 16:54:30 +0800 | [diff] [blame] | 429 | } |
| 430 | |
TDYa127 | 3de5ba3 | 2012-04-02 07:04:40 -0700 | [diff] [blame] | 431 | void art_check_cast_from_code(const Class* dest_type, const Class* src_type) { |
Shih-wei Liao | 9e0e54d | 2012-04-02 19:22:28 -0700 | [diff] [blame] | 432 | DCHECK(dest_type->IsClass()) << PrettyClass(dest_type); |
TDYa127 | 3de5ba3 | 2012-04-02 07:04:40 -0700 | [diff] [blame] | 433 | DCHECK(src_type->IsClass()) << PrettyClass(src_type); |
| 434 | if (UNLIKELY(!dest_type->IsAssignableFrom(src_type))) { |
| 435 | Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassCastException;", |
| 436 | "%s cannot be cast to %s", |
| 437 | PrettyDescriptor(dest_type).c_str(), |
| 438 | PrettyDescriptor(src_type).c_str()); |
| 439 | } |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 440 | } |
| 441 | |
Logan Chien | 2771fb1 | 2012-03-06 16:28:35 +0800 | [diff] [blame] | 442 | //---------------------------------------------------------------------------- |
| 443 | // Runtime Support Function Lookup Callback |
| 444 | //---------------------------------------------------------------------------- |
| 445 | |
Logan Chien | d23c5ad | 2012-03-30 17:46:04 +0800 | [diff] [blame] | 446 | class CStringComparator { |
| 447 | public: |
| 448 | bool operator()(const char* lhs, const char* rhs) const { |
| 449 | return (strcmp(lhs, rhs) <= 0); |
| 450 | } |
| 451 | }; |
| 452 | |
| 453 | #define EXTERNAL_LINKAGE(NAME) \ |
| 454 | extern "C" void NAME(...); |
| 455 | |
| 456 | #include "compiler_runtime_func_list.h" |
| 457 | COMPILER_RUNTIME_FUNC_LIST(EXTERNAL_LINKAGE) |
| 458 | #undef COMPILER_RUNTIME_FUNC_LIST |
| 459 | #undef EXTERNAL_LINKAGE |
| 460 | |
| 461 | static void* art_find_compiler_runtime_func(char const* name) { |
| 462 | static const char* const names[] = { |
| 463 | #define DEFINE_ENTRY(NAME) #NAME , |
| 464 | #include "compiler_runtime_func_list.h" |
| 465 | COMPILER_RUNTIME_FUNC_LIST(DEFINE_ENTRY) |
| 466 | #undef COMPILER_RUNTIME_FUNC_LIST |
| 467 | #undef DEFINE_ENTRY |
| 468 | }; |
| 469 | |
| 470 | static void* const funcs[] = { |
| 471 | #define DEFINE_ENTRY(NAME) reinterpret_cast<void*>(NAME) , |
| 472 | #include "compiler_runtime_func_list.h" |
| 473 | COMPILER_RUNTIME_FUNC_LIST(DEFINE_ENTRY) |
| 474 | #undef COMPILER_RUNTIME_FUNC_LIST |
| 475 | #undef DEFINE_ENTRY |
| 476 | }; |
| 477 | |
| 478 | static const size_t num_entries = sizeof(names) / sizeof(const char* const); |
| 479 | |
| 480 | const char* const* matched_name_ptr = |
| 481 | std::lower_bound(names, names + num_entries, name, CStringComparator()); |
| 482 | |
| 483 | if (matched_name_ptr == names + num_entries) { |
| 484 | return NULL; |
| 485 | } else { |
| 486 | return funcs[matched_name_ptr - names]; |
| 487 | } |
| 488 | } |
| 489 | |
Logan Chien | 2771fb1 | 2012-03-06 16:28:35 +0800 | [diff] [blame] | 490 | void* art_find_runtime_support_func(void* context, char const* name) { |
| 491 | struct func_entry_t { |
| 492 | char const* name; |
| 493 | size_t name_len; |
| 494 | void* addr; |
| 495 | }; |
| 496 | |
| 497 | static struct func_entry_t const tab[] = { |
Logan Chien | bc615a1 | 2012-03-06 17:03:48 +0800 | [diff] [blame] | 498 | #define DEFINE_ENTRY(ID, NAME) \ |
| 499 | { #NAME, sizeof(#NAME) - 1, reinterpret_cast<void*>(NAME) }, |
Logan Chien | 2771fb1 | 2012-03-06 16:28:35 +0800 | [diff] [blame] | 500 | |
Logan Chien | bc615a1 | 2012-03-06 17:03:48 +0800 | [diff] [blame] | 501 | #include "runtime_support_func_list.h" |
| 502 | RUNTIME_SUPPORT_FUNC_LIST(DEFINE_ENTRY) |
| 503 | #undef RUNTIME_SUPPORT_FUNC_LIST |
| 504 | #undef DEFINE_ENTRY |
Logan Chien | 2771fb1 | 2012-03-06 16:28:35 +0800 | [diff] [blame] | 505 | }; |
| 506 | |
| 507 | static size_t const tab_size = sizeof(tab) / sizeof(struct func_entry_t); |
| 508 | |
Logan Chien | d23c5ad | 2012-03-30 17:46:04 +0800 | [diff] [blame] | 509 | // Search the compiler runtime (such as __divdi3) |
| 510 | void* result = art_find_compiler_runtime_func(name); |
| 511 | if (result != NULL) { |
| 512 | return result; |
| 513 | } |
| 514 | |
Logan Chien | 2771fb1 | 2012-03-06 16:28:35 +0800 | [diff] [blame] | 515 | // Note: Since our table is small, we are using trivial O(n) searching |
| 516 | // function. For bigger table, it will be better to use binary |
| 517 | // search or hash function. |
| 518 | size_t i; |
| 519 | size_t name_len = strlen(name); |
| 520 | for (i = 0; i < tab_size; ++i) { |
| 521 | if (name_len == tab[i].name_len && strcmp(name, tab[i].name) == 0) { |
| 522 | return tab[i].addr; |
| 523 | } |
| 524 | } |
| 525 | |
| 526 | LOG(FATAL) << "Error: Can't find symbol " << name; |
| 527 | return 0; |
| 528 | } |
| 529 | |
Shih-wei Liao | a8a9c34 | 2012-03-03 22:35:16 -0800 | [diff] [blame] | 530 | } // namespace art |