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 Code* new_target) { | |
76 if (FLAG_trace_ic) { | 75 if (FLAG_trace_ic) { |
76 Code* new_target = raw_target(); | |
77 State new_state = new_target->ic_state(); | 77 State new_state = new_target->ic_state(); |
78 PrintF("[%s in ", type); | 78 PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type); |
79 StackFrameIterator it(isolate()); | 79 StackFrameIterator it(isolate()); |
80 while (it.frame()->fp() != this->fp()) it.Advance(); | 80 while (it.frame()->fp() != this->fp()) it.Advance(); |
81 StackFrame* raw_frame = it.frame(); | 81 StackFrame* raw_frame = it.frame(); |
82 if (raw_frame->is_internal()) { | 82 if (raw_frame->is_internal()) { |
83 Code* apply_builtin = isolate()->builtins()->builtin( | 83 Code* apply_builtin = isolate()->builtins()->builtin( |
84 Builtins::kFunctionApply); | 84 Builtins::kFunctionApply); |
85 if (raw_frame->unchecked_code() == apply_builtin) { | 85 if (raw_frame->unchecked_code() == apply_builtin) { |
86 PrintF("apply from "); | 86 PrintF("apply from "); |
87 it.Advance(); | 87 it.Advance(); |
88 raw_frame = it.frame(); | 88 raw_frame = it.frame(); |
(...skipping 18 matching lines...) Expand all Loading... | |
107 PrintF("[%s patching generic stub in ", type); \ | 107 PrintF("[%s patching generic stub in ", type); \ |
108 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \ | 108 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \ |
109 PrintF(" (%s)]\n", reason); \ | 109 PrintF(" (%s)]\n", reason); \ |
110 } \ | 110 } \ |
111 } while (false) | 111 } while (false) |
112 | 112 |
113 #else | 113 #else |
114 #define TRACE_GENERIC_IC(isolate, type, reason) | 114 #define TRACE_GENERIC_IC(isolate, type, reason) |
115 #endif // DEBUG | 115 #endif // DEBUG |
116 | 116 |
117 #define TRACE_IC(type, name, new_target) \ | 117 #define TRACE_IC(type, name) \ |
118 ASSERT((TraceIC(type, name, *new_target), true)) | 118 ASSERT((TraceIC(type, name), true)) |
119 | 119 |
120 IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) { | 120 IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) { |
121 // 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 |
122 // 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 |
123 // 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. |
124 const Address entry = | 124 const Address entry = |
125 Isolate::c_entry_fp(isolate->thread_local_top()); | 125 Isolate::c_entry_fp(isolate->thread_local_top()); |
126 Address* pc_address = | 126 Address* pc_address = |
127 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); | 127 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); |
128 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); | 128 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
171 // 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 |
172 // the call which has been overwritten by the DebugBreakXXX resides | 172 // the call which has been overwritten by the DebugBreakXXX resides |
173 // and the place where the inline cache system should look. | 173 // and the place where the inline cache system should look. |
174 intptr_t delta = | 174 intptr_t delta = |
175 original_code->instruction_start() - code->instruction_start(); | 175 original_code->instruction_start() - code->instruction_start(); |
176 return addr + delta; | 176 return addr + delta; |
177 } | 177 } |
178 #endif | 178 #endif |
179 | 179 |
180 | 180 |
181 bool IC::TryRemoveInvalidPrototypeDependentStub(Object* receiver, | 181 static bool HasInterceptorGetter(JSObject* object) { |
182 Object* name) { | 182 return !object->GetNamedInterceptor()->getter()->IsUndefined(); |
183 } | |
184 | |
185 | |
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) { | |
183 DisallowHeapAllocation no_gc; | 271 DisallowHeapAllocation no_gc; |
184 | 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 | |
185 if (target()->is_keyed_stub()) { | 281 if (target()->is_keyed_stub()) { |
186 // Determine whether the failure is due to a name failure. | 282 // Determine whether the failure is due to a name failure. |
187 if (!name->IsName()) return false; | 283 if (!name->IsName()) return false; |
188 Name* stub_name = target()->FindFirstName(); | 284 Name* stub_name = target()->FindFirstName(); |
189 if (Name::cast(name) != stub_name) return false; | 285 if (*name != stub_name) return false; |
190 } | 286 } |
191 | 287 |
192 InlineCacheHolderFlag cache_holder = | 288 InlineCacheHolderFlag cache_holder = |
193 Code::ExtractCacheHolderFromFlags(target()->flags()); | 289 Code::ExtractCacheHolderFromFlags(target()->flags()); |
194 | 290 |
195 switch (cache_holder) { | 291 switch (cache_holder) { |
196 case OWN_MAP: | 292 case OWN_MAP: |
197 // The stub was generated for JSObject but called for non-JSObject. | 293 // The stub was generated for JSObject but called for non-JSObject. |
198 // IC::GetCodeCacheHolder is not applicable. | 294 // IC::GetCodeCacheHolder is not applicable. |
199 if (!receiver->IsJSObject()) return false; | 295 if (!receiver->IsJSObject()) return false; |
200 break; | 296 break; |
201 case PROTOTYPE_MAP: | 297 case PROTOTYPE_MAP: |
202 // IC::GetCodeCacheHolder is not applicable. | 298 // IC::GetCodeCacheHolder is not applicable. |
203 if (receiver->GetPrototype(isolate())->IsNull()) return false; | 299 if (receiver->GetPrototype(isolate())->IsNull()) return false; |
204 break; | 300 break; |
205 } | 301 } |
206 | 302 |
207 Map* map = IC::GetCodeCacheHolder(isolate(), receiver, cache_holder)->map(); | 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 // Handlers are stored in addition to the ICs on the map. Remove those, too. | 316 // Handlers are stored in addition to the ICs on the map. Remove those, too. |
221 Code* handler = target()->FindFirstHandler(); | 317 Code* handler = target()->FindFirstHandler(); |
222 if (handler != NULL) { | 318 if (handler != NULL) { |
223 index = map->IndexInCodeCache(name, handler); | 319 index = map->IndexInCodeCache(*name, handler); |
224 if (index >= 0) { | 320 if (index >= 0) { |
225 map->RemoveFromCodeCache(String::cast(name), handler, index); | 321 map->RemoveFromCodeCache(*name, handler, index); |
226 } | 322 } |
227 } | 323 } |
228 return true; | 324 return true; |
229 } | 325 } |
230 | 326 |
231 // 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 |
232 // 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 |
233 // 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 |
234 // constant global property that will become mutable. Threat all those | 330 // constant global property that will become mutable. Threat all those |
235 // situations as prototype failures (stay monomorphic if possible). | 331 // situations as prototype failures (stay monomorphic if possible). |
236 | 332 |
237 // 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 |
238 // the map cannot be deprecated and the stub invalidated. | 334 // the map cannot be deprecated and the stub invalidated. |
239 if (cache_holder == OWN_MAP) { | 335 if (cache_holder == OWN_MAP) { |
240 Map* old_map = target()->FindFirstMap(); | 336 Map* old_map = target()->FindFirstMap(); |
241 if (old_map == map) return true; | 337 if (old_map == map) return true; |
242 if (old_map != NULL) { | 338 if (old_map != NULL) { |
243 if (old_map->is_deprecated()) return true; | 339 if (old_map->is_deprecated()) return true; |
244 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(), | 340 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(), |
245 map->elements_kind())) { | 341 map->elements_kind())) { |
246 return true; | 342 return true; |
247 } | 343 } |
248 } | 344 } |
249 } | 345 } |
250 | 346 |
251 if (receiver->IsGlobalObject()) { | 347 if (receiver->IsGlobalObject()) { |
252 if (!name->IsName()) return false; | |
253 LookupResult lookup(isolate()); | 348 LookupResult lookup(isolate()); |
254 GlobalObject* global = GlobalObject::cast(receiver); | 349 GlobalObject* global = GlobalObject::cast(*receiver); |
255 global->LocalLookupRealNamedProperty(Name::cast(name), &lookup); | 350 global->LocalLookupRealNamedProperty(*name, &lookup); |
256 if (!lookup.IsFound()) return false; | 351 if (!lookup.IsFound()) return false; |
257 PropertyCell* cell = global->GetPropertyCell(&lookup); | 352 PropertyCell* cell = global->GetPropertyCell(&lookup); |
258 return cell->type()->IsConstant(); | 353 return cell->type()->IsConstant(); |
259 } | 354 } |
260 | 355 |
261 return false; | 356 return false; |
262 } | 357 } |
263 | 358 |
264 | 359 |
265 void IC::UpdateState(Object* receiver, Object* name) { | 360 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { |
266 if (state() != MONOMORPHIC || !name->IsString()) return; | 361 if (state() != MONOMORPHIC || !name->IsString()) return; |
267 if (receiver->IsUndefined() || receiver->IsNull()) return; | 362 if (receiver->IsUndefined() || receiver->IsNull()) return; |
268 | 363 |
269 Code::Kind kind = target()->kind(); | |
270 // Remove the target from the code cache if it became invalid | 364 // Remove the target from the code cache if it became invalid |
271 // because of changes in the prototype chain to avoid hitting it | 365 // because of changes in the prototype chain to avoid hitting it |
272 // again. | 366 // again. |
273 // Call stubs handle this later to allow extra IC state | 367 if (TryRemoveInvalidPrototypeDependentStub( |
274 // transitions. | 368 receiver, Handle<String>::cast(name))) { |
275 if (kind != Code::CALL_IC && kind != Code::KEYED_CALL_IC && | 369 return MarkMonomorphicPrototypeFailure(); |
276 TryRemoveInvalidPrototypeDependentStub(receiver, name)) { | |
277 MarkMonomorphicPrototypeFailure(); | |
278 return; | |
279 } | 370 } |
280 | 371 |
281 // The builtins object is special. It only changes when JavaScript | 372 // The builtins object is special. It only changes when JavaScript |
282 // builtins are loaded lazily. It is important to keep inline | 373 // builtins are loaded lazily. It is important to keep inline |
283 // caches for the builtins object monomorphic. Therefore, if we get | 374 // caches for the builtins object monomorphic. Therefore, if we get |
284 // an inline cache miss for the builtins object after lazily loading | 375 // an inline cache miss for the builtins object after lazily loading |
285 // JavaScript builtins, we return uninitialized as the state to | 376 // JavaScript builtins, we return uninitialized as the state to |
286 // force the inline cache back to monomorphic state. | 377 // force the inline cache back to monomorphic state. |
287 if (receiver->IsJSBuiltinsObject()) state_ = UNINITIALIZED; | 378 if (receiver->IsJSBuiltinsObject()) state_ = UNINITIALIZED; |
288 } | 379 } |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
442 Token::Value op; | 533 Token::Value op; |
443 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL, | 534 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL, |
444 &handler_state, &op); | 535 &handler_state, &op); |
445 // Only clear CompareICs that can retain objects. | 536 // Only clear CompareICs that can retain objects. |
446 if (handler_state != KNOWN_OBJECT) return; | 537 if (handler_state != KNOWN_OBJECT) return; |
447 SetTargetAtAddress(address, GetRawUninitialized(isolate, op)); | 538 SetTargetAtAddress(address, GetRawUninitialized(isolate, op)); |
448 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); | 539 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); |
449 } | 540 } |
450 | 541 |
451 | 542 |
452 static bool HasInterceptorGetter(JSObject* object) { | |
453 return !object->GetNamedInterceptor()->getter()->IsUndefined(); | |
454 } | |
455 | |
456 | |
457 static bool HasInterceptorSetter(JSObject* object) { | |
458 return !object->GetNamedInterceptor()->setter()->IsUndefined(); | |
459 } | |
460 | |
461 | |
462 static void LookupForRead(Handle<Object> object, | |
463 Handle<String> name, | |
464 LookupResult* lookup) { | |
465 // Skip all the objects with named interceptors, but | |
466 // without actual getter. | |
467 while (true) { | |
468 object->Lookup(*name, lookup); | |
469 // Besides normal conditions (property not found or it's not | |
470 // an interceptor), bail out if lookup is not cacheable: we won't | |
471 // be able to IC it anyway and regular lookup should work fine. | |
472 if (!lookup->IsInterceptor() || !lookup->IsCacheable()) { | |
473 return; | |
474 } | |
475 | |
476 Handle<JSObject> holder(lookup->holder(), lookup->isolate()); | |
477 if (HasInterceptorGetter(*holder)) { | |
478 return; | |
479 } | |
480 | |
481 holder->LocalLookupRealNamedProperty(*name, lookup); | |
482 if (lookup->IsFound()) { | |
483 ASSERT(!lookup->IsInterceptor()); | |
484 return; | |
485 } | |
486 | |
487 Handle<Object> proto(holder->GetPrototype(), lookup->isolate()); | |
488 if (proto->IsNull()) { | |
489 ASSERT(!lookup->IsFound()); | |
490 return; | |
491 } | |
492 | |
493 object = proto; | |
494 } | |
495 } | |
496 | |
497 | |
498 Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) { | 543 Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) { |
499 Handle<Object> delegate = Execution::GetFunctionDelegate(isolate(), object); | 544 Handle<Object> delegate = Execution::GetFunctionDelegate(isolate(), object); |
500 | 545 |
501 if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) { | 546 if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) { |
502 // Patch the receiver and use the delegate as the function to | 547 // Patch the receiver and use the delegate as the function to |
503 // 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. |
504 const int argc = target()->arguments_count(); | 549 const int argc = target()->arguments_count(); |
505 StackFrameLocator locator(isolate()); | 550 StackFrameLocator locator(isolate()); |
506 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 551 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
507 int index = frame->ComputeExpressionsCount() - (argc + 1); | 552 int index = frame->ComputeExpressionsCount() - (argc + 1); |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
624 } | 669 } |
625 | 670 |
626 // 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. |
627 result = TryCallAsFunction(result); | 672 result = TryCallAsFunction(result); |
628 if (result->IsJSFunction()) return *result; | 673 if (result->IsJSFunction()) return *result; |
629 | 674 |
630 return TypeError("property_not_function", object, name); | 675 return TypeError("property_not_function", object, name); |
631 } | 676 } |
632 | 677 |
633 | 678 |
634 bool CallIC::TryUpdateExtraICState(LookupResult* lookup, | |
635 Handle<Object> object) { | |
636 if (!lookup->IsConstantFunction()) return false; | |
637 JSFunction* function = lookup->GetConstantFunction(); | |
638 if (!function->shared()->HasBuiltinFunctionId()) return false; | |
639 | |
640 // Fetch the arguments passed to the called function. | |
641 const int argc = target()->arguments_count(); | |
642 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top()); | |
643 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); | |
644 Arguments args(argc + 1, | |
645 &Memory::Object_at(fp + | |
646 StandardFrameConstants::kCallerSPOffset + | |
647 argc * kPointerSize)); | |
648 switch (function->shared()->builtin_function_id()) { | |
649 case kStringCharCodeAt: | |
650 case kStringCharAt: | |
651 if (object->IsString()) { | |
652 String* string = String::cast(*object); | |
653 // Check there's the right string value or wrapper in the receiver slot. | |
654 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value()); | |
655 // If we're in the default (fastest) state and the index is | |
656 // out of bounds, update the state to record this fact. | |
657 if (StringStubState::decode(extra_ic_state()) == DEFAULT_STRING_STUB && | |
658 argc >= 1 && args[1]->IsNumber()) { | |
659 double index = DoubleToInteger(args.number_at(1)); | |
660 if (index < 0 || index >= string->length()) { | |
661 extra_ic_state_ = | |
662 StringStubState::update(extra_ic_state(), | |
663 STRING_INDEX_OUT_OF_BOUNDS); | |
664 return true; | |
665 } | |
666 } | |
667 } | |
668 break; | |
669 default: | |
670 return false; | |
671 } | |
672 return false; | |
673 } | |
674 | |
675 | |
676 Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, | 679 Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, |
677 Code::ExtraICState extra_state, | |
678 Handle<Object> object, | 680 Handle<Object> object, |
679 Handle<String> name) { | 681 Handle<String> name) { |
680 int argc = target()->arguments_count(); | 682 int argc = target()->arguments_count(); |
681 Handle<JSObject> holder(lookup->holder(), isolate()); | 683 Handle<JSObject> holder(lookup->holder(), isolate()); |
682 switch (lookup->type()) { | 684 switch (lookup->type()) { |
683 case FIELD: { | 685 case FIELD: { |
684 PropertyIndex index = lookup->GetFieldIndex(); | 686 PropertyIndex index = lookup->GetFieldIndex(); |
685 return isolate()->stub_cache()->ComputeCallField( | 687 return isolate()->stub_cache()->ComputeCallField( |
686 argc, kind_, extra_state, name, object, holder, index); | 688 argc, kind_, extra_ic_state(), name, object, holder, index); |
687 } | 689 } |
688 case CONSTANT: { | 690 case CONSTANT: { |
689 if (!lookup->IsConstantFunction()) return Handle<Code>::null(); | 691 if (!lookup->IsConstantFunction()) return Handle<Code>::null(); |
690 // Get the constant function and compute the code stub for this | 692 // Get the constant function and compute the code stub for this |
691 // call; used for rewriting to monomorphic state and making sure | 693 // call; used for rewriting to monomorphic state and making sure |
692 // that the code stub is in the stub cache. | 694 // that the code stub is in the stub cache. |
693 Handle<JSFunction> function(lookup->GetConstantFunction(), isolate()); | 695 Handle<JSFunction> function(lookup->GetConstantFunction(), isolate()); |
694 return isolate()->stub_cache()->ComputeCallConstant( | 696 return isolate()->stub_cache()->ComputeCallConstant( |
695 argc, kind_, extra_state, name, object, holder, function); | 697 argc, kind_, extra_ic_state(), name, object, holder, function); |
696 } | 698 } |
697 case NORMAL: { | 699 case NORMAL: { |
698 // 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. |
699 if (!object->IsJSObject()) return Handle<Code>::null(); | 701 if (!object->IsJSObject()) return Handle<Code>::null(); |
700 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 702 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
701 | 703 |
702 if (holder->IsGlobalObject()) { | 704 if (holder->IsGlobalObject()) { |
703 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); | 705 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
704 Handle<PropertyCell> cell( | 706 Handle<PropertyCell> cell( |
705 global->GetPropertyCell(lookup), isolate()); | 707 global->GetPropertyCell(lookup), isolate()); |
706 if (!cell->value()->IsJSFunction()) return Handle<Code>::null(); | 708 if (!cell->value()->IsJSFunction()) return Handle<Code>::null(); |
707 Handle<JSFunction> function(JSFunction::cast(cell->value())); | 709 Handle<JSFunction> function(JSFunction::cast(cell->value())); |
708 return isolate()->stub_cache()->ComputeCallGlobal( | 710 return isolate()->stub_cache()->ComputeCallGlobal( |
709 argc, kind_, extra_state, name, receiver, global, cell, function); | 711 argc, kind_, extra_ic_state(), name, |
712 receiver, global, cell, function); | |
710 } else { | 713 } else { |
711 // There is only one shared stub for calling normalized | 714 // There is only one shared stub for calling normalized |
712 // properties. It does not traverse the prototype chain, so the | 715 // properties. It does not traverse the prototype chain, so the |
713 // 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 |
714 // applicable. | 717 // applicable. |
715 if (!holder.is_identical_to(receiver)) return Handle<Code>::null(); | 718 if (!holder.is_identical_to(receiver)) return Handle<Code>::null(); |
716 return isolate()->stub_cache()->ComputeCallNormal( | 719 return isolate()->stub_cache()->ComputeCallNormal( |
717 argc, kind_, extra_state); | 720 argc, kind_, extra_ic_state()); |
718 } | 721 } |
719 break; | 722 break; |
720 } | 723 } |
721 case INTERCEPTOR: | 724 case INTERCEPTOR: |
722 ASSERT(HasInterceptorGetter(*holder)); | 725 ASSERT(HasInterceptorGetter(*holder)); |
723 return isolate()->stub_cache()->ComputeCallInterceptor( | 726 return isolate()->stub_cache()->ComputeCallInterceptor( |
724 argc, kind_, extra_state, name, object, holder); | 727 argc, kind_, extra_ic_state(), name, object, holder); |
725 default: | 728 default: |
726 return Handle<Code>::null(); | 729 return Handle<Code>::null(); |
727 } | 730 } |
728 } | 731 } |
729 | 732 |
730 | 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 | |
731 void CallICBase::UpdateCaches(LookupResult* lookup, | 746 void CallICBase::UpdateCaches(LookupResult* lookup, |
732 Handle<Object> object, | 747 Handle<Object> object, |
733 Handle<String> name) { | 748 Handle<String> name) { |
734 // Bail out if we didn't find a result. | 749 // Bail out if we didn't find a result. |
735 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 750 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
736 | 751 |
737 // Compute the number of arguments. | 752 // Compute the number of arguments. |
738 int argc = target()->arguments_count(); | |
739 Handle<Code> code; | 753 Handle<Code> code; |
740 if (state() == UNINITIALIZED) { | 754 code = state() == UNINITIALIZED |
741 // This is the first time we execute this inline cache. | 755 ? pre_monomorphic_stub() |
742 // Set the target to the pre monomorphic stub to delay | 756 : ComputeMonomorphicStub(lookup, object, name); |
743 // setting the monomorphic state. | |
744 code = isolate()->stub_cache()->ComputeCallPreMonomorphic( | |
745 argc, kind_, extra_ic_state()); | |
746 } else if (state() == MONOMORPHIC) { | |
747 if (kind_ == Code::CALL_IC && | |
748 static_cast<CallIC*>(this)->TryUpdateExtraICState(lookup, object)) { | |
749 code = ComputeMonomorphicStub(lookup, extra_ic_state(), object, name); | |
750 } else if (TryRemoveInvalidPrototypeDependentStub(*object, *name)) { | |
751 MarkMonomorphicPrototypeFailure(); | |
752 code = ComputeMonomorphicStub(lookup, extra_ic_state(), object, name); | |
753 } else { | |
754 code = isolate()->stub_cache()->ComputeCallMegamorphic( | |
755 argc, kind_, extra_ic_state()); | |
ulan
2013/10/02 08:45:24
Why are we removing these cases?
Toon Verwaest
2013/10/02 08:56:05
They aren't removed, they are just folded in the e
| |
756 } | |
757 } else { | |
758 code = ComputeMonomorphicStub(lookup, extra_ic_state(), object, name); | |
759 } | |
760 | 757 |
761 // 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. | |
762 if (code.is_null()) return; | 761 if (code.is_null()) return; |
763 | 762 |
764 // Patch the call site depending on the state of the cache. | 763 Handle<JSObject> cache_object = object->IsJSObject() |
765 switch (state()) { | 764 ? Handle<JSObject>::cast(object) |
766 case UNINITIALIZED: | 765 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), |
767 case MONOMORPHIC_PROTOTYPE_FAILURE: | 766 isolate()); |
768 case PREMONOMORPHIC: | |
769 case MONOMORPHIC: | |
770 set_target(*code); | |
771 break; | |
772 case MEGAMORPHIC: { | |
773 // Cache code holding map should be consistent with | |
774 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. | |
775 Handle<JSObject> cache_object = object->IsJSObject() | |
776 ? Handle<JSObject>::cast(object) | |
777 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), | |
778 isolate()); | |
779 // Update the stub cache. | |
780 UpdateMegamorphicCache(cache_object->map(), *name, *code); | |
781 break; | |
782 } | |
783 case DEBUG_STUB: | |
784 break; | |
785 case POLYMORPHIC: | |
786 case GENERIC: | |
787 UNREACHABLE(); | |
788 break; | |
789 } | |
790 | 767 |
791 TRACE_IC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", name, target()); | 768 PatchCache(cache_object, name, code); |
769 TRACE_IC("CallIC", name); | |
792 } | 770 } |
793 | 771 |
794 | 772 |
795 MaybeObject* KeyedCallIC::LoadFunction(Handle<Object> object, | 773 MaybeObject* KeyedCallIC::LoadFunction(Handle<Object> object, |
796 Handle<Object> key) { | 774 Handle<Object> key) { |
797 if (key->IsInternalizedString()) { | 775 if (key->IsInternalizedString()) { |
798 return CallICBase::LoadFunction(object, Handle<String>::cast(key)); | 776 return CallICBase::LoadFunction(object, Handle<String>::cast(key)); |
799 } | 777 } |
800 | 778 |
801 if (object->IsUndefined() || object->IsNull()) { | 779 if (object->IsUndefined() || object->IsNull()) { |
(...skipping 10 matching lines...) Expand all Loading... | |
812 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState); | 790 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState); |
813 if (object->IsJSObject()) { | 791 if (object->IsJSObject()) { |
814 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 792 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
815 if (receiver->elements()->map() == | 793 if (receiver->elements()->map() == |
816 isolate()->heap()->non_strict_arguments_elements_map()) { | 794 isolate()->heap()->non_strict_arguments_elements_map()) { |
817 stub = isolate()->stub_cache()->ComputeCallArguments(argc); | 795 stub = isolate()->stub_cache()->ComputeCallArguments(argc); |
818 } | 796 } |
819 } | 797 } |
820 ASSERT(!stub.is_null()); | 798 ASSERT(!stub.is_null()); |
821 set_target(*stub); | 799 set_target(*stub); |
822 TRACE_IC("KeyedCallIC", key, target()); | 800 TRACE_IC("CallIC", key); |
823 } | 801 } |
824 | 802 |
825 Handle<Object> result = GetProperty(isolate(), object, key); | 803 Handle<Object> result = GetProperty(isolate(), object, key); |
826 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 804 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
827 | 805 |
828 // 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 |
829 // functions do not wrap the receiver, non-strict functions and objects | 807 // functions do not wrap the receiver, non-strict functions and objects |
830 // called as functions do. | 808 // called as functions do. |
831 ReceiverToObjectIfRequired(result, object); | 809 ReceiverToObjectIfRequired(result, object); |
832 if (result->IsJSFunction()) return *result; | 810 if (result->IsJSFunction()) return *result; |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1050 void IC::PatchCache(Handle<HeapObject> receiver, | 1028 void IC::PatchCache(Handle<HeapObject> receiver, |
1051 Handle<String> name, | 1029 Handle<String> name, |
1052 Handle<Code> code) { | 1030 Handle<Code> code) { |
1053 switch (state()) { | 1031 switch (state()) { |
1054 case UNINITIALIZED: | 1032 case UNINITIALIZED: |
1055 case PREMONOMORPHIC: | 1033 case PREMONOMORPHIC: |
1056 case MONOMORPHIC_PROTOTYPE_FAILURE: | 1034 case MONOMORPHIC_PROTOTYPE_FAILURE: |
1057 UpdateMonomorphicIC(receiver, code, name); | 1035 UpdateMonomorphicIC(receiver, code, name); |
1058 break; | 1036 break; |
1059 case MONOMORPHIC: | 1037 case MONOMORPHIC: |
1060 ASSERT(!target().is_identical_to(code)); | 1038 // For now, call stubs are allowed to rewrite to the same stub. This |
1039 // happens e.g., when the field does not contain a function. | |
1040 ASSERT(target()->is_call_stub() || | |
1041 target()->is_keyed_call_stub() || | |
1042 !target().is_identical_to(code)); | |
1061 if (!target()->is_keyed_stub()) { | 1043 if (!target()->is_keyed_stub()) { |
1062 bool is_same_handler = false; | 1044 bool is_same_handler = false; |
1063 { | 1045 { |
1064 DisallowHeapAllocation no_allocation; | 1046 DisallowHeapAllocation no_allocation; |
1065 Code* old_handler = target()->FindFirstHandler(); | 1047 Code* old_handler = target()->FindFirstHandler(); |
1066 is_same_handler = old_handler == *code; | 1048 is_same_handler = old_handler == *code; |
1067 } | 1049 } |
1068 if (is_same_handler | 1050 if (is_same_handler |
1069 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) { | 1051 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) { |
1070 UpdateMonomorphicIC(receiver, code, name); | 1052 UpdateMonomorphicIC(receiver, code, name); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1137 } else if (!object->IsJSObject()) { | 1119 } else if (!object->IsJSObject()) { |
1138 // TODO(jkummerow): It would be nice to support non-JSObjects in | 1120 // TODO(jkummerow): It would be nice to support non-JSObjects in |
1139 // ComputeLoadHandler, then we wouldn't need to go generic here. | 1121 // ComputeLoadHandler, then we wouldn't need to go generic here. |
1140 code = slow_stub(); | 1122 code = slow_stub(); |
1141 } else { | 1123 } else { |
1142 code = ComputeLoadHandler(lookup, Handle<JSObject>::cast(receiver), name); | 1124 code = ComputeLoadHandler(lookup, Handle<JSObject>::cast(receiver), name); |
1143 if (code.is_null()) code = slow_stub(); | 1125 if (code.is_null()) code = slow_stub(); |
1144 } | 1126 } |
1145 | 1127 |
1146 PatchCache(receiver, name, code); | 1128 PatchCache(receiver, name, code); |
1147 TRACE_IC("LoadIC", name, target()); | 1129 TRACE_IC("LoadIC", name); |
1148 } | 1130 } |
1149 | 1131 |
1150 | 1132 |
1151 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) { | 1133 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) { |
1152 // Cache code holding map should be consistent with | 1134 // Cache code holding map should be consistent with |
1153 // GenerateMonomorphicCacheProbe. | 1135 // GenerateMonomorphicCacheProbe. |
1154 isolate()->stub_cache()->Set(name, map, code); | 1136 isolate()->stub_cache()->Set(name, map, code); |
1155 } | 1137 } |
1156 | 1138 |
1157 | 1139 |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1359 } else if (receiver->HasIndexedInterceptor()) { | 1341 } else if (receiver->HasIndexedInterceptor()) { |
1360 stub = indexed_interceptor_stub(); | 1342 stub = indexed_interceptor_stub(); |
1361 } else if (!key->ToSmi()->IsFailure() && | 1343 } else if (!key->ToSmi()->IsFailure() && |
1362 (!target().is_identical_to(non_strict_arguments_stub()))) { | 1344 (!target().is_identical_to(non_strict_arguments_stub()))) { |
1363 stub = LoadElementStub(receiver); | 1345 stub = LoadElementStub(receiver); |
1364 } | 1346 } |
1365 } | 1347 } |
1366 | 1348 |
1367 ASSERT(!stub.is_null()); | 1349 ASSERT(!stub.is_null()); |
1368 set_target(*stub); | 1350 set_target(*stub); |
1369 TRACE_IC("KeyedLoadIC", key, target()); | 1351 TRACE_IC("LoadIC", key); |
1370 } | 1352 } |
1371 | 1353 |
1372 | 1354 |
1373 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); | 1355 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); |
1374 } | 1356 } |
1375 | 1357 |
1376 | 1358 |
1377 Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, | 1359 Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, |
1378 Handle<JSObject> receiver, | 1360 Handle<JSObject> receiver, |
1379 Handle<String> name) { | 1361 Handle<String> name) { |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1551 // to have fast properties but a read-only length. | 1533 // to have fast properties but a read-only length. |
1552 if (FLAG_use_ic && | 1534 if (FLAG_use_ic && |
1553 receiver->IsJSArray() && | 1535 receiver->IsJSArray() && |
1554 name->Equals(isolate()->heap()->length_string()) && | 1536 name->Equals(isolate()->heap()->length_string()) && |
1555 Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() && | 1537 Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() && |
1556 receiver->HasFastProperties() && | 1538 receiver->HasFastProperties() && |
1557 !receiver->map()->is_frozen()) { | 1539 !receiver->map()->is_frozen()) { |
1558 Handle<Code> stub = | 1540 Handle<Code> stub = |
1559 StoreArrayLengthStub(kind(), strict_mode()).GetCode(isolate()); | 1541 StoreArrayLengthStub(kind(), strict_mode()).GetCode(isolate()); |
1560 set_target(*stub); | 1542 set_target(*stub); |
1561 TRACE_IC("StoreIC", name, stub); | 1543 TRACE_IC("StoreIC", name); |
1562 Handle<Object> result = JSReceiver::SetProperty( | 1544 Handle<Object> result = JSReceiver::SetProperty( |
1563 receiver, name, value, NONE, strict_mode(), store_mode); | 1545 receiver, name, value, NONE, strict_mode(), store_mode); |
1564 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 1546 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
1565 return *result; | 1547 return *result; |
1566 } | 1548 } |
1567 | 1549 |
1568 if (receiver->IsJSGlobalProxy()) { | 1550 if (receiver->IsJSGlobalProxy()) { |
1569 if (FLAG_use_ic && kind() != Code::KEYED_STORE_IC) { | 1551 if (FLAG_use_ic && kind() != Code::KEYED_STORE_IC) { |
1570 // Generate a generic stub that goes to the runtime when we see a global | 1552 // Generate a generic stub that goes to the runtime when we see a global |
1571 // proxy as receiver. | 1553 // proxy as receiver. |
1572 Handle<Code> stub = global_proxy_stub(); | 1554 Handle<Code> stub = global_proxy_stub(); |
1573 set_target(*stub); | 1555 set_target(*stub); |
1574 TRACE_IC("StoreIC", name, stub); | 1556 TRACE_IC("StoreIC", name); |
1575 } | 1557 } |
1576 Handle<Object> result = JSReceiver::SetProperty( | 1558 Handle<Object> result = JSReceiver::SetProperty( |
1577 receiver, name, value, NONE, strict_mode(), store_mode); | 1559 receiver, name, value, NONE, strict_mode(), store_mode); |
1578 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 1560 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
1579 return *result; | 1561 return *result; |
1580 } | 1562 } |
1581 | 1563 |
1582 LookupResult lookup(isolate()); | 1564 LookupResult lookup(isolate()); |
1583 bool can_store = LookupForWrite(receiver, name, value, &lookup, this); | 1565 bool can_store = LookupForWrite(receiver, name, value, &lookup, this); |
1584 if (!can_store && | 1566 if (!can_store && |
1585 strict_mode() == kStrictMode && | 1567 strict_mode() == kStrictMode && |
1586 !(lookup.IsProperty() && lookup.IsReadOnly()) && | 1568 !(lookup.IsProperty() && lookup.IsReadOnly()) && |
1587 IsUndeclaredGlobal(object)) { | 1569 IsUndeclaredGlobal(object)) { |
1588 // Strict mode doesn't allow setting non-existent global property. | 1570 // Strict mode doesn't allow setting non-existent global property. |
1589 return ReferenceError("not_defined", name); | 1571 return ReferenceError("not_defined", name); |
1590 } | 1572 } |
1591 if (FLAG_use_ic) { | 1573 if (FLAG_use_ic) { |
1592 if (state() == UNINITIALIZED) { | 1574 if (state() == UNINITIALIZED) { |
1593 Handle<Code> stub = pre_monomorphic_stub(); | 1575 Handle<Code> stub = pre_monomorphic_stub(); |
1594 set_target(*stub); | 1576 set_target(*stub); |
1595 TRACE_IC("StoreIC", name, stub); | 1577 TRACE_IC("StoreIC", name); |
1596 } else if (can_store) { | 1578 } else if (can_store) { |
1597 UpdateCaches(&lookup, receiver, name, value); | 1579 UpdateCaches(&lookup, receiver, name, value); |
1598 } else if (!name->IsCacheable(isolate()) || | 1580 } else if (!name->IsCacheable(isolate()) || |
1599 lookup.IsNormal() || | 1581 lookup.IsNormal() || |
1600 (lookup.IsField() && lookup.CanHoldValue(value))) { | 1582 (lookup.IsField() && lookup.CanHoldValue(value))) { |
1601 Handle<Code> stub = generic_stub(); | 1583 Handle<Code> stub = generic_stub(); |
1602 set_target(*stub); | 1584 set_target(*stub); |
1603 } | 1585 } |
1604 } | 1586 } |
1605 | 1587 |
(...skipping 15 matching lines...) Expand all Loading... | |
1621 // These are not cacheable, so we never see such LookupResults here. | 1603 // These are not cacheable, so we never see such LookupResults here. |
1622 ASSERT(!lookup->IsHandler()); | 1604 ASSERT(!lookup->IsHandler()); |
1623 | 1605 |
1624 Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value); | 1606 Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value); |
1625 if (code.is_null()) { | 1607 if (code.is_null()) { |
1626 set_target(*generic_stub()); | 1608 set_target(*generic_stub()); |
1627 return; | 1609 return; |
1628 } | 1610 } |
1629 | 1611 |
1630 PatchCache(receiver, name, code); | 1612 PatchCache(receiver, name, code); |
1631 TRACE_IC("StoreIC", name, target()); | 1613 TRACE_IC("StoreIC", name); |
1632 } | 1614 } |
1633 | 1615 |
1634 | 1616 |
1635 Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup, | 1617 Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup, |
1636 Handle<JSObject> receiver, | 1618 Handle<JSObject> receiver, |
1637 Handle<String> name, | 1619 Handle<String> name, |
1638 Handle<Object> value) { | 1620 Handle<Object> value) { |
1639 Handle<JSObject> holder(lookup->holder()); | 1621 Handle<JSObject> holder(lookup->holder()); |
1640 switch (lookup->type()) { | 1622 switch (lookup->type()) { |
1641 case FIELD: | 1623 case FIELD: |
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2009 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "key not a number"); | 1991 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "key not a number"); |
2010 } | 1992 } |
2011 } else { | 1993 } else { |
2012 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "not an object"); | 1994 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "not an object"); |
2013 } | 1995 } |
2014 } else { | 1996 } else { |
2015 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "force generic"); | 1997 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "force generic"); |
2016 } | 1998 } |
2017 ASSERT(!stub.is_null()); | 1999 ASSERT(!stub.is_null()); |
2018 set_target(*stub); | 2000 set_target(*stub); |
2019 TRACE_IC("KeyedStoreIC", key, target()); | 2001 TRACE_IC("StoreIC", key); |
2020 } | 2002 } |
2021 | 2003 |
2022 return Runtime::SetObjectPropertyOrFail( | 2004 return Runtime::SetObjectPropertyOrFail( |
2023 isolate(), object , key, value, NONE, strict_mode()); | 2005 isolate(), object , key, value, NONE, strict_mode()); |
2024 } | 2006 } |
2025 | 2007 |
2026 | 2008 |
2027 Handle<Code> KeyedStoreIC::ComputeStoreHandler(LookupResult* lookup, | 2009 Handle<Code> KeyedStoreIC::ComputeStoreHandler(LookupResult* lookup, |
2028 Handle<JSObject> receiver, | 2010 Handle<JSObject> receiver, |
2029 Handle<String> name, | 2011 Handle<String> name, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2072 | 2054 |
2073 // ---------------------------------------------------------------------------- | 2055 // ---------------------------------------------------------------------------- |
2074 // Static IC stub generators. | 2056 // Static IC stub generators. |
2075 // | 2057 // |
2076 | 2058 |
2077 // Used from ic-<arch>.cc. | 2059 // Used from ic-<arch>.cc. |
2078 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { | 2060 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { |
2079 HandleScope scope(isolate); | 2061 HandleScope scope(isolate); |
2080 ASSERT(args.length() == 2); | 2062 ASSERT(args.length() == 2); |
2081 CallIC ic(isolate); | 2063 CallIC ic(isolate); |
2082 ic.UpdateState(args[0], args[1]); | 2064 Handle<Object> receiver = args.at<Object>(0); |
2083 MaybeObject* maybe_result = ic.LoadFunction(args.at<Object>(0), | 2065 Handle<String> key = args.at<String>(1); |
2084 args.at<String>(1)); | 2066 ic.UpdateState(receiver, key); |
2067 MaybeObject* maybe_result = ic.LoadFunction(receiver, key); | |
2085 JSFunction* raw_function; | 2068 JSFunction* raw_function; |
2086 if (!maybe_result->To(&raw_function)) return maybe_result; | 2069 if (!maybe_result->To(&raw_function)) return maybe_result; |
2087 | 2070 |
2088 // The first time the inline cache is updated may be the first time the | 2071 // The first time the inline cache is updated may be the first time the |
2089 // function it references gets called. If the function is lazily compiled | 2072 // function it references gets called. If the function is lazily compiled |
2090 // then the first call will trigger a compilation. We check for this case | 2073 // then the first call will trigger a compilation. We check for this case |
2091 // and we do the compilation immediately, instead of waiting for the stub | 2074 // and we do the compilation immediately, instead of waiting for the stub |
2092 // currently attached to the JSFunction object to trigger compilation. | 2075 // currently attached to the JSFunction object to trigger compilation. |
2093 if (raw_function->is_compiled()) return raw_function; | 2076 if (raw_function->is_compiled()) return raw_function; |
2094 | 2077 |
2095 Handle<JSFunction> function(raw_function); | 2078 Handle<JSFunction> function(raw_function); |
2096 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); | 2079 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); |
2097 return *function; | 2080 return *function; |
2098 } | 2081 } |
2099 | 2082 |
2100 | 2083 |
2101 // Used from ic-<arch>.cc. | 2084 // Used from ic-<arch>.cc. |
2102 RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) { | 2085 RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) { |
2103 HandleScope scope(isolate); | 2086 HandleScope scope(isolate); |
2104 ASSERT(args.length() == 2); | 2087 ASSERT(args.length() == 2); |
2105 KeyedCallIC ic(isolate); | 2088 KeyedCallIC ic(isolate); |
2106 ic.UpdateState(args[0], args[1]); | 2089 Handle<Object> receiver = args.at<Object>(0); |
2107 MaybeObject* maybe_result = | 2090 Handle<Object> key = args.at<Object>(1); |
2108 ic.LoadFunction(args.at<Object>(0), args.at<Object>(1)); | 2091 ic.UpdateState(receiver, key); |
2092 MaybeObject* maybe_result = ic.LoadFunction(receiver, key); | |
2109 // Result could be a function or a failure. | 2093 // Result could be a function or a failure. |
2110 JSFunction* raw_function = NULL; | 2094 JSFunction* raw_function = NULL; |
2111 if (!maybe_result->To(&raw_function)) return maybe_result; | 2095 if (!maybe_result->To(&raw_function)) return maybe_result; |
2112 | 2096 |
2113 if (raw_function->is_compiled()) return raw_function; | 2097 if (raw_function->is_compiled()) return raw_function; |
2114 | 2098 |
2115 Handle<JSFunction> function(raw_function, isolate); | 2099 Handle<JSFunction> function(raw_function, isolate); |
2116 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); | 2100 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); |
2117 return *function; | 2101 return *function; |
2118 } | 2102 } |
2119 | 2103 |
2120 | 2104 |
2121 // Used from ic-<arch>.cc. | 2105 // Used from ic-<arch>.cc. |
2122 RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { | 2106 RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { |
2123 HandleScope scope(isolate); | 2107 HandleScope scope(isolate); |
2124 ASSERT(args.length() == 2); | 2108 ASSERT(args.length() == 2); |
2125 LoadIC ic(IC::NO_EXTRA_FRAME, isolate); | 2109 LoadIC ic(IC::NO_EXTRA_FRAME, isolate); |
2126 ic.UpdateState(args[0], args[1]); | 2110 Handle<Object> receiver = args.at<Object>(0); |
2127 return ic.Load(args.at<Object>(0), args.at<String>(1)); | 2111 Handle<String> key = args.at<String>(1); |
2112 ic.UpdateState(receiver, key); | |
2113 return ic.Load(receiver, key); | |
2128 } | 2114 } |
2129 | 2115 |
2130 | 2116 |
2131 // Used from ic-<arch>.cc | 2117 // Used from ic-<arch>.cc |
2132 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { | 2118 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { |
2133 HandleScope scope(isolate); | 2119 HandleScope scope(isolate); |
2134 ASSERT(args.length() == 2); | 2120 ASSERT(args.length() == 2); |
2135 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate); | 2121 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate); |
2136 ic.UpdateState(args[0], args[1]); | 2122 Handle<Object> receiver = args.at<Object>(0); |
2137 return ic.Load(args.at<Object>(0), args.at<Object>(1), MISS); | 2123 Handle<Object> key = args.at<Object>(1); |
2124 ic.UpdateState(receiver, key); | |
2125 return ic.Load(receiver, key, MISS); | |
2138 } | 2126 } |
2139 | 2127 |
2140 | 2128 |
2141 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure) { | 2129 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure) { |
2142 HandleScope scope(isolate); | 2130 HandleScope scope(isolate); |
2143 ASSERT(args.length() == 2); | 2131 ASSERT(args.length() == 2); |
2144 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate); | 2132 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate); |
2145 ic.UpdateState(args[0], args[1]); | 2133 Handle<Object> receiver = args.at<Object>(0); |
2146 return ic.Load(args.at<Object>(0), args.at<Object>(1), MISS); | 2134 Handle<Object> key = args.at<Object>(1); |
2135 ic.UpdateState(receiver, key); | |
2136 return ic.Load(receiver, key, MISS); | |
2147 } | 2137 } |
2148 | 2138 |
2149 | 2139 |
2150 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) { | 2140 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) { |
2151 HandleScope scope(isolate); | 2141 HandleScope scope(isolate); |
2152 ASSERT(args.length() == 2); | 2142 ASSERT(args.length() == 2); |
2153 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate); | 2143 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate); |
2154 ic.UpdateState(args[0], args[1]); | 2144 Handle<Object> receiver = args.at<Object>(0); |
2155 return ic.Load(args.at<Object>(0), | 2145 Handle<Object> key = args.at<Object>(1); |
2156 args.at<Object>(1), | 2146 ic.UpdateState(receiver, key); |
2157 MISS_FORCE_GENERIC); | 2147 return ic.Load(receiver, key, MISS_FORCE_GENERIC); |
2158 } | 2148 } |
2159 | 2149 |
2160 | 2150 |
2161 // Used from ic-<arch>.cc. | 2151 // Used from ic-<arch>.cc. |
2162 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { | 2152 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { |
2163 HandleScope scope(isolate); | 2153 HandleScope scope(isolate); |
2164 ASSERT(args.length() == 3); | 2154 ASSERT(args.length() == 3); |
2165 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2155 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
2166 ic.UpdateState(args[0], args[1]); | 2156 Handle<Object> receiver = args.at<Object>(0); |
2167 return ic.Store(args.at<Object>(0), | 2157 Handle<String> key = args.at<String>(1); |
2168 args.at<String>(1), | 2158 ic.UpdateState(receiver, key); |
2169 args.at<Object>(2)); | 2159 return ic.Store(receiver, key, args.at<Object>(2)); |
2170 } | 2160 } |
2171 | 2161 |
2172 | 2162 |
2173 RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) { | 2163 RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) { |
2174 HandleScope scope(isolate); | 2164 HandleScope scope(isolate); |
2175 ASSERT(args.length() == 3); | 2165 ASSERT(args.length() == 3); |
2176 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate); | 2166 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate); |
2177 ic.UpdateState(args[0], args[1]); | 2167 Handle<Object> receiver = args.at<Object>(0); |
2178 return ic.Store(args.at<Object>(0), | 2168 Handle<String> key = args.at<String>(1); |
2179 args.at<String>(1), | 2169 ic.UpdateState(receiver, key); |
2180 args.at<Object>(2)); | 2170 return ic.Store(receiver, key, args.at<Object>(2)); |
2181 } | 2171 } |
2182 | 2172 |
2183 | 2173 |
2184 RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) { | 2174 RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) { |
2185 SealHandleScope shs(isolate); | 2175 SealHandleScope shs(isolate); |
2186 | 2176 |
2187 ASSERT(args.length() == 2); | 2177 ASSERT(args.length() == 2); |
2188 JSArray* receiver = JSArray::cast(args[0]); | 2178 JSArray* receiver = JSArray::cast(args[0]); |
2189 Object* len = args[1]; | 2179 Object* len = args[1]; |
2190 | 2180 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2253 // Return the stored value. | 2243 // Return the stored value. |
2254 return value; | 2244 return value; |
2255 } | 2245 } |
2256 | 2246 |
2257 | 2247 |
2258 // Used from ic-<arch>.cc. | 2248 // Used from ic-<arch>.cc. |
2259 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { | 2249 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { |
2260 HandleScope scope(isolate); | 2250 HandleScope scope(isolate); |
2261 ASSERT(args.length() == 3); | 2251 ASSERT(args.length() == 3); |
2262 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2252 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
2263 ic.UpdateState(args[0], args[1]); | 2253 Handle<Object> receiver = args.at<Object>(0); |
2264 return ic.Store(args.at<Object>(0), | 2254 Handle<Object> key = args.at<Object>(1); |
2265 args.at<Object>(1), | 2255 ic.UpdateState(receiver, key); |
2266 args.at<Object>(2), | 2256 return ic.Store(receiver, key, args.at<Object>(2), MISS); |
2267 MISS); | |
2268 } | 2257 } |
2269 | 2258 |
2270 | 2259 |
2271 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure) { | 2260 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure) { |
2272 HandleScope scope(isolate); | 2261 HandleScope scope(isolate); |
2273 ASSERT(args.length() == 3); | 2262 ASSERT(args.length() == 3); |
2274 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); | 2263 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); |
2275 ic.UpdateState(args[0], args[1]); | 2264 Handle<Object> receiver = args.at<Object>(0); |
2276 return ic.Store(args.at<Object>(0), | 2265 Handle<Object> key = args.at<Object>(1); |
2277 args.at<Object>(1), | 2266 ic.UpdateState(receiver, key); |
2278 args.at<Object>(2), | 2267 return ic.Store(receiver, key, args.at<Object>(2), MISS); |
2279 MISS); | |
2280 } | 2268 } |
2281 | 2269 |
2282 | 2270 |
2283 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) { | 2271 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) { |
2284 HandleScope scope(isolate); | 2272 HandleScope scope(isolate); |
2285 ASSERT(args.length() == 3); | 2273 ASSERT(args.length() == 3); |
2286 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2274 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
2287 Handle<Object> object = args.at<Object>(0); | 2275 Handle<Object> object = args.at<Object>(0); |
2288 Handle<Object> key = args.at<Object>(1); | 2276 Handle<Object> key = args.at<Object>(1); |
2289 Handle<Object> value = args.at<Object>(2); | 2277 Handle<Object> value = args.at<Object>(2); |
(...skipping 21 matching lines...) Expand all Loading... | |
2311 value, | 2299 value, |
2312 NONE, | 2300 NONE, |
2313 strict_mode); | 2301 strict_mode); |
2314 } | 2302 } |
2315 | 2303 |
2316 | 2304 |
2317 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { | 2305 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { |
2318 HandleScope scope(isolate); | 2306 HandleScope scope(isolate); |
2319 ASSERT(args.length() == 3); | 2307 ASSERT(args.length() == 3); |
2320 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); | 2308 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); |
2321 ic.UpdateState(args[0], args[1]); | 2309 Handle<Object> receiver = args.at<Object>(0); |
2322 return ic.Store(args.at<Object>(0), | 2310 Handle<Object> key = args.at<Object>(1); |
2323 args.at<Object>(1), | 2311 ic.UpdateState(receiver, key); |
2324 args.at<Object>(2), | 2312 return ic.Store(receiver, key, args.at<Object>(2), MISS_FORCE_GENERIC); |
2325 MISS_FORCE_GENERIC); | |
2326 } | 2313 } |
2327 | 2314 |
2328 | 2315 |
2329 RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) { | 2316 RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) { |
2330 HandleScope scope(isolate); | 2317 HandleScope scope(isolate); |
2331 ASSERT(args.length() == 4); | 2318 ASSERT(args.length() == 4); |
2332 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); | 2319 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); |
2333 Handle<Object> value = args.at<Object>(0); | 2320 Handle<Object> value = args.at<Object>(0); |
2334 Handle<Object> key = args.at<Object>(2); | 2321 Handle<Object> key = args.at<Object>(2); |
2335 Handle<Object> object = args.at<Object>(3); | 2322 Handle<Object> object = args.at<Object>(3); |
(...skipping 603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2939 #undef ADDR | 2926 #undef ADDR |
2940 }; | 2927 }; |
2941 | 2928 |
2942 | 2929 |
2943 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2930 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2944 return IC_utilities[id]; | 2931 return IC_utilities[id]; |
2945 } | 2932 } |
2946 | 2933 |
2947 | 2934 |
2948 } } // namespace v8::internal | 2935 } } // namespace v8::internal |
OLD | NEW |