OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 } else { | 93 } else { |
94 PrintF("<unknown>"); | 94 PrintF("<unknown>"); |
95 } | 95 } |
96 PrintF(" (%c->%c)", | 96 PrintF(" (%c->%c)", |
97 TransitionMarkFromState(old_state), | 97 TransitionMarkFromState(old_state), |
98 TransitionMarkFromState(new_state)); | 98 TransitionMarkFromState(new_state)); |
99 name->Print(); | 99 name->Print(); |
100 PrintF("]\n"); | 100 PrintF("]\n"); |
101 } | 101 } |
102 } | 102 } |
103 #endif | 103 #endif // DEBUG |
| 104 |
| 105 |
| 106 #define TRACE_IC(type, name, old_state, new_target) \ |
| 107 ASSERT((TraceIC(type, name, old_state, new_target), true)) |
104 | 108 |
105 | 109 |
106 IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) { | 110 IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) { |
107 ASSERT(isolate == Isolate::Current()); | 111 ASSERT(isolate == Isolate::Current()); |
108 // To improve the performance of the (much used) IC code, we unfold | 112 // To improve the performance of the (much used) IC code, we unfold |
109 // a few levels of the stack frame iteration code. This yields a | 113 // a few levels of the stack frame iteration code. This yields a |
110 // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag. | 114 // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag. |
111 const Address entry = | 115 const Address entry = |
112 Isolate::c_entry_fp(isolate->thread_local_top()); | 116 Isolate::c_entry_fp(isolate->thread_local_top()); |
113 Address* pc_address = | 117 Address* pc_address = |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 ? initialize_stub_strict() | 365 ? initialize_stub_strict() |
362 : initialize_stub()); | 366 : initialize_stub()); |
363 } | 367 } |
364 | 368 |
365 | 369 |
366 static bool HasInterceptorGetter(JSObject* object) { | 370 static bool HasInterceptorGetter(JSObject* object) { |
367 return !object->GetNamedInterceptor()->getter()->IsUndefined(); | 371 return !object->GetNamedInterceptor()->getter()->IsUndefined(); |
368 } | 372 } |
369 | 373 |
370 | 374 |
371 static void LookupForRead(Object* object, | 375 static void LookupForRead(Handle<Object> object, |
372 String* name, | 376 Handle<String> name, |
373 LookupResult* lookup) { | 377 LookupResult* lookup) { |
374 AssertNoAllocation no_gc; // pointers must stay valid | |
375 | |
376 // Skip all the objects with named interceptors, but | 378 // Skip all the objects with named interceptors, but |
377 // without actual getter. | 379 // without actual getter. |
378 while (true) { | 380 while (true) { |
379 object->Lookup(name, lookup); | 381 object->Lookup(*name, lookup); |
380 // Besides normal conditions (property not found or it's not | 382 // Besides normal conditions (property not found or it's not |
381 // an interceptor), bail out if lookup is not cacheable: we won't | 383 // an interceptor), bail out if lookup is not cacheable: we won't |
382 // be able to IC it anyway and regular lookup should work fine. | 384 // be able to IC it anyway and regular lookup should work fine. |
383 if (!lookup->IsFound() | 385 if (!lookup->IsFound() |
384 || (lookup->type() != INTERCEPTOR) | 386 || (lookup->type() != INTERCEPTOR) |
385 || !lookup->IsCacheable()) { | 387 || !lookup->IsCacheable()) { |
386 return; | 388 return; |
387 } | 389 } |
388 | 390 |
389 JSObject* holder = lookup->holder(); | 391 Handle<JSObject> holder(lookup->holder()); |
390 if (HasInterceptorGetter(holder)) { | 392 if (HasInterceptorGetter(*holder)) { |
391 return; | 393 return; |
392 } | 394 } |
393 | 395 |
394 holder->LocalLookupRealNamedProperty(name, lookup); | 396 holder->LocalLookupRealNamedProperty(*name, lookup); |
395 if (lookup->IsProperty()) { | 397 if (lookup->IsProperty()) { |
396 ASSERT(lookup->type() != INTERCEPTOR); | 398 ASSERT(lookup->type() != INTERCEPTOR); |
397 return; | 399 return; |
398 } | 400 } |
399 | 401 |
400 Object* proto = holder->GetPrototype(); | 402 Handle<Object> proto(holder->GetPrototype()); |
401 if (proto->IsNull()) { | 403 if (proto->IsNull()) { |
402 lookup->NotFound(); | 404 lookup->NotFound(); |
403 return; | 405 return; |
404 } | 406 } |
405 | 407 |
406 object = proto; | 408 object = proto; |
407 } | 409 } |
408 } | 410 } |
409 | 411 |
410 | 412 |
411 Object* CallICBase::TryCallAsFunction(Object* object) { | 413 Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) { |
412 HandleScope scope(isolate()); | 414 Handle<Object> delegate = Execution::GetFunctionDelegate(object); |
413 Handle<Object> target(object, isolate()); | |
414 Handle<Object> delegate = Execution::GetFunctionDelegate(target); | |
415 | 415 |
416 if (delegate->IsJSFunction()) { | 416 if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) { |
417 // Patch the receiver and use the delegate as the function to | 417 // Patch the receiver and use the delegate as the function to |
418 // invoke. This is used for invoking objects as if they were | 418 // invoke. This is used for invoking objects as if they were functions. |
419 // functions. | 419 const int argc = target()->arguments_count(); |
420 const int argc = this->target()->arguments_count(); | |
421 StackFrameLocator locator; | 420 StackFrameLocator locator; |
422 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 421 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
423 int index = frame->ComputeExpressionsCount() - (argc + 1); | 422 int index = frame->ComputeExpressionsCount() - (argc + 1); |
424 frame->SetExpression(index, *target); | 423 frame->SetExpression(index, *object); |
425 } | 424 } |
426 | 425 |
427 return *delegate; | 426 return delegate; |
428 } | 427 } |
429 | 428 |
430 | 429 |
431 void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee, | 430 void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee, |
432 Handle<Object> object) { | 431 Handle<Object> object) { |
| 432 while (callee->IsJSFunctionProxy()) { |
| 433 callee = Handle<Object>(JSFunctionProxy::cast(*callee)->call_trap()); |
| 434 } |
| 435 |
433 if (callee->IsJSFunction()) { | 436 if (callee->IsJSFunction()) { |
434 Handle<JSFunction> function = Handle<JSFunction>::cast(callee); | 437 Handle<JSFunction> function = Handle<JSFunction>::cast(callee); |
435 if (function->shared()->strict_mode() || function->IsBuiltin()) { | 438 if (function->shared()->strict_mode() || function->IsBuiltin()) { |
436 // Do not wrap receiver for strict mode functions or for builtins. | 439 // Do not wrap receiver for strict mode functions or for builtins. |
437 return; | 440 return; |
438 } | 441 } |
439 } | 442 } |
440 | 443 |
441 // And only wrap string, number or boolean. | 444 // And only wrap string, number or boolean. |
442 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | 445 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
(...skipping 14 matching lines...) Expand all Loading... |
457 // If the object is undefined or null it's illegal to try to get any | 460 // If the object is undefined or null it's illegal to try to get any |
458 // of its properties; throw a TypeError in that case. | 461 // of its properties; throw a TypeError in that case. |
459 if (object->IsUndefined() || object->IsNull()) { | 462 if (object->IsUndefined() || object->IsNull()) { |
460 return TypeError("non_object_property_call", object, name); | 463 return TypeError("non_object_property_call", object, name); |
461 } | 464 } |
462 | 465 |
463 // Check if the name is trivially convertible to an index and get | 466 // Check if the name is trivially convertible to an index and get |
464 // the element if so. | 467 // the element if so. |
465 uint32_t index; | 468 uint32_t index; |
466 if (name->AsArrayIndex(&index)) { | 469 if (name->AsArrayIndex(&index)) { |
467 Object* result; | 470 Handle<Object> result = Object::GetElement(object, index); |
468 { MaybeObject* maybe_result = object->GetElement(index); | 471 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
469 if (!maybe_result->ToObject(&result)) return maybe_result; | 472 if (result->IsJSFunction()) return *result; |
470 } | |
471 | |
472 if (result->IsJSFunction()) return result; | |
473 | 473 |
474 // Try to find a suitable function delegate for the object at hand. | 474 // Try to find a suitable function delegate for the object at hand. |
475 result = TryCallAsFunction(result); | 475 result = TryCallAsFunction(result); |
476 if (result->IsJSFunction()) return result; | 476 if (result->IsJSFunction()) return *result; |
477 | 477 |
478 // Otherwise, it will fail in the lookup step. | 478 // Otherwise, it will fail in the lookup step. |
479 } | 479 } |
480 | 480 |
481 // Lookup the property in the object. | 481 // Lookup the property in the object. |
482 LookupResult lookup; | 482 LookupResult lookup(isolate()); |
483 LookupForRead(*object, *name, &lookup); | 483 LookupForRead(object, name, &lookup); |
484 | 484 |
485 if (!lookup.IsProperty()) { | 485 if (!lookup.IsProperty()) { |
486 // If the object does not have the requested property, check which | 486 // If the object does not have the requested property, check which |
487 // exception we need to throw. | 487 // exception we need to throw. |
488 if (IsContextual(object)) { | 488 return IsContextual(object) |
489 return ReferenceError("not_defined", name); | 489 ? ReferenceError("not_defined", name) |
490 } | 490 : TypeError("undefined_method", object, name); |
491 return TypeError("undefined_method", object, name); | |
492 } | 491 } |
493 | 492 |
494 // Lookup is valid: Update inline cache and stub cache. | 493 // Lookup is valid: Update inline cache and stub cache. |
495 if (FLAG_use_ic) { | 494 if (FLAG_use_ic) { |
496 UpdateCaches(&lookup, state, extra_ic_state, object, name); | 495 UpdateCaches(&lookup, state, extra_ic_state, object, name); |
497 } | 496 } |
498 | 497 |
499 // Get the property. | 498 // Get the property. |
500 PropertyAttributes attr; | 499 PropertyAttributes attr; |
501 Object* result; | 500 Handle<Object> result = |
502 { MaybeObject* maybe_result = | 501 Object::GetProperty(object, object, &lookup, name, &attr); |
503 object->GetProperty(*object, &lookup, *name, &attr); | 502 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
504 if (!maybe_result->ToObject(&result)) return maybe_result; | |
505 } | |
506 | 503 |
507 if (lookup.type() == INTERCEPTOR) { | 504 if (lookup.type() == INTERCEPTOR && attr == ABSENT) { |
508 // If the object does not have the requested property, check which | 505 // If the object does not have the requested property, check which |
509 // exception we need to throw. | 506 // exception we need to throw. |
510 if (attr == ABSENT) { | 507 return IsContextual(object) |
511 if (IsContextual(object)) { | 508 ? ReferenceError("not_defined", name) |
512 return ReferenceError("not_defined", name); | 509 : TypeError("undefined_method", object, name); |
513 } | |
514 return TypeError("undefined_method", object, name); | |
515 } | |
516 } | 510 } |
517 | 511 |
518 ASSERT(!result->IsTheHole()); | 512 ASSERT(!result->IsTheHole()); |
519 | 513 |
520 HandleScope scope(isolate()); | |
521 // Wrap result in a handle because ReceiverToObjectIfRequired may allocate | |
522 // new object and cause GC. | |
523 Handle<Object> result_handle(result); | |
524 // Make receiver an object if the callee requires it. Strict mode or builtin | 514 // Make receiver an object if the callee requires it. Strict mode or builtin |
525 // functions do not wrap the receiver, non-strict functions and objects | 515 // functions do not wrap the receiver, non-strict functions and objects |
526 // called as functions do. | 516 // called as functions do. |
527 ReceiverToObjectIfRequired(result_handle, object); | 517 ReceiverToObjectIfRequired(result, object); |
528 | 518 |
529 if (result_handle->IsJSFunction()) { | 519 if (result->IsJSFunction()) { |
| 520 Handle<JSFunction> function = Handle<JSFunction>::cast(result); |
530 #ifdef ENABLE_DEBUGGER_SUPPORT | 521 #ifdef ENABLE_DEBUGGER_SUPPORT |
531 // Handle stepping into a function if step into is active. | 522 // Handle stepping into a function if step into is active. |
532 Debug* debug = isolate()->debug(); | 523 Debug* debug = isolate()->debug(); |
533 if (debug->StepInActive()) { | 524 if (debug->StepInActive()) { |
534 // Protect the result in a handle as the debugger can allocate and might | 525 // Protect the result in a handle as the debugger can allocate and might |
535 // cause GC. | 526 // cause GC. |
536 Handle<JSFunction> function(JSFunction::cast(*result_handle), isolate()); | |
537 debug->HandleStepIn(function, object, fp(), false); | 527 debug->HandleStepIn(function, object, fp(), false); |
538 return *function; | |
539 } | 528 } |
540 #endif | 529 #endif |
541 | 530 return *function; |
542 return *result_handle; | |
543 } | 531 } |
544 | 532 |
545 // Try to find a suitable function delegate for the object at hand. | 533 // Try to find a suitable function delegate for the object at hand. |
546 result_handle = Handle<Object>(TryCallAsFunction(*result_handle)); | 534 result = TryCallAsFunction(result); |
547 if (result_handle->IsJSFunction()) return *result_handle; | 535 if (result->IsJSFunction()) return *result; |
548 | 536 |
549 return TypeError("property_not_function", object, name); | 537 return TypeError("property_not_function", object, name); |
550 } | 538 } |
551 | 539 |
552 | 540 |
553 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, | 541 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, |
554 Handle<Object> object, | 542 Handle<Object> object, |
555 Code::ExtraICState* extra_ic_state) { | 543 Code::ExtraICState* extra_ic_state) { |
556 ASSERT(kind_ == Code::CALL_IC); | 544 ASSERT(kind_ == Code::CALL_IC); |
557 if (lookup->type() != CONSTANT_FUNCTION) return false; | 545 if (lookup->type() != CONSTANT_FUNCTION) return false; |
(...skipping 29 matching lines...) Expand all Loading... |
587 } | 575 } |
588 } | 576 } |
589 break; | 577 break; |
590 default: | 578 default: |
591 return false; | 579 return false; |
592 } | 580 } |
593 return false; | 581 return false; |
594 } | 582 } |
595 | 583 |
596 | 584 |
597 MaybeObject* CallICBase::ComputeMonomorphicStub( | 585 Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, |
598 LookupResult* lookup, | 586 State state, |
599 State state, | 587 Code::ExtraICState extra_state, |
600 Code::ExtraICState extra_ic_state, | 588 Handle<Object> object, |
601 Handle<Object> object, | 589 Handle<String> name) { |
602 Handle<String> name) { | |
603 int argc = target()->arguments_count(); | 590 int argc = target()->arguments_count(); |
604 MaybeObject* maybe_code = NULL; | 591 Handle<JSObject> holder(lookup->holder()); |
605 switch (lookup->type()) { | 592 switch (lookup->type()) { |
606 case FIELD: { | 593 case FIELD: { |
607 int index = lookup->GetFieldIndex(); | 594 int index = lookup->GetFieldIndex(); |
608 maybe_code = isolate()->stub_cache()->ComputeCallField(argc, | 595 return isolate()->stub_cache()->ComputeCallField( |
609 kind_, | 596 argc, kind_, extra_state, name, object, holder, index); |
610 extra_ic_state, | |
611 *name, | |
612 *object, | |
613 lookup->holder(), | |
614 index); | |
615 break; | |
616 } | 597 } |
617 case CONSTANT_FUNCTION: { | 598 case CONSTANT_FUNCTION: { |
618 // Get the constant function and compute the code stub for this | 599 // Get the constant function and compute the code stub for this |
619 // call; used for rewriting to monomorphic state and making sure | 600 // call; used for rewriting to monomorphic state and making sure |
620 // that the code stub is in the stub cache. | 601 // that the code stub is in the stub cache. |
621 JSFunction* function = lookup->GetConstantFunction(); | 602 Handle<JSFunction> function(lookup->GetConstantFunction()); |
622 maybe_code = | 603 return isolate()->stub_cache()->ComputeCallConstant( |
623 isolate()->stub_cache()->ComputeCallConstant(argc, | 604 argc, kind_, extra_state, name, object, holder, function); |
624 kind_, | |
625 extra_ic_state, | |
626 *name, | |
627 *object, | |
628 lookup->holder(), | |
629 function); | |
630 break; | |
631 } | 605 } |
632 case NORMAL: { | 606 case NORMAL: { |
633 if (!object->IsJSObject()) return NULL; | 607 // If we return a null handle, the IC will not be patched. |
| 608 if (!object->IsJSObject()) return Handle<Code>::null(); |
634 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 609 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
635 | 610 |
636 if (lookup->holder()->IsGlobalObject()) { | 611 if (holder->IsGlobalObject()) { |
637 GlobalObject* global = GlobalObject::cast(lookup->holder()); | 612 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
638 JSGlobalPropertyCell* cell = | 613 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); |
639 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | 614 if (!cell->value()->IsJSFunction()) return Handle<Code>::null(); |
640 if (!cell->value()->IsJSFunction()) return NULL; | 615 Handle<JSFunction> function(JSFunction::cast(cell->value())); |
641 JSFunction* function = JSFunction::cast(cell->value()); | 616 return isolate()->stub_cache()->ComputeCallGlobal( |
642 maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc, | 617 argc, kind_, extra_state, name, receiver, global, cell, function); |
643 kind_, | |
644 extra_ic_state, | |
645 *name, | |
646 *receiver, | |
647 global, | |
648 cell, | |
649 function); | |
650 } else { | 618 } else { |
651 // There is only one shared stub for calling normalized | 619 // There is only one shared stub for calling normalized |
652 // properties. It does not traverse the prototype chain, so the | 620 // properties. It does not traverse the prototype chain, so the |
653 // property must be found in the receiver for the stub to be | 621 // property must be found in the receiver for the stub to be |
654 // applicable. | 622 // applicable. |
655 if (lookup->holder() != *receiver) return NULL; | 623 if (!holder.is_identical_to(receiver)) return Handle<Code>::null(); |
656 maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc, | 624 return isolate()->stub_cache()->ComputeCallNormal( |
657 kind_, | 625 argc, kind_, extra_state); |
658 extra_ic_state, | |
659 *name, | |
660 *receiver); | |
661 } | 626 } |
662 break; | 627 break; |
663 } | 628 } |
664 case INTERCEPTOR: { | 629 case INTERCEPTOR: |
665 ASSERT(HasInterceptorGetter(lookup->holder())); | 630 ASSERT(HasInterceptorGetter(*holder)); |
666 maybe_code = isolate()->stub_cache()->ComputeCallInterceptor( | 631 return isolate()->stub_cache()->ComputeCallInterceptor( |
667 argc, | 632 argc, kind_, extra_state, name, object, holder); |
668 kind_, | |
669 extra_ic_state, | |
670 *name, | |
671 *object, | |
672 lookup->holder()); | |
673 break; | |
674 } | |
675 default: | 633 default: |
676 maybe_code = NULL; | 634 return Handle<Code>::null(); |
677 break; | |
678 } | 635 } |
679 return maybe_code; | |
680 } | 636 } |
681 | 637 |
682 | 638 |
683 void CallICBase::UpdateCaches(LookupResult* lookup, | 639 void CallICBase::UpdateCaches(LookupResult* lookup, |
684 State state, | 640 State state, |
685 Code::ExtraICState extra_ic_state, | 641 Code::ExtraICState extra_ic_state, |
686 Handle<Object> object, | 642 Handle<Object> object, |
687 Handle<String> name) { | 643 Handle<String> name) { |
688 // Bail out if we didn't find a result. | 644 // Bail out if we didn't find a result. |
689 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 645 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
690 | 646 |
691 if (lookup->holder() != *object && | 647 if (lookup->holder() != *object && |
692 HasNormalObjectsInPrototypeChain( | 648 HasNormalObjectsInPrototypeChain( |
693 isolate(), lookup, object->GetPrototype())) { | 649 isolate(), lookup, object->GetPrototype())) { |
694 // Suppress optimization for prototype chains with slow properties objects | 650 // Suppress optimization for prototype chains with slow properties objects |
695 // in the middle. | 651 // in the middle. |
696 return; | 652 return; |
697 } | 653 } |
698 | 654 |
699 // Compute the number of arguments. | 655 // Compute the number of arguments. |
700 int argc = target()->arguments_count(); | 656 int argc = target()->arguments_count(); |
701 MaybeObject* maybe_code = NULL; | |
702 bool had_proto_failure = false; | 657 bool had_proto_failure = false; |
| 658 Handle<Code> code; |
703 if (state == UNINITIALIZED) { | 659 if (state == UNINITIALIZED) { |
704 // This is the first time we execute this inline cache. | 660 // This is the first time we execute this inline cache. |
705 // Set the target to the pre monomorphic stub to delay | 661 // Set the target to the pre monomorphic stub to delay |
706 // setting the monomorphic state. | 662 // setting the monomorphic state. |
707 maybe_code = | 663 code = isolate()->stub_cache()->ComputeCallPreMonomorphic( |
708 isolate()->stub_cache()->ComputeCallPreMonomorphic(argc, | 664 argc, kind_, extra_ic_state); |
709 kind_, | |
710 extra_ic_state); | |
711 } else if (state == MONOMORPHIC) { | 665 } else if (state == MONOMORPHIC) { |
712 if (kind_ == Code::CALL_IC && | 666 if (kind_ == Code::CALL_IC && |
713 TryUpdateExtraICState(lookup, object, &extra_ic_state)) { | 667 TryUpdateExtraICState(lookup, object, &extra_ic_state)) { |
714 maybe_code = ComputeMonomorphicStub(lookup, | 668 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, |
715 state, | 669 object, name); |
716 extra_ic_state, | |
717 object, | |
718 name); | |
719 } else if (kind_ == Code::CALL_IC && | 670 } else if (kind_ == Code::CALL_IC && |
720 TryRemoveInvalidPrototypeDependentStub(target(), | 671 TryRemoveInvalidPrototypeDependentStub(target(), |
721 *object, | 672 *object, |
722 *name)) { | 673 *name)) { |
723 had_proto_failure = true; | 674 had_proto_failure = true; |
724 maybe_code = ComputeMonomorphicStub(lookup, | 675 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, |
725 state, | 676 object, name); |
726 extra_ic_state, | |
727 object, | |
728 name); | |
729 } else { | 677 } else { |
730 maybe_code = | 678 code = isolate()->stub_cache()->ComputeCallMegamorphic( |
731 isolate()->stub_cache()->ComputeCallMegamorphic(argc, | 679 argc, kind_, extra_ic_state); |
732 kind_, | |
733 extra_ic_state); | |
734 } | 680 } |
735 } else { | 681 } else { |
736 maybe_code = ComputeMonomorphicStub(lookup, | 682 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, |
737 state, | 683 object, name); |
738 extra_ic_state, | |
739 object, | |
740 name); | |
741 } | 684 } |
742 | 685 |
743 // If we're unable to compute the stub (not enough memory left), we | 686 // If there's no appropriate stub we simply avoid updating the caches. |
744 // simply avoid updating the caches. | 687 if (code.is_null()) return; |
745 Object* code; | |
746 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | |
747 | 688 |
748 // Patch the call site depending on the state of the cache. | 689 // Patch the call site depending on the state of the cache. |
749 if (state == UNINITIALIZED || | 690 if (state == UNINITIALIZED || |
750 state == PREMONOMORPHIC || | 691 state == PREMONOMORPHIC || |
751 state == MONOMORPHIC || | 692 state == MONOMORPHIC || |
752 state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 693 state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
753 set_target(Code::cast(code)); | 694 set_target(*code); |
754 } else if (state == MEGAMORPHIC) { | 695 } else if (state == MEGAMORPHIC) { |
755 // Cache code holding map should be consistent with | 696 // Cache code holding map should be consistent with |
756 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. | 697 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. |
757 Map* map = JSObject::cast(object->IsJSObject() ? *object : | 698 Handle<JSObject> cache_object = object->IsJSObject() |
758 object->GetPrototype())->map(); | 699 ? Handle<JSObject>::cast(object) |
759 | 700 : Handle<JSObject>(JSObject::cast(object->GetPrototype())); |
760 // Update the stub cache. | 701 // Update the stub cache. |
761 isolate()->stub_cache()->Set(*name, map, Code::cast(code)); | 702 isolate()->stub_cache()->Set(*name, cache_object->map(), *code); |
762 } | 703 } |
763 | 704 |
764 USE(had_proto_failure); | |
765 #ifdef DEBUG | |
766 if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE; | 705 if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE; |
767 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", | 706 TRACE_IC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", |
768 name, state, target()); | 707 name, state, target()); |
769 #endif | |
770 } | 708 } |
771 | 709 |
772 | 710 |
773 MaybeObject* KeyedCallIC::LoadFunction(State state, | 711 MaybeObject* KeyedCallIC::LoadFunction(State state, |
774 Handle<Object> object, | 712 Handle<Object> object, |
775 Handle<Object> key) { | 713 Handle<Object> key) { |
776 if (key->IsSymbol()) { | 714 if (key->IsSymbol()) { |
777 return CallICBase::LoadFunction(state, | 715 return CallICBase::LoadFunction(state, |
778 Code::kNoExtraICState, | 716 Code::kNoExtraICState, |
779 object, | 717 object, |
780 Handle<String>::cast(key)); | 718 Handle<String>::cast(key)); |
781 } | 719 } |
782 | 720 |
783 if (object->IsUndefined() || object->IsNull()) { | 721 if (object->IsUndefined() || object->IsNull()) { |
784 return TypeError("non_object_property_call", object, key); | 722 return TypeError("non_object_property_call", object, key); |
785 } | 723 } |
786 | 724 |
787 if (FLAG_use_ic && state != MEGAMORPHIC && object->IsHeapObject()) { | 725 if (FLAG_use_ic && state != MEGAMORPHIC && object->IsHeapObject()) { |
788 int argc = target()->arguments_count(); | 726 int argc = target()->arguments_count(); |
789 Heap* heap = Handle<HeapObject>::cast(object)->GetHeap(); | 727 Handle<Map> map = |
790 Map* map = heap->non_strict_arguments_elements_map(); | 728 isolate()->factory()->non_strict_arguments_elements_map(); |
791 if (object->IsJSObject() && | 729 if (object->IsJSObject() && |
792 Handle<JSObject>::cast(object)->elements()->map() == map) { | 730 Handle<JSObject>::cast(object)->elements()->map() == *map) { |
793 MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallArguments( | 731 Handle<Code> code = isolate()->stub_cache()->ComputeCallArguments( |
794 argc, Code::KEYED_CALL_IC); | 732 argc, Code::KEYED_CALL_IC); |
795 Object* code; | 733 set_target(*code); |
796 if (maybe_code->ToObject(&code)) { | 734 TRACE_IC("KeyedCallIC", key, state, target()); |
797 set_target(Code::cast(code)); | 735 } else if (!object->IsAccessCheckNeeded()) { |
798 #ifdef DEBUG | 736 Handle<Code> code = isolate()->stub_cache()->ComputeCallMegamorphic( |
799 TraceIC("KeyedCallIC", key, state, target()); | |
800 #endif | |
801 } | |
802 } else if (FLAG_use_ic && state != MEGAMORPHIC && | |
803 !object->IsAccessCheckNeeded()) { | |
804 MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic( | |
805 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState); | 737 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState); |
806 Object* code; | 738 set_target(*code); |
807 if (maybe_code->ToObject(&code)) { | 739 TRACE_IC("KeyedCallIC", key, state, target()); |
808 set_target(Code::cast(code)); | |
809 #ifdef DEBUG | |
810 TraceIC("KeyedCallIC", key, state, target()); | |
811 #endif | |
812 } | |
813 } | 740 } |
814 } | 741 } |
815 | 742 |
816 HandleScope scope(isolate()); | |
817 Handle<Object> result = GetProperty(object, key); | 743 Handle<Object> result = GetProperty(object, key); |
818 RETURN_IF_EMPTY_HANDLE(isolate(), result); | 744 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
819 | 745 |
820 // Make receiver an object if the callee requires it. Strict mode or builtin | 746 // Make receiver an object if the callee requires it. Strict mode or builtin |
821 // functions do not wrap the receiver, non-strict functions and objects | 747 // functions do not wrap the receiver, non-strict functions and objects |
822 // called as functions do. | 748 // called as functions do. |
823 ReceiverToObjectIfRequired(result, object); | 749 ReceiverToObjectIfRequired(result, object); |
| 750 if (result->IsJSFunction()) return *result; |
824 | 751 |
825 if (result->IsJSFunction()) return *result; | 752 result = TryCallAsFunction(result); |
826 result = Handle<Object>(TryCallAsFunction(*result)); | |
827 if (result->IsJSFunction()) return *result; | 753 if (result->IsJSFunction()) return *result; |
828 | 754 |
829 return TypeError("property_not_function", object, key); | 755 return TypeError("property_not_function", object, key); |
830 } | 756 } |
831 | 757 |
832 | 758 |
833 MaybeObject* LoadIC::Load(State state, | 759 MaybeObject* LoadIC::Load(State state, |
834 Handle<Object> object, | 760 Handle<Object> object, |
835 Handle<String> name) { | 761 Handle<String> name) { |
836 // If the object is undefined or null it's illegal to try to get any | 762 // If the object is undefined or null it's illegal to try to get any |
837 // of its properties; throw a TypeError in that case. | 763 // of its properties; throw a TypeError in that case. |
838 if (object->IsUndefined() || object->IsNull()) { | 764 if (object->IsUndefined() || object->IsNull()) { |
839 return TypeError("non_object_property_load", object, name); | 765 return TypeError("non_object_property_load", object, name); |
840 } | 766 } |
841 | 767 |
842 if (FLAG_use_ic) { | 768 if (FLAG_use_ic) { |
843 // Use specialized code for getting the length of strings and | 769 // Use specialized code for getting the length of strings and |
844 // string wrapper objects. The length property of string wrapper | 770 // string wrapper objects. The length property of string wrapper |
845 // objects is read-only and therefore always returns the length of | 771 // objects is read-only and therefore always returns the length of |
846 // the underlying string value. See ECMA-262 15.5.5.1. | 772 // the underlying string value. See ECMA-262 15.5.5.1. |
847 if ((object->IsString() || object->IsStringWrapper()) && | 773 if ((object->IsString() || object->IsStringWrapper()) && |
848 name->Equals(isolate()->heap()->length_symbol())) { | 774 name->Equals(isolate()->heap()->length_symbol())) { |
849 AssertNoAllocation no_allocation; | 775 Handle<Code> stub; |
850 Code* stub = NULL; | |
851 if (state == UNINITIALIZED) { | 776 if (state == UNINITIALIZED) { |
852 stub = pre_monomorphic_stub(); | 777 stub = pre_monomorphic_stub(); |
853 } else if (state == PREMONOMORPHIC) { | 778 } else if (state == PREMONOMORPHIC) { |
854 if (object->IsString()) { | 779 stub = object->IsString() |
855 stub = isolate()->builtins()->builtin( | 780 ? isolate()->builtins()->LoadIC_StringLength() |
856 Builtins::kLoadIC_StringLength); | 781 : isolate()->builtins()->LoadIC_StringWrapperLength(); |
857 } else { | |
858 stub = isolate()->builtins()->builtin( | |
859 Builtins::kLoadIC_StringWrapperLength); | |
860 } | |
861 } else if (state == MONOMORPHIC && object->IsStringWrapper()) { | 782 } else if (state == MONOMORPHIC && object->IsStringWrapper()) { |
862 stub = isolate()->builtins()->builtin( | 783 stub = isolate()->builtins()->LoadIC_StringWrapperLength(); |
863 Builtins::kLoadIC_StringWrapperLength); | |
864 } else if (state != MEGAMORPHIC) { | 784 } else if (state != MEGAMORPHIC) { |
865 stub = megamorphic_stub(); | 785 stub = megamorphic_stub(); |
866 } | 786 } |
867 if (stub != NULL) { | 787 if (!stub.is_null()) { |
868 set_target(stub); | 788 set_target(*stub); |
869 #ifdef DEBUG | 789 #ifdef DEBUG |
870 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); | 790 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); |
871 #endif | 791 #endif |
872 } | 792 } |
873 // Get the string if we have a string wrapper object. | 793 // Get the string if we have a string wrapper object. |
874 if (object->IsJSValue()) { | 794 Handle<Object> string = object->IsJSValue() |
875 return Smi::FromInt( | 795 ? Handle<Object>(Handle<JSValue>::cast(object)->value()) |
876 String::cast(Handle<JSValue>::cast(object)->value())->length()); | 796 : object; |
877 } | 797 return Smi::FromInt(String::cast(*string)->length()); |
878 return Smi::FromInt(String::cast(*object)->length()); | |
879 } | 798 } |
880 | 799 |
881 // Use specialized code for getting the length of arrays. | 800 // Use specialized code for getting the length of arrays. |
882 if (object->IsJSArray() && | 801 if (object->IsJSArray() && |
883 name->Equals(isolate()->heap()->length_symbol())) { | 802 name->Equals(isolate()->heap()->length_symbol())) { |
884 AssertNoAllocation no_allocation; | 803 Handle<Code> stub; |
885 Code* stub = NULL; | |
886 if (state == UNINITIALIZED) { | 804 if (state == UNINITIALIZED) { |
887 stub = pre_monomorphic_stub(); | 805 stub = pre_monomorphic_stub(); |
888 } else if (state == PREMONOMORPHIC) { | 806 } else if (state == PREMONOMORPHIC) { |
889 stub = isolate()->builtins()->builtin( | 807 stub = isolate()->builtins()->LoadIC_ArrayLength(); |
890 Builtins::kLoadIC_ArrayLength); | |
891 } else if (state != MEGAMORPHIC) { | 808 } else if (state != MEGAMORPHIC) { |
892 stub = megamorphic_stub(); | 809 stub = megamorphic_stub(); |
893 } | 810 } |
894 if (stub != NULL) { | 811 if (!stub.is_null()) { |
895 set_target(stub); | 812 set_target(*stub); |
896 #ifdef DEBUG | 813 #ifdef DEBUG |
897 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); | 814 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); |
898 #endif | 815 #endif |
899 } | 816 } |
900 return JSArray::cast(*object)->length(); | 817 return JSArray::cast(*object)->length(); |
901 } | 818 } |
902 | 819 |
903 // Use specialized code for getting prototype of functions. | 820 // Use specialized code for getting prototype of functions. |
904 if (object->IsJSFunction() && | 821 if (object->IsJSFunction() && |
905 name->Equals(isolate()->heap()->prototype_symbol()) && | 822 name->Equals(isolate()->heap()->prototype_symbol()) && |
906 JSFunction::cast(*object)->should_have_prototype()) { | 823 Handle<JSFunction>::cast(object)->should_have_prototype()) { |
907 { AssertNoAllocation no_allocation; | 824 Handle<Code> stub; |
908 Code* stub = NULL; | 825 if (state == UNINITIALIZED) { |
909 if (state == UNINITIALIZED) { | 826 stub = pre_monomorphic_stub(); |
910 stub = pre_monomorphic_stub(); | 827 } else if (state == PREMONOMORPHIC) { |
911 } else if (state == PREMONOMORPHIC) { | 828 stub = isolate()->builtins()->LoadIC_FunctionPrototype(); |
912 stub = isolate()->builtins()->builtin( | 829 } else if (state != MEGAMORPHIC) { |
913 Builtins::kLoadIC_FunctionPrototype); | 830 stub = megamorphic_stub(); |
914 } else if (state != MEGAMORPHIC) { | 831 } |
915 stub = megamorphic_stub(); | 832 if (!stub.is_null()) { |
916 } | 833 set_target(*stub); |
917 if (stub != NULL) { | |
918 set_target(stub); | |
919 #ifdef DEBUG | 834 #ifdef DEBUG |
920 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); | 835 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); |
921 #endif | 836 #endif |
922 } | |
923 } | 837 } |
924 return Accessors::FunctionGetPrototype(*object, 0); | 838 return Accessors::FunctionGetPrototype(*object, 0); |
925 } | 839 } |
926 } | 840 } |
927 | 841 |
928 // Check if the name is trivially convertible to an index and get | 842 // Check if the name is trivially convertible to an index and get |
929 // the element if so. | 843 // the element if so. |
930 uint32_t index; | 844 uint32_t index; |
931 if (name->AsArrayIndex(&index)) return object->GetElement(index); | 845 if (name->AsArrayIndex(&index)) return object->GetElement(index); |
932 | 846 |
933 // Named lookup in the object. | 847 // Named lookup in the object. |
934 LookupResult lookup; | 848 LookupResult lookup(isolate()); |
935 LookupForRead(*object, *name, &lookup); | 849 LookupForRead(object, name, &lookup); |
936 | 850 |
937 // If we did not find a property, check if we need to throw an exception. | 851 // If we did not find a property, check if we need to throw an exception. |
938 if (!lookup.IsProperty()) { | 852 if (!lookup.IsProperty()) { |
939 if (IsContextual(object)) { | 853 if (IsContextual(object)) { |
940 return ReferenceError("not_defined", name); | 854 return ReferenceError("not_defined", name); |
941 } | 855 } |
942 LOG(isolate(), SuspectReadEvent(*name, *object)); | 856 LOG(isolate(), SuspectReadEvent(*name, *object)); |
943 } | 857 } |
944 | 858 |
945 // Update inline cache and stub cache. | 859 // Update inline cache and stub cache. |
946 if (FLAG_use_ic) { | 860 if (FLAG_use_ic) { |
947 UpdateCaches(&lookup, state, object, name); | 861 UpdateCaches(&lookup, state, object, name); |
948 } | 862 } |
949 | 863 |
950 PropertyAttributes attr; | 864 PropertyAttributes attr; |
951 if (lookup.IsProperty() && | 865 if (lookup.IsProperty() && |
952 (lookup.type() == INTERCEPTOR || lookup.type() == HANDLER)) { | 866 (lookup.type() == INTERCEPTOR || lookup.type() == HANDLER)) { |
953 // Get the property. | 867 // Get the property. |
954 Object* result; | 868 Handle<Object> result = |
955 { MaybeObject* maybe_result = | 869 Object::GetProperty(object, object, &lookup, name, &attr); |
956 object->GetProperty(*object, &lookup, *name, &attr); | 870 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
957 if (!maybe_result->ToObject(&result)) return maybe_result; | |
958 } | |
959 // If the property is not present, check if we need to throw an | 871 // If the property is not present, check if we need to throw an |
960 // exception. | 872 // exception. |
961 if (attr == ABSENT && IsContextual(object)) { | 873 if (attr == ABSENT && IsContextual(object)) { |
962 return ReferenceError("not_defined", name); | 874 return ReferenceError("not_defined", name); |
963 } | 875 } |
964 return result; | 876 return *result; |
965 } | 877 } |
966 | 878 |
967 // Get the property. | 879 // Get the property. |
968 return object->GetProperty(*object, &lookup, *name, &attr); | 880 return object->GetProperty(*object, &lookup, *name, &attr); |
969 } | 881 } |
970 | 882 |
971 | 883 |
972 void LoadIC::UpdateCaches(LookupResult* lookup, | 884 void LoadIC::UpdateCaches(LookupResult* lookup, |
973 State state, | 885 State state, |
974 Handle<Object> object, | 886 Handle<Object> object, |
975 Handle<String> name) { | 887 Handle<String> name) { |
976 // Bail out if the result is not cacheable. | 888 // Bail out if the result is not cacheable. |
977 if (!lookup->IsCacheable()) return; | 889 if (!lookup->IsCacheable()) return; |
978 | 890 |
979 // Loading properties from values is not common, so don't try to | 891 // Loading properties from values is not common, so don't try to |
980 // deal with non-JS objects here. | 892 // deal with non-JS objects here. |
981 if (!object->IsJSObject()) return; | 893 if (!object->IsJSObject()) return; |
982 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 894 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
983 | 895 |
984 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; | 896 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; |
985 | 897 |
986 // Compute the code stub for this load. | 898 // Compute the code stub for this load. |
987 MaybeObject* maybe_code = NULL; | 899 Handle<Code> code; |
988 Object* code; | |
989 if (state == UNINITIALIZED) { | 900 if (state == UNINITIALIZED) { |
990 // This is the first time we execute this inline cache. | 901 // This is the first time we execute this inline cache. |
991 // Set the target to the pre monomorphic stub to delay | 902 // Set the target to the pre monomorphic stub to delay |
992 // setting the monomorphic state. | 903 // setting the monomorphic state. |
993 maybe_code = pre_monomorphic_stub(); | 904 code = pre_monomorphic_stub(); |
994 } else if (!lookup->IsProperty()) { | 905 } else if (!lookup->IsProperty()) { |
995 // Nonexistent property. The result is undefined. | 906 // Nonexistent property. The result is undefined. |
996 maybe_code = isolate()->stub_cache()->ComputeLoadNonexistent(*name, | 907 code = isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver); |
997 *receiver); | |
998 } else { | 908 } else { |
999 // Compute monomorphic stub. | 909 // Compute monomorphic stub. |
| 910 Handle<JSObject> holder(lookup->holder()); |
1000 switch (lookup->type()) { | 911 switch (lookup->type()) { |
1001 case FIELD: { | 912 case FIELD: |
1002 maybe_code = isolate()->stub_cache()->ComputeLoadField( | 913 code = isolate()->stub_cache()->ComputeLoadField( |
1003 *name, | 914 name, receiver, holder, lookup->GetFieldIndex()); |
1004 *receiver, | 915 break; |
1005 lookup->holder(), | 916 case CONSTANT_FUNCTION: { |
1006 lookup->GetFieldIndex()); | 917 Handle<Object> constant(lookup->GetConstantFunction()); |
| 918 code = isolate()->stub_cache()->ComputeLoadConstant( |
| 919 name, receiver, holder, constant); |
1007 break; | 920 break; |
1008 } | 921 } |
1009 case CONSTANT_FUNCTION: { | 922 case NORMAL: |
1010 Object* constant = lookup->GetConstantFunction(); | 923 if (holder->IsGlobalObject()) { |
1011 maybe_code = isolate()->stub_cache()->ComputeLoadConstant( | 924 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
1012 *name, *receiver, lookup->holder(), constant); | 925 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); |
1013 break; | 926 code = isolate()->stub_cache()->ComputeLoadGlobal( |
1014 } | 927 name, receiver, global, cell, lookup->IsDontDelete()); |
1015 case NORMAL: { | |
1016 if (lookup->holder()->IsGlobalObject()) { | |
1017 GlobalObject* global = GlobalObject::cast(lookup->holder()); | |
1018 JSGlobalPropertyCell* cell = | |
1019 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | |
1020 maybe_code = isolate()->stub_cache()->ComputeLoadGlobal(*name, | |
1021 *receiver, | |
1022 global, | |
1023 cell, | |
1024 lookup->IsDontDelete()); | |
1025 } else { | 928 } else { |
1026 // There is only one shared stub for loading normalized | 929 // There is only one shared stub for loading normalized |
1027 // properties. It does not traverse the prototype chain, so the | 930 // properties. It does not traverse the prototype chain, so the |
1028 // property must be found in the receiver for the stub to be | 931 // property must be found in the receiver for the stub to be |
1029 // applicable. | 932 // applicable. |
1030 if (lookup->holder() != *receiver) return; | 933 if (!holder.is_identical_to(receiver)) return; |
1031 maybe_code = isolate()->stub_cache()->ComputeLoadNormal(); | 934 code = isolate()->stub_cache()->ComputeLoadNormal(); |
1032 } | 935 } |
1033 break; | 936 break; |
1034 } | |
1035 case CALLBACKS: { | 937 case CALLBACKS: { |
1036 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 938 Handle<Object> callback_object(lookup->GetCallbackObject()); |
1037 AccessorInfo* callback = | 939 if (!callback_object->IsAccessorInfo()) return; |
1038 AccessorInfo::cast(lookup->GetCallbackObject()); | 940 Handle<AccessorInfo> callback = |
| 941 Handle<AccessorInfo>::cast(callback_object); |
1039 if (v8::ToCData<Address>(callback->getter()) == 0) return; | 942 if (v8::ToCData<Address>(callback->getter()) == 0) return; |
1040 maybe_code = isolate()->stub_cache()->ComputeLoadCallback( | 943 code = isolate()->stub_cache()->ComputeLoadCallback( |
1041 *name, *receiver, lookup->holder(), callback); | 944 name, receiver, holder, callback); |
1042 break; | 945 break; |
1043 } | 946 } |
1044 case INTERCEPTOR: { | 947 case INTERCEPTOR: |
1045 ASSERT(HasInterceptorGetter(lookup->holder())); | 948 ASSERT(HasInterceptorGetter(*holder)); |
1046 maybe_code = isolate()->stub_cache()->ComputeLoadInterceptor( | 949 code = isolate()->stub_cache()->ComputeLoadInterceptor( |
1047 *name, *receiver, lookup->holder()); | 950 name, receiver, holder); |
1048 break; | 951 break; |
1049 } | |
1050 default: | 952 default: |
1051 return; | 953 return; |
1052 } | 954 } |
1053 } | 955 } |
1054 | 956 |
1055 // If we're unable to compute the stub (not enough memory left), we | |
1056 // simply avoid updating the caches. | |
1057 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | |
1058 | |
1059 // Patch the call site depending on the state of the cache. | 957 // Patch the call site depending on the state of the cache. |
1060 if (state == UNINITIALIZED || state == PREMONOMORPHIC || | 958 if (state == UNINITIALIZED || |
| 959 state == PREMONOMORPHIC || |
1061 state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 960 state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
1062 set_target(Code::cast(code)); | 961 set_target(*code); |
1063 } else if (state == MONOMORPHIC) { | 962 } else if (state == MONOMORPHIC) { |
1064 set_target(megamorphic_stub()); | 963 set_target(*megamorphic_stub()); |
1065 } else if (state == MEGAMORPHIC) { | 964 } else if (state == MEGAMORPHIC) { |
1066 // Cache code holding map should be consistent with | 965 // Cache code holding map should be consistent with |
1067 // GenerateMonomorphicCacheProbe. | 966 // GenerateMonomorphicCacheProbe. |
1068 Map* map = JSObject::cast(object->IsJSObject() ? *object : | 967 isolate()->stub_cache()->Set(*name, receiver->map(), *code); |
1069 object->GetPrototype())->map(); | |
1070 | |
1071 isolate()->stub_cache()->Set(*name, map, Code::cast(code)); | |
1072 } | 968 } |
1073 | 969 |
1074 #ifdef DEBUG | 970 TRACE_IC("LoadIC", name, state, target()); |
1075 TraceIC("LoadIC", name, state, target()); | |
1076 #endif | |
1077 } | 971 } |
1078 | 972 |
1079 | 973 |
1080 MaybeObject* KeyedLoadIC::GetElementStubWithoutMapCheck( | 974 Handle<Code> KeyedLoadIC::GetElementStubWithoutMapCheck( |
1081 bool is_js_array, | 975 bool is_js_array, |
1082 ElementsKind elements_kind) { | 976 ElementsKind elements_kind) { |
1083 return KeyedLoadElementStub(elements_kind).TryGetCode(); | 977 return KeyedLoadElementStub(elements_kind).GetCode(); |
1084 } | 978 } |
1085 | 979 |
1086 | 980 |
1087 MaybeObject* KeyedLoadIC::ComputePolymorphicStub( | 981 Handle<Code> KeyedLoadIC::ComputePolymorphicStub( |
1088 MapList* receiver_maps, | 982 MapHandleList* receiver_maps, |
1089 StrictModeFlag strict_mode) { | 983 StrictModeFlag strict_mode) { |
1090 CodeList handler_ics(receiver_maps->length()); | 984 CodeHandleList handler_ics(receiver_maps->length()); |
1091 for (int i = 0; i < receiver_maps->length(); ++i) { | 985 for (int i = 0; i < receiver_maps->length(); ++i) { |
1092 Map* receiver_map(receiver_maps->at(i)); | 986 Handle<Map> receiver_map = receiver_maps->at(i); |
1093 MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck( | 987 Handle<Code> cached_stub = ComputeMonomorphicStubWithoutMapCheck( |
1094 receiver_map, strict_mode); | 988 receiver_map, strict_mode); |
1095 Code* cached_stub; | |
1096 if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub; | |
1097 handler_ics.Add(cached_stub); | 989 handler_ics.Add(cached_stub); |
1098 } | 990 } |
1099 Object* object; | 991 KeyedLoadStubCompiler compiler(isolate()); |
1100 KeyedLoadStubCompiler compiler; | 992 Handle<Code> code = compiler.CompileLoadPolymorphic( |
1101 MaybeObject* maybe_code = compiler.CompileLoadPolymorphic(receiver_maps, | 993 receiver_maps, &handler_ics); |
1102 &handler_ics); | |
1103 if (!maybe_code->ToObject(&object)) return maybe_code; | |
1104 isolate()->counters()->keyed_load_polymorphic_stubs()->Increment(); | 994 isolate()->counters()->keyed_load_polymorphic_stubs()->Increment(); |
1105 PROFILE(isolate(), CodeCreateEvent( | 995 PROFILE(isolate(), |
1106 Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG, | 996 CodeCreateEvent(Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG, *code, 0)); |
1107 Code::cast(object), 0)); | 997 return code; |
1108 return object; | |
1109 } | 998 } |
1110 | 999 |
1111 | 1000 |
1112 MaybeObject* KeyedLoadIC::Load(State state, | 1001 MaybeObject* KeyedLoadIC::Load(State state, |
1113 Handle<Object> object, | 1002 Handle<Object> object, |
1114 Handle<Object> key, | 1003 Handle<Object> key, |
1115 bool force_generic_stub) { | 1004 bool force_generic_stub) { |
1116 // Check for values that can be converted into a symbol. | 1005 // Check for values that can be converted into a symbol. |
1117 // TODO(1295): Remove this code. | 1006 // TODO(1295): Remove this code. |
1118 HandleScope scope(isolate()); | |
1119 if (key->IsHeapNumber() && | 1007 if (key->IsHeapNumber() && |
1120 isnan(HeapNumber::cast(*key)->value())) { | 1008 isnan(Handle<HeapNumber>::cast(key)->value())) { |
1121 key = isolate()->factory()->nan_symbol(); | 1009 key = isolate()->factory()->nan_symbol(); |
1122 } else if (key->IsUndefined()) { | 1010 } else if (key->IsUndefined()) { |
1123 key = isolate()->factory()->undefined_symbol(); | 1011 key = isolate()->factory()->undefined_symbol(); |
1124 } | 1012 } |
1125 | 1013 |
1126 if (key->IsSymbol()) { | 1014 if (key->IsSymbol()) { |
1127 Handle<String> name = Handle<String>::cast(key); | 1015 Handle<String> name = Handle<String>::cast(key); |
1128 | 1016 |
1129 // If the object is undefined or null it's illegal to try to get any | 1017 // If the object is undefined or null it's illegal to try to get any |
1130 // of its properties; throw a TypeError in that case. | 1018 // of its properties; throw a TypeError in that case. |
1131 if (object->IsUndefined() || object->IsNull()) { | 1019 if (object->IsUndefined() || object->IsNull()) { |
1132 return TypeError("non_object_property_load", object, name); | 1020 return TypeError("non_object_property_load", object, name); |
1133 } | 1021 } |
1134 | 1022 |
1135 if (FLAG_use_ic) { | 1023 if (FLAG_use_ic) { |
1136 // TODO(1073): don't ignore the current stub state. | 1024 // TODO(1073): don't ignore the current stub state. |
1137 | 1025 |
1138 // Use specialized code for getting the length of strings. | 1026 // Use specialized code for getting the length of strings. |
1139 if (object->IsString() && | 1027 if (object->IsString() && |
1140 name->Equals(isolate()->heap()->length_symbol())) { | 1028 name->Equals(isolate()->heap()->length_symbol())) { |
1141 Handle<String> string = Handle<String>::cast(object); | 1029 Handle<String> string = Handle<String>::cast(object); |
1142 Object* code = NULL; | 1030 Handle<Code> code = |
1143 { MaybeObject* maybe_code = | 1031 isolate()->stub_cache()->ComputeKeyedLoadStringLength(name, string); |
1144 isolate()->stub_cache()->ComputeKeyedLoadStringLength(*name, | 1032 ASSERT(!code.is_null()); |
1145 *string); | 1033 set_target(*code); |
1146 if (!maybe_code->ToObject(&code)) return maybe_code; | 1034 TRACE_IC("KeyedLoadIC", name, state, target()); |
1147 } | |
1148 set_target(Code::cast(code)); | |
1149 #ifdef DEBUG | |
1150 TraceIC("KeyedLoadIC", name, state, target()); | |
1151 #endif // DEBUG | |
1152 return Smi::FromInt(string->length()); | 1035 return Smi::FromInt(string->length()); |
1153 } | 1036 } |
1154 | 1037 |
1155 // Use specialized code for getting the length of arrays. | 1038 // Use specialized code for getting the length of arrays. |
1156 if (object->IsJSArray() && | 1039 if (object->IsJSArray() && |
1157 name->Equals(isolate()->heap()->length_symbol())) { | 1040 name->Equals(isolate()->heap()->length_symbol())) { |
1158 Handle<JSArray> array = Handle<JSArray>::cast(object); | 1041 Handle<JSArray> array = Handle<JSArray>::cast(object); |
1159 Object* code; | 1042 Handle<Code> code = |
1160 { MaybeObject* maybe_code = | 1043 isolate()->stub_cache()->ComputeKeyedLoadArrayLength(name, array); |
1161 isolate()->stub_cache()->ComputeKeyedLoadArrayLength(*name, | 1044 ASSERT(!code.is_null()); |
1162 *array); | 1045 set_target(*code); |
1163 if (!maybe_code->ToObject(&code)) return maybe_code; | 1046 TRACE_IC("KeyedLoadIC", name, state, target()); |
1164 } | 1047 return array->length(); |
1165 set_target(Code::cast(code)); | |
1166 #ifdef DEBUG | |
1167 TraceIC("KeyedLoadIC", name, state, target()); | |
1168 #endif // DEBUG | |
1169 return JSArray::cast(*object)->length(); | |
1170 } | 1048 } |
1171 | 1049 |
1172 // Use specialized code for getting prototype of functions. | 1050 // Use specialized code for getting prototype of functions. |
1173 if (object->IsJSFunction() && | 1051 if (object->IsJSFunction() && |
1174 name->Equals(isolate()->heap()->prototype_symbol()) && | 1052 name->Equals(isolate()->heap()->prototype_symbol()) && |
1175 JSFunction::cast(*object)->should_have_prototype()) { | 1053 Handle<JSFunction>::cast(object)->should_have_prototype()) { |
1176 Handle<JSFunction> function = Handle<JSFunction>::cast(object); | 1054 Handle<JSFunction> function = Handle<JSFunction>::cast(object); |
1177 Object* code; | 1055 Handle<Code> code = |
1178 { MaybeObject* maybe_code = | 1056 isolate()->stub_cache()->ComputeKeyedLoadFunctionPrototype( |
1179 isolate()->stub_cache()->ComputeKeyedLoadFunctionPrototype( | 1057 name, function); |
1180 *name, *function); | 1058 ASSERT(!code.is_null()); |
1181 if (!maybe_code->ToObject(&code)) return maybe_code; | 1059 set_target(*code); |
1182 } | 1060 TRACE_IC("KeyedLoadIC", name, state, target()); |
1183 set_target(Code::cast(code)); | |
1184 #ifdef DEBUG | |
1185 TraceIC("KeyedLoadIC", name, state, target()); | |
1186 #endif // DEBUG | |
1187 return Accessors::FunctionGetPrototype(*object, 0); | 1061 return Accessors::FunctionGetPrototype(*object, 0); |
1188 } | 1062 } |
1189 } | 1063 } |
1190 | 1064 |
1191 // Check if the name is trivially convertible to an index and get | 1065 // Check if the name is trivially convertible to an index and get |
1192 // the element or char if so. | 1066 // the element or char if so. |
1193 uint32_t index = 0; | 1067 uint32_t index = 0; |
1194 if (name->AsArrayIndex(&index)) { | 1068 if (name->AsArrayIndex(&index)) { |
1195 HandleScope scope(isolate()); | |
1196 // Rewrite to the generic keyed load stub. | 1069 // Rewrite to the generic keyed load stub. |
1197 if (FLAG_use_ic) set_target(generic_stub()); | 1070 if (FLAG_use_ic) set_target(*generic_stub()); |
1198 return Runtime::GetElementOrCharAt(isolate(), object, index); | 1071 return Runtime::GetElementOrCharAt(isolate(), object, index); |
1199 } | 1072 } |
1200 | 1073 |
1201 // Named lookup. | 1074 // Named lookup. |
1202 LookupResult lookup; | 1075 LookupResult lookup(isolate()); |
1203 LookupForRead(*object, *name, &lookup); | 1076 LookupForRead(object, name, &lookup); |
1204 | 1077 |
1205 // If we did not find a property, check if we need to throw an exception. | 1078 // If we did not find a property, check if we need to throw an exception. |
1206 if (!lookup.IsProperty() && IsContextual(object)) { | 1079 if (!lookup.IsProperty() && IsContextual(object)) { |
1207 return ReferenceError("not_defined", name); | 1080 return ReferenceError("not_defined", name); |
1208 } | 1081 } |
1209 | 1082 |
1210 if (FLAG_use_ic) { | 1083 if (FLAG_use_ic) { |
1211 UpdateCaches(&lookup, state, object, name); | 1084 UpdateCaches(&lookup, state, object, name); |
1212 } | 1085 } |
1213 | 1086 |
1214 PropertyAttributes attr; | 1087 PropertyAttributes attr; |
1215 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) { | 1088 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) { |
1216 // Get the property. | 1089 // Get the property. |
1217 Object* result; | 1090 Handle<Object> result = |
1218 { MaybeObject* maybe_result = | 1091 Object::GetProperty(object, object, &lookup, name, &attr); |
1219 object->GetProperty(*object, &lookup, *name, &attr); | 1092 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
1220 if (!maybe_result->ToObject(&result)) return maybe_result; | |
1221 } | |
1222 // If the property is not present, check if we need to throw an | 1093 // If the property is not present, check if we need to throw an |
1223 // exception. | 1094 // exception. |
1224 if (attr == ABSENT && IsContextual(object)) { | 1095 if (attr == ABSENT && IsContextual(object)) { |
1225 return ReferenceError("not_defined", name); | 1096 return ReferenceError("not_defined", name); |
1226 } | 1097 } |
1227 return result; | 1098 return *result; |
1228 } | 1099 } |
1229 | 1100 |
1230 return object->GetProperty(*object, &lookup, *name, &attr); | 1101 return object->GetProperty(*object, &lookup, *name, &attr); |
1231 } | 1102 } |
1232 | 1103 |
1233 // Do not use ICs for objects that require access checks (including | 1104 // Do not use ICs for objects that require access checks (including |
1234 // the global object). | 1105 // the global object). |
1235 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1106 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
1236 | 1107 |
1237 if (use_ic) { | 1108 if (use_ic) { |
1238 Code* stub = generic_stub(); | 1109 Handle<Code> stub = generic_stub(); |
1239 if (!force_generic_stub) { | 1110 if (!force_generic_stub) { |
1240 if (object->IsString() && key->IsNumber()) { | 1111 if (object->IsString() && key->IsNumber()) { |
1241 if (state == UNINITIALIZED) { | 1112 if (state == UNINITIALIZED) { |
1242 stub = string_stub(); | 1113 stub = string_stub(); |
1243 } | 1114 } |
1244 } else if (object->IsJSObject()) { | 1115 } else if (object->IsJSObject()) { |
1245 JSObject* receiver = JSObject::cast(*object); | 1116 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1246 Heap* heap = Handle<JSObject>::cast(object)->GetHeap(); | 1117 if (receiver->elements()->map() == |
1247 Map* elements_map = Handle<JSObject>::cast(object)->elements()->map(); | 1118 isolate()->heap()->non_strict_arguments_elements_map()) { |
1248 if (elements_map == heap->non_strict_arguments_elements_map()) { | |
1249 stub = non_strict_arguments_stub(); | 1119 stub = non_strict_arguments_stub(); |
1250 } else if (receiver->HasIndexedInterceptor()) { | 1120 } else if (receiver->HasIndexedInterceptor()) { |
1251 stub = indexed_interceptor_stub(); | 1121 stub = indexed_interceptor_stub(); |
1252 } else if (key->IsSmi() && (target() != non_strict_arguments_stub())) { | 1122 } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { |
1253 MaybeObject* maybe_stub = ComputeStub(receiver, | 1123 stub = ComputeStub(receiver, LOAD, kNonStrictMode, stub); |
1254 LOAD, | |
1255 kNonStrictMode, | |
1256 stub); | |
1257 stub = maybe_stub->IsFailure() ? | |
1258 NULL : Code::cast(maybe_stub->ToObjectUnchecked()); | |
1259 } | 1124 } |
1260 } | 1125 } |
1261 } | 1126 } |
1262 if (stub != NULL) set_target(stub); | 1127 if (!stub.is_null()) set_target(*stub); |
1263 } | 1128 } |
1264 | 1129 |
1265 #ifdef DEBUG | 1130 TRACE_IC("KeyedLoadIC", key, state, target()); |
1266 TraceIC("KeyedLoadIC", key, state, target()); | |
1267 #endif // DEBUG | |
1268 | 1131 |
1269 // Get the property. | 1132 // Get the property. |
1270 return Runtime::GetObjectProperty(isolate(), object, key); | 1133 return Runtime::GetObjectProperty(isolate(), object, key); |
1271 } | 1134 } |
1272 | 1135 |
1273 | 1136 |
1274 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, | 1137 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, |
1275 Handle<Object> object, Handle<String> name) { | 1138 State state, |
| 1139 Handle<Object> object, |
| 1140 Handle<String> name) { |
1276 // Bail out if we didn't find a result. | 1141 // Bail out if we didn't find a result. |
1277 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 1142 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
1278 | 1143 |
1279 if (!object->IsJSObject()) return; | 1144 if (!object->IsJSObject()) return; |
1280 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1145 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1281 | 1146 |
1282 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; | 1147 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; |
1283 | 1148 |
1284 // Compute the code stub for this load. | 1149 // Compute the code stub for this load. |
1285 MaybeObject* maybe_code = NULL; | 1150 Handle<Code> code; |
1286 Object* code; | |
1287 | 1151 |
1288 if (state == UNINITIALIZED) { | 1152 if (state == UNINITIALIZED) { |
1289 // This is the first time we execute this inline cache. | 1153 // This is the first time we execute this inline cache. |
1290 // Set the target to the pre monomorphic stub to delay | 1154 // Set the target to the pre monomorphic stub to delay |
1291 // setting the monomorphic state. | 1155 // setting the monomorphic state. |
1292 maybe_code = pre_monomorphic_stub(); | 1156 code = pre_monomorphic_stub(); |
1293 } else { | 1157 } else { |
1294 // Compute a monomorphic stub. | 1158 // Compute a monomorphic stub. |
| 1159 Handle<JSObject> holder(lookup->holder()); |
1295 switch (lookup->type()) { | 1160 switch (lookup->type()) { |
1296 case FIELD: { | 1161 case FIELD: |
1297 maybe_code = isolate()->stub_cache()->ComputeKeyedLoadField( | 1162 code = isolate()->stub_cache()->ComputeKeyedLoadField( |
1298 *name, *receiver, lookup->holder(), lookup->GetFieldIndex()); | 1163 name, receiver, holder, lookup->GetFieldIndex()); |
1299 break; | 1164 break; |
1300 } | |
1301 case CONSTANT_FUNCTION: { | 1165 case CONSTANT_FUNCTION: { |
1302 Object* constant = lookup->GetConstantFunction(); | 1166 Handle<Object> constant(lookup->GetConstantFunction()); |
1303 maybe_code = isolate()->stub_cache()->ComputeKeyedLoadConstant( | 1167 code = isolate()->stub_cache()->ComputeKeyedLoadConstant( |
1304 *name, *receiver, lookup->holder(), constant); | 1168 name, receiver, holder, constant); |
1305 break; | 1169 break; |
1306 } | 1170 } |
1307 case CALLBACKS: { | 1171 case CALLBACKS: { |
1308 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 1172 Handle<Object> callback_object(lookup->GetCallbackObject()); |
1309 AccessorInfo* callback = | 1173 if (!callback_object->IsAccessorInfo()) return; |
1310 AccessorInfo::cast(lookup->GetCallbackObject()); | 1174 Handle<AccessorInfo> callback = |
| 1175 Handle<AccessorInfo>::cast(callback_object); |
1311 if (v8::ToCData<Address>(callback->getter()) == 0) return; | 1176 if (v8::ToCData<Address>(callback->getter()) == 0) return; |
1312 maybe_code = isolate()->stub_cache()->ComputeKeyedLoadCallback( | 1177 code = isolate()->stub_cache()->ComputeKeyedLoadCallback( |
1313 *name, *receiver, lookup->holder(), callback); | 1178 name, receiver, holder, callback); |
1314 break; | 1179 break; |
1315 } | 1180 } |
1316 case INTERCEPTOR: { | 1181 case INTERCEPTOR: |
1317 ASSERT(HasInterceptorGetter(lookup->holder())); | 1182 ASSERT(HasInterceptorGetter(lookup->holder())); |
1318 maybe_code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor( | 1183 code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor( |
1319 *name, *receiver, lookup->holder()); | 1184 name, receiver, holder); |
1320 break; | 1185 break; |
1321 } | 1186 default: |
1322 default: { | |
1323 // Always rewrite to the generic case so that we do not | 1187 // Always rewrite to the generic case so that we do not |
1324 // repeatedly try to rewrite. | 1188 // repeatedly try to rewrite. |
1325 maybe_code = generic_stub(); | 1189 code = generic_stub(); |
1326 break; | 1190 break; |
1327 } | |
1328 } | 1191 } |
1329 } | 1192 } |
1330 | 1193 |
1331 // If we're unable to compute the stub (not enough memory left), we | |
1332 // simply avoid updating the caches. | |
1333 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | |
1334 | |
1335 // Patch the call site depending on the state of the cache. Make | 1194 // Patch the call site depending on the state of the cache. Make |
1336 // sure to always rewrite from monomorphic to megamorphic. | 1195 // sure to always rewrite from monomorphic to megamorphic. |
1337 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); | 1196 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); |
1338 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { | 1197 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { |
1339 set_target(Code::cast(code)); | 1198 set_target(*code); |
1340 } else if (state == MONOMORPHIC) { | 1199 } else if (state == MONOMORPHIC) { |
1341 set_target(megamorphic_stub()); | 1200 set_target(*megamorphic_stub()); |
1342 } | 1201 } |
1343 | 1202 |
1344 #ifdef DEBUG | 1203 TRACE_IC("KeyedLoadIC", name, state, target()); |
1345 TraceIC("KeyedLoadIC", name, state, target()); | |
1346 #endif | |
1347 } | 1204 } |
1348 | 1205 |
1349 | 1206 |
1350 static bool StoreICableLookup(LookupResult* lookup) { | 1207 static bool StoreICableLookup(LookupResult* lookup) { |
1351 // Bail out if we didn't find a result. | 1208 // Bail out if we didn't find a result. |
1352 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return false; | 1209 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return false; |
1353 | 1210 |
1354 // If the property is read-only, we leave the IC in its current | 1211 // If the property is read-only, we leave the IC in its current |
1355 // state. | 1212 // state. |
1356 if (lookup->IsReadOnly()) return false; | 1213 if (lookup->IsReadOnly()) return false; |
1357 | 1214 |
1358 return true; | 1215 return true; |
1359 } | 1216 } |
1360 | 1217 |
1361 | 1218 |
1362 static bool LookupForWrite(JSObject* receiver, | 1219 static bool LookupForWrite(Handle<JSObject> receiver, |
1363 String* name, | 1220 Handle<String> name, |
1364 LookupResult* lookup) { | 1221 LookupResult* lookup) { |
1365 receiver->LocalLookup(name, lookup); | 1222 receiver->LocalLookup(*name, lookup); |
1366 if (!StoreICableLookup(lookup)) { | 1223 if (!StoreICableLookup(lookup)) { |
1367 return false; | 1224 return false; |
1368 } | 1225 } |
1369 | 1226 |
1370 if (lookup->type() == INTERCEPTOR && | 1227 if (lookup->type() == INTERCEPTOR && |
1371 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { | 1228 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { |
1372 receiver->LocalLookupRealNamedProperty(name, lookup); | 1229 receiver->LocalLookupRealNamedProperty(*name, lookup); |
1373 return StoreICableLookup(lookup); | 1230 return StoreICableLookup(lookup); |
1374 } | 1231 } |
1375 | 1232 |
1376 return true; | 1233 return true; |
1377 } | 1234 } |
1378 | 1235 |
1379 | 1236 |
1380 MaybeObject* StoreIC::Store(State state, | 1237 MaybeObject* StoreIC::Store(State state, |
1381 StrictModeFlag strict_mode, | 1238 StrictModeFlag strict_mode, |
1382 Handle<Object> object, | 1239 Handle<Object> object, |
(...skipping 11 matching lines...) Expand all Loading... |
1394 if (object->IsUndefined() || object->IsNull()) { | 1251 if (object->IsUndefined() || object->IsNull()) { |
1395 return TypeError("non_object_property_store", object, name); | 1252 return TypeError("non_object_property_store", object, name); |
1396 } | 1253 } |
1397 | 1254 |
1398 // The length property of string values is read-only. Throw in strict mode. | 1255 // The length property of string values is read-only. Throw in strict mode. |
1399 if (strict_mode == kStrictMode && object->IsString() && | 1256 if (strict_mode == kStrictMode && object->IsString() && |
1400 name->Equals(isolate()->heap()->length_symbol())) { | 1257 name->Equals(isolate()->heap()->length_symbol())) { |
1401 return TypeError("strict_read_only_property", object, name); | 1258 return TypeError("strict_read_only_property", object, name); |
1402 } | 1259 } |
1403 // Ignore other stores where the receiver is not a JSObject. | 1260 // Ignore other stores where the receiver is not a JSObject. |
| 1261 // TODO(1475): Must check prototype chains of object wrappers. |
1404 return *value; | 1262 return *value; |
1405 } | 1263 } |
1406 | 1264 |
1407 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1265 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1408 | 1266 |
1409 // Check if the given name is an array index. | 1267 // Check if the given name is an array index. |
1410 uint32_t index; | 1268 uint32_t index; |
1411 if (name->AsArrayIndex(&index)) { | 1269 if (name->AsArrayIndex(&index)) { |
1412 HandleScope scope(isolate()); | |
1413 Handle<Object> result = SetElement(receiver, index, value, strict_mode); | 1270 Handle<Object> result = SetElement(receiver, index, value, strict_mode); |
1414 if (result.is_null()) return Failure::Exception(); | 1271 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
1415 return *value; | 1272 return *value; |
1416 } | 1273 } |
1417 | 1274 |
1418 // Use specialized code for setting the length of arrays. | 1275 // Use specialized code for setting the length of arrays. |
1419 if (receiver->IsJSArray() | 1276 if (receiver->IsJSArray() |
1420 && name->Equals(isolate()->heap()->length_symbol()) | 1277 && name->Equals(isolate()->heap()->length_symbol()) |
1421 && JSArray::cast(*receiver)->AllowsSetElementsLength()) { | 1278 && Handle<JSArray>::cast(receiver)->AllowsSetElementsLength()) { |
1422 #ifdef DEBUG | 1279 #ifdef DEBUG |
1423 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); | 1280 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); |
1424 #endif | 1281 #endif |
1425 Builtins::Name target = (strict_mode == kStrictMode) | 1282 Handle<Code> stub = (strict_mode == kStrictMode) |
1426 ? Builtins::kStoreIC_ArrayLength_Strict | 1283 ? isolate()->builtins()->StoreIC_ArrayLength_Strict() |
1427 : Builtins::kStoreIC_ArrayLength; | 1284 : isolate()->builtins()->StoreIC_ArrayLength(); |
1428 set_target(isolate()->builtins()->builtin(target)); | 1285 set_target(*stub); |
1429 return receiver->SetProperty(*name, *value, NONE, strict_mode); | 1286 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
1430 } | 1287 } |
1431 | 1288 |
1432 // Lookup the property locally in the receiver. | 1289 // Lookup the property locally in the receiver. |
1433 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { | 1290 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { |
1434 LookupResult lookup; | 1291 LookupResult lookup(isolate()); |
1435 | 1292 |
1436 if (LookupForWrite(*receiver, *name, &lookup)) { | 1293 if (LookupForWrite(receiver, name, &lookup)) { |
1437 // Generate a stub for this store. | 1294 // Generate a stub for this store. |
1438 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); | 1295 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
1439 } else { | 1296 } else { |
1440 // Strict mode doesn't allow setting non-existent global property | 1297 // Strict mode doesn't allow setting non-existent global property |
1441 // or an assignment to a read only property. | 1298 // or an assignment to a read only property. |
1442 if (strict_mode == kStrictMode) { | 1299 if (strict_mode == kStrictMode) { |
1443 if (lookup.IsFound() && lookup.IsReadOnly()) { | 1300 if (lookup.IsFound() && lookup.IsReadOnly()) { |
1444 return TypeError("strict_read_only_property", object, name); | 1301 return TypeError("strict_read_only_property", object, name); |
1445 } else if (IsContextual(object)) { | 1302 } else if (IsContextual(object)) { |
1446 return ReferenceError("not_defined", name); | 1303 return ReferenceError("not_defined", name); |
1447 } | 1304 } |
1448 } | 1305 } |
1449 } | 1306 } |
1450 } | 1307 } |
1451 | 1308 |
1452 if (receiver->IsJSGlobalProxy()) { | 1309 if (receiver->IsJSGlobalProxy()) { |
| 1310 // TODO(ulan): find out why we patch this site even with --no-use-ic |
1453 // Generate a generic stub that goes to the runtime when we see a global | 1311 // Generate a generic stub that goes to the runtime when we see a global |
1454 // proxy as receiver. | 1312 // proxy as receiver. |
1455 Code* stub = (strict_mode == kStrictMode) | 1313 Handle<Code> stub = (strict_mode == kStrictMode) |
1456 ? global_proxy_stub_strict() | 1314 ? global_proxy_stub_strict() |
1457 : global_proxy_stub(); | 1315 : global_proxy_stub(); |
1458 if (target() != stub) { | 1316 if (target() != *stub) { |
1459 set_target(stub); | 1317 set_target(*stub); |
1460 #ifdef DEBUG | 1318 TRACE_IC("StoreIC", name, state, target()); |
1461 TraceIC("StoreIC", name, state, target()); | |
1462 #endif | |
1463 } | 1319 } |
1464 } | 1320 } |
1465 | 1321 |
1466 // Set the property. | 1322 // Set the property. |
1467 return receiver->SetProperty(*name, *value, NONE, strict_mode); | 1323 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
1468 } | 1324 } |
1469 | 1325 |
1470 | 1326 |
1471 void StoreIC::UpdateCaches(LookupResult* lookup, | 1327 void StoreIC::UpdateCaches(LookupResult* lookup, |
1472 State state, | 1328 State state, |
1473 StrictModeFlag strict_mode, | 1329 StrictModeFlag strict_mode, |
1474 Handle<JSObject> receiver, | 1330 Handle<JSObject> receiver, |
1475 Handle<String> name, | 1331 Handle<String> name, |
1476 Handle<Object> value) { | 1332 Handle<Object> value) { |
1477 // Skip JSGlobalProxy. | 1333 // Skip JSGlobalProxy. |
1478 ASSERT(!receiver->IsJSGlobalProxy()); | 1334 ASSERT(!receiver->IsJSGlobalProxy()); |
1479 | 1335 |
1480 ASSERT(StoreICableLookup(lookup)); | 1336 ASSERT(StoreICableLookup(lookup)); |
1481 | 1337 |
1482 // If the property has a non-field type allowing map transitions | 1338 // If the property has a non-field type allowing map transitions |
1483 // where there is extra room in the object, we leave the IC in its | 1339 // where there is extra room in the object, we leave the IC in its |
1484 // current state. | 1340 // current state. |
1485 PropertyType type = lookup->type(); | 1341 PropertyType type = lookup->type(); |
1486 | 1342 |
1487 // Compute the code stub for this store; used for rewriting to | 1343 // Compute the code stub for this store; used for rewriting to |
1488 // monomorphic state and making sure that the code stub is in the | 1344 // monomorphic state and making sure that the code stub is in the |
1489 // stub cache. | 1345 // stub cache. |
1490 MaybeObject* maybe_code = NULL; | 1346 Handle<Code> code; |
1491 Object* code = NULL; | |
1492 switch (type) { | 1347 switch (type) { |
1493 case FIELD: { | 1348 case FIELD: |
1494 maybe_code = isolate()->stub_cache()->ComputeStoreField( | 1349 code = isolate()->stub_cache()->ComputeStoreField(name, |
1495 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); | 1350 receiver, |
| 1351 lookup->GetFieldIndex(), |
| 1352 Handle<Map>::null(), |
| 1353 strict_mode); |
1496 break; | 1354 break; |
1497 } | |
1498 case MAP_TRANSITION: { | 1355 case MAP_TRANSITION: { |
1499 if (lookup->GetAttributes() != NONE) return; | 1356 if (lookup->GetAttributes() != NONE) return; |
1500 HandleScope scope(isolate()); | |
1501 ASSERT(type == MAP_TRANSITION); | 1357 ASSERT(type == MAP_TRANSITION); |
1502 Handle<Map> transition(lookup->GetTransitionMap()); | 1358 Handle<Map> transition(lookup->GetTransitionMap()); |
1503 int index = transition->PropertyIndexFor(*name); | 1359 int index = transition->PropertyIndexFor(*name); |
1504 maybe_code = isolate()->stub_cache()->ComputeStoreField( | 1360 code = isolate()->stub_cache()->ComputeStoreField( |
1505 *name, *receiver, index, *transition, strict_mode); | 1361 name, receiver, index, transition, strict_mode); |
1506 break; | 1362 break; |
1507 } | 1363 } |
1508 case NORMAL: { | 1364 case NORMAL: |
1509 if (receiver->IsGlobalObject()) { | 1365 if (receiver->IsGlobalObject()) { |
1510 // The stub generated for the global object picks the value directly | 1366 // The stub generated for the global object picks the value directly |
1511 // from the property cell. So the property must be directly on the | 1367 // from the property cell. So the property must be directly on the |
1512 // global object. | 1368 // global object. |
1513 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1369 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
1514 JSGlobalPropertyCell* cell = | 1370 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); |
1515 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | 1371 code = isolate()->stub_cache()->ComputeStoreGlobal( |
1516 maybe_code = isolate()->stub_cache()->ComputeStoreGlobal( | 1372 name, global, cell, strict_mode); |
1517 *name, *global, cell, strict_mode); | |
1518 } else { | 1373 } else { |
1519 if (lookup->holder() != *receiver) return; | 1374 if (lookup->holder() != *receiver) return; |
1520 maybe_code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode); | 1375 code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode); |
1521 } | 1376 } |
1522 break; | 1377 break; |
1523 } | |
1524 case CALLBACKS: { | 1378 case CALLBACKS: { |
1525 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 1379 Handle<Object> callback_object(lookup->GetCallbackObject()); |
1526 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1380 if (!callback_object->IsAccessorInfo()) return; |
| 1381 Handle<AccessorInfo> callback = |
| 1382 Handle<AccessorInfo>::cast(callback_object); |
1527 if (v8::ToCData<Address>(callback->setter()) == 0) return; | 1383 if (v8::ToCData<Address>(callback->setter()) == 0) return; |
1528 maybe_code = isolate()->stub_cache()->ComputeStoreCallback( | 1384 code = isolate()->stub_cache()->ComputeStoreCallback( |
1529 *name, *receiver, callback, strict_mode); | 1385 name, receiver, callback, strict_mode); |
1530 break; | 1386 break; |
1531 } | 1387 } |
1532 case INTERCEPTOR: { | 1388 case INTERCEPTOR: |
1533 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); | 1389 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); |
1534 maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor( | 1390 code = isolate()->stub_cache()->ComputeStoreInterceptor( |
1535 *name, *receiver, strict_mode); | 1391 name, receiver, strict_mode); |
1536 break; | 1392 break; |
1537 } | |
1538 default: | 1393 default: |
1539 return; | 1394 return; |
1540 } | 1395 } |
1541 | 1396 |
1542 // If we're unable to compute the stub (not enough memory left), we | |
1543 // simply avoid updating the caches. | |
1544 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | |
1545 | |
1546 // Patch the call site depending on the state of the cache. | 1397 // Patch the call site depending on the state of the cache. |
1547 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 1398 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
1548 set_target(Code::cast(code)); | 1399 set_target(*code); |
1549 } else if (state == MONOMORPHIC) { | 1400 } else if (state == MONOMORPHIC) { |
1550 // Only move to megamorphic if the target changes. | 1401 // Only move to megamorphic if the target changes. |
1551 if (target() != Code::cast(code)) { | 1402 if (target() != *code) { |
1552 set_target((strict_mode == kStrictMode) | 1403 set_target((strict_mode == kStrictMode) |
1553 ? megamorphic_stub_strict() | 1404 ? megamorphic_stub_strict() |
1554 : megamorphic_stub()); | 1405 : megamorphic_stub()); |
1555 } | 1406 } |
1556 } else if (state == MEGAMORPHIC) { | 1407 } else if (state == MEGAMORPHIC) { |
1557 // Update the stub cache. | 1408 // Update the stub cache. |
1558 isolate()->stub_cache()->Set(*name, | 1409 isolate()->stub_cache()->Set(*name, receiver->map(), *code); |
1559 receiver->map(), | |
1560 Code::cast(code)); | |
1561 } | 1410 } |
1562 | 1411 |
1563 #ifdef DEBUG | 1412 TRACE_IC("StoreIC", name, state, target()); |
1564 TraceIC("StoreIC", name, state, target()); | |
1565 #endif | |
1566 } | 1413 } |
1567 | 1414 |
1568 | 1415 |
1569 static bool AddOneReceiverMapIfMissing(MapList* receiver_maps, | 1416 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, |
1570 Map* new_receiver_map) { | 1417 Handle<Map> new_receiver_map) { |
| 1418 ASSERT(!new_receiver_map.is_null()); |
1571 for (int current = 0; current < receiver_maps->length(); ++current) { | 1419 for (int current = 0; current < receiver_maps->length(); ++current) { |
1572 if (receiver_maps->at(current) == new_receiver_map) { | 1420 if (!receiver_maps->at(current).is_null() && |
| 1421 receiver_maps->at(current).is_identical_to(new_receiver_map)) { |
1573 return false; | 1422 return false; |
1574 } | 1423 } |
1575 } | 1424 } |
1576 receiver_maps->Add(new_receiver_map); | 1425 receiver_maps->Add(new_receiver_map); |
1577 return true; | 1426 return true; |
1578 } | 1427 } |
1579 | 1428 |
1580 | 1429 |
1581 void KeyedIC::GetReceiverMapsForStub(Code* stub, MapList* result) { | 1430 void KeyedIC::GetReceiverMapsForStub(Handle<Code> stub, |
| 1431 MapHandleList* result) { |
1582 ASSERT(stub->is_inline_cache_stub()); | 1432 ASSERT(stub->is_inline_cache_stub()); |
1583 if (stub == string_stub()) { | 1433 if (!string_stub().is_null() && stub.is_identical_to(string_stub())) { |
1584 return result->Add(isolate()->heap()->string_map()); | 1434 return result->Add(isolate()->factory()->string_map()); |
1585 } else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) { | 1435 } else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) { |
1586 if (stub->ic_state() == MONOMORPHIC) { | 1436 if (stub->ic_state() == MONOMORPHIC) { |
1587 result->Add(Map::cast(stub->FindFirstMap())); | 1437 result->Add(Handle<Map>(stub->FindFirstMap())); |
1588 } else { | 1438 } else { |
1589 ASSERT(stub->ic_state() == MEGAMORPHIC); | 1439 ASSERT(stub->ic_state() == MEGAMORPHIC); |
1590 AssertNoAllocation no_allocation; | 1440 AssertNoAllocation no_allocation; |
1591 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); | 1441 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); |
1592 for (RelocIterator it(stub, mask); !it.done(); it.next()) { | 1442 for (RelocIterator it(*stub, mask); !it.done(); it.next()) { |
1593 RelocInfo* info = it.rinfo(); | 1443 RelocInfo* info = it.rinfo(); |
1594 Object* object = info->target_object(); | 1444 Handle<Object> object(info->target_object()); |
1595 ASSERT(object->IsMap()); | 1445 ASSERT(object->IsMap()); |
1596 result->Add(Map::cast(object)); | 1446 AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object)); |
1597 } | 1447 } |
1598 } | 1448 } |
1599 } | 1449 } |
1600 } | 1450 } |
1601 | 1451 |
1602 | 1452 |
1603 MaybeObject* KeyedIC::ComputeStub(JSObject* receiver, | 1453 Handle<Code> KeyedIC::ComputeStub(Handle<JSObject> receiver, |
1604 StubKind stub_kind, | 1454 StubKind stub_kind, |
1605 StrictModeFlag strict_mode, | 1455 StrictModeFlag strict_mode, |
1606 Code* generic_stub) { | 1456 Handle<Code> generic_stub) { |
1607 State ic_state = target()->ic_state(); | 1457 State ic_state = target()->ic_state(); |
1608 if ((ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) && | 1458 if ((ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) && |
1609 !IsTransitionStubKind(stub_kind)) { | 1459 !IsTransitionStubKind(stub_kind)) { |
1610 Code* monomorphic_stub; | 1460 return ComputeMonomorphicStub( |
1611 MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver, | 1461 receiver, stub_kind, strict_mode, generic_stub); |
1612 stub_kind, | |
1613 strict_mode, | |
1614 generic_stub); | |
1615 if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub; | |
1616 | |
1617 return monomorphic_stub; | |
1618 } | 1462 } |
1619 ASSERT(target() != generic_stub); | 1463 ASSERT(target() != *generic_stub); |
1620 | 1464 |
1621 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 1465 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
1622 // via megamorphic stubs, since they don't have a map in their relocation info | 1466 // via megamorphic stubs, since they don't have a map in their relocation info |
1623 // and so the stubs can't be harvested for the object needed for a map check. | 1467 // and so the stubs can't be harvested for the object needed for a map check. |
1624 if (target()->type() != NORMAL) { | 1468 if (target()->type() != NORMAL) { |
1625 return generic_stub; | 1469 return generic_stub; |
1626 } | 1470 } |
1627 | 1471 |
1628 // Determine the list of receiver maps that this call site has seen, | 1472 // Determine the list of receiver maps that this call site has seen, |
1629 // adding the map that was just encountered. | 1473 // adding the map that was just encountered. |
1630 MapList target_receiver_maps; | 1474 MapHandleList target_receiver_maps; |
| 1475 Handle<Map> receiver_map(receiver->map()); |
1631 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { | 1476 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { |
1632 target_receiver_maps.Add(receiver->map()); | 1477 target_receiver_maps.Add(receiver_map); |
1633 } else { | 1478 } else { |
1634 GetReceiverMapsForStub(target(), &target_receiver_maps); | 1479 GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps); |
1635 } | 1480 } |
1636 bool map_added = | 1481 bool map_added = |
1637 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map()); | 1482 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); |
1638 if (IsTransitionStubKind(stub_kind)) { | 1483 if (IsTransitionStubKind(stub_kind)) { |
1639 MaybeObject* maybe_map = ComputeTransitionedMap(receiver, stub_kind); | 1484 Handle<Map> new_map = ComputeTransitionedMap(receiver, stub_kind); |
1640 Map* new_map = NULL; | |
1641 if (!maybe_map->To(&new_map)) return maybe_map; | |
1642 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map); | 1485 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map); |
1643 } | 1486 } |
1644 if (!map_added) { | 1487 if (!map_added) { |
1645 // If the miss wasn't due to an unseen map, a polymorphic stub | 1488 // If the miss wasn't due to an unseen map, a polymorphic stub |
1646 // won't help, use the generic stub. | 1489 // won't help, use the generic stub. |
1647 return generic_stub; | 1490 return generic_stub; |
1648 } | 1491 } |
1649 | 1492 |
1650 // If the maximum number of receiver maps has been exceeded, use the generic | 1493 // If the maximum number of receiver maps has been exceeded, use the generic |
1651 // version of the IC. | 1494 // version of the IC. |
1652 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { | 1495 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { |
1653 return generic_stub; | 1496 return generic_stub; |
1654 } | 1497 } |
1655 | 1498 |
1656 PolymorphicCodeCache* cache = isolate()->heap()->polymorphic_code_cache(); | 1499 Handle<PolymorphicCodeCache> cache = |
1657 Code::Flags flags = Code::ComputeFlags(this->kind(), | 1500 isolate()->factory()->polymorphic_code_cache(); |
1658 MEGAMORPHIC, | 1501 Code::Flags flags = Code::ComputeFlags(kind(), MEGAMORPHIC, strict_mode); |
1659 strict_mode); | 1502 Handle<Object> probe = cache->Lookup(&target_receiver_maps, flags); |
1660 Object* maybe_cached_stub = cache->Lookup(&target_receiver_maps, flags); | 1503 if (probe->IsCode()) return Handle<Code>::cast(probe); |
1661 // If there is a cached stub, use it. | 1504 |
1662 if (!maybe_cached_stub->IsUndefined()) { | 1505 Handle<Code> stub = |
1663 ASSERT(maybe_cached_stub->IsCode()); | |
1664 return Code::cast(maybe_cached_stub); | |
1665 } | |
1666 MaybeObject* maybe_stub = | |
1667 ComputePolymorphicStub(&target_receiver_maps, strict_mode); | 1506 ComputePolymorphicStub(&target_receiver_maps, strict_mode); |
1668 Code* stub; | 1507 PolymorphicCodeCache::Update(cache, &target_receiver_maps, flags, stub); |
1669 if (!maybe_stub->To(&stub)) return maybe_stub; | |
1670 MaybeObject* maybe_update = cache->Update(&target_receiver_maps, flags, stub); | |
1671 if (maybe_update->IsFailure()) return maybe_update; | |
1672 return stub; | 1508 return stub; |
1673 } | 1509 } |
1674 | 1510 |
1675 | 1511 |
1676 MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck( | 1512 Handle<Code> KeyedIC::ComputeMonomorphicStubWithoutMapCheck( |
1677 Map* receiver_map, | 1513 Handle<Map> receiver_map, |
1678 StrictModeFlag strict_mode) { | 1514 StrictModeFlag strict_mode) { |
1679 if ((receiver_map->instance_type() & kNotStringTag) == 0) { | 1515 if ((receiver_map->instance_type() & kNotStringTag) == 0) { |
1680 ASSERT(string_stub() != NULL); | 1516 ASSERT(!string_stub().is_null()); |
1681 return string_stub(); | 1517 return string_stub(); |
1682 } else { | 1518 } else { |
1683 ASSERT(receiver_map->has_dictionary_elements() || | 1519 ASSERT(receiver_map->has_dictionary_elements() || |
1684 receiver_map->has_fast_elements() || | 1520 receiver_map->has_fast_elements() || |
1685 receiver_map->has_fast_smi_only_elements() || | 1521 receiver_map->has_fast_smi_only_elements() || |
1686 receiver_map->has_fast_double_elements() || | 1522 receiver_map->has_fast_double_elements() || |
1687 receiver_map->has_external_array_elements()); | 1523 receiver_map->has_external_array_elements()); |
1688 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; | 1524 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; |
1689 return GetElementStubWithoutMapCheck(is_js_array, | 1525 return GetElementStubWithoutMapCheck(is_js_array, |
1690 receiver_map->elements_kind()); | 1526 receiver_map->elements_kind()); |
1691 } | 1527 } |
1692 } | 1528 } |
1693 | 1529 |
1694 | 1530 |
1695 MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver, | 1531 Handle<Code> KeyedIC::ComputeMonomorphicStub(Handle<JSObject> receiver, |
1696 StubKind stub_kind, | 1532 StubKind stub_kind, |
1697 StrictModeFlag strict_mode, | 1533 StrictModeFlag strict_mode, |
1698 Code* generic_stub) { | 1534 Handle<Code> generic_stub) { |
1699 Code* result = NULL; | |
1700 if (receiver->HasFastElements() || | 1535 if (receiver->HasFastElements() || |
1701 receiver->HasFastSmiOnlyElements() || | 1536 receiver->HasFastSmiOnlyElements() || |
1702 receiver->HasExternalArrayElements() || | 1537 receiver->HasExternalArrayElements() || |
1703 receiver->HasFastDoubleElements() || | 1538 receiver->HasFastDoubleElements() || |
1704 receiver->HasDictionaryElements()) { | 1539 receiver->HasDictionaryElements()) { |
1705 MaybeObject* maybe_stub = | 1540 return isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement( |
1706 isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement( | 1541 receiver, stub_kind, strict_mode); |
1707 receiver, stub_kind, strict_mode); | |
1708 if (!maybe_stub->To(&result)) return maybe_stub; | |
1709 } else { | 1542 } else { |
1710 result = generic_stub; | 1543 return generic_stub; |
1711 } | |
1712 return result; | |
1713 } | |
1714 | |
1715 | |
1716 MaybeObject* KeyedIC::ComputeTransitionedMap(JSObject* receiver, | |
1717 StubKind stub_kind) { | |
1718 switch (stub_kind) { | |
1719 case KeyedIC::STORE_TRANSITION_SMI_TO_OBJECT: | |
1720 case KeyedIC::STORE_TRANSITION_DOUBLE_TO_OBJECT: | |
1721 return receiver->GetElementsTransitionMap(FAST_ELEMENTS); | |
1722 case KeyedIC::STORE_TRANSITION_SMI_TO_DOUBLE: | |
1723 return receiver->GetElementsTransitionMap(FAST_DOUBLE_ELEMENTS); | |
1724 default: | |
1725 UNREACHABLE(); | |
1726 return NULL; | |
1727 } | 1544 } |
1728 } | 1545 } |
1729 | 1546 |
1730 | 1547 |
1731 MaybeObject* KeyedStoreIC::GetElementStubWithoutMapCheck( | 1548 Handle<Map> KeyedIC::ComputeTransitionedMap(Handle<JSObject> receiver, |
1732 bool is_js_array, | 1549 StubKind stub_kind) { |
1733 ElementsKind elements_kind) { | 1550 switch (stub_kind) { |
1734 return KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode(); | 1551 case KeyedIC::STORE_TRANSITION_SMI_TO_OBJECT: |
| 1552 case KeyedIC::STORE_TRANSITION_DOUBLE_TO_OBJECT: |
| 1553 return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS); |
| 1554 break; |
| 1555 case KeyedIC::STORE_TRANSITION_SMI_TO_DOUBLE: |
| 1556 return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS); |
| 1557 break; |
| 1558 default: |
| 1559 UNREACHABLE(); |
| 1560 return Handle<Map>::null(); |
| 1561 } |
1735 } | 1562 } |
1736 | 1563 |
1737 | 1564 |
1738 // If |map| is contained in |maps_list|, returns |map|; otherwise returns NULL. | 1565 Handle<Code> KeyedStoreIC::GetElementStubWithoutMapCheck( |
1739 Map* GetMapIfPresent(Map* map, MapList* maps_list) { | 1566 bool is_js_array, |
1740 for (int i = 0; i < maps_list->length(); ++i) { | 1567 ElementsKind elements_kind) { |
1741 if (maps_list->at(i) == map) return map; | 1568 return KeyedStoreElementStub(is_js_array, elements_kind).GetCode(); |
1742 } | |
1743 return NULL; | |
1744 } | 1569 } |
1745 | 1570 |
1746 | 1571 |
1747 // Returns the most generic transitioned map for |map| that's found in | 1572 Handle<Code> KeyedStoreIC::ComputePolymorphicStub(MapHandleList* receiver_maps, |
1748 // |maps_list|, or NULL if no transitioned map for |map| is found at all. | 1573 StrictModeFlag strict_mode) { |
1749 Map* GetTransitionedMap(Map* map, MapList* maps_list) { | 1574 // Collect MONOMORPHIC stubs for all target_receiver_maps. |
1750 ElementsKind elements_kind = map->elements_kind(); | 1575 CodeHandleList handler_ics(receiver_maps->length()); |
1751 if (elements_kind == FAST_ELEMENTS) { | 1576 MapHandleList transitioned_maps(receiver_maps->length()); |
1752 return NULL; | 1577 for (int i = 0; i < receiver_maps->length(); ++i) { |
| 1578 Handle<Map> receiver_map(receiver_maps->at(i)); |
| 1579 Handle<Code> cached_stub; |
| 1580 Handle<Map> transitioned_map = |
| 1581 receiver_map->FindTransitionedMap(receiver_maps); |
| 1582 if (!transitioned_map.is_null()) { |
| 1583 cached_stub = ElementsTransitionAndStoreStub( |
| 1584 receiver_map->elements_kind(), // original elements_kind |
| 1585 transitioned_map->elements_kind(), |
| 1586 receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array |
| 1587 strict_mode).GetCode(); |
| 1588 } else { |
| 1589 cached_stub = ComputeMonomorphicStubWithoutMapCheck(receiver_map, |
| 1590 strict_mode); |
| 1591 } |
| 1592 ASSERT(!cached_stub.is_null()); |
| 1593 handler_ics.Add(cached_stub); |
| 1594 transitioned_maps.Add(transitioned_map); |
1753 } | 1595 } |
1754 if (elements_kind == FAST_DOUBLE_ELEMENTS) { | 1596 KeyedStoreStubCompiler compiler(isolate(), strict_mode); |
1755 bool dummy = true; | 1597 Handle<Code> code = compiler.CompileStorePolymorphic( |
1756 Map* fast_map = map->LookupElementsTransitionMap(FAST_ELEMENTS, &dummy); | 1598 receiver_maps, &handler_ics, &transitioned_maps); |
1757 if (fast_map == NULL) return NULL; | 1599 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); |
1758 return GetMapIfPresent(fast_map, maps_list); | 1600 PROFILE(isolate(), |
1759 } | 1601 CodeCreateEvent(Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG, *code, 0)); |
1760 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { | 1602 return code; |
1761 bool dummy = true; | |
1762 Map* double_map = map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, | |
1763 &dummy); | |
1764 // In the current implementation, if the DOUBLE map doesn't exist, the | |
1765 // FAST map can't exist either. | |
1766 if (double_map == NULL) return NULL; | |
1767 Map* fast_map = map->LookupElementsTransitionMap(FAST_ELEMENTS, &dummy); | |
1768 if (fast_map == NULL) { | |
1769 return GetMapIfPresent(double_map, maps_list); | |
1770 } | |
1771 // Both double_map and fast_map are non-NULL. Return fast_map if it's in | |
1772 // maps_list, double_map otherwise. | |
1773 Map* fast_map_present = GetMapIfPresent(fast_map, maps_list); | |
1774 if (fast_map_present != NULL) return fast_map_present; | |
1775 return GetMapIfPresent(double_map, maps_list); | |
1776 } | |
1777 return NULL; | |
1778 } | 1603 } |
1779 | 1604 |
1780 | 1605 |
1781 MaybeObject* KeyedStoreIC::ComputePolymorphicStub( | |
1782 MapList* receiver_maps, | |
1783 StrictModeFlag strict_mode) { | |
1784 // TODO(yangguo): <remove> | |
1785 Code* generic_stub = (strict_mode == kStrictMode) | |
1786 ? isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic_Strict) | |
1787 : isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic); | |
1788 // </remove> | |
1789 | |
1790 // Collect MONOMORPHIC stubs for all target_receiver_maps. | |
1791 CodeList handler_ics(receiver_maps->length()); | |
1792 MapList transitioned_maps(receiver_maps->length()); | |
1793 for (int i = 0; i < receiver_maps->length(); ++i) { | |
1794 Map* receiver_map(receiver_maps->at(i)); | |
1795 MaybeObject* maybe_cached_stub = NULL; | |
1796 Map* transitioned_map = GetTransitionedMap(receiver_map, receiver_maps); | |
1797 if (transitioned_map != NULL) { | |
1798 // TODO(yangguo): Enable this code! | |
1799 // maybe_cached_stub = FastElementsConversionStub( | |
1800 // receiver_map->elements_kind(), // original elements_kind | |
1801 // transitioned_map->elements_kind(), | |
1802 // receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array | |
1803 // strict_mode_).TryGetCode(); | |
1804 // TODO(yangguo): <remove> | |
1805 maybe_cached_stub = generic_stub; | |
1806 // </remove> | |
1807 } else { | |
1808 maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck( | |
1809 receiver_map, strict_mode); | |
1810 } | |
1811 Code* cached_stub; | |
1812 if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub; | |
1813 handler_ics.Add(cached_stub); | |
1814 transitioned_maps.Add(transitioned_map); | |
1815 } | |
1816 Object* object; | |
1817 KeyedStoreStubCompiler compiler(strict_mode); | |
1818 MaybeObject* maybe_code = compiler.CompileStorePolymorphic( | |
1819 receiver_maps, &handler_ics, &transitioned_maps); | |
1820 if (!maybe_code->ToObject(&object)) return maybe_code; | |
1821 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); | |
1822 PROFILE(isolate(), CodeCreateEvent( | |
1823 Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG, | |
1824 Code::cast(object), 0)); | |
1825 return object; | |
1826 } | |
1827 | |
1828 | |
1829 MaybeObject* KeyedStoreIC::Store(State state, | 1606 MaybeObject* KeyedStoreIC::Store(State state, |
1830 StrictModeFlag strict_mode, | 1607 StrictModeFlag strict_mode, |
1831 Handle<Object> object, | 1608 Handle<Object> object, |
1832 Handle<Object> key, | 1609 Handle<Object> key, |
1833 Handle<Object> value, | 1610 Handle<Object> value, |
1834 bool force_generic) { | 1611 bool force_generic) { |
1835 if (key->IsSymbol()) { | 1612 if (key->IsSymbol()) { |
1836 Handle<String> name = Handle<String>::cast(key); | 1613 Handle<String> name = Handle<String>::cast(key); |
1837 | 1614 |
| 1615 // Handle proxies. |
| 1616 if (object->IsJSProxy()) { |
| 1617 return JSProxy::cast(*object)->SetProperty( |
| 1618 *name, *value, NONE, strict_mode); |
| 1619 } |
| 1620 |
1838 // If the object is undefined or null it's illegal to try to set any | 1621 // If the object is undefined or null it's illegal to try to set any |
1839 // properties on it; throw a TypeError in that case. | 1622 // properties on it; throw a TypeError in that case. |
1840 if (object->IsUndefined() || object->IsNull()) { | 1623 if (object->IsUndefined() || object->IsNull()) { |
1841 return TypeError("non_object_property_store", object, name); | 1624 return TypeError("non_object_property_store", object, name); |
1842 } | 1625 } |
1843 | 1626 |
1844 // Ignore stores where the receiver is not a JSObject. | 1627 // Ignore stores where the receiver is not a JSObject. |
1845 if (!object->IsJSObject()) return *value; | 1628 if (!object->IsJSObject()) return *value; |
1846 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1629 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1847 | 1630 |
1848 // Check if the given name is an array index. | 1631 // Check if the given name is an array index. |
1849 uint32_t index; | 1632 uint32_t index; |
1850 if (name->AsArrayIndex(&index)) { | 1633 if (name->AsArrayIndex(&index)) { |
1851 HandleScope scope(isolate()); | |
1852 Handle<Object> result = SetElement(receiver, index, value, strict_mode); | 1634 Handle<Object> result = SetElement(receiver, index, value, strict_mode); |
1853 if (result.is_null()) return Failure::Exception(); | 1635 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
1854 return *value; | 1636 return *value; |
1855 } | 1637 } |
1856 | 1638 |
1857 // Lookup the property locally in the receiver. | 1639 // Lookup the property locally in the receiver. |
1858 LookupResult lookup; | 1640 LookupResult lookup(isolate()); |
1859 receiver->LocalLookup(*name, &lookup); | 1641 receiver->LocalLookup(*name, &lookup); |
1860 | 1642 |
1861 // Update inline cache and stub cache. | 1643 // Update inline cache and stub cache. |
1862 if (FLAG_use_ic) { | 1644 if (FLAG_use_ic) { |
1863 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); | 1645 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
1864 } | 1646 } |
1865 | 1647 |
1866 // Set the property. | 1648 // Set the property. |
1867 return receiver->SetProperty(*name, *value, NONE, strict_mode); | 1649 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
1868 } | 1650 } |
1869 | 1651 |
1870 // Do not use ICs for objects that require access checks (including | 1652 // Do not use ICs for objects that require access checks (including |
1871 // the global object). | 1653 // the global object). |
1872 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1654 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
1873 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1655 ASSERT(!(use_ic && object->IsJSGlobalProxy())); |
1874 | 1656 |
1875 if (use_ic) { | 1657 if (use_ic) { |
1876 Code* stub = (strict_mode == kStrictMode) | 1658 Handle<Code> stub = (strict_mode == kStrictMode) |
1877 ? generic_stub_strict() | 1659 ? generic_stub_strict() |
1878 : generic_stub(); | 1660 : generic_stub(); |
1879 if (object->IsJSObject()) { | 1661 if (object->IsJSObject()) { |
1880 JSObject* receiver = JSObject::cast(*object); | 1662 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1881 Heap* heap = Handle<JSObject>::cast(object)->GetHeap(); | 1663 if (receiver->elements()->map() == |
1882 Map* elements_map = Handle<JSObject>::cast(object)->elements()->map(); | 1664 isolate()->heap()->non_strict_arguments_elements_map()) { |
1883 if (elements_map == heap->non_strict_arguments_elements_map()) { | |
1884 stub = non_strict_arguments_stub(); | 1665 stub = non_strict_arguments_stub(); |
1885 } else if (!force_generic) { | 1666 } else if (!force_generic) { |
1886 if (key->IsSmi() && (target() != non_strict_arguments_stub())) { | 1667 if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { |
1887 StubKind stub_kind = STORE_NO_TRANSITION; | 1668 StubKind stub_kind = STORE_NO_TRANSITION; |
1888 if (receiver->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS) { | 1669 if (receiver->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS) { |
1889 if (value->IsHeapNumber()) { | 1670 if (value->IsHeapNumber()) { |
1890 stub_kind = STORE_TRANSITION_SMI_TO_DOUBLE; | 1671 stub_kind = STORE_TRANSITION_SMI_TO_DOUBLE; |
1891 } else if (value->IsHeapObject()) { | 1672 } else if (value->IsHeapObject()) { |
1892 stub_kind = STORE_TRANSITION_SMI_TO_OBJECT; | 1673 stub_kind = STORE_TRANSITION_SMI_TO_OBJECT; |
1893 } | 1674 } |
1894 } else if (receiver->GetElementsKind() == FAST_DOUBLE_ELEMENTS) { | 1675 } else if (receiver->GetElementsKind() == FAST_DOUBLE_ELEMENTS) { |
1895 if (!value->IsSmi() && !value->IsHeapNumber()) { | 1676 if (!value->IsSmi() && !value->IsHeapNumber()) { |
1896 stub_kind = STORE_TRANSITION_DOUBLE_TO_OBJECT; | 1677 stub_kind = STORE_TRANSITION_DOUBLE_TO_OBJECT; |
1897 } | 1678 } |
1898 } | 1679 } |
1899 HandleScope scope(isolate()); | 1680 stub = ComputeStub(receiver, stub_kind, strict_mode, stub); |
1900 MaybeObject* maybe_stub = ComputeStub(receiver, | |
1901 stub_kind, | |
1902 strict_mode, | |
1903 stub); | |
1904 stub = maybe_stub->IsFailure() ? | |
1905 NULL : Code::cast(maybe_stub->ToObjectUnchecked()); | |
1906 } | 1681 } |
1907 } | 1682 } |
1908 } | 1683 } |
1909 if (stub != NULL) set_target(stub); | 1684 if (!stub.is_null()) set_target(*stub); |
1910 } | 1685 } |
1911 | 1686 |
1912 #ifdef DEBUG | 1687 TRACE_IC("KeyedStoreIC", key, state, target()); |
1913 TraceIC("KeyedStoreIC", key, state, target()); | |
1914 #endif | |
1915 | 1688 |
1916 // Set the property. | 1689 // Set the property. |
1917 return Runtime::SetObjectProperty( | 1690 return Runtime::SetObjectProperty( |
1918 isolate(), object , key, value, NONE, strict_mode); | 1691 isolate(), object , key, value, NONE, strict_mode); |
1919 } | 1692 } |
1920 | 1693 |
1921 | 1694 |
1922 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, | 1695 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, |
1923 State state, | 1696 State state, |
1924 StrictModeFlag strict_mode, | 1697 StrictModeFlag strict_mode, |
(...skipping 11 matching lines...) Expand all Loading... |
1936 if (lookup->IsReadOnly()) return; | 1709 if (lookup->IsReadOnly()) return; |
1937 | 1710 |
1938 // If the property has a non-field type allowing map transitions | 1711 // If the property has a non-field type allowing map transitions |
1939 // where there is extra room in the object, we leave the IC in its | 1712 // where there is extra room in the object, we leave the IC in its |
1940 // current state. | 1713 // current state. |
1941 PropertyType type = lookup->type(); | 1714 PropertyType type = lookup->type(); |
1942 | 1715 |
1943 // Compute the code stub for this store; used for rewriting to | 1716 // Compute the code stub for this store; used for rewriting to |
1944 // monomorphic state and making sure that the code stub is in the | 1717 // monomorphic state and making sure that the code stub is in the |
1945 // stub cache. | 1718 // stub cache. |
1946 MaybeObject* maybe_code = NULL; | 1719 Handle<Code> code; |
1947 Object* code = NULL; | |
1948 | 1720 |
1949 switch (type) { | 1721 switch (type) { |
1950 case FIELD: { | 1722 case FIELD: |
1951 maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField( | 1723 code = isolate()->stub_cache()->ComputeKeyedStoreField( |
1952 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); | 1724 name, receiver, lookup->GetFieldIndex(), |
| 1725 Handle<Map>::null(), strict_mode); |
1953 break; | 1726 break; |
1954 } | 1727 case MAP_TRANSITION: |
1955 case MAP_TRANSITION: { | |
1956 if (lookup->GetAttributes() == NONE) { | 1728 if (lookup->GetAttributes() == NONE) { |
1957 HandleScope scope(isolate()); | |
1958 ASSERT(type == MAP_TRANSITION); | 1729 ASSERT(type == MAP_TRANSITION); |
1959 Handle<Map> transition(lookup->GetTransitionMap()); | 1730 Handle<Map> transition(lookup->GetTransitionMap()); |
1960 int index = transition->PropertyIndexFor(*name); | 1731 int index = transition->PropertyIndexFor(*name); |
1961 maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField( | 1732 code = isolate()->stub_cache()->ComputeKeyedStoreField( |
1962 *name, *receiver, index, *transition, strict_mode); | 1733 name, receiver, index, transition, strict_mode); |
1963 break; | 1734 break; |
1964 } | 1735 } |
1965 // fall through. | 1736 // fall through. |
1966 } | 1737 default: |
1967 default: { | |
1968 // Always rewrite to the generic case so that we do not | 1738 // Always rewrite to the generic case so that we do not |
1969 // repeatedly try to rewrite. | 1739 // repeatedly try to rewrite. |
1970 maybe_code = (strict_mode == kStrictMode) | 1740 code = (strict_mode == kStrictMode) |
1971 ? generic_stub_strict() | 1741 ? generic_stub_strict() |
1972 : generic_stub(); | 1742 : generic_stub(); |
1973 break; | 1743 break; |
1974 } | |
1975 } | 1744 } |
1976 | 1745 |
1977 // If we're unable to compute the stub (not enough memory left), we | 1746 ASSERT(!code.is_null()); |
1978 // simply avoid updating the caches. | |
1979 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | |
1980 | 1747 |
1981 // Patch the call site depending on the state of the cache. Make | 1748 // Patch the call site depending on the state of the cache. Make |
1982 // sure to always rewrite from monomorphic to megamorphic. | 1749 // sure to always rewrite from monomorphic to megamorphic. |
1983 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); | 1750 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); |
1984 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { | 1751 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { |
1985 set_target(Code::cast(code)); | 1752 set_target(*code); |
1986 } else if (state == MONOMORPHIC) { | 1753 } else if (state == MONOMORPHIC) { |
1987 set_target((strict_mode == kStrictMode) | 1754 set_target((strict_mode == kStrictMode) |
1988 ? megamorphic_stub_strict() | 1755 ? *megamorphic_stub_strict() |
1989 : megamorphic_stub()); | 1756 : *megamorphic_stub()); |
1990 } | 1757 } |
1991 | 1758 |
1992 #ifdef DEBUG | 1759 TRACE_IC("KeyedStoreIC", name, state, target()); |
1993 TraceIC("KeyedStoreIC", name, state, target()); | |
1994 #endif | |
1995 } | 1760 } |
1996 | 1761 |
1997 | 1762 |
| 1763 #undef TRACE_IC |
| 1764 |
| 1765 |
1998 // ---------------------------------------------------------------------------- | 1766 // ---------------------------------------------------------------------------- |
1999 // Static IC stub generators. | 1767 // Static IC stub generators. |
2000 // | 1768 // |
2001 | 1769 |
2002 static JSFunction* CompileFunction(Isolate* isolate, | |
2003 JSFunction* function) { | |
2004 // Compile now with optimization. | |
2005 HandleScope scope(isolate); | |
2006 Handle<JSFunction> function_handle(function, isolate); | |
2007 CompileLazy(function_handle, CLEAR_EXCEPTION); | |
2008 return *function_handle; | |
2009 } | |
2010 | |
2011 | |
2012 // Used from ic-<arch>.cc. | 1770 // Used from ic-<arch>.cc. |
2013 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { | 1771 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { |
2014 NoHandleAllocation na; | 1772 HandleScope scope(isolate); |
2015 ASSERT(args.length() == 2); | 1773 ASSERT(args.length() == 2); |
2016 CallIC ic(isolate); | 1774 CallIC ic(isolate); |
2017 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1775 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
2018 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 1776 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
2019 MaybeObject* maybe_result = ic.LoadFunction(state, | 1777 MaybeObject* maybe_result = ic.LoadFunction(state, |
2020 extra_ic_state, | 1778 extra_ic_state, |
2021 args.at<Object>(0), | 1779 args.at<Object>(0), |
2022 args.at<String>(1)); | 1780 args.at<String>(1)); |
2023 Object* result; | 1781 // Result could be a function or a failure. |
2024 if (!maybe_result->ToObject(&result)) return maybe_result; | 1782 JSFunction* raw_function = NULL; |
| 1783 if (!maybe_result->To(&raw_function)) return maybe_result; |
2025 | 1784 |
2026 // The first time the inline cache is updated may be the first time the | 1785 // The first time the inline cache is updated may be the first time the |
2027 // function it references gets called. If the function was lazily compiled | 1786 // function it references gets called. If the function is lazily compiled |
2028 // then the first call will trigger a compilation. We check for this case | 1787 // then the first call will trigger a compilation. We check for this case |
2029 // and we do the compilation immediately, instead of waiting for the stub | 1788 // and we do the compilation immediately, instead of waiting for the stub |
2030 // currently attached to the JSFunction object to trigger compilation. We | 1789 // currently attached to the JSFunction object to trigger compilation. |
2031 // do this in the case where we know that the inline cache is inside a loop, | 1790 if (raw_function->is_compiled()) return raw_function; |
2032 // because then we know that we want to optimize the function. | 1791 |
2033 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { | 1792 Handle<JSFunction> function(raw_function); |
2034 return result; | 1793 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); |
2035 } | 1794 return *function; |
2036 return CompileFunction(isolate, JSFunction::cast(result)); | |
2037 } | 1795 } |
2038 | 1796 |
2039 | 1797 |
2040 // Used from ic-<arch>.cc. | 1798 // Used from ic-<arch>.cc. |
2041 RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) { | 1799 RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) { |
2042 NoHandleAllocation na; | 1800 HandleScope scope(isolate); |
2043 ASSERT(args.length() == 2); | 1801 ASSERT(args.length() == 2); |
2044 KeyedCallIC ic(isolate); | 1802 KeyedCallIC ic(isolate); |
2045 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1803 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
2046 Object* result; | 1804 MaybeObject* maybe_result = |
2047 { MaybeObject* maybe_result = | |
2048 ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1)); | 1805 ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1)); |
2049 if (!maybe_result->ToObject(&result)) return maybe_result; | 1806 // Result could be a function or a failure. |
2050 } | 1807 JSFunction* raw_function = NULL; |
| 1808 if (!maybe_result->To(&raw_function)) return maybe_result; |
2051 | 1809 |
2052 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { | 1810 if (raw_function->is_compiled()) return raw_function; |
2053 return result; | 1811 |
2054 } | 1812 Handle<JSFunction> function(raw_function); |
2055 return CompileFunction(isolate, JSFunction::cast(result)); | 1813 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); |
| 1814 return *function; |
2056 } | 1815 } |
2057 | 1816 |
2058 | 1817 |
2059 // Used from ic-<arch>.cc. | 1818 // Used from ic-<arch>.cc. |
2060 RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { | 1819 RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { |
2061 NoHandleAllocation na; | 1820 HandleScope scope(isolate); |
2062 ASSERT(args.length() == 2); | 1821 ASSERT(args.length() == 2); |
2063 LoadIC ic(isolate); | 1822 LoadIC ic(isolate); |
2064 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1823 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
2065 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); | 1824 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); |
2066 } | 1825 } |
2067 | 1826 |
2068 | 1827 |
2069 // Used from ic-<arch>.cc | 1828 // Used from ic-<arch>.cc |
2070 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { | 1829 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { |
2071 NoHandleAllocation na; | 1830 HandleScope scope(isolate); |
2072 ASSERT(args.length() == 2); | 1831 ASSERT(args.length() == 2); |
2073 KeyedLoadIC ic(isolate); | 1832 KeyedLoadIC ic(isolate); |
2074 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1833 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
2075 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), false); | 1834 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), false); |
2076 } | 1835 } |
2077 | 1836 |
2078 | 1837 |
2079 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) { | 1838 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) { |
2080 NoHandleAllocation na; | 1839 HandleScope scope(isolate); |
2081 ASSERT(args.length() == 2); | 1840 ASSERT(args.length() == 2); |
2082 KeyedLoadIC ic(isolate); | 1841 KeyedLoadIC ic(isolate); |
2083 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1842 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
2084 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), true); | 1843 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), true); |
2085 } | 1844 } |
2086 | 1845 |
2087 | 1846 |
2088 // Used from ic-<arch>.cc. | 1847 // Used from ic-<arch>.cc. |
2089 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { | 1848 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { |
2090 NoHandleAllocation na; | 1849 HandleScope scope; |
2091 ASSERT(args.length() == 3); | 1850 ASSERT(args.length() == 3); |
2092 StoreIC ic(isolate); | 1851 StoreIC ic(isolate); |
2093 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1852 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
2094 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 1853 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
2095 return ic.Store(state, | 1854 return ic.Store(state, |
2096 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), | 1855 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
2097 args.at<Object>(0), | 1856 args.at<Object>(0), |
2098 args.at<String>(1), | 1857 args.at<String>(1), |
2099 args.at<Object>(2)); | 1858 args.at<Object>(2)); |
2100 } | 1859 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2149 object->set_properties(new_storage); | 1908 object->set_properties(new_storage); |
2150 object->set_map(transition); | 1909 object->set_map(transition); |
2151 | 1910 |
2152 // Return the stored value. | 1911 // Return the stored value. |
2153 return value; | 1912 return value; |
2154 } | 1913 } |
2155 | 1914 |
2156 | 1915 |
2157 // Used from ic-<arch>.cc. | 1916 // Used from ic-<arch>.cc. |
2158 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { | 1917 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { |
2159 NoHandleAllocation na; | 1918 HandleScope scope(isolate); |
2160 ASSERT(args.length() == 3); | 1919 ASSERT(args.length() == 3); |
2161 KeyedStoreIC ic(isolate); | 1920 KeyedStoreIC ic(isolate); |
2162 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1921 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
2163 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 1922 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
2164 return ic.Store(state, | 1923 return ic.Store(state, |
2165 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), | 1924 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
2166 args.at<Object>(0), | 1925 args.at<Object>(0), |
2167 args.at<Object>(1), | 1926 args.at<Object>(1), |
2168 args.at<Object>(2), | 1927 args.at<Object>(2), |
2169 false); | 1928 false); |
(...skipping 13 matching lines...) Expand all Loading... |
2183 return Runtime::SetObjectProperty(isolate, | 1942 return Runtime::SetObjectProperty(isolate, |
2184 object, | 1943 object, |
2185 key, | 1944 key, |
2186 value, | 1945 value, |
2187 NONE, | 1946 NONE, |
2188 strict_mode); | 1947 strict_mode); |
2189 } | 1948 } |
2190 | 1949 |
2191 | 1950 |
2192 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { | 1951 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { |
2193 NoHandleAllocation na; | 1952 HandleScope scope(isolate); |
2194 ASSERT(args.length() == 3); | 1953 ASSERT(args.length() == 3); |
2195 KeyedStoreIC ic(isolate); | 1954 KeyedStoreIC ic(isolate); |
2196 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1955 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
2197 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 1956 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
2198 return ic.Store(state, | 1957 return ic.Store(state, |
2199 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), | 1958 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
2200 args.at<Object>(0), | 1959 args.at<Object>(0), |
2201 args.at<Object>(1), | 1960 args.at<Object>(1), |
2202 args.at<Object>(2), | 1961 args.at<Object>(2), |
2203 true); | 1962 true); |
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2618 #undef ADDR | 2377 #undef ADDR |
2619 }; | 2378 }; |
2620 | 2379 |
2621 | 2380 |
2622 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2381 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2623 return IC_utilities[id]; | 2382 return IC_utilities[id]; |
2624 } | 2383 } |
2625 | 2384 |
2626 | 2385 |
2627 } } // namespace v8::internal | 2386 } } // namespace v8::internal |
OLD | NEW |