| 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 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 // Reset the map check of the inlined inobject property store (if | 342 // Reset the map check of the inlined inobject property store (if |
| 343 // present) to guarantee failure by holding an invalid map (the null | 343 // present) to guarantee failure by holding an invalid map (the null |
| 344 // value). The offset can be patched to anything. | 344 // value). The offset can be patched to anything. |
| 345 PatchInlinedStore(address, HEAP->null_value(), 0); | 345 PatchInlinedStore(address, HEAP->null_value(), 0); |
| 346 } | 346 } |
| 347 | 347 |
| 348 | 348 |
| 349 void StoreIC::Clear(Address address, Code* target) { | 349 void StoreIC::Clear(Address address, Code* target) { |
| 350 if (target->ic_state() == UNINITIALIZED) return; | 350 if (target->ic_state() == UNINITIALIZED) return; |
| 351 ClearInlinedVersion(address); | 351 ClearInlinedVersion(address); |
| 352 SetTargetAtAddress(address, initialize_stub()); | 352 SetTargetAtAddress(address, |
| 353 (target->extra_ic_state() == kStrictMode) |
| 354 ? initialize_stub_strict() |
| 355 : initialize_stub()); |
| 353 } | 356 } |
| 354 | 357 |
| 355 | 358 |
| 356 void KeyedStoreIC::ClearInlinedVersion(Address address) { | 359 void KeyedStoreIC::ClearInlinedVersion(Address address) { |
| 357 // Insert null as the elements map to check for. This will make | 360 // Insert null as the elements map to check for. This will make |
| 358 // sure that the elements fast-case map check fails so that control | 361 // sure that the elements fast-case map check fails so that control |
| 359 // flows to the IC instead of the inlined version. | 362 // flows to the IC instead of the inlined version. |
| 360 PatchInlinedStore(address, HEAP->null_value()); | 363 PatchInlinedStore(address, HEAP->null_value()); |
| 361 } | 364 } |
| 362 | 365 |
| 363 | 366 |
| 364 void KeyedStoreIC::RestoreInlinedVersion(Address address) { | 367 void KeyedStoreIC::RestoreInlinedVersion(Address address) { |
| 365 // Restore the fast-case elements map check so that the inlined | 368 // Restore the fast-case elements map check so that the inlined |
| 366 // version can be used again. | 369 // version can be used again. |
| 367 PatchInlinedStore(address, HEAP->fixed_array_map()); | 370 PatchInlinedStore(address, HEAP->fixed_array_map()); |
| 368 } | 371 } |
| 369 | 372 |
| 370 | 373 |
| 371 void KeyedStoreIC::Clear(Address address, Code* target) { | 374 void KeyedStoreIC::Clear(Address address, Code* target) { |
| 372 if (target->ic_state() == UNINITIALIZED) return; | 375 if (target->ic_state() == UNINITIALIZED) return; |
| 373 SetTargetAtAddress(address, initialize_stub()); | 376 SetTargetAtAddress(address, |
| 377 (target->extra_ic_state() == kStrictMode) |
| 378 ? initialize_stub_strict() |
| 379 : initialize_stub()); |
| 374 } | 380 } |
| 375 | 381 |
| 376 | 382 |
| 377 static bool HasInterceptorGetter(JSObject* object) { | 383 static bool HasInterceptorGetter(JSObject* object) { |
| 378 return !object->GetNamedInterceptor()->getter()->IsUndefined(); | 384 return !object->GetNamedInterceptor()->getter()->IsUndefined(); |
| 379 } | 385 } |
| 380 | 386 |
| 381 | 387 |
| 382 static void LookupForRead(Object* object, | 388 static void LookupForRead(Object* object, |
| 383 String* name, | 389 String* name, |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 StackFrameLocator locator; | 438 StackFrameLocator locator; |
| 433 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 439 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
| 434 int index = frame->ComputeExpressionsCount() - (argc + 1); | 440 int index = frame->ComputeExpressionsCount() - (argc + 1); |
| 435 frame->SetExpression(index, *target); | 441 frame->SetExpression(index, *target); |
| 436 } | 442 } |
| 437 | 443 |
| 438 return *delegate; | 444 return *delegate; |
| 439 } | 445 } |
| 440 | 446 |
| 441 | 447 |
| 442 void CallICBase::ReceiverToObject(Handle<Object> object) { | 448 void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee, |
| 443 HandleScope scope(isolate()); | 449 Handle<Object> object) { |
| 444 Handle<Object> receiver = object; | 450 if (callee->IsJSFunction()) { |
| 451 Handle<JSFunction> function = Handle<JSFunction>::cast(callee); |
| 452 if (function->shared()->strict_mode() || function->IsBuiltin()) { |
| 453 // Do not wrap receiver for strict mode functions or for builtins. |
| 454 return; |
| 455 } |
| 456 } |
| 445 | 457 |
| 446 // Change the receiver to the result of calling ToObject on it. | 458 // And only wrap string, number or boolean. |
| 447 const int argc = this->target()->arguments_count(); | 459 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
| 448 StackFrameLocator locator; | 460 // Change the receiver to the result of calling ToObject on it. |
| 449 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 461 const int argc = this->target()->arguments_count(); |
| 450 int index = frame->ComputeExpressionsCount() - (argc + 1); | 462 StackFrameLocator locator; |
| 451 frame->SetExpression(index, *isolate()->factory()->ToObject(object)); | 463 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
| 464 int index = frame->ComputeExpressionsCount() - (argc + 1); |
| 465 frame->SetExpression(index, *isolate()->factory()->ToObject(object)); |
| 466 } |
| 452 } | 467 } |
| 453 | 468 |
| 454 | 469 |
| 455 MaybeObject* CallICBase::LoadFunction(State state, | 470 MaybeObject* CallICBase::LoadFunction(State state, |
| 456 Code::ExtraICState extra_ic_state, | 471 Code::ExtraICState extra_ic_state, |
| 457 Handle<Object> object, | 472 Handle<Object> object, |
| 458 Handle<String> name) { | 473 Handle<String> name) { |
| 459 // If the object is undefined or null it's illegal to try to get any | 474 // If the object is undefined or null it's illegal to try to get any |
| 460 // of its properties; throw a TypeError in that case. | 475 // of its properties; throw a TypeError in that case. |
| 461 if (object->IsUndefined() || object->IsNull()) { | 476 if (object->IsUndefined() || object->IsNull()) { |
| 462 return TypeError("non_object_property_call", object, name); | 477 return TypeError("non_object_property_call", object, name); |
| 463 } | 478 } |
| 464 | 479 |
| 465 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | |
| 466 ReceiverToObject(object); | |
| 467 } | |
| 468 | |
| 469 // Check if the name is trivially convertible to an index and get | 480 // Check if the name is trivially convertible to an index and get |
| 470 // the element if so. | 481 // the element if so. |
| 471 uint32_t index; | 482 uint32_t index; |
| 472 if (name->AsArrayIndex(&index)) { | 483 if (name->AsArrayIndex(&index)) { |
| 473 Object* result; | 484 Object* result; |
| 474 { MaybeObject* maybe_result = object->GetElement(index); | 485 { MaybeObject* maybe_result = object->GetElement(index); |
| 475 if (!maybe_result->ToObject(&result)) return maybe_result; | 486 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 476 } | 487 } |
| 477 | 488 |
| 478 if (result->IsJSFunction()) return result; | 489 if (result->IsJSFunction()) return result; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 502 UpdateCaches(&lookup, state, extra_ic_state, object, name); | 513 UpdateCaches(&lookup, state, extra_ic_state, object, name); |
| 503 } | 514 } |
| 504 | 515 |
| 505 // Get the property. | 516 // Get the property. |
| 506 PropertyAttributes attr; | 517 PropertyAttributes attr; |
| 507 Object* result; | 518 Object* result; |
| 508 { MaybeObject* maybe_result = | 519 { MaybeObject* maybe_result = |
| 509 object->GetProperty(*object, &lookup, *name, &attr); | 520 object->GetProperty(*object, &lookup, *name, &attr); |
| 510 if (!maybe_result->ToObject(&result)) return maybe_result; | 521 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 511 } | 522 } |
| 523 |
| 512 if (lookup.type() == INTERCEPTOR) { | 524 if (lookup.type() == INTERCEPTOR) { |
| 513 // If the object does not have the requested property, check which | 525 // If the object does not have the requested property, check which |
| 514 // exception we need to throw. | 526 // exception we need to throw. |
| 515 if (attr == ABSENT) { | 527 if (attr == ABSENT) { |
| 516 if (IsContextual(object)) { | 528 if (IsContextual(object)) { |
| 517 return ReferenceError("not_defined", name); | 529 return ReferenceError("not_defined", name); |
| 518 } | 530 } |
| 519 return TypeError("undefined_method", object, name); | 531 return TypeError("undefined_method", object, name); |
| 520 } | 532 } |
| 521 } | 533 } |
| 522 | 534 |
| 523 ASSERT(result != isolate()->heap()->the_hole_value()); | 535 ASSERT(!result->IsTheHole()); |
| 524 | 536 |
| 525 if (result->IsJSFunction()) { | 537 HandleScope scope(isolate()); |
| 538 // Wrap result in a handle because ReceiverToObjectIfRequired may allocate |
| 539 // new object and cause GC. |
| 540 Handle<Object> result_handle(result); |
| 541 // Make receiver an object if the callee requires it. Strict mode or builtin |
| 542 // functions do not wrap the receiver, non-strict functions and objects |
| 543 // called as functions do. |
| 544 ReceiverToObjectIfRequired(result_handle, object); |
| 545 |
| 546 if (result_handle->IsJSFunction()) { |
| 526 #ifdef ENABLE_DEBUGGER_SUPPORT | 547 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 527 // Handle stepping into a function if step into is active. | 548 // Handle stepping into a function if step into is active. |
| 528 Debug* debug = isolate()->debug(); | 549 Debug* debug = isolate()->debug(); |
| 529 if (debug->StepInActive()) { | 550 if (debug->StepInActive()) { |
| 530 // Protect the result in a handle as the debugger can allocate and might | 551 // Protect the result in a handle as the debugger can allocate and might |
| 531 // cause GC. | 552 // cause GC. |
| 532 HandleScope scope(isolate()); | 553 Handle<JSFunction> function(JSFunction::cast(*result_handle), isolate()); |
| 533 Handle<JSFunction> function(JSFunction::cast(result), isolate()); | |
| 534 debug->HandleStepIn(function, object, fp(), false); | 554 debug->HandleStepIn(function, object, fp(), false); |
| 535 return *function; | 555 return *function; |
| 536 } | 556 } |
| 537 #endif | 557 #endif |
| 538 | 558 |
| 539 return result; | 559 return *result_handle; |
| 540 } | 560 } |
| 541 | 561 |
| 542 // Try to find a suitable function delegate for the object at hand. | 562 // Try to find a suitable function delegate for the object at hand. |
| 543 result = TryCallAsFunction(result); | 563 result_handle = Handle<Object>(TryCallAsFunction(*result_handle)); |
| 544 MaybeObject* answer = result; | 564 if (result_handle->IsJSFunction()) return *result_handle; |
| 545 if (!result->IsJSFunction()) { | 565 |
| 546 answer = TypeError("property_not_function", object, name); | 566 return TypeError("property_not_function", object, name); |
| 547 } | |
| 548 return answer; | |
| 549 } | 567 } |
| 550 | 568 |
| 551 | 569 |
| 552 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, | 570 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, |
| 553 Handle<Object> object, | 571 Handle<Object> object, |
| 554 Code::ExtraICState* extra_ic_state) { | 572 Code::ExtraICState* extra_ic_state) { |
| 555 ASSERT(kind_ == Code::CALL_IC); | 573 ASSERT(kind_ == Code::CALL_IC); |
| 556 if (lookup->type() != CONSTANT_FUNCTION) return false; | 574 if (lookup->type() != CONSTANT_FUNCTION) return false; |
| 557 JSFunction* function = lookup->GetConstantFunction(); | 575 JSFunction* function = lookup->GetConstantFunction(); |
| 558 if (!function->shared()->HasBuiltinFunctionId()) return false; | 576 if (!function->shared()->HasBuiltinFunctionId()) return false; |
| 559 | 577 |
| 560 // Fetch the arguments passed to the called function. | 578 // Fetch the arguments passed to the called function. |
| 561 const int argc = target()->arguments_count(); | 579 const int argc = target()->arguments_count(); |
| 562 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top()); | 580 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top()); |
| 563 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); | 581 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
| 564 Arguments args(argc + 1, | 582 Arguments args(argc + 1, |
| 565 &Memory::Object_at(fp + | 583 &Memory::Object_at(fp + |
| 566 StandardFrameConstants::kCallerSPOffset + | 584 StandardFrameConstants::kCallerSPOffset + |
| 567 argc * kPointerSize)); | 585 argc * kPointerSize)); |
| 568 switch (function->shared()->builtin_function_id()) { | 586 switch (function->shared()->builtin_function_id()) { |
| 569 case kStringCharCodeAt: | 587 case kStringCharCodeAt: |
| 570 case kStringCharAt: | 588 case kStringCharAt: |
| 571 if (object->IsString()) { | 589 if (object->IsString()) { |
| 572 String* string = String::cast(*object); | 590 String* string = String::cast(*object); |
| 573 // Check that there's the right wrapper in the receiver slot. | 591 // Check there's the right string value or wrapper in the receiver slot. |
| 574 ASSERT(string == JSValue::cast(args[0])->value()); | 592 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value()); |
| 575 // If we're in the default (fastest) state and the index is | 593 // If we're in the default (fastest) state and the index is |
| 576 // out of bounds, update the state to record this fact. | 594 // out of bounds, update the state to record this fact. |
| 577 if (*extra_ic_state == DEFAULT_STRING_STUB && | 595 if (*extra_ic_state == DEFAULT_STRING_STUB && |
| 578 argc >= 1 && args[1]->IsNumber()) { | 596 argc >= 1 && args[1]->IsNumber()) { |
| 579 double index; | 597 double index; |
| 580 if (args[1]->IsSmi()) { | 598 if (args[1]->IsSmi()) { |
| 581 index = Smi::cast(args[1])->value(); | 599 index = Smi::cast(args[1])->value(); |
| 582 } else { | 600 } else { |
| 583 ASSERT(args[1]->IsHeapNumber()); | 601 ASSERT(args[1]->IsHeapNumber()); |
| 584 index = DoubleToInteger(HeapNumber::cast(args[1])->value()); | 602 index = DoubleToInteger(HeapNumber::cast(args[1])->value()); |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 780 return CallICBase::LoadFunction(state, | 798 return CallICBase::LoadFunction(state, |
| 781 Code::kNoExtraICState, | 799 Code::kNoExtraICState, |
| 782 object, | 800 object, |
| 783 Handle<String>::cast(key)); | 801 Handle<String>::cast(key)); |
| 784 } | 802 } |
| 785 | 803 |
| 786 if (object->IsUndefined() || object->IsNull()) { | 804 if (object->IsUndefined() || object->IsNull()) { |
| 787 return TypeError("non_object_property_call", object, key); | 805 return TypeError("non_object_property_call", object, key); |
| 788 } | 806 } |
| 789 | 807 |
| 790 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | |
| 791 ReceiverToObject(object); | |
| 792 } | |
| 793 | |
| 794 if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) { | 808 if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) { |
| 795 int argc = target()->arguments_count(); | 809 int argc = target()->arguments_count(); |
| 796 InLoopFlag in_loop = target()->ic_in_loop(); | 810 InLoopFlag in_loop = target()->ic_in_loop(); |
| 797 MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic( | 811 MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic( |
| 798 argc, in_loop, Code::KEYED_CALL_IC); | 812 argc, in_loop, Code::KEYED_CALL_IC); |
| 799 Object* code; | 813 Object* code; |
| 800 if (maybe_code->ToObject(&code)) { | 814 if (maybe_code->ToObject(&code)) { |
| 801 set_target(Code::cast(code)); | 815 set_target(Code::cast(code)); |
| 802 #ifdef DEBUG | 816 #ifdef DEBUG |
| 803 TraceIC( | 817 TraceIC( |
| 804 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : ""); | 818 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : ""); |
| 805 #endif | 819 #endif |
| 806 } | 820 } |
| 807 } | 821 } |
| 808 Object* result; | 822 |
| 809 { MaybeObject* maybe_result = Runtime::GetObjectProperty(isolate(), | 823 HandleScope scope(isolate()); |
| 810 object, | 824 Handle<Object> result = GetProperty(object, key); |
| 811 key); | 825 RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| 812 if (!maybe_result->ToObject(&result)) return maybe_result; | 826 |
| 813 } | 827 // Make receiver an object if the callee requires it. Strict mode or builtin |
| 814 if (result->IsJSFunction()) return result; | 828 // functions do not wrap the receiver, non-strict functions and objects |
| 815 result = TryCallAsFunction(result); | 829 // called as functions do. |
| 816 MaybeObject* answer = result; | 830 ReceiverToObjectIfRequired(result, object); |
| 817 if (!result->IsJSFunction()) { | 831 |
| 818 answer = TypeError("property_not_function", object, key); | 832 if (result->IsJSFunction()) return *result; |
| 819 } | 833 result = Handle<Object>(TryCallAsFunction(*result)); |
| 820 return answer; | 834 if (result->IsJSFunction()) return *result; |
| 835 |
| 836 return TypeError("property_not_function", object, key); |
| 821 } | 837 } |
| 822 | 838 |
| 823 | 839 |
| 824 #ifdef DEBUG | 840 #ifdef DEBUG |
| 825 #define TRACE_IC_NAMED(msg, name) \ | 841 #define TRACE_IC_NAMED(msg, name) \ |
| 826 if (FLAG_trace_ic) PrintF(msg, *(name)->ToCString()) | 842 if (FLAG_trace_ic) PrintF(msg, *(name)->ToCString()) |
| 827 #else | 843 #else |
| 828 #define TRACE_IC_NAMED(msg, name) | 844 #define TRACE_IC_NAMED(msg, name) |
| 829 #endif | 845 #endif |
| 830 | 846 |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1239 if (use_ic) { | 1255 if (use_ic) { |
| 1240 Code* stub = generic_stub(); | 1256 Code* stub = generic_stub(); |
| 1241 if (state == UNINITIALIZED) { | 1257 if (state == UNINITIALIZED) { |
| 1242 if (object->IsString() && key->IsNumber()) { | 1258 if (object->IsString() && key->IsNumber()) { |
| 1243 stub = string_stub(); | 1259 stub = string_stub(); |
| 1244 } else if (object->IsJSObject()) { | 1260 } else if (object->IsJSObject()) { |
| 1245 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1261 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1246 if (receiver->HasExternalArrayElements()) { | 1262 if (receiver->HasExternalArrayElements()) { |
| 1247 MaybeObject* probe = | 1263 MaybeObject* probe = |
| 1248 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( | 1264 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( |
| 1249 *receiver, false); | 1265 *receiver, false, kNonStrictMode); |
| 1250 stub = probe->IsFailure() ? | 1266 stub = probe->IsFailure() ? |
| 1251 NULL : Code::cast(probe->ToObjectUnchecked()); | 1267 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1252 } else if (receiver->HasIndexedInterceptor()) { | 1268 } else if (receiver->HasIndexedInterceptor()) { |
| 1253 stub = indexed_interceptor_stub(); | 1269 stub = indexed_interceptor_stub(); |
| 1254 } else if (receiver->HasPixelElements()) { | 1270 } else if (receiver->HasPixelElements()) { |
| 1255 MaybeObject* probe = | 1271 MaybeObject* probe = |
| 1256 isolate()->stub_cache()->ComputeKeyedLoadPixelArray(*receiver); | 1272 isolate()->stub_cache()->ComputeKeyedLoadPixelArray(*receiver); |
| 1257 stub = probe->IsFailure() ? | 1273 stub = probe->IsFailure() ? |
| 1258 NULL : Code::cast(probe->ToObjectUnchecked()); | 1274 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1259 } else if (key->IsSmi() && | 1275 } else if (key->IsSmi() && |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1390 object->LocalLookupRealNamedProperty(name, lookup); | 1406 object->LocalLookupRealNamedProperty(name, lookup); |
| 1391 return StoreICableLookup(lookup); | 1407 return StoreICableLookup(lookup); |
| 1392 } | 1408 } |
| 1393 } | 1409 } |
| 1394 | 1410 |
| 1395 return true; | 1411 return true; |
| 1396 } | 1412 } |
| 1397 | 1413 |
| 1398 | 1414 |
| 1399 MaybeObject* StoreIC::Store(State state, | 1415 MaybeObject* StoreIC::Store(State state, |
| 1416 StrictModeFlag strict_mode, |
| 1400 Handle<Object> object, | 1417 Handle<Object> object, |
| 1401 Handle<String> name, | 1418 Handle<String> name, |
| 1402 Handle<Object> value) { | 1419 Handle<Object> value) { |
| 1403 // If the object is undefined or null it's illegal to try to set any | 1420 // If the object is undefined or null it's illegal to try to set any |
| 1404 // properties on it; throw a TypeError in that case. | 1421 // properties on it; throw a TypeError in that case. |
| 1405 if (object->IsUndefined() || object->IsNull()) { | 1422 if (object->IsUndefined() || object->IsNull()) { |
| 1406 return TypeError("non_object_property_store", object, name); | 1423 return TypeError("non_object_property_store", object, name); |
| 1407 } | 1424 } |
| 1408 | 1425 |
| 1409 // Ignore stores where the receiver is not a JSObject. | 1426 // Ignore stores where the receiver is not a JSObject. |
| 1410 if (!object->IsJSObject()) return *value; | 1427 if (!object->IsJSObject()) return *value; |
| 1411 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1428 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1412 | 1429 |
| 1413 // Check if the given name is an array index. | 1430 // Check if the given name is an array index. |
| 1414 uint32_t index; | 1431 uint32_t index; |
| 1415 if (name->AsArrayIndex(&index)) { | 1432 if (name->AsArrayIndex(&index)) { |
| 1416 HandleScope scope(isolate()); | 1433 HandleScope scope(isolate()); |
| 1417 Handle<Object> result = SetElement(receiver, index, value); | 1434 Handle<Object> result = SetElement(receiver, index, value); |
| 1418 if (result.is_null()) return Failure::Exception(); | 1435 if (result.is_null()) return Failure::Exception(); |
| 1419 return *value; | 1436 return *value; |
| 1420 } | 1437 } |
| 1421 | 1438 |
| 1422 // Use specialized code for setting the length of arrays. | 1439 // Use specialized code for setting the length of arrays. |
| 1423 if (receiver->IsJSArray() | 1440 if (receiver->IsJSArray() |
| 1424 && name->Equals(isolate()->heap()->length_symbol()) | 1441 && name->Equals(isolate()->heap()->length_symbol()) |
| 1425 && receiver->AllowsSetElementsLength()) { | 1442 && receiver->AllowsSetElementsLength()) { |
| 1426 #ifdef DEBUG | 1443 #ifdef DEBUG |
| 1427 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); | 1444 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); |
| 1428 #endif | 1445 #endif |
| 1429 Code* target = isolate()->builtins()->builtin( | 1446 Builtins::Name target = (strict_mode == kStrictMode) |
| 1430 Builtins::StoreIC_ArrayLength); | 1447 ? Builtins::StoreIC_ArrayLength_Strict |
| 1431 set_target(target); | 1448 : Builtins::StoreIC_ArrayLength; |
| 1432 return receiver->SetProperty(*name, *value, NONE); | 1449 set_target(isolate()->builtins()->builtin(target)); |
| 1450 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1433 } | 1451 } |
| 1434 | 1452 |
| 1435 // Lookup the property locally in the receiver. | 1453 // Lookup the property locally in the receiver. |
| 1436 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { | 1454 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { |
| 1437 LookupResult lookup; | 1455 LookupResult lookup; |
| 1438 | 1456 |
| 1439 if (LookupForWrite(*receiver, *name, &lookup)) { | 1457 if (LookupForWrite(*receiver, *name, &lookup)) { |
| 1440 bool can_be_inlined = | 1458 bool can_be_inlined = |
| 1441 state == UNINITIALIZED && | 1459 state == UNINITIALIZED && |
| 1442 lookup.IsProperty() && | 1460 lookup.IsProperty() && |
| 1443 lookup.holder() == *receiver && | 1461 lookup.holder() == *receiver && |
| 1444 lookup.type() == FIELD && | 1462 lookup.type() == FIELD && |
| 1445 !receiver->IsAccessCheckNeeded(); | 1463 !receiver->IsAccessCheckNeeded(); |
| 1446 | 1464 |
| 1447 if (can_be_inlined) { | 1465 if (can_be_inlined) { |
| 1448 Map* map = lookup.holder()->map(); | 1466 Map* map = lookup.holder()->map(); |
| 1449 // Property's index in the properties array. If negative we have | 1467 // Property's index in the properties array. If negative we have |
| 1450 // an inobject property. | 1468 // an inobject property. |
| 1451 int index = lookup.GetFieldIndex() - map->inobject_properties(); | 1469 int index = lookup.GetFieldIndex() - map->inobject_properties(); |
| 1452 if (index < 0) { | 1470 if (index < 0) { |
| 1453 // Index is an offset from the end of the object. | 1471 // Index is an offset from the end of the object. |
| 1454 int offset = map->instance_size() + (index * kPointerSize); | 1472 int offset = map->instance_size() + (index * kPointerSize); |
| 1455 if (PatchInlinedStore(address(), map, offset)) { | 1473 if (PatchInlinedStore(address(), map, offset)) { |
| 1456 set_target(megamorphic_stub()); | 1474 set_target((strict_mode == kStrictMode) |
| 1475 ? megamorphic_stub_strict() |
| 1476 : megamorphic_stub()); |
| 1457 #ifdef DEBUG | 1477 #ifdef DEBUG |
| 1458 if (FLAG_trace_ic) { | 1478 if (FLAG_trace_ic) { |
| 1459 PrintF("[StoreIC : inline patch %s]\n", *name->ToCString()); | 1479 PrintF("[StoreIC : inline patch %s]\n", *name->ToCString()); |
| 1460 } | 1480 } |
| 1461 #endif | 1481 #endif |
| 1462 return receiver->SetProperty(*name, *value, NONE); | 1482 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1463 #ifdef DEBUG | 1483 #ifdef DEBUG |
| 1464 | 1484 |
| 1465 } else { | 1485 } else { |
| 1466 if (FLAG_trace_ic) { | 1486 if (FLAG_trace_ic) { |
| 1467 PrintF("[StoreIC : no inline patch %s (patching failed)]\n", | 1487 PrintF("[StoreIC : no inline patch %s (patching failed)]\n", |
| 1468 *name->ToCString()); | 1488 *name->ToCString()); |
| 1469 } | 1489 } |
| 1470 } | 1490 } |
| 1471 } else { | 1491 } else { |
| 1472 if (FLAG_trace_ic) { | 1492 if (FLAG_trace_ic) { |
| 1473 PrintF("[StoreIC : no inline patch %s (not inobject)]\n", | 1493 PrintF("[StoreIC : no inline patch %s (not inobject)]\n", |
| 1474 *name->ToCString()); | 1494 *name->ToCString()); |
| 1475 } | 1495 } |
| 1476 } | 1496 } |
| 1477 } else { | 1497 } else { |
| 1478 if (state == PREMONOMORPHIC) { | 1498 if (state == PREMONOMORPHIC) { |
| 1479 if (FLAG_trace_ic) { | 1499 if (FLAG_trace_ic) { |
| 1480 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n", | 1500 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n", |
| 1481 *name->ToCString()); | 1501 *name->ToCString()); |
| 1482 #endif | 1502 #endif |
| 1483 } | 1503 } |
| 1484 } | 1504 } |
| 1485 } | 1505 } |
| 1486 | 1506 |
| 1487 // If no inlined store ic was patched, generate a stub for this | 1507 // If no inlined store ic was patched, generate a stub for this |
| 1488 // store. | 1508 // store. |
| 1489 UpdateCaches(&lookup, state, receiver, name, value); | 1509 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
| 1510 } else { |
| 1511 // Strict mode doesn't allow setting non-existent global property |
| 1512 // or an assignment to a read only property. |
| 1513 if (strict_mode == kStrictMode) { |
| 1514 if (lookup.IsFound() && lookup.IsReadOnly()) { |
| 1515 return TypeError("strict_read_only_property", object, name); |
| 1516 } else if (IsContextual(object)) { |
| 1517 return ReferenceError("not_defined", name); |
| 1518 } |
| 1519 } |
| 1490 } | 1520 } |
| 1491 } | 1521 } |
| 1492 | 1522 |
| 1493 if (receiver->IsJSGlobalProxy()) { | 1523 if (receiver->IsJSGlobalProxy()) { |
| 1494 // Generate a generic stub that goes to the runtime when we see a global | 1524 // Generate a generic stub that goes to the runtime when we see a global |
| 1495 // proxy as receiver. | 1525 // proxy as receiver. |
| 1496 if (target() != global_proxy_stub()) { | 1526 Code* stub = (strict_mode == kStrictMode) |
| 1497 set_target(global_proxy_stub()); | 1527 ? global_proxy_stub_strict() |
| 1528 : global_proxy_stub(); |
| 1529 if (target() != stub) { |
| 1530 set_target(stub); |
| 1498 #ifdef DEBUG | 1531 #ifdef DEBUG |
| 1499 TraceIC("StoreIC", name, state, target()); | 1532 TraceIC("StoreIC", name, state, target()); |
| 1500 #endif | 1533 #endif |
| 1501 } | 1534 } |
| 1502 } | 1535 } |
| 1503 | 1536 |
| 1504 // Set the property. | 1537 // Set the property. |
| 1505 return receiver->SetProperty(*name, *value, NONE); | 1538 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1506 } | 1539 } |
| 1507 | 1540 |
| 1508 | 1541 |
| 1509 void StoreIC::UpdateCaches(LookupResult* lookup, | 1542 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 1510 State state, | 1543 State state, |
| 1544 StrictModeFlag strict_mode, |
| 1511 Handle<JSObject> receiver, | 1545 Handle<JSObject> receiver, |
| 1512 Handle<String> name, | 1546 Handle<String> name, |
| 1513 Handle<Object> value) { | 1547 Handle<Object> value) { |
| 1514 // Skip JSGlobalProxy. | 1548 // Skip JSGlobalProxy. |
| 1515 ASSERT(!receiver->IsJSGlobalProxy()); | 1549 ASSERT(!receiver->IsJSGlobalProxy()); |
| 1516 | 1550 |
| 1517 ASSERT(StoreICableLookup(lookup)); | 1551 ASSERT(StoreICableLookup(lookup)); |
| 1518 | 1552 |
| 1519 // If the property has a non-field type allowing map transitions | 1553 // If the property has a non-field type allowing map transitions |
| 1520 // where there is extra room in the object, we leave the IC in its | 1554 // where there is extra room in the object, we leave the IC in its |
| 1521 // current state. | 1555 // current state. |
| 1522 PropertyType type = lookup->type(); | 1556 PropertyType type = lookup->type(); |
| 1523 | 1557 |
| 1524 // Compute the code stub for this store; used for rewriting to | 1558 // Compute the code stub for this store; used for rewriting to |
| 1525 // monomorphic state and making sure that the code stub is in the | 1559 // monomorphic state and making sure that the code stub is in the |
| 1526 // stub cache. | 1560 // stub cache. |
| 1527 MaybeObject* maybe_code = NULL; | 1561 MaybeObject* maybe_code = NULL; |
| 1528 Object* code = NULL; | 1562 Object* code = NULL; |
| 1529 switch (type) { | 1563 switch (type) { |
| 1530 case FIELD: { | 1564 case FIELD: { |
| 1531 maybe_code = isolate()->stub_cache()->ComputeStoreField( | 1565 maybe_code = isolate()->stub_cache()->ComputeStoreField( |
| 1532 *name, *receiver, lookup->GetFieldIndex()); | 1566 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); |
| 1533 break; | 1567 break; |
| 1534 } | 1568 } |
| 1535 case MAP_TRANSITION: { | 1569 case MAP_TRANSITION: { |
| 1536 if (lookup->GetAttributes() != NONE) return; | 1570 if (lookup->GetAttributes() != NONE) return; |
| 1537 HandleScope scope(isolate()); | 1571 HandleScope scope(isolate()); |
| 1538 ASSERT(type == MAP_TRANSITION); | 1572 ASSERT(type == MAP_TRANSITION); |
| 1539 Handle<Map> transition(lookup->GetTransitionMap()); | 1573 Handle<Map> transition(lookup->GetTransitionMap()); |
| 1540 int index = transition->PropertyIndexFor(*name); | 1574 int index = transition->PropertyIndexFor(*name); |
| 1541 maybe_code = isolate()->stub_cache()->ComputeStoreField( | 1575 maybe_code = isolate()->stub_cache()->ComputeStoreField( |
| 1542 *name, *receiver, index, *transition); | 1576 *name, *receiver, index, *transition, strict_mode); |
| 1543 break; | 1577 break; |
| 1544 } | 1578 } |
| 1545 case NORMAL: { | 1579 case NORMAL: { |
| 1546 if (receiver->IsGlobalObject()) { | 1580 if (receiver->IsGlobalObject()) { |
| 1547 // The stub generated for the global object picks the value directly | 1581 // The stub generated for the global object picks the value directly |
| 1548 // from the property cell. So the property must be directly on the | 1582 // from the property cell. So the property must be directly on the |
| 1549 // global object. | 1583 // global object. |
| 1550 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1584 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1551 JSGlobalPropertyCell* cell = | 1585 JSGlobalPropertyCell* cell = |
| 1552 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | 1586 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); |
| 1553 maybe_code = isolate()->stub_cache()->ComputeStoreGlobal( | 1587 maybe_code = isolate()->stub_cache()->ComputeStoreGlobal( |
| 1554 *name, *global, cell); | 1588 *name, *global, cell, strict_mode); |
| 1555 } else { | 1589 } else { |
| 1556 if (lookup->holder() != *receiver) return; | 1590 if (lookup->holder() != *receiver) return; |
| 1557 maybe_code = isolate()->stub_cache()->ComputeStoreNormal(); | 1591 maybe_code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode); |
| 1558 } | 1592 } |
| 1559 break; | 1593 break; |
| 1560 } | 1594 } |
| 1561 case CALLBACKS: { | 1595 case CALLBACKS: { |
| 1562 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 1596 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; |
| 1563 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1597 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); |
| 1564 if (v8::ToCData<Address>(callback->setter()) == 0) return; | 1598 if (v8::ToCData<Address>(callback->setter()) == 0) return; |
| 1565 maybe_code = isolate()->stub_cache()->ComputeStoreCallback(*name, | 1599 maybe_code = isolate()->stub_cache()->ComputeStoreCallback( |
| 1566 *receiver, | 1600 *name, *receiver, callback, strict_mode); |
| 1567 callback); | |
| 1568 break; | 1601 break; |
| 1569 } | 1602 } |
| 1570 case INTERCEPTOR: { | 1603 case INTERCEPTOR: { |
| 1571 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); | 1604 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); |
| 1572 maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor(*name, | 1605 maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor( |
| 1573 *receiver); | 1606 *name, *receiver, strict_mode); |
| 1574 break; | 1607 break; |
| 1575 } | 1608 } |
| 1576 default: | 1609 default: |
| 1577 return; | 1610 return; |
| 1578 } | 1611 } |
| 1579 | 1612 |
| 1580 // If we're unable to compute the stub (not enough memory left), we | 1613 // If we're unable to compute the stub (not enough memory left), we |
| 1581 // simply avoid updating the caches. | 1614 // simply avoid updating the caches. |
| 1582 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 1615 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
| 1583 | 1616 |
| 1584 // Patch the call site depending on the state of the cache. | 1617 // Patch the call site depending on the state of the cache. |
| 1585 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 1618 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
| 1586 set_target(Code::cast(code)); | 1619 set_target(Code::cast(code)); |
| 1587 } else if (state == MONOMORPHIC) { | 1620 } else if (state == MONOMORPHIC) { |
| 1588 // Only move to megamorphic if the target changes. | 1621 // Only move to megamorphic if the target changes. |
| 1589 if (target() != Code::cast(code)) set_target(megamorphic_stub()); | 1622 if (target() != Code::cast(code)) { |
| 1623 set_target((strict_mode == kStrictMode) |
| 1624 ? megamorphic_stub_strict() |
| 1625 : megamorphic_stub()); |
| 1626 } |
| 1590 } else if (state == MEGAMORPHIC) { | 1627 } else if (state == MEGAMORPHIC) { |
| 1591 // Update the stub cache. | 1628 // Update the stub cache. |
| 1592 isolate()->stub_cache()->Set(*name, | 1629 isolate()->stub_cache()->Set(*name, |
| 1593 receiver->map(), | 1630 receiver->map(), |
| 1594 Code::cast(code)); | 1631 Code::cast(code)); |
| 1595 } | 1632 } |
| 1596 | 1633 |
| 1597 #ifdef DEBUG | 1634 #ifdef DEBUG |
| 1598 TraceIC("StoreIC", name, state, target()); | 1635 TraceIC("StoreIC", name, state, target()); |
| 1599 #endif | 1636 #endif |
| 1600 } | 1637 } |
| 1601 | 1638 |
| 1602 | 1639 |
| 1603 MaybeObject* KeyedStoreIC::Store(State state, | 1640 MaybeObject* KeyedStoreIC::Store(State state, |
| 1641 StrictModeFlag strict_mode, |
| 1604 Handle<Object> object, | 1642 Handle<Object> object, |
| 1605 Handle<Object> key, | 1643 Handle<Object> key, |
| 1606 Handle<Object> value) { | 1644 Handle<Object> value) { |
| 1607 if (key->IsSymbol()) { | 1645 if (key->IsSymbol()) { |
| 1608 Handle<String> name = Handle<String>::cast(key); | 1646 Handle<String> name = Handle<String>::cast(key); |
| 1609 | 1647 |
| 1610 // If the object is undefined or null it's illegal to try to set any | 1648 // If the object is undefined or null it's illegal to try to set any |
| 1611 // properties on it; throw a TypeError in that case. | 1649 // properties on it; throw a TypeError in that case. |
| 1612 if (object->IsUndefined() || object->IsNull()) { | 1650 if (object->IsUndefined() || object->IsNull()) { |
| 1613 return TypeError("non_object_property_store", object, name); | 1651 return TypeError("non_object_property_store", object, name); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1625 if (result.is_null()) return Failure::Exception(); | 1663 if (result.is_null()) return Failure::Exception(); |
| 1626 return *value; | 1664 return *value; |
| 1627 } | 1665 } |
| 1628 | 1666 |
| 1629 // Lookup the property locally in the receiver. | 1667 // Lookup the property locally in the receiver. |
| 1630 LookupResult lookup; | 1668 LookupResult lookup; |
| 1631 receiver->LocalLookup(*name, &lookup); | 1669 receiver->LocalLookup(*name, &lookup); |
| 1632 | 1670 |
| 1633 // Update inline cache and stub cache. | 1671 // Update inline cache and stub cache. |
| 1634 if (FLAG_use_ic) { | 1672 if (FLAG_use_ic) { |
| 1635 UpdateCaches(&lookup, state, receiver, name, value); | 1673 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
| 1636 } | 1674 } |
| 1637 | 1675 |
| 1638 // Set the property. | 1676 // Set the property. |
| 1639 return receiver->SetProperty(*name, *value, NONE); | 1677 return receiver->SetProperty(*name, *value, NONE, strict_mode); |
| 1640 } | 1678 } |
| 1641 | 1679 |
| 1642 // Do not use ICs for objects that require access checks (including | 1680 // Do not use ICs for objects that require access checks (including |
| 1643 // the global object). | 1681 // the global object). |
| 1644 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1682 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 1645 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1683 ASSERT(!(use_ic && object->IsJSGlobalProxy())); |
| 1646 | 1684 |
| 1647 if (use_ic) { | 1685 if (use_ic) { |
| 1648 Code* stub = generic_stub(); | 1686 Code* stub = |
| 1649 if (object->IsJSObject()) { | 1687 (strict_mode == kStrictMode) ? generic_stub_strict() : generic_stub(); |
| 1650 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1688 if (state == UNINITIALIZED) { |
| 1651 if (receiver->HasExternalArrayElements()) { | 1689 if (object->IsJSObject()) { |
| 1652 MaybeObject* probe = | 1690 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1653 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( | 1691 if (receiver->HasExternalArrayElements()) { |
| 1654 *receiver, true); | 1692 MaybeObject* probe = |
| 1655 stub = | 1693 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( |
| 1656 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); | 1694 *receiver, true, strict_mode); |
| 1657 } else if (state == UNINITIALIZED && | 1695 stub = probe->IsFailure() ? |
| 1658 key->IsSmi() && | 1696 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1659 receiver->map()->has_fast_elements()) { | 1697 } else if (receiver->HasPixelElements()) { |
| 1660 MaybeObject* probe = | 1698 MaybeObject* probe = |
| 1661 isolate()->stub_cache()->ComputeKeyedStoreSpecialized(*receiver); | 1699 isolate()->stub_cache()->ComputeKeyedStorePixelArray( |
| 1662 stub = | 1700 *receiver, strict_mode); |
| 1663 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); | 1701 stub = probe->IsFailure() ? |
| 1702 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1703 } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { |
| 1704 MaybeObject* probe = |
| 1705 isolate()->stub_cache()->ComputeKeyedStoreSpecialized( |
| 1706 *receiver, strict_mode); |
| 1707 stub = probe->IsFailure() ? |
| 1708 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1709 } |
| 1664 } | 1710 } |
| 1665 } | 1711 } |
| 1666 if (stub != NULL) set_target(stub); | 1712 if (stub != NULL) set_target(stub); |
| 1667 } | 1713 } |
| 1668 | 1714 |
| 1669 // Set the property. | 1715 // Set the property. |
| 1670 return Runtime::SetObjectProperty(isolate(), object, key, value, NONE); | 1716 return Runtime::SetObjectProperty( |
| 1717 isolate(), object , key, value, NONE, strict_mode); |
| 1671 } | 1718 } |
| 1672 | 1719 |
| 1673 | 1720 |
| 1674 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, | 1721 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, |
| 1675 State state, | 1722 State state, |
| 1723 StrictModeFlag strict_mode, |
| 1676 Handle<JSObject> receiver, | 1724 Handle<JSObject> receiver, |
| 1677 Handle<String> name, | 1725 Handle<String> name, |
| 1678 Handle<Object> value) { | 1726 Handle<Object> value) { |
| 1679 // Skip JSGlobalProxy. | 1727 // Skip JSGlobalProxy. |
| 1680 if (receiver->IsJSGlobalProxy()) return; | 1728 if (receiver->IsJSGlobalProxy()) return; |
| 1681 | 1729 |
| 1682 // Bail out if we didn't find a result. | 1730 // Bail out if we didn't find a result. |
| 1683 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return; | 1731 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return; |
| 1684 | 1732 |
| 1685 // If the property is read-only, we leave the IC in its current | 1733 // If the property is read-only, we leave the IC in its current |
| 1686 // state. | 1734 // state. |
| 1687 if (lookup->IsReadOnly()) return; | 1735 if (lookup->IsReadOnly()) return; |
| 1688 | 1736 |
| 1689 // If the property has a non-field type allowing map transitions | 1737 // If the property has a non-field type allowing map transitions |
| 1690 // where there is extra room in the object, we leave the IC in its | 1738 // where there is extra room in the object, we leave the IC in its |
| 1691 // current state. | 1739 // current state. |
| 1692 PropertyType type = lookup->type(); | 1740 PropertyType type = lookup->type(); |
| 1693 | 1741 |
| 1694 // Compute the code stub for this store; used for rewriting to | 1742 // Compute the code stub for this store; used for rewriting to |
| 1695 // monomorphic state and making sure that the code stub is in the | 1743 // monomorphic state and making sure that the code stub is in the |
| 1696 // stub cache. | 1744 // stub cache. |
| 1697 MaybeObject* maybe_code = NULL; | 1745 MaybeObject* maybe_code = NULL; |
| 1698 Object* code = NULL; | 1746 Object* code = NULL; |
| 1699 | 1747 |
| 1700 switch (type) { | 1748 switch (type) { |
| 1701 case FIELD: { | 1749 case FIELD: { |
| 1702 maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField( | 1750 maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField( |
| 1703 *name, *receiver, lookup->GetFieldIndex()); | 1751 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); |
| 1704 break; | 1752 break; |
| 1705 } | 1753 } |
| 1706 case MAP_TRANSITION: { | 1754 case MAP_TRANSITION: { |
| 1707 if (lookup->GetAttributes() == NONE) { | 1755 if (lookup->GetAttributes() == NONE) { |
| 1708 HandleScope scope(isolate()); | 1756 HandleScope scope(isolate()); |
| 1709 ASSERT(type == MAP_TRANSITION); | 1757 ASSERT(type == MAP_TRANSITION); |
| 1710 Handle<Map> transition(lookup->GetTransitionMap()); | 1758 Handle<Map> transition(lookup->GetTransitionMap()); |
| 1711 int index = transition->PropertyIndexFor(*name); | 1759 int index = transition->PropertyIndexFor(*name); |
| 1712 maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField( | 1760 maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField( |
| 1713 *name, *receiver, index, *transition); | 1761 *name, *receiver, index, *transition, strict_mode); |
| 1714 break; | 1762 break; |
| 1715 } | 1763 } |
| 1716 // fall through. | 1764 // fall through. |
| 1717 } | 1765 } |
| 1718 default: { | 1766 default: { |
| 1719 // Always rewrite to the generic case so that we do not | 1767 // Always rewrite to the generic case so that we do not |
| 1720 // repeatedly try to rewrite. | 1768 // repeatedly try to rewrite. |
| 1721 maybe_code = generic_stub(); | 1769 maybe_code = (strict_mode == kStrictMode) |
| 1770 ? generic_stub_strict() |
| 1771 : generic_stub(); |
| 1722 break; | 1772 break; |
| 1723 } | 1773 } |
| 1724 } | 1774 } |
| 1725 | 1775 |
| 1726 // If we're unable to compute the stub (not enough memory left), we | 1776 // If we're unable to compute the stub (not enough memory left), we |
| 1727 // simply avoid updating the caches. | 1777 // simply avoid updating the caches. |
| 1728 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 1778 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
| 1729 | 1779 |
| 1730 // Patch the call site depending on the state of the cache. Make | 1780 // Patch the call site depending on the state of the cache. Make |
| 1731 // sure to always rewrite from monomorphic to megamorphic. | 1781 // sure to always rewrite from monomorphic to megamorphic. |
| 1732 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); | 1782 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); |
| 1733 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { | 1783 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { |
| 1734 set_target(Code::cast(code)); | 1784 set_target(Code::cast(code)); |
| 1735 } else if (state == MONOMORPHIC) { | 1785 } else if (state == MONOMORPHIC) { |
| 1736 set_target(megamorphic_stub()); | 1786 set_target((strict_mode == kStrictMode) |
| 1787 ? megamorphic_stub_strict() |
| 1788 : megamorphic_stub()); |
| 1737 } | 1789 } |
| 1738 | 1790 |
| 1739 #ifdef DEBUG | 1791 #ifdef DEBUG |
| 1740 TraceIC("KeyedStoreIC", name, state, target()); | 1792 TraceIC("KeyedStoreIC", name, state, target()); |
| 1741 #endif | 1793 #endif |
| 1742 } | 1794 } |
| 1743 | 1795 |
| 1744 | 1796 |
| 1745 // ---------------------------------------------------------------------------- | 1797 // ---------------------------------------------------------------------------- |
| 1746 // Static IC stub generators. | 1798 // Static IC stub generators. |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1836 } | 1888 } |
| 1837 | 1889 |
| 1838 | 1890 |
| 1839 // Used from ic-<arch>.cc. | 1891 // Used from ic-<arch>.cc. |
| 1840 MUST_USE_RESULT MaybeObject* StoreIC_Miss(RUNTIME_CALLING_CONVENTION) { | 1892 MUST_USE_RESULT MaybeObject* StoreIC_Miss(RUNTIME_CALLING_CONVENTION) { |
| 1841 RUNTIME_GET_ISOLATE; | 1893 RUNTIME_GET_ISOLATE; |
| 1842 NoHandleAllocation na; | 1894 NoHandleAllocation na; |
| 1843 ASSERT(args.length() == 3); | 1895 ASSERT(args.length() == 3); |
| 1844 StoreIC ic(isolate); | 1896 StoreIC ic(isolate); |
| 1845 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1897 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1846 return ic.Store(state, args.at<Object>(0), args.at<String>(1), | 1898 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1899 return ic.Store(state, |
| 1900 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
| 1901 args.at<Object>(0), |
| 1902 args.at<String>(1), |
| 1847 args.at<Object>(2)); | 1903 args.at<Object>(2)); |
| 1848 } | 1904 } |
| 1849 | 1905 |
| 1850 | 1906 |
| 1851 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(RUNTIME_CALLING_CONVENTION) { | 1907 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(RUNTIME_CALLING_CONVENTION) { |
| 1852 RUNTIME_GET_ISOLATE; | 1908 RUNTIME_GET_ISOLATE; |
| 1853 NoHandleAllocation nha; | 1909 NoHandleAllocation nha; |
| 1854 | 1910 |
| 1855 ASSERT(args.length() == 2); | 1911 ASSERT(args.length() == 2); |
| 1856 JSObject* receiver = JSObject::cast(args[0]); | 1912 JSObject* receiver = JSObject::cast(args[0]); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1905 } | 1961 } |
| 1906 | 1962 |
| 1907 | 1963 |
| 1908 // Used from ic-<arch>.cc. | 1964 // Used from ic-<arch>.cc. |
| 1909 MUST_USE_RESULT MaybeObject* KeyedStoreIC_Miss(RUNTIME_CALLING_CONVENTION) { | 1965 MUST_USE_RESULT MaybeObject* KeyedStoreIC_Miss(RUNTIME_CALLING_CONVENTION) { |
| 1910 RUNTIME_GET_ISOLATE; | 1966 RUNTIME_GET_ISOLATE; |
| 1911 NoHandleAllocation na; | 1967 NoHandleAllocation na; |
| 1912 ASSERT(args.length() == 3); | 1968 ASSERT(args.length() == 3); |
| 1913 KeyedStoreIC ic(isolate); | 1969 KeyedStoreIC ic(isolate); |
| 1914 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1970 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1915 return ic.Store(state, args.at<Object>(0), args.at<Object>(1), | 1971 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1972 return ic.Store(state, |
| 1973 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
| 1974 args.at<Object>(0), |
| 1975 args.at<Object>(1), |
| 1916 args.at<Object>(2)); | 1976 args.at<Object>(2)); |
| 1917 } | 1977 } |
| 1918 | 1978 |
| 1919 | 1979 |
| 1920 void BinaryOpIC::patch(Code* code) { | 1980 void BinaryOpIC::patch(Code* code) { |
| 1921 set_target(code); | 1981 set_target(code); |
| 1922 } | 1982 } |
| 1923 | 1983 |
| 1924 | 1984 |
| 1925 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 1985 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
| (...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2315 #undef ADDR | 2375 #undef ADDR |
| 2316 }; | 2376 }; |
| 2317 | 2377 |
| 2318 | 2378 |
| 2319 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2379 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2320 return IC_utilities[id]; | 2380 return IC_utilities[id]; |
| 2321 } | 2381 } |
| 2322 | 2382 |
| 2323 | 2383 |
| 2324 } } // namespace v8::internal | 2384 } } // namespace v8::internal |
| OLD | NEW |