Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: src/ic.cc

Issue 6529032: Merge 6168:6800 from bleeding_edge to experimental/gc branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ic.h ('k') | src/inspector.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 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 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 !current->IsJSGlobalProxy() && 147 !current->IsJSGlobalProxy() &&
148 !current->IsJSGlobalObject()) { 148 !current->IsJSGlobalObject()) {
149 return true; 149 return true;
150 } 150 }
151 } 151 }
152 152
153 return false; 153 return false;
154 } 154 }
155 155
156 156
157 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { 157 static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
158 IC::State state = target->ic_state(); 158 Object* receiver,
159 159 Object* name) {
160 if (state != MONOMORPHIC || !name->IsString()) return state;
161 if (receiver->IsUndefined() || receiver->IsNull()) return state;
162
163 InlineCacheHolderFlag cache_holder = 160 InlineCacheHolderFlag cache_holder =
164 Code::ExtractCacheHolderFromFlags(target->flags()); 161 Code::ExtractCacheHolderFromFlags(target->flags());
165 162
166
167 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { 163 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) {
168 // The stub was generated for JSObject but called for non-JSObject. 164 // The stub was generated for JSObject but called for non-JSObject.
169 // IC::GetCodeCacheHolder is not applicable. 165 // IC::GetCodeCacheHolder is not applicable.
170 return MONOMORPHIC; 166 return false;
171 } else if (cache_holder == PROTOTYPE_MAP && 167 } else if (cache_holder == PROTOTYPE_MAP &&
172 receiver->GetPrototype()->IsNull()) { 168 receiver->GetPrototype()->IsNull()) {
173 // IC::GetCodeCacheHolder is not applicable. 169 // IC::GetCodeCacheHolder is not applicable.
174 return MONOMORPHIC; 170 return false;
175 } 171 }
176 Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map(); 172 Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map();
177 173
178 // Decide whether the inline cache failed because of changes to the 174 // Decide whether the inline cache failed because of changes to the
179 // receiver itself or changes to one of its prototypes. 175 // receiver itself or changes to one of its prototypes.
180 // 176 //
181 // If there are changes to the receiver itself, the map of the 177 // If there are changes to the receiver itself, the map of the
182 // receiver will have changed and the current target will not be in 178 // receiver will have changed and the current target will not be in
183 // the receiver map's code cache. Therefore, if the current target 179 // the receiver map's code cache. Therefore, if the current target
184 // is in the receiver map's code cache, the inline cache failed due 180 // is in the receiver map's code cache, the inline cache failed due
185 // to prototype check failure. 181 // to prototype check failure.
186 int index = map->IndexInCodeCache(name, target); 182 int index = map->IndexInCodeCache(name, target);
187 if (index >= 0) { 183 if (index >= 0) {
188 // For keyed load/store/call, the most likely cause of cache failure is 184 map->RemoveFromCodeCache(String::cast(name), target, index);
189 // that the key has changed. We do not distinguish between 185 return true;
190 // prototype and non-prototype failures for keyed access. 186 }
191 Code::Kind kind = target->kind();
192 if (kind == Code::KEYED_LOAD_IC ||
193 kind == Code::KEYED_STORE_IC ||
194 kind == Code::KEYED_CALL_IC) {
195 return MONOMORPHIC;
196 }
197 187
198 // Remove the target from the code cache to avoid hitting the same 188 return false;
199 // invalid stub again. 189 }
200 map->RemoveFromCodeCache(String::cast(name), target, index);
201 190
191
192 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
193 IC::State state = target->ic_state();
194
195 if (state != MONOMORPHIC || !name->IsString()) return state;
196 if (receiver->IsUndefined() || receiver->IsNull()) return state;
197
198 // For keyed load/store/call, the most likely cause of cache failure is
199 // that the key has changed. We do not distinguish between
200 // prototype and non-prototype failures for keyed access.
201 Code::Kind kind = target->kind();
202 if (kind == Code::KEYED_LOAD_IC ||
203 kind == Code::KEYED_STORE_IC ||
204 kind == Code::KEYED_CALL_IC) {
205 return MONOMORPHIC;
206 }
207
208 // Remove the target from the code cache if it became invalid
209 // because of changes in the prototype chain to avoid hitting it
210 // again.
211 // Call stubs handle this later to allow extra IC state
212 // transitions.
213 if (kind != Code::CALL_IC &&
214 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) {
202 return MONOMORPHIC_PROTOTYPE_FAILURE; 215 return MONOMORPHIC_PROTOTYPE_FAILURE;
203 } 216 }
204 217
205 // The builtins object is special. It only changes when JavaScript 218 // The builtins object is special. It only changes when JavaScript
206 // builtins are loaded lazily. It is important to keep inline 219 // builtins are loaded lazily. It is important to keep inline
207 // caches for the builtins object monomorphic. Therefore, if we get 220 // caches for the builtins object monomorphic. Therefore, if we get
208 // an inline cache miss for the builtins object after lazily loading 221 // an inline cache miss for the builtins object after lazily loading
209 // JavaScript builtins, we return uninitialized as the state to 222 // JavaScript builtins, we return uninitialized as the state to
210 // force the inline cache back to monomorphic state. 223 // force the inline cache back to monomorphic state.
211 if (receiver->IsJSBuiltinsObject()) { 224 if (receiver->IsJSBuiltinsObject()) {
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
322 // Reset the map check of the inlined inobject property store (if 335 // Reset the map check of the inlined inobject property store (if
323 // present) to guarantee failure by holding an invalid map (the null 336 // present) to guarantee failure by holding an invalid map (the null
324 // value). The offset can be patched to anything. 337 // value). The offset can be patched to anything.
325 PatchInlinedStore(address, Heap::null_value(), 0); 338 PatchInlinedStore(address, Heap::null_value(), 0);
326 } 339 }
327 340
328 341
329 void StoreIC::Clear(Address address, Code* target) { 342 void StoreIC::Clear(Address address, Code* target) {
330 if (target->ic_state() == UNINITIALIZED) return; 343 if (target->ic_state() == UNINITIALIZED) return;
331 ClearInlinedVersion(address); 344 ClearInlinedVersion(address);
332 SetTargetAtAddress(address, initialize_stub()); 345 SetTargetAtAddress(address,
346 target->extra_ic_state() == kStoreICStrict
347 ? initialize_stub_strict()
348 : initialize_stub());
333 } 349 }
334 350
335 351
336 void KeyedStoreIC::ClearInlinedVersion(Address address) { 352 void KeyedStoreIC::ClearInlinedVersion(Address address) {
337 // Insert null as the elements map to check for. This will make 353 // Insert null as the elements map to check for. This will make
338 // sure that the elements fast-case map check fails so that control 354 // sure that the elements fast-case map check fails so that control
339 // flows to the IC instead of the inlined version. 355 // flows to the IC instead of the inlined version.
340 PatchInlinedStore(address, Heap::null_value()); 356 PatchInlinedStore(address, Heap::null_value());
341 } 357 }
342 358
343 359
344 void KeyedStoreIC::RestoreInlinedVersion(Address address) { 360 void KeyedStoreIC::RestoreInlinedVersion(Address address) {
345 // Restore the fast-case elements map check so that the inlined 361 // Restore the fast-case elements map check so that the inlined
346 // version can be used again. 362 // version can be used again.
347 PatchInlinedStore(address, Heap::fixed_array_map()); 363 PatchInlinedStore(address, Heap::fixed_array_map());
348 } 364 }
349 365
350 366
351 void KeyedStoreIC::Clear(Address address, Code* target) { 367 void KeyedStoreIC::Clear(Address address, Code* target) {
352 if (target->ic_state() == UNINITIALIZED) return; 368 if (target->ic_state() == UNINITIALIZED) return;
353 SetTargetAtAddress(address, initialize_stub()); 369 SetTargetAtAddress(address, initialize_stub());
354 } 370 }
355 371
356 372
357 Code* KeyedLoadIC::external_array_stub(JSObject::ElementsKind elements_kind) {
358 switch (elements_kind) {
359 case JSObject::EXTERNAL_BYTE_ELEMENTS:
360 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalByteArray);
361 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
362 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalUnsignedByteArray);
363 case JSObject::EXTERNAL_SHORT_ELEMENTS:
364 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalShortArray);
365 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
366 return Builtins::builtin(
367 Builtins::KeyedLoadIC_ExternalUnsignedShortArray);
368 case JSObject::EXTERNAL_INT_ELEMENTS:
369 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalIntArray);
370 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
371 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalUnsignedIntArray);
372 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
373 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalFloatArray);
374 default:
375 UNREACHABLE();
376 return NULL;
377 }
378 }
379
380
381 Code* KeyedStoreIC::external_array_stub(JSObject::ElementsKind elements_kind) {
382 switch (elements_kind) {
383 case JSObject::EXTERNAL_BYTE_ELEMENTS:
384 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalByteArray);
385 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
386 return Builtins::builtin(
387 Builtins::KeyedStoreIC_ExternalUnsignedByteArray);
388 case JSObject::EXTERNAL_SHORT_ELEMENTS:
389 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalShortArray);
390 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
391 return Builtins::builtin(
392 Builtins::KeyedStoreIC_ExternalUnsignedShortArray);
393 case JSObject::EXTERNAL_INT_ELEMENTS:
394 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalIntArray);
395 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
396 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalUnsignedIntArray);
397 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
398 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalFloatArray);
399 default:
400 UNREACHABLE();
401 return NULL;
402 }
403 }
404
405
406 static bool HasInterceptorGetter(JSObject* object) { 373 static bool HasInterceptorGetter(JSObject* object) {
407 return !object->GetNamedInterceptor()->getter()->IsUndefined(); 374 return !object->GetNamedInterceptor()->getter()->IsUndefined();
408 } 375 }
409 376
410 377
411 static void LookupForRead(Object* object, 378 static void LookupForRead(Object* object,
412 String* name, 379 String* name,
413 LookupResult* lookup) { 380 LookupResult* lookup) {
414 AssertNoAllocation no_gc; // pointers must stay valid 381 AssertNoAllocation no_gc; // pointers must stay valid
415 382
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 // Change the receiver to the result of calling ToObject on it. 442 // Change the receiver to the result of calling ToObject on it.
476 const int argc = this->target()->arguments_count(); 443 const int argc = this->target()->arguments_count();
477 StackFrameLocator locator; 444 StackFrameLocator locator;
478 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 445 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
479 int index = frame->ComputeExpressionsCount() - (argc + 1); 446 int index = frame->ComputeExpressionsCount() - (argc + 1);
480 frame->SetExpression(index, *Factory::ToObject(object)); 447 frame->SetExpression(index, *Factory::ToObject(object));
481 } 448 }
482 449
483 450
484 MaybeObject* CallICBase::LoadFunction(State state, 451 MaybeObject* CallICBase::LoadFunction(State state,
452 Code::ExtraICState extra_ic_state,
485 Handle<Object> object, 453 Handle<Object> object,
486 Handle<String> name) { 454 Handle<String> name) {
487 // If the object is undefined or null it's illegal to try to get any 455 // If the object is undefined or null it's illegal to try to get any
488 // of its properties; throw a TypeError in that case. 456 // of its properties; throw a TypeError in that case.
489 if (object->IsUndefined() || object->IsNull()) { 457 if (object->IsUndefined() || object->IsNull()) {
490 return TypeError("non_object_property_call", object, name); 458 return TypeError("non_object_property_call", object, name);
491 } 459 }
492 460
493 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { 461 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
494 ReceiverToObject(object); 462 ReceiverToObject(object);
(...skipping 25 matching lines...) Expand all
520 // If the object does not have the requested property, check which 488 // If the object does not have the requested property, check which
521 // exception we need to throw. 489 // exception we need to throw.
522 if (IsContextual(object)) { 490 if (IsContextual(object)) {
523 return ReferenceError("not_defined", name); 491 return ReferenceError("not_defined", name);
524 } 492 }
525 return TypeError("undefined_method", object, name); 493 return TypeError("undefined_method", object, name);
526 } 494 }
527 495
528 // Lookup is valid: Update inline cache and stub cache. 496 // Lookup is valid: Update inline cache and stub cache.
529 if (FLAG_use_ic) { 497 if (FLAG_use_ic) {
530 UpdateCaches(&lookup, state, object, name); 498 UpdateCaches(&lookup, state, extra_ic_state, object, name);
531 } 499 }
532 500
533 // Get the property. 501 // Get the property.
534 PropertyAttributes attr; 502 PropertyAttributes attr;
535 Object* result; 503 Object* result;
536 { MaybeObject* maybe_result = 504 { MaybeObject* maybe_result =
537 object->GetProperty(*object, &lookup, *name, &attr); 505 object->GetProperty(*object, &lookup, *name, &attr);
538 if (!maybe_result->ToObject(&result)) return maybe_result; 506 if (!maybe_result->ToObject(&result)) return maybe_result;
539 } 507 }
540 if (lookup.type() == INTERCEPTOR) { 508 if (lookup.type() == INTERCEPTOR) {
(...skipping 28 matching lines...) Expand all
569 // Try to find a suitable function delegate for the object at hand. 537 // Try to find a suitable function delegate for the object at hand.
570 result = TryCallAsFunction(result); 538 result = TryCallAsFunction(result);
571 MaybeObject* answer = result; 539 MaybeObject* answer = result;
572 if (!result->IsJSFunction()) { 540 if (!result->IsJSFunction()) {
573 answer = TypeError("property_not_function", object, name); 541 answer = TypeError("property_not_function", object, name);
574 } 542 }
575 return answer; 543 return answer;
576 } 544 }
577 545
578 546
547 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup,
548 Handle<Object> object,
549 Code::ExtraICState* extra_ic_state) {
550 ASSERT(kind_ == Code::CALL_IC);
551 if (lookup->type() != CONSTANT_FUNCTION) return false;
552 JSFunction* function = lookup->GetConstantFunction();
553 if (!function->shared()->HasBuiltinFunctionId()) return false;
554
555 // Fetch the arguments passed to the called function.
556 const int argc = target()->arguments_count();
557 Address entry = Top::c_entry_fp(Top::GetCurrentThread());
558 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
559 Arguments args(argc + 1,
560 &Memory::Object_at(fp +
561 StandardFrameConstants::kCallerSPOffset +
562 argc * kPointerSize));
563 switch (function->shared()->builtin_function_id()) {
564 case kStringCharCodeAt:
565 case kStringCharAt:
566 if (object->IsString()) {
567 String* string = String::cast(*object);
568 // Check that there's the right wrapper in the receiver slot.
569 ASSERT(string == JSValue::cast(args[0])->value());
570 // If we're in the default (fastest) state and the index is
571 // out of bounds, update the state to record this fact.
572 if (*extra_ic_state == DEFAULT_STRING_STUB &&
573 argc >= 1 && args[1]->IsNumber()) {
574 double index;
575 if (args[1]->IsSmi()) {
576 index = Smi::cast(args[1])->value();
577 } else {
578 ASSERT(args[1]->IsHeapNumber());
579 index = DoubleToInteger(HeapNumber::cast(args[1])->value());
580 }
581 if (index < 0 || index >= string->length()) {
582 *extra_ic_state = STRING_INDEX_OUT_OF_BOUNDS;
583 return true;
584 }
585 }
586 }
587 break;
588 default:
589 return false;
590 }
591 return false;
592 }
593
594
595 MaybeObject* CallICBase::ComputeMonomorphicStub(
596 LookupResult* lookup,
597 State state,
598 Code::ExtraICState extra_ic_state,
599 Handle<Object> object,
600 Handle<String> name) {
601 int argc = target()->arguments_count();
602 InLoopFlag in_loop = target()->ic_in_loop();
603 MaybeObject* maybe_code = NULL;
604 switch (lookup->type()) {
605 case FIELD: {
606 int index = lookup->GetFieldIndex();
607 maybe_code = StubCache::ComputeCallField(argc,
608 in_loop,
609 kind_,
610 *name,
611 *object,
612 lookup->holder(),
613 index);
614 break;
615 }
616 case CONSTANT_FUNCTION: {
617 // Get the constant function and compute the code stub for this
618 // call; used for rewriting to monomorphic state and making sure
619 // that the code stub is in the stub cache.
620 JSFunction* function = lookup->GetConstantFunction();
621 maybe_code = StubCache::ComputeCallConstant(argc,
622 in_loop,
623 kind_,
624 extra_ic_state,
625 *name,
626 *object,
627 lookup->holder(),
628 function);
629 break;
630 }
631 case NORMAL: {
632 if (!object->IsJSObject()) return NULL;
633 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
634
635 if (lookup->holder()->IsGlobalObject()) {
636 GlobalObject* global = GlobalObject::cast(lookup->holder());
637 JSGlobalPropertyCell* cell =
638 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
639 if (!cell->value()->IsJSFunction()) return NULL;
640 JSFunction* function = JSFunction::cast(cell->value());
641 maybe_code = StubCache::ComputeCallGlobal(argc,
642 in_loop,
643 kind_,
644 *name,
645 *receiver,
646 global,
647 cell,
648 function);
649 } else {
650 // There is only one shared stub for calling normalized
651 // properties. It does not traverse the prototype chain, so the
652 // property must be found in the receiver for the stub to be
653 // applicable.
654 if (lookup->holder() != *receiver) return NULL;
655 maybe_code = StubCache::ComputeCallNormal(argc,
656 in_loop,
657 kind_,
658 *name,
659 *receiver);
660 }
661 break;
662 }
663 case INTERCEPTOR: {
664 ASSERT(HasInterceptorGetter(lookup->holder()));
665 maybe_code = StubCache::ComputeCallInterceptor(argc,
666 kind_,
667 *name,
668 *object,
669 lookup->holder());
670 break;
671 }
672 default:
673 maybe_code = NULL;
674 break;
675 }
676 return maybe_code;
677 }
678
679
579 void CallICBase::UpdateCaches(LookupResult* lookup, 680 void CallICBase::UpdateCaches(LookupResult* lookup,
580 State state, 681 State state,
682 Code::ExtraICState extra_ic_state,
581 Handle<Object> object, 683 Handle<Object> object,
582 Handle<String> name) { 684 Handle<String> name) {
583 // Bail out if we didn't find a result. 685 // Bail out if we didn't find a result.
584 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; 686 if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
585 687
586 if (lookup->holder() != *object && 688 if (lookup->holder() != *object &&
587 HasNormalObjectsInPrototypeChain(lookup, object->GetPrototype())) { 689 HasNormalObjectsInPrototypeChain(lookup, object->GetPrototype())) {
588 // Suppress optimization for prototype chains with slow properties objects 690 // Suppress optimization for prototype chains with slow properties objects
589 // in the middle. 691 // in the middle.
590 return; 692 return;
591 } 693 }
592 694
593 // Compute the number of arguments. 695 // Compute the number of arguments.
594 int argc = target()->arguments_count(); 696 int argc = target()->arguments_count();
595 InLoopFlag in_loop = target()->ic_in_loop(); 697 InLoopFlag in_loop = target()->ic_in_loop();
596 MaybeObject* maybe_code = NULL; 698 MaybeObject* maybe_code = NULL;
597 Object* code; 699 bool had_proto_failure = false;
598 if (state == UNINITIALIZED) { 700 if (state == UNINITIALIZED) {
599 // This is the first time we execute this inline cache. 701 // This is the first time we execute this inline cache.
600 // Set the target to the pre monomorphic stub to delay 702 // Set the target to the pre monomorphic stub to delay
601 // setting the monomorphic state. 703 // setting the monomorphic state.
602 maybe_code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_); 704 maybe_code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_);
603 } else if (state == MONOMORPHIC) { 705 } else if (state == MONOMORPHIC) {
604 maybe_code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_); 706 if (kind_ == Code::CALL_IC &&
707 TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
708 maybe_code = ComputeMonomorphicStub(lookup,
709 state,
710 extra_ic_state,
711 object,
712 name);
713 } else if (kind_ == Code::CALL_IC &&
714 TryRemoveInvalidPrototypeDependentStub(target(),
715 *object,
716 *name)) {
717 had_proto_failure = true;
718 maybe_code = ComputeMonomorphicStub(lookup,
719 state,
720 extra_ic_state,
721 object,
722 name);
723 } else {
724 maybe_code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_);
725 }
605 } else { 726 } else {
606 // Compute monomorphic stub. 727 maybe_code = ComputeMonomorphicStub(lookup,
607 switch (lookup->type()) { 728 state,
608 case FIELD: { 729 extra_ic_state,
609 int index = lookup->GetFieldIndex(); 730 object,
610 maybe_code = StubCache::ComputeCallField(argc, 731 name);
611 in_loop,
612 kind_,
613 *name,
614 *object,
615 lookup->holder(),
616 index);
617 break;
618 }
619 case CONSTANT_FUNCTION: {
620 // Get the constant function and compute the code stub for this
621 // call; used for rewriting to monomorphic state and making sure
622 // that the code stub is in the stub cache.
623 JSFunction* function = lookup->GetConstantFunction();
624 maybe_code = StubCache::ComputeCallConstant(argc,
625 in_loop,
626 kind_,
627 *name,
628 *object,
629 lookup->holder(),
630 function);
631 break;
632 }
633 case NORMAL: {
634 if (!object->IsJSObject()) return;
635 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
636
637 if (lookup->holder()->IsGlobalObject()) {
638 GlobalObject* global = GlobalObject::cast(lookup->holder());
639 JSGlobalPropertyCell* cell =
640 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
641 if (!cell->value()->IsJSFunction()) return;
642 JSFunction* function = JSFunction::cast(cell->value());
643 maybe_code = StubCache::ComputeCallGlobal(argc,
644 in_loop,
645 kind_,
646 *name,
647 *receiver,
648 global,
649 cell,
650 function);
651 } else {
652 // There is only one shared stub for calling normalized
653 // properties. It does not traverse the prototype chain, so the
654 // property must be found in the receiver for the stub to be
655 // applicable.
656 if (lookup->holder() != *receiver) return;
657 maybe_code = StubCache::ComputeCallNormal(argc,
658 in_loop,
659 kind_,
660 *name,
661 *receiver);
662 }
663 break;
664 }
665 case INTERCEPTOR: {
666 ASSERT(HasInterceptorGetter(lookup->holder()));
667 maybe_code = StubCache::ComputeCallInterceptor(argc,
668 kind_,
669 *name,
670 *object,
671 lookup->holder());
672 break;
673 }
674 default:
675 return;
676 }
677 } 732 }
678 733
679 // If we're unable to compute the stub (not enough memory left), we 734 // If we're unable to compute the stub (not enough memory left), we
680 // simply avoid updating the caches. 735 // simply avoid updating the caches.
736 Object* code;
681 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; 737 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
682 738
683 // Patch the call site depending on the state of the cache. 739 // Patch the call site depending on the state of the cache.
684 if (state == UNINITIALIZED || 740 if (state == UNINITIALIZED ||
685 state == PREMONOMORPHIC || 741 state == PREMONOMORPHIC ||
686 state == MONOMORPHIC || 742 state == MONOMORPHIC ||
687 state == MONOMORPHIC_PROTOTYPE_FAILURE) { 743 state == MONOMORPHIC_PROTOTYPE_FAILURE) {
688 set_target(Code::cast(code)); 744 set_target(Code::cast(code));
689 } else if (state == MEGAMORPHIC) { 745 } else if (state == MEGAMORPHIC) {
690 // Cache code holding map should be consistent with 746 // Cache code holding map should be consistent with
691 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. 747 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
692 Map* map = JSObject::cast(object->IsJSObject() ? *object : 748 Map* map = JSObject::cast(object->IsJSObject() ? *object :
693 object->GetPrototype())->map(); 749 object->GetPrototype())->map();
694 750
695 // Update the stub cache. 751 // Update the stub cache.
696 StubCache::Set(*name, map, Code::cast(code)); 752 StubCache::Set(*name, map, Code::cast(code));
697 } 753 }
698 754
755 USE(had_proto_failure);
699 #ifdef DEBUG 756 #ifdef DEBUG
757 if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE;
700 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", 758 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
701 name, state, target(), in_loop ? " (in-loop)" : ""); 759 name, state, target(), in_loop ? " (in-loop)" : "");
702 #endif 760 #endif
703 } 761 }
704 762
705 763
706 MaybeObject* KeyedCallIC::LoadFunction(State state, 764 MaybeObject* KeyedCallIC::LoadFunction(State state,
707 Handle<Object> object, 765 Handle<Object> object,
708 Handle<Object> key) { 766 Handle<Object> key) {
709 if (key->IsSymbol()) { 767 if (key->IsSymbol()) {
710 return CallICBase::LoadFunction(state, object, Handle<String>::cast(key)); 768 return CallICBase::LoadFunction(state,
769 Code::kNoExtraICState,
770 object,
771 Handle<String>::cast(key));
711 } 772 }
712 773
713 if (object->IsUndefined() || object->IsNull()) { 774 if (object->IsUndefined() || object->IsNull()) {
714 return TypeError("non_object_property_call", object, key); 775 return TypeError("non_object_property_call", object, key);
715 } 776 }
716 777
717 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { 778 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
718 ReceiverToObject(object); 779 ReceiverToObject(object);
719 } 780 }
720 781
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
757 MaybeObject* LoadIC::Load(State state, 818 MaybeObject* LoadIC::Load(State state,
758 Handle<Object> object, 819 Handle<Object> object,
759 Handle<String> name) { 820 Handle<String> name) {
760 // 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
761 // of its properties; throw a TypeError in that case. 822 // of its properties; throw a TypeError in that case.
762 if (object->IsUndefined() || object->IsNull()) { 823 if (object->IsUndefined() || object->IsNull()) {
763 return TypeError("non_object_property_load", object, name); 824 return TypeError("non_object_property_load", object, name);
764 } 825 }
765 826
766 if (FLAG_use_ic) { 827 if (FLAG_use_ic) {
828 Code* non_monomorphic_stub =
829 (state == UNINITIALIZED) ? pre_monomorphic_stub() : megamorphic_stub();
830
767 // Use specialized code for getting the length of strings and 831 // Use specialized code for getting the length of strings and
768 // string wrapper objects. The length property of string wrapper 832 // string wrapper objects. The length property of string wrapper
769 // objects is read-only and therefore always returns the length of 833 // objects is read-only and therefore always returns the length of
770 // the underlying string value. See ECMA-262 15.5.5.1. 834 // the underlying string value. See ECMA-262 15.5.5.1.
771 if ((object->IsString() || object->IsStringWrapper()) && 835 if ((object->IsString() || object->IsStringWrapper()) &&
772 name->Equals(Heap::length_symbol())) { 836 name->Equals(Heap::length_symbol())) {
773 HandleScope scope; 837 HandleScope scope;
838 #ifdef DEBUG
839 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
840 #endif
841 if (state == PREMONOMORPHIC) {
842 if (object->IsString()) {
843 Map* map = HeapObject::cast(*object)->map();
844 const int offset = String::kLengthOffset;
845 PatchInlinedLoad(address(), map, offset);
846 set_target(Builtins::builtin(Builtins::LoadIC_StringLength));
847 } else {
848 set_target(Builtins::builtin(Builtins::LoadIC_StringWrapperLength));
849 }
850 } else if (state == MONOMORPHIC && object->IsStringWrapper()) {
851 set_target(Builtins::builtin(Builtins::LoadIC_StringWrapperLength));
852 } else {
853 set_target(non_monomorphic_stub);
854 }
774 // Get the string if we have a string wrapper object. 855 // Get the string if we have a string wrapper object.
775 if (object->IsJSValue()) { 856 if (object->IsJSValue()) {
776 object = Handle<Object>(Handle<JSValue>::cast(object)->value()); 857 object = Handle<Object>(Handle<JSValue>::cast(object)->value());
777 } 858 }
778 #ifdef DEBUG
779 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
780 #endif
781 Map* map = HeapObject::cast(*object)->map();
782 if (object->IsString()) {
783 const int offset = String::kLengthOffset;
784 PatchInlinedLoad(address(), map, offset);
785 }
786
787 Code* target = NULL;
788 target = Builtins::builtin(Builtins::LoadIC_StringLength);
789 set_target(target);
790 return Smi::FromInt(String::cast(*object)->length()); 859 return Smi::FromInt(String::cast(*object)->length());
791 } 860 }
792 861
793 // Use specialized code for getting the length of arrays. 862 // Use specialized code for getting the length of arrays.
794 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) { 863 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) {
795 #ifdef DEBUG 864 #ifdef DEBUG
796 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); 865 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
797 #endif 866 #endif
798 Map* map = HeapObject::cast(*object)->map(); 867 if (state == PREMONOMORPHIC) {
799 const int offset = JSArray::kLengthOffset; 868 Map* map = HeapObject::cast(*object)->map();
800 PatchInlinedLoad(address(), map, offset); 869 const int offset = JSArray::kLengthOffset;
801 870 PatchInlinedLoad(address(), map, offset);
802 Code* target = Builtins::builtin(Builtins::LoadIC_ArrayLength); 871 set_target(Builtins::builtin(Builtins::LoadIC_ArrayLength));
803 set_target(target); 872 } else {
873 set_target(non_monomorphic_stub);
874 }
804 return JSArray::cast(*object)->length(); 875 return JSArray::cast(*object)->length();
805 } 876 }
806 877
807 // Use specialized code for getting prototype of functions. 878 // Use specialized code for getting prototype of functions.
808 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol()) && 879 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol()) &&
809 JSFunction::cast(*object)->should_have_prototype()) { 880 JSFunction::cast(*object)->should_have_prototype()) {
810 #ifdef DEBUG 881 #ifdef DEBUG
811 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); 882 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
812 #endif 883 #endif
813 Code* target = Builtins::builtin(Builtins::LoadIC_FunctionPrototype); 884 if (state == PREMONOMORPHIC) {
814 set_target(target); 885 set_target(Builtins::builtin(Builtins::LoadIC_FunctionPrototype));
886 } else {
887 set_target(non_monomorphic_stub);
888 }
815 return Accessors::FunctionGetPrototype(*object, 0); 889 return Accessors::FunctionGetPrototype(*object, 0);
816 } 890 }
817 } 891 }
818 892
819 // Check if the name is trivially convertible to an index and get 893 // Check if the name is trivially convertible to an index and get
820 // the element if so. 894 // the element if so.
821 uint32_t index; 895 uint32_t index;
822 if (name->AsArrayIndex(&index)) return object->GetElement(index); 896 if (name->AsArrayIndex(&index)) return object->GetElement(index);
823 897
824 // Named lookup in the object. 898 // Named lookup in the object.
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
1027 if (key->IsSymbol()) { 1101 if (key->IsSymbol()) {
1028 Handle<String> name = Handle<String>::cast(key); 1102 Handle<String> name = Handle<String>::cast(key);
1029 1103
1030 // If the object is undefined or null it's illegal to try to get any 1104 // If the object is undefined or null it's illegal to try to get any
1031 // of its properties; throw a TypeError in that case. 1105 // of its properties; throw a TypeError in that case.
1032 if (object->IsUndefined() || object->IsNull()) { 1106 if (object->IsUndefined() || object->IsNull()) {
1033 return TypeError("non_object_property_load", object, name); 1107 return TypeError("non_object_property_load", object, name);
1034 } 1108 }
1035 1109
1036 if (FLAG_use_ic) { 1110 if (FLAG_use_ic) {
1111 // TODO(1073): don't ignore the current stub state.
1112
1037 // Use specialized code for getting the length of strings. 1113 // Use specialized code for getting the length of strings.
1038 if (object->IsString() && name->Equals(Heap::length_symbol())) { 1114 if (object->IsString() && name->Equals(Heap::length_symbol())) {
1039 Handle<String> string = Handle<String>::cast(object); 1115 Handle<String> string = Handle<String>::cast(object);
1040 Object* code = NULL; 1116 Object* code = NULL;
1041 { MaybeObject* maybe_code = 1117 { MaybeObject* maybe_code =
1042 StubCache::ComputeKeyedLoadStringLength(*name, *string); 1118 StubCache::ComputeKeyedLoadStringLength(*name, *string);
1043 if (!maybe_code->ToObject(&code)) return maybe_code; 1119 if (!maybe_code->ToObject(&code)) return maybe_code;
1044 } 1120 }
1045 set_target(Code::cast(code)); 1121 set_target(Code::cast(code));
1046 #ifdef DEBUG 1122 #ifdef DEBUG
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
1124 1200
1125 return object->GetProperty(*object, &lookup, *name, &attr); 1201 return object->GetProperty(*object, &lookup, *name, &attr);
1126 } 1202 }
1127 1203
1128 // Do not use ICs for objects that require access checks (including 1204 // Do not use ICs for objects that require access checks (including
1129 // the global object). 1205 // the global object).
1130 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); 1206 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
1131 1207
1132 if (use_ic) { 1208 if (use_ic) {
1133 Code* stub = generic_stub(); 1209 Code* stub = generic_stub();
1134 if (object->IsString() && key->IsNumber()) { 1210 if (state == UNINITIALIZED) {
1135 stub = string_stub(); 1211 if (object->IsString() && key->IsNumber()) {
1136 } else if (object->IsJSObject()) { 1212 stub = string_stub();
1137 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1213 } else if (object->IsJSObject()) {
1138 if (receiver->HasExternalArrayElements()) { 1214 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1139 stub = external_array_stub(receiver->GetElementsKind()); 1215 if (receiver->HasExternalArrayElements()) {
1140 } else if (receiver->HasIndexedInterceptor()) { 1216 MaybeObject* probe =
1141 stub = indexed_interceptor_stub(); 1217 StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver,
1142 } else if (state == UNINITIALIZED && 1218 false);
1143 key->IsSmi() && 1219 stub = probe->IsFailure() ?
1144 receiver->map()->has_fast_elements()) { 1220 NULL : Code::cast(probe->ToObjectUnchecked());
1145 MaybeObject* probe = StubCache::ComputeKeyedLoadSpecialized(*receiver); 1221 } else if (receiver->HasIndexedInterceptor()) {
1146 stub = 1222 stub = indexed_interceptor_stub();
1147 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); 1223 } else if (receiver->HasPixelElements()) {
1224 MaybeObject* probe =
1225 StubCache::ComputeKeyedLoadPixelArray(*receiver);
1226 stub = probe->IsFailure() ?
1227 NULL : Code::cast(probe->ToObjectUnchecked());
1228 } else if (key->IsSmi() &&
1229 receiver->map()->has_fast_elements()) {
1230 MaybeObject* probe =
1231 StubCache::ComputeKeyedLoadSpecialized(*receiver);
1232 stub = probe->IsFailure() ?
1233 NULL : Code::cast(probe->ToObjectUnchecked());
1234 }
1148 } 1235 }
1149 } 1236 }
1150 if (stub != NULL) set_target(stub); 1237 if (stub != NULL) set_target(stub);
1151 1238
1152 #ifdef DEBUG 1239 #ifdef DEBUG
1153 TraceIC("KeyedLoadIC", key, state, target()); 1240 TraceIC("KeyedLoadIC", key, state, target());
1154 #endif // DEBUG 1241 #endif // DEBUG
1155 1242
1156 // For JSObjects with fast elements that are not value wrappers 1243 // For JSObjects with fast elements that are not value wrappers
1157 // and that do not have indexed interceptors, we initialize the 1244 // and that do not have indexed interceptors, we initialize the
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
1277 object->LocalLookupRealNamedProperty(name, lookup); 1364 object->LocalLookupRealNamedProperty(name, lookup);
1278 return StoreICableLookup(lookup); 1365 return StoreICableLookup(lookup);
1279 } 1366 }
1280 } 1367 }
1281 1368
1282 return true; 1369 return true;
1283 } 1370 }
1284 1371
1285 1372
1286 MaybeObject* StoreIC::Store(State state, 1373 MaybeObject* StoreIC::Store(State state,
1374 Code::ExtraICState extra_ic_state,
1287 Handle<Object> object, 1375 Handle<Object> object,
1288 Handle<String> name, 1376 Handle<String> name,
1289 Handle<Object> value) { 1377 Handle<Object> value) {
1290 // If the object is undefined or null it's illegal to try to set any 1378 // If the object is undefined or null it's illegal to try to set any
1291 // properties on it; throw a TypeError in that case. 1379 // properties on it; throw a TypeError in that case.
1292 if (object->IsUndefined() || object->IsNull()) { 1380 if (object->IsUndefined() || object->IsNull()) {
1293 return TypeError("non_object_property_store", object, name); 1381 return TypeError("non_object_property_store", object, name);
1294 } 1382 }
1295 1383
1296 // Ignore stores where the receiver is not a JSObject. 1384 // Ignore stores where the receiver is not a JSObject.
1297 if (!object->IsJSObject()) return *value; 1385 if (!object->IsJSObject()) return *value;
1298 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1386 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1299 1387
1300 // Check if the given name is an array index. 1388 // Check if the given name is an array index.
1301 uint32_t index; 1389 uint32_t index;
1302 if (name->AsArrayIndex(&index)) { 1390 if (name->AsArrayIndex(&index)) {
1303 HandleScope scope; 1391 HandleScope scope;
1304 Handle<Object> result = SetElement(receiver, index, value); 1392 Handle<Object> result = SetElement(receiver, index, value);
1305 if (result.is_null()) return Failure::Exception(); 1393 if (result.is_null()) return Failure::Exception();
1306 return *value; 1394 return *value;
1307 } 1395 }
1308 1396
1309 // Use specialized code for setting the length of arrays. 1397 // Use specialized code for setting the length of arrays.
1310 if (receiver->IsJSArray() 1398 if (receiver->IsJSArray()
1311 && name->Equals(Heap::length_symbol()) 1399 && name->Equals(Heap::length_symbol())
1312 && receiver->AllowsSetElementsLength()) { 1400 && receiver->AllowsSetElementsLength()) {
1313 #ifdef DEBUG 1401 #ifdef DEBUG
1314 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); 1402 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
1315 #endif 1403 #endif
1316 Code* target = Builtins::builtin(Builtins::StoreIC_ArrayLength); 1404 Builtins::Name target = (extra_ic_state == kStoreICStrict)
1317 set_target(target); 1405 ? Builtins::StoreIC_ArrayLength_Strict
1406 : Builtins::StoreIC_ArrayLength;
1407 set_target(Builtins::builtin(target));
1318 return receiver->SetProperty(*name, *value, NONE); 1408 return receiver->SetProperty(*name, *value, NONE);
1319 } 1409 }
1320 1410
1321 // Lookup the property locally in the receiver. 1411 // Lookup the property locally in the receiver.
1322 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { 1412 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
1323 LookupResult lookup; 1413 LookupResult lookup;
1324 1414
1325 if (LookupForWrite(*receiver, *name, &lookup)) { 1415 if (LookupForWrite(*receiver, *name, &lookup)) {
1326 bool can_be_inlined = 1416 bool can_be_inlined =
1327 state == UNINITIALIZED && 1417 state == UNINITIALIZED &&
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1365 if (FLAG_trace_ic) { 1455 if (FLAG_trace_ic) {
1366 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n", 1456 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n",
1367 *name->ToCString()); 1457 *name->ToCString());
1368 #endif 1458 #endif
1369 } 1459 }
1370 } 1460 }
1371 } 1461 }
1372 1462
1373 // If no inlined store ic was patched, generate a stub for this 1463 // If no inlined store ic was patched, generate a stub for this
1374 // store. 1464 // store.
1375 UpdateCaches(&lookup, state, receiver, name, value); 1465 UpdateCaches(&lookup, state, extra_ic_state, receiver, name, value);
1466 } else {
1467 // Strict mode doesn't allow setting non-existent global property.
1468 if (extra_ic_state == kStoreICStrict && IsContextual(object)) {
1469 return ReferenceError("not_defined", name);
1470 }
1376 } 1471 }
1377 } 1472 }
1378 1473
1379 if (receiver->IsJSGlobalProxy()) { 1474 if (receiver->IsJSGlobalProxy()) {
1380 // Generate a generic stub that goes to the runtime when we see a global 1475 // Generate a generic stub that goes to the runtime when we see a global
1381 // proxy as receiver. 1476 // proxy as receiver.
1382 if (target() != global_proxy_stub()) { 1477 Code* stub = (extra_ic_state == kStoreICStrict)
1383 set_target(global_proxy_stub()); 1478 ? global_proxy_stub_strict()
1479 : global_proxy_stub();
1480 if (target() != stub) {
1481 set_target(stub);
1384 #ifdef DEBUG 1482 #ifdef DEBUG
1385 TraceIC("StoreIC", name, state, target()); 1483 TraceIC("StoreIC", name, state, target());
1386 #endif 1484 #endif
1387 } 1485 }
1388 } 1486 }
1389 1487
1390 // Set the property. 1488 // Set the property.
1391 return receiver->SetProperty(*name, *value, NONE); 1489 return receiver->SetProperty(*name, *value, NONE);
1392 } 1490 }
1393 1491
1394 1492
1395 void StoreIC::UpdateCaches(LookupResult* lookup, 1493 void StoreIC::UpdateCaches(LookupResult* lookup,
1396 State state, 1494 State state,
1495 Code::ExtraICState extra_ic_state,
1397 Handle<JSObject> receiver, 1496 Handle<JSObject> receiver,
1398 Handle<String> name, 1497 Handle<String> name,
1399 Handle<Object> value) { 1498 Handle<Object> value) {
1400 // Skip JSGlobalProxy. 1499 // Skip JSGlobalProxy.
1401 ASSERT(!receiver->IsJSGlobalProxy()); 1500 ASSERT(!receiver->IsJSGlobalProxy());
1402 1501
1403 ASSERT(StoreICableLookup(lookup)); 1502 ASSERT(StoreICableLookup(lookup));
1404 1503
1405 // If the property has a non-field type allowing map transitions 1504 // If the property has a non-field type allowing map transitions
1406 // where there is extra room in the object, we leave the IC in its 1505 // where there is extra room in the object, we leave the IC in its
1407 // current state. 1506 // current state.
1408 PropertyType type = lookup->type(); 1507 PropertyType type = lookup->type();
1409 1508
1410 // Compute the code stub for this store; used for rewriting to 1509 // Compute the code stub for this store; used for rewriting to
1411 // monomorphic state and making sure that the code stub is in the 1510 // monomorphic state and making sure that the code stub is in the
1412 // stub cache. 1511 // stub cache.
1413 MaybeObject* maybe_code = NULL; 1512 MaybeObject* maybe_code = NULL;
1414 Object* code = NULL; 1513 Object* code = NULL;
1415 switch (type) { 1514 switch (type) {
1416 case FIELD: { 1515 case FIELD: {
1417 maybe_code = StubCache::ComputeStoreField(*name, *receiver, 1516 maybe_code = StubCache::ComputeStoreField(
1418 lookup->GetFieldIndex()); 1517 *name, *receiver, lookup->GetFieldIndex(), NULL, extra_ic_state);
1419 break; 1518 break;
1420 } 1519 }
1421 case MAP_TRANSITION: { 1520 case MAP_TRANSITION: {
1422 if (lookup->GetAttributes() != NONE) return; 1521 if (lookup->GetAttributes() != NONE) return;
1423 HandleScope scope; 1522 HandleScope scope;
1424 ASSERT(type == MAP_TRANSITION); 1523 ASSERT(type == MAP_TRANSITION);
1425 Handle<Map> transition(lookup->GetTransitionMap()); 1524 Handle<Map> transition(lookup->GetTransitionMap());
1426 int index = transition->PropertyIndexFor(*name); 1525 int index = transition->PropertyIndexFor(*name);
1427 maybe_code = StubCache::ComputeStoreField(*name, *receiver, 1526 maybe_code = StubCache::ComputeStoreField(
1428 index, *transition); 1527 *name, *receiver, index, *transition, extra_ic_state);
1429 break; 1528 break;
1430 } 1529 }
1431 case NORMAL: { 1530 case NORMAL: {
1432 if (receiver->IsGlobalObject()) { 1531 if (receiver->IsGlobalObject()) {
1433 // The stub generated for the global object picks the value directly 1532 // The stub generated for the global object picks the value directly
1434 // from the property cell. So the property must be directly on the 1533 // from the property cell. So the property must be directly on the
1435 // global object. 1534 // global object.
1436 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); 1535 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
1437 JSGlobalPropertyCell* cell = 1536 JSGlobalPropertyCell* cell =
1438 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); 1537 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
1439 maybe_code = StubCache::ComputeStoreGlobal(*name, *global, cell); 1538 maybe_code = StubCache::ComputeStoreGlobal(
1539 *name, *global, cell, extra_ic_state);
1440 } else { 1540 } else {
1441 if (lookup->holder() != *receiver) return; 1541 if (lookup->holder() != *receiver) return;
1442 maybe_code = StubCache::ComputeStoreNormal(); 1542 maybe_code = StubCache::ComputeStoreNormal(extra_ic_state);
1443 } 1543 }
1444 break; 1544 break;
1445 } 1545 }
1446 case CALLBACKS: { 1546 case CALLBACKS: {
1447 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; 1547 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
1448 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); 1548 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1449 if (v8::ToCData<Address>(callback->setter()) == 0) return; 1549 if (v8::ToCData<Address>(callback->setter()) == 0) return;
1450 maybe_code = StubCache::ComputeStoreCallback(*name, *receiver, callback); 1550 maybe_code = StubCache::ComputeStoreCallback(
1551 *name, *receiver, callback, extra_ic_state);
1451 break; 1552 break;
1452 } 1553 }
1453 case INTERCEPTOR: { 1554 case INTERCEPTOR: {
1454 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); 1555 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
1455 maybe_code = StubCache::ComputeStoreInterceptor(*name, *receiver); 1556 maybe_code = StubCache::ComputeStoreInterceptor(
1557 *name, *receiver, extra_ic_state);
1456 break; 1558 break;
1457 } 1559 }
1458 default: 1560 default:
1459 return; 1561 return;
1460 } 1562 }
1461 1563
1462 // If we're unable to compute the stub (not enough memory left), we 1564 // If we're unable to compute the stub (not enough memory left), we
1463 // simply avoid updating the caches. 1565 // simply avoid updating the caches.
1464 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; 1566 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
1465 1567
1466 // Patch the call site depending on the state of the cache. 1568 // Patch the call site depending on the state of the cache.
1467 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { 1569 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
1468 set_target(Code::cast(code)); 1570 set_target(Code::cast(code));
1469 } else if (state == MONOMORPHIC) { 1571 } else if (state == MONOMORPHIC) {
1470 // Only move to megamorphic if the target changes. 1572 // Only move to megamorphic if the target changes.
1471 if (target() != Code::cast(code)) set_target(megamorphic_stub()); 1573 if (target() != Code::cast(code)) {
1574 set_target(extra_ic_state == kStoreICStrict
1575 ? megamorphic_stub_strict()
1576 : megamorphic_stub());
1577 }
1472 } else if (state == MEGAMORPHIC) { 1578 } else if (state == MEGAMORPHIC) {
1473 // Update the stub cache. 1579 // Update the stub cache.
1474 StubCache::Set(*name, receiver->map(), Code::cast(code)); 1580 StubCache::Set(*name, receiver->map(), Code::cast(code));
1475 } 1581 }
1476 1582
1477 #ifdef DEBUG 1583 #ifdef DEBUG
1478 TraceIC("StoreIC", name, state, target()); 1584 TraceIC("StoreIC", name, state, target());
1479 #endif 1585 #endif
1480 } 1586 }
1481 1587
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1519 return receiver->SetProperty(*name, *value, NONE); 1625 return receiver->SetProperty(*name, *value, NONE);
1520 } 1626 }
1521 1627
1522 // Do not use ICs for objects that require access checks (including 1628 // Do not use ICs for objects that require access checks (including
1523 // the global object). 1629 // the global object).
1524 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); 1630 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
1525 ASSERT(!(use_ic && object->IsJSGlobalProxy())); 1631 ASSERT(!(use_ic && object->IsJSGlobalProxy()));
1526 1632
1527 if (use_ic) { 1633 if (use_ic) {
1528 Code* stub = generic_stub(); 1634 Code* stub = generic_stub();
1529 if (object->IsJSObject()) { 1635 if (state == UNINITIALIZED) {
1530 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1636 if (object->IsJSObject()) {
1531 if (receiver->HasExternalArrayElements()) { 1637 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1532 stub = external_array_stub(receiver->GetElementsKind()); 1638 if (receiver->HasExternalArrayElements()) {
1533 } else if (state == UNINITIALIZED && 1639 MaybeObject* probe =
1534 key->IsSmi() && 1640 StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, true);
1535 receiver->map()->has_fast_elements()) { 1641 stub = probe->IsFailure() ?
1536 MaybeObject* probe = StubCache::ComputeKeyedStoreSpecialized(*receiver); 1642 NULL : Code::cast(probe->ToObjectUnchecked());
1537 stub = 1643 } else if (receiver->HasPixelElements()) {
1538 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); 1644 MaybeObject* probe =
1645 StubCache::ComputeKeyedStorePixelArray(*receiver);
1646 stub = probe->IsFailure() ?
1647 NULL : Code::cast(probe->ToObjectUnchecked());
1648 } else if (key->IsSmi() && receiver->map()->has_fast_elements()) {
1649 MaybeObject* probe =
1650 StubCache::ComputeKeyedStoreSpecialized(*receiver);
1651 stub = probe->IsFailure() ?
1652 NULL : Code::cast(probe->ToObjectUnchecked());
1653 }
1539 } 1654 }
1540 } 1655 }
1541 if (stub != NULL) set_target(stub); 1656 if (stub != NULL) set_target(stub);
1542 } 1657 }
1543 1658
1544 // Set the property. 1659 // Set the property.
1545 return Runtime::SetObjectProperty(object, key, value, NONE); 1660 return Runtime::SetObjectProperty(object, key, value, NONE);
1546 } 1661 }
1547 1662
1548 1663
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
1634 return *function_handle; 1749 return *function_handle;
1635 } 1750 }
1636 1751
1637 1752
1638 // Used from ic-<arch>.cc. 1753 // Used from ic-<arch>.cc.
1639 MUST_USE_RESULT MaybeObject* CallIC_Miss(Arguments args) { 1754 MUST_USE_RESULT MaybeObject* CallIC_Miss(Arguments args) {
1640 NoHandleAllocation na; 1755 NoHandleAllocation na;
1641 ASSERT(args.length() == 2); 1756 ASSERT(args.length() == 2);
1642 CallIC ic; 1757 CallIC ic;
1643 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 1758 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
1759 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
1760 MaybeObject* maybe_result = ic.LoadFunction(state,
1761 extra_ic_state,
1762 args.at<Object>(0),
1763 args.at<String>(1));
1644 Object* result; 1764 Object* result;
1645 { MaybeObject* maybe_result = 1765 if (!maybe_result->ToObject(&result)) return maybe_result;
1646 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
1647 if (!maybe_result->ToObject(&result)) return maybe_result;
1648 }
1649 1766
1650 // The first time the inline cache is updated may be the first time the 1767 // The first time the inline cache is updated may be the first time the
1651 // function it references gets called. If the function was lazily compiled 1768 // function it references gets called. If the function was lazily compiled
1652 // then the first call will trigger a compilation. We check for this case 1769 // then the first call will trigger a compilation. We check for this case
1653 // and we do the compilation immediately, instead of waiting for the stub 1770 // and we do the compilation immediately, instead of waiting for the stub
1654 // currently attached to the JSFunction object to trigger compilation. We 1771 // currently attached to the JSFunction object to trigger compilation. We
1655 // do this in the case where we know that the inline cache is inside a loop, 1772 // do this in the case where we know that the inline cache is inside a loop,
1656 // because then we know that we want to optimize the function. 1773 // because then we know that we want to optimize the function.
1657 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { 1774 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
1658 return result; 1775 return result;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1699 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); 1816 return ic.Load(state, args.at<Object>(0), args.at<Object>(1));
1700 } 1817 }
1701 1818
1702 1819
1703 // Used from ic-<arch>.cc. 1820 // Used from ic-<arch>.cc.
1704 MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { 1821 MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) {
1705 NoHandleAllocation na; 1822 NoHandleAllocation na;
1706 ASSERT(args.length() == 3); 1823 ASSERT(args.length() == 3);
1707 StoreIC ic; 1824 StoreIC ic;
1708 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 1825 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
1709 return ic.Store(state, args.at<Object>(0), args.at<String>(1), 1826 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
1710 args.at<Object>(2)); 1827 return ic.Store(state, extra_ic_state, args.at<Object>(0),
1828 args.at<String>(1), args.at<Object>(2));
1711 } 1829 }
1712 1830
1713 1831
1714 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) { 1832 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) {
1715 NoHandleAllocation nha; 1833 NoHandleAllocation nha;
1716 1834
1717 ASSERT(args.length() == 2); 1835 ASSERT(args.length() == 2);
1718 JSObject* receiver = JSObject::cast(args[0]); 1836 JSObject* receiver = JSObject::cast(args[0]);
1719 Object* len = args[1]; 1837 Object* len = args[1];
1720 1838
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
1965 ::v8::internal::TypeInfo left_type = 2083 ::v8::internal::TypeInfo left_type =
1966 ::v8::internal::TypeInfo::TypeFromValue(left); 2084 ::v8::internal::TypeInfo::TypeFromValue(left);
1967 ::v8::internal::TypeInfo right_type = 2085 ::v8::internal::TypeInfo right_type =
1968 ::v8::internal::TypeInfo::TypeFromValue(right); 2086 ::v8::internal::TypeInfo::TypeFromValue(right);
1969 2087
1970 if (left_type.IsSmi() && right_type.IsSmi()) { 2088 if (left_type.IsSmi() && right_type.IsSmi()) {
1971 return SMI; 2089 return SMI;
1972 } 2090 }
1973 2091
1974 if (left_type.IsInteger32() && right_type.IsInteger32()) { 2092 if (left_type.IsInteger32() && right_type.IsInteger32()) {
2093 // Platforms with 32-bit Smis have no distinct INT32 type.
2094 if (kSmiValueSize == 32) return SMI;
1975 return INT32; 2095 return INT32;
1976 } 2096 }
1977 2097
1978 if (left_type.IsNumber() && right_type.IsNumber()) { 2098 if (left_type.IsNumber() && right_type.IsNumber()) {
1979 return HEAP_NUMBER; 2099 return HEAP_NUMBER;
1980 } 2100 }
1981 2101
1982 if (left_type.IsString() || right_type.IsString()) { 2102 if (left_type.IsString() || right_type.IsString()) {
1983 // Patching for fast string ADD makes sense even if only one of the 2103 // Patching for fast string ADD makes sense even if only one of the
1984 // arguments is a string. 2104 // arguments is a string.
(...skipping 23 matching lines...) Expand all
2008 static_cast<TRBinaryOpIC::TypeInfo>(Smi::cast(args[4])->value()); 2128 static_cast<TRBinaryOpIC::TypeInfo>(Smi::cast(args[4])->value());
2009 2129
2010 TRBinaryOpIC::TypeInfo type = TRBinaryOpIC::GetTypeInfo(left, right); 2130 TRBinaryOpIC::TypeInfo type = TRBinaryOpIC::GetTypeInfo(left, right);
2011 type = TRBinaryOpIC::JoinTypes(type, previous_type); 2131 type = TRBinaryOpIC::JoinTypes(type, previous_type);
2012 TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED; 2132 TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED;
2013 if (type == TRBinaryOpIC::STRING && op != Token::ADD) { 2133 if (type == TRBinaryOpIC::STRING && op != Token::ADD) {
2014 type = TRBinaryOpIC::GENERIC; 2134 type = TRBinaryOpIC::GENERIC;
2015 } 2135 }
2016 if (type == TRBinaryOpIC::SMI && 2136 if (type == TRBinaryOpIC::SMI &&
2017 previous_type == TRBinaryOpIC::SMI) { 2137 previous_type == TRBinaryOpIC::SMI) {
2018 if (op == Token::DIV || op == Token::MUL) { 2138 if (op == Token::DIV || op == Token::MUL || kSmiValueSize == 32) {
2019 // Arithmetic on two Smi inputs has yielded a heap number. 2139 // Arithmetic on two Smi inputs has yielded a heap number.
2020 // That is the only way to get here from the Smi stub. 2140 // That is the only way to get here from the Smi stub.
2141 // With 32-bit Smis, all overflows give heap numbers, but with
2142 // 31-bit Smis, most operations overflow to int32 results.
2021 result_type = TRBinaryOpIC::HEAP_NUMBER; 2143 result_type = TRBinaryOpIC::HEAP_NUMBER;
2022 } else { 2144 } else {
2023 // Other operations on SMIs that overflow yield int32s. 2145 // Other operations on SMIs that overflow yield int32s.
2024 result_type = TRBinaryOpIC::INT32; 2146 result_type = TRBinaryOpIC::INT32;
2025 } 2147 }
2026 } 2148 }
2027 if (type == TRBinaryOpIC::INT32 && 2149 if (type == TRBinaryOpIC::INT32 &&
2028 previous_type == TRBinaryOpIC::INT32) { 2150 previous_type == TRBinaryOpIC::INT32) {
2029 // We must be here because an operation on two INT32 types overflowed. 2151 // We must be here because an operation on two INT32 types overflowed.
2030 result_type = TRBinaryOpIC::HEAP_NUMBER; 2152 result_type = TRBinaryOpIC::HEAP_NUMBER;
2031 } 2153 }
2032 2154
2033 Handle<Code> code = GetTypeRecordingBinaryOpStub(key, type, result_type); 2155 Handle<Code> code = GetTypeRecordingBinaryOpStub(key, type, result_type);
2034 if (!code.is_null()) { 2156 if (!code.is_null()) {
2035 TRBinaryOpIC ic;
2036 ic.patch(*code);
2037 if (FLAG_trace_ic) { 2157 if (FLAG_trace_ic) {
2038 PrintF("[TypeRecordingBinaryOpIC (%s->(%s->%s))#%s]\n", 2158 PrintF("[TypeRecordingBinaryOpIC (%s->(%s->%s))#%s]\n",
2039 TRBinaryOpIC::GetName(previous_type), 2159 TRBinaryOpIC::GetName(previous_type),
2040 TRBinaryOpIC::GetName(type), 2160 TRBinaryOpIC::GetName(type),
2041 TRBinaryOpIC::GetName(result_type), 2161 TRBinaryOpIC::GetName(result_type),
2042 Token::Name(op)); 2162 Token::Name(op));
2043 } 2163 }
2164 TRBinaryOpIC ic;
2165 ic.patch(*code);
2044 2166
2045 // Activate inlined smi code. 2167 // Activate inlined smi code.
2046 if (previous_type == TRBinaryOpIC::UNINITIALIZED) { 2168 if (previous_type == TRBinaryOpIC::UNINITIALIZED) {
2047 PatchInlinedSmiCode(ic.address()); 2169 PatchInlinedSmiCode(ic.address());
2048 } 2170 }
2049 } 2171 }
2050 2172
2051 Handle<JSBuiltinsObject> builtins = Top::builtins(); 2173 Handle<JSBuiltinsObject> builtins = Top::builtins();
2052 Object* builtin = NULL; // Initialization calms down the compiler. 2174 Object* builtin = NULL; // Initialization calms down the compiler.
2053 switch (op) { 2175 switch (op) {
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
2164 #undef ADDR 2286 #undef ADDR
2165 }; 2287 };
2166 2288
2167 2289
2168 Address IC::AddressFromUtilityId(IC::UtilityId id) { 2290 Address IC::AddressFromUtilityId(IC::UtilityId id) {
2169 return IC_utilities[id]; 2291 return IC_utilities[id];
2170 } 2292 }
2171 2293
2172 2294
2173 } } // namespace v8::internal 2295 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/ic.h ('k') | src/inspector.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698