| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW"; | 64 if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW"; |
| 65 if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { | 65 if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { |
| 66 return ".IGNORE_OOB"; | 66 return ".IGNORE_OOB"; |
| 67 } | 67 } |
| 68 if (IsGrowStoreMode(mode)) return ".GROW"; | 68 if (IsGrowStoreMode(mode)) return ".GROW"; |
| 69 return ""; | 69 return ""; |
| 70 } | 70 } |
| 71 | 71 |
| 72 | 72 |
| 73 void IC::TraceIC(const char* type, | 73 void IC::TraceIC(const char* type, |
| 74 Handle<Object> name, | 74 Handle<Object> name) { |
| 75 State old_state, | |
| 76 Code* new_target) { | |
| 77 if (FLAG_trace_ic) { | 75 if (FLAG_trace_ic) { |
| 78 Object* undef = new_target->GetHeap()->undefined_value(); | 76 Code* new_target = raw_target(); |
| 79 State new_state = StateFrom(new_target, undef, undef); | 77 State new_state = new_target->ic_state(); |
| 80 PrintF("[%s in ", type); | 78 PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type); |
| 81 Isolate* isolate = new_target->GetIsolate(); | 79 StackFrameIterator it(isolate()); |
| 82 StackFrameIterator it(isolate); | |
| 83 while (it.frame()->fp() != this->fp()) it.Advance(); | 80 while (it.frame()->fp() != this->fp()) it.Advance(); |
| 84 StackFrame* raw_frame = it.frame(); | 81 StackFrame* raw_frame = it.frame(); |
| 85 if (raw_frame->is_internal()) { | 82 if (raw_frame->is_internal()) { |
| 86 Code* apply_builtin = isolate->builtins()->builtin( | 83 Code* apply_builtin = isolate()->builtins()->builtin( |
| 87 Builtins::kFunctionApply); | 84 Builtins::kFunctionApply); |
| 88 if (raw_frame->unchecked_code() == apply_builtin) { | 85 if (raw_frame->unchecked_code() == apply_builtin) { |
| 89 PrintF("apply from "); | 86 PrintF("apply from "); |
| 90 it.Advance(); | 87 it.Advance(); |
| 91 raw_frame = it.frame(); | 88 raw_frame = it.frame(); |
| 92 } | 89 } |
| 93 } | 90 } |
| 94 JavaScriptFrame::PrintTop(isolate, stdout, false, true); | 91 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| 95 Code::ExtraICState state = new_target->extra_ic_state(); | 92 Code::ExtraICState extra_state = new_target->extra_ic_state(); |
| 96 const char* modifier = | 93 const char* modifier = |
| 97 GetTransitionMarkModifier(Code::GetKeyedAccessStoreMode(state)); | 94 GetTransitionMarkModifier(Code::GetKeyedAccessStoreMode(extra_state)); |
| 98 PrintF(" (%c->%c%s)", | 95 PrintF(" (%c->%c%s)", |
| 99 TransitionMarkFromState(old_state), | 96 TransitionMarkFromState(state()), |
| 100 TransitionMarkFromState(new_state), | 97 TransitionMarkFromState(new_state), |
| 101 modifier); | 98 modifier); |
| 102 name->Print(); | 99 name->Print(); |
| 103 PrintF("]\n"); | 100 PrintF("]\n"); |
| 104 } | 101 } |
| 105 } | 102 } |
| 106 | 103 |
| 107 #define TRACE_GENERIC_IC(isolate, type, reason) \ | 104 #define TRACE_GENERIC_IC(isolate, type, reason) \ |
| 108 do { \ | 105 do { \ |
| 109 if (FLAG_trace_ic) { \ | 106 if (FLAG_trace_ic) { \ |
| 110 PrintF("[%s patching generic stub in ", type); \ | 107 PrintF("[%s patching generic stub in ", type); \ |
| 111 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \ | 108 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \ |
| 112 PrintF(" (%s)]\n", reason); \ | 109 PrintF(" (%s)]\n", reason); \ |
| 113 } \ | 110 } \ |
| 114 } while (false) | 111 } while (false) |
| 115 | 112 |
| 116 #else | 113 #else |
| 117 #define TRACE_GENERIC_IC(isolate, type, reason) | 114 #define TRACE_GENERIC_IC(isolate, type, reason) |
| 118 #endif // DEBUG | 115 #endif // DEBUG |
| 119 | 116 |
| 120 #define TRACE_IC(type, name, old_state, new_target) \ | 117 #define TRACE_IC(type, name) \ |
| 121 ASSERT((TraceIC(type, name, old_state, new_target), true)) | 118 ASSERT((TraceIC(type, name), true)) |
| 122 | 119 |
| 123 IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) { | 120 IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) { |
| 124 // To improve the performance of the (much used) IC code, we unfold a few | 121 // To improve the performance of the (much used) IC code, we unfold a few |
| 125 // levels of the stack frame iteration code. This yields a ~35% speedup when | 122 // levels of the stack frame iteration code. This yields a ~35% speedup when |
| 126 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag. | 123 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag. |
| 127 const Address entry = | 124 const Address entry = |
| 128 Isolate::c_entry_fp(isolate->thread_local_top()); | 125 Isolate::c_entry_fp(isolate->thread_local_top()); |
| 129 Address* pc_address = | 126 Address* pc_address = |
| 130 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); | 127 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); |
| 131 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); | 128 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
| 132 // If there's another JavaScript frame on the stack or a | 129 // If there's another JavaScript frame on the stack or a |
| 133 // StubFailureTrampoline, we need to look one frame further down the stack to | 130 // StubFailureTrampoline, we need to look one frame further down the stack to |
| 134 // find the frame pointer and the return address stack slot. | 131 // find the frame pointer and the return address stack slot. |
| 135 if (depth == EXTRA_CALL_FRAME) { | 132 if (depth == EXTRA_CALL_FRAME) { |
| 136 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset; | 133 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset; |
| 137 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset); | 134 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset); |
| 138 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset); | 135 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset); |
| 139 } | 136 } |
| 140 #ifdef DEBUG | 137 #ifdef DEBUG |
| 141 StackFrameIterator it(isolate); | 138 StackFrameIterator it(isolate); |
| 142 for (int i = 0; i < depth + 1; i++) it.Advance(); | 139 for (int i = 0; i < depth + 1; i++) it.Advance(); |
| 143 StackFrame* frame = it.frame(); | 140 StackFrame* frame = it.frame(); |
| 144 ASSERT(fp == frame->fp() && pc_address == frame->pc_address()); | 141 ASSERT(fp == frame->fp() && pc_address == frame->pc_address()); |
| 145 #endif | 142 #endif |
| 146 fp_ = fp; | 143 fp_ = fp; |
| 147 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address); | 144 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address); |
| 145 target_ = handle(raw_target(), isolate); |
| 146 state_ = target_->ic_state(); |
| 148 } | 147 } |
| 149 | 148 |
| 150 | 149 |
| 151 #ifdef ENABLE_DEBUGGER_SUPPORT | 150 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 152 Address IC::OriginalCodeAddress() const { | 151 Address IC::OriginalCodeAddress() const { |
| 153 HandleScope scope(isolate()); | 152 HandleScope scope(isolate()); |
| 154 // Compute the JavaScript frame for the frame pointer of this IC | 153 // Compute the JavaScript frame for the frame pointer of this IC |
| 155 // structure. We need this to be able to find the function | 154 // structure. We need this to be able to find the function |
| 156 // corresponding to the frame. | 155 // corresponding to the frame. |
| 157 StackFrameIterator it(isolate()); | 156 StackFrameIterator it(isolate()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 172 // Return the address in the original code. This is the place where | 171 // Return the address in the original code. This is the place where |
| 173 // the call which has been overwritten by the DebugBreakXXX resides | 172 // the call which has been overwritten by the DebugBreakXXX resides |
| 174 // and the place where the inline cache system should look. | 173 // and the place where the inline cache system should look. |
| 175 intptr_t delta = | 174 intptr_t delta = |
| 176 original_code->instruction_start() - code->instruction_start(); | 175 original_code->instruction_start() - code->instruction_start(); |
| 177 return addr + delta; | 176 return addr + delta; |
| 178 } | 177 } |
| 179 #endif | 178 #endif |
| 180 | 179 |
| 181 | 180 |
| 182 static bool TryRemoveInvalidPrototypeDependentStub(Code* target, | 181 static bool HasInterceptorGetter(JSObject* object) { |
| 183 Object* receiver, | 182 return !object->GetNamedInterceptor()->getter()->IsUndefined(); |
| 184 Object* name) { | 183 } |
| 185 if (target->is_keyed_load_stub() || | 184 |
| 186 target->is_keyed_call_stub() || | 185 |
| 187 target->is_keyed_store_stub()) { | 186 static bool HasInterceptorSetter(JSObject* object) { |
| 187 return !object->GetNamedInterceptor()->setter()->IsUndefined(); |
| 188 } |
| 189 |
| 190 |
| 191 static void LookupForRead(Handle<Object> object, |
| 192 Handle<String> name, |
| 193 LookupResult* lookup) { |
| 194 // Skip all the objects with named interceptors, but |
| 195 // without actual getter. |
| 196 while (true) { |
| 197 object->Lookup(*name, lookup); |
| 198 // Besides normal conditions (property not found or it's not |
| 199 // an interceptor), bail out if lookup is not cacheable: we won't |
| 200 // be able to IC it anyway and regular lookup should work fine. |
| 201 if (!lookup->IsInterceptor() || !lookup->IsCacheable()) { |
| 202 return; |
| 203 } |
| 204 |
| 205 Handle<JSObject> holder(lookup->holder(), lookup->isolate()); |
| 206 if (HasInterceptorGetter(*holder)) { |
| 207 return; |
| 208 } |
| 209 |
| 210 holder->LocalLookupRealNamedProperty(*name, lookup); |
| 211 if (lookup->IsFound()) { |
| 212 ASSERT(!lookup->IsInterceptor()); |
| 213 return; |
| 214 } |
| 215 |
| 216 Handle<Object> proto(holder->GetPrototype(), lookup->isolate()); |
| 217 if (proto->IsNull()) { |
| 218 ASSERT(!lookup->IsFound()); |
| 219 return; |
| 220 } |
| 221 |
| 222 object = proto; |
| 223 } |
| 224 } |
| 225 |
| 226 |
| 227 bool CallIC::TryUpdateExtraICState(LookupResult* lookup, |
| 228 Handle<Object> object) { |
| 229 if (!lookup->IsConstantFunction()) return false; |
| 230 JSFunction* function = lookup->GetConstantFunction(); |
| 231 if (!function->shared()->HasBuiltinFunctionId()) return false; |
| 232 |
| 233 // Fetch the arguments passed to the called function. |
| 234 const int argc = target()->arguments_count(); |
| 235 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top()); |
| 236 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
| 237 Arguments args(argc + 1, |
| 238 &Memory::Object_at(fp + |
| 239 StandardFrameConstants::kCallerSPOffset + |
| 240 argc * kPointerSize)); |
| 241 switch (function->shared()->builtin_function_id()) { |
| 242 case kStringCharCodeAt: |
| 243 case kStringCharAt: |
| 244 if (object->IsString()) { |
| 245 String* string = String::cast(*object); |
| 246 // Check there's the right string value or wrapper in the receiver slot. |
| 247 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value()); |
| 248 // If we're in the default (fastest) state and the index is |
| 249 // out of bounds, update the state to record this fact. |
| 250 if (StringStubState::decode(extra_ic_state()) == DEFAULT_STRING_STUB && |
| 251 argc >= 1 && args[1]->IsNumber()) { |
| 252 double index = DoubleToInteger(args.number_at(1)); |
| 253 if (index < 0 || index >= string->length()) { |
| 254 extra_ic_state_ = |
| 255 StringStubState::update(extra_ic_state(), |
| 256 STRING_INDEX_OUT_OF_BOUNDS); |
| 257 return true; |
| 258 } |
| 259 } |
| 260 } |
| 261 break; |
| 262 default: |
| 263 return false; |
| 264 } |
| 265 return false; |
| 266 } |
| 267 |
| 268 |
| 269 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver, |
| 270 Handle<String> name) { |
| 271 DisallowHeapAllocation no_gc; |
| 272 |
| 273 if (target()->is_call_stub()) { |
| 274 LookupResult lookup(isolate()); |
| 275 LookupForRead(receiver, name, &lookup); |
| 276 if (static_cast<CallIC*>(this)->TryUpdateExtraICState(&lookup, receiver)) { |
| 277 return true; |
| 278 } |
| 279 } |
| 280 |
| 281 if (target()->is_keyed_stub()) { |
| 188 // Determine whether the failure is due to a name failure. | 282 // Determine whether the failure is due to a name failure. |
| 189 if (!name->IsName()) return false; | 283 if (!name->IsName()) return false; |
| 190 Name* stub_name = target->FindFirstName(); | 284 Name* stub_name = target()->FindFirstName(); |
| 191 if (Name::cast(name) != stub_name) return false; | 285 if (*name != stub_name) return false; |
| 192 } | 286 } |
| 193 | 287 |
| 194 InlineCacheHolderFlag cache_holder = | 288 InlineCacheHolderFlag cache_holder = |
| 195 Code::ExtractCacheHolderFromFlags(target->flags()); | 289 Code::ExtractCacheHolderFromFlags(target()->flags()); |
| 196 | 290 |
| 197 Isolate* isolate = target->GetIsolate(); | 291 switch (cache_holder) { |
| 198 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { | 292 case OWN_MAP: |
| 199 // The stub was generated for JSObject but called for non-JSObject. | 293 // The stub was generated for JSObject but called for non-JSObject. |
| 200 // IC::GetCodeCacheHolder is not applicable. | 294 // IC::GetCodeCacheHolder is not applicable. |
| 201 return false; | 295 if (!receiver->IsJSObject()) return false; |
| 202 } else if (cache_holder == PROTOTYPE_MAP && | 296 break; |
| 203 receiver->GetPrototype(isolate)->IsNull()) { | 297 case PROTOTYPE_MAP: |
| 204 // IC::GetCodeCacheHolder is not applicable. | 298 // IC::GetCodeCacheHolder is not applicable. |
| 205 return false; | 299 if (receiver->GetPrototype(isolate())->IsNull()) return false; |
| 300 break; |
| 206 } | 301 } |
| 207 Map* map = IC::GetCodeCacheHolder(isolate, receiver, cache_holder)->map(); | 302 |
| 303 Map* map = IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map(); |
| 208 | 304 |
| 209 // Decide whether the inline cache failed because of changes to the | 305 // Decide whether the inline cache failed because of changes to the |
| 210 // receiver itself or changes to one of its prototypes. | 306 // receiver itself or changes to one of its prototypes. |
| 211 // | 307 // |
| 212 // If there are changes to the receiver itself, the map of the | 308 // If there are changes to the receiver itself, the map of the |
| 213 // receiver will have changed and the current target will not be in | 309 // receiver will have changed and the current target will not be in |
| 214 // the receiver map's code cache. Therefore, if the current target | 310 // the receiver map's code cache. Therefore, if the current target |
| 215 // is in the receiver map's code cache, the inline cache failed due | 311 // is in the receiver map's code cache, the inline cache failed due |
| 216 // to prototype check failure. | 312 // to prototype check failure. |
| 217 int index = map->IndexInCodeCache(name, target); | 313 int index = map->IndexInCodeCache(*name, *target()); |
| 218 if (index >= 0) { | 314 if (index >= 0) { |
| 219 map->RemoveFromCodeCache(String::cast(name), target, index); | 315 map->RemoveFromCodeCache(*name, *target(), index); |
| 220 // For loads and stores, handlers are stored in addition to the ICs on the | 316 // Handlers are stored in addition to the ICs on the map. Remove those, too. |
| 221 // map. Remove those, too. | 317 Code* handler = target()->FindFirstHandler(); |
| 222 if ((target->is_load_stub() || target->is_keyed_load_stub() || | 318 if (handler != NULL) { |
| 223 target->is_store_stub() || target->is_keyed_store_stub()) && | 319 index = map->IndexInCodeCache(*name, handler); |
| 224 target->type() != Code::NORMAL) { | |
| 225 Code* handler = target->FindFirstCode(); | |
| 226 index = map->IndexInCodeCache(name, handler); | |
| 227 if (index >= 0) { | 320 if (index >= 0) { |
| 228 map->RemoveFromCodeCache(String::cast(name), handler, index); | 321 map->RemoveFromCodeCache(*name, handler, index); |
| 229 } | 322 } |
| 230 } | 323 } |
| 231 return true; | 324 return true; |
| 232 } | 325 } |
| 233 | 326 |
| 234 // The stub is not in the cache. We've ruled out all other kinds of failure | 327 // The stub is not in the cache. We've ruled out all other kinds of failure |
| 235 // except for proptotype chain changes, a deprecated map, a map that's | 328 // except for proptotype chain changes, a deprecated map, a map that's |
| 236 // different from the one that the stub expects, elements kind changes, or a | 329 // different from the one that the stub expects, elements kind changes, or a |
| 237 // constant global property that will become mutable. Threat all those | 330 // constant global property that will become mutable. Threat all those |
| 238 // situations as prototype failures (stay monomorphic if possible). | 331 // situations as prototype failures (stay monomorphic if possible). |
| 239 | 332 |
| 240 // If the IC is shared between multiple receivers (slow dictionary mode), then | 333 // If the IC is shared between multiple receivers (slow dictionary mode), then |
| 241 // the map cannot be deprecated and the stub invalidated. | 334 // the map cannot be deprecated and the stub invalidated. |
| 242 if (cache_holder == OWN_MAP) { | 335 if (cache_holder == OWN_MAP) { |
| 243 Map* old_map = target->FindFirstMap(); | 336 Map* old_map = target()->FindFirstMap(); |
| 244 if (old_map == map) return true; | 337 if (old_map == map) return true; |
| 245 if (old_map != NULL) { | 338 if (old_map != NULL) { |
| 246 if (old_map->is_deprecated()) return true; | 339 if (old_map->is_deprecated()) return true; |
| 247 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(), | 340 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(), |
| 248 map->elements_kind())) { | 341 map->elements_kind())) { |
| 249 return true; | 342 return true; |
| 250 } | 343 } |
| 251 } | 344 } |
| 252 } | 345 } |
| 253 | 346 |
| 254 if (receiver->IsGlobalObject()) { | 347 if (receiver->IsGlobalObject()) { |
| 255 if (!name->IsName()) return false; | 348 LookupResult lookup(isolate()); |
| 256 Isolate* isolate = target->GetIsolate(); | 349 GlobalObject* global = GlobalObject::cast(*receiver); |
| 257 LookupResult lookup(isolate); | 350 global->LocalLookupRealNamedProperty(*name, &lookup); |
| 258 GlobalObject* global = GlobalObject::cast(receiver); | |
| 259 global->LocalLookupRealNamedProperty(Name::cast(name), &lookup); | |
| 260 if (!lookup.IsFound()) return false; | 351 if (!lookup.IsFound()) return false; |
| 261 PropertyCell* cell = global->GetPropertyCell(&lookup); | 352 PropertyCell* cell = global->GetPropertyCell(&lookup); |
| 262 return cell->type()->IsConstant(); | 353 return cell->type()->IsConstant(); |
| 263 } | 354 } |
| 264 | 355 |
| 265 return false; | 356 return false; |
| 266 } | 357 } |
| 267 | 358 |
| 268 | 359 |
| 269 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { | 360 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { |
| 270 IC::State state = target->ic_state(); | 361 if (state() != MONOMORPHIC || !name->IsString()) return; |
| 362 if (receiver->IsUndefined() || receiver->IsNull()) return; |
| 271 | 363 |
| 272 if (state != MONOMORPHIC || !name->IsString()) return state; | |
| 273 if (receiver->IsUndefined() || receiver->IsNull()) return state; | |
| 274 | |
| 275 Code::Kind kind = target->kind(); | |
| 276 // Remove the target from the code cache if it became invalid | 364 // Remove the target from the code cache if it became invalid |
| 277 // because of changes in the prototype chain to avoid hitting it | 365 // because of changes in the prototype chain to avoid hitting it |
| 278 // again. | 366 // again. |
| 279 // Call stubs handle this later to allow extra IC state | 367 if (TryRemoveInvalidPrototypeDependentStub( |
| 280 // transitions. | 368 receiver, Handle<String>::cast(name))) { |
| 281 if (kind != Code::CALL_IC && kind != Code::KEYED_CALL_IC && | 369 return MarkMonomorphicPrototypeFailure(); |
| 282 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { | |
| 283 return MONOMORPHIC_PROTOTYPE_FAILURE; | |
| 284 } | 370 } |
| 285 | 371 |
| 286 // The builtins object is special. It only changes when JavaScript | 372 // The builtins object is special. It only changes when JavaScript |
| 287 // builtins are loaded lazily. It is important to keep inline | 373 // builtins are loaded lazily. It is important to keep inline |
| 288 // caches for the builtins object monomorphic. Therefore, if we get | 374 // caches for the builtins object monomorphic. Therefore, if we get |
| 289 // an inline cache miss for the builtins object after lazily loading | 375 // an inline cache miss for the builtins object after lazily loading |
| 290 // JavaScript builtins, we return uninitialized as the state to | 376 // JavaScript builtins, we return uninitialized as the state to |
| 291 // force the inline cache back to monomorphic state. | 377 // force the inline cache back to monomorphic state. |
| 292 if (receiver->IsJSBuiltinsObject()) { | 378 if (receiver->IsJSBuiltinsObject()) state_ = UNINITIALIZED; |
| 293 return UNINITIALIZED; | |
| 294 } | |
| 295 | |
| 296 return MONOMORPHIC; | |
| 297 } | 379 } |
| 298 | 380 |
| 299 | 381 |
| 300 RelocInfo::Mode IC::ComputeMode() { | 382 RelocInfo::Mode IC::ComputeMode() { |
| 301 Address addr = address(); | 383 Address addr = address(); |
| 302 Code* code = Code::cast(isolate()->FindCodeObject(addr)); | 384 Code* code = Code::cast(isolate()->FindCodeObject(addr)); |
| 303 for (RelocIterator it(code, RelocInfo::kCodeTargetMask); | 385 for (RelocIterator it(code, RelocInfo::kCodeTargetMask); |
| 304 !it.done(); it.next()) { | 386 !it.done(); it.next()) { |
| 305 RelocInfo* info = it.rinfo(); | 387 RelocInfo* info = it.rinfo(); |
| 306 if (info->pc() == addr) return info->rmode(); | 388 if (info->pc() == addr) return info->rmode(); |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 | 507 |
| 426 void LoadIC::Clear(Isolate* isolate, Address address, Code* target) { | 508 void LoadIC::Clear(Isolate* isolate, Address address, Code* target) { |
| 427 if (IsCleared(target)) return; | 509 if (IsCleared(target)) return; |
| 428 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate)); | 510 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate)); |
| 429 } | 511 } |
| 430 | 512 |
| 431 | 513 |
| 432 void StoreIC::Clear(Isolate* isolate, Address address, Code* target) { | 514 void StoreIC::Clear(Isolate* isolate, Address address, Code* target) { |
| 433 if (IsCleared(target)) return; | 515 if (IsCleared(target)) return; |
| 434 SetTargetAtAddress(address, | 516 SetTargetAtAddress(address, |
| 435 (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) | 517 *pre_monomorphic_stub( |
| 436 ? *pre_monomorphic_stub_strict(isolate) | 518 isolate, Code::GetStrictMode(target->extra_ic_state()))); |
| 437 : *pre_monomorphic_stub(isolate)); | |
| 438 } | 519 } |
| 439 | 520 |
| 440 | 521 |
| 441 void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target) { | 522 void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target) { |
| 442 if (IsCleared(target)) return; | 523 if (IsCleared(target)) return; |
| 443 SetTargetAtAddress(address, | 524 SetTargetAtAddress(address, |
| 444 (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) | 525 *pre_monomorphic_stub( |
| 445 ? *pre_monomorphic_stub_strict(isolate) | 526 isolate, Code::GetStrictMode(target->extra_ic_state()))); |
| 446 : *pre_monomorphic_stub(isolate)); | |
| 447 } | 527 } |
| 448 | 528 |
| 449 | 529 |
| 450 void CompareIC::Clear(Isolate* isolate, Address address, Code* target) { | 530 void CompareIC::Clear(Isolate* isolate, Address address, Code* target) { |
| 451 ASSERT(target->major_key() == CodeStub::CompareIC); | 531 ASSERT(target->major_key() == CodeStub::CompareIC); |
| 452 CompareIC::State handler_state; | 532 CompareIC::State handler_state; |
| 453 Token::Value op; | 533 Token::Value op; |
| 454 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL, | 534 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL, |
| 455 &handler_state, &op); | 535 &handler_state, &op); |
| 456 // Only clear CompareICs that can retain objects. | 536 // Only clear CompareICs that can retain objects. |
| 457 if (handler_state != KNOWN_OBJECT) return; | 537 if (handler_state != KNOWN_OBJECT) return; |
| 458 SetTargetAtAddress(address, GetRawUninitialized(isolate, op)); | 538 SetTargetAtAddress(address, GetRawUninitialized(isolate, op)); |
| 459 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); | 539 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); |
| 460 } | 540 } |
| 461 | 541 |
| 462 | 542 |
| 463 static bool HasInterceptorGetter(JSObject* object) { | |
| 464 return !object->GetNamedInterceptor()->getter()->IsUndefined(); | |
| 465 } | |
| 466 | |
| 467 | |
| 468 static void LookupForRead(Handle<Object> object, | |
| 469 Handle<String> name, | |
| 470 LookupResult* lookup) { | |
| 471 // Skip all the objects with named interceptors, but | |
| 472 // without actual getter. | |
| 473 while (true) { | |
| 474 object->Lookup(*name, lookup); | |
| 475 // Besides normal conditions (property not found or it's not | |
| 476 // an interceptor), bail out if lookup is not cacheable: we won't | |
| 477 // be able to IC it anyway and regular lookup should work fine. | |
| 478 if (!lookup->IsInterceptor() || !lookup->IsCacheable()) { | |
| 479 return; | |
| 480 } | |
| 481 | |
| 482 Handle<JSObject> holder(lookup->holder(), lookup->isolate()); | |
| 483 if (HasInterceptorGetter(*holder)) { | |
| 484 return; | |
| 485 } | |
| 486 | |
| 487 holder->LocalLookupRealNamedProperty(*name, lookup); | |
| 488 if (lookup->IsFound()) { | |
| 489 ASSERT(!lookup->IsInterceptor()); | |
| 490 return; | |
| 491 } | |
| 492 | |
| 493 Handle<Object> proto(holder->GetPrototype(), lookup->isolate()); | |
| 494 if (proto->IsNull()) { | |
| 495 ASSERT(!lookup->IsFound()); | |
| 496 return; | |
| 497 } | |
| 498 | |
| 499 object = proto; | |
| 500 } | |
| 501 } | |
| 502 | |
| 503 | |
| 504 Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) { | 543 Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) { |
| 505 Handle<Object> delegate = Execution::GetFunctionDelegate(isolate(), object); | 544 Handle<Object> delegate = Execution::GetFunctionDelegate(isolate(), object); |
| 506 | 545 |
| 507 if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) { | 546 if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) { |
| 508 // Patch the receiver and use the delegate as the function to | 547 // Patch the receiver and use the delegate as the function to |
| 509 // invoke. This is used for invoking objects as if they were functions. | 548 // invoke. This is used for invoking objects as if they were functions. |
| 510 const int argc = target()->arguments_count(); | 549 const int argc = target()->arguments_count(); |
| 511 StackFrameLocator locator(isolate()); | 550 StackFrameLocator locator(isolate()); |
| 512 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 551 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
| 513 int index = frame->ComputeExpressionsCount() - (argc + 1); | 552 int index = frame->ComputeExpressionsCount() - (argc + 1); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 538 // Change the receiver to the result of calling ToObject on it. | 577 // Change the receiver to the result of calling ToObject on it. |
| 539 const int argc = this->target()->arguments_count(); | 578 const int argc = this->target()->arguments_count(); |
| 540 StackFrameLocator locator(isolate()); | 579 StackFrameLocator locator(isolate()); |
| 541 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 580 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
| 542 int index = frame->ComputeExpressionsCount() - (argc + 1); | 581 int index = frame->ComputeExpressionsCount() - (argc + 1); |
| 543 frame->SetExpression(index, *isolate()->factory()->ToObject(object)); | 582 frame->SetExpression(index, *isolate()->factory()->ToObject(object)); |
| 544 } | 583 } |
| 545 } | 584 } |
| 546 | 585 |
| 547 | 586 |
| 548 MaybeObject* CallICBase::LoadFunction(State state, | 587 static bool MigrateDeprecated(Handle<Object> object) { |
| 549 Code::ExtraICState extra_ic_state, | 588 if (!object->IsJSObject()) return false; |
| 550 Handle<Object> object, | 589 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 590 if (!receiver->map()->is_deprecated()) return false; |
| 591 JSObject::MigrateInstance(Handle<JSObject>::cast(object)); |
| 592 return true; |
| 593 } |
| 594 |
| 595 |
| 596 MaybeObject* CallICBase::LoadFunction(Handle<Object> object, |
| 551 Handle<String> name) { | 597 Handle<String> name) { |
| 552 bool use_ic = FLAG_use_ic; | 598 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic; |
| 553 if (object->IsJSObject()) { | |
| 554 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 555 if (receiver->map()->is_deprecated()) { | |
| 556 use_ic = false; | |
| 557 JSObject::MigrateInstance(receiver); | |
| 558 } | |
| 559 } | |
| 560 | 599 |
| 561 // If the object is undefined or null it's illegal to try to get any | 600 // If the object is undefined or null it's illegal to try to get any |
| 562 // of its properties; throw a TypeError in that case. | 601 // of its properties; throw a TypeError in that case. |
| 563 if (object->IsUndefined() || object->IsNull()) { | 602 if (object->IsUndefined() || object->IsNull()) { |
| 564 return TypeError("non_object_property_call", object, name); | 603 return TypeError("non_object_property_call", object, name); |
| 565 } | 604 } |
| 566 | 605 |
| 567 // Check if the name is trivially convertible to an index and get | 606 // Check if the name is trivially convertible to an index and get |
| 568 // the element if so. | 607 // the element if so. |
| 569 uint32_t index; | 608 uint32_t index; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 585 | 624 |
| 586 if (!lookup.IsFound()) { | 625 if (!lookup.IsFound()) { |
| 587 // If the object does not have the requested property, check which | 626 // If the object does not have the requested property, check which |
| 588 // exception we need to throw. | 627 // exception we need to throw. |
| 589 return IsUndeclaredGlobal(object) | 628 return IsUndeclaredGlobal(object) |
| 590 ? ReferenceError("not_defined", name) | 629 ? ReferenceError("not_defined", name) |
| 591 : TypeError("undefined_method", object, name); | 630 : TypeError("undefined_method", object, name); |
| 592 } | 631 } |
| 593 | 632 |
| 594 // Lookup is valid: Update inline cache and stub cache. | 633 // Lookup is valid: Update inline cache and stub cache. |
| 595 if (use_ic) UpdateCaches(&lookup, state, extra_ic_state, object, name); | 634 if (use_ic) UpdateCaches(&lookup, object, name); |
| 596 | 635 |
| 597 // Get the property. | 636 // Get the property. |
| 598 PropertyAttributes attr; | 637 PropertyAttributes attr; |
| 599 Handle<Object> result = | 638 Handle<Object> result = |
| 600 Object::GetProperty(object, object, &lookup, name, &attr); | 639 Object::GetProperty(object, object, &lookup, name, &attr); |
| 601 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 640 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 602 | 641 |
| 603 if (lookup.IsInterceptor() && attr == ABSENT) { | 642 if (lookup.IsInterceptor() && attr == ABSENT) { |
| 604 // If the object does not have the requested property, check which | 643 // If the object does not have the requested property, check which |
| 605 // exception we need to throw. | 644 // exception we need to throw. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 630 } | 669 } |
| 631 | 670 |
| 632 // Try to find a suitable function delegate for the object at hand. | 671 // Try to find a suitable function delegate for the object at hand. |
| 633 result = TryCallAsFunction(result); | 672 result = TryCallAsFunction(result); |
| 634 if (result->IsJSFunction()) return *result; | 673 if (result->IsJSFunction()) return *result; |
| 635 | 674 |
| 636 return TypeError("property_not_function", object, name); | 675 return TypeError("property_not_function", object, name); |
| 637 } | 676 } |
| 638 | 677 |
| 639 | 678 |
| 640 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, | |
| 641 Handle<Object> object, | |
| 642 Code::ExtraICState* extra_ic_state) { | |
| 643 ASSERT(kind_ == Code::CALL_IC); | |
| 644 if (!lookup->IsConstantFunction()) return false; | |
| 645 JSFunction* function = lookup->GetConstantFunction(); | |
| 646 if (!function->shared()->HasBuiltinFunctionId()) return false; | |
| 647 | |
| 648 // Fetch the arguments passed to the called function. | |
| 649 const int argc = target()->arguments_count(); | |
| 650 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top()); | |
| 651 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); | |
| 652 Arguments args(argc + 1, | |
| 653 &Memory::Object_at(fp + | |
| 654 StandardFrameConstants::kCallerSPOffset + | |
| 655 argc * kPointerSize)); | |
| 656 switch (function->shared()->builtin_function_id()) { | |
| 657 case kStringCharCodeAt: | |
| 658 case kStringCharAt: | |
| 659 if (object->IsString()) { | |
| 660 String* string = String::cast(*object); | |
| 661 // Check there's the right string value or wrapper in the receiver slot. | |
| 662 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value()); | |
| 663 // If we're in the default (fastest) state and the index is | |
| 664 // out of bounds, update the state to record this fact. | |
| 665 if (StringStubState::decode(*extra_ic_state) == DEFAULT_STRING_STUB && | |
| 666 argc >= 1 && args[1]->IsNumber()) { | |
| 667 double index = DoubleToInteger(args.number_at(1)); | |
| 668 if (index < 0 || index >= string->length()) { | |
| 669 *extra_ic_state = | |
| 670 StringStubState::update(*extra_ic_state, | |
| 671 STRING_INDEX_OUT_OF_BOUNDS); | |
| 672 return true; | |
| 673 } | |
| 674 } | |
| 675 } | |
| 676 break; | |
| 677 default: | |
| 678 return false; | |
| 679 } | |
| 680 return false; | |
| 681 } | |
| 682 | |
| 683 | |
| 684 Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, | 679 Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, |
| 685 State state, | |
| 686 Code::ExtraICState extra_state, | |
| 687 Handle<Object> object, | 680 Handle<Object> object, |
| 688 Handle<String> name) { | 681 Handle<String> name) { |
| 689 int argc = target()->arguments_count(); | 682 int argc = target()->arguments_count(); |
| 690 Handle<JSObject> holder(lookup->holder(), isolate()); | 683 Handle<JSObject> holder(lookup->holder(), isolate()); |
| 691 switch (lookup->type()) { | 684 switch (lookup->type()) { |
| 692 case FIELD: { | 685 case FIELD: { |
| 693 PropertyIndex index = lookup->GetFieldIndex(); | 686 PropertyIndex index = lookup->GetFieldIndex(); |
| 694 return isolate()->stub_cache()->ComputeCallField( | 687 return isolate()->stub_cache()->ComputeCallField( |
| 695 argc, kind_, extra_state, name, object, holder, index); | 688 argc, kind_, extra_ic_state(), name, object, holder, index); |
| 696 } | 689 } |
| 697 case CONSTANT: { | 690 case CONSTANT: { |
| 698 if (!lookup->IsConstantFunction()) return Handle<Code>::null(); | 691 if (!lookup->IsConstantFunction()) return Handle<Code>::null(); |
| 699 // Get the constant function and compute the code stub for this | 692 // Get the constant function and compute the code stub for this |
| 700 // call; used for rewriting to monomorphic state and making sure | 693 // call; used for rewriting to monomorphic state and making sure |
| 701 // that the code stub is in the stub cache. | 694 // that the code stub is in the stub cache. |
| 702 Handle<JSFunction> function(lookup->GetConstantFunction(), isolate()); | 695 Handle<JSFunction> function(lookup->GetConstantFunction(), isolate()); |
| 703 return isolate()->stub_cache()->ComputeCallConstant( | 696 return isolate()->stub_cache()->ComputeCallConstant( |
| 704 argc, kind_, extra_state, name, object, holder, function); | 697 argc, kind_, extra_ic_state(), name, object, holder, function); |
| 705 } | 698 } |
| 706 case NORMAL: { | 699 case NORMAL: { |
| 707 // If we return a null handle, the IC will not be patched. | 700 // If we return a null handle, the IC will not be patched. |
| 708 if (!object->IsJSObject()) return Handle<Code>::null(); | 701 if (!object->IsJSObject()) return Handle<Code>::null(); |
| 709 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 702 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 710 | 703 |
| 711 if (holder->IsGlobalObject()) { | 704 if (holder->IsGlobalObject()) { |
| 712 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); | 705 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
| 713 Handle<PropertyCell> cell( | 706 Handle<PropertyCell> cell( |
| 714 global->GetPropertyCell(lookup), isolate()); | 707 global->GetPropertyCell(lookup), isolate()); |
| 715 if (!cell->value()->IsJSFunction()) return Handle<Code>::null(); | 708 if (!cell->value()->IsJSFunction()) return Handle<Code>::null(); |
| 716 Handle<JSFunction> function(JSFunction::cast(cell->value())); | 709 Handle<JSFunction> function(JSFunction::cast(cell->value())); |
| 717 return isolate()->stub_cache()->ComputeCallGlobal( | 710 return isolate()->stub_cache()->ComputeCallGlobal( |
| 718 argc, kind_, extra_state, name, receiver, global, cell, function); | 711 argc, kind_, extra_ic_state(), name, |
| 712 receiver, global, cell, function); |
| 719 } else { | 713 } else { |
| 720 // There is only one shared stub for calling normalized | 714 // There is only one shared stub for calling normalized |
| 721 // properties. It does not traverse the prototype chain, so the | 715 // properties. It does not traverse the prototype chain, so the |
| 722 // property must be found in the receiver for the stub to be | 716 // property must be found in the receiver for the stub to be |
| 723 // applicable. | 717 // applicable. |
| 724 if (!holder.is_identical_to(receiver)) return Handle<Code>::null(); | 718 if (!holder.is_identical_to(receiver)) return Handle<Code>::null(); |
| 725 return isolate()->stub_cache()->ComputeCallNormal( | 719 return isolate()->stub_cache()->ComputeCallNormal( |
| 726 argc, kind_, extra_state); | 720 argc, kind_, extra_ic_state()); |
| 727 } | 721 } |
| 728 break; | 722 break; |
| 729 } | 723 } |
| 730 case INTERCEPTOR: | 724 case INTERCEPTOR: |
| 731 ASSERT(HasInterceptorGetter(*holder)); | 725 ASSERT(HasInterceptorGetter(*holder)); |
| 732 return isolate()->stub_cache()->ComputeCallInterceptor( | 726 return isolate()->stub_cache()->ComputeCallInterceptor( |
| 733 argc, kind_, extra_state, name, object, holder); | 727 argc, kind_, extra_ic_state(), name, object, holder); |
| 734 default: | 728 default: |
| 735 return Handle<Code>::null(); | 729 return Handle<Code>::null(); |
| 736 } | 730 } |
| 737 } | 731 } |
| 738 | 732 |
| 739 | 733 |
| 734 Handle<Code> CallICBase::megamorphic_stub() { |
| 735 return isolate()->stub_cache()->ComputeCallMegamorphic( |
| 736 target()->arguments_count(), kind_, extra_ic_state()); |
| 737 } |
| 738 |
| 739 |
| 740 Handle<Code> CallICBase::pre_monomorphic_stub() { |
| 741 return isolate()->stub_cache()->ComputeCallPreMonomorphic( |
| 742 target()->arguments_count(), kind_, extra_ic_state()); |
| 743 } |
| 744 |
| 745 |
| 740 void CallICBase::UpdateCaches(LookupResult* lookup, | 746 void CallICBase::UpdateCaches(LookupResult* lookup, |
| 741 State state, | |
| 742 Code::ExtraICState extra_ic_state, | |
| 743 Handle<Object> object, | 747 Handle<Object> object, |
| 744 Handle<String> name) { | 748 Handle<String> name) { |
| 745 // Bail out if we didn't find a result. | 749 // Bail out if we didn't find a result. |
| 746 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 750 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
| 747 | 751 |
| 748 // Compute the number of arguments. | 752 // Compute the number of arguments. |
| 749 int argc = target()->arguments_count(); | |
| 750 Handle<Code> code; | 753 Handle<Code> code; |
| 751 if (state == UNINITIALIZED) { | 754 code = state() == UNINITIALIZED |
| 752 // This is the first time we execute this inline cache. | 755 ? pre_monomorphic_stub() |
| 753 // Set the target to the pre monomorphic stub to delay | 756 : ComputeMonomorphicStub(lookup, object, name); |
| 754 // setting the monomorphic state. | |
| 755 code = isolate()->stub_cache()->ComputeCallPreMonomorphic( | |
| 756 argc, kind_, extra_ic_state); | |
| 757 } else if (state == MONOMORPHIC) { | |
| 758 if (kind_ == Code::CALL_IC && | |
| 759 TryUpdateExtraICState(lookup, object, &extra_ic_state)) { | |
| 760 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, | |
| 761 object, name); | |
| 762 } else if (TryRemoveInvalidPrototypeDependentStub(target(), | |
| 763 *object, | |
| 764 *name)) { | |
| 765 state = MONOMORPHIC_PROTOTYPE_FAILURE; | |
| 766 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, | |
| 767 object, name); | |
| 768 } else { | |
| 769 code = isolate()->stub_cache()->ComputeCallMegamorphic( | |
| 770 argc, kind_, extra_ic_state); | |
| 771 } | |
| 772 } else { | |
| 773 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, | |
| 774 object, name); | |
| 775 } | |
| 776 | 757 |
| 777 // If there's no appropriate stub we simply avoid updating the caches. | 758 // If there's no appropriate stub we simply avoid updating the caches. |
| 759 // TODO(verwaest): Install a slow fallback in this case to avoid not learning, |
| 760 // and deopting Crankshaft code. |
| 778 if (code.is_null()) return; | 761 if (code.is_null()) return; |
| 779 | 762 |
| 780 // Patch the call site depending on the state of the cache. | 763 Handle<JSObject> cache_object = object->IsJSObject() |
| 781 switch (state) { | 764 ? Handle<JSObject>::cast(object) |
| 782 case UNINITIALIZED: | 765 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), |
| 783 case MONOMORPHIC_PROTOTYPE_FAILURE: | 766 isolate()); |
| 784 case PREMONOMORPHIC: | |
| 785 case MONOMORPHIC: | |
| 786 set_target(*code); | |
| 787 break; | |
| 788 case MEGAMORPHIC: { | |
| 789 // Cache code holding map should be consistent with | |
| 790 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. | |
| 791 Handle<JSObject> cache_object = object->IsJSObject() | |
| 792 ? Handle<JSObject>::cast(object) | |
| 793 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), | |
| 794 isolate()); | |
| 795 // Update the stub cache. | |
| 796 UpdateMegamorphicCache(cache_object->map(), *name, *code); | |
| 797 break; | |
| 798 } | |
| 799 case DEBUG_STUB: | |
| 800 break; | |
| 801 case POLYMORPHIC: | |
| 802 case GENERIC: | |
| 803 UNREACHABLE(); | |
| 804 break; | |
| 805 } | |
| 806 | 767 |
| 807 TRACE_IC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", | 768 PatchCache(cache_object, name, code); |
| 808 name, state, target()); | 769 TRACE_IC("CallIC", name); |
| 809 } | 770 } |
| 810 | 771 |
| 811 | 772 |
| 812 MaybeObject* KeyedCallIC::LoadFunction(State state, | 773 MaybeObject* KeyedCallIC::LoadFunction(Handle<Object> object, |
| 813 Handle<Object> object, | |
| 814 Handle<Object> key) { | 774 Handle<Object> key) { |
| 815 if (key->IsInternalizedString()) { | 775 if (key->IsInternalizedString()) { |
| 816 return CallICBase::LoadFunction(state, | 776 return CallICBase::LoadFunction(object, Handle<String>::cast(key)); |
| 817 Code::kNoExtraICState, | |
| 818 object, | |
| 819 Handle<String>::cast(key)); | |
| 820 } | |
| 821 | |
| 822 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | |
| 823 if (object->IsJSObject()) { | |
| 824 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 825 if (receiver->map()->is_deprecated()) { | |
| 826 use_ic = false; | |
| 827 JSObject::MigrateInstance(receiver); | |
| 828 } | |
| 829 } | 777 } |
| 830 | 778 |
| 831 if (object->IsUndefined() || object->IsNull()) { | 779 if (object->IsUndefined() || object->IsNull()) { |
| 832 return TypeError("non_object_property_call", object, key); | 780 return TypeError("non_object_property_call", object, key); |
| 833 } | 781 } |
| 834 | 782 |
| 835 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 783 bool use_ic = MigrateDeprecated(object) |
| 784 ? false : FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 836 | 785 |
| 837 if (use_ic && state != MEGAMORPHIC) { | 786 if (use_ic && state() != MEGAMORPHIC) { |
| 787 ASSERT(!object->IsJSGlobalProxy()); |
| 838 int argc = target()->arguments_count(); | 788 int argc = target()->arguments_count(); |
| 839 Handle<Code> stub = isolate()->stub_cache()->ComputeCallMegamorphic( | 789 Handle<Code> stub = isolate()->stub_cache()->ComputeCallMegamorphic( |
| 840 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState); | 790 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState); |
| 841 if (object->IsJSObject()) { | 791 if (object->IsJSObject()) { |
| 842 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 792 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 843 if (receiver->elements()->map() == | 793 if (receiver->elements()->map() == |
| 844 isolate()->heap()->non_strict_arguments_elements_map()) { | 794 isolate()->heap()->non_strict_arguments_elements_map()) { |
| 845 stub = isolate()->stub_cache()->ComputeCallArguments(argc); | 795 stub = isolate()->stub_cache()->ComputeCallArguments(argc); |
| 846 } | 796 } |
| 847 } | 797 } |
| 848 ASSERT(!stub.is_null()); | 798 ASSERT(!stub.is_null()); |
| 849 set_target(*stub); | 799 set_target(*stub); |
| 850 TRACE_IC("KeyedCallIC", key, state, target()); | 800 TRACE_IC("CallIC", key); |
| 851 } | 801 } |
| 852 | 802 |
| 853 Handle<Object> result = GetProperty(isolate(), object, key); | 803 Handle<Object> result = GetProperty(isolate(), object, key); |
| 854 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 804 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 855 | 805 |
| 856 // Make receiver an object if the callee requires it. Strict mode or builtin | 806 // Make receiver an object if the callee requires it. Strict mode or builtin |
| 857 // functions do not wrap the receiver, non-strict functions and objects | 807 // functions do not wrap the receiver, non-strict functions and objects |
| 858 // called as functions do. | 808 // called as functions do. |
| 859 ReceiverToObjectIfRequired(result, object); | 809 ReceiverToObjectIfRequired(result, object); |
| 860 if (result->IsJSFunction()) return *result; | 810 if (result->IsJSFunction()) return *result; |
| 861 | 811 |
| 862 result = TryCallAsFunction(result); | 812 result = TryCallAsFunction(result); |
| 863 if (result->IsJSFunction()) return *result; | 813 if (result->IsJSFunction()) return *result; |
| 864 | 814 |
| 865 return TypeError("property_not_function", object, key); | 815 return TypeError("property_not_function", object, key); |
| 866 } | 816 } |
| 867 | 817 |
| 868 | 818 |
| 869 MaybeObject* LoadIC::Load(State state, | 819 MaybeObject* LoadIC::Load(Handle<Object> object, |
| 870 Handle<Object> object, | |
| 871 Handle<String> name) { | 820 Handle<String> name) { |
| 872 // If the object is undefined or null it's illegal to try to get any | 821 // If the object is undefined or null it's illegal to try to get any |
| 873 // of its properties; throw a TypeError in that case. | 822 // of its properties; throw a TypeError in that case. |
| 874 if (object->IsUndefined() || object->IsNull()) { | 823 if (object->IsUndefined() || object->IsNull()) { |
| 875 return TypeError("non_object_property_load", object, name); | 824 return TypeError("non_object_property_load", object, name); |
| 876 } | 825 } |
| 877 | 826 |
| 878 bool use_ic = FLAG_use_ic; | 827 if (FLAG_use_ic) { |
| 879 | |
| 880 if (use_ic) { | |
| 881 // Use specialized code for getting the length of strings and | 828 // Use specialized code for getting the length of strings and |
| 882 // string wrapper objects. The length property of string wrapper | 829 // string wrapper objects. The length property of string wrapper |
| 883 // objects is read-only and therefore always returns the length of | 830 // objects is read-only and therefore always returns the length of |
| 884 // the underlying string value. See ECMA-262 15.5.5.1. | 831 // the underlying string value. See ECMA-262 15.5.5.1. |
| 885 if (object->IsStringWrapper() && | 832 if (object->IsStringWrapper() && |
| 886 name->Equals(isolate()->heap()->length_string())) { | 833 name->Equals(isolate()->heap()->length_string())) { |
| 887 Handle<Code> stub; | 834 Handle<Code> stub; |
| 888 if (state == UNINITIALIZED) { | 835 if (state() == UNINITIALIZED) { |
| 889 stub = pre_monomorphic_stub(); | 836 stub = pre_monomorphic_stub(); |
| 890 } else if (state == PREMONOMORPHIC || state == MONOMORPHIC) { | 837 } else if (state() == PREMONOMORPHIC || state() == MONOMORPHIC) { |
| 891 StringLengthStub string_length_stub(kind()); | 838 StringLengthStub string_length_stub(kind()); |
| 892 stub = string_length_stub.GetCode(isolate()); | 839 stub = string_length_stub.GetCode(isolate()); |
| 893 } else if (state != MEGAMORPHIC) { | 840 } else if (state() != MEGAMORPHIC) { |
| 894 ASSERT(state != GENERIC); | 841 ASSERT(state() != GENERIC); |
| 895 stub = megamorphic_stub(); | 842 stub = megamorphic_stub(); |
| 896 } | 843 } |
| 897 if (!stub.is_null()) { | 844 if (!stub.is_null()) { |
| 898 set_target(*stub); | 845 set_target(*stub); |
| 899 #ifdef DEBUG | 846 #ifdef DEBUG |
| 900 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /stringwrapper]\n"); | 847 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /stringwrapper]\n"); |
| 901 #endif | 848 #endif |
| 902 } | 849 } |
| 903 // Get the string if we have a string wrapper object. | 850 // Get the string if we have a string wrapper object. |
| 904 String* string = String::cast(JSValue::cast(*object)->value()); | 851 String* string = String::cast(JSValue::cast(*object)->value()); |
| 905 return Smi::FromInt(string->length()); | 852 return Smi::FromInt(string->length()); |
| 906 } | 853 } |
| 907 | 854 |
| 908 // Use specialized code for getting prototype of functions. | 855 // Use specialized code for getting prototype of functions. |
| 909 if (object->IsJSFunction() && | 856 if (object->IsJSFunction() && |
| 910 name->Equals(isolate()->heap()->prototype_string()) && | 857 name->Equals(isolate()->heap()->prototype_string()) && |
| 911 Handle<JSFunction>::cast(object)->should_have_prototype()) { | 858 Handle<JSFunction>::cast(object)->should_have_prototype()) { |
| 912 Handle<Code> stub; | 859 Handle<Code> stub; |
| 913 if (state == UNINITIALIZED) { | 860 if (state() == UNINITIALIZED) { |
| 914 stub = pre_monomorphic_stub(); | 861 stub = pre_monomorphic_stub(); |
| 915 } else if (state == PREMONOMORPHIC) { | 862 } else if (state() == PREMONOMORPHIC) { |
| 916 FunctionPrototypeStub function_prototype_stub(kind()); | 863 FunctionPrototypeStub function_prototype_stub(kind()); |
| 917 stub = function_prototype_stub.GetCode(isolate()); | 864 stub = function_prototype_stub.GetCode(isolate()); |
| 918 } else if (state != MEGAMORPHIC) { | 865 } else if (state() != MEGAMORPHIC) { |
| 919 ASSERT(state != GENERIC); | 866 ASSERT(state() != GENERIC); |
| 920 stub = megamorphic_stub(); | 867 stub = megamorphic_stub(); |
| 921 } | 868 } |
| 922 if (!stub.is_null()) { | 869 if (!stub.is_null()) { |
| 923 set_target(*stub); | 870 set_target(*stub); |
| 924 #ifdef DEBUG | 871 #ifdef DEBUG |
| 925 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); | 872 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); |
| 926 #endif | 873 #endif |
| 927 } | 874 } |
| 928 return *Accessors::FunctionGetPrototype(Handle<JSFunction>::cast(object)); | 875 return *Accessors::FunctionGetPrototype(Handle<JSFunction>::cast(object)); |
| 929 } | 876 } |
| 930 } | 877 } |
| 931 | 878 |
| 932 // Check if the name is trivially convertible to an index and get | 879 // Check if the name is trivially convertible to an index and get |
| 933 // the element or char if so. | 880 // the element or char if so. |
| 934 uint32_t index; | 881 uint32_t index; |
| 935 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) { | 882 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) { |
| 936 // Rewrite to the generic keyed load stub. | 883 // Rewrite to the generic keyed load stub. |
| 937 if (use_ic) set_target(*generic_stub()); | 884 if (FLAG_use_ic) set_target(*generic_stub()); |
| 938 return Runtime::GetElementOrCharAtOrFail(isolate(), object, index); | 885 return Runtime::GetElementOrCharAtOrFail(isolate(), object, index); |
| 939 } | 886 } |
| 940 | 887 |
| 941 if (object->IsJSObject()) { | 888 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic; |
| 942 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 943 if (receiver->map()->is_deprecated()) { | |
| 944 use_ic = false; | |
| 945 JSObject::MigrateInstance(receiver); | |
| 946 } | |
| 947 } | |
| 948 | 889 |
| 949 // Named lookup in the object. | 890 // Named lookup in the object. |
| 950 LookupResult lookup(isolate()); | 891 LookupResult lookup(isolate()); |
| 951 LookupForRead(object, name, &lookup); | 892 LookupForRead(object, name, &lookup); |
| 952 | 893 |
| 953 // If we did not find a property, check if we need to throw an exception. | 894 // If we did not find a property, check if we need to throw an exception. |
| 954 if (!lookup.IsFound()) { | 895 if (!lookup.IsFound()) { |
| 955 if (IsUndeclaredGlobal(object)) { | 896 if (IsUndeclaredGlobal(object)) { |
| 956 return ReferenceError("not_defined", name); | 897 return ReferenceError("not_defined", name); |
| 957 } | 898 } |
| 958 LOG(isolate(), SuspectReadEvent(*name, *object)); | 899 LOG(isolate(), SuspectReadEvent(*name, *object)); |
| 959 } | 900 } |
| 960 | 901 |
| 961 // Update inline cache and stub cache. | 902 // Update inline cache and stub cache. |
| 962 if (use_ic) UpdateCaches(&lookup, state, object, name); | 903 if (use_ic) UpdateCaches(&lookup, object, name); |
| 963 | 904 |
| 964 PropertyAttributes attr; | 905 PropertyAttributes attr; |
| 965 if (lookup.IsInterceptor() || lookup.IsHandler()) { | 906 // Get the property. |
| 966 // Get the property. | 907 Handle<Object> result = |
| 967 Handle<Object> result = | 908 Object::GetProperty(object, object, &lookup, name, &attr); |
| 968 Object::GetProperty(object, object, &lookup, name, &attr); | 909 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 969 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 910 // If the property is not present, check if we need to throw an |
| 970 // If the property is not present, check if we need to throw an | 911 // exception. |
| 971 // exception. | 912 if ((lookup.IsInterceptor() || lookup.IsHandler()) && |
| 972 if (attr == ABSENT && IsUndeclaredGlobal(object)) { | 913 attr == ABSENT && IsUndeclaredGlobal(object)) { |
| 973 return ReferenceError("not_defined", name); | 914 return ReferenceError("not_defined", name); |
| 974 } | |
| 975 return *result; | |
| 976 } | 915 } |
| 977 | 916 return *result; |
| 978 // Get the property. | |
| 979 return Object::GetPropertyOrFail(object, object, &lookup, name, &attr); | |
| 980 } | 917 } |
| 981 | 918 |
| 982 | 919 |
| 983 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, | 920 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, |
| 984 Handle<Map> new_receiver_map) { | 921 Handle<Map> new_receiver_map) { |
| 985 ASSERT(!new_receiver_map.is_null()); | 922 ASSERT(!new_receiver_map.is_null()); |
| 986 for (int current = 0; current < receiver_maps->length(); ++current) { | 923 for (int current = 0; current < receiver_maps->length(); ++current) { |
| 987 if (!receiver_maps->at(current).is_null() && | 924 if (!receiver_maps->at(current).is_null() && |
| 988 receiver_maps->at(current).is_identical_to(new_receiver_map)) { | 925 receiver_maps->at(current).is_identical_to(new_receiver_map)) { |
| 989 return false; | 926 return false; |
| 990 } | 927 } |
| 991 } | 928 } |
| 992 receiver_maps->Add(new_receiver_map); | 929 receiver_maps->Add(new_receiver_map); |
| 993 return true; | 930 return true; |
| 994 } | 931 } |
| 995 | 932 |
| 996 | 933 |
| 997 bool IC::UpdatePolymorphicIC(State state, | 934 bool IC::UpdatePolymorphicIC(Handle<HeapObject> receiver, |
| 998 Handle<HeapObject> receiver, | |
| 999 Handle<String> name, | 935 Handle<String> name, |
| 1000 Handle<Code> code, | 936 Handle<Code> code) { |
| 1001 StrictModeFlag strict_mode) { | 937 if (!code->is_handler()) return false; |
| 1002 if (code->type() == Code::NORMAL) return false; | |
| 1003 if (target()->ic_state() == MONOMORPHIC && | |
| 1004 target()->type() == Code::NORMAL) { | |
| 1005 return false; | |
| 1006 } | |
| 1007 | 938 |
| 1008 MapHandleList receiver_maps; | 939 MapHandleList receiver_maps; |
| 1009 CodeHandleList handlers; | 940 CodeHandleList handlers; |
| 1010 | 941 |
| 1011 int number_of_valid_maps; | 942 int number_of_valid_maps; |
| 1012 int handler_to_overwrite = -1; | 943 int handler_to_overwrite = -1; |
| 1013 Handle<Map> new_receiver_map(receiver->map()); | 944 Handle<Map> new_receiver_map(receiver->map()); |
| 1014 { | 945 { |
| 1015 DisallowHeapAllocation no_gc; | 946 DisallowHeapAllocation no_gc; |
| 1016 target()->FindAllMaps(&receiver_maps); | 947 target()->FindAllMaps(&receiver_maps); |
| 1017 int number_of_maps = receiver_maps.length(); | 948 int number_of_maps = receiver_maps.length(); |
| 1018 number_of_valid_maps = number_of_maps; | 949 number_of_valid_maps = number_of_maps; |
| 1019 | 950 |
| 1020 for (int i = 0; i < number_of_maps; i++) { | 951 for (int i = 0; i < number_of_maps; i++) { |
| 1021 Handle<Map> map = receiver_maps.at(i); | 952 Handle<Map> map = receiver_maps.at(i); |
| 1022 // Filter out deprecated maps to ensure its instances get migrated. | 953 // Filter out deprecated maps to ensure its instances get migrated. |
| 1023 if (map->is_deprecated()) { | 954 if (map->is_deprecated()) { |
| 1024 number_of_valid_maps--; | 955 number_of_valid_maps--; |
| 1025 // If the receiver map is already in the polymorphic IC, this indicates | 956 // If the receiver map is already in the polymorphic IC, this indicates |
| 1026 // there was a prototoype chain failure. In that case, just overwrite the | 957 // there was a prototoype chain failure. In that case, just overwrite the |
| 1027 // handler. | 958 // handler. |
| 1028 } else if (map.is_identical_to(new_receiver_map)) { | 959 } else if (map.is_identical_to(new_receiver_map)) { |
| 1029 number_of_valid_maps--; | 960 number_of_valid_maps--; |
| 1030 handler_to_overwrite = i; | 961 handler_to_overwrite = i; |
| 1031 } | 962 } |
| 1032 } | 963 } |
| 1033 | 964 |
| 1034 if (number_of_valid_maps >= 4) return false; | 965 if (number_of_valid_maps >= 4) return false; |
| 966 if (number_of_maps == 0) return false; |
| 1035 | 967 |
| 1036 // Only allow 0 maps in case target() was reset to UNINITIALIZED by the GC. | 968 if (!target()->FindHandlers(&handlers, receiver_maps.length())) { |
| 1037 // In that case, allow the IC to go back monomorphic. | |
| 1038 if (number_of_maps == 0 && target()->ic_state() != UNINITIALIZED) { | |
| 1039 return false; | 969 return false; |
| 1040 } | 970 } |
| 1041 target()->FindAllCode(&handlers, receiver_maps.length()); | |
| 1042 } | 971 } |
| 1043 | 972 |
| 1044 number_of_valid_maps++; | 973 number_of_valid_maps++; |
| 1045 if (handler_to_overwrite >= 0) { | 974 if (handler_to_overwrite >= 0) { |
| 1046 handlers.Set(handler_to_overwrite, code); | 975 handlers.Set(handler_to_overwrite, code); |
| 1047 } else { | 976 } else { |
| 1048 receiver_maps.Add(new_receiver_map); | 977 receiver_maps.Add(new_receiver_map); |
| 1049 handlers.Add(code); | 978 handlers.Add(code); |
| 1050 } | 979 } |
| 1051 | 980 |
| 1052 Handle<Code> ic = ComputePolymorphicIC( | 981 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC( |
| 1053 &receiver_maps, &handlers, number_of_valid_maps, name, strict_mode); | 982 &receiver_maps, &handlers, number_of_valid_maps, name, strict_mode()); |
| 1054 set_target(*ic); | 983 set_target(*ic); |
| 1055 return true; | 984 return true; |
| 1056 } | 985 } |
| 1057 | 986 |
| 1058 | 987 |
| 1059 Handle<Code> LoadIC::ComputePolymorphicIC(MapHandleList* receiver_maps, | 988 void IC::UpdateMonomorphicIC(Handle<HeapObject> receiver, |
| 1060 CodeHandleList* handlers, | 989 Handle<Code> handler, |
| 1061 int number_of_valid_maps, | 990 Handle<String> name) { |
| 1062 Handle<Name> name, | 991 if (!handler->is_handler()) return set_target(*handler); |
| 1063 StrictModeFlag strict_mode) { | 992 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC( |
| 1064 return isolate()->stub_cache()->ComputePolymorphicLoadIC( | 993 receiver, handler, name, strict_mode()); |
| 1065 receiver_maps, handlers, number_of_valid_maps, name); | |
| 1066 } | |
| 1067 | |
| 1068 | |
| 1069 Handle<Code> StoreIC::ComputePolymorphicIC(MapHandleList* receiver_maps, | |
| 1070 CodeHandleList* handlers, | |
| 1071 int number_of_valid_maps, | |
| 1072 Handle<Name> name, | |
| 1073 StrictModeFlag strict_mode) { | |
| 1074 return isolate()->stub_cache()->ComputePolymorphicStoreIC( | |
| 1075 receiver_maps, handlers, number_of_valid_maps, name, strict_mode); | |
| 1076 } | |
| 1077 | |
| 1078 | |
| 1079 void LoadIC::UpdateMonomorphicIC(Handle<HeapObject> receiver, | |
| 1080 Handle<Code> handler, | |
| 1081 Handle<String> name, | |
| 1082 StrictModeFlag strict_mode) { | |
| 1083 if (handler->is_load_stub()) return set_target(*handler); | |
| 1084 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicLoadIC( | |
| 1085 receiver, handler, name); | |
| 1086 set_target(*ic); | 994 set_target(*ic); |
| 1087 } | 995 } |
| 1088 | 996 |
| 1089 | |
| 1090 void KeyedLoadIC::UpdateMonomorphicIC(Handle<HeapObject> receiver, | |
| 1091 Handle<Code> handler, | |
| 1092 Handle<String> name, | |
| 1093 StrictModeFlag strict_mode) { | |
| 1094 if (handler->is_keyed_load_stub()) return set_target(*handler); | |
| 1095 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicKeyedLoadIC( | |
| 1096 receiver, handler, name); | |
| 1097 set_target(*ic); | |
| 1098 } | |
| 1099 | |
| 1100 | |
| 1101 void StoreIC::UpdateMonomorphicIC(Handle<HeapObject> receiver, | |
| 1102 Handle<Code> handler, | |
| 1103 Handle<String> name, | |
| 1104 StrictModeFlag strict_mode) { | |
| 1105 if (handler->is_store_stub()) return set_target(*handler); | |
| 1106 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicStoreIC( | |
| 1107 receiver, handler, name, strict_mode); | |
| 1108 set_target(*ic); | |
| 1109 } | |
| 1110 | |
| 1111 | |
| 1112 void KeyedStoreIC::UpdateMonomorphicIC(Handle<HeapObject> receiver, | |
| 1113 Handle<Code> handler, | |
| 1114 Handle<String> name, | |
| 1115 StrictModeFlag strict_mode) { | |
| 1116 if (handler->is_keyed_store_stub()) return set_target(*handler); | |
| 1117 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicKeyedStoreIC( | |
| 1118 receiver, handler, name, strict_mode); | |
| 1119 set_target(*ic); | |
| 1120 } | |
| 1121 | |
| 1122 | 997 |
| 1123 void IC::CopyICToMegamorphicCache(Handle<String> name) { | 998 void IC::CopyICToMegamorphicCache(Handle<String> name) { |
| 1124 MapHandleList receiver_maps; | 999 MapHandleList receiver_maps; |
| 1125 CodeHandleList handlers; | 1000 CodeHandleList handlers; |
| 1126 { | 1001 { |
| 1127 DisallowHeapAllocation no_gc; | 1002 DisallowHeapAllocation no_gc; |
| 1128 target()->FindAllMaps(&receiver_maps); | 1003 target()->FindAllMaps(&receiver_maps); |
| 1129 target()->FindAllCode(&handlers, receiver_maps.length()); | 1004 if (!target()->FindHandlers(&handlers, receiver_maps.length())) return; |
| 1130 } | 1005 } |
| 1131 for (int i = 0; i < receiver_maps.length(); i++) { | 1006 for (int i = 0; i < receiver_maps.length(); i++) { |
| 1132 UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i)); | 1007 UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i)); |
| 1133 } | 1008 } |
| 1134 } | 1009 } |
| 1135 | 1010 |
| 1136 | 1011 |
| 1137 bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) { | 1012 bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) { |
| 1138 DisallowHeapAllocation no_allocation; | 1013 DisallowHeapAllocation no_allocation; |
| 1139 | 1014 |
| 1140 Map* current_map = target()->FindFirstMap(); | 1015 Map* current_map = target()->FindFirstMap(); |
| 1141 ElementsKind receiver_elements_kind = receiver_map->elements_kind(); | 1016 ElementsKind receiver_elements_kind = receiver_map->elements_kind(); |
| 1142 bool more_general_transition = | 1017 bool more_general_transition = |
| 1143 IsMoreGeneralElementsKindTransition( | 1018 IsMoreGeneralElementsKindTransition( |
| 1144 current_map->elements_kind(), receiver_elements_kind); | 1019 current_map->elements_kind(), receiver_elements_kind); |
| 1145 Map* transitioned_map = more_general_transition | 1020 Map* transitioned_map = more_general_transition |
| 1146 ? current_map->LookupElementsTransitionMap(receiver_elements_kind) | 1021 ? current_map->LookupElementsTransitionMap(receiver_elements_kind) |
| 1147 : NULL; | 1022 : NULL; |
| 1148 | 1023 |
| 1149 return transitioned_map == receiver_map; | 1024 return transitioned_map == receiver_map; |
| 1150 } | 1025 } |
| 1151 | 1026 |
| 1152 | 1027 |
| 1153 // Since GC may have been invoked, by the time PatchCache is called, |state| is | 1028 void IC::PatchCache(Handle<HeapObject> receiver, |
| 1154 // not necessarily equal to target()->state(). | |
| 1155 void IC::PatchCache(State state, | |
| 1156 StrictModeFlag strict_mode, | |
| 1157 Handle<HeapObject> receiver, | |
| 1158 Handle<String> name, | 1029 Handle<String> name, |
| 1159 Handle<Code> code) { | 1030 Handle<Code> code) { |
| 1160 switch (state) { | 1031 switch (state()) { |
| 1161 case UNINITIALIZED: | 1032 case UNINITIALIZED: |
| 1162 case PREMONOMORPHIC: | 1033 case PREMONOMORPHIC: |
| 1163 case MONOMORPHIC_PROTOTYPE_FAILURE: | 1034 case MONOMORPHIC_PROTOTYPE_FAILURE: |
| 1164 UpdateMonomorphicIC(receiver, code, name, strict_mode); | 1035 UpdateMonomorphicIC(receiver, code, name); |
| 1165 break; | 1036 break; |
| 1166 case MONOMORPHIC: | 1037 case MONOMORPHIC: |
| 1167 // Only move to megamorphic if the target changes. | 1038 // For now, call stubs are allowed to rewrite to the same stub. This |
| 1168 if (target() != *code) { | 1039 // happens e.g., when the field does not contain a function. |
| 1169 if (target()->is_load_stub() || target()->is_store_stub()) { | 1040 ASSERT(target()->is_call_stub() || |
| 1170 bool is_same_handler = false; | 1041 target()->is_keyed_call_stub() || |
| 1171 { | 1042 !target().is_identical_to(code)); |
| 1172 DisallowHeapAllocation no_allocation; | 1043 if (!target()->is_keyed_stub()) { |
| 1173 Code* old_handler = target()->FindFirstCode(); | 1044 bool is_same_handler = false; |
| 1174 is_same_handler = old_handler == *code; | 1045 { |
| 1175 } | 1046 DisallowHeapAllocation no_allocation; |
| 1176 if (is_same_handler | 1047 Code* old_handler = target()->FindFirstHandler(); |
| 1177 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) { | 1048 is_same_handler = old_handler == *code; |
| 1178 UpdateMonomorphicIC(receiver, code, name, strict_mode); | 1049 } |
| 1179 break; | 1050 if (is_same_handler |
| 1180 } | 1051 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) { |
| 1181 if (UpdatePolymorphicIC(state, receiver, name, code, strict_mode)) { | 1052 UpdateMonomorphicIC(receiver, code, name); |
| 1182 break; | 1053 break; |
| 1183 } | 1054 } |
| 1184 | 1055 if (UpdatePolymorphicIC(receiver, name, code)) { |
| 1185 if (target()->type() != Code::NORMAL) { | 1056 break; |
| 1186 CopyICToMegamorphicCache(name); | |
| 1187 } | |
| 1188 } | 1057 } |
| 1189 | 1058 |
| 1190 UpdateMegamorphicCache(receiver->map(), *name, *code); | 1059 CopyICToMegamorphicCache(name); |
| 1191 set_target((strict_mode == kStrictMode) | |
| 1192 ? *megamorphic_stub_strict() | |
| 1193 : *megamorphic_stub()); | |
| 1194 } | 1060 } |
| 1061 |
| 1062 UpdateMegamorphicCache(receiver->map(), *name, *code); |
| 1063 set_target(*megamorphic_stub()); |
| 1195 break; | 1064 break; |
| 1196 case MEGAMORPHIC: | 1065 case MEGAMORPHIC: |
| 1197 // Update the stub cache. | |
| 1198 UpdateMegamorphicCache(receiver->map(), *name, *code); | 1066 UpdateMegamorphicCache(receiver->map(), *name, *code); |
| 1199 break; | 1067 break; |
| 1200 case POLYMORPHIC: | 1068 case POLYMORPHIC: |
| 1201 if (target()->is_load_stub() || target()->is_store_stub()) { | 1069 if (target()->is_keyed_stub()) { |
| 1202 if (UpdatePolymorphicIC(state, receiver, name, code, strict_mode)) { | 1070 // When trying to patch a polymorphic keyed stub with anything other |
| 1071 // than another polymorphic stub, go generic. |
| 1072 set_target(*generic_stub()); |
| 1073 } else { |
| 1074 if (UpdatePolymorphicIC(receiver, name, code)) { |
| 1203 break; | 1075 break; |
| 1204 } | 1076 } |
| 1205 CopyICToMegamorphicCache(name); | 1077 CopyICToMegamorphicCache(name); |
| 1206 UpdateMegamorphicCache(receiver->map(), *name, *code); | 1078 UpdateMegamorphicCache(receiver->map(), *name, *code); |
| 1207 set_target((strict_mode == kStrictMode) | 1079 set_target(*megamorphic_stub()); |
| 1208 ? *megamorphic_stub_strict() | |
| 1209 : *megamorphic_stub()); | |
| 1210 } else { | |
| 1211 // When trying to patch a polymorphic keyed load/store element stub | |
| 1212 // with anything other than another polymorphic stub, go generic. | |
| 1213 set_target((strict_mode == kStrictMode) | |
| 1214 ? *generic_stub_strict() | |
| 1215 : *generic_stub()); | |
| 1216 } | 1080 } |
| 1217 break; | 1081 break; |
| 1218 case DEBUG_STUB: | 1082 case DEBUG_STUB: |
| 1219 break; | 1083 break; |
| 1220 case GENERIC: | 1084 case GENERIC: |
| 1221 UNREACHABLE(); | 1085 UNREACHABLE(); |
| 1222 break; | 1086 break; |
| 1223 } | 1087 } |
| 1224 } | 1088 } |
| 1225 | 1089 |
| 1226 | 1090 |
| 1227 static void GetReceiverMapsForStub(Handle<Code> stub, | |
| 1228 MapHandleList* result) { | |
| 1229 ASSERT(stub->is_inline_cache_stub()); | |
| 1230 switch (stub->ic_state()) { | |
| 1231 case MONOMORPHIC: { | |
| 1232 Map* map = stub->FindFirstMap(); | |
| 1233 if (map != NULL) { | |
| 1234 result->Add(Handle<Map>(map)); | |
| 1235 } | |
| 1236 break; | |
| 1237 } | |
| 1238 case POLYMORPHIC: { | |
| 1239 DisallowHeapAllocation no_allocation; | |
| 1240 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); | |
| 1241 for (RelocIterator it(*stub, mask); !it.done(); it.next()) { | |
| 1242 RelocInfo* info = it.rinfo(); | |
| 1243 Handle<Object> object(info->target_object(), stub->GetIsolate()); | |
| 1244 if (object->IsString()) break; | |
| 1245 ASSERT(object->IsMap()); | |
| 1246 AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object)); | |
| 1247 } | |
| 1248 break; | |
| 1249 } | |
| 1250 case MEGAMORPHIC: | |
| 1251 break; | |
| 1252 case UNINITIALIZED: | |
| 1253 case PREMONOMORPHIC: | |
| 1254 case MONOMORPHIC_PROTOTYPE_FAILURE: | |
| 1255 case GENERIC: | |
| 1256 case DEBUG_STUB: | |
| 1257 UNREACHABLE(); | |
| 1258 break; | |
| 1259 } | |
| 1260 } | |
| 1261 | |
| 1262 | |
| 1263 void LoadIC::UpdateCaches(LookupResult* lookup, | 1091 void LoadIC::UpdateCaches(LookupResult* lookup, |
| 1264 State state, | |
| 1265 Handle<Object> object, | 1092 Handle<Object> object, |
| 1266 Handle<String> name) { | 1093 Handle<String> name) { |
| 1267 // TODO(verwaest): It would be nice to support loading fields from smis as | 1094 // TODO(verwaest): It would be nice to support loading fields from smis as |
| 1268 // well. For now just fail to update the cache. | 1095 // well. For now just fail to update the cache. |
| 1269 if (!object->IsHeapObject()) return; | 1096 if (!object->IsHeapObject()) return; |
| 1270 | 1097 |
| 1271 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object); | 1098 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object); |
| 1272 | 1099 |
| 1273 Handle<Code> code; | 1100 Handle<Code> code; |
| 1274 if (state == UNINITIALIZED) { | 1101 if (state() == UNINITIALIZED) { |
| 1275 // This is the first time we execute this inline cache. | 1102 // This is the first time we execute this inline cache. |
| 1276 // Set the target to the pre monomorphic stub to delay | 1103 // Set the target to the pre monomorphic stub to delay |
| 1277 // setting the monomorphic state. | 1104 // setting the monomorphic state. |
| 1278 code = pre_monomorphic_stub(); | 1105 code = pre_monomorphic_stub(); |
| 1279 } else if (!lookup->IsCacheable()) { | 1106 } else if (!lookup->IsCacheable()) { |
| 1280 // Bail out if the result is not cacheable. | 1107 // Bail out if the result is not cacheable. |
| 1281 code = slow_stub(); | 1108 code = slow_stub(); |
| 1282 } else if (object->IsString() && | 1109 } else if (object->IsString() && |
| 1283 name->Equals(isolate()->heap()->length_string())) { | 1110 name->Equals(isolate()->heap()->length_string())) { |
| 1284 int length_index = String::kLengthOffset / kPointerSize; | 1111 int length_index = String::kLengthOffset / kPointerSize; |
| 1285 if (target()->is_load_stub()) { | 1112 if (target()->is_load_stub()) { |
| 1286 LoadFieldStub stub(true, length_index, Representation::Tagged()); | 1113 LoadFieldStub stub(true, length_index, Representation::Tagged()); |
| 1287 code = stub.GetCode(isolate()); | 1114 code = stub.GetCode(isolate()); |
| 1288 } else { | 1115 } else { |
| 1289 KeyedLoadFieldStub stub(true, length_index, Representation::Tagged()); | 1116 KeyedLoadFieldStub stub(true, length_index, Representation::Tagged()); |
| 1290 code = stub.GetCode(isolate()); | 1117 code = stub.GetCode(isolate()); |
| 1291 } | 1118 } |
| 1292 } else if (!object->IsJSObject()) { | 1119 } else if (!object->IsJSObject()) { |
| 1293 // TODO(jkummerow): It would be nice to support non-JSObjects in | 1120 // TODO(jkummerow): It would be nice to support non-JSObjects in |
| 1294 // ComputeLoadHandler, then we wouldn't need to go generic here. | 1121 // ComputeLoadHandler, then we wouldn't need to go generic here. |
| 1295 code = slow_stub(); | 1122 code = slow_stub(); |
| 1296 } else { | 1123 } else { |
| 1297 code = ComputeLoadHandler(lookup, Handle<JSObject>::cast(receiver), name); | 1124 code = ComputeLoadHandler(lookup, Handle<JSObject>::cast(receiver), name); |
| 1298 if (code.is_null()) code = slow_stub(); | 1125 if (code.is_null()) code = slow_stub(); |
| 1299 } | 1126 } |
| 1300 | 1127 |
| 1301 PatchCache(state, kNonStrictMode, receiver, name, code); | 1128 PatchCache(receiver, name, code); |
| 1302 TRACE_IC("LoadIC", name, state, target()); | 1129 TRACE_IC("LoadIC", name); |
| 1303 } | 1130 } |
| 1304 | 1131 |
| 1305 | 1132 |
| 1306 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) { | 1133 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) { |
| 1307 // Cache code holding map should be consistent with | 1134 // Cache code holding map should be consistent with |
| 1308 // GenerateMonomorphicCacheProbe. | 1135 // GenerateMonomorphicCacheProbe. |
| 1309 isolate()->stub_cache()->Set(name, map, code); | 1136 isolate()->stub_cache()->Set(name, map, code); |
| 1310 } | 1137 } |
| 1311 | 1138 |
| 1312 | 1139 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1415 } | 1242 } |
| 1416 } | 1243 } |
| 1417 } else if (key->IsUndefined()) { | 1244 } else if (key->IsUndefined()) { |
| 1418 key = isolate->factory()->undefined_string(); | 1245 key = isolate->factory()->undefined_string(); |
| 1419 } | 1246 } |
| 1420 return key; | 1247 return key; |
| 1421 } | 1248 } |
| 1422 | 1249 |
| 1423 | 1250 |
| 1424 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) { | 1251 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) { |
| 1425 State ic_state = target()->ic_state(); | |
| 1426 | |
| 1427 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 1252 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
| 1428 // via megamorphic stubs, since they don't have a map in their relocation info | 1253 // via megamorphic stubs, since they don't have a map in their relocation info |
| 1429 // and so the stubs can't be harvested for the object needed for a map check. | 1254 // and so the stubs can't be harvested for the object needed for a map check. |
| 1430 if (target()->type() != Code::NORMAL) { | 1255 if (target()->type() != Code::NORMAL) { |
| 1431 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); | 1256 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); |
| 1432 return generic_stub(); | 1257 return generic_stub(); |
| 1433 } | 1258 } |
| 1434 | 1259 |
| 1435 Handle<Map> receiver_map(receiver->map(), isolate()); | 1260 Handle<Map> receiver_map(receiver->map(), isolate()); |
| 1436 MapHandleList target_receiver_maps; | 1261 MapHandleList target_receiver_maps; |
| 1437 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { | 1262 if (state() == UNINITIALIZED || state() == PREMONOMORPHIC) { |
| 1438 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state | 1263 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state |
| 1439 // yet will do so and stay there. | 1264 // yet will do so and stay there. |
| 1440 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map); | 1265 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map); |
| 1441 } | 1266 } |
| 1442 | 1267 |
| 1443 if (target() == *string_stub()) { | 1268 if (target().is_identical_to(string_stub())) { |
| 1444 target_receiver_maps.Add(isolate()->factory()->string_map()); | 1269 target_receiver_maps.Add(isolate()->factory()->string_map()); |
| 1445 } else { | 1270 } else { |
| 1446 GetReceiverMapsForStub(Handle<Code>(target(), isolate()), | 1271 target()->FindAllMaps(&target_receiver_maps); |
| 1447 &target_receiver_maps); | |
| 1448 if (target_receiver_maps.length() == 0) { | 1272 if (target_receiver_maps.length() == 0) { |
| 1449 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map); | 1273 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map); |
| 1450 } | 1274 } |
| 1451 } | 1275 } |
| 1452 | 1276 |
| 1453 // The first time a receiver is seen that is a transitioned version of the | 1277 // The first time a receiver is seen that is a transitioned version of the |
| 1454 // previous monomorphic receiver type, assume the new ElementsKind is the | 1278 // previous monomorphic receiver type, assume the new ElementsKind is the |
| 1455 // monomorphic type. This benefits global arrays that only transition | 1279 // monomorphic type. This benefits global arrays that only transition |
| 1456 // once, and all call sites accessing them are faster if they remain | 1280 // once, and all call sites accessing them are faster if they remain |
| 1457 // monomorphic. If this optimistic assumption is not true, the IC will | 1281 // monomorphic. If this optimistic assumption is not true, the IC will |
| 1458 // miss again and it will become polymorphic and support both the | 1282 // miss again and it will become polymorphic and support both the |
| 1459 // untransitioned and transitioned maps. | 1283 // untransitioned and transitioned maps. |
| 1460 if (ic_state == MONOMORPHIC && | 1284 if (state() == MONOMORPHIC && |
| 1461 IsMoreGeneralElementsKindTransition( | 1285 IsMoreGeneralElementsKindTransition( |
| 1462 target_receiver_maps.at(0)->elements_kind(), | 1286 target_receiver_maps.at(0)->elements_kind(), |
| 1463 receiver->GetElementsKind())) { | 1287 receiver->GetElementsKind())) { |
| 1464 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map); | 1288 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map); |
| 1465 } | 1289 } |
| 1466 | 1290 |
| 1467 ASSERT(ic_state != GENERIC); | 1291 ASSERT(state() != GENERIC); |
| 1468 | 1292 |
| 1469 // Determine the list of receiver maps that this call site has seen, | 1293 // Determine the list of receiver maps that this call site has seen, |
| 1470 // adding the map that was just encountered. | 1294 // adding the map that was just encountered. |
| 1471 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) { | 1295 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) { |
| 1472 // If the miss wasn't due to an unseen map, a polymorphic stub | 1296 // If the miss wasn't due to an unseen map, a polymorphic stub |
| 1473 // won't help, use the generic stub. | 1297 // won't help, use the generic stub. |
| 1474 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice"); | 1298 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice"); |
| 1475 return generic_stub(); | 1299 return generic_stub(); |
| 1476 } | 1300 } |
| 1477 | 1301 |
| 1478 // If the maximum number of receiver maps has been exceeded, use the generic | 1302 // If the maximum number of receiver maps has been exceeded, use the generic |
| 1479 // version of the IC. | 1303 // version of the IC. |
| 1480 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { | 1304 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { |
| 1481 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded"); | 1305 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded"); |
| 1482 return generic_stub(); | 1306 return generic_stub(); |
| 1483 } | 1307 } |
| 1484 | 1308 |
| 1485 return isolate()->stub_cache()->ComputeLoadElementPolymorphic( | 1309 return isolate()->stub_cache()->ComputeLoadElementPolymorphic( |
| 1486 &target_receiver_maps); | 1310 &target_receiver_maps); |
| 1487 } | 1311 } |
| 1488 | 1312 |
| 1489 | 1313 |
| 1490 MaybeObject* KeyedLoadIC::Load(State state, | 1314 MaybeObject* KeyedLoadIC::Load(Handle<Object> object, |
| 1491 Handle<Object> object, | |
| 1492 Handle<Object> key, | 1315 Handle<Object> key, |
| 1493 ICMissMode miss_mode) { | 1316 ICMissMode miss_mode) { |
| 1317 if (MigrateDeprecated(object)) { |
| 1318 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); |
| 1319 } |
| 1320 |
| 1494 // Check for values that can be converted into an internalized string directly | 1321 // Check for values that can be converted into an internalized string directly |
| 1495 // or is representable as a smi. | 1322 // or is representable as a smi. |
| 1496 key = TryConvertKey(key, isolate()); | 1323 key = TryConvertKey(key, isolate()); |
| 1497 | 1324 |
| 1498 if (key->IsInternalizedString()) { | 1325 if (key->IsInternalizedString()) { |
| 1499 return LoadIC::Load(state, object, Handle<String>::cast(key)); | 1326 return LoadIC::Load(object, Handle<String>::cast(key)); |
| 1500 } | 1327 } |
| 1501 | 1328 |
| 1502 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1329 if (FLAG_use_ic && !object->IsAccessCheckNeeded()) { |
| 1503 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1330 ASSERT(!object->IsJSGlobalProxy()); |
| 1331 Handle<Code> stub = generic_stub(); |
| 1332 if (miss_mode == MISS_FORCE_GENERIC) { |
| 1333 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "force generic"); |
| 1334 } else if (object->IsString() && key->IsNumber()) { |
| 1335 if (state() == UNINITIALIZED) stub = string_stub(); |
| 1336 } else if (object->IsJSObject()) { |
| 1337 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1338 if (receiver->elements()->map() == |
| 1339 isolate()->heap()->non_strict_arguments_elements_map()) { |
| 1340 stub = non_strict_arguments_stub(); |
| 1341 } else if (receiver->HasIndexedInterceptor()) { |
| 1342 stub = indexed_interceptor_stub(); |
| 1343 } else if (!key->ToSmi()->IsFailure() && |
| 1344 (!target().is_identical_to(non_strict_arguments_stub()))) { |
| 1345 stub = LoadElementStub(receiver); |
| 1346 } |
| 1347 } |
| 1504 | 1348 |
| 1505 if (use_ic) { | 1349 ASSERT(!stub.is_null()); |
| 1506 Handle<Code> stub = generic_stub(); | 1350 set_target(*stub); |
| 1507 if (miss_mode != MISS_FORCE_GENERIC) { | 1351 TRACE_IC("LoadIC", key); |
| 1508 if (object->IsString() && key->IsNumber()) { | |
| 1509 if (state == UNINITIALIZED) { | |
| 1510 stub = string_stub(); | |
| 1511 } | |
| 1512 } else if (object->IsJSObject()) { | |
| 1513 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 1514 if (receiver->map()->is_deprecated()) { | |
| 1515 use_ic = false; | |
| 1516 JSObject::MigrateInstance(receiver); | |
| 1517 } | |
| 1518 | |
| 1519 if (receiver->elements()->map() == | |
| 1520 isolate()->heap()->non_strict_arguments_elements_map()) { | |
| 1521 stub = non_strict_arguments_stub(); | |
| 1522 } else if (receiver->HasIndexedInterceptor()) { | |
| 1523 stub = indexed_interceptor_stub(); | |
| 1524 } else if (!key->ToSmi()->IsFailure() && | |
| 1525 (target() != *non_strict_arguments_stub())) { | |
| 1526 stub = LoadElementStub(receiver); | |
| 1527 } | |
| 1528 } | |
| 1529 } else { | |
| 1530 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "force generic"); | |
| 1531 } | |
| 1532 if (use_ic) { | |
| 1533 ASSERT(!stub.is_null()); | |
| 1534 set_target(*stub); | |
| 1535 TRACE_IC("KeyedLoadIC", key, state, target()); | |
| 1536 } | |
| 1537 } | 1352 } |
| 1538 | 1353 |
| 1539 | 1354 |
| 1540 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); | 1355 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); |
| 1541 } | 1356 } |
| 1542 | 1357 |
| 1543 | 1358 |
| 1544 Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, | 1359 Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, |
| 1545 Handle<JSObject> receiver, | 1360 Handle<JSObject> receiver, |
| 1546 Handle<String> name) { | 1361 Handle<String> name) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1599 return generic_stub(); | 1414 return generic_stub(); |
| 1600 } | 1415 } |
| 1601 return Handle<Code>::null(); | 1416 return Handle<Code>::null(); |
| 1602 } | 1417 } |
| 1603 | 1418 |
| 1604 | 1419 |
| 1605 static bool LookupForWrite(Handle<JSObject> receiver, | 1420 static bool LookupForWrite(Handle<JSObject> receiver, |
| 1606 Handle<String> name, | 1421 Handle<String> name, |
| 1607 Handle<Object> value, | 1422 Handle<Object> value, |
| 1608 LookupResult* lookup, | 1423 LookupResult* lookup, |
| 1609 IC::State* state) { | 1424 IC* ic) { |
| 1610 Handle<JSObject> holder = receiver; | 1425 Handle<JSObject> holder = receiver; |
| 1611 receiver->Lookup(*name, lookup); | 1426 receiver->Lookup(*name, lookup); |
| 1612 if (lookup->IsFound()) { | 1427 if (lookup->IsFound()) { |
| 1613 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; | 1428 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; |
| 1614 | 1429 |
| 1615 if (lookup->holder() == *receiver) { | 1430 if (lookup->holder() == *receiver) { |
| 1616 if (lookup->IsInterceptor() && | 1431 if (lookup->IsInterceptor() && !HasInterceptorSetter(*receiver)) { |
| 1617 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { | |
| 1618 receiver->LocalLookupRealNamedProperty(*name, lookup); | 1432 receiver->LocalLookupRealNamedProperty(*name, lookup); |
| 1619 return lookup->IsFound() && | 1433 return lookup->IsFound() && |
| 1620 !lookup->IsReadOnly() && | 1434 !lookup->IsReadOnly() && |
| 1621 lookup->CanHoldValue(value) && | 1435 lookup->CanHoldValue(value) && |
| 1622 lookup->IsCacheable(); | 1436 lookup->IsCacheable(); |
| 1623 } | 1437 } |
| 1624 return lookup->CanHoldValue(value); | 1438 return lookup->CanHoldValue(value); |
| 1625 } | 1439 } |
| 1626 | 1440 |
| 1627 if (lookup->IsPropertyCallbacks()) return true; | 1441 if (lookup->IsPropertyCallbacks()) return true; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1653 ASSERT(!receiver->map()->is_deprecated()); | 1467 ASSERT(!receiver->map()->is_deprecated()); |
| 1654 if (!value->FitsRepresentation(target_details.representation())) { | 1468 if (!value->FitsRepresentation(target_details.representation())) { |
| 1655 Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map())); | 1469 Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map())); |
| 1656 Map::GeneralizeRepresentation( | 1470 Map::GeneralizeRepresentation( |
| 1657 target, target->LastAdded(), | 1471 target, target->LastAdded(), |
| 1658 value->OptimalRepresentation(), FORCE_FIELD); | 1472 value->OptimalRepresentation(), FORCE_FIELD); |
| 1659 // Lookup the transition again since the transition tree may have changed | 1473 // Lookup the transition again since the transition tree may have changed |
| 1660 // entirely by the migration above. | 1474 // entirely by the migration above. |
| 1661 receiver->map()->LookupTransition(*holder, *name, lookup); | 1475 receiver->map()->LookupTransition(*holder, *name, lookup); |
| 1662 if (!lookup->IsTransition()) return false; | 1476 if (!lookup->IsTransition()) return false; |
| 1663 *state = MONOMORPHIC_PROTOTYPE_FAILURE; | 1477 ic->MarkMonomorphicPrototypeFailure(); |
| 1664 } | 1478 } |
| 1665 return true; | 1479 return true; |
| 1666 } | 1480 } |
| 1667 | 1481 |
| 1668 | 1482 |
| 1669 MaybeObject* StoreIC::Store(State state, | 1483 MaybeObject* StoreIC::Store(Handle<Object> object, |
| 1670 StrictModeFlag strict_mode, | |
| 1671 Handle<Object> object, | |
| 1672 Handle<String> name, | 1484 Handle<String> name, |
| 1673 Handle<Object> value, | 1485 Handle<Object> value, |
| 1674 JSReceiver::StoreFromKeyed store_mode) { | 1486 JSReceiver::StoreFromKeyed store_mode) { |
| 1675 // Handle proxies. | 1487 if (MigrateDeprecated(object) || object->IsJSProxy()) { |
| 1676 if (object->IsJSProxy()) { | |
| 1677 Handle<Object> result = JSReceiver::SetProperty( | 1488 Handle<Object> result = JSReceiver::SetProperty( |
| 1678 Handle<JSReceiver>::cast(object), name, value, NONE, strict_mode); | 1489 Handle<JSReceiver>::cast(object), name, value, NONE, strict_mode()); |
| 1679 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 1490 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 1680 return *result; | 1491 return *result; |
| 1681 } | 1492 } |
| 1682 | 1493 |
| 1683 // If the object is undefined or null it's illegal to try to set any | 1494 // If the object is undefined or null it's illegal to try to set any |
| 1684 // properties on it; throw a TypeError in that case. | 1495 // properties on it; throw a TypeError in that case. |
| 1685 if (object->IsUndefined() || object->IsNull()) { | 1496 if (object->IsUndefined() || object->IsNull()) { |
| 1686 return TypeError("non_object_property_store", object, name); | 1497 return TypeError("non_object_property_store", object, name); |
| 1687 } | 1498 } |
| 1688 | 1499 |
| 1689 // The length property of string values is read-only. Throw in strict mode. | 1500 // The length property of string values is read-only. Throw in strict mode. |
| 1690 if (strict_mode == kStrictMode && object->IsString() && | 1501 if (strict_mode() == kStrictMode && object->IsString() && |
| 1691 name->Equals(isolate()->heap()->length_string())) { | 1502 name->Equals(isolate()->heap()->length_string())) { |
| 1692 return TypeError("strict_read_only_property", object, name); | 1503 return TypeError("strict_read_only_property", object, name); |
| 1693 } | 1504 } |
| 1694 | 1505 |
| 1695 // Ignore other stores where the receiver is not a JSObject. | 1506 // Ignore other stores where the receiver is not a JSObject. |
| 1696 // TODO(1475): Must check prototype chains of object wrappers. | 1507 // TODO(1475): Must check prototype chains of object wrappers. |
| 1697 if (!object->IsJSObject()) return *value; | 1508 if (!object->IsJSObject()) return *value; |
| 1698 | 1509 |
| 1699 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1510 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1700 | 1511 |
| 1701 bool use_ic = FLAG_use_ic; | |
| 1702 if (receiver->map()->is_deprecated()) { | |
| 1703 use_ic = false; | |
| 1704 JSObject::MigrateInstance(receiver); | |
| 1705 } | |
| 1706 | |
| 1707 // Check if the given name is an array index. | 1512 // Check if the given name is an array index. |
| 1708 uint32_t index; | 1513 uint32_t index; |
| 1709 if (name->AsArrayIndex(&index)) { | 1514 if (name->AsArrayIndex(&index)) { |
| 1710 Handle<Object> result = | 1515 Handle<Object> result = |
| 1711 JSObject::SetElement(receiver, index, value, NONE, strict_mode); | 1516 JSObject::SetElement(receiver, index, value, NONE, strict_mode()); |
| 1712 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 1517 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 1713 return *value; | 1518 return *value; |
| 1714 } | 1519 } |
| 1715 | 1520 |
| 1716 // Observed objects are always modified through the runtime. | 1521 // Observed objects are always modified through the runtime. |
| 1717 if (FLAG_harmony_observation && receiver->map()->is_observed()) { | 1522 if (FLAG_harmony_observation && receiver->map()->is_observed()) { |
| 1718 Handle<Object> result = JSReceiver::SetProperty( | 1523 Handle<Object> result = JSReceiver::SetProperty( |
| 1719 receiver, name, value, NONE, strict_mode, store_mode); | 1524 receiver, name, value, NONE, strict_mode(), store_mode); |
| 1720 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 1525 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 1721 return *result; | 1526 return *result; |
| 1722 } | 1527 } |
| 1723 | 1528 |
| 1724 // Use specialized code for setting the length of arrays with fast | 1529 // Use specialized code for setting the length of arrays with fast |
| 1725 // properties. Slow properties might indicate redefinition of the length | 1530 // properties. Slow properties might indicate redefinition of the length |
| 1726 // property. Note that when redefined using Object.freeze, it's possible | 1531 // property. Note that when redefined using Object.freeze, it's possible |
| 1727 // to have fast properties but a read-only length. | 1532 // to have fast properties but a read-only length. |
| 1728 if (use_ic && | 1533 if (FLAG_use_ic && |
| 1729 receiver->IsJSArray() && | 1534 receiver->IsJSArray() && |
| 1730 name->Equals(isolate()->heap()->length_string()) && | 1535 name->Equals(isolate()->heap()->length_string()) && |
| 1731 Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() && | 1536 Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() && |
| 1732 receiver->HasFastProperties() && | 1537 receiver->HasFastProperties() && |
| 1733 !receiver->map()->is_frozen()) { | 1538 !receiver->map()->is_frozen()) { |
| 1734 Handle<Code> stub = | 1539 Handle<Code> stub = |
| 1735 StoreArrayLengthStub(kind(), strict_mode).GetCode(isolate()); | 1540 StoreArrayLengthStub(kind(), strict_mode()).GetCode(isolate()); |
| 1736 set_target(*stub); | 1541 set_target(*stub); |
| 1737 TRACE_IC("StoreIC", name, state, *stub); | 1542 TRACE_IC("StoreIC", name); |
| 1738 Handle<Object> result = JSReceiver::SetProperty( | 1543 Handle<Object> result = JSReceiver::SetProperty( |
| 1739 receiver, name, value, NONE, strict_mode, store_mode); | 1544 receiver, name, value, NONE, strict_mode(), store_mode); |
| 1740 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 1545 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 1741 return *result; | 1546 return *result; |
| 1742 } | 1547 } |
| 1743 | 1548 |
| 1744 if (receiver->IsJSGlobalProxy()) { | 1549 if (receiver->IsJSGlobalProxy()) { |
| 1745 if (use_ic && kind() != Code::KEYED_STORE_IC) { | 1550 if (FLAG_use_ic && kind() != Code::KEYED_STORE_IC) { |
| 1746 // Generate a generic stub that goes to the runtime when we see a global | 1551 // Generate a generic stub that goes to the runtime when we see a global |
| 1747 // proxy as receiver. | 1552 // proxy as receiver. |
| 1748 Handle<Code> stub = (strict_mode == kStrictMode) | 1553 Handle<Code> stub = global_proxy_stub(); |
| 1749 ? global_proxy_stub_strict() | |
| 1750 : global_proxy_stub(); | |
| 1751 set_target(*stub); | 1554 set_target(*stub); |
| 1752 TRACE_IC("StoreIC", name, state, *stub); | 1555 TRACE_IC("StoreIC", name); |
| 1753 } | 1556 } |
| 1754 Handle<Object> result = JSReceiver::SetProperty( | 1557 Handle<Object> result = JSReceiver::SetProperty( |
| 1755 receiver, name, value, NONE, strict_mode, store_mode); | 1558 receiver, name, value, NONE, strict_mode(), store_mode); |
| 1756 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 1559 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 1757 return *result; | 1560 return *result; |
| 1758 } | 1561 } |
| 1759 | 1562 |
| 1760 LookupResult lookup(isolate()); | 1563 LookupResult lookup(isolate()); |
| 1761 bool can_store = LookupForWrite(receiver, name, value, &lookup, &state); | 1564 bool can_store = LookupForWrite(receiver, name, value, &lookup, this); |
| 1762 if (!can_store && | 1565 if (!can_store && |
| 1763 strict_mode == kStrictMode && | 1566 strict_mode() == kStrictMode && |
| 1764 !(lookup.IsProperty() && lookup.IsReadOnly()) && | 1567 !(lookup.IsProperty() && lookup.IsReadOnly()) && |
| 1765 IsUndeclaredGlobal(object)) { | 1568 IsUndeclaredGlobal(object)) { |
| 1766 // Strict mode doesn't allow setting non-existent global property. | 1569 // Strict mode doesn't allow setting non-existent global property. |
| 1767 return ReferenceError("not_defined", name); | 1570 return ReferenceError("not_defined", name); |
| 1768 } | 1571 } |
| 1769 if (use_ic) { | 1572 if (FLAG_use_ic) { |
| 1770 if (state == UNINITIALIZED) { | 1573 if (state() == UNINITIALIZED) { |
| 1771 Handle<Code> stub = (strict_mode == kStrictMode) | 1574 Handle<Code> stub = pre_monomorphic_stub(); |
| 1772 ? pre_monomorphic_stub_strict() | |
| 1773 : pre_monomorphic_stub(); | |
| 1774 set_target(*stub); | 1575 set_target(*stub); |
| 1775 TRACE_IC("StoreIC", name, state, *stub); | 1576 TRACE_IC("StoreIC", name); |
| 1776 } else if (can_store) { | 1577 } else if (can_store) { |
| 1777 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); | 1578 UpdateCaches(&lookup, receiver, name, value); |
| 1778 } else if (!name->IsCacheable(isolate()) || | 1579 } else if (!name->IsCacheable(isolate()) || |
| 1779 lookup.IsNormal() || | 1580 lookup.IsNormal() || |
| 1780 (lookup.IsField() && lookup.CanHoldValue(value))) { | 1581 (lookup.IsField() && lookup.CanHoldValue(value))) { |
| 1781 Handle<Code> stub = (strict_mode == kStrictMode) ? generic_stub_strict() | 1582 Handle<Code> stub = generic_stub(); |
| 1782 : generic_stub(); | |
| 1783 set_target(*stub); | 1583 set_target(*stub); |
| 1784 } | 1584 } |
| 1785 } | 1585 } |
| 1786 | 1586 |
| 1787 // Set the property. | 1587 // Set the property. |
| 1788 Handle<Object> result = JSReceiver::SetProperty( | 1588 Handle<Object> result = JSReceiver::SetProperty( |
| 1789 receiver, name, value, NONE, strict_mode, store_mode); | 1589 receiver, name, value, NONE, strict_mode(), store_mode); |
| 1790 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 1590 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 1791 return *result; | 1591 return *result; |
| 1792 } | 1592 } |
| 1793 | 1593 |
| 1794 | 1594 |
| 1795 void StoreIC::UpdateCaches(LookupResult* lookup, | 1595 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 1796 State state, | |
| 1797 StrictModeFlag strict_mode, | |
| 1798 Handle<JSObject> receiver, | 1596 Handle<JSObject> receiver, |
| 1799 Handle<String> name, | 1597 Handle<String> name, |
| 1800 Handle<Object> value) { | 1598 Handle<Object> value) { |
| 1801 ASSERT(!receiver->IsJSGlobalProxy()); | 1599 ASSERT(!receiver->IsJSGlobalProxy()); |
| 1802 ASSERT(lookup->IsFound()); | 1600 ASSERT(lookup->IsFound()); |
| 1803 | 1601 |
| 1804 // These are not cacheable, so we never see such LookupResults here. | 1602 // These are not cacheable, so we never see such LookupResults here. |
| 1805 ASSERT(!lookup->IsHandler()); | 1603 ASSERT(!lookup->IsHandler()); |
| 1806 | 1604 |
| 1807 Handle<Code> code = ComputeStoreMonomorphic( | 1605 Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value); |
| 1808 lookup, strict_mode, receiver, name, value); | |
| 1809 if (code.is_null()) { | 1606 if (code.is_null()) { |
| 1810 Handle<Code> stub = strict_mode == kStrictMode | 1607 set_target(*generic_stub()); |
| 1811 ? generic_stub_strict() : generic_stub(); | |
| 1812 set_target(*stub); | |
| 1813 return; | 1608 return; |
| 1814 } | 1609 } |
| 1815 | 1610 |
| 1816 PatchCache(state, strict_mode, receiver, name, code); | 1611 PatchCache(receiver, name, code); |
| 1817 TRACE_IC("StoreIC", name, state, target()); | 1612 TRACE_IC("StoreIC", name); |
| 1818 } | 1613 } |
| 1819 | 1614 |
| 1820 | 1615 |
| 1821 Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, | 1616 Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup, |
| 1822 StrictModeFlag strict_mode, | 1617 Handle<JSObject> receiver, |
| 1823 Handle<JSObject> receiver, | 1618 Handle<String> name, |
| 1824 Handle<String> name, | 1619 Handle<Object> value) { |
| 1825 Handle<Object> value) { | |
| 1826 Handle<JSObject> holder(lookup->holder()); | 1620 Handle<JSObject> holder(lookup->holder()); |
| 1827 switch (lookup->type()) { | 1621 switch (lookup->type()) { |
| 1828 case FIELD: | 1622 case FIELD: |
| 1829 return isolate()->stub_cache()->ComputeStoreField( | 1623 return isolate()->stub_cache()->ComputeStoreField( |
| 1830 name, receiver, lookup, strict_mode); | 1624 name, receiver, lookup, strict_mode()); |
| 1831 case NORMAL: | 1625 case NORMAL: |
| 1832 if (receiver->IsGlobalObject()) { | 1626 if (receiver->IsGlobalObject()) { |
| 1833 // The stub generated for the global object picks the value directly | 1627 // The stub generated for the global object picks the value directly |
| 1834 // from the property cell. So the property must be directly on the | 1628 // from the property cell. So the property must be directly on the |
| 1835 // global object. | 1629 // global object. |
| 1836 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1630 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1837 Handle<PropertyCell> cell( | 1631 Handle<PropertyCell> cell( |
| 1838 global->GetPropertyCell(lookup), isolate()); | 1632 global->GetPropertyCell(lookup), isolate()); |
| 1839 return isolate()->stub_cache()->ComputeStoreGlobal( | 1633 return isolate()->stub_cache()->ComputeStoreGlobal( |
| 1840 name, global, cell, value, strict_mode); | 1634 name, global, cell, value, strict_mode()); |
| 1841 } | 1635 } |
| 1842 ASSERT(holder.is_identical_to(receiver)); | 1636 ASSERT(holder.is_identical_to(receiver)); |
| 1843 return isolate()->stub_cache()->ComputeStoreNormal(strict_mode); | 1637 return isolate()->stub_cache()->ComputeStoreNormal(strict_mode()); |
| 1844 case CALLBACKS: { | 1638 case CALLBACKS: { |
| 1845 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1639 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
| 1846 if (callback->IsExecutableAccessorInfo()) { | 1640 if (callback->IsExecutableAccessorInfo()) { |
| 1847 Handle<ExecutableAccessorInfo> info = | 1641 Handle<ExecutableAccessorInfo> info = |
| 1848 Handle<ExecutableAccessorInfo>::cast(callback); | 1642 Handle<ExecutableAccessorInfo>::cast(callback); |
| 1849 if (v8::ToCData<Address>(info->setter()) == 0) break; | 1643 if (v8::ToCData<Address>(info->setter()) == 0) break; |
| 1850 if (!holder->HasFastProperties()) break; | 1644 if (!holder->HasFastProperties()) break; |
| 1851 if (!info->IsCompatibleReceiver(*receiver)) break; | 1645 if (!info->IsCompatibleReceiver(*receiver)) break; |
| 1852 return isolate()->stub_cache()->ComputeStoreCallback( | 1646 return isolate()->stub_cache()->ComputeStoreCallback( |
| 1853 name, receiver, holder, info, strict_mode); | 1647 name, receiver, holder, info, strict_mode()); |
| 1854 } else if (callback->IsAccessorPair()) { | 1648 } else if (callback->IsAccessorPair()) { |
| 1855 Handle<Object> setter( | 1649 Handle<Object> setter( |
| 1856 Handle<AccessorPair>::cast(callback)->setter(), isolate()); | 1650 Handle<AccessorPair>::cast(callback)->setter(), isolate()); |
| 1857 if (!setter->IsJSFunction()) break; | 1651 if (!setter->IsJSFunction()) break; |
| 1858 if (holder->IsGlobalObject()) break; | 1652 if (holder->IsGlobalObject()) break; |
| 1859 if (!holder->HasFastProperties()) break; | 1653 if (!holder->HasFastProperties()) break; |
| 1860 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); | 1654 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); |
| 1861 CallOptimization call_optimization(function); | 1655 CallOptimization call_optimization(function); |
| 1862 if (call_optimization.is_simple_api_call() && | 1656 if (call_optimization.is_simple_api_call() && |
| 1863 call_optimization.IsCompatibleReceiver(*receiver)) { | 1657 call_optimization.IsCompatibleReceiver(*receiver)) { |
| 1864 return isolate()->stub_cache()->ComputeStoreCallback( | 1658 return isolate()->stub_cache()->ComputeStoreCallback( |
| 1865 name, receiver, holder, call_optimization, strict_mode); | 1659 name, receiver, holder, call_optimization, strict_mode()); |
| 1866 } | 1660 } |
| 1867 return isolate()->stub_cache()->ComputeStoreViaSetter( | 1661 return isolate()->stub_cache()->ComputeStoreViaSetter( |
| 1868 name, receiver, holder, Handle<JSFunction>::cast(setter), | 1662 name, receiver, holder, Handle<JSFunction>::cast(setter), |
| 1869 strict_mode); | 1663 strict_mode()); |
| 1870 } | 1664 } |
| 1871 // TODO(dcarney): Handle correctly. | 1665 // TODO(dcarney): Handle correctly. |
| 1872 if (callback->IsDeclaredAccessorInfo()) break; | 1666 if (callback->IsDeclaredAccessorInfo()) break; |
| 1873 ASSERT(callback->IsForeign()); | 1667 ASSERT(callback->IsForeign()); |
| 1874 // No IC support for old-style native accessors. | 1668 // No IC support for old-style native accessors. |
| 1875 break; | 1669 break; |
| 1876 } | 1670 } |
| 1877 case INTERCEPTOR: | 1671 case INTERCEPTOR: |
| 1878 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); | 1672 ASSERT(HasInterceptorSetter(*receiver)); |
| 1879 return isolate()->stub_cache()->ComputeStoreInterceptor( | 1673 return isolate()->stub_cache()->ComputeStoreInterceptor( |
| 1880 name, receiver, strict_mode); | 1674 name, receiver, strict_mode()); |
| 1881 case CONSTANT: | 1675 case CONSTANT: |
| 1882 break; | 1676 break; |
| 1883 case TRANSITION: { | 1677 case TRANSITION: { |
| 1884 // Explicitly pass in the receiver map since LookupForWrite may have | 1678 // Explicitly pass in the receiver map since LookupForWrite may have |
| 1885 // stored something else than the receiver in the holder. | 1679 // stored something else than the receiver in the holder. |
| 1886 Handle<Map> transition( | 1680 Handle<Map> transition( |
| 1887 lookup->GetTransitionTarget(receiver->map()), isolate()); | 1681 lookup->GetTransitionTarget(receiver->map()), isolate()); |
| 1888 int descriptor = transition->LastAdded(); | 1682 int descriptor = transition->LastAdded(); |
| 1889 | 1683 |
| 1890 DescriptorArray* target_descriptors = transition->instance_descriptors(); | 1684 DescriptorArray* target_descriptors = transition->instance_descriptors(); |
| 1891 PropertyDetails details = target_descriptors->GetDetails(descriptor); | 1685 PropertyDetails details = target_descriptors->GetDetails(descriptor); |
| 1892 | 1686 |
| 1893 if (details.type() == CALLBACKS || details.attributes() != NONE) break; | 1687 if (details.type() == CALLBACKS || details.attributes() != NONE) break; |
| 1894 | 1688 |
| 1895 return isolate()->stub_cache()->ComputeStoreTransition( | 1689 return isolate()->stub_cache()->ComputeStoreTransition( |
| 1896 name, receiver, lookup, transition, strict_mode); | 1690 name, receiver, lookup, transition, strict_mode()); |
| 1897 } | 1691 } |
| 1898 case NONEXISTENT: | 1692 case NONEXISTENT: |
| 1899 case HANDLER: | 1693 case HANDLER: |
| 1900 UNREACHABLE(); | 1694 UNREACHABLE(); |
| 1901 break; | 1695 break; |
| 1902 } | 1696 } |
| 1903 return Handle<Code>::null(); | 1697 return Handle<Code>::null(); |
| 1904 } | 1698 } |
| 1905 | 1699 |
| 1906 | 1700 |
| 1907 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, | 1701 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, |
| 1908 KeyedAccessStoreMode store_mode, | 1702 KeyedAccessStoreMode store_mode) { |
| 1909 StrictModeFlag strict_mode) { | |
| 1910 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 1703 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
| 1911 // via megamorphic stubs, since they don't have a map in their relocation info | 1704 // via megamorphic stubs, since they don't have a map in their relocation info |
| 1912 // and so the stubs can't be harvested for the object needed for a map check. | 1705 // and so the stubs can't be harvested for the object needed for a map check. |
| 1913 if (target()->type() != Code::NORMAL) { | 1706 if (target()->type() != Code::NORMAL) { |
| 1914 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); | 1707 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); |
| 1915 return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub(); | 1708 return generic_stub(); |
| 1916 } | 1709 } |
| 1917 | 1710 |
| 1918 State ic_state = target()->ic_state(); | |
| 1919 Handle<Map> receiver_map(receiver->map(), isolate()); | 1711 Handle<Map> receiver_map(receiver->map(), isolate()); |
| 1920 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { | 1712 if (state() == UNINITIALIZED || state() == PREMONOMORPHIC) { |
| 1921 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state | 1713 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state |
| 1922 // yet will do so and stay there. | 1714 // yet will do so and stay there. |
| 1923 Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, store_mode); | 1715 Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, store_mode); |
| 1924 store_mode = GetNonTransitioningStoreMode(store_mode); | 1716 store_mode = GetNonTransitioningStoreMode(store_mode); |
| 1925 return isolate()->stub_cache()->ComputeKeyedStoreElement( | 1717 return isolate()->stub_cache()->ComputeKeyedStoreElement( |
| 1926 monomorphic_map, strict_mode, store_mode); | 1718 monomorphic_map, strict_mode(), store_mode); |
| 1927 } | 1719 } |
| 1928 | 1720 |
| 1929 MapHandleList target_receiver_maps; | 1721 MapHandleList target_receiver_maps; |
| 1930 target()->FindAllMaps(&target_receiver_maps); | 1722 target()->FindAllMaps(&target_receiver_maps); |
| 1931 if (target_receiver_maps.length() == 0) { | 1723 if (target_receiver_maps.length() == 0) { |
| 1932 // In the case that there is a non-map-specific IC is installed (e.g. keyed | 1724 // In the case that there is a non-map-specific IC is installed (e.g. keyed |
| 1933 // stores into properties in dictionary mode), then there will be not | 1725 // stores into properties in dictionary mode), then there will be not |
| 1934 // receiver maps in the target. | 1726 // receiver maps in the target. |
| 1935 return strict_mode == kStrictMode | 1727 return generic_stub(); |
| 1936 ? generic_stub_strict() | |
| 1937 : generic_stub(); | |
| 1938 } | 1728 } |
| 1939 | 1729 |
| 1940 // There are several special cases where an IC that is MONOMORPHIC can still | 1730 // There are several special cases where an IC that is MONOMORPHIC can still |
| 1941 // transition to a different GetNonTransitioningStoreMode IC that handles a | 1731 // transition to a different GetNonTransitioningStoreMode IC that handles a |
| 1942 // superset of the original IC. Handle those here if the receiver map hasn't | 1732 // superset of the original IC. Handle those here if the receiver map hasn't |
| 1943 // changed or it has transitioned to a more general kind. | 1733 // changed or it has transitioned to a more general kind. |
| 1944 KeyedAccessStoreMode old_store_mode = | 1734 KeyedAccessStoreMode old_store_mode = |
| 1945 Code::GetKeyedAccessStoreMode(target()->extra_ic_state()); | 1735 Code::GetKeyedAccessStoreMode(target()->extra_ic_state()); |
| 1946 Handle<Map> previous_receiver_map = target_receiver_maps.at(0); | 1736 Handle<Map> previous_receiver_map = target_receiver_maps.at(0); |
| 1947 if (ic_state == MONOMORPHIC) { | 1737 if (state() == MONOMORPHIC) { |
| 1948 // If the "old" and "new" maps are in the same elements map family, stay | 1738 // If the "old" and "new" maps are in the same elements map family, stay |
| 1949 // MONOMORPHIC and use the map for the most generic ElementsKind. | 1739 // MONOMORPHIC and use the map for the most generic ElementsKind. |
| 1950 Handle<Map> transitioned_receiver_map = receiver_map; | 1740 Handle<Map> transitioned_receiver_map = receiver_map; |
| 1951 if (IsTransitionStoreMode(store_mode)) { | 1741 if (IsTransitionStoreMode(store_mode)) { |
| 1952 transitioned_receiver_map = | 1742 transitioned_receiver_map = |
| 1953 ComputeTransitionedMap(receiver, store_mode); | 1743 ComputeTransitionedMap(receiver, store_mode); |
| 1954 } | 1744 } |
| 1955 if (IsTransitionedMapOfMonomorphicTarget(*transitioned_receiver_map)) { | 1745 if (IsTransitionedMapOfMonomorphicTarget(*transitioned_receiver_map)) { |
| 1956 // Element family is the same, use the "worst" case map. | 1746 // Element family is the same, use the "worst" case map. |
| 1957 store_mode = GetNonTransitioningStoreMode(store_mode); | 1747 store_mode = GetNonTransitioningStoreMode(store_mode); |
| 1958 return isolate()->stub_cache()->ComputeKeyedStoreElement( | 1748 return isolate()->stub_cache()->ComputeKeyedStoreElement( |
| 1959 transitioned_receiver_map, strict_mode, store_mode); | 1749 transitioned_receiver_map, strict_mode(), store_mode); |
| 1960 } else if (*previous_receiver_map == receiver->map() && | 1750 } else if (*previous_receiver_map == receiver->map() && |
| 1961 old_store_mode == STANDARD_STORE && | 1751 old_store_mode == STANDARD_STORE && |
| 1962 (IsGrowStoreMode(store_mode) || | 1752 (IsGrowStoreMode(store_mode) || |
| 1963 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || | 1753 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || |
| 1964 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) { | 1754 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) { |
| 1965 // A "normal" IC that handles stores can switch to a version that can | 1755 // A "normal" IC that handles stores can switch to a version that can |
| 1966 // grow at the end of the array, handle OOB accesses or copy COW arrays | 1756 // grow at the end of the array, handle OOB accesses or copy COW arrays |
| 1967 // and still stay MONOMORPHIC. | 1757 // and still stay MONOMORPHIC. |
| 1968 return isolate()->stub_cache()->ComputeKeyedStoreElement( | 1758 return isolate()->stub_cache()->ComputeKeyedStoreElement( |
| 1969 receiver_map, strict_mode, store_mode); | 1759 receiver_map, strict_mode(), store_mode); |
| 1970 } | 1760 } |
| 1971 } | 1761 } |
| 1972 | 1762 |
| 1973 ASSERT(ic_state != GENERIC); | 1763 ASSERT(state() != GENERIC); |
| 1974 | 1764 |
| 1975 bool map_added = | 1765 bool map_added = |
| 1976 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); | 1766 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); |
| 1977 | 1767 |
| 1978 if (IsTransitionStoreMode(store_mode)) { | 1768 if (IsTransitionStoreMode(store_mode)) { |
| 1979 Handle<Map> transitioned_receiver_map = | 1769 Handle<Map> transitioned_receiver_map = |
| 1980 ComputeTransitionedMap(receiver, store_mode); | 1770 ComputeTransitionedMap(receiver, store_mode); |
| 1981 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, | 1771 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, |
| 1982 transitioned_receiver_map); | 1772 transitioned_receiver_map); |
| 1983 } | 1773 } |
| 1984 | 1774 |
| 1985 if (!map_added) { | 1775 if (!map_added) { |
| 1986 // If the miss wasn't due to an unseen map, a polymorphic stub | 1776 // If the miss wasn't due to an unseen map, a polymorphic stub |
| 1987 // won't help, use the generic stub. | 1777 // won't help, use the generic stub. |
| 1988 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice"); | 1778 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice"); |
| 1989 return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub(); | 1779 return generic_stub(); |
| 1990 } | 1780 } |
| 1991 | 1781 |
| 1992 // If the maximum number of receiver maps has been exceeded, use the generic | 1782 // If the maximum number of receiver maps has been exceeded, use the generic |
| 1993 // version of the IC. | 1783 // version of the IC. |
| 1994 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { | 1784 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { |
| 1995 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded"); | 1785 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded"); |
| 1996 return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub(); | 1786 return generic_stub(); |
| 1997 } | 1787 } |
| 1998 | 1788 |
| 1999 // Make sure all polymorphic handlers have the same store mode, otherwise the | 1789 // Make sure all polymorphic handlers have the same store mode, otherwise the |
| 2000 // generic stub must be used. | 1790 // generic stub must be used. |
| 2001 store_mode = GetNonTransitioningStoreMode(store_mode); | 1791 store_mode = GetNonTransitioningStoreMode(store_mode); |
| 2002 if (old_store_mode != STANDARD_STORE) { | 1792 if (old_store_mode != STANDARD_STORE) { |
| 2003 if (store_mode == STANDARD_STORE) { | 1793 if (store_mode == STANDARD_STORE) { |
| 2004 store_mode = old_store_mode; | 1794 store_mode = old_store_mode; |
| 2005 } else if (store_mode != old_store_mode) { | 1795 } else if (store_mode != old_store_mode) { |
| 2006 TRACE_GENERIC_IC(isolate(), "KeyedIC", "store mode mismatch"); | 1796 TRACE_GENERIC_IC(isolate(), "KeyedIC", "store mode mismatch"); |
| 2007 return strict_mode == kStrictMode | 1797 return generic_stub(); |
| 2008 ? generic_stub_strict() | |
| 2009 : generic_stub(); | |
| 2010 } | 1798 } |
| 2011 } | 1799 } |
| 2012 | 1800 |
| 2013 // If the store mode isn't the standard mode, make sure that all polymorphic | 1801 // If the store mode isn't the standard mode, make sure that all polymorphic |
| 2014 // receivers are either external arrays, or all "normal" arrays. Otherwise, | 1802 // receivers are either external arrays, or all "normal" arrays. Otherwise, |
| 2015 // use the generic stub. | 1803 // use the generic stub. |
| 2016 if (store_mode != STANDARD_STORE) { | 1804 if (store_mode != STANDARD_STORE) { |
| 2017 int external_arrays = 0; | 1805 int external_arrays = 0; |
| 2018 for (int i = 0; i < target_receiver_maps.length(); ++i) { | 1806 for (int i = 0; i < target_receiver_maps.length(); ++i) { |
| 2019 if (target_receiver_maps[i]->has_external_array_elements()) { | 1807 if (target_receiver_maps[i]->has_external_array_elements()) { |
| 2020 external_arrays++; | 1808 external_arrays++; |
| 2021 } | 1809 } |
| 2022 } | 1810 } |
| 2023 if (external_arrays != 0 && | 1811 if (external_arrays != 0 && |
| 2024 external_arrays != target_receiver_maps.length()) { | 1812 external_arrays != target_receiver_maps.length()) { |
| 2025 TRACE_GENERIC_IC(isolate(), "KeyedIC", | 1813 TRACE_GENERIC_IC(isolate(), "KeyedIC", |
| 2026 "unsupported combination of external and normal arrays"); | 1814 "unsupported combination of external and normal arrays"); |
| 2027 return strict_mode == kStrictMode | 1815 return generic_stub(); |
| 2028 ? generic_stub_strict() | |
| 2029 : generic_stub(); | |
| 2030 } | 1816 } |
| 2031 } | 1817 } |
| 2032 | 1818 |
| 2033 return isolate()->stub_cache()->ComputeStoreElementPolymorphic( | 1819 return isolate()->stub_cache()->ComputeStoreElementPolymorphic( |
| 2034 &target_receiver_maps, store_mode, strict_mode); | 1820 &target_receiver_maps, store_mode, strict_mode()); |
| 2035 } | 1821 } |
| 2036 | 1822 |
| 2037 | 1823 |
| 2038 Handle<Map> KeyedStoreIC::ComputeTransitionedMap( | 1824 Handle<Map> KeyedStoreIC::ComputeTransitionedMap( |
| 2039 Handle<JSObject> receiver, | 1825 Handle<JSObject> receiver, |
| 2040 KeyedAccessStoreMode store_mode) { | 1826 KeyedAccessStoreMode store_mode) { |
| 2041 switch (store_mode) { | 1827 switch (store_mode) { |
| 2042 case STORE_TRANSITION_SMI_TO_OBJECT: | 1828 case STORE_TRANSITION_SMI_TO_OBJECT: |
| 2043 case STORE_TRANSITION_DOUBLE_TO_OBJECT: | 1829 case STORE_TRANSITION_DOUBLE_TO_OBJECT: |
| 2044 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT: | 1830 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT: |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2147 Heap* heap = receiver->GetHeap(); | 1933 Heap* heap = receiver->GetHeap(); |
| 2148 if (receiver->elements()->map() == heap->fixed_cow_array_map()) { | 1934 if (receiver->elements()->map() == heap->fixed_cow_array_map()) { |
| 2149 return STORE_NO_TRANSITION_HANDLE_COW; | 1935 return STORE_NO_TRANSITION_HANDLE_COW; |
| 2150 } else { | 1936 } else { |
| 2151 return STANDARD_STORE; | 1937 return STANDARD_STORE; |
| 2152 } | 1938 } |
| 2153 } | 1939 } |
| 2154 } | 1940 } |
| 2155 | 1941 |
| 2156 | 1942 |
| 2157 MaybeObject* KeyedStoreIC::Store(State state, | 1943 MaybeObject* KeyedStoreIC::Store(Handle<Object> object, |
| 2158 StrictModeFlag strict_mode, | |
| 2159 Handle<Object> object, | |
| 2160 Handle<Object> key, | 1944 Handle<Object> key, |
| 2161 Handle<Object> value, | 1945 Handle<Object> value, |
| 2162 ICMissMode miss_mode) { | 1946 ICMissMode miss_mode) { |
| 1947 if (MigrateDeprecated(object)) { |
| 1948 return Runtime::SetObjectPropertyOrFail( |
| 1949 isolate(), object , key, value, NONE, strict_mode()); |
| 1950 } |
| 1951 |
| 2163 // Check for values that can be converted into an internalized string directly | 1952 // Check for values that can be converted into an internalized string directly |
| 2164 // or is representable as a smi. | 1953 // or is representable as a smi. |
| 2165 key = TryConvertKey(key, isolate()); | 1954 key = TryConvertKey(key, isolate()); |
| 2166 | 1955 |
| 2167 if (key->IsInternalizedString()) { | 1956 if (key->IsInternalizedString()) { |
| 2168 return StoreIC::Store(state, | 1957 return StoreIC::Store(object, |
| 2169 strict_mode, | |
| 2170 object, | |
| 2171 Handle<String>::cast(key), | 1958 Handle<String>::cast(key), |
| 2172 value, | 1959 value, |
| 2173 JSReceiver::MAY_BE_STORE_FROM_KEYED); | 1960 JSReceiver::MAY_BE_STORE_FROM_KEYED); |
| 2174 } | 1961 } |
| 2175 | 1962 |
| 2176 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() && | 1963 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() && |
| 2177 !(FLAG_harmony_observation && object->IsJSObject() && | 1964 !(FLAG_harmony_observation && object->IsJSObject() && |
| 2178 JSObject::cast(*object)->map()->is_observed()); | 1965 JSObject::cast(*object)->map()->is_observed()); |
| 2179 if (use_ic && !object->IsSmi()) { | 1966 if (use_ic && !object->IsSmi()) { |
| 2180 // Don't use ICs for maps of the objects in Array's prototype chain. We | 1967 // Don't use ICs for maps of the objects in Array's prototype chain. We |
| 2181 // expect to be able to trap element sets to objects with those maps in the | 1968 // expect to be able to trap element sets to objects with those maps in the |
| 2182 // runtime to enable optimization of element hole access. | 1969 // runtime to enable optimization of element hole access. |
| 2183 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); | 1970 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); |
| 2184 if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false; | 1971 if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false; |
| 2185 } | 1972 } |
| 2186 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | |
| 2187 | 1973 |
| 2188 if (use_ic) { | 1974 if (use_ic) { |
| 2189 Handle<Code> stub = (strict_mode == kStrictMode) | 1975 ASSERT(!object->IsJSGlobalProxy()); |
| 2190 ? generic_stub_strict() | 1976 |
| 2191 : generic_stub(); | 1977 Handle<Code> stub = generic_stub(); |
| 2192 if (miss_mode != MISS_FORCE_GENERIC) { | 1978 if (miss_mode != MISS_FORCE_GENERIC) { |
| 2193 if (object->IsJSObject()) { | 1979 if (object->IsJSObject()) { |
| 2194 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1980 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 2195 if (receiver->map()->is_deprecated()) { | |
| 2196 JSObject::MigrateInstance(receiver); | |
| 2197 } | |
| 2198 bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure(); | 1981 bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure(); |
| 2199 if (receiver->elements()->map() == | 1982 if (receiver->elements()->map() == |
| 2200 isolate()->heap()->non_strict_arguments_elements_map()) { | 1983 isolate()->heap()->non_strict_arguments_elements_map()) { |
| 2201 stub = non_strict_arguments_stub(); | 1984 stub = non_strict_arguments_stub(); |
| 2202 } else if (key_is_smi_like && | 1985 } else if (key_is_smi_like && |
| 2203 (target() != *non_strict_arguments_stub())) { | 1986 (!target().is_identical_to(non_strict_arguments_stub()))) { |
| 2204 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value); | 1987 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value); |
| 2205 stub = StoreElementStub(receiver, store_mode, strict_mode); | 1988 stub = StoreElementStub(receiver, store_mode); |
| 2206 } else { | 1989 } else { |
| 2207 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "key not a number"); | 1990 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "key not a number"); |
| 2208 } | 1991 } |
| 2209 } else { | 1992 } else { |
| 2210 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "not an object"); | 1993 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "not an object"); |
| 2211 } | 1994 } |
| 2212 } else { | 1995 } else { |
| 2213 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "force generic"); | 1996 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "force generic"); |
| 2214 } | 1997 } |
| 2215 ASSERT(!stub.is_null()); | 1998 ASSERT(!stub.is_null()); |
| 2216 set_target(*stub); | 1999 set_target(*stub); |
| 2217 TRACE_IC("KeyedStoreIC", key, state, target()); | 2000 TRACE_IC("StoreIC", key); |
| 2218 } | 2001 } |
| 2219 | 2002 |
| 2220 return Runtime::SetObjectPropertyOrFail( | 2003 return Runtime::SetObjectPropertyOrFail( |
| 2221 isolate(), object , key, value, NONE, strict_mode); | 2004 isolate(), object , key, value, NONE, strict_mode()); |
| 2222 } | 2005 } |
| 2223 | 2006 |
| 2224 | 2007 |
| 2225 Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup, | 2008 Handle<Code> KeyedStoreIC::ComputeStoreHandler(LookupResult* lookup, |
| 2226 StrictModeFlag strict_mode, | 2009 Handle<JSObject> receiver, |
| 2227 Handle<JSObject> receiver, | 2010 Handle<String> name, |
| 2228 Handle<String> name, | 2011 Handle<Object> value) { |
| 2229 Handle<Object> value) { | |
| 2230 // If the property has a non-field type allowing map transitions | 2012 // If the property has a non-field type allowing map transitions |
| 2231 // where there is extra room in the object, we leave the IC in its | 2013 // where there is extra room in the object, we leave the IC in its |
| 2232 // current state. | 2014 // current state. |
| 2233 switch (lookup->type()) { | 2015 switch (lookup->type()) { |
| 2234 case FIELD: | 2016 case FIELD: |
| 2235 return isolate()->stub_cache()->ComputeKeyedStoreField( | 2017 return isolate()->stub_cache()->ComputeKeyedStoreField( |
| 2236 name, receiver, lookup, strict_mode); | 2018 name, receiver, lookup, strict_mode()); |
| 2237 case TRANSITION: { | 2019 case TRANSITION: { |
| 2238 // Explicitly pass in the receiver map since LookupForWrite may have | 2020 // Explicitly pass in the receiver map since LookupForWrite may have |
| 2239 // stored something else than the receiver in the holder. | 2021 // stored something else than the receiver in the holder. |
| 2240 Handle<Map> transition( | 2022 Handle<Map> transition( |
| 2241 lookup->GetTransitionTarget(receiver->map()), isolate()); | 2023 lookup->GetTransitionTarget(receiver->map()), isolate()); |
| 2242 int descriptor = transition->LastAdded(); | 2024 int descriptor = transition->LastAdded(); |
| 2243 | 2025 |
| 2244 DescriptorArray* target_descriptors = transition->instance_descriptors(); | 2026 DescriptorArray* target_descriptors = transition->instance_descriptors(); |
| 2245 PropertyDetails details = target_descriptors->GetDetails(descriptor); | 2027 PropertyDetails details = target_descriptors->GetDetails(descriptor); |
| 2246 | 2028 |
| 2247 if (details.type() != CALLBACKS && details.attributes() == NONE) { | 2029 if (details.type() != CALLBACKS && details.attributes() == NONE) { |
| 2248 return isolate()->stub_cache()->ComputeKeyedStoreTransition( | 2030 return isolate()->stub_cache()->ComputeKeyedStoreTransition( |
| 2249 name, receiver, lookup, transition, strict_mode); | 2031 name, receiver, lookup, transition, strict_mode()); |
| 2250 } | 2032 } |
| 2251 // fall through. | 2033 // fall through. |
| 2252 } | 2034 } |
| 2253 case NORMAL: | 2035 case NORMAL: |
| 2254 case CONSTANT: | 2036 case CONSTANT: |
| 2255 case CALLBACKS: | 2037 case CALLBACKS: |
| 2256 case INTERCEPTOR: | 2038 case INTERCEPTOR: |
| 2257 // Always rewrite to the generic case so that we do not | 2039 // Always rewrite to the generic case so that we do not |
| 2258 // repeatedly try to rewrite. | 2040 // repeatedly try to rewrite. |
| 2259 return (strict_mode == kStrictMode) | 2041 return generic_stub(); |
| 2260 ? generic_stub_strict() | |
| 2261 : generic_stub(); | |
| 2262 case HANDLER: | 2042 case HANDLER: |
| 2263 case NONEXISTENT: | 2043 case NONEXISTENT: |
| 2264 UNREACHABLE(); | 2044 UNREACHABLE(); |
| 2265 break; | 2045 break; |
| 2266 } | 2046 } |
| 2267 return Handle<Code>::null(); | 2047 return Handle<Code>::null(); |
| 2268 } | 2048 } |
| 2269 | 2049 |
| 2270 | 2050 |
| 2271 #undef TRACE_IC | 2051 #undef TRACE_IC |
| 2272 | 2052 |
| 2273 | 2053 |
| 2274 // ---------------------------------------------------------------------------- | 2054 // ---------------------------------------------------------------------------- |
| 2275 // Static IC stub generators. | 2055 // Static IC stub generators. |
| 2276 // | 2056 // |
| 2277 | 2057 |
| 2278 // Used from ic-<arch>.cc. | 2058 // Used from ic-<arch>.cc. |
| 2279 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { | 2059 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { |
| 2280 HandleScope scope(isolate); | 2060 HandleScope scope(isolate); |
| 2281 ASSERT(args.length() == 2); | 2061 ASSERT(args.length() == 2); |
| 2282 CallIC ic(isolate); | 2062 CallIC ic(isolate); |
| 2283 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2063 Handle<Object> receiver = args.at<Object>(0); |
| 2284 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 2064 Handle<String> key = args.at<String>(1); |
| 2285 MaybeObject* maybe_result = ic.LoadFunction(state, | 2065 ic.UpdateState(receiver, key); |
| 2286 extra_ic_state, | 2066 MaybeObject* maybe_result = ic.LoadFunction(receiver, key); |
| 2287 args.at<Object>(0), | |
| 2288 args.at<String>(1)); | |
| 2289 JSFunction* raw_function; | 2067 JSFunction* raw_function; |
| 2290 if (!maybe_result->To(&raw_function)) return maybe_result; | 2068 if (!maybe_result->To(&raw_function)) return maybe_result; |
| 2291 | 2069 |
| 2292 // The first time the inline cache is updated may be the first time the | 2070 // The first time the inline cache is updated may be the first time the |
| 2293 // function it references gets called. If the function is lazily compiled | 2071 // function it references gets called. If the function is lazily compiled |
| 2294 // then the first call will trigger a compilation. We check for this case | 2072 // then the first call will trigger a compilation. We check for this case |
| 2295 // and we do the compilation immediately, instead of waiting for the stub | 2073 // and we do the compilation immediately, instead of waiting for the stub |
| 2296 // currently attached to the JSFunction object to trigger compilation. | 2074 // currently attached to the JSFunction object to trigger compilation. |
| 2297 if (raw_function->is_compiled()) return raw_function; | 2075 if (raw_function->is_compiled()) return raw_function; |
| 2298 | 2076 |
| 2299 Handle<JSFunction> function(raw_function); | 2077 Handle<JSFunction> function(raw_function); |
| 2300 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); | 2078 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); |
| 2301 return *function; | 2079 return *function; |
| 2302 } | 2080 } |
| 2303 | 2081 |
| 2304 | 2082 |
| 2305 // Used from ic-<arch>.cc. | 2083 // Used from ic-<arch>.cc. |
| 2306 RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) { | 2084 RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) { |
| 2307 HandleScope scope(isolate); | 2085 HandleScope scope(isolate); |
| 2308 ASSERT(args.length() == 2); | 2086 ASSERT(args.length() == 2); |
| 2309 KeyedCallIC ic(isolate); | 2087 KeyedCallIC ic(isolate); |
| 2310 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2088 Handle<Object> receiver = args.at<Object>(0); |
| 2311 MaybeObject* maybe_result = | 2089 Handle<Object> key = args.at<Object>(1); |
| 2312 ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1)); | 2090 ic.UpdateState(receiver, key); |
| 2091 MaybeObject* maybe_result = ic.LoadFunction(receiver, key); |
| 2313 // Result could be a function or a failure. | 2092 // Result could be a function or a failure. |
| 2314 JSFunction* raw_function = NULL; | 2093 JSFunction* raw_function = NULL; |
| 2315 if (!maybe_result->To(&raw_function)) return maybe_result; | 2094 if (!maybe_result->To(&raw_function)) return maybe_result; |
| 2316 | 2095 |
| 2317 if (raw_function->is_compiled()) return raw_function; | 2096 if (raw_function->is_compiled()) return raw_function; |
| 2318 | 2097 |
| 2319 Handle<JSFunction> function(raw_function, isolate); | 2098 Handle<JSFunction> function(raw_function, isolate); |
| 2320 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); | 2099 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); |
| 2321 return *function; | 2100 return *function; |
| 2322 } | 2101 } |
| 2323 | 2102 |
| 2324 | 2103 |
| 2325 // Used from ic-<arch>.cc. | 2104 // Used from ic-<arch>.cc. |
| 2326 RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { | 2105 RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { |
| 2327 HandleScope scope(isolate); | 2106 HandleScope scope(isolate); |
| 2328 ASSERT(args.length() == 2); | 2107 ASSERT(args.length() == 2); |
| 2329 LoadIC ic(IC::NO_EXTRA_FRAME, isolate); | 2108 LoadIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 2330 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2109 Handle<Object> receiver = args.at<Object>(0); |
| 2331 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); | 2110 Handle<String> key = args.at<String>(1); |
| 2111 ic.UpdateState(receiver, key); |
| 2112 return ic.Load(receiver, key); |
| 2332 } | 2113 } |
| 2333 | 2114 |
| 2334 | 2115 |
| 2335 // Used from ic-<arch>.cc | 2116 // Used from ic-<arch>.cc |
| 2336 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { | 2117 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { |
| 2337 HandleScope scope(isolate); | 2118 HandleScope scope(isolate); |
| 2338 ASSERT(args.length() == 2); | 2119 ASSERT(args.length() == 2); |
| 2339 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate); | 2120 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 2340 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2121 Handle<Object> receiver = args.at<Object>(0); |
| 2341 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), MISS); | 2122 Handle<Object> key = args.at<Object>(1); |
| 2123 ic.UpdateState(receiver, key); |
| 2124 return ic.Load(receiver, key, MISS); |
| 2342 } | 2125 } |
| 2343 | 2126 |
| 2344 | 2127 |
| 2345 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure) { | 2128 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure) { |
| 2346 HandleScope scope(isolate); | 2129 HandleScope scope(isolate); |
| 2347 ASSERT(args.length() == 2); | 2130 ASSERT(args.length() == 2); |
| 2348 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate); | 2131 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate); |
| 2349 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2132 Handle<Object> receiver = args.at<Object>(0); |
| 2350 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), MISS); | 2133 Handle<Object> key = args.at<Object>(1); |
| 2134 ic.UpdateState(receiver, key); |
| 2135 return ic.Load(receiver, key, MISS); |
| 2351 } | 2136 } |
| 2352 | 2137 |
| 2353 | 2138 |
| 2354 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) { | 2139 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) { |
| 2355 HandleScope scope(isolate); | 2140 HandleScope scope(isolate); |
| 2356 ASSERT(args.length() == 2); | 2141 ASSERT(args.length() == 2); |
| 2357 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate); | 2142 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 2358 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2143 Handle<Object> receiver = args.at<Object>(0); |
| 2359 return ic.Load(state, | 2144 Handle<Object> key = args.at<Object>(1); |
| 2360 args.at<Object>(0), | 2145 ic.UpdateState(receiver, key); |
| 2361 args.at<Object>(1), | 2146 return ic.Load(receiver, key, MISS_FORCE_GENERIC); |
| 2362 MISS_FORCE_GENERIC); | |
| 2363 } | 2147 } |
| 2364 | 2148 |
| 2365 | 2149 |
| 2366 // Used from ic-<arch>.cc. | 2150 // Used from ic-<arch>.cc. |
| 2367 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { | 2151 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { |
| 2368 HandleScope scope(isolate); | 2152 HandleScope scope(isolate); |
| 2369 ASSERT(args.length() == 3); | 2153 ASSERT(args.length() == 3); |
| 2370 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2154 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 2371 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2155 Handle<Object> receiver = args.at<Object>(0); |
| 2372 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 2156 Handle<String> key = args.at<String>(1); |
| 2373 return ic.Store(state, | 2157 ic.UpdateState(receiver, key); |
| 2374 Code::GetStrictMode(extra_ic_state), | 2158 return ic.Store(receiver, key, args.at<Object>(2)); |
| 2375 args.at<Object>(0), | |
| 2376 args.at<String>(1), | |
| 2377 args.at<Object>(2)); | |
| 2378 } | 2159 } |
| 2379 | 2160 |
| 2380 | 2161 |
| 2381 RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) { | 2162 RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) { |
| 2382 HandleScope scope(isolate); | 2163 HandleScope scope(isolate); |
| 2383 ASSERT(args.length() == 3); | 2164 ASSERT(args.length() == 3); |
| 2384 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate); | 2165 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate); |
| 2385 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2166 Handle<Object> receiver = args.at<Object>(0); |
| 2386 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 2167 Handle<String> key = args.at<String>(1); |
| 2387 return ic.Store(state, | 2168 ic.UpdateState(receiver, key); |
| 2388 Code::GetStrictMode(extra_ic_state), | 2169 return ic.Store(receiver, key, args.at<Object>(2)); |
| 2389 args.at<Object>(0), | |
| 2390 args.at<String>(1), | |
| 2391 args.at<Object>(2)); | |
| 2392 } | 2170 } |
| 2393 | 2171 |
| 2394 | 2172 |
| 2395 RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) { | 2173 RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) { |
| 2396 SealHandleScope shs(isolate); | 2174 SealHandleScope shs(isolate); |
| 2397 | 2175 |
| 2398 ASSERT(args.length() == 2); | 2176 ASSERT(args.length() == 2); |
| 2399 JSArray* receiver = JSArray::cast(args[0]); | 2177 JSArray* receiver = JSArray::cast(args[0]); |
| 2400 Object* len = args[1]; | 2178 Object* len = args[1]; |
| 2401 | 2179 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2464 // Return the stored value. | 2242 // Return the stored value. |
| 2465 return value; | 2243 return value; |
| 2466 } | 2244 } |
| 2467 | 2245 |
| 2468 | 2246 |
| 2469 // Used from ic-<arch>.cc. | 2247 // Used from ic-<arch>.cc. |
| 2470 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { | 2248 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { |
| 2471 HandleScope scope(isolate); | 2249 HandleScope scope(isolate); |
| 2472 ASSERT(args.length() == 3); | 2250 ASSERT(args.length() == 3); |
| 2473 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2251 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 2474 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2252 Handle<Object> receiver = args.at<Object>(0); |
| 2475 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 2253 Handle<Object> key = args.at<Object>(1); |
| 2476 return ic.Store(state, | 2254 ic.UpdateState(receiver, key); |
| 2477 Code::GetStrictMode(extra_ic_state), | 2255 return ic.Store(receiver, key, args.at<Object>(2), MISS); |
| 2478 args.at<Object>(0), | |
| 2479 args.at<Object>(1), | |
| 2480 args.at<Object>(2), | |
| 2481 MISS); | |
| 2482 } | 2256 } |
| 2483 | 2257 |
| 2484 | 2258 |
| 2485 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure) { | 2259 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure) { |
| 2486 HandleScope scope(isolate); | 2260 HandleScope scope(isolate); |
| 2487 ASSERT(args.length() == 3); | 2261 ASSERT(args.length() == 3); |
| 2488 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); | 2262 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); |
| 2489 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2263 Handle<Object> receiver = args.at<Object>(0); |
| 2490 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 2264 Handle<Object> key = args.at<Object>(1); |
| 2491 return ic.Store(state, | 2265 ic.UpdateState(receiver, key); |
| 2492 Code::GetStrictMode(extra_ic_state), | 2266 return ic.Store(receiver, key, args.at<Object>(2), MISS); |
| 2493 args.at<Object>(0), | |
| 2494 args.at<Object>(1), | |
| 2495 args.at<Object>(2), | |
| 2496 MISS); | |
| 2497 } | 2267 } |
| 2498 | 2268 |
| 2499 | 2269 |
| 2500 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) { | 2270 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) { |
| 2501 SealHandleScope shs(isolate); | 2271 HandleScope scope(isolate); |
| 2502 ASSERT(args.length() == 3); | 2272 ASSERT(args.length() == 3); |
| 2503 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2273 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 2504 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | |
| 2505 Handle<Object> object = args.at<Object>(0); | 2274 Handle<Object> object = args.at<Object>(0); |
| 2506 Handle<Object> key = args.at<Object>(1); | 2275 Handle<Object> key = args.at<Object>(1); |
| 2507 Handle<Object> value = args.at<Object>(2); | 2276 Handle<Object> value = args.at<Object>(2); |
| 2508 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state); | 2277 StrictModeFlag strict_mode = ic.strict_mode(); |
| 2509 return Runtime::SetObjectProperty(isolate, | 2278 return Runtime::SetObjectProperty(isolate, |
| 2510 object, | 2279 object, |
| 2511 key, | 2280 key, |
| 2512 value, | 2281 value, |
| 2513 NONE, | 2282 NONE, |
| 2514 strict_mode); | 2283 strict_mode); |
| 2515 } | 2284 } |
| 2516 | 2285 |
| 2517 | 2286 |
| 2518 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) { | 2287 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) { |
| 2519 SealHandleScope shs(isolate); | 2288 HandleScope scope(isolate); |
| 2520 ASSERT(args.length() == 3); | 2289 ASSERT(args.length() == 3); |
| 2521 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2290 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 2522 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | |
| 2523 Handle<Object> object = args.at<Object>(0); | 2291 Handle<Object> object = args.at<Object>(0); |
| 2524 Handle<Object> key = args.at<Object>(1); | 2292 Handle<Object> key = args.at<Object>(1); |
| 2525 Handle<Object> value = args.at<Object>(2); | 2293 Handle<Object> value = args.at<Object>(2); |
| 2526 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state); | 2294 StrictModeFlag strict_mode = ic.strict_mode(); |
| 2527 return Runtime::SetObjectProperty(isolate, | 2295 return Runtime::SetObjectProperty(isolate, |
| 2528 object, | 2296 object, |
| 2529 key, | 2297 key, |
| 2530 value, | 2298 value, |
| 2531 NONE, | 2299 NONE, |
| 2532 strict_mode); | 2300 strict_mode); |
| 2533 } | 2301 } |
| 2534 | 2302 |
| 2535 | 2303 |
| 2536 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { | 2304 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { |
| 2537 HandleScope scope(isolate); | 2305 HandleScope scope(isolate); |
| 2538 ASSERT(args.length() == 3); | 2306 ASSERT(args.length() == 3); |
| 2539 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2307 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
| 2540 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 2308 Handle<Object> receiver = args.at<Object>(0); |
| 2541 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 2309 Handle<Object> key = args.at<Object>(1); |
| 2542 return ic.Store(state, | 2310 ic.UpdateState(receiver, key); |
| 2543 Code::GetStrictMode(extra_ic_state), | 2311 return ic.Store(receiver, key, args.at<Object>(2), MISS_FORCE_GENERIC); |
| 2544 args.at<Object>(0), | |
| 2545 args.at<Object>(1), | |
| 2546 args.at<Object>(2), | |
| 2547 MISS_FORCE_GENERIC); | |
| 2548 } | 2312 } |
| 2549 | 2313 |
| 2550 | 2314 |
| 2551 RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) { | 2315 RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) { |
| 2552 SealHandleScope scope(isolate); | 2316 HandleScope scope(isolate); |
| 2553 ASSERT(args.length() == 4); | 2317 ASSERT(args.length() == 4); |
| 2554 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); | 2318 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); |
| 2555 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | |
| 2556 Handle<Object> value = args.at<Object>(0); | 2319 Handle<Object> value = args.at<Object>(0); |
| 2557 Handle<Object> key = args.at<Object>(2); | 2320 Handle<Object> key = args.at<Object>(2); |
| 2558 Handle<Object> object = args.at<Object>(3); | 2321 Handle<Object> object = args.at<Object>(3); |
| 2559 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state); | 2322 StrictModeFlag strict_mode = ic.strict_mode(); |
| 2560 return Runtime::SetObjectProperty(isolate, | 2323 return Runtime::SetObjectProperty(isolate, |
| 2561 object, | 2324 object, |
| 2562 key, | 2325 key, |
| 2563 value, | 2326 value, |
| 2564 NONE, | 2327 NONE, |
| 2565 strict_mode); | 2328 strict_mode); |
| 2566 } | 2329 } |
| 2567 | 2330 |
| 2568 | 2331 |
| 2569 void BinaryOpIC::patch(Code* code) { | |
| 2570 set_target(code); | |
| 2571 } | |
| 2572 | |
| 2573 | |
| 2574 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 2332 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
| 2575 switch (type_info) { | 2333 switch (type_info) { |
| 2576 case UNINITIALIZED: return "Uninitialized"; | 2334 case UNINITIALIZED: return "Uninitialized"; |
| 2577 case SMI: return "Smi"; | 2335 case SMI: return "Smi"; |
| 2578 case INT32: return "Int32"; | 2336 case INT32: return "Int32"; |
| 2579 case NUMBER: return "Number"; | 2337 case NUMBER: return "Number"; |
| 2580 case ODDBALL: return "Oddball"; | 2338 case ODDBALL: return "Oddball"; |
| 2581 case STRING: return "String"; | 2339 case STRING: return "String"; |
| 2582 case GENERIC: return "Generic"; | 2340 case GENERIC: return "Generic"; |
| 2583 default: return "Invalid"; | 2341 default: return "Invalid"; |
| 2584 } | 2342 } |
| 2585 } | 2343 } |
| 2586 | 2344 |
| 2587 | 2345 |
| 2588 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { | 2346 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { |
| 2589 switch (type_info) { | 2347 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); |
| 2590 case UNINITIALIZED: | 2348 BinaryOpStub stub(extra_ic_state); |
| 2591 return ::v8::internal::UNINITIALIZED; | 2349 |
| 2592 case SMI: | 2350 bool smi_was_enabled = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
| 2593 case INT32: | 2351 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
| 2594 case NUMBER: | 2352 |
| 2595 case ODDBALL: | 2353 Maybe<Handle<Object> > result = stub.Result(left, right, isolate()); |
| 2596 case STRING: | 2354 |
| 2597 return MONOMORPHIC; | 2355 #ifdef DEBUG |
| 2598 case GENERIC: | 2356 if (FLAG_trace_ic) { |
| 2599 return ::v8::internal::GENERIC; | 2357 char buffer[100]; |
| 2358 NoAllocationStringAllocator allocator(buffer, |
| 2359 static_cast<unsigned>(sizeof(buffer))); |
| 2360 StringStream stream(&allocator); |
| 2361 stream.Add("["); |
| 2362 stub.PrintName(&stream); |
| 2363 |
| 2364 stub.UpdateStatus(left, right, result); |
| 2365 |
| 2366 stream.Add(" => "); |
| 2367 stub.PrintState(&stream); |
| 2368 stream.Add(" "); |
| 2369 stream.OutputToStdOut(); |
| 2370 PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate()))); |
| 2371 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| 2372 PrintF("]\n"); |
| 2373 } else { |
| 2374 stub.UpdateStatus(left, right, result); |
| 2600 } | 2375 } |
| 2601 UNREACHABLE(); | 2376 #else |
| 2602 return ::v8::internal::UNINITIALIZED; | 2377 stub.UpdateStatus(left, right, result); |
| 2378 #endif |
| 2379 |
| 2380 Handle<Code> code = stub.GetCode(isolate()); |
| 2381 set_target(*code); |
| 2382 |
| 2383 bool enable_smi = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
| 2384 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
| 2385 |
| 2386 if (!smi_was_enabled && enable_smi) { |
| 2387 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 2388 } else if (smi_was_enabled && !enable_smi) { |
| 2389 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); |
| 2390 } |
| 2391 |
| 2392 return result.has_value |
| 2393 ? static_cast<MaybeObject*>(*result.value) |
| 2394 : Failure::Exception(); |
| 2603 } | 2395 } |
| 2604 | 2396 |
| 2605 | 2397 |
| 2606 Handle<Type> BinaryOpIC::TypeInfoToType(BinaryOpIC::TypeInfo binary_type, | 2398 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { |
| 2607 Isolate* isolate) { | 2399 HandleScope scope(isolate); |
| 2608 switch (binary_type) { | 2400 Handle<Object> left = args.at<Object>(0); |
| 2609 case UNINITIALIZED: | 2401 Handle<Object> right = args.at<Object>(1); |
| 2610 return handle(Type::None(), isolate); | 2402 BinaryOpIC ic(isolate); |
| 2611 case SMI: | 2403 return ic.Transition(left, right); |
| 2612 return handle(Type::Smi(), isolate); | |
| 2613 case INT32: | |
| 2614 return handle(Type::Signed32(), isolate); | |
| 2615 case NUMBER: | |
| 2616 return handle(Type::Number(), isolate); | |
| 2617 case ODDBALL: | |
| 2618 return handle(Type::Optional( | |
| 2619 handle(Type::Union( | |
| 2620 handle(Type::Number(), isolate), | |
| 2621 handle(Type::String(), isolate)), isolate)), isolate); | |
| 2622 case STRING: | |
| 2623 return handle(Type::String(), isolate); | |
| 2624 case GENERIC: | |
| 2625 return handle(Type::Any(), isolate); | |
| 2626 } | |
| 2627 UNREACHABLE(); | |
| 2628 return handle(Type::Any(), isolate); | |
| 2629 } | 2404 } |
| 2630 | 2405 |
| 2631 | 2406 |
| 2632 void BinaryOpIC::StubInfoToType(int minor_key, | |
| 2633 Handle<Type>* left, | |
| 2634 Handle<Type>* right, | |
| 2635 Handle<Type>* result, | |
| 2636 Isolate* isolate) { | |
| 2637 TypeInfo left_typeinfo, right_typeinfo, result_typeinfo; | |
| 2638 BinaryOpStub::decode_types_from_minor_key( | |
| 2639 minor_key, &left_typeinfo, &right_typeinfo, &result_typeinfo); | |
| 2640 *left = TypeInfoToType(left_typeinfo, isolate); | |
| 2641 *right = TypeInfoToType(right_typeinfo, isolate); | |
| 2642 *result = TypeInfoToType(result_typeinfo, isolate); | |
| 2643 } | |
| 2644 | |
| 2645 | |
| 2646 static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value, | |
| 2647 Token::Value op) { | |
| 2648 v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(value); | |
| 2649 if (type.IsSmi()) return BinaryOpIC::SMI; | |
| 2650 if (type.IsInteger32()) { | |
| 2651 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
| 2652 return BinaryOpIC::INT32; | |
| 2653 } | |
| 2654 if (type.IsNumber()) return BinaryOpIC::NUMBER; | |
| 2655 if (type.IsString()) return BinaryOpIC::STRING; | |
| 2656 if (value->IsUndefined()) { | |
| 2657 if (op == Token::BIT_AND || | |
| 2658 op == Token::BIT_OR || | |
| 2659 op == Token::BIT_XOR || | |
| 2660 op == Token::SAR || | |
| 2661 op == Token::SHL || | |
| 2662 op == Token::SHR) { | |
| 2663 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
| 2664 return BinaryOpIC::INT32; | |
| 2665 } | |
| 2666 return BinaryOpIC::ODDBALL; | |
| 2667 } | |
| 2668 return BinaryOpIC::GENERIC; | |
| 2669 } | |
| 2670 | |
| 2671 | |
| 2672 static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type, | |
| 2673 Handle<Object> value, | |
| 2674 Token::Value op) { | |
| 2675 BinaryOpIC::TypeInfo new_type = TypeInfoFromValue(value, op); | |
| 2676 if (old_type == BinaryOpIC::STRING) { | |
| 2677 if (new_type == BinaryOpIC::STRING) return new_type; | |
| 2678 return BinaryOpIC::GENERIC; | |
| 2679 } | |
| 2680 return Max(old_type, new_type); | |
| 2681 } | |
| 2682 | |
| 2683 | |
| 2684 #ifdef DEBUG | |
| 2685 static void TraceBinaryOp(BinaryOpIC::TypeInfo left, | |
| 2686 BinaryOpIC::TypeInfo right, | |
| 2687 Maybe<int32_t> fixed_right_arg, | |
| 2688 BinaryOpIC::TypeInfo result) { | |
| 2689 PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right)); | |
| 2690 if (fixed_right_arg.has_value) PrintF("{%d}", fixed_right_arg.value); | |
| 2691 PrintF("->%s", BinaryOpIC::GetName(result)); | |
| 2692 } | |
| 2693 #endif | |
| 2694 | |
| 2695 | |
| 2696 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { | |
| 2697 ASSERT(args.length() == 3); | |
| 2698 | |
| 2699 HandleScope scope(isolate); | |
| 2700 Handle<Object> left = args.at<Object>(0); | |
| 2701 Handle<Object> right = args.at<Object>(1); | |
| 2702 int key = args.smi_at(2); | |
| 2703 Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); | |
| 2704 | |
| 2705 BinaryOpIC::TypeInfo previous_left, previous_right, previous_result; | |
| 2706 BinaryOpStub::decode_types_from_minor_key( | |
| 2707 key, &previous_left, &previous_right, &previous_result); | |
| 2708 | |
| 2709 BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op); | |
| 2710 BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op); | |
| 2711 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; | |
| 2712 | |
| 2713 // STRING is only used for ADD operations. | |
| 2714 if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) && | |
| 2715 op != Token::ADD) { | |
| 2716 new_left = new_right = BinaryOpIC::GENERIC; | |
| 2717 } | |
| 2718 | |
| 2719 BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right); | |
| 2720 BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right); | |
| 2721 | |
| 2722 Maybe<int> previous_fixed_right_arg = | |
| 2723 BinaryOpStub::decode_fixed_right_arg_from_minor_key(key); | |
| 2724 | |
| 2725 int32_t value; | |
| 2726 bool new_has_fixed_right_arg = | |
| 2727 op == Token::MOD && | |
| 2728 right->ToInt32(&value) && | |
| 2729 BinaryOpStub::can_encode_arg_value(value) && | |
| 2730 (previous_overall == BinaryOpIC::UNINITIALIZED || | |
| 2731 (previous_fixed_right_arg.has_value && | |
| 2732 previous_fixed_right_arg.value == value)); | |
| 2733 Maybe<int32_t> new_fixed_right_arg( | |
| 2734 new_has_fixed_right_arg, new_has_fixed_right_arg ? value : 1); | |
| 2735 | |
| 2736 if (previous_fixed_right_arg.has_value == new_fixed_right_arg.has_value) { | |
| 2737 if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { | |
| 2738 if (op == Token::DIV || | |
| 2739 op == Token::MUL || | |
| 2740 op == Token::SHR || | |
| 2741 SmiValuesAre32Bits()) { | |
| 2742 // Arithmetic on two Smi inputs has yielded a heap number. | |
| 2743 // That is the only way to get here from the Smi stub. | |
| 2744 // With 32-bit Smis, all overflows give heap numbers, but with | |
| 2745 // 31-bit Smis, most operations overflow to int32 results. | |
| 2746 result_type = BinaryOpIC::NUMBER; | |
| 2747 } else { | |
| 2748 // Other operations on SMIs that overflow yield int32s. | |
| 2749 result_type = BinaryOpIC::INT32; | |
| 2750 } | |
| 2751 } | |
| 2752 if (new_overall == BinaryOpIC::INT32 && | |
| 2753 previous_overall == BinaryOpIC::INT32) { | |
| 2754 if (new_left == previous_left && new_right == previous_right) { | |
| 2755 result_type = BinaryOpIC::NUMBER; | |
| 2756 } | |
| 2757 } | |
| 2758 } | |
| 2759 | |
| 2760 BinaryOpStub stub(key, new_left, new_right, result_type, new_fixed_right_arg); | |
| 2761 Handle<Code> code = stub.GetCode(isolate); | |
| 2762 if (!code.is_null()) { | |
| 2763 #ifdef DEBUG | |
| 2764 if (FLAG_trace_ic) { | |
| 2765 PrintF("[BinaryOpIC in "); | |
| 2766 JavaScriptFrame::PrintTop(isolate, stdout, false, true); | |
| 2767 PrintF(" "); | |
| 2768 TraceBinaryOp(previous_left, previous_right, previous_fixed_right_arg, | |
| 2769 previous_result); | |
| 2770 PrintF(" => "); | |
| 2771 TraceBinaryOp(new_left, new_right, new_fixed_right_arg, result_type); | |
| 2772 PrintF(" #%s @ %p]\n", Token::Name(op), static_cast<void*>(*code)); | |
| 2773 } | |
| 2774 #endif | |
| 2775 BinaryOpIC ic(isolate); | |
| 2776 ic.patch(*code); | |
| 2777 | |
| 2778 // Activate inlined smi code. | |
| 2779 if (previous_overall == BinaryOpIC::UNINITIALIZED) { | |
| 2780 PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); | |
| 2781 } | |
| 2782 } | |
| 2783 | |
| 2784 Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object()); | |
| 2785 Object* builtin = NULL; // Initialization calms down the compiler. | |
| 2786 switch (op) { | |
| 2787 case Token::ADD: | |
| 2788 builtin = builtins->javascript_builtin(Builtins::ADD); | |
| 2789 break; | |
| 2790 case Token::SUB: | |
| 2791 builtin = builtins->javascript_builtin(Builtins::SUB); | |
| 2792 break; | |
| 2793 case Token::MUL: | |
| 2794 builtin = builtins->javascript_builtin(Builtins::MUL); | |
| 2795 break; | |
| 2796 case Token::DIV: | |
| 2797 builtin = builtins->javascript_builtin(Builtins::DIV); | |
| 2798 break; | |
| 2799 case Token::MOD: | |
| 2800 builtin = builtins->javascript_builtin(Builtins::MOD); | |
| 2801 break; | |
| 2802 case Token::BIT_AND: | |
| 2803 builtin = builtins->javascript_builtin(Builtins::BIT_AND); | |
| 2804 break; | |
| 2805 case Token::BIT_OR: | |
| 2806 builtin = builtins->javascript_builtin(Builtins::BIT_OR); | |
| 2807 break; | |
| 2808 case Token::BIT_XOR: | |
| 2809 builtin = builtins->javascript_builtin(Builtins::BIT_XOR); | |
| 2810 break; | |
| 2811 case Token::SHR: | |
| 2812 builtin = builtins->javascript_builtin(Builtins::SHR); | |
| 2813 break; | |
| 2814 case Token::SAR: | |
| 2815 builtin = builtins->javascript_builtin(Builtins::SAR); | |
| 2816 break; | |
| 2817 case Token::SHL: | |
| 2818 builtin = builtins->javascript_builtin(Builtins::SHL); | |
| 2819 break; | |
| 2820 default: | |
| 2821 UNREACHABLE(); | |
| 2822 } | |
| 2823 | |
| 2824 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate); | |
| 2825 | |
| 2826 bool caught_exception; | |
| 2827 Handle<Object> builtin_args[] = { right }; | |
| 2828 Handle<Object> result = Execution::Call(isolate, | |
| 2829 builtin_function, | |
| 2830 left, | |
| 2831 ARRAY_SIZE(builtin_args), | |
| 2832 builtin_args, | |
| 2833 &caught_exception); | |
| 2834 if (caught_exception) { | |
| 2835 return Failure::Exception(); | |
| 2836 } | |
| 2837 return *result; | |
| 2838 } | |
| 2839 | |
| 2840 | |
| 2841 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { | 2407 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { |
| 2842 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2408 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
| 2843 Code* code = NULL; | 2409 Code* code = NULL; |
| 2844 CHECK(stub.FindCodeInCache(&code, isolate)); | 2410 CHECK(stub.FindCodeInCache(&code, isolate)); |
| 2845 return code; | 2411 return code; |
| 2846 } | 2412 } |
| 2847 | 2413 |
| 2848 | 2414 |
| 2849 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { | 2415 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { |
| 2850 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2416 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3054 | 2620 |
| 3055 // Activate inlined smi code. | 2621 // Activate inlined smi code. |
| 3056 if (previous_state == UNINITIALIZED) { | 2622 if (previous_state == UNINITIALIZED) { |
| 3057 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); | 2623 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 3058 } | 2624 } |
| 3059 } | 2625 } |
| 3060 | 2626 |
| 3061 | 2627 |
| 3062 // Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc. | 2628 // Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc. |
| 3063 RUNTIME_FUNCTION(Code*, CompareIC_Miss) { | 2629 RUNTIME_FUNCTION(Code*, CompareIC_Miss) { |
| 3064 SealHandleScope shs(isolate); | 2630 HandleScope scope(isolate); |
| 3065 ASSERT(args.length() == 3); | 2631 ASSERT(args.length() == 3); |
| 3066 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); | 2632 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); |
| 3067 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); | 2633 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); |
| 3068 return ic.target(); | 2634 return ic.raw_target(); |
| 3069 } | 2635 } |
| 3070 | 2636 |
| 3071 | 2637 |
| 3072 void CompareNilIC::Clear(Address address, Code* target) { | 2638 void CompareNilIC::Clear(Address address, Code* target) { |
| 3073 if (target->ic_state() == UNINITIALIZED) return; | 2639 if (IsCleared(target)) return; |
| 3074 Code::ExtraICState state = target->extended_extra_ic_state(); | 2640 Code::ExtraICState state = target->extended_extra_ic_state(); |
| 3075 | 2641 |
| 3076 CompareNilICStub stub(state, HydrogenCodeStub::UNINITIALIZED); | 2642 CompareNilICStub stub(state, HydrogenCodeStub::UNINITIALIZED); |
| 3077 stub.ClearState(); | 2643 stub.ClearState(); |
| 3078 | 2644 |
| 3079 Code* code = NULL; | 2645 Code* code = NULL; |
| 3080 CHECK(stub.FindCodeInCache(&code, target->GetIsolate())); | 2646 CHECK(stub.FindCodeInCache(&code, target->GetIsolate())); |
| 3081 | 2647 |
| 3082 SetTargetAtAddress(address, code); | 2648 SetTargetAtAddress(address, code); |
| 3083 } | 2649 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3128 } | 2694 } |
| 3129 | 2695 |
| 3130 | 2696 |
| 3131 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { | 2697 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { |
| 3132 UNREACHABLE(); | 2698 UNREACHABLE(); |
| 3133 CHECK(false); | 2699 CHECK(false); |
| 3134 return isolate->heap()->undefined_value(); | 2700 return isolate->heap()->undefined_value(); |
| 3135 } | 2701 } |
| 3136 | 2702 |
| 3137 | 2703 |
| 2704 Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) { |
| 2705 switch (op) { |
| 2706 default: |
| 2707 UNREACHABLE(); |
| 2708 case Token::ADD: |
| 2709 return Builtins::ADD; |
| 2710 break; |
| 2711 case Token::SUB: |
| 2712 return Builtins::SUB; |
| 2713 break; |
| 2714 case Token::MUL: |
| 2715 return Builtins::MUL; |
| 2716 break; |
| 2717 case Token::DIV: |
| 2718 return Builtins::DIV; |
| 2719 break; |
| 2720 case Token::MOD: |
| 2721 return Builtins::MOD; |
| 2722 break; |
| 2723 case Token::BIT_OR: |
| 2724 return Builtins::BIT_OR; |
| 2725 break; |
| 2726 case Token::BIT_AND: |
| 2727 return Builtins::BIT_AND; |
| 2728 break; |
| 2729 case Token::BIT_XOR: |
| 2730 return Builtins::BIT_XOR; |
| 2731 break; |
| 2732 case Token::SAR: |
| 2733 return Builtins::SAR; |
| 2734 break; |
| 2735 case Token::SHR: |
| 2736 return Builtins::SHR; |
| 2737 break; |
| 2738 case Token::SHL: |
| 2739 return Builtins::SHL; |
| 2740 break; |
| 2741 } |
| 2742 } |
| 2743 |
| 2744 |
| 3138 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, | 2745 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, |
| 3139 Code::ExtraICState extra_ic_state) { | 2746 Code::ExtraICState extra_ic_state) { |
| 3140 ToBooleanStub stub(extra_ic_state); | 2747 ToBooleanStub stub(extra_ic_state); |
| 3141 bool to_boolean_value = stub.UpdateStatus(object); | 2748 bool to_boolean_value = stub.UpdateStatus(object); |
| 3142 Handle<Code> code = stub.GetCode(isolate()); | 2749 Handle<Code> code = stub.GetCode(isolate()); |
| 3143 set_target(*code); | 2750 set_target(*code); |
| 3144 return Smi::FromInt(to_boolean_value ? 1 : 0); | 2751 return Smi::FromInt(to_boolean_value ? 1 : 0); |
| 3145 } | 2752 } |
| 3146 | 2753 |
| 3147 | 2754 |
| 3148 RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss) { | 2755 RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss) { |
| 3149 ASSERT(args.length() == 1); | 2756 ASSERT(args.length() == 1); |
| 3150 HandleScope scope(isolate); | 2757 HandleScope scope(isolate); |
| 3151 Handle<Object> object = args.at<Object>(0); | 2758 Handle<Object> object = args.at<Object>(0); |
| 3152 ToBooleanIC ic(isolate); | 2759 ToBooleanIC ic(isolate); |
| 3153 Code::ExtraICState ic_state = ic.target()->extended_extra_ic_state(); | 2760 Code::ExtraICState extra_ic_state = ic.target()->extended_extra_ic_state(); |
| 3154 return ic.ToBoolean(object, ic_state); | 2761 return ic.ToBoolean(object, extra_ic_state); |
| 3155 } | 2762 } |
| 3156 | 2763 |
| 3157 | 2764 |
| 3158 static const Address IC_utilities[] = { | 2765 static const Address IC_utilities[] = { |
| 3159 #define ADDR(name) FUNCTION_ADDR(name), | 2766 #define ADDR(name) FUNCTION_ADDR(name), |
| 3160 IC_UTIL_LIST(ADDR) | 2767 IC_UTIL_LIST(ADDR) |
| 3161 NULL | 2768 NULL |
| 3162 #undef ADDR | 2769 #undef ADDR |
| 3163 }; | 2770 }; |
| 3164 | 2771 |
| 3165 | 2772 |
| 3166 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2773 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 3167 return IC_utilities[id]; | 2774 return IC_utilities[id]; |
| 3168 } | 2775 } |
| 3169 | 2776 |
| 3170 | 2777 |
| 3171 } } // namespace v8::internal | 2778 } } // namespace v8::internal |
| OLD | NEW |