OLD | NEW |
---|---|
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
428 StackFrameLocator locator; | 428 StackFrameLocator locator; |
429 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 429 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
430 int index = frame->ComputeExpressionsCount() - (argc + 1); | 430 int index = frame->ComputeExpressionsCount() - (argc + 1); |
431 frame->SetExpression(index, *target); | 431 frame->SetExpression(index, *target); |
432 } | 432 } |
433 | 433 |
434 return *delegate; | 434 return *delegate; |
435 } | 435 } |
436 | 436 |
437 | 437 |
438 void CallICBase::ReceiverToObject(Handle<Object> object) { | 438 void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee, |
439 HandleScope scope; | 439 Handle<Object> object) { |
440 Handle<Object> receiver(object); | 440 if (callee->IsJSFunction()) { |
441 JSFunction* function = JSFunction::cast(*callee); | |
442 if (function->shared()->strict_mode() || function->IsBuiltin()) { | |
443 // Do not wrap receiver for strict mode functions or for builtins. | |
444 return; | |
445 } | |
446 } | |
441 | 447 |
442 // Change the receiver to the result of calling ToObject on it. | 448 // And only wrap string, number or boolean. |
443 const int argc = this->target()->arguments_count(); | 449 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
Martin Maly
2011/02/18 00:55:38
I don't understand why the object was double-wrapp
Mads Ager (chromium)
2011/02/18 07:22:48
Yes, there is no reason to rewrap the incoming obj
| |
444 StackFrameLocator locator; | 450 // Change the receiver to the result of calling ToObject on it. |
445 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 451 const int argc = this->target()->arguments_count(); |
446 int index = frame->ComputeExpressionsCount() - (argc + 1); | 452 StackFrameLocator locator; |
447 frame->SetExpression(index, *Factory::ToObject(object)); | 453 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
454 int index = frame->ComputeExpressionsCount() - (argc + 1); | |
455 frame->SetExpression(index, *Factory::ToObject(object)); | |
456 } | |
448 } | 457 } |
449 | 458 |
450 | 459 |
451 MaybeObject* CallICBase::LoadFunction(State state, | 460 MaybeObject* CallICBase::LoadFunction(State state, |
452 Code::ExtraICState extra_ic_state, | 461 Code::ExtraICState extra_ic_state, |
453 Handle<Object> object, | 462 Handle<Object> object, |
454 Handle<String> name) { | 463 Handle<String> name) { |
455 // If the object is undefined or null it's illegal to try to get any | 464 // If the object is undefined or null it's illegal to try to get any |
456 // of its properties; throw a TypeError in that case. | 465 // of its properties; throw a TypeError in that case. |
457 if (object->IsUndefined() || object->IsNull()) { | 466 if (object->IsUndefined() || object->IsNull()) { |
458 return TypeError("non_object_property_call", object, name); | 467 return TypeError("non_object_property_call", object, name); |
459 } | 468 } |
460 | 469 |
461 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | |
462 ReceiverToObject(object); | |
463 } | |
464 | |
465 // Check if the name is trivially convertible to an index and get | 470 // Check if the name is trivially convertible to an index and get |
466 // the element if so. | 471 // the element if so. |
467 uint32_t index; | 472 uint32_t index; |
468 if (name->AsArrayIndex(&index)) { | 473 if (name->AsArrayIndex(&index)) { |
469 Object* result; | 474 Object* result; |
470 { MaybeObject* maybe_result = object->GetElement(index); | 475 { MaybeObject* maybe_result = object->GetElement(index); |
471 if (!maybe_result->ToObject(&result)) return maybe_result; | 476 if (!maybe_result->ToObject(&result)) return maybe_result; |
472 } | 477 } |
473 | 478 |
474 if (result->IsJSFunction()) return result; | 479 if (result->IsJSFunction()) return result; |
(...skipping 18 matching lines...) Expand all Loading... | |
493 return TypeError("undefined_method", object, name); | 498 return TypeError("undefined_method", object, name); |
494 } | 499 } |
495 | 500 |
496 // Lookup is valid: Update inline cache and stub cache. | 501 // Lookup is valid: Update inline cache and stub cache. |
497 if (FLAG_use_ic) { | 502 if (FLAG_use_ic) { |
498 UpdateCaches(&lookup, state, extra_ic_state, object, name); | 503 UpdateCaches(&lookup, state, extra_ic_state, object, name); |
499 } | 504 } |
500 | 505 |
501 // Get the property. | 506 // Get the property. |
502 PropertyAttributes attr; | 507 PropertyAttributes attr; |
503 Object* result; | 508 HandleScope scope; |
509 Handle<Object> result; | |
Mads Ager (chromium)
2011/02/18 07:22:48
I would move the object_result out here (maybe cal
Martin Maly
2011/02/19 01:26:13
Done.
| |
504 { MaybeObject* maybe_result = | 510 { MaybeObject* maybe_result = |
505 object->GetProperty(*object, &lookup, *name, &attr); | 511 object->GetProperty(*object, &lookup, *name, &attr); |
506 if (!maybe_result->ToObject(&result)) return maybe_result; | 512 Object* object_result; |
513 if (!maybe_result->ToObject(&object_result)) return maybe_result; | |
514 result = Handle<Object>(object_result); | |
507 } | 515 } |
516 | |
517 // Make receiver an object if the callee requires it. Strict mode or builtin | |
518 // functions do not wrap the receiver, non-strict functions and objects | |
519 // called as functions do. | |
520 ReceiverToObjectIfRequired(result, object); | |
521 | |
508 if (lookup.type() == INTERCEPTOR) { | 522 if (lookup.type() == INTERCEPTOR) { |
Mads Ager (chromium)
2011/02/18 07:22:48
It looks like you can move the wrapping below this
Martin Maly
2011/02/19 01:26:13
Done.
| |
509 // If the object does not have the requested property, check which | 523 // If the object does not have the requested property, check which |
510 // exception we need to throw. | 524 // exception we need to throw. |
511 if (attr == ABSENT) { | 525 if (attr == ABSENT) { |
512 if (IsContextual(object)) { | 526 if (IsContextual(object)) { |
513 return ReferenceError("not_defined", name); | 527 return ReferenceError("not_defined", name); |
514 } | 528 } |
515 return TypeError("undefined_method", object, name); | 529 return TypeError("undefined_method", object, name); |
516 } | 530 } |
517 } | 531 } |
518 | 532 |
519 ASSERT(result != Heap::the_hole_value()); | 533 ASSERT(*result != Heap::the_hole_value()); |
Mads Ager (chromium)
2011/02/18 07:22:48
ASSERT(!result->IsTheHole());
Martin Maly
2011/02/19 01:26:13
Done.
| |
520 | 534 |
521 if (result->IsJSFunction()) { | 535 if (result->IsJSFunction()) { |
522 #ifdef ENABLE_DEBUGGER_SUPPORT | 536 #ifdef ENABLE_DEBUGGER_SUPPORT |
523 // Handle stepping into a function if step into is active. | 537 // Handle stepping into a function if step into is active. |
524 if (Debug::StepInActive()) { | 538 if (Debug::StepInActive()) { |
525 // Protect the result in a handle as the debugger can allocate and might | 539 // Protect the result in a handle as the debugger can allocate and might |
526 // cause GC. | 540 // cause GC. |
527 HandleScope scope; | 541 Handle<JSFunction> function(JSFunction::cast(*result)); |
Martin Maly
2011/02/18 00:55:38
No HandleScope needed here, I believe ... the Hand
Mads Ager (chromium)
2011/02/18 07:22:48
Yes, that's fine.
| |
528 Handle<JSFunction> function(JSFunction::cast(result)); | |
529 Debug::HandleStepIn(function, object, fp(), false); | 542 Debug::HandleStepIn(function, object, fp(), false); |
530 return *function; | 543 return *function; |
531 } | 544 } |
532 #endif | 545 #endif |
533 | 546 |
534 return result; | 547 return *result; |
535 } | 548 } |
536 | 549 |
537 // Try to find a suitable function delegate for the object at hand. | 550 // Try to find a suitable function delegate for the object at hand. |
538 result = TryCallAsFunction(result); | 551 result = Handle<Object>(TryCallAsFunction(*result)); |
539 MaybeObject* answer = result; | 552 if (result->IsJSFunction()) return *result; |
Martin Maly
2011/02/18 00:55:38
I am a bit hazy on using
"return handle.EscapeFrom
Mads Ager (chromium)
2011/02/18 07:22:48
This method returns a MaybeObject which is a raw o
| |
540 if (!result->IsJSFunction()) { | 553 |
541 answer = TypeError("property_not_function", object, name); | 554 return TypeError("property_not_function", object, name); |
542 } | |
543 return answer; | |
544 } | 555 } |
545 | 556 |
546 | 557 |
547 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, | 558 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, |
548 Handle<Object> object, | 559 Handle<Object> object, |
549 Code::ExtraICState* extra_ic_state) { | 560 Code::ExtraICState* extra_ic_state) { |
550 ASSERT(kind_ == Code::CALL_IC); | 561 ASSERT(kind_ == Code::CALL_IC); |
551 if (lookup->type() != CONSTANT_FUNCTION) return false; | 562 if (lookup->type() != CONSTANT_FUNCTION) return false; |
552 JSFunction* function = lookup->GetConstantFunction(); | 563 JSFunction* function = lookup->GetConstantFunction(); |
553 if (!function->shared()->HasBuiltinFunctionId()) return false; | 564 if (!function->shared()->HasBuiltinFunctionId()) return false; |
554 | 565 |
555 // Fetch the arguments passed to the called function. | 566 // Fetch the arguments passed to the called function. |
556 const int argc = target()->arguments_count(); | 567 const int argc = target()->arguments_count(); |
557 Address entry = Top::c_entry_fp(Top::GetCurrentThread()); | 568 Address entry = Top::c_entry_fp(Top::GetCurrentThread()); |
558 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); | 569 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
559 Arguments args(argc + 1, | 570 Arguments args(argc + 1, |
560 &Memory::Object_at(fp + | 571 &Memory::Object_at(fp + |
561 StandardFrameConstants::kCallerSPOffset + | 572 StandardFrameConstants::kCallerSPOffset + |
562 argc * kPointerSize)); | 573 argc * kPointerSize)); |
563 switch (function->shared()->builtin_function_id()) { | 574 switch (function->shared()->builtin_function_id()) { |
564 case kStringCharCodeAt: | 575 case kStringCharCodeAt: |
565 case kStringCharAt: | 576 case kStringCharAt: |
566 if (object->IsString()) { | 577 if (object->IsString()) { |
567 String* string = String::cast(*object); | 578 String* string = String::cast(*object); |
568 // Check that there's the right wrapper in the receiver slot. | 579 // Check there's the right string value or wrapper in the receiver slot. |
569 ASSERT(string == JSValue::cast(args[0])->value()); | 580 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value()); |
570 // If we're in the default (fastest) state and the index is | 581 // If we're in the default (fastest) state and the index is |
571 // out of bounds, update the state to record this fact. | 582 // out of bounds, update the state to record this fact. |
572 if (*extra_ic_state == DEFAULT_STRING_STUB && | 583 if (*extra_ic_state == DEFAULT_STRING_STUB && |
573 argc >= 1 && args[1]->IsNumber()) { | 584 argc >= 1 && args[1]->IsNumber()) { |
574 double index; | 585 double index; |
575 if (args[1]->IsSmi()) { | 586 if (args[1]->IsSmi()) { |
576 index = Smi::cast(args[1])->value(); | 587 index = Smi::cast(args[1])->value(); |
577 } else { | 588 } else { |
578 ASSERT(args[1]->IsHeapNumber()); | 589 ASSERT(args[1]->IsHeapNumber()); |
579 index = DoubleToInteger(HeapNumber::cast(args[1])->value()); | 590 index = DoubleToInteger(HeapNumber::cast(args[1])->value()); |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
768 return CallICBase::LoadFunction(state, | 779 return CallICBase::LoadFunction(state, |
769 Code::kNoExtraICState, | 780 Code::kNoExtraICState, |
770 object, | 781 object, |
771 Handle<String>::cast(key)); | 782 Handle<String>::cast(key)); |
772 } | 783 } |
773 | 784 |
774 if (object->IsUndefined() || object->IsNull()) { | 785 if (object->IsUndefined() || object->IsNull()) { |
775 return TypeError("non_object_property_call", object, key); | 786 return TypeError("non_object_property_call", object, key); |
776 } | 787 } |
777 | 788 |
778 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | |
779 ReceiverToObject(object); | |
780 } | |
781 | |
782 if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) { | 789 if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) { |
783 int argc = target()->arguments_count(); | 790 int argc = target()->arguments_count(); |
784 InLoopFlag in_loop = target()->ic_in_loop(); | 791 InLoopFlag in_loop = target()->ic_in_loop(); |
785 MaybeObject* maybe_code = StubCache::ComputeCallMegamorphic( | 792 MaybeObject* maybe_code = StubCache::ComputeCallMegamorphic( |
786 argc, in_loop, Code::KEYED_CALL_IC); | 793 argc, in_loop, Code::KEYED_CALL_IC); |
787 Object* code; | 794 Object* code; |
788 if (maybe_code->ToObject(&code)) { | 795 if (maybe_code->ToObject(&code)) { |
789 set_target(Code::cast(code)); | 796 set_target(Code::cast(code)); |
790 #ifdef DEBUG | 797 #ifdef DEBUG |
791 TraceIC( | 798 TraceIC( |
792 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : ""); | 799 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : ""); |
793 #endif | 800 #endif |
794 } | 801 } |
795 } | 802 } |
796 Object* result; | 803 |
804 HandleScope scope; | |
805 Handle<Object> result; | |
Mads Ager (chromium)
2011/02/18 07:22:48
This case can be rewritten to just use handles. Yo
Martin Maly
2011/02/19 01:26:13
Done.
| |
797 { MaybeObject* maybe_result = Runtime::GetObjectProperty(object, key); | 806 { MaybeObject* maybe_result = Runtime::GetObjectProperty(object, key); |
798 if (!maybe_result->ToObject(&result)) return maybe_result; | 807 Object* object_result; |
808 if (!maybe_result->ToObject(&object_result)) return maybe_result; | |
809 result = Handle<Object>(object_result); | |
Martin Maly
2011/02/18 00:55:38
Is there an established V8 pattern to export objec
| |
799 } | 810 } |
800 if (result->IsJSFunction()) return result; | 811 |
801 result = TryCallAsFunction(result); | 812 // Make receiver an object if the callee requires it. Strict mode or builtin |
802 MaybeObject* answer = result; | 813 // functions do not wrap the receiver, non-strict functions and objects |
803 if (!result->IsJSFunction()) { | 814 // called as functions do. |
804 answer = TypeError("property_not_function", object, key); | 815 ReceiverToObjectIfRequired(result, object); |
805 } | 816 |
806 return answer; | 817 if (result->IsJSFunction()) return *result; |
818 result = Handle<Object>(TryCallAsFunction(*result)); | |
819 if (result->IsJSFunction()) return *result; | |
820 | |
821 return TypeError("property_not_function", object, key); | |
Martin Maly
2011/02/18 00:55:38
This sequence seemed cleaner, get rid of "answer"
Mads Ager (chromium)
2011/02/18 07:22:48
Yes, thanks for cleaning that up! The original cod
| |
807 } | 822 } |
808 | 823 |
809 | 824 |
810 #ifdef DEBUG | 825 #ifdef DEBUG |
811 #define TRACE_IC_NAMED(msg, name) \ | 826 #define TRACE_IC_NAMED(msg, name) \ |
812 if (FLAG_trace_ic) PrintF(msg, *(name)->ToCString()) | 827 if (FLAG_trace_ic) PrintF(msg, *(name)->ToCString()) |
813 #else | 828 #else |
814 #define TRACE_IC_NAMED(msg, name) | 829 #define TRACE_IC_NAMED(msg, name) |
815 #endif | 830 #endif |
816 | 831 |
(...skipping 1469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2286 #undef ADDR | 2301 #undef ADDR |
2287 }; | 2302 }; |
2288 | 2303 |
2289 | 2304 |
2290 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2305 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2291 return IC_utilities[id]; | 2306 return IC_utilities[id]; |
2292 } | 2307 } |
2293 | 2308 |
2294 | 2309 |
2295 } } // namespace v8::internal | 2310 } } // namespace v8::internal |
OLD | NEW |