| 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 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 !current->IsJSGlobalProxy() && | 147 !current->IsJSGlobalProxy() && |
| 148 !current->IsJSGlobalObject()) { | 148 !current->IsJSGlobalObject()) { |
| 149 return true; | 149 return true; |
| 150 } | 150 } |
| 151 } | 151 } |
| 152 | 152 |
| 153 return false; | 153 return false; |
| 154 } | 154 } |
| 155 | 155 |
| 156 | 156 |
| 157 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { | 157 static bool TryRemoveInvalidPrototypeDependentStub(Code* target, |
| 158 IC::State state = target->ic_state(); | 158 Object* receiver, |
| 159 | 159 Object* name) { |
| 160 if (state != MONOMORPHIC || !name->IsString()) return state; | |
| 161 if (receiver->IsUndefined() || receiver->IsNull()) return state; | |
| 162 | |
| 163 InlineCacheHolderFlag cache_holder = | 160 InlineCacheHolderFlag cache_holder = |
| 164 Code::ExtractCacheHolderFromFlags(target->flags()); | 161 Code::ExtractCacheHolderFromFlags(target->flags()); |
| 165 | 162 |
| 166 | |
| 167 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { | 163 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { |
| 168 // The stub was generated for JSObject but called for non-JSObject. | 164 // The stub was generated for JSObject but called for non-JSObject. |
| 169 // IC::GetCodeCacheHolder is not applicable. | 165 // IC::GetCodeCacheHolder is not applicable. |
| 170 return MONOMORPHIC; | 166 return false; |
| 171 } else if (cache_holder == PROTOTYPE_MAP && | 167 } else if (cache_holder == PROTOTYPE_MAP && |
| 172 receiver->GetPrototype()->IsNull()) { | 168 receiver->GetPrototype()->IsNull()) { |
| 173 // IC::GetCodeCacheHolder is not applicable. | 169 // IC::GetCodeCacheHolder is not applicable. |
| 174 return MONOMORPHIC; | 170 return false; |
| 175 } | 171 } |
| 176 Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map(); | 172 Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map(); |
| 177 | 173 |
| 178 // Decide whether the inline cache failed because of changes to the | 174 // Decide whether the inline cache failed because of changes to the |
| 179 // receiver itself or changes to one of its prototypes. | 175 // receiver itself or changes to one of its prototypes. |
| 180 // | 176 // |
| 181 // If there are changes to the receiver itself, the map of the | 177 // If there are changes to the receiver itself, the map of the |
| 182 // receiver will have changed and the current target will not be in | 178 // receiver will have changed and the current target will not be in |
| 183 // the receiver map's code cache. Therefore, if the current target | 179 // the receiver map's code cache. Therefore, if the current target |
| 184 // is in the receiver map's code cache, the inline cache failed due | 180 // is in the receiver map's code cache, the inline cache failed due |
| 185 // to prototype check failure. | 181 // to prototype check failure. |
| 186 int index = map->IndexInCodeCache(name, target); | 182 int index = map->IndexInCodeCache(name, target); |
| 187 if (index >= 0) { | 183 if (index >= 0) { |
| 188 // For keyed load/store/call, the most likely cause of cache failure is | 184 map->RemoveFromCodeCache(String::cast(name), target, index); |
| 189 // that the key has changed. We do not distinguish between | 185 return true; |
| 190 // prototype and non-prototype failures for keyed access. | 186 } |
| 191 Code::Kind kind = target->kind(); | |
| 192 if (kind == Code::KEYED_LOAD_IC || | |
| 193 kind == Code::KEYED_STORE_IC || | |
| 194 kind == Code::KEYED_CALL_IC) { | |
| 195 return MONOMORPHIC; | |
| 196 } | |
| 197 | 187 |
| 198 // Remove the target from the code cache to avoid hitting the same | 188 return false; |
| 199 // invalid stub again. | 189 } |
| 200 map->RemoveFromCodeCache(String::cast(name), target, index); | |
| 201 | 190 |
| 191 |
| 192 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { |
| 193 IC::State state = target->ic_state(); |
| 194 |
| 195 if (state != MONOMORPHIC || !name->IsString()) return state; |
| 196 if (receiver->IsUndefined() || receiver->IsNull()) return state; |
| 197 |
| 198 // For keyed load/store/call, the most likely cause of cache failure is |
| 199 // that the key has changed. We do not distinguish between |
| 200 // prototype and non-prototype failures for keyed access. |
| 201 Code::Kind kind = target->kind(); |
| 202 if (kind == Code::KEYED_LOAD_IC || |
| 203 kind == Code::KEYED_STORE_IC || |
| 204 kind == Code::KEYED_CALL_IC) { |
| 205 return MONOMORPHIC; |
| 206 } |
| 207 |
| 208 // Remove the target from the code cache if it became invalid |
| 209 // because of changes in the prototype chain to avoid hitting it |
| 210 // again. |
| 211 // Call stubs handle this later to allow extra IC state |
| 212 // transitions. |
| 213 if (kind != Code::CALL_IC && |
| 214 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { |
| 202 return MONOMORPHIC_PROTOTYPE_FAILURE; | 215 return MONOMORPHIC_PROTOTYPE_FAILURE; |
| 203 } | 216 } |
| 204 | 217 |
| 205 // The builtins object is special. It only changes when JavaScript | 218 // The builtins object is special. It only changes when JavaScript |
| 206 // builtins are loaded lazily. It is important to keep inline | 219 // builtins are loaded lazily. It is important to keep inline |
| 207 // caches for the builtins object monomorphic. Therefore, if we get | 220 // caches for the builtins object monomorphic. Therefore, if we get |
| 208 // an inline cache miss for the builtins object after lazily loading | 221 // an inline cache miss for the builtins object after lazily loading |
| 209 // JavaScript builtins, we return uninitialized as the state to | 222 // JavaScript builtins, we return uninitialized as the state to |
| 210 // force the inline cache back to monomorphic state. | 223 // force the inline cache back to monomorphic state. |
| 211 if (receiver->IsJSBuiltinsObject()) { | 224 if (receiver->IsJSBuiltinsObject()) { |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 322 // Reset the map check of the inlined inobject property store (if | 335 // Reset the map check of the inlined inobject property store (if |
| 323 // present) to guarantee failure by holding an invalid map (the null | 336 // present) to guarantee failure by holding an invalid map (the null |
| 324 // value). The offset can be patched to anything. | 337 // value). The offset can be patched to anything. |
| 325 PatchInlinedStore(address, Heap::null_value(), 0); | 338 PatchInlinedStore(address, Heap::null_value(), 0); |
| 326 } | 339 } |
| 327 | 340 |
| 328 | 341 |
| 329 void StoreIC::Clear(Address address, Code* target) { | 342 void StoreIC::Clear(Address address, Code* target) { |
| 330 if (target->ic_state() == UNINITIALIZED) return; | 343 if (target->ic_state() == UNINITIALIZED) return; |
| 331 ClearInlinedVersion(address); | 344 ClearInlinedVersion(address); |
| 332 SetTargetAtAddress(address, initialize_stub()); | 345 SetTargetAtAddress(address, |
| 346 target->extra_ic_state() == kStoreICStrict |
| 347 ? initialize_stub_strict() |
| 348 : initialize_stub()); |
| 333 } | 349 } |
| 334 | 350 |
| 335 | 351 |
| 336 void KeyedStoreIC::ClearInlinedVersion(Address address) { | 352 void KeyedStoreIC::ClearInlinedVersion(Address address) { |
| 337 // Insert null as the elements map to check for. This will make | 353 // Insert null as the elements map to check for. This will make |
| 338 // sure that the elements fast-case map check fails so that control | 354 // sure that the elements fast-case map check fails so that control |
| 339 // flows to the IC instead of the inlined version. | 355 // flows to the IC instead of the inlined version. |
| 340 PatchInlinedStore(address, Heap::null_value()); | 356 PatchInlinedStore(address, Heap::null_value()); |
| 341 } | 357 } |
| 342 | 358 |
| 343 | 359 |
| 344 void KeyedStoreIC::RestoreInlinedVersion(Address address) { | 360 void KeyedStoreIC::RestoreInlinedVersion(Address address) { |
| 345 // Restore the fast-case elements map check so that the inlined | 361 // Restore the fast-case elements map check so that the inlined |
| 346 // version can be used again. | 362 // version can be used again. |
| 347 PatchInlinedStore(address, Heap::fixed_array_map()); | 363 PatchInlinedStore(address, Heap::fixed_array_map()); |
| 348 } | 364 } |
| 349 | 365 |
| 350 | 366 |
| 351 void KeyedStoreIC::Clear(Address address, Code* target) { | 367 void KeyedStoreIC::Clear(Address address, Code* target) { |
| 352 if (target->ic_state() == UNINITIALIZED) return; | 368 if (target->ic_state() == UNINITIALIZED) return; |
| 353 SetTargetAtAddress(address, initialize_stub()); | 369 SetTargetAtAddress(address, initialize_stub()); |
| 354 } | 370 } |
| 355 | 371 |
| 356 | 372 |
| 357 Code* KeyedLoadIC::external_array_stub(JSObject::ElementsKind elements_kind) { | |
| 358 switch (elements_kind) { | |
| 359 case JSObject::EXTERNAL_BYTE_ELEMENTS: | |
| 360 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalByteArray); | |
| 361 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
| 362 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalUnsignedByteArray); | |
| 363 case JSObject::EXTERNAL_SHORT_ELEMENTS: | |
| 364 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalShortArray); | |
| 365 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
| 366 return Builtins::builtin( | |
| 367 Builtins::KeyedLoadIC_ExternalUnsignedShortArray); | |
| 368 case JSObject::EXTERNAL_INT_ELEMENTS: | |
| 369 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalIntArray); | |
| 370 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
| 371 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalUnsignedIntArray); | |
| 372 case JSObject::EXTERNAL_FLOAT_ELEMENTS: | |
| 373 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalFloatArray); | |
| 374 default: | |
| 375 UNREACHABLE(); | |
| 376 return NULL; | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 | |
| 381 Code* KeyedStoreIC::external_array_stub(JSObject::ElementsKind elements_kind) { | |
| 382 switch (elements_kind) { | |
| 383 case JSObject::EXTERNAL_BYTE_ELEMENTS: | |
| 384 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalByteArray); | |
| 385 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
| 386 return Builtins::builtin( | |
| 387 Builtins::KeyedStoreIC_ExternalUnsignedByteArray); | |
| 388 case JSObject::EXTERNAL_SHORT_ELEMENTS: | |
| 389 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalShortArray); | |
| 390 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
| 391 return Builtins::builtin( | |
| 392 Builtins::KeyedStoreIC_ExternalUnsignedShortArray); | |
| 393 case JSObject::EXTERNAL_INT_ELEMENTS: | |
| 394 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalIntArray); | |
| 395 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
| 396 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalUnsignedIntArray); | |
| 397 case JSObject::EXTERNAL_FLOAT_ELEMENTS: | |
| 398 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalFloatArray); | |
| 399 default: | |
| 400 UNREACHABLE(); | |
| 401 return NULL; | |
| 402 } | |
| 403 } | |
| 404 | |
| 405 | |
| 406 static bool HasInterceptorGetter(JSObject* object) { | 373 static bool HasInterceptorGetter(JSObject* object) { |
| 407 return !object->GetNamedInterceptor()->getter()->IsUndefined(); | 374 return !object->GetNamedInterceptor()->getter()->IsUndefined(); |
| 408 } | 375 } |
| 409 | 376 |
| 410 | 377 |
| 411 static void LookupForRead(Object* object, | 378 static void LookupForRead(Object* object, |
| 412 String* name, | 379 String* name, |
| 413 LookupResult* lookup) { | 380 LookupResult* lookup) { |
| 414 AssertNoAllocation no_gc; // pointers must stay valid | 381 AssertNoAllocation no_gc; // pointers must stay valid |
| 415 | 382 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 475 // Change the receiver to the result of calling ToObject on it. | 442 // Change the receiver to the result of calling ToObject on it. |
| 476 const int argc = this->target()->arguments_count(); | 443 const int argc = this->target()->arguments_count(); |
| 477 StackFrameLocator locator; | 444 StackFrameLocator locator; |
| 478 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 445 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
| 479 int index = frame->ComputeExpressionsCount() - (argc + 1); | 446 int index = frame->ComputeExpressionsCount() - (argc + 1); |
| 480 frame->SetExpression(index, *Factory::ToObject(object)); | 447 frame->SetExpression(index, *Factory::ToObject(object)); |
| 481 } | 448 } |
| 482 | 449 |
| 483 | 450 |
| 484 MaybeObject* CallICBase::LoadFunction(State state, | 451 MaybeObject* CallICBase::LoadFunction(State state, |
| 452 Code::ExtraICState extra_ic_state, |
| 485 Handle<Object> object, | 453 Handle<Object> object, |
| 486 Handle<String> name) { | 454 Handle<String> name) { |
| 487 // If the object is undefined or null it's illegal to try to get any | 455 // If the object is undefined or null it's illegal to try to get any |
| 488 // of its properties; throw a TypeError in that case. | 456 // of its properties; throw a TypeError in that case. |
| 489 if (object->IsUndefined() || object->IsNull()) { | 457 if (object->IsUndefined() || object->IsNull()) { |
| 490 return TypeError("non_object_property_call", object, name); | 458 return TypeError("non_object_property_call", object, name); |
| 491 } | 459 } |
| 492 | 460 |
| 493 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | 461 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
| 494 ReceiverToObject(object); | 462 ReceiverToObject(object); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 520 // If the object does not have the requested property, check which | 488 // If the object does not have the requested property, check which |
| 521 // exception we need to throw. | 489 // exception we need to throw. |
| 522 if (IsContextual(object)) { | 490 if (IsContextual(object)) { |
| 523 return ReferenceError("not_defined", name); | 491 return ReferenceError("not_defined", name); |
| 524 } | 492 } |
| 525 return TypeError("undefined_method", object, name); | 493 return TypeError("undefined_method", object, name); |
| 526 } | 494 } |
| 527 | 495 |
| 528 // Lookup is valid: Update inline cache and stub cache. | 496 // Lookup is valid: Update inline cache and stub cache. |
| 529 if (FLAG_use_ic) { | 497 if (FLAG_use_ic) { |
| 530 UpdateCaches(&lookup, state, object, name); | 498 UpdateCaches(&lookup, state, extra_ic_state, object, name); |
| 531 } | 499 } |
| 532 | 500 |
| 533 // Get the property. | 501 // Get the property. |
| 534 PropertyAttributes attr; | 502 PropertyAttributes attr; |
| 535 Object* result; | 503 Object* result; |
| 536 { MaybeObject* maybe_result = | 504 { MaybeObject* maybe_result = |
| 537 object->GetProperty(*object, &lookup, *name, &attr); | 505 object->GetProperty(*object, &lookup, *name, &attr); |
| 538 if (!maybe_result->ToObject(&result)) return maybe_result; | 506 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 539 } | 507 } |
| 540 if (lookup.type() == INTERCEPTOR) { | 508 if (lookup.type() == INTERCEPTOR) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 569 // Try to find a suitable function delegate for the object at hand. | 537 // Try to find a suitable function delegate for the object at hand. |
| 570 result = TryCallAsFunction(result); | 538 result = TryCallAsFunction(result); |
| 571 MaybeObject* answer = result; | 539 MaybeObject* answer = result; |
| 572 if (!result->IsJSFunction()) { | 540 if (!result->IsJSFunction()) { |
| 573 answer = TypeError("property_not_function", object, name); | 541 answer = TypeError("property_not_function", object, name); |
| 574 } | 542 } |
| 575 return answer; | 543 return answer; |
| 576 } | 544 } |
| 577 | 545 |
| 578 | 546 |
| 547 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, |
| 548 Handle<Object> object, |
| 549 Code::ExtraICState* extra_ic_state) { |
| 550 ASSERT(kind_ == Code::CALL_IC); |
| 551 if (lookup->type() != CONSTANT_FUNCTION) return false; |
| 552 JSFunction* function = lookup->GetConstantFunction(); |
| 553 if (!function->shared()->HasBuiltinFunctionId()) return false; |
| 554 |
| 555 // Fetch the arguments passed to the called function. |
| 556 const int argc = target()->arguments_count(); |
| 557 Address entry = Top::c_entry_fp(Top::GetCurrentThread()); |
| 558 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
| 559 Arguments args(argc + 1, |
| 560 &Memory::Object_at(fp + |
| 561 StandardFrameConstants::kCallerSPOffset + |
| 562 argc * kPointerSize)); |
| 563 switch (function->shared()->builtin_function_id()) { |
| 564 case kStringCharCodeAt: |
| 565 case kStringCharAt: |
| 566 if (object->IsString()) { |
| 567 String* string = String::cast(*object); |
| 568 // Check that there's the right wrapper in the receiver slot. |
| 569 ASSERT(string == JSValue::cast(args[0])->value()); |
| 570 // If we're in the default (fastest) state and the index is |
| 571 // out of bounds, update the state to record this fact. |
| 572 if (*extra_ic_state == DEFAULT_STRING_STUB && |
| 573 argc >= 1 && args[1]->IsNumber()) { |
| 574 double index; |
| 575 if (args[1]->IsSmi()) { |
| 576 index = Smi::cast(args[1])->value(); |
| 577 } else { |
| 578 ASSERT(args[1]->IsHeapNumber()); |
| 579 index = DoubleToInteger(HeapNumber::cast(args[1])->value()); |
| 580 } |
| 581 if (index < 0 || index >= string->length()) { |
| 582 *extra_ic_state = STRING_INDEX_OUT_OF_BOUNDS; |
| 583 return true; |
| 584 } |
| 585 } |
| 586 } |
| 587 break; |
| 588 default: |
| 589 return false; |
| 590 } |
| 591 return false; |
| 592 } |
| 593 |
| 594 |
| 595 MaybeObject* CallICBase::ComputeMonomorphicStub( |
| 596 LookupResult* lookup, |
| 597 State state, |
| 598 Code::ExtraICState extra_ic_state, |
| 599 Handle<Object> object, |
| 600 Handle<String> name) { |
| 601 int argc = target()->arguments_count(); |
| 602 InLoopFlag in_loop = target()->ic_in_loop(); |
| 603 MaybeObject* maybe_code = NULL; |
| 604 switch (lookup->type()) { |
| 605 case FIELD: { |
| 606 int index = lookup->GetFieldIndex(); |
| 607 maybe_code = StubCache::ComputeCallField(argc, |
| 608 in_loop, |
| 609 kind_, |
| 610 *name, |
| 611 *object, |
| 612 lookup->holder(), |
| 613 index); |
| 614 break; |
| 615 } |
| 616 case CONSTANT_FUNCTION: { |
| 617 // Get the constant function and compute the code stub for this |
| 618 // call; used for rewriting to monomorphic state and making sure |
| 619 // that the code stub is in the stub cache. |
| 620 JSFunction* function = lookup->GetConstantFunction(); |
| 621 maybe_code = StubCache::ComputeCallConstant(argc, |
| 622 in_loop, |
| 623 kind_, |
| 624 extra_ic_state, |
| 625 *name, |
| 626 *object, |
| 627 lookup->holder(), |
| 628 function); |
| 629 break; |
| 630 } |
| 631 case NORMAL: { |
| 632 if (!object->IsJSObject()) return NULL; |
| 633 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 634 |
| 635 if (lookup->holder()->IsGlobalObject()) { |
| 636 GlobalObject* global = GlobalObject::cast(lookup->holder()); |
| 637 JSGlobalPropertyCell* cell = |
| 638 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); |
| 639 if (!cell->value()->IsJSFunction()) return NULL; |
| 640 JSFunction* function = JSFunction::cast(cell->value()); |
| 641 maybe_code = StubCache::ComputeCallGlobal(argc, |
| 642 in_loop, |
| 643 kind_, |
| 644 *name, |
| 645 *receiver, |
| 646 global, |
| 647 cell, |
| 648 function); |
| 649 } else { |
| 650 // There is only one shared stub for calling normalized |
| 651 // properties. It does not traverse the prototype chain, so the |
| 652 // property must be found in the receiver for the stub to be |
| 653 // applicable. |
| 654 if (lookup->holder() != *receiver) return NULL; |
| 655 maybe_code = StubCache::ComputeCallNormal(argc, |
| 656 in_loop, |
| 657 kind_, |
| 658 *name, |
| 659 *receiver); |
| 660 } |
| 661 break; |
| 662 } |
| 663 case INTERCEPTOR: { |
| 664 ASSERT(HasInterceptorGetter(lookup->holder())); |
| 665 maybe_code = StubCache::ComputeCallInterceptor(argc, |
| 666 kind_, |
| 667 *name, |
| 668 *object, |
| 669 lookup->holder()); |
| 670 break; |
| 671 } |
| 672 default: |
| 673 maybe_code = NULL; |
| 674 break; |
| 675 } |
| 676 return maybe_code; |
| 677 } |
| 678 |
| 679 |
| 579 void CallICBase::UpdateCaches(LookupResult* lookup, | 680 void CallICBase::UpdateCaches(LookupResult* lookup, |
| 580 State state, | 681 State state, |
| 682 Code::ExtraICState extra_ic_state, |
| 581 Handle<Object> object, | 683 Handle<Object> object, |
| 582 Handle<String> name) { | 684 Handle<String> name) { |
| 583 // Bail out if we didn't find a result. | 685 // Bail out if we didn't find a result. |
| 584 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 686 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
| 585 | 687 |
| 586 if (lookup->holder() != *object && | 688 if (lookup->holder() != *object && |
| 587 HasNormalObjectsInPrototypeChain(lookup, object->GetPrototype())) { | 689 HasNormalObjectsInPrototypeChain(lookup, object->GetPrototype())) { |
| 588 // Suppress optimization for prototype chains with slow properties objects | 690 // Suppress optimization for prototype chains with slow properties objects |
| 589 // in the middle. | 691 // in the middle. |
| 590 return; | 692 return; |
| 591 } | 693 } |
| 592 | 694 |
| 593 // Compute the number of arguments. | 695 // Compute the number of arguments. |
| 594 int argc = target()->arguments_count(); | 696 int argc = target()->arguments_count(); |
| 595 InLoopFlag in_loop = target()->ic_in_loop(); | 697 InLoopFlag in_loop = target()->ic_in_loop(); |
| 596 MaybeObject* maybe_code = NULL; | 698 MaybeObject* maybe_code = NULL; |
| 597 Object* code; | 699 bool had_proto_failure = false; |
| 598 if (state == UNINITIALIZED) { | 700 if (state == UNINITIALIZED) { |
| 599 // This is the first time we execute this inline cache. | 701 // This is the first time we execute this inline cache. |
| 600 // Set the target to the pre monomorphic stub to delay | 702 // Set the target to the pre monomorphic stub to delay |
| 601 // setting the monomorphic state. | 703 // setting the monomorphic state. |
| 602 maybe_code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_); | 704 maybe_code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_); |
| 603 } else if (state == MONOMORPHIC) { | 705 } else if (state == MONOMORPHIC) { |
| 604 maybe_code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_); | 706 if (kind_ == Code::CALL_IC && |
| 707 TryUpdateExtraICState(lookup, object, &extra_ic_state)) { |
| 708 maybe_code = ComputeMonomorphicStub(lookup, |
| 709 state, |
| 710 extra_ic_state, |
| 711 object, |
| 712 name); |
| 713 } else if (kind_ == Code::CALL_IC && |
| 714 TryRemoveInvalidPrototypeDependentStub(target(), |
| 715 *object, |
| 716 *name)) { |
| 717 had_proto_failure = true; |
| 718 maybe_code = ComputeMonomorphicStub(lookup, |
| 719 state, |
| 720 extra_ic_state, |
| 721 object, |
| 722 name); |
| 723 } else { |
| 724 maybe_code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_); |
| 725 } |
| 605 } else { | 726 } else { |
| 606 // Compute monomorphic stub. | 727 maybe_code = ComputeMonomorphicStub(lookup, |
| 607 switch (lookup->type()) { | 728 state, |
| 608 case FIELD: { | 729 extra_ic_state, |
| 609 int index = lookup->GetFieldIndex(); | 730 object, |
| 610 maybe_code = StubCache::ComputeCallField(argc, | 731 name); |
| 611 in_loop, | |
| 612 kind_, | |
| 613 *name, | |
| 614 *object, | |
| 615 lookup->holder(), | |
| 616 index); | |
| 617 break; | |
| 618 } | |
| 619 case CONSTANT_FUNCTION: { | |
| 620 // Get the constant function and compute the code stub for this | |
| 621 // call; used for rewriting to monomorphic state and making sure | |
| 622 // that the code stub is in the stub cache. | |
| 623 JSFunction* function = lookup->GetConstantFunction(); | |
| 624 maybe_code = StubCache::ComputeCallConstant(argc, | |
| 625 in_loop, | |
| 626 kind_, | |
| 627 *name, | |
| 628 *object, | |
| 629 lookup->holder(), | |
| 630 function); | |
| 631 break; | |
| 632 } | |
| 633 case NORMAL: { | |
| 634 if (!object->IsJSObject()) return; | |
| 635 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 636 | |
| 637 if (lookup->holder()->IsGlobalObject()) { | |
| 638 GlobalObject* global = GlobalObject::cast(lookup->holder()); | |
| 639 JSGlobalPropertyCell* cell = | |
| 640 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | |
| 641 if (!cell->value()->IsJSFunction()) return; | |
| 642 JSFunction* function = JSFunction::cast(cell->value()); | |
| 643 maybe_code = StubCache::ComputeCallGlobal(argc, | |
| 644 in_loop, | |
| 645 kind_, | |
| 646 *name, | |
| 647 *receiver, | |
| 648 global, | |
| 649 cell, | |
| 650 function); | |
| 651 } else { | |
| 652 // There is only one shared stub for calling normalized | |
| 653 // properties. It does not traverse the prototype chain, so the | |
| 654 // property must be found in the receiver for the stub to be | |
| 655 // applicable. | |
| 656 if (lookup->holder() != *receiver) return; | |
| 657 maybe_code = StubCache::ComputeCallNormal(argc, | |
| 658 in_loop, | |
| 659 kind_, | |
| 660 *name, | |
| 661 *receiver); | |
| 662 } | |
| 663 break; | |
| 664 } | |
| 665 case INTERCEPTOR: { | |
| 666 ASSERT(HasInterceptorGetter(lookup->holder())); | |
| 667 maybe_code = StubCache::ComputeCallInterceptor(argc, | |
| 668 kind_, | |
| 669 *name, | |
| 670 *object, | |
| 671 lookup->holder()); | |
| 672 break; | |
| 673 } | |
| 674 default: | |
| 675 return; | |
| 676 } | |
| 677 } | 732 } |
| 678 | 733 |
| 679 // If we're unable to compute the stub (not enough memory left), we | 734 // If we're unable to compute the stub (not enough memory left), we |
| 680 // simply avoid updating the caches. | 735 // simply avoid updating the caches. |
| 736 Object* code; |
| 681 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 737 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
| 682 | 738 |
| 683 // Patch the call site depending on the state of the cache. | 739 // Patch the call site depending on the state of the cache. |
| 684 if (state == UNINITIALIZED || | 740 if (state == UNINITIALIZED || |
| 685 state == PREMONOMORPHIC || | 741 state == PREMONOMORPHIC || |
| 686 state == MONOMORPHIC || | 742 state == MONOMORPHIC || |
| 687 state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 743 state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
| 688 set_target(Code::cast(code)); | 744 set_target(Code::cast(code)); |
| 689 } else if (state == MEGAMORPHIC) { | 745 } else if (state == MEGAMORPHIC) { |
| 690 // Cache code holding map should be consistent with | 746 // Cache code holding map should be consistent with |
| 691 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. | 747 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. |
| 692 Map* map = JSObject::cast(object->IsJSObject() ? *object : | 748 Map* map = JSObject::cast(object->IsJSObject() ? *object : |
| 693 object->GetPrototype())->map(); | 749 object->GetPrototype())->map(); |
| 694 | 750 |
| 695 // Update the stub cache. | 751 // Update the stub cache. |
| 696 StubCache::Set(*name, map, Code::cast(code)); | 752 StubCache::Set(*name, map, Code::cast(code)); |
| 697 } | 753 } |
| 698 | 754 |
| 755 USE(had_proto_failure); |
| 699 #ifdef DEBUG | 756 #ifdef DEBUG |
| 757 if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE; |
| 700 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", | 758 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", |
| 701 name, state, target(), in_loop ? " (in-loop)" : ""); | 759 name, state, target(), in_loop ? " (in-loop)" : ""); |
| 702 #endif | 760 #endif |
| 703 } | 761 } |
| 704 | 762 |
| 705 | 763 |
| 706 MaybeObject* KeyedCallIC::LoadFunction(State state, | 764 MaybeObject* KeyedCallIC::LoadFunction(State state, |
| 707 Handle<Object> object, | 765 Handle<Object> object, |
| 708 Handle<Object> key) { | 766 Handle<Object> key) { |
| 709 if (key->IsSymbol()) { | 767 if (key->IsSymbol()) { |
| 710 return CallICBase::LoadFunction(state, object, Handle<String>::cast(key)); | 768 return CallICBase::LoadFunction(state, |
| 769 Code::kNoExtraICState, |
| 770 object, |
| 771 Handle<String>::cast(key)); |
| 711 } | 772 } |
| 712 | 773 |
| 713 if (object->IsUndefined() || object->IsNull()) { | 774 if (object->IsUndefined() || object->IsNull()) { |
| 714 return TypeError("non_object_property_call", object, key); | 775 return TypeError("non_object_property_call", object, key); |
| 715 } | 776 } |
| 716 | 777 |
| 717 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | 778 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
| 718 ReceiverToObject(object); | 779 ReceiverToObject(object); |
| 719 } | 780 } |
| 720 | 781 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 757 MaybeObject* LoadIC::Load(State state, | 818 MaybeObject* LoadIC::Load(State state, |
| 758 Handle<Object> object, | 819 Handle<Object> object, |
| 759 Handle<String> name) { | 820 Handle<String> name) { |
| 760 // If the object is undefined or null it's illegal to try to get any | 821 // If the object is undefined or null it's illegal to try to get any |
| 761 // of its properties; throw a TypeError in that case. | 822 // of its properties; throw a TypeError in that case. |
| 762 if (object->IsUndefined() || object->IsNull()) { | 823 if (object->IsUndefined() || object->IsNull()) { |
| 763 return TypeError("non_object_property_load", object, name); | 824 return TypeError("non_object_property_load", object, name); |
| 764 } | 825 } |
| 765 | 826 |
| 766 if (FLAG_use_ic) { | 827 if (FLAG_use_ic) { |
| 828 Code* non_monomorphic_stub = |
| 829 (state == UNINITIALIZED) ? pre_monomorphic_stub() : megamorphic_stub(); |
| 830 |
| 767 // Use specialized code for getting the length of strings and | 831 // Use specialized code for getting the length of strings and |
| 768 // string wrapper objects. The length property of string wrapper | 832 // string wrapper objects. The length property of string wrapper |
| 769 // objects is read-only and therefore always returns the length of | 833 // objects is read-only and therefore always returns the length of |
| 770 // the underlying string value. See ECMA-262 15.5.5.1. | 834 // the underlying string value. See ECMA-262 15.5.5.1. |
| 771 if ((object->IsString() || object->IsStringWrapper()) && | 835 if ((object->IsString() || object->IsStringWrapper()) && |
| 772 name->Equals(Heap::length_symbol())) { | 836 name->Equals(Heap::length_symbol())) { |
| 773 HandleScope scope; | 837 HandleScope scope; |
| 838 #ifdef DEBUG |
| 839 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); |
| 840 #endif |
| 841 if (state == PREMONOMORPHIC) { |
| 842 if (object->IsString()) { |
| 843 Map* map = HeapObject::cast(*object)->map(); |
| 844 const int offset = String::kLengthOffset; |
| 845 PatchInlinedLoad(address(), map, offset); |
| 846 set_target(Builtins::builtin(Builtins::LoadIC_StringLength)); |
| 847 } else { |
| 848 set_target(Builtins::builtin(Builtins::LoadIC_StringWrapperLength)); |
| 849 } |
| 850 } else if (state == MONOMORPHIC && object->IsStringWrapper()) { |
| 851 set_target(Builtins::builtin(Builtins::LoadIC_StringWrapperLength)); |
| 852 } else { |
| 853 set_target(non_monomorphic_stub); |
| 854 } |
| 774 // Get the string if we have a string wrapper object. | 855 // Get the string if we have a string wrapper object. |
| 775 if (object->IsJSValue()) { | 856 if (object->IsJSValue()) { |
| 776 object = Handle<Object>(Handle<JSValue>::cast(object)->value()); | 857 object = Handle<Object>(Handle<JSValue>::cast(object)->value()); |
| 777 } | 858 } |
| 778 #ifdef DEBUG | |
| 779 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); | |
| 780 #endif | |
| 781 Map* map = HeapObject::cast(*object)->map(); | |
| 782 if (object->IsString()) { | |
| 783 const int offset = String::kLengthOffset; | |
| 784 PatchInlinedLoad(address(), map, offset); | |
| 785 } | |
| 786 | |
| 787 Code* target = NULL; | |
| 788 target = Builtins::builtin(Builtins::LoadIC_StringLength); | |
| 789 set_target(target); | |
| 790 return Smi::FromInt(String::cast(*object)->length()); | 859 return Smi::FromInt(String::cast(*object)->length()); |
| 791 } | 860 } |
| 792 | 861 |
| 793 // Use specialized code for getting the length of arrays. | 862 // Use specialized code for getting the length of arrays. |
| 794 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) { | 863 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) { |
| 795 #ifdef DEBUG | 864 #ifdef DEBUG |
| 796 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); | 865 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); |
| 797 #endif | 866 #endif |
| 798 Map* map = HeapObject::cast(*object)->map(); | 867 if (state == PREMONOMORPHIC) { |
| 799 const int offset = JSArray::kLengthOffset; | 868 Map* map = HeapObject::cast(*object)->map(); |
| 800 PatchInlinedLoad(address(), map, offset); | 869 const int offset = JSArray::kLengthOffset; |
| 801 | 870 PatchInlinedLoad(address(), map, offset); |
| 802 Code* target = Builtins::builtin(Builtins::LoadIC_ArrayLength); | 871 set_target(Builtins::builtin(Builtins::LoadIC_ArrayLength)); |
| 803 set_target(target); | 872 } else { |
| 873 set_target(non_monomorphic_stub); |
| 874 } |
| 804 return JSArray::cast(*object)->length(); | 875 return JSArray::cast(*object)->length(); |
| 805 } | 876 } |
| 806 | 877 |
| 807 // Use specialized code for getting prototype of functions. | 878 // Use specialized code for getting prototype of functions. |
| 808 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol()) && | 879 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol()) && |
| 809 JSFunction::cast(*object)->should_have_prototype()) { | 880 JSFunction::cast(*object)->should_have_prototype()) { |
| 810 #ifdef DEBUG | 881 #ifdef DEBUG |
| 811 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); | 882 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); |
| 812 #endif | 883 #endif |
| 813 Code* target = Builtins::builtin(Builtins::LoadIC_FunctionPrototype); | 884 if (state == PREMONOMORPHIC) { |
| 814 set_target(target); | 885 set_target(Builtins::builtin(Builtins::LoadIC_FunctionPrototype)); |
| 886 } else { |
| 887 set_target(non_monomorphic_stub); |
| 888 } |
| 815 return Accessors::FunctionGetPrototype(*object, 0); | 889 return Accessors::FunctionGetPrototype(*object, 0); |
| 816 } | 890 } |
| 817 } | 891 } |
| 818 | 892 |
| 819 // Check if the name is trivially convertible to an index and get | 893 // Check if the name is trivially convertible to an index and get |
| 820 // the element if so. | 894 // the element if so. |
| 821 uint32_t index; | 895 uint32_t index; |
| 822 if (name->AsArrayIndex(&index)) return object->GetElement(index); | 896 if (name->AsArrayIndex(&index)) return object->GetElement(index); |
| 823 | 897 |
| 824 // Named lookup in the object. | 898 // Named lookup in the object. |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1027 if (key->IsSymbol()) { | 1101 if (key->IsSymbol()) { |
| 1028 Handle<String> name = Handle<String>::cast(key); | 1102 Handle<String> name = Handle<String>::cast(key); |
| 1029 | 1103 |
| 1030 // If the object is undefined or null it's illegal to try to get any | 1104 // If the object is undefined or null it's illegal to try to get any |
| 1031 // of its properties; throw a TypeError in that case. | 1105 // of its properties; throw a TypeError in that case. |
| 1032 if (object->IsUndefined() || object->IsNull()) { | 1106 if (object->IsUndefined() || object->IsNull()) { |
| 1033 return TypeError("non_object_property_load", object, name); | 1107 return TypeError("non_object_property_load", object, name); |
| 1034 } | 1108 } |
| 1035 | 1109 |
| 1036 if (FLAG_use_ic) { | 1110 if (FLAG_use_ic) { |
| 1111 // TODO(1073): don't ignore the current stub state. |
| 1112 |
| 1037 // Use specialized code for getting the length of strings. | 1113 // Use specialized code for getting the length of strings. |
| 1038 if (object->IsString() && name->Equals(Heap::length_symbol())) { | 1114 if (object->IsString() && name->Equals(Heap::length_symbol())) { |
| 1039 Handle<String> string = Handle<String>::cast(object); | 1115 Handle<String> string = Handle<String>::cast(object); |
| 1040 Object* code = NULL; | 1116 Object* code = NULL; |
| 1041 { MaybeObject* maybe_code = | 1117 { MaybeObject* maybe_code = |
| 1042 StubCache::ComputeKeyedLoadStringLength(*name, *string); | 1118 StubCache::ComputeKeyedLoadStringLength(*name, *string); |
| 1043 if (!maybe_code->ToObject(&code)) return maybe_code; | 1119 if (!maybe_code->ToObject(&code)) return maybe_code; |
| 1044 } | 1120 } |
| 1045 set_target(Code::cast(code)); | 1121 set_target(Code::cast(code)); |
| 1046 #ifdef DEBUG | 1122 #ifdef DEBUG |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1124 | 1200 |
| 1125 return object->GetProperty(*object, &lookup, *name, &attr); | 1201 return object->GetProperty(*object, &lookup, *name, &attr); |
| 1126 } | 1202 } |
| 1127 | 1203 |
| 1128 // Do not use ICs for objects that require access checks (including | 1204 // Do not use ICs for objects that require access checks (including |
| 1129 // the global object). | 1205 // the global object). |
| 1130 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1206 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 1131 | 1207 |
| 1132 if (use_ic) { | 1208 if (use_ic) { |
| 1133 Code* stub = generic_stub(); | 1209 Code* stub = generic_stub(); |
| 1134 if (object->IsString() && key->IsNumber()) { | 1210 if (state == UNINITIALIZED) { |
| 1135 stub = string_stub(); | 1211 if (object->IsString() && key->IsNumber()) { |
| 1136 } else if (object->IsJSObject()) { | 1212 stub = string_stub(); |
| 1137 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1213 } else if (object->IsJSObject()) { |
| 1138 if (receiver->HasExternalArrayElements()) { | 1214 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1139 stub = external_array_stub(receiver->GetElementsKind()); | 1215 if (receiver->HasExternalArrayElements()) { |
| 1140 } else if (receiver->HasIndexedInterceptor()) { | 1216 MaybeObject* probe = |
| 1141 stub = indexed_interceptor_stub(); | 1217 StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, |
| 1142 } else if (state == UNINITIALIZED && | 1218 false); |
| 1143 key->IsSmi() && | 1219 stub = probe->IsFailure() ? |
| 1144 receiver->map()->has_fast_elements()) { | 1220 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1145 MaybeObject* probe = StubCache::ComputeKeyedLoadSpecialized(*receiver); | 1221 } else if (receiver->HasIndexedInterceptor()) { |
| 1146 stub = | 1222 stub = indexed_interceptor_stub(); |
| 1147 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); | 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() && |
| 1229 receiver->map()->has_fast_elements()) { |
| 1230 MaybeObject* probe = |
| 1231 StubCache::ComputeKeyedLoadSpecialized(*receiver); |
| 1232 stub = probe->IsFailure() ? |
| 1233 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1234 } |
| 1148 } | 1235 } |
| 1149 } | 1236 } |
| 1150 if (stub != NULL) set_target(stub); | 1237 if (stub != NULL) set_target(stub); |
| 1151 | 1238 |
| 1152 #ifdef DEBUG | 1239 #ifdef DEBUG |
| 1153 TraceIC("KeyedLoadIC", key, state, target()); | 1240 TraceIC("KeyedLoadIC", key, state, target()); |
| 1154 #endif // DEBUG | 1241 #endif // DEBUG |
| 1155 | 1242 |
| 1156 // For JSObjects with fast elements that are not value wrappers | 1243 // For JSObjects with fast elements that are not value wrappers |
| 1157 // and that do not have indexed interceptors, we initialize the | 1244 // and that do not have indexed interceptors, we initialize the |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1277 object->LocalLookupRealNamedProperty(name, lookup); | 1364 object->LocalLookupRealNamedProperty(name, lookup); |
| 1278 return StoreICableLookup(lookup); | 1365 return StoreICableLookup(lookup); |
| 1279 } | 1366 } |
| 1280 } | 1367 } |
| 1281 | 1368 |
| 1282 return true; | 1369 return true; |
| 1283 } | 1370 } |
| 1284 | 1371 |
| 1285 | 1372 |
| 1286 MaybeObject* StoreIC::Store(State state, | 1373 MaybeObject* StoreIC::Store(State state, |
| 1374 Code::ExtraICState extra_ic_state, |
| 1287 Handle<Object> object, | 1375 Handle<Object> object, |
| 1288 Handle<String> name, | 1376 Handle<String> name, |
| 1289 Handle<Object> value) { | 1377 Handle<Object> value) { |
| 1290 // If the object is undefined or null it's illegal to try to set any | 1378 // If the object is undefined or null it's illegal to try to set any |
| 1291 // properties on it; throw a TypeError in that case. | 1379 // properties on it; throw a TypeError in that case. |
| 1292 if (object->IsUndefined() || object->IsNull()) { | 1380 if (object->IsUndefined() || object->IsNull()) { |
| 1293 return TypeError("non_object_property_store", object, name); | 1381 return TypeError("non_object_property_store", object, name); |
| 1294 } | 1382 } |
| 1295 | 1383 |
| 1296 // Ignore stores where the receiver is not a JSObject. | 1384 // Ignore stores where the receiver is not a JSObject. |
| 1297 if (!object->IsJSObject()) return *value; | 1385 if (!object->IsJSObject()) return *value; |
| 1298 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1386 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1299 | 1387 |
| 1300 // Check if the given name is an array index. | 1388 // Check if the given name is an array index. |
| 1301 uint32_t index; | 1389 uint32_t index; |
| 1302 if (name->AsArrayIndex(&index)) { | 1390 if (name->AsArrayIndex(&index)) { |
| 1303 HandleScope scope; | 1391 HandleScope scope; |
| 1304 Handle<Object> result = SetElement(receiver, index, value); | 1392 Handle<Object> result = SetElement(receiver, index, value); |
| 1305 if (result.is_null()) return Failure::Exception(); | 1393 if (result.is_null()) return Failure::Exception(); |
| 1306 return *value; | 1394 return *value; |
| 1307 } | 1395 } |
| 1308 | 1396 |
| 1309 // Use specialized code for setting the length of arrays. | 1397 // Use specialized code for setting the length of arrays. |
| 1310 if (receiver->IsJSArray() | 1398 if (receiver->IsJSArray() |
| 1311 && name->Equals(Heap::length_symbol()) | 1399 && name->Equals(Heap::length_symbol()) |
| 1312 && receiver->AllowsSetElementsLength()) { | 1400 && receiver->AllowsSetElementsLength()) { |
| 1313 #ifdef DEBUG | 1401 #ifdef DEBUG |
| 1314 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); | 1402 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); |
| 1315 #endif | 1403 #endif |
| 1316 Code* target = Builtins::builtin(Builtins::StoreIC_ArrayLength); | 1404 Builtins::Name target = (extra_ic_state == kStoreICStrict) |
| 1317 set_target(target); | 1405 ? Builtins::StoreIC_ArrayLength_Strict |
| 1406 : Builtins::StoreIC_ArrayLength; |
| 1407 set_target(Builtins::builtin(target)); |
| 1318 return receiver->SetProperty(*name, *value, NONE); | 1408 return receiver->SetProperty(*name, *value, NONE); |
| 1319 } | 1409 } |
| 1320 | 1410 |
| 1321 // Lookup the property locally in the receiver. | 1411 // Lookup the property locally in the receiver. |
| 1322 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { | 1412 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { |
| 1323 LookupResult lookup; | 1413 LookupResult lookup; |
| 1324 | 1414 |
| 1325 if (LookupForWrite(*receiver, *name, &lookup)) { | 1415 if (LookupForWrite(*receiver, *name, &lookup)) { |
| 1326 bool can_be_inlined = | 1416 bool can_be_inlined = |
| 1327 state == UNINITIALIZED && | 1417 state == UNINITIALIZED && |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1365 if (FLAG_trace_ic) { | 1455 if (FLAG_trace_ic) { |
| 1366 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n", | 1456 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n", |
| 1367 *name->ToCString()); | 1457 *name->ToCString()); |
| 1368 #endif | 1458 #endif |
| 1369 } | 1459 } |
| 1370 } | 1460 } |
| 1371 } | 1461 } |
| 1372 | 1462 |
| 1373 // If no inlined store ic was patched, generate a stub for this | 1463 // If no inlined store ic was patched, generate a stub for this |
| 1374 // store. | 1464 // store. |
| 1375 UpdateCaches(&lookup, state, receiver, name, value); | 1465 UpdateCaches(&lookup, state, extra_ic_state, receiver, name, value); |
| 1466 } else { |
| 1467 // Strict mode doesn't allow setting non-existent global property. |
| 1468 if (extra_ic_state == kStoreICStrict && IsContextual(object)) { |
| 1469 return ReferenceError("not_defined", name); |
| 1470 } |
| 1376 } | 1471 } |
| 1377 } | 1472 } |
| 1378 | 1473 |
| 1379 if (receiver->IsJSGlobalProxy()) { | 1474 if (receiver->IsJSGlobalProxy()) { |
| 1380 // Generate a generic stub that goes to the runtime when we see a global | 1475 // Generate a generic stub that goes to the runtime when we see a global |
| 1381 // proxy as receiver. | 1476 // proxy as receiver. |
| 1382 if (target() != global_proxy_stub()) { | 1477 Code* stub = (extra_ic_state == kStoreICStrict) |
| 1383 set_target(global_proxy_stub()); | 1478 ? global_proxy_stub_strict() |
| 1479 : global_proxy_stub(); |
| 1480 if (target() != stub) { |
| 1481 set_target(stub); |
| 1384 #ifdef DEBUG | 1482 #ifdef DEBUG |
| 1385 TraceIC("StoreIC", name, state, target()); | 1483 TraceIC("StoreIC", name, state, target()); |
| 1386 #endif | 1484 #endif |
| 1387 } | 1485 } |
| 1388 } | 1486 } |
| 1389 | 1487 |
| 1390 // Set the property. | 1488 // Set the property. |
| 1391 return receiver->SetProperty(*name, *value, NONE); | 1489 return receiver->SetProperty(*name, *value, NONE); |
| 1392 } | 1490 } |
| 1393 | 1491 |
| 1394 | 1492 |
| 1395 void StoreIC::UpdateCaches(LookupResult* lookup, | 1493 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 1396 State state, | 1494 State state, |
| 1495 Code::ExtraICState extra_ic_state, |
| 1397 Handle<JSObject> receiver, | 1496 Handle<JSObject> receiver, |
| 1398 Handle<String> name, | 1497 Handle<String> name, |
| 1399 Handle<Object> value) { | 1498 Handle<Object> value) { |
| 1400 // Skip JSGlobalProxy. | 1499 // Skip JSGlobalProxy. |
| 1401 ASSERT(!receiver->IsJSGlobalProxy()); | 1500 ASSERT(!receiver->IsJSGlobalProxy()); |
| 1402 | 1501 |
| 1403 ASSERT(StoreICableLookup(lookup)); | 1502 ASSERT(StoreICableLookup(lookup)); |
| 1404 | 1503 |
| 1405 // If the property has a non-field type allowing map transitions | 1504 // If the property has a non-field type allowing map transitions |
| 1406 // where there is extra room in the object, we leave the IC in its | 1505 // where there is extra room in the object, we leave the IC in its |
| 1407 // current state. | 1506 // current state. |
| 1408 PropertyType type = lookup->type(); | 1507 PropertyType type = lookup->type(); |
| 1409 | 1508 |
| 1410 // Compute the code stub for this store; used for rewriting to | 1509 // Compute the code stub for this store; used for rewriting to |
| 1411 // monomorphic state and making sure that the code stub is in the | 1510 // monomorphic state and making sure that the code stub is in the |
| 1412 // stub cache. | 1511 // stub cache. |
| 1413 MaybeObject* maybe_code = NULL; | 1512 MaybeObject* maybe_code = NULL; |
| 1414 Object* code = NULL; | 1513 Object* code = NULL; |
| 1415 switch (type) { | 1514 switch (type) { |
| 1416 case FIELD: { | 1515 case FIELD: { |
| 1417 maybe_code = StubCache::ComputeStoreField(*name, *receiver, | 1516 maybe_code = StubCache::ComputeStoreField( |
| 1418 lookup->GetFieldIndex()); | 1517 *name, *receiver, lookup->GetFieldIndex(), NULL, extra_ic_state); |
| 1419 break; | 1518 break; |
| 1420 } | 1519 } |
| 1421 case MAP_TRANSITION: { | 1520 case MAP_TRANSITION: { |
| 1422 if (lookup->GetAttributes() != NONE) return; | 1521 if (lookup->GetAttributes() != NONE) return; |
| 1423 HandleScope scope; | 1522 HandleScope scope; |
| 1424 ASSERT(type == MAP_TRANSITION); | 1523 ASSERT(type == MAP_TRANSITION); |
| 1425 Handle<Map> transition(lookup->GetTransitionMap()); | 1524 Handle<Map> transition(lookup->GetTransitionMap()); |
| 1426 int index = transition->PropertyIndexFor(*name); | 1525 int index = transition->PropertyIndexFor(*name); |
| 1427 maybe_code = StubCache::ComputeStoreField(*name, *receiver, | 1526 maybe_code = StubCache::ComputeStoreField( |
| 1428 index, *transition); | 1527 *name, *receiver, index, *transition, extra_ic_state); |
| 1429 break; | 1528 break; |
| 1430 } | 1529 } |
| 1431 case NORMAL: { | 1530 case NORMAL: { |
| 1432 if (receiver->IsGlobalObject()) { | 1531 if (receiver->IsGlobalObject()) { |
| 1433 // The stub generated for the global object picks the value directly | 1532 // The stub generated for the global object picks the value directly |
| 1434 // from the property cell. So the property must be directly on the | 1533 // from the property cell. So the property must be directly on the |
| 1435 // global object. | 1534 // global object. |
| 1436 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1535 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1437 JSGlobalPropertyCell* cell = | 1536 JSGlobalPropertyCell* cell = |
| 1438 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | 1537 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); |
| 1439 maybe_code = StubCache::ComputeStoreGlobal(*name, *global, cell); | 1538 maybe_code = StubCache::ComputeStoreGlobal( |
| 1539 *name, *global, cell, extra_ic_state); |
| 1440 } else { | 1540 } else { |
| 1441 if (lookup->holder() != *receiver) return; | 1541 if (lookup->holder() != *receiver) return; |
| 1442 maybe_code = StubCache::ComputeStoreNormal(); | 1542 maybe_code = StubCache::ComputeStoreNormal(extra_ic_state); |
| 1443 } | 1543 } |
| 1444 break; | 1544 break; |
| 1445 } | 1545 } |
| 1446 case CALLBACKS: { | 1546 case CALLBACKS: { |
| 1447 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 1547 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; |
| 1448 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1548 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); |
| 1449 if (v8::ToCData<Address>(callback->setter()) == 0) return; | 1549 if (v8::ToCData<Address>(callback->setter()) == 0) return; |
| 1450 maybe_code = StubCache::ComputeStoreCallback(*name, *receiver, callback); | 1550 maybe_code = StubCache::ComputeStoreCallback( |
| 1551 *name, *receiver, callback, extra_ic_state); |
| 1451 break; | 1552 break; |
| 1452 } | 1553 } |
| 1453 case INTERCEPTOR: { | 1554 case INTERCEPTOR: { |
| 1454 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); | 1555 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); |
| 1455 maybe_code = StubCache::ComputeStoreInterceptor(*name, *receiver); | 1556 maybe_code = StubCache::ComputeStoreInterceptor( |
| 1557 *name, *receiver, extra_ic_state); |
| 1456 break; | 1558 break; |
| 1457 } | 1559 } |
| 1458 default: | 1560 default: |
| 1459 return; | 1561 return; |
| 1460 } | 1562 } |
| 1461 | 1563 |
| 1462 // If we're unable to compute the stub (not enough memory left), we | 1564 // If we're unable to compute the stub (not enough memory left), we |
| 1463 // simply avoid updating the caches. | 1565 // simply avoid updating the caches. |
| 1464 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 1566 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
| 1465 | 1567 |
| 1466 // Patch the call site depending on the state of the cache. | 1568 // Patch the call site depending on the state of the cache. |
| 1467 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 1569 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
| 1468 set_target(Code::cast(code)); | 1570 set_target(Code::cast(code)); |
| 1469 } else if (state == MONOMORPHIC) { | 1571 } else if (state == MONOMORPHIC) { |
| 1470 // Only move to megamorphic if the target changes. | 1572 // Only move to megamorphic if the target changes. |
| 1471 if (target() != Code::cast(code)) set_target(megamorphic_stub()); | 1573 if (target() != Code::cast(code)) { |
| 1574 set_target(extra_ic_state == kStoreICStrict |
| 1575 ? megamorphic_stub_strict() |
| 1576 : megamorphic_stub()); |
| 1577 } |
| 1472 } else if (state == MEGAMORPHIC) { | 1578 } else if (state == MEGAMORPHIC) { |
| 1473 // Update the stub cache. | 1579 // Update the stub cache. |
| 1474 StubCache::Set(*name, receiver->map(), Code::cast(code)); | 1580 StubCache::Set(*name, receiver->map(), Code::cast(code)); |
| 1475 } | 1581 } |
| 1476 | 1582 |
| 1477 #ifdef DEBUG | 1583 #ifdef DEBUG |
| 1478 TraceIC("StoreIC", name, state, target()); | 1584 TraceIC("StoreIC", name, state, target()); |
| 1479 #endif | 1585 #endif |
| 1480 } | 1586 } |
| 1481 | 1587 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1519 return receiver->SetProperty(*name, *value, NONE); | 1625 return receiver->SetProperty(*name, *value, NONE); |
| 1520 } | 1626 } |
| 1521 | 1627 |
| 1522 // Do not use ICs for objects that require access checks (including | 1628 // Do not use ICs for objects that require access checks (including |
| 1523 // the global object). | 1629 // the global object). |
| 1524 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1630 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 1525 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1631 ASSERT(!(use_ic && object->IsJSGlobalProxy())); |
| 1526 | 1632 |
| 1527 if (use_ic) { | 1633 if (use_ic) { |
| 1528 Code* stub = generic_stub(); | 1634 Code* stub = generic_stub(); |
| 1529 if (object->IsJSObject()) { | 1635 if (state == UNINITIALIZED) { |
| 1530 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1636 if (object->IsJSObject()) { |
| 1531 if (receiver->HasExternalArrayElements()) { | 1637 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1532 stub = external_array_stub(receiver->GetElementsKind()); | 1638 if (receiver->HasExternalArrayElements()) { |
| 1533 } else if (state == UNINITIALIZED && | 1639 MaybeObject* probe = |
| 1534 key->IsSmi() && | 1640 StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, true); |
| 1535 receiver->map()->has_fast_elements()) { | 1641 stub = probe->IsFailure() ? |
| 1536 MaybeObject* probe = StubCache::ComputeKeyedStoreSpecialized(*receiver); | 1642 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1537 stub = | 1643 } else if (receiver->HasPixelElements()) { |
| 1538 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); | 1644 MaybeObject* probe = |
| 1645 StubCache::ComputeKeyedStorePixelArray(*receiver); |
| 1646 stub = probe->IsFailure() ? |
| 1647 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1648 } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { |
| 1649 MaybeObject* probe = |
| 1650 StubCache::ComputeKeyedStoreSpecialized(*receiver); |
| 1651 stub = probe->IsFailure() ? |
| 1652 NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1653 } |
| 1539 } | 1654 } |
| 1540 } | 1655 } |
| 1541 if (stub != NULL) set_target(stub); | 1656 if (stub != NULL) set_target(stub); |
| 1542 } | 1657 } |
| 1543 | 1658 |
| 1544 // Set the property. | 1659 // Set the property. |
| 1545 return Runtime::SetObjectProperty(object, key, value, NONE); | 1660 return Runtime::SetObjectProperty(object, key, value, NONE); |
| 1546 } | 1661 } |
| 1547 | 1662 |
| 1548 | 1663 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1634 return *function_handle; | 1749 return *function_handle; |
| 1635 } | 1750 } |
| 1636 | 1751 |
| 1637 | 1752 |
| 1638 // Used from ic-<arch>.cc. | 1753 // Used from ic-<arch>.cc. |
| 1639 MUST_USE_RESULT MaybeObject* CallIC_Miss(Arguments args) { | 1754 MUST_USE_RESULT MaybeObject* CallIC_Miss(Arguments args) { |
| 1640 NoHandleAllocation na; | 1755 NoHandleAllocation na; |
| 1641 ASSERT(args.length() == 2); | 1756 ASSERT(args.length() == 2); |
| 1642 CallIC ic; | 1757 CallIC ic; |
| 1643 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1758 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1759 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1760 MaybeObject* maybe_result = ic.LoadFunction(state, |
| 1761 extra_ic_state, |
| 1762 args.at<Object>(0), |
| 1763 args.at<String>(1)); |
| 1644 Object* result; | 1764 Object* result; |
| 1645 { MaybeObject* maybe_result = | 1765 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 1646 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); | |
| 1647 if (!maybe_result->ToObject(&result)) return maybe_result; | |
| 1648 } | |
| 1649 | 1766 |
| 1650 // The first time the inline cache is updated may be the first time the | 1767 // The first time the inline cache is updated may be the first time the |
| 1651 // function it references gets called. If the function was lazily compiled | 1768 // function it references gets called. If the function was lazily compiled |
| 1652 // then the first call will trigger a compilation. We check for this case | 1769 // then the first call will trigger a compilation. We check for this case |
| 1653 // and we do the compilation immediately, instead of waiting for the stub | 1770 // and we do the compilation immediately, instead of waiting for the stub |
| 1654 // currently attached to the JSFunction object to trigger compilation. We | 1771 // currently attached to the JSFunction object to trigger compilation. We |
| 1655 // do this in the case where we know that the inline cache is inside a loop, | 1772 // do this in the case where we know that the inline cache is inside a loop, |
| 1656 // because then we know that we want to optimize the function. | 1773 // because then we know that we want to optimize the function. |
| 1657 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { | 1774 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { |
| 1658 return result; | 1775 return result; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1699 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); | 1816 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); |
| 1700 } | 1817 } |
| 1701 | 1818 |
| 1702 | 1819 |
| 1703 // Used from ic-<arch>.cc. | 1820 // Used from ic-<arch>.cc. |
| 1704 MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { | 1821 MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { |
| 1705 NoHandleAllocation na; | 1822 NoHandleAllocation na; |
| 1706 ASSERT(args.length() == 3); | 1823 ASSERT(args.length() == 3); |
| 1707 StoreIC ic; | 1824 StoreIC ic; |
| 1708 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1825 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1709 return ic.Store(state, args.at<Object>(0), args.at<String>(1), | 1826 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1710 args.at<Object>(2)); | 1827 return ic.Store(state, extra_ic_state, args.at<Object>(0), |
| 1828 args.at<String>(1), args.at<Object>(2)); |
| 1711 } | 1829 } |
| 1712 | 1830 |
| 1713 | 1831 |
| 1714 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) { | 1832 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) { |
| 1715 NoHandleAllocation nha; | 1833 NoHandleAllocation nha; |
| 1716 | 1834 |
| 1717 ASSERT(args.length() == 2); | 1835 ASSERT(args.length() == 2); |
| 1718 JSObject* receiver = JSObject::cast(args[0]); | 1836 JSObject* receiver = JSObject::cast(args[0]); |
| 1719 Object* len = args[1]; | 1837 Object* len = args[1]; |
| 1720 | 1838 |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1965 ::v8::internal::TypeInfo left_type = | 2083 ::v8::internal::TypeInfo left_type = |
| 1966 ::v8::internal::TypeInfo::TypeFromValue(left); | 2084 ::v8::internal::TypeInfo::TypeFromValue(left); |
| 1967 ::v8::internal::TypeInfo right_type = | 2085 ::v8::internal::TypeInfo right_type = |
| 1968 ::v8::internal::TypeInfo::TypeFromValue(right); | 2086 ::v8::internal::TypeInfo::TypeFromValue(right); |
| 1969 | 2087 |
| 1970 if (left_type.IsSmi() && right_type.IsSmi()) { | 2088 if (left_type.IsSmi() && right_type.IsSmi()) { |
| 1971 return SMI; | 2089 return SMI; |
| 1972 } | 2090 } |
| 1973 | 2091 |
| 1974 if (left_type.IsInteger32() && right_type.IsInteger32()) { | 2092 if (left_type.IsInteger32() && right_type.IsInteger32()) { |
| 2093 // Platforms with 32-bit Smis have no distinct INT32 type. |
| 2094 if (kSmiValueSize == 32) return SMI; |
| 1975 return INT32; | 2095 return INT32; |
| 1976 } | 2096 } |
| 1977 | 2097 |
| 1978 if (left_type.IsNumber() && right_type.IsNumber()) { | 2098 if (left_type.IsNumber() && right_type.IsNumber()) { |
| 1979 return HEAP_NUMBER; | 2099 return HEAP_NUMBER; |
| 1980 } | 2100 } |
| 1981 | 2101 |
| 1982 if (left_type.IsString() || right_type.IsString()) { | 2102 if (left_type.IsString() || right_type.IsString()) { |
| 1983 // Patching for fast string ADD makes sense even if only one of the | 2103 // Patching for fast string ADD makes sense even if only one of the |
| 1984 // arguments is a string. | 2104 // arguments is a string. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2008 static_cast<TRBinaryOpIC::TypeInfo>(Smi::cast(args[4])->value()); | 2128 static_cast<TRBinaryOpIC::TypeInfo>(Smi::cast(args[4])->value()); |
| 2009 | 2129 |
| 2010 TRBinaryOpIC::TypeInfo type = TRBinaryOpIC::GetTypeInfo(left, right); | 2130 TRBinaryOpIC::TypeInfo type = TRBinaryOpIC::GetTypeInfo(left, right); |
| 2011 type = TRBinaryOpIC::JoinTypes(type, previous_type); | 2131 type = TRBinaryOpIC::JoinTypes(type, previous_type); |
| 2012 TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED; | 2132 TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED; |
| 2013 if (type == TRBinaryOpIC::STRING && op != Token::ADD) { | 2133 if (type == TRBinaryOpIC::STRING && op != Token::ADD) { |
| 2014 type = TRBinaryOpIC::GENERIC; | 2134 type = TRBinaryOpIC::GENERIC; |
| 2015 } | 2135 } |
| 2016 if (type == TRBinaryOpIC::SMI && | 2136 if (type == TRBinaryOpIC::SMI && |
| 2017 previous_type == TRBinaryOpIC::SMI) { | 2137 previous_type == TRBinaryOpIC::SMI) { |
| 2018 if (op == Token::DIV || op == Token::MUL) { | 2138 if (op == Token::DIV || op == Token::MUL || kSmiValueSize == 32) { |
| 2019 // Arithmetic on two Smi inputs has yielded a heap number. | 2139 // Arithmetic on two Smi inputs has yielded a heap number. |
| 2020 // That is the only way to get here from the Smi stub. | 2140 // That is the only way to get here from the Smi stub. |
| 2141 // With 32-bit Smis, all overflows give heap numbers, but with |
| 2142 // 31-bit Smis, most operations overflow to int32 results. |
| 2021 result_type = TRBinaryOpIC::HEAP_NUMBER; | 2143 result_type = TRBinaryOpIC::HEAP_NUMBER; |
| 2022 } else { | 2144 } else { |
| 2023 // Other operations on SMIs that overflow yield int32s. | 2145 // Other operations on SMIs that overflow yield int32s. |
| 2024 result_type = TRBinaryOpIC::INT32; | 2146 result_type = TRBinaryOpIC::INT32; |
| 2025 } | 2147 } |
| 2026 } | 2148 } |
| 2027 if (type == TRBinaryOpIC::INT32 && | 2149 if (type == TRBinaryOpIC::INT32 && |
| 2028 previous_type == TRBinaryOpIC::INT32) { | 2150 previous_type == TRBinaryOpIC::INT32) { |
| 2029 // We must be here because an operation on two INT32 types overflowed. | 2151 // We must be here because an operation on two INT32 types overflowed. |
| 2030 result_type = TRBinaryOpIC::HEAP_NUMBER; | 2152 result_type = TRBinaryOpIC::HEAP_NUMBER; |
| 2031 } | 2153 } |
| 2032 | 2154 |
| 2033 Handle<Code> code = GetTypeRecordingBinaryOpStub(key, type, result_type); | 2155 Handle<Code> code = GetTypeRecordingBinaryOpStub(key, type, result_type); |
| 2034 if (!code.is_null()) { | 2156 if (!code.is_null()) { |
| 2035 TRBinaryOpIC ic; | |
| 2036 ic.patch(*code); | |
| 2037 if (FLAG_trace_ic) { | 2157 if (FLAG_trace_ic) { |
| 2038 PrintF("[TypeRecordingBinaryOpIC (%s->(%s->%s))#%s]\n", | 2158 PrintF("[TypeRecordingBinaryOpIC (%s->(%s->%s))#%s]\n", |
| 2039 TRBinaryOpIC::GetName(previous_type), | 2159 TRBinaryOpIC::GetName(previous_type), |
| 2040 TRBinaryOpIC::GetName(type), | 2160 TRBinaryOpIC::GetName(type), |
| 2041 TRBinaryOpIC::GetName(result_type), | 2161 TRBinaryOpIC::GetName(result_type), |
| 2042 Token::Name(op)); | 2162 Token::Name(op)); |
| 2043 } | 2163 } |
| 2164 TRBinaryOpIC ic; |
| 2165 ic.patch(*code); |
| 2044 | 2166 |
| 2045 // Activate inlined smi code. | 2167 // Activate inlined smi code. |
| 2046 if (previous_type == TRBinaryOpIC::UNINITIALIZED) { | 2168 if (previous_type == TRBinaryOpIC::UNINITIALIZED) { |
| 2047 PatchInlinedSmiCode(ic.address()); | 2169 PatchInlinedSmiCode(ic.address()); |
| 2048 } | 2170 } |
| 2049 } | 2171 } |
| 2050 | 2172 |
| 2051 Handle<JSBuiltinsObject> builtins = Top::builtins(); | 2173 Handle<JSBuiltinsObject> builtins = Top::builtins(); |
| 2052 Object* builtin = NULL; // Initialization calms down the compiler. | 2174 Object* builtin = NULL; // Initialization calms down the compiler. |
| 2053 switch (op) { | 2175 switch (op) { |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2164 #undef ADDR | 2286 #undef ADDR |
| 2165 }; | 2287 }; |
| 2166 | 2288 |
| 2167 | 2289 |
| 2168 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2290 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2169 return IC_utilities[id]; | 2291 return IC_utilities[id]; |
| 2170 } | 2292 } |
| 2171 | 2293 |
| 2172 | 2294 |
| 2173 } } // namespace v8::internal | 2295 } } // namespace v8::internal |
| OLD | NEW |