| 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 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 | 261 |
| 262 | 262 |
| 263 void IC::Clear(Address address) { | 263 void IC::Clear(Address address) { |
| 264 Code* target = GetTargetAtAddress(address); | 264 Code* target = GetTargetAtAddress(address); |
| 265 | 265 |
| 266 // Don't clear debug break inline cache as it will remove the break point. | 266 // Don't clear debug break inline cache as it will remove the break point. |
| 267 if (target->ic_state() == DEBUG_BREAK) return; | 267 if (target->ic_state() == DEBUG_BREAK) return; |
| 268 | 268 |
| 269 switch (target->kind()) { | 269 switch (target->kind()) { |
| 270 case Code::LOAD_IC: return LoadIC::Clear(address, target); | 270 case Code::LOAD_IC: return LoadIC::Clear(address, target); |
| 271 case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target); | 271 case Code::KEYED_LOAD_IC: |
| 272 case Code::KEYED_EXTERNAL_ARRAY_LOAD_IC: |
| 273 return KeyedLoadIC::Clear(address, target); |
| 272 case Code::STORE_IC: return StoreIC::Clear(address, target); | 274 case Code::STORE_IC: return StoreIC::Clear(address, target); |
| 273 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); | 275 case Code::KEYED_STORE_IC: |
| 276 case Code::KEYED_EXTERNAL_ARRAY_STORE_IC: |
| 277 return KeyedStoreIC::Clear(address, target); |
| 274 case Code::CALL_IC: return CallIC::Clear(address, target); | 278 case Code::CALL_IC: return CallIC::Clear(address, target); |
| 275 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); | 279 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); |
| 276 case Code::BINARY_OP_IC: | 280 case Code::BINARY_OP_IC: |
| 277 case Code::TYPE_RECORDING_BINARY_OP_IC: | 281 case Code::TYPE_RECORDING_BINARY_OP_IC: |
| 278 case Code::COMPARE_IC: | 282 case Code::COMPARE_IC: |
| 279 // Clearing these is tricky and does not | 283 // Clearing these is tricky and does not |
| 280 // make any performance difference. | 284 // make any performance difference. |
| 281 return; | 285 return; |
| 282 default: UNREACHABLE(); | 286 default: UNREACHABLE(); |
| 283 } | 287 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 // present) to guarantee failure by holding an invalid map (the null | 340 // present) to guarantee failure by holding an invalid map (the null |
| 337 // value). The offset can be patched to anything. | 341 // value). The offset can be patched to anything. |
| 338 PatchInlinedStore(address, Heap::null_value(), 0); | 342 PatchInlinedStore(address, Heap::null_value(), 0); |
| 339 } | 343 } |
| 340 | 344 |
| 341 | 345 |
| 342 void StoreIC::Clear(Address address, Code* target) { | 346 void StoreIC::Clear(Address address, Code* target) { |
| 343 if (target->ic_state() == UNINITIALIZED) return; | 347 if (target->ic_state() == UNINITIALIZED) return; |
| 344 ClearInlinedVersion(address); | 348 ClearInlinedVersion(address); |
| 345 SetTargetAtAddress(address, | 349 SetTargetAtAddress(address, |
| 346 target->extra_ic_state() == kStoreICStrict | 350 (target->extra_ic_state() == kStrictMode) |
| 347 ? initialize_stub_strict() | 351 ? initialize_stub_strict() |
| 348 : initialize_stub()); | 352 : initialize_stub()); |
| 349 } | 353 } |
| 350 | 354 |
| 351 | 355 |
| 352 void KeyedStoreIC::ClearInlinedVersion(Address address) { | 356 void KeyedStoreIC::ClearInlinedVersion(Address address) { |
| 353 // Insert null as the elements map to check for. This will make | 357 // Insert null as the elements map to check for. This will make |
| 354 // sure that the elements fast-case map check fails so that control | 358 // sure that the elements fast-case map check fails so that control |
| 355 // flows to the IC instead of the inlined version. | 359 // flows to the IC instead of the inlined version. |
| 356 PatchInlinedStore(address, Heap::null_value()); | 360 PatchInlinedStore(address, Heap::null_value()); |
| 357 } | 361 } |
| 358 | 362 |
| 359 | 363 |
| 360 void KeyedStoreIC::RestoreInlinedVersion(Address address) { | 364 void KeyedStoreIC::RestoreInlinedVersion(Address address) { |
| 361 // Restore the fast-case elements map check so that the inlined | 365 // Restore the fast-case elements map check so that the inlined |
| 362 // version can be used again. | 366 // version can be used again. |
| 363 PatchInlinedStore(address, Heap::fixed_array_map()); | 367 PatchInlinedStore(address, Heap::fixed_array_map()); |
| 364 } | 368 } |
| 365 | 369 |
| 366 | 370 |
| 367 void KeyedStoreIC::Clear(Address address, Code* target) { | 371 void KeyedStoreIC::Clear(Address address, Code* target) { |
| 368 if (target->ic_state() == UNINITIALIZED) return; | 372 if (target->ic_state() == UNINITIALIZED) return; |
| 369 SetTargetAtAddress(address, initialize_stub()); | 373 SetTargetAtAddress(address, |
| 374 (target->extra_ic_state() == kStrictMode) |
| 375 ? initialize_stub_strict() |
| 376 : initialize_stub()); |
| 370 } | 377 } |
| 371 | 378 |
| 372 | 379 |
| 373 static bool HasInterceptorGetter(JSObject* object) { | 380 static bool HasInterceptorGetter(JSObject* object) { |
| 374 return !object->GetNamedInterceptor()->getter()->IsUndefined(); | 381 return !object->GetNamedInterceptor()->getter()->IsUndefined(); |
| 375 } | 382 } |
| 376 | 383 |
| 377 | 384 |
| 378 static void LookupForRead(Object* object, | 385 static void LookupForRead(Object* object, |
| 379 String* name, | 386 String* name, |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 StackFrameLocator locator; | 435 StackFrameLocator locator; |
| 429 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 436 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
| 430 int index = frame->ComputeExpressionsCount() - (argc + 1); | 437 int index = frame->ComputeExpressionsCount() - (argc + 1); |
| 431 frame->SetExpression(index, *target); | 438 frame->SetExpression(index, *target); |
| 432 } | 439 } |
| 433 | 440 |
| 434 return *delegate; | 441 return *delegate; |
| 435 } | 442 } |
| 436 | 443 |
| 437 | 444 |
| 438 void CallICBase::ReceiverToObject(Handle<Object> object) { | 445 void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee, |
| 439 HandleScope scope; | 446 Handle<Object> object) { |
| 440 Handle<Object> receiver(object); | 447 if (callee->IsJSFunction()) { |
| 448 Handle<JSFunction> function = Handle<JSFunction>::cast(callee); |
| 449 if (function->shared()->strict_mode() || function->IsBuiltin()) { |
| 450 // Do not wrap receiver for strict mode functions or for builtins. |
| 451 return; |
| 452 } |
| 453 } |
| 441 | 454 |
| 442 // Change the receiver to the result of calling ToObject on it. | 455 // And only wrap string, number or boolean. |
| 443 const int argc = this->target()->arguments_count(); | 456 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
| 444 StackFrameLocator locator; | 457 // Change the receiver to the result of calling ToObject on it. |
| 445 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 458 const int argc = this->target()->arguments_count(); |
| 446 int index = frame->ComputeExpressionsCount() - (argc + 1); | 459 StackFrameLocator locator; |
| 447 frame->SetExpression(index, *Factory::ToObject(object)); | 460 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
| 461 int index = frame->ComputeExpressionsCount() - (argc + 1); |
| 462 frame->SetExpression(index, *Factory::ToObject(object)); |
| 463 } |
| 448 } | 464 } |
| 449 | 465 |
| 450 | 466 |
| 451 MaybeObject* CallICBase::LoadFunction(State state, | 467 MaybeObject* CallICBase::LoadFunction(State state, |
| 452 Code::ExtraICState extra_ic_state, | 468 Code::ExtraICState extra_ic_state, |
| 453 Handle<Object> object, | 469 Handle<Object> object, |
| 454 Handle<String> name) { | 470 Handle<String> name) { |
| 455 // If the object is undefined or null it's illegal to try to get any | 471 // 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. | 472 // of its properties; throw a TypeError in that case. |
| 457 if (object->IsUndefined() || object->IsNull()) { | 473 if (object->IsUndefined() || object->IsNull()) { |
| 458 return TypeError("non_object_property_call", object, name); | 474 return TypeError("non_object_property_call", object, name); |
| 459 } | 475 } |
| 460 | 476 |
| 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 | 477 // Check if the name is trivially convertible to an index and get |
| 466 // the element if so. | 478 // the element if so. |
| 467 uint32_t index; | 479 uint32_t index; |
| 468 if (name->AsArrayIndex(&index)) { | 480 if (name->AsArrayIndex(&index)) { |
| 469 Object* result; | 481 Object* result; |
| 470 { MaybeObject* maybe_result = object->GetElement(index); | 482 { MaybeObject* maybe_result = object->GetElement(index); |
| 471 if (!maybe_result->ToObject(&result)) return maybe_result; | 483 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 472 } | 484 } |
| 473 | 485 |
| 474 if (result->IsJSFunction()) return result; | 486 if (result->IsJSFunction()) return result; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 498 UpdateCaches(&lookup, state, extra_ic_state, object, name); | 510 UpdateCaches(&lookup, state, extra_ic_state, object, name); |
| 499 } | 511 } |
| 500 | 512 |
| 501 // Get the property. | 513 // Get the property. |
| 502 PropertyAttributes attr; | 514 PropertyAttributes attr; |
| 503 Object* result; | 515 Object* result; |
| 504 { MaybeObject* maybe_result = | 516 { MaybeObject* maybe_result = |
| 505 object->GetProperty(*object, &lookup, *name, &attr); | 517 object->GetProperty(*object, &lookup, *name, &attr); |
| 506 if (!maybe_result->ToObject(&result)) return maybe_result; | 518 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 507 } | 519 } |
| 520 |
| 508 if (lookup.type() == INTERCEPTOR) { | 521 if (lookup.type() == INTERCEPTOR) { |
| 509 // If the object does not have the requested property, check which | 522 // If the object does not have the requested property, check which |
| 510 // exception we need to throw. | 523 // exception we need to throw. |
| 511 if (attr == ABSENT) { | 524 if (attr == ABSENT) { |
| 512 if (IsContextual(object)) { | 525 if (IsContextual(object)) { |
| 513 return ReferenceError("not_defined", name); | 526 return ReferenceError("not_defined", name); |
| 514 } | 527 } |
| 515 return TypeError("undefined_method", object, name); | 528 return TypeError("undefined_method", object, name); |
| 516 } | 529 } |
| 517 } | 530 } |
| 518 | 531 |
| 519 ASSERT(result != Heap::the_hole_value()); | 532 ASSERT(!result->IsTheHole()); |
| 520 | 533 |
| 521 if (result->IsJSFunction()) { | 534 HandleScope scope; |
| 535 // Wrap result in a handle because ReceiverToObjectIfRequired may allocate |
| 536 // new object and cause GC. |
| 537 Handle<Object> result_handle(result); |
| 538 // Make receiver an object if the callee requires it. Strict mode or builtin |
| 539 // functions do not wrap the receiver, non-strict functions and objects |
| 540 // called as functions do. |
| 541 ReceiverToObjectIfRequired(result_handle, object); |
| 542 |
| 543 if (result_handle->IsJSFunction()) { |
| 522 #ifdef ENABLE_DEBUGGER_SUPPORT | 544 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 523 // Handle stepping into a function if step into is active. | 545 // Handle stepping into a function if step into is active. |
| 524 if (Debug::StepInActive()) { | 546 if (Debug::StepInActive()) { |
| 525 // Protect the result in a handle as the debugger can allocate and might | 547 // Protect the result in a handle as the debugger can allocate and might |
| 526 // cause GC. | 548 // cause GC. |
| 527 HandleScope scope; | 549 Handle<JSFunction> function(JSFunction::cast(*result_handle)); |
| 528 Handle<JSFunction> function(JSFunction::cast(result)); | |
| 529 Debug::HandleStepIn(function, object, fp(), false); | 550 Debug::HandleStepIn(function, object, fp(), false); |
| 530 return *function; | 551 return *function; |
| 531 } | 552 } |
| 532 #endif | 553 #endif |
| 533 | 554 |
| 534 return result; | 555 return *result_handle; |
| 535 } | 556 } |
| 536 | 557 |
| 537 // Try to find a suitable function delegate for the object at hand. | 558 // Try to find a suitable function delegate for the object at hand. |
| 538 result = TryCallAsFunction(result); | 559 result_handle = Handle<Object>(TryCallAsFunction(*result_handle)); |
| 539 MaybeObject* answer = result; | 560 if (result_handle->IsJSFunction()) return *result_handle; |
| 540 if (!result->IsJSFunction()) { | 561 |
| 541 answer = TypeError("property_not_function", object, name); | 562 return TypeError("property_not_function", object, name); |
| 542 } | |
| 543 return answer; | |
| 544 } | 563 } |
| 545 | 564 |
| 546 | 565 |
| 547 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, | 566 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, |
| 548 Handle<Object> object, | 567 Handle<Object> object, |
| 549 Code::ExtraICState* extra_ic_state) { | 568 Code::ExtraICState* extra_ic_state) { |
| 550 ASSERT(kind_ == Code::CALL_IC); | 569 ASSERT(kind_ == Code::CALL_IC); |
| 551 if (lookup->type() != CONSTANT_FUNCTION) return false; | 570 if (lookup->type() != CONSTANT_FUNCTION) return false; |
| 552 JSFunction* function = lookup->GetConstantFunction(); | 571 JSFunction* function = lookup->GetConstantFunction(); |
| 553 if (!function->shared()->HasBuiltinFunctionId()) return false; | 572 if (!function->shared()->HasBuiltinFunctionId()) return false; |
| 554 | 573 |
| 555 // Fetch the arguments passed to the called function. | 574 // Fetch the arguments passed to the called function. |
| 556 const int argc = target()->arguments_count(); | 575 const int argc = target()->arguments_count(); |
| 557 Address entry = Top::c_entry_fp(Top::GetCurrentThread()); | 576 Address entry = Top::c_entry_fp(Top::GetCurrentThread()); |
| 558 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); | 577 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
| 559 Arguments args(argc + 1, | 578 Arguments args(argc + 1, |
| 560 &Memory::Object_at(fp + | 579 &Memory::Object_at(fp + |
| 561 StandardFrameConstants::kCallerSPOffset + | 580 StandardFrameConstants::kCallerSPOffset + |
| 562 argc * kPointerSize)); | 581 argc * kPointerSize)); |
| 563 switch (function->shared()->builtin_function_id()) { | 582 switch (function->shared()->builtin_function_id()) { |
| 564 case kStringCharCodeAt: | 583 case kStringCharCodeAt: |
| 565 case kStringCharAt: | 584 case kStringCharAt: |
| 566 if (object->IsString()) { | 585 if (object->IsString()) { |
| 567 String* string = String::cast(*object); | 586 String* string = String::cast(*object); |
| 568 // Check that there's the right wrapper in the receiver slot. | 587 // Check there's the right string value or wrapper in the receiver slot. |
| 569 ASSERT(string == JSValue::cast(args[0])->value()); | 588 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value()); |
| 570 // If we're in the default (fastest) state and the index is | 589 // If we're in the default (fastest) state and the index is |
| 571 // out of bounds, update the state to record this fact. | 590 // out of bounds, update the state to record this fact. |
| 572 if (*extra_ic_state == DEFAULT_STRING_STUB && | 591 if (*extra_ic_state == DEFAULT_STRING_STUB && |
| 573 argc >= 1 && args[1]->IsNumber()) { | 592 argc >= 1 && args[1]->IsNumber()) { |
| 574 double index; | 593 double index; |
| 575 if (args[1]->IsSmi()) { | 594 if (args[1]->IsSmi()) { |
| 576 index = Smi::cast(args[1])->value(); | 595 index = Smi::cast(args[1])->value(); |
| 577 } else { | 596 } else { |
| 578 ASSERT(args[1]->IsHeapNumber()); | 597 ASSERT(args[1]->IsHeapNumber()); |
| 579 index = DoubleToInteger(HeapNumber::cast(args[1])->value()); | 598 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, | 787 return CallICBase::LoadFunction(state, |
| 769 Code::kNoExtraICState, | 788 Code::kNoExtraICState, |
| 770 object, | 789 object, |
| 771 Handle<String>::cast(key)); | 790 Handle<String>::cast(key)); |
| 772 } | 791 } |
| 773 | 792 |
| 774 if (object->IsUndefined() || object->IsNull()) { | 793 if (object->IsUndefined() || object->IsNull()) { |
| 775 return TypeError("non_object_property_call", object, key); | 794 return TypeError("non_object_property_call", object, key); |
| 776 } | 795 } |
| 777 | 796 |
| 778 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | |
| 779 ReceiverToObject(object); | |
| 780 } | |
| 781 | |
| 782 if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) { | 797 if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) { |
| 783 int argc = target()->arguments_count(); | 798 int argc = target()->arguments_count(); |
| 784 InLoopFlag in_loop = target()->ic_in_loop(); | 799 InLoopFlag in_loop = target()->ic_in_loop(); |
| 785 MaybeObject* maybe_code = StubCache::ComputeCallMegamorphic( | 800 MaybeObject* maybe_code = StubCache::ComputeCallMegamorphic( |
| 786 argc, in_loop, Code::KEYED_CALL_IC); | 801 argc, in_loop, Code::KEYED_CALL_IC); |
| 787 Object* code; | 802 Object* code; |
| 788 if (maybe_code->ToObject(&code)) { | 803 if (maybe_code->ToObject(&code)) { |
| 789 set_target(Code::cast(code)); | 804 set_target(Code::cast(code)); |
| 790 #ifdef DEBUG | 805 #ifdef DEBUG |
| 791 TraceIC( | 806 TraceIC( |
| 792 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : ""); | 807 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : ""); |
| 793 #endif | 808 #endif |
| 794 } | 809 } |
| 795 } | 810 } |
| 796 Object* result; | 811 |
| 797 { MaybeObject* maybe_result = Runtime::GetObjectProperty(object, key); | 812 HandleScope scope; |
| 798 if (!maybe_result->ToObject(&result)) return maybe_result; | 813 Handle<Object> result = GetProperty(object, key); |
| 799 } | 814 RETURN_IF_EMPTY_HANDLE(result); |
| 800 if (result->IsJSFunction()) return result; | 815 |
| 801 result = TryCallAsFunction(result); | 816 // Make receiver an object if the callee requires it. Strict mode or builtin |
| 802 MaybeObject* answer = result; | 817 // functions do not wrap the receiver, non-strict functions and objects |
| 803 if (!result->IsJSFunction()) { | 818 // called as functions do. |
| 804 answer = TypeError("property_not_function", object, key); | 819 ReceiverToObjectIfRequired(result, object); |
| 805 } | 820 |
| 806 return answer; | 821 if (result->IsJSFunction()) return *result; |
| 822 result = Handle<Object>(TryCallAsFunction(*result)); |
| 823 if (result->IsJSFunction()) return *result; |
| 824 |
| 825 return TypeError("property_not_function", object, key); |
| 807 } | 826 } |
| 808 | 827 |
| 809 | 828 |
| 810 #ifdef DEBUG | 829 #ifdef DEBUG |
| 811 #define TRACE_IC_NAMED(msg, name) \ | 830 #define TRACE_IC_NAMED(msg, name) \ |
| 812 if (FLAG_trace_ic) PrintF(msg, *(name)->ToCString()) | 831 if (FLAG_trace_ic) PrintF(msg, *(name)->ToCString()) |
| 813 #else | 832 #else |
| 814 #define TRACE_IC_NAMED(msg, name) | 833 #define TRACE_IC_NAMED(msg, name) |
| 815 #endif | 834 #endif |
| 816 | 835 |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1208 if (use_ic) { | 1227 if (use_ic) { |
| 1209 Code* stub = generic_stub(); | 1228 Code* stub = generic_stub(); |
| 1210 if (state == UNINITIALIZED) { | 1229 if (state == UNINITIALIZED) { |
| 1211 if (object->IsString() && key->IsNumber()) { | 1230 if (object->IsString() && key->IsNumber()) { |
| 1212 stub = string_stub(); | 1231 stub = string_stub(); |
| 1213 } else if (object->IsJSObject()) { | 1232 } else if (object->IsJSObject()) { |
| 1214 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1233 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1215 if (receiver->HasExternalArrayElements()) { | 1234 if (receiver->HasExternalArrayElements()) { |
| 1216 MaybeObject* probe = | 1235 MaybeObject* probe = |
| 1217 StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, | 1236 StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, |
| 1218 false); | 1237 false, |
| 1238 kNonStrictMode); |
| 1219 stub = probe->IsFailure() ? | 1239 stub = probe->IsFailure() ? |
| 1220 NULL : Code::cast(probe->ToObjectUnchecked()); | 1240 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1221 } else if (receiver->HasIndexedInterceptor()) { | 1241 } else if (receiver->HasIndexedInterceptor()) { |
| 1222 stub = indexed_interceptor_stub(); | 1242 stub = indexed_interceptor_stub(); |
| 1223 } else if (receiver->HasPixelElements()) { | |
| 1224 MaybeObject* probe = | |
| 1225 StubCache::ComputeKeyedLoadPixelArray(*receiver); | |
| 1226 stub = probe->IsFailure() ? | |
| 1227 NULL : Code::cast(probe->ToObjectUnchecked()); | |
| 1228 } else if (key->IsSmi() && | 1243 } else if (key->IsSmi() && |
| 1229 receiver->map()->has_fast_elements()) { | 1244 receiver->map()->has_fast_elements()) { |
| 1230 MaybeObject* probe = | 1245 MaybeObject* probe = |
| 1231 StubCache::ComputeKeyedLoadSpecialized(*receiver); | 1246 StubCache::ComputeKeyedLoadSpecialized(*receiver); |
| 1232 stub = probe->IsFailure() ? | 1247 stub = probe->IsFailure() ? |
| 1233 NULL : Code::cast(probe->ToObjectUnchecked()); | 1248 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1234 } | 1249 } |
| 1235 } | 1250 } |
| 1236 } | 1251 } |
| 1237 if (stub != NULL) set_target(stub); | 1252 if (stub != NULL) set_target(stub); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1364 object->LocalLookupRealNamedProperty(name, lookup); | 1379 object->LocalLookupRealNamedProperty(name, lookup); |
| 1365 return StoreICableLookup(lookup); | 1380 return StoreICableLookup(lookup); |
| 1366 } | 1381 } |
| 1367 } | 1382 } |
| 1368 | 1383 |
| 1369 return true; | 1384 return true; |
| 1370 } | 1385 } |
| 1371 | 1386 |
| 1372 | 1387 |
| 1373 MaybeObject* StoreIC::Store(State state, | 1388 MaybeObject* StoreIC::Store(State state, |
| 1374 Code::ExtraICState extra_ic_state, | 1389 StrictModeFlag strict_mode, |
| 1375 Handle<Object> object, | 1390 Handle<Object> object, |
| 1376 Handle<String> name, | 1391 Handle<String> name, |
| 1377 Handle<Object> value) { | 1392 Handle<Object> value) { |
| 1378 // If the object is undefined or null it's illegal to try to set any | 1393 // If the object is undefined or null it's illegal to try to set any |
| 1379 // properties on it; throw a TypeError in that case. | 1394 // properties on it; throw a TypeError in that case. |
| 1380 if (object->IsUndefined() || object->IsNull()) { | 1395 if (object->IsUndefined() || object->IsNull()) { |
| 1381 return TypeError("non_object_property_store", object, name); | 1396 return TypeError("non_object_property_store", object, name); |
| 1382 } | 1397 } |
| 1383 | 1398 |
| 1384 // Ignore stores where the receiver is not a JSObject. | 1399 if (!object->IsJSObject()) { |
| 1385 if (!object->IsJSObject()) return *value; | 1400 // The length property of string values is read-only. Throw in strict mode. |
| 1401 if (strict_mode == kStrictMode && object->IsString() && |
| 1402 name->Equals(Heap::length_symbol())) { |
| 1403 return TypeError("strict_read_only_property", object, name); |
| 1404 } |
| 1405 // Ignore stores where the receiver is not a JSObject. |
| 1406 return *value; |
| 1407 } |
| 1408 |
| 1386 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1409 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1387 | 1410 |
| 1388 // Check if the given name is an array index. | 1411 // Check if the given name is an array index. |
| 1389 uint32_t index; | 1412 uint32_t index; |
| 1390 if (name->AsArrayIndex(&index)) { | 1413 if (name->AsArrayIndex(&index)) { |
| 1391 HandleScope scope; | 1414 HandleScope scope; |
| 1392 Handle<Object> result = SetElement(receiver, index, value); | 1415 Handle<Object> result = SetElement(receiver, index, value, strict_mode); |
| 1393 if (result.is_null()) return Failure::Exception(); | 1416 if (result.is_null()) return Failure::Exception(); |
| 1394 return *value; | 1417 return *value; |
| 1395 } | 1418 } |
| 1396 | 1419 |
| 1397 // Use specialized code for setting the length of arrays. | 1420 // Use specialized code for setting the length of arrays. |
| 1398 if (receiver->IsJSArray() | 1421 if (receiver->IsJSArray() |
| 1399 && name->Equals(Heap::length_symbol()) | 1422 && name->Equals(Heap::length_symbol()) |
| 1400 && receiver->AllowsSetElementsLength()) { | 1423 && receiver->AllowsSetElementsLength()) { |
| 1401 #ifdef DEBUG | 1424 #ifdef DEBUG |
| 1402 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); | 1425 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); |
| 1403 #endif | 1426 #endif |
| 1404 Builtins::Name target = (extra_ic_state == kStoreICStrict) | 1427 Builtins::Name target = (strict_mode == kStrictMode) |
| 1405 ? Builtins::StoreIC_ArrayLength_Strict | 1428 ? Builtins::StoreIC_ArrayLength_Strict |
| 1406 : Builtins::StoreIC_ArrayLength; | 1429 : Builtins::StoreIC_ArrayLength; |
| 1407 set_target(Builtins::builtin(target)); | 1430 set_target(Builtins::builtin(target)); |
| 1408 return receiver->SetProperty(*name, *value, NONE); | 1431 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1409 } | 1432 } |
| 1410 | 1433 |
| 1411 // Lookup the property locally in the receiver. | 1434 // Lookup the property locally in the receiver. |
| 1412 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { | 1435 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { |
| 1413 LookupResult lookup; | 1436 LookupResult lookup; |
| 1414 | 1437 |
| 1415 if (LookupForWrite(*receiver, *name, &lookup)) { | 1438 if (LookupForWrite(*receiver, *name, &lookup)) { |
| 1416 bool can_be_inlined = | 1439 bool can_be_inlined = |
| 1417 state == UNINITIALIZED && | 1440 state == UNINITIALIZED && |
| 1418 lookup.IsProperty() && | 1441 lookup.IsProperty() && |
| 1419 lookup.holder() == *receiver && | 1442 lookup.holder() == *receiver && |
| 1420 lookup.type() == FIELD && | 1443 lookup.type() == FIELD && |
| 1421 !receiver->IsAccessCheckNeeded(); | 1444 !receiver->IsAccessCheckNeeded(); |
| 1422 | 1445 |
| 1423 if (can_be_inlined) { | 1446 if (can_be_inlined) { |
| 1424 Map* map = lookup.holder()->map(); | 1447 Map* map = lookup.holder()->map(); |
| 1425 // Property's index in the properties array. If negative we have | 1448 // Property's index in the properties array. If negative we have |
| 1426 // an inobject property. | 1449 // an inobject property. |
| 1427 int index = lookup.GetFieldIndex() - map->inobject_properties(); | 1450 int index = lookup.GetFieldIndex() - map->inobject_properties(); |
| 1428 if (index < 0) { | 1451 if (index < 0) { |
| 1429 // Index is an offset from the end of the object. | 1452 // Index is an offset from the end of the object. |
| 1430 int offset = map->instance_size() + (index * kPointerSize); | 1453 int offset = map->instance_size() + (index * kPointerSize); |
| 1431 if (PatchInlinedStore(address(), map, offset)) { | 1454 if (PatchInlinedStore(address(), map, offset)) { |
| 1432 set_target(megamorphic_stub()); | 1455 set_target((strict_mode == kStrictMode) |
| 1456 ? megamorphic_stub_strict() |
| 1457 : megamorphic_stub()); |
| 1433 #ifdef DEBUG | 1458 #ifdef DEBUG |
| 1434 if (FLAG_trace_ic) { | 1459 if (FLAG_trace_ic) { |
| 1435 PrintF("[StoreIC : inline patch %s]\n", *name->ToCString()); | 1460 PrintF("[StoreIC : inline patch %s]\n", *name->ToCString()); |
| 1436 } | 1461 } |
| 1437 #endif | 1462 #endif |
| 1438 return receiver->SetProperty(*name, *value, NONE); | 1463 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1439 #ifdef DEBUG | 1464 #ifdef DEBUG |
| 1440 | 1465 |
| 1441 } else { | 1466 } else { |
| 1442 if (FLAG_trace_ic) { | 1467 if (FLAG_trace_ic) { |
| 1443 PrintF("[StoreIC : no inline patch %s (patching failed)]\n", | 1468 PrintF("[StoreIC : no inline patch %s (patching failed)]\n", |
| 1444 *name->ToCString()); | 1469 *name->ToCString()); |
| 1445 } | 1470 } |
| 1446 } | 1471 } |
| 1447 } else { | 1472 } else { |
| 1448 if (FLAG_trace_ic) { | 1473 if (FLAG_trace_ic) { |
| 1449 PrintF("[StoreIC : no inline patch %s (not inobject)]\n", | 1474 PrintF("[StoreIC : no inline patch %s (not inobject)]\n", |
| 1450 *name->ToCString()); | 1475 *name->ToCString()); |
| 1451 } | 1476 } |
| 1452 } | 1477 } |
| 1453 } else { | 1478 } else { |
| 1454 if (state == PREMONOMORPHIC) { | 1479 if (state == PREMONOMORPHIC) { |
| 1455 if (FLAG_trace_ic) { | 1480 if (FLAG_trace_ic) { |
| 1456 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n", | 1481 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n", |
| 1457 *name->ToCString()); | 1482 *name->ToCString()); |
| 1458 #endif | 1483 #endif |
| 1459 } | 1484 } |
| 1460 } | 1485 } |
| 1461 } | 1486 } |
| 1462 | 1487 |
| 1463 // If no inlined store ic was patched, generate a stub for this | 1488 // If no inlined store ic was patched, generate a stub for this |
| 1464 // store. | 1489 // store. |
| 1465 UpdateCaches(&lookup, state, extra_ic_state, receiver, name, value); | 1490 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
| 1466 } else { | 1491 } else { |
| 1467 // Strict mode doesn't allow setting non-existent global property. | 1492 // Strict mode doesn't allow setting non-existent global property |
| 1468 if (extra_ic_state == kStoreICStrict && IsContextual(object)) { | 1493 // or an assignment to a read only property. |
| 1469 return ReferenceError("not_defined", name); | 1494 if (strict_mode == kStrictMode) { |
| 1495 if (lookup.IsFound() && lookup.IsReadOnly()) { |
| 1496 return TypeError("strict_read_only_property", object, name); |
| 1497 } else if (IsContextual(object)) { |
| 1498 return ReferenceError("not_defined", name); |
| 1499 } |
| 1470 } | 1500 } |
| 1471 } | 1501 } |
| 1472 } | 1502 } |
| 1473 | 1503 |
| 1474 if (receiver->IsJSGlobalProxy()) { | 1504 if (receiver->IsJSGlobalProxy()) { |
| 1475 // Generate a generic stub that goes to the runtime when we see a global | 1505 // Generate a generic stub that goes to the runtime when we see a global |
| 1476 // proxy as receiver. | 1506 // proxy as receiver. |
| 1477 Code* stub = (extra_ic_state == kStoreICStrict) | 1507 Code* stub = (strict_mode == kStrictMode) |
| 1478 ? global_proxy_stub_strict() | 1508 ? global_proxy_stub_strict() |
| 1479 : global_proxy_stub(); | 1509 : global_proxy_stub(); |
| 1480 if (target() != stub) { | 1510 if (target() != stub) { |
| 1481 set_target(stub); | 1511 set_target(stub); |
| 1482 #ifdef DEBUG | 1512 #ifdef DEBUG |
| 1483 TraceIC("StoreIC", name, state, target()); | 1513 TraceIC("StoreIC", name, state, target()); |
| 1484 #endif | 1514 #endif |
| 1485 } | 1515 } |
| 1486 } | 1516 } |
| 1487 | 1517 |
| 1488 // Set the property. | 1518 // Set the property. |
| 1489 return receiver->SetProperty(*name, *value, NONE); | 1519 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1490 } | 1520 } |
| 1491 | 1521 |
| 1492 | 1522 |
| 1493 void StoreIC::UpdateCaches(LookupResult* lookup, | 1523 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 1494 State state, | 1524 State state, |
| 1495 Code::ExtraICState extra_ic_state, | 1525 StrictModeFlag strict_mode, |
| 1496 Handle<JSObject> receiver, | 1526 Handle<JSObject> receiver, |
| 1497 Handle<String> name, | 1527 Handle<String> name, |
| 1498 Handle<Object> value) { | 1528 Handle<Object> value) { |
| 1499 // Skip JSGlobalProxy. | 1529 // Skip JSGlobalProxy. |
| 1500 ASSERT(!receiver->IsJSGlobalProxy()); | 1530 ASSERT(!receiver->IsJSGlobalProxy()); |
| 1501 | 1531 |
| 1502 ASSERT(StoreICableLookup(lookup)); | 1532 ASSERT(StoreICableLookup(lookup)); |
| 1503 | 1533 |
| 1504 // If the property has a non-field type allowing map transitions | 1534 // If the property has a non-field type allowing map transitions |
| 1505 // where there is extra room in the object, we leave the IC in its | 1535 // where there is extra room in the object, we leave the IC in its |
| 1506 // current state. | 1536 // current state. |
| 1507 PropertyType type = lookup->type(); | 1537 PropertyType type = lookup->type(); |
| 1508 | 1538 |
| 1509 // Compute the code stub for this store; used for rewriting to | 1539 // Compute the code stub for this store; used for rewriting to |
| 1510 // monomorphic state and making sure that the code stub is in the | 1540 // monomorphic state and making sure that the code stub is in the |
| 1511 // stub cache. | 1541 // stub cache. |
| 1512 MaybeObject* maybe_code = NULL; | 1542 MaybeObject* maybe_code = NULL; |
| 1513 Object* code = NULL; | 1543 Object* code = NULL; |
| 1514 switch (type) { | 1544 switch (type) { |
| 1515 case FIELD: { | 1545 case FIELD: { |
| 1516 maybe_code = StubCache::ComputeStoreField( | 1546 maybe_code = StubCache::ComputeStoreField( |
| 1517 *name, *receiver, lookup->GetFieldIndex(), NULL, extra_ic_state); | 1547 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); |
| 1518 break; | 1548 break; |
| 1519 } | 1549 } |
| 1520 case MAP_TRANSITION: { | 1550 case MAP_TRANSITION: { |
| 1521 if (lookup->GetAttributes() != NONE) return; | 1551 if (lookup->GetAttributes() != NONE) return; |
| 1522 HandleScope scope; | 1552 HandleScope scope; |
| 1523 ASSERT(type == MAP_TRANSITION); | 1553 ASSERT(type == MAP_TRANSITION); |
| 1524 Handle<Map> transition(lookup->GetTransitionMap()); | 1554 Handle<Map> transition(lookup->GetTransitionMap()); |
| 1525 int index = transition->PropertyIndexFor(*name); | 1555 int index = transition->PropertyIndexFor(*name); |
| 1526 maybe_code = StubCache::ComputeStoreField( | 1556 maybe_code = StubCache::ComputeStoreField( |
| 1527 *name, *receiver, index, *transition, extra_ic_state); | 1557 *name, *receiver, index, *transition, strict_mode); |
| 1528 break; | 1558 break; |
| 1529 } | 1559 } |
| 1530 case NORMAL: { | 1560 case NORMAL: { |
| 1531 if (receiver->IsGlobalObject()) { | 1561 if (receiver->IsGlobalObject()) { |
| 1532 // The stub generated for the global object picks the value directly | 1562 // The stub generated for the global object picks the value directly |
| 1533 // from the property cell. So the property must be directly on the | 1563 // from the property cell. So the property must be directly on the |
| 1534 // global object. | 1564 // global object. |
| 1535 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1565 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1536 JSGlobalPropertyCell* cell = | 1566 JSGlobalPropertyCell* cell = |
| 1537 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | 1567 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); |
| 1538 maybe_code = StubCache::ComputeStoreGlobal( | 1568 maybe_code = StubCache::ComputeStoreGlobal( |
| 1539 *name, *global, cell, extra_ic_state); | 1569 *name, *global, cell, strict_mode); |
| 1540 } else { | 1570 } else { |
| 1541 if (lookup->holder() != *receiver) return; | 1571 if (lookup->holder() != *receiver) return; |
| 1542 maybe_code = StubCache::ComputeStoreNormal(extra_ic_state); | 1572 maybe_code = StubCache::ComputeStoreNormal(strict_mode); |
| 1543 } | 1573 } |
| 1544 break; | 1574 break; |
| 1545 } | 1575 } |
| 1546 case CALLBACKS: { | 1576 case CALLBACKS: { |
| 1547 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 1577 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; |
| 1548 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1578 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); |
| 1549 if (v8::ToCData<Address>(callback->setter()) == 0) return; | 1579 if (v8::ToCData<Address>(callback->setter()) == 0) return; |
| 1550 maybe_code = StubCache::ComputeStoreCallback( | 1580 maybe_code = StubCache::ComputeStoreCallback( |
| 1551 *name, *receiver, callback, extra_ic_state); | 1581 *name, *receiver, callback, strict_mode); |
| 1552 break; | 1582 break; |
| 1553 } | 1583 } |
| 1554 case INTERCEPTOR: { | 1584 case INTERCEPTOR: { |
| 1555 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); | 1585 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); |
| 1556 maybe_code = StubCache::ComputeStoreInterceptor( | 1586 maybe_code = StubCache::ComputeStoreInterceptor( |
| 1557 *name, *receiver, extra_ic_state); | 1587 *name, *receiver, strict_mode); |
| 1558 break; | 1588 break; |
| 1559 } | 1589 } |
| 1560 default: | 1590 default: |
| 1561 return; | 1591 return; |
| 1562 } | 1592 } |
| 1563 | 1593 |
| 1564 // If we're unable to compute the stub (not enough memory left), we | 1594 // If we're unable to compute the stub (not enough memory left), we |
| 1565 // simply avoid updating the caches. | 1595 // simply avoid updating the caches. |
| 1566 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 1596 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
| 1567 | 1597 |
| 1568 // Patch the call site depending on the state of the cache. | 1598 // Patch the call site depending on the state of the cache. |
| 1569 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 1599 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
| 1570 set_target(Code::cast(code)); | 1600 set_target(Code::cast(code)); |
| 1571 } else if (state == MONOMORPHIC) { | 1601 } else if (state == MONOMORPHIC) { |
| 1572 // Only move to megamorphic if the target changes. | 1602 // Only move to megamorphic if the target changes. |
| 1573 if (target() != Code::cast(code)) { | 1603 if (target() != Code::cast(code)) { |
| 1574 set_target(extra_ic_state == kStoreICStrict | 1604 set_target((strict_mode == kStrictMode) |
| 1575 ? megamorphic_stub_strict() | 1605 ? megamorphic_stub_strict() |
| 1576 : megamorphic_stub()); | 1606 : megamorphic_stub()); |
| 1577 } | 1607 } |
| 1578 } else if (state == MEGAMORPHIC) { | 1608 } else if (state == MEGAMORPHIC) { |
| 1579 // Update the stub cache. | 1609 // Update the stub cache. |
| 1580 StubCache::Set(*name, receiver->map(), Code::cast(code)); | 1610 StubCache::Set(*name, receiver->map(), Code::cast(code)); |
| 1581 } | 1611 } |
| 1582 | 1612 |
| 1583 #ifdef DEBUG | 1613 #ifdef DEBUG |
| 1584 TraceIC("StoreIC", name, state, target()); | 1614 TraceIC("StoreIC", name, state, target()); |
| 1585 #endif | 1615 #endif |
| 1586 } | 1616 } |
| 1587 | 1617 |
| 1588 | 1618 |
| 1589 MaybeObject* KeyedStoreIC::Store(State state, | 1619 MaybeObject* KeyedStoreIC::Store(State state, |
| 1620 StrictModeFlag strict_mode, |
| 1590 Handle<Object> object, | 1621 Handle<Object> object, |
| 1591 Handle<Object> key, | 1622 Handle<Object> key, |
| 1592 Handle<Object> value) { | 1623 Handle<Object> value) { |
| 1593 if (key->IsSymbol()) { | 1624 if (key->IsSymbol()) { |
| 1594 Handle<String> name = Handle<String>::cast(key); | 1625 Handle<String> name = Handle<String>::cast(key); |
| 1595 | 1626 |
| 1596 // If the object is undefined or null it's illegal to try to set any | 1627 // If the object is undefined or null it's illegal to try to set any |
| 1597 // properties on it; throw a TypeError in that case. | 1628 // properties on it; throw a TypeError in that case. |
| 1598 if (object->IsUndefined() || object->IsNull()) { | 1629 if (object->IsUndefined() || object->IsNull()) { |
| 1599 return TypeError("non_object_property_store", object, name); | 1630 return TypeError("non_object_property_store", object, name); |
| 1600 } | 1631 } |
| 1601 | 1632 |
| 1602 // Ignore stores where the receiver is not a JSObject. | 1633 // Ignore stores where the receiver is not a JSObject. |
| 1603 if (!object->IsJSObject()) return *value; | 1634 if (!object->IsJSObject()) return *value; |
| 1604 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1635 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1605 | 1636 |
| 1606 // Check if the given name is an array index. | 1637 // Check if the given name is an array index. |
| 1607 uint32_t index; | 1638 uint32_t index; |
| 1608 if (name->AsArrayIndex(&index)) { | 1639 if (name->AsArrayIndex(&index)) { |
| 1609 HandleScope scope; | 1640 HandleScope scope; |
| 1610 Handle<Object> result = SetElement(receiver, index, value); | 1641 Handle<Object> result = SetElement(receiver, index, value, strict_mode); |
| 1611 if (result.is_null()) return Failure::Exception(); | 1642 if (result.is_null()) return Failure::Exception(); |
| 1612 return *value; | 1643 return *value; |
| 1613 } | 1644 } |
| 1614 | 1645 |
| 1615 // Lookup the property locally in the receiver. | 1646 // Lookup the property locally in the receiver. |
| 1616 LookupResult lookup; | 1647 LookupResult lookup; |
| 1617 receiver->LocalLookup(*name, &lookup); | 1648 receiver->LocalLookup(*name, &lookup); |
| 1618 | 1649 |
| 1619 // Update inline cache and stub cache. | 1650 // Update inline cache and stub cache. |
| 1620 if (FLAG_use_ic) { | 1651 if (FLAG_use_ic) { |
| 1621 UpdateCaches(&lookup, state, receiver, name, value); | 1652 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
| 1622 } | 1653 } |
| 1623 | 1654 |
| 1624 // Set the property. | 1655 // Set the property. |
| 1625 return receiver->SetProperty(*name, *value, NONE); | 1656 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1626 } | 1657 } |
| 1627 | 1658 |
| 1628 // Do not use ICs for objects that require access checks (including | 1659 // Do not use ICs for objects that require access checks (including |
| 1629 // the global object). | 1660 // the global object). |
| 1630 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1661 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 1631 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1662 ASSERT(!(use_ic && object->IsJSGlobalProxy())); |
| 1632 | 1663 |
| 1633 if (use_ic) { | 1664 if (use_ic) { |
| 1634 Code* stub = generic_stub(); | 1665 Code* stub = |
| 1666 (strict_mode == kStrictMode) ? generic_stub_strict() : generic_stub(); |
| 1635 if (state == UNINITIALIZED) { | 1667 if (state == UNINITIALIZED) { |
| 1636 if (object->IsJSObject()) { | 1668 if (object->IsJSObject()) { |
| 1637 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1669 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1638 if (receiver->HasExternalArrayElements()) { | 1670 if (receiver->HasExternalArrayElements()) { |
| 1639 MaybeObject* probe = | 1671 MaybeObject* probe = |
| 1640 StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, true); | 1672 StubCache::ComputeKeyedLoadOrStoreExternalArray( |
| 1641 stub = probe->IsFailure() ? | 1673 *receiver, true, strict_mode); |
| 1642 NULL : Code::cast(probe->ToObjectUnchecked()); | |
| 1643 } else if (receiver->HasPixelElements()) { | |
| 1644 MaybeObject* probe = | |
| 1645 StubCache::ComputeKeyedStorePixelArray(*receiver); | |
| 1646 stub = probe->IsFailure() ? | 1674 stub = probe->IsFailure() ? |
| 1647 NULL : Code::cast(probe->ToObjectUnchecked()); | 1675 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1648 } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { | 1676 } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { |
| 1649 MaybeObject* probe = | 1677 MaybeObject* probe = |
| 1650 StubCache::ComputeKeyedStoreSpecialized(*receiver); | 1678 StubCache::ComputeKeyedStoreSpecialized(*receiver, strict_mode); |
| 1651 stub = probe->IsFailure() ? | 1679 stub = probe->IsFailure() ? |
| 1652 NULL : Code::cast(probe->ToObjectUnchecked()); | 1680 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1653 } | 1681 } |
| 1654 } | 1682 } |
| 1655 } | 1683 } |
| 1656 if (stub != NULL) set_target(stub); | 1684 if (stub != NULL) set_target(stub); |
| 1657 } | 1685 } |
| 1658 | 1686 |
| 1659 // Set the property. | 1687 // Set the property. |
| 1660 return Runtime::SetObjectProperty(object, key, value, NONE); | 1688 return Runtime::SetObjectProperty(object, key, value, NONE, strict_mode); |
| 1661 } | 1689 } |
| 1662 | 1690 |
| 1663 | 1691 |
| 1664 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, | 1692 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, |
| 1665 State state, | 1693 State state, |
| 1694 StrictModeFlag strict_mode, |
| 1666 Handle<JSObject> receiver, | 1695 Handle<JSObject> receiver, |
| 1667 Handle<String> name, | 1696 Handle<String> name, |
| 1668 Handle<Object> value) { | 1697 Handle<Object> value) { |
| 1669 // Skip JSGlobalProxy. | 1698 // Skip JSGlobalProxy. |
| 1670 if (receiver->IsJSGlobalProxy()) return; | 1699 if (receiver->IsJSGlobalProxy()) return; |
| 1671 | 1700 |
| 1672 // Bail out if we didn't find a result. | 1701 // Bail out if we didn't find a result. |
| 1673 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return; | 1702 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return; |
| 1674 | 1703 |
| 1675 // If the property is read-only, we leave the IC in its current | 1704 // If the property is read-only, we leave the IC in its current |
| 1676 // state. | 1705 // state. |
| 1677 if (lookup->IsReadOnly()) return; | 1706 if (lookup->IsReadOnly()) return; |
| 1678 | 1707 |
| 1679 // If the property has a non-field type allowing map transitions | 1708 // If the property has a non-field type allowing map transitions |
| 1680 // where there is extra room in the object, we leave the IC in its | 1709 // where there is extra room in the object, we leave the IC in its |
| 1681 // current state. | 1710 // current state. |
| 1682 PropertyType type = lookup->type(); | 1711 PropertyType type = lookup->type(); |
| 1683 | 1712 |
| 1684 // Compute the code stub for this store; used for rewriting to | 1713 // Compute the code stub for this store; used for rewriting to |
| 1685 // monomorphic state and making sure that the code stub is in the | 1714 // monomorphic state and making sure that the code stub is in the |
| 1686 // stub cache. | 1715 // stub cache. |
| 1687 MaybeObject* maybe_code = NULL; | 1716 MaybeObject* maybe_code = NULL; |
| 1688 Object* code = NULL; | 1717 Object* code = NULL; |
| 1689 | 1718 |
| 1690 switch (type) { | 1719 switch (type) { |
| 1691 case FIELD: { | 1720 case FIELD: { |
| 1692 maybe_code = StubCache::ComputeKeyedStoreField(*name, *receiver, | 1721 maybe_code = StubCache::ComputeKeyedStoreField( |
| 1693 lookup->GetFieldIndex()); | 1722 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); |
| 1694 break; | 1723 break; |
| 1695 } | 1724 } |
| 1696 case MAP_TRANSITION: { | 1725 case MAP_TRANSITION: { |
| 1697 if (lookup->GetAttributes() == NONE) { | 1726 if (lookup->GetAttributes() == NONE) { |
| 1698 HandleScope scope; | 1727 HandleScope scope; |
| 1699 ASSERT(type == MAP_TRANSITION); | 1728 ASSERT(type == MAP_TRANSITION); |
| 1700 Handle<Map> transition(lookup->GetTransitionMap()); | 1729 Handle<Map> transition(lookup->GetTransitionMap()); |
| 1701 int index = transition->PropertyIndexFor(*name); | 1730 int index = transition->PropertyIndexFor(*name); |
| 1702 maybe_code = StubCache::ComputeKeyedStoreField(*name, *receiver, | 1731 maybe_code = StubCache::ComputeKeyedStoreField( |
| 1703 index, *transition); | 1732 *name, *receiver, index, *transition, strict_mode); |
| 1704 break; | 1733 break; |
| 1705 } | 1734 } |
| 1706 // fall through. | 1735 // fall through. |
| 1707 } | 1736 } |
| 1708 default: { | 1737 default: { |
| 1709 // Always rewrite to the generic case so that we do not | 1738 // Always rewrite to the generic case so that we do not |
| 1710 // repeatedly try to rewrite. | 1739 // repeatedly try to rewrite. |
| 1711 maybe_code = generic_stub(); | 1740 maybe_code = (strict_mode == kStrictMode) |
| 1741 ? generic_stub_strict() |
| 1742 : generic_stub(); |
| 1712 break; | 1743 break; |
| 1713 } | 1744 } |
| 1714 } | 1745 } |
| 1715 | 1746 |
| 1716 // If we're unable to compute the stub (not enough memory left), we | 1747 // If we're unable to compute the stub (not enough memory left), we |
| 1717 // simply avoid updating the caches. | 1748 // simply avoid updating the caches. |
| 1718 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 1749 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
| 1719 | 1750 |
| 1720 // Patch the call site depending on the state of the cache. Make | 1751 // Patch the call site depending on the state of the cache. Make |
| 1721 // sure to always rewrite from monomorphic to megamorphic. | 1752 // sure to always rewrite from monomorphic to megamorphic. |
| 1722 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); | 1753 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); |
| 1723 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { | 1754 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { |
| 1724 set_target(Code::cast(code)); | 1755 set_target(Code::cast(code)); |
| 1725 } else if (state == MONOMORPHIC) { | 1756 } else if (state == MONOMORPHIC) { |
| 1726 set_target(megamorphic_stub()); | 1757 set_target((strict_mode == kStrictMode) |
| 1758 ? megamorphic_stub_strict() |
| 1759 : megamorphic_stub()); |
| 1727 } | 1760 } |
| 1728 | 1761 |
| 1729 #ifdef DEBUG | 1762 #ifdef DEBUG |
| 1730 TraceIC("KeyedStoreIC", name, state, target()); | 1763 TraceIC("KeyedStoreIC", name, state, target()); |
| 1731 #endif | 1764 #endif |
| 1732 } | 1765 } |
| 1733 | 1766 |
| 1734 | 1767 |
| 1735 // ---------------------------------------------------------------------------- | 1768 // ---------------------------------------------------------------------------- |
| 1736 // Static IC stub generators. | 1769 // Static IC stub generators. |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1817 } | 1850 } |
| 1818 | 1851 |
| 1819 | 1852 |
| 1820 // Used from ic-<arch>.cc. | 1853 // Used from ic-<arch>.cc. |
| 1821 MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { | 1854 MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { |
| 1822 NoHandleAllocation na; | 1855 NoHandleAllocation na; |
| 1823 ASSERT(args.length() == 3); | 1856 ASSERT(args.length() == 3); |
| 1824 StoreIC ic; | 1857 StoreIC ic; |
| 1825 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1858 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1826 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); | 1859 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1827 return ic.Store(state, extra_ic_state, args.at<Object>(0), | 1860 return ic.Store(state, |
| 1828 args.at<String>(1), args.at<Object>(2)); | 1861 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
| 1862 args.at<Object>(0), |
| 1863 args.at<String>(1), |
| 1864 args.at<Object>(2)); |
| 1829 } | 1865 } |
| 1830 | 1866 |
| 1831 | 1867 |
| 1832 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) { | 1868 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) { |
| 1833 NoHandleAllocation nha; | 1869 NoHandleAllocation nha; |
| 1834 | 1870 |
| 1835 ASSERT(args.length() == 2); | 1871 ASSERT(args.length() == 2); |
| 1836 JSObject* receiver = JSObject::cast(args[0]); | 1872 JSObject* receiver = JSObject::cast(args[0]); |
| 1837 Object* len = args[1]; | 1873 Object* len = args[1]; |
| 1838 | 1874 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1882 return value; | 1918 return value; |
| 1883 } | 1919 } |
| 1884 | 1920 |
| 1885 | 1921 |
| 1886 // Used from ic-<arch>.cc. | 1922 // Used from ic-<arch>.cc. |
| 1887 MUST_USE_RESULT MaybeObject* KeyedStoreIC_Miss(Arguments args) { | 1923 MUST_USE_RESULT MaybeObject* KeyedStoreIC_Miss(Arguments args) { |
| 1888 NoHandleAllocation na; | 1924 NoHandleAllocation na; |
| 1889 ASSERT(args.length() == 3); | 1925 ASSERT(args.length() == 3); |
| 1890 KeyedStoreIC ic; | 1926 KeyedStoreIC ic; |
| 1891 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1927 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1892 return ic.Store(state, args.at<Object>(0), args.at<Object>(1), | 1928 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1929 return ic.Store(state, |
| 1930 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
| 1931 args.at<Object>(0), |
| 1932 args.at<Object>(1), |
| 1893 args.at<Object>(2)); | 1933 args.at<Object>(2)); |
| 1894 } | 1934 } |
| 1895 | 1935 |
| 1896 | 1936 |
| 1897 void BinaryOpIC::patch(Code* code) { | 1937 void BinaryOpIC::patch(Code* code) { |
| 1898 set_target(code); | 1938 set_target(code); |
| 1899 } | 1939 } |
| 1900 | 1940 |
| 1901 | 1941 |
| 1902 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 1942 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2286 #undef ADDR | 2326 #undef ADDR |
| 2287 }; | 2327 }; |
| 2288 | 2328 |
| 2289 | 2329 |
| 2290 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2330 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2291 return IC_utilities[id]; | 2331 return IC_utilities[id]; |
| 2292 } | 2332 } |
| 2293 | 2333 |
| 2294 | 2334 |
| 2295 } } // namespace v8::internal | 2335 } } // namespace v8::internal |
| OLD | NEW |