Chromium Code Reviews| 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); | |
|
Mads Ager (chromium)
2011/02/21 07:45:11
Let's keep it all in handles here to not mix handl
Martin Maly
2011/02/22 00:40:35
Done.
| |
| 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()) { |
| 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 23 matching lines...) Expand all Loading... | |
| 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 Object* result; |
| 504 { MaybeObject* maybe_result = | 509 { MaybeObject* maybe_result = |
| 505 object->GetProperty(*object, &lookup, *name, &attr); | 510 object->GetProperty(*object, &lookup, *name, &attr); |
| 506 if (!maybe_result->ToObject(&result)) return maybe_result; | 511 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 507 } | 512 } |
| 513 | |
| 508 if (lookup.type() == INTERCEPTOR) { | 514 if (lookup.type() == INTERCEPTOR) { |
| 509 // If the object does not have the requested property, check which | 515 // If the object does not have the requested property, check which |
| 510 // exception we need to throw. | 516 // exception we need to throw. |
| 511 if (attr == ABSENT) { | 517 if (attr == ABSENT) { |
| 512 if (IsContextual(object)) { | 518 if (IsContextual(object)) { |
| 513 return ReferenceError("not_defined", name); | 519 return ReferenceError("not_defined", name); |
| 514 } | 520 } |
| 515 return TypeError("undefined_method", object, name); | 521 return TypeError("undefined_method", object, name); |
| 516 } | 522 } |
| 517 } | 523 } |
| 518 | 524 |
| 519 ASSERT(result != Heap::the_hole_value()); | 525 ASSERT(!result->IsTheHole()); |
| 520 | 526 |
| 521 if (result->IsJSFunction()) { | 527 HandleScope scope; |
| 528 // Wrap result in a handle because ReceiverToObjectIfRequired may allocate | |
| 529 // new object and cause GC. | |
| 530 Handle<Object> result_handle(result); | |
| 531 // Make receiver an object if the callee requires it. Strict mode or builtin | |
| 532 // functions do not wrap the receiver, non-strict functions and objects | |
| 533 // called as functions do. | |
| 534 ReceiverToObjectIfRequired(result_handle, object); | |
| 535 | |
| 536 if (result_handle->IsJSFunction()) { | |
| 522 #ifdef ENABLE_DEBUGGER_SUPPORT | 537 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 523 // Handle stepping into a function if step into is active. | 538 // Handle stepping into a function if step into is active. |
| 524 if (Debug::StepInActive()) { | 539 if (Debug::StepInActive()) { |
| 525 // Protect the result in a handle as the debugger can allocate and might | 540 // Protect the result in a handle as the debugger can allocate and might |
| 526 // cause GC. | 541 // cause GC. |
| 527 HandleScope scope; | 542 Handle<JSFunction> function(JSFunction::cast(*result_handle)); |
| 528 Handle<JSFunction> function(JSFunction::cast(result)); | |
| 529 Debug::HandleStepIn(function, object, fp(), false); | 543 Debug::HandleStepIn(function, object, fp(), false); |
| 530 return *function; | 544 return *function; |
| 531 } | 545 } |
| 532 #endif | 546 #endif |
| 533 | 547 |
| 534 return result; | 548 return *result_handle; |
| 535 } | 549 } |
| 536 | 550 |
| 537 // Try to find a suitable function delegate for the object at hand. | 551 // Try to find a suitable function delegate for the object at hand. |
| 538 result = TryCallAsFunction(result); | 552 result_handle = Handle<Object>(TryCallAsFunction(*result_handle)); |
| 539 MaybeObject* answer = result; | 553 if (result_handle->IsJSFunction()) return *result_handle; |
| 540 if (!result->IsJSFunction()) { | 554 |
| 541 answer = TypeError("property_not_function", object, name); | 555 return TypeError("property_not_function", object, name); |
| 542 } | |
| 543 return answer; | |
| 544 } | 556 } |
| 545 | 557 |
| 546 | 558 |
| 547 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, | 559 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, |
| 548 Handle<Object> object, | 560 Handle<Object> object, |
| 549 Code::ExtraICState* extra_ic_state) { | 561 Code::ExtraICState* extra_ic_state) { |
| 550 ASSERT(kind_ == Code::CALL_IC); | 562 ASSERT(kind_ == Code::CALL_IC); |
| 551 if (lookup->type() != CONSTANT_FUNCTION) return false; | 563 if (lookup->type() != CONSTANT_FUNCTION) return false; |
| 552 JSFunction* function = lookup->GetConstantFunction(); | 564 JSFunction* function = lookup->GetConstantFunction(); |
| 553 if (!function->shared()->HasBuiltinFunctionId()) return false; | 565 if (!function->shared()->HasBuiltinFunctionId()) return false; |
| 554 | 566 |
| 555 // Fetch the arguments passed to the called function. | 567 // Fetch the arguments passed to the called function. |
| 556 const int argc = target()->arguments_count(); | 568 const int argc = target()->arguments_count(); |
| 557 Address entry = Top::c_entry_fp(Top::GetCurrentThread()); | 569 Address entry = Top::c_entry_fp(Top::GetCurrentThread()); |
| 558 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); | 570 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
| 559 Arguments args(argc + 1, | 571 Arguments args(argc + 1, |
| 560 &Memory::Object_at(fp + | 572 &Memory::Object_at(fp + |
| 561 StandardFrameConstants::kCallerSPOffset + | 573 StandardFrameConstants::kCallerSPOffset + |
| 562 argc * kPointerSize)); | 574 argc * kPointerSize)); |
| 563 switch (function->shared()->builtin_function_id()) { | 575 switch (function->shared()->builtin_function_id()) { |
| 564 case kStringCharCodeAt: | 576 case kStringCharCodeAt: |
| 565 case kStringCharAt: | 577 case kStringCharAt: |
| 566 if (object->IsString()) { | 578 if (object->IsString()) { |
| 567 String* string = String::cast(*object); | 579 String* string = String::cast(*object); |
| 568 // Check that there's the right wrapper in the receiver slot. | 580 // Check there's the right string value or wrapper in the receiver slot. |
| 569 ASSERT(string == JSValue::cast(args[0])->value()); | 581 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value()); |
| 570 // If we're in the default (fastest) state and the index is | 582 // If we're in the default (fastest) state and the index is |
| 571 // out of bounds, update the state to record this fact. | 583 // out of bounds, update the state to record this fact. |
| 572 if (*extra_ic_state == DEFAULT_STRING_STUB && | 584 if (*extra_ic_state == DEFAULT_STRING_STUB && |
| 573 argc >= 1 && args[1]->IsNumber()) { | 585 argc >= 1 && args[1]->IsNumber()) { |
| 574 double index; | 586 double index; |
| 575 if (args[1]->IsSmi()) { | 587 if (args[1]->IsSmi()) { |
| 576 index = Smi::cast(args[1])->value(); | 588 index = Smi::cast(args[1])->value(); |
| 577 } else { | 589 } else { |
| 578 ASSERT(args[1]->IsHeapNumber()); | 590 ASSERT(args[1]->IsHeapNumber()); |
| 579 index = DoubleToInteger(HeapNumber::cast(args[1])->value()); | 591 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, | 780 return CallICBase::LoadFunction(state, |
| 769 Code::kNoExtraICState, | 781 Code::kNoExtraICState, |
| 770 object, | 782 object, |
| 771 Handle<String>::cast(key)); | 783 Handle<String>::cast(key)); |
| 772 } | 784 } |
| 773 | 785 |
| 774 if (object->IsUndefined() || object->IsNull()) { | 786 if (object->IsUndefined() || object->IsNull()) { |
| 775 return TypeError("non_object_property_call", object, key); | 787 return TypeError("non_object_property_call", object, key); |
| 776 } | 788 } |
| 777 | 789 |
| 778 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | |
| 779 ReceiverToObject(object); | |
| 780 } | |
| 781 | |
| 782 if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) { | 790 if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) { |
| 783 int argc = target()->arguments_count(); | 791 int argc = target()->arguments_count(); |
| 784 InLoopFlag in_loop = target()->ic_in_loop(); | 792 InLoopFlag in_loop = target()->ic_in_loop(); |
| 785 MaybeObject* maybe_code = StubCache::ComputeCallMegamorphic( | 793 MaybeObject* maybe_code = StubCache::ComputeCallMegamorphic( |
| 786 argc, in_loop, Code::KEYED_CALL_IC); | 794 argc, in_loop, Code::KEYED_CALL_IC); |
| 787 Object* code; | 795 Object* code; |
| 788 if (maybe_code->ToObject(&code)) { | 796 if (maybe_code->ToObject(&code)) { |
| 789 set_target(Code::cast(code)); | 797 set_target(Code::cast(code)); |
| 790 #ifdef DEBUG | 798 #ifdef DEBUG |
| 791 TraceIC( | 799 TraceIC( |
| 792 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : ""); | 800 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : ""); |
| 793 #endif | 801 #endif |
| 794 } | 802 } |
| 795 } | 803 } |
| 796 Object* result; | 804 |
| 797 { MaybeObject* maybe_result = Runtime::GetObjectProperty(object, key); | 805 HandleScope scope; |
| 798 if (!maybe_result->ToObject(&result)) return maybe_result; | 806 Handle<Object> result = GetProperty(object, key); |
| 799 } | 807 |
| 800 if (result->IsJSFunction()) return result; | 808 // Make receiver an object if the callee requires it. Strict mode or builtin |
| 801 result = TryCallAsFunction(result); | 809 // functions do not wrap the receiver, non-strict functions and objects |
| 802 MaybeObject* answer = result; | 810 // called as functions do. |
| 803 if (!result->IsJSFunction()) { | 811 ReceiverToObjectIfRequired(result, object); |
| 804 answer = TypeError("property_not_function", object, key); | 812 |
| 805 } | 813 if (result->IsJSFunction()) return *result; |
| 806 return answer; | 814 result = Handle<Object>(TryCallAsFunction(*result)); |
| 815 if (result->IsJSFunction()) return *result; | |
| 816 | |
| 817 return TypeError("property_not_function", object, key); | |
| 807 } | 818 } |
| 808 | 819 |
| 809 | 820 |
| 810 #ifdef DEBUG | 821 #ifdef DEBUG |
| 811 #define TRACE_IC_NAMED(msg, name) \ | 822 #define TRACE_IC_NAMED(msg, name) \ |
| 812 if (FLAG_trace_ic) PrintF(msg, *(name)->ToCString()) | 823 if (FLAG_trace_ic) PrintF(msg, *(name)->ToCString()) |
| 813 #else | 824 #else |
| 814 #define TRACE_IC_NAMED(msg, name) | 825 #define TRACE_IC_NAMED(msg, name) |
| 815 #endif | 826 #endif |
| 816 | 827 |
| (...skipping 1469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2286 #undef ADDR | 2297 #undef ADDR |
| 2287 }; | 2298 }; |
| 2288 | 2299 |
| 2289 | 2300 |
| 2290 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2301 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2291 return IC_utilities[id]; | 2302 return IC_utilities[id]; |
| 2292 } | 2303 } |
| 2293 | 2304 |
| 2294 | 2305 |
| 2295 } } // namespace v8::internal | 2306 } } // namespace v8::internal |
| OLD | NEW |