| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/ic/call-optimization.h" | 7 #include "src/ic/handler-compiler.h" |
| 8 #include "src/ic/ic-inl.h" | 8 #include "src/ic/ic-inl.h" |
| 9 #include "src/ic/ic-compiler.h" | 9 #include "src/ic/ic-compiler.h" |
| 10 | 10 |
| 11 | 11 |
| 12 namespace v8 { | 12 namespace v8 { |
| 13 namespace internal { | 13 namespace internal { |
| 14 | 14 |
| 15 | 15 |
| 16 Handle<Code> PropertyICCompiler::Find(Handle<Name> name, | 16 Handle<Code> PropertyICCompiler::Find(Handle<Name> name, |
| 17 Handle<Map> stub_holder, Code::Kind kind, | 17 Handle<Map> stub_holder, Code::Kind kind, |
| 18 ExtraICState extra_state, | 18 ExtraICState extra_state, |
| 19 CacheHolderFlag cache_holder) { | 19 CacheHolderFlag cache_holder) { |
| 20 Code::Flags flags = | 20 Code::Flags flags = |
| 21 Code::ComputeMonomorphicFlags(kind, extra_state, cache_holder); | 21 Code::ComputeMonomorphicFlags(kind, extra_state, cache_holder); |
| 22 Object* probe = stub_holder->FindInCodeCache(*name, flags); | 22 Object* probe = stub_holder->FindInCodeCache(*name, flags); |
| 23 if (probe->IsCode()) return handle(Code::cast(probe)); | 23 if (probe->IsCode()) return handle(Code::cast(probe)); |
| 24 return Handle<Code>::null(); | 24 return Handle<Code>::null(); |
| 25 } | 25 } |
| 26 | 26 |
| 27 | 27 |
| 28 Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name, | 28 bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) { |
| 29 Handle<Map> stub_holder, | 29 for (int i = 0; i < types->length(); ++i) { |
| 30 Code::Kind kind, | 30 if (types->at(i)->Is(HeapType::Number())) return true; |
| 31 CacheHolderFlag cache_holder, | 31 } |
| 32 Code::StubType type) { | 32 return false; |
| 33 Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder); | |
| 34 Object* probe = stub_holder->FindInCodeCache(*name, flags); | |
| 35 if (probe->IsCode()) return handle(Code::cast(probe)); | |
| 36 return Handle<Code>::null(); | |
| 37 } | 33 } |
| 38 | 34 |
| 39 | 35 |
| 36 Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type, |
| 37 Handle<Code> handler, |
| 38 Handle<Name> name, |
| 39 IcCheckType check) { |
| 40 TypeHandleList types(1); |
| 41 CodeHandleList handlers(1); |
| 42 types.Add(type); |
| 43 handlers.Add(handler); |
| 44 Code::StubType stub_type = handler->type(); |
| 45 return CompilePolymorphic(&types, &handlers, name, stub_type, check); |
| 46 } |
| 47 |
| 48 |
| 40 Handle<Code> PropertyICCompiler::ComputeMonomorphic( | 49 Handle<Code> PropertyICCompiler::ComputeMonomorphic( |
| 41 Code::Kind kind, Handle<Name> name, Handle<HeapType> type, | 50 Code::Kind kind, Handle<Name> name, Handle<HeapType> type, |
| 42 Handle<Code> handler, ExtraICState extra_ic_state) { | 51 Handle<Code> handler, ExtraICState extra_ic_state) { |
| 43 Isolate* isolate = name->GetIsolate(); | 52 Isolate* isolate = name->GetIsolate(); |
| 44 if (handler.is_identical_to(isolate->builtins()->LoadIC_Normal()) || | 53 if (handler.is_identical_to(isolate->builtins()->LoadIC_Normal()) || |
| 45 handler.is_identical_to(isolate->builtins()->StoreIC_Normal())) { | 54 handler.is_identical_to(isolate->builtins()->StoreIC_Normal())) { |
| 46 name = isolate->factory()->normal_ic_symbol(); | 55 name = isolate->factory()->normal_ic_symbol(); |
| 47 } | 56 } |
| 48 | 57 |
| 49 CacheHolderFlag flag; | 58 CacheHolderFlag flag; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 67 #endif | 76 #endif |
| 68 | 77 |
| 69 PropertyICCompiler ic_compiler(isolate, kind, extra_ic_state, flag); | 78 PropertyICCompiler ic_compiler(isolate, kind, extra_ic_state, flag); |
| 70 ic = ic_compiler.CompileMonomorphic(type, handler, name, PROPERTY); | 79 ic = ic_compiler.CompileMonomorphic(type, handler, name, PROPERTY); |
| 71 | 80 |
| 72 if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic); | 81 if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic); |
| 73 return ic; | 82 return ic; |
| 74 } | 83 } |
| 75 | 84 |
| 76 | 85 |
| 77 Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent( | |
| 78 Handle<Name> name, Handle<HeapType> type) { | |
| 79 Isolate* isolate = name->GetIsolate(); | |
| 80 Handle<Map> receiver_map = IC::TypeToMap(*type, isolate); | |
| 81 if (receiver_map->prototype()->IsNull()) { | |
| 82 // TODO(jkummerow/verwaest): If there is no prototype and the property | |
| 83 // is nonexistent, introduce a builtin to handle this (fast properties | |
| 84 // -> return undefined, dictionary properties -> do negative lookup). | |
| 85 return Handle<Code>(); | |
| 86 } | |
| 87 CacheHolderFlag flag; | |
| 88 Handle<Map> stub_holder_map = | |
| 89 IC::GetHandlerCacheHolder(*type, false, isolate, &flag); | |
| 90 | |
| 91 // If no dictionary mode objects are present in the prototype chain, the load | |
| 92 // nonexistent IC stub can be shared for all names for a given map and we use | |
| 93 // the empty string for the map cache in that case. If there are dictionary | |
| 94 // mode objects involved, we need to do negative lookups in the stub and | |
| 95 // therefore the stub will be specific to the name. | |
| 96 Handle<Name> cache_name = | |
| 97 receiver_map->is_dictionary_map() | |
| 98 ? name | |
| 99 : Handle<Name>::cast(isolate->factory()->nonexistent_symbol()); | |
| 100 Handle<Map> current_map = stub_holder_map; | |
| 101 Handle<JSObject> last(JSObject::cast(receiver_map->prototype())); | |
| 102 while (true) { | |
| 103 if (current_map->is_dictionary_map()) cache_name = name; | |
| 104 if (current_map->prototype()->IsNull()) break; | |
| 105 last = handle(JSObject::cast(current_map->prototype())); | |
| 106 current_map = handle(last->map()); | |
| 107 } | |
| 108 // Compile the stub that is either shared for all names or | |
| 109 // name specific if there are global objects involved. | |
| 110 Handle<Code> handler = PropertyHandlerCompiler::Find( | |
| 111 cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST); | |
| 112 if (!handler.is_null()) return handler; | |
| 113 | |
| 114 NamedLoadHandlerCompiler compiler(isolate, type, last, flag); | |
| 115 handler = compiler.CompileLoadNonexistent(cache_name); | |
| 116 Map::UpdateCodeCache(stub_holder_map, cache_name, handler); | |
| 117 return handler; | |
| 118 } | |
| 119 | |
| 120 | |
| 121 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic( | 86 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic( |
| 122 Handle<Map> receiver_map) { | 87 Handle<Map> receiver_map) { |
| 123 Isolate* isolate = receiver_map->GetIsolate(); | 88 Isolate* isolate = receiver_map->GetIsolate(); |
| 124 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC); | 89 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC); |
| 125 Handle<Name> name = isolate->factory()->KeyedLoadMonomorphic_string(); | 90 Handle<Name> name = isolate->factory()->KeyedLoadMonomorphic_string(); |
| 126 | 91 |
| 127 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate); | 92 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate); |
| 128 if (probe->IsCode()) return Handle<Code>::cast(probe); | 93 if (probe->IsCode()) return Handle<Code>::cast(probe); |
| 129 | 94 |
| 130 ElementsKind elements_kind = receiver_map->elements_kind(); | 95 ElementsKind elements_kind = receiver_map->elements_kind(); |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 393 | 358 |
| 394 | 359 |
| 395 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) { | 360 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) { |
| 396 StoreIC::GenerateMegamorphic(masm()); | 361 StoreIC::GenerateMegamorphic(masm()); |
| 397 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic"); | 362 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic"); |
| 398 PROFILE(isolate(), CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0)); | 363 PROFILE(isolate(), CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0)); |
| 399 return code; | 364 return code; |
| 400 } | 365 } |
| 401 | 366 |
| 402 | 367 |
| 403 #define __ ACCESS_MASM(masm()) | |
| 404 | |
| 405 | |
| 406 Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, | |
| 407 Handle<Name> name, | |
| 408 Label* miss) { | |
| 409 PrototypeCheckType check_type = CHECK_ALL_MAPS; | |
| 410 int function_index = -1; | |
| 411 if (type()->Is(HeapType::String())) { | |
| 412 function_index = Context::STRING_FUNCTION_INDEX; | |
| 413 } else if (type()->Is(HeapType::Symbol())) { | |
| 414 function_index = Context::SYMBOL_FUNCTION_INDEX; | |
| 415 } else if (type()->Is(HeapType::Number())) { | |
| 416 function_index = Context::NUMBER_FUNCTION_INDEX; | |
| 417 } else if (type()->Is(HeapType::Boolean())) { | |
| 418 function_index = Context::BOOLEAN_FUNCTION_INDEX; | |
| 419 } else { | |
| 420 check_type = SKIP_RECEIVER; | |
| 421 } | |
| 422 | |
| 423 if (check_type == CHECK_ALL_MAPS) { | |
| 424 GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index, | |
| 425 scratch1(), miss); | |
| 426 Object* function = isolate()->native_context()->get(function_index); | |
| 427 Object* prototype = JSFunction::cast(function)->instance_prototype(); | |
| 428 set_type_for_object(handle(prototype, isolate())); | |
| 429 object_reg = scratch1(); | |
| 430 } | |
| 431 | |
| 432 // Check that the maps starting from the prototype haven't changed. | |
| 433 return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name, | |
| 434 miss, check_type); | |
| 435 } | |
| 436 | |
| 437 | |
| 438 // Frontend for store uses the name register. It has to be restored before a | |
| 439 // miss. | |
| 440 Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg, | |
| 441 Handle<Name> name, | |
| 442 Label* miss) { | |
| 443 return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name, | |
| 444 miss, SKIP_RECEIVER); | |
| 445 } | |
| 446 | |
| 447 | |
| 448 bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) { | |
| 449 for (int i = 0; i < types->length(); ++i) { | |
| 450 if (types->at(i)->Is(HeapType::Number())) return true; | |
| 451 } | |
| 452 return false; | |
| 453 } | |
| 454 | |
| 455 | |
| 456 Register PropertyHandlerCompiler::Frontend(Register object_reg, | |
| 457 Handle<Name> name) { | |
| 458 Label miss; | |
| 459 Register reg = FrontendHeader(object_reg, name, &miss); | |
| 460 FrontendFooter(name, &miss); | |
| 461 return reg; | |
| 462 } | |
| 463 | |
| 464 | |
| 465 void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name, | |
| 466 Label* miss, | |
| 467 Register scratch1, | |
| 468 Register scratch2) { | |
| 469 Register holder_reg; | |
| 470 Handle<Map> last_map; | |
| 471 if (holder().is_null()) { | |
| 472 holder_reg = receiver(); | |
| 473 last_map = IC::TypeToMap(*type(), isolate()); | |
| 474 // If |type| has null as its prototype, |holder()| is | |
| 475 // Handle<JSObject>::null(). | |
| 476 DCHECK(last_map->prototype() == isolate()->heap()->null_value()); | |
| 477 } else { | |
| 478 holder_reg = FrontendHeader(receiver(), name, miss); | |
| 479 last_map = handle(holder()->map()); | |
| 480 } | |
| 481 | |
| 482 if (last_map->is_dictionary_map()) { | |
| 483 if (last_map->IsJSGlobalObjectMap()) { | |
| 484 Handle<JSGlobalObject> global = | |
| 485 holder().is_null() | |
| 486 ? Handle<JSGlobalObject>::cast(type()->AsConstant()->Value()) | |
| 487 : Handle<JSGlobalObject>::cast(holder()); | |
| 488 GenerateCheckPropertyCell(masm(), global, name, scratch1, miss); | |
| 489 } else { | |
| 490 if (!name->IsUniqueName()) { | |
| 491 DCHECK(name->IsString()); | |
| 492 name = factory()->InternalizeString(Handle<String>::cast(name)); | |
| 493 } | |
| 494 DCHECK(holder().is_null() || | |
| 495 holder()->property_dictionary()->FindEntry(name) == | |
| 496 NameDictionary::kNotFound); | |
| 497 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1, | |
| 498 scratch2); | |
| 499 } | |
| 500 } | |
| 501 } | |
| 502 | |
| 503 | |
| 504 Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name, | |
| 505 FieldIndex field) { | |
| 506 Register reg = Frontend(receiver(), name); | |
| 507 __ Move(receiver(), reg); | |
| 508 LoadFieldStub stub(isolate(), field); | |
| 509 GenerateTailCall(masm(), stub.GetCode()); | |
| 510 return GetCode(kind(), Code::FAST, name); | |
| 511 } | |
| 512 | |
| 513 | |
| 514 Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name, | |
| 515 int constant_index) { | |
| 516 Register reg = Frontend(receiver(), name); | |
| 517 __ Move(receiver(), reg); | |
| 518 LoadConstantStub stub(isolate(), constant_index); | |
| 519 GenerateTailCall(masm(), stub.GetCode()); | |
| 520 return GetCode(kind(), Code::FAST, name); | |
| 521 } | |
| 522 | |
| 523 | |
| 524 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent( | |
| 525 Handle<Name> name) { | |
| 526 Label miss; | |
| 527 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3()); | |
| 528 GenerateLoadConstant(isolate()->factory()->undefined_value()); | |
| 529 FrontendFooter(name, &miss); | |
| 530 return GetCode(kind(), Code::FAST, name); | |
| 531 } | |
| 532 | |
| 533 | |
| 534 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( | |
| 535 Handle<Name> name, Handle<ExecutableAccessorInfo> callback) { | |
| 536 Register reg = Frontend(receiver(), name); | |
| 537 GenerateLoadCallback(reg, callback); | |
| 538 return GetCode(kind(), Code::FAST, name); | |
| 539 } | |
| 540 | |
| 541 | |
| 542 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( | |
| 543 Handle<Name> name, const CallOptimization& call_optimization) { | |
| 544 DCHECK(call_optimization.is_simple_api_call()); | |
| 545 Frontend(receiver(), name); | |
| 546 Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate()); | |
| 547 GenerateFastApiCall(masm(), call_optimization, receiver_map, receiver(), | |
| 548 scratch1(), false, 0, NULL); | |
| 549 return GetCode(kind(), Code::FAST, name); | |
| 550 } | |
| 551 | |
| 552 | |
| 553 Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor( | |
| 554 LookupIterator* it) { | |
| 555 // So far the most popular follow ups for interceptor loads are FIELD and | |
| 556 // ExecutableAccessorInfo, so inline only them. Other cases may be added | |
| 557 // later. | |
| 558 bool inline_followup = it->state() == LookupIterator::PROPERTY; | |
| 559 if (inline_followup) { | |
| 560 switch (it->property_kind()) { | |
| 561 case LookupIterator::DATA: | |
| 562 inline_followup = it->property_details().type() == FIELD; | |
| 563 break; | |
| 564 case LookupIterator::ACCESSOR: { | |
| 565 Handle<Object> accessors = it->GetAccessors(); | |
| 566 inline_followup = accessors->IsExecutableAccessorInfo(); | |
| 567 if (!inline_followup) break; | |
| 568 Handle<ExecutableAccessorInfo> info = | |
| 569 Handle<ExecutableAccessorInfo>::cast(accessors); | |
| 570 inline_followup = info->getter() != NULL && | |
| 571 ExecutableAccessorInfo::IsCompatibleReceiverType( | |
| 572 isolate(), info, type()); | |
| 573 } | |
| 574 } | |
| 575 } | |
| 576 | |
| 577 Register reg = Frontend(receiver(), it->name()); | |
| 578 if (inline_followup) { | |
| 579 // TODO(368): Compile in the whole chain: all the interceptors in | |
| 580 // prototypes and ultimate answer. | |
| 581 GenerateLoadInterceptorWithFollowup(it, reg); | |
| 582 } else { | |
| 583 GenerateLoadInterceptor(reg); | |
| 584 } | |
| 585 return GetCode(kind(), Code::FAST, it->name()); | |
| 586 } | |
| 587 | |
| 588 | |
| 589 void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor( | |
| 590 LookupIterator* it, Register interceptor_reg) { | |
| 591 Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>()); | |
| 592 | |
| 593 set_type_for_object(holder()); | |
| 594 set_holder(real_named_property_holder); | |
| 595 Register reg = Frontend(interceptor_reg, it->name()); | |
| 596 | |
| 597 switch (it->property_kind()) { | |
| 598 case LookupIterator::DATA: { | |
| 599 DCHECK_EQ(FIELD, it->property_details().type()); | |
| 600 __ Move(receiver(), reg); | |
| 601 LoadFieldStub stub(isolate(), it->GetFieldIndex()); | |
| 602 GenerateTailCall(masm(), stub.GetCode()); | |
| 603 break; | |
| 604 } | |
| 605 case LookupIterator::ACCESSOR: | |
| 606 Handle<ExecutableAccessorInfo> info = | |
| 607 Handle<ExecutableAccessorInfo>::cast(it->GetAccessors()); | |
| 608 DCHECK_NE(NULL, info->getter()); | |
| 609 GenerateLoadCallback(reg, info); | |
| 610 } | |
| 611 } | |
| 612 | |
| 613 | |
| 614 Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type, | |
| 615 Handle<Code> handler, | |
| 616 Handle<Name> name, | |
| 617 IcCheckType check) { | |
| 618 TypeHandleList types(1); | |
| 619 CodeHandleList handlers(1); | |
| 620 types.Add(type); | |
| 621 handlers.Add(handler); | |
| 622 Code::StubType stub_type = handler->type(); | |
| 623 return CompilePolymorphic(&types, &handlers, name, stub_type, check); | |
| 624 } | |
| 625 | |
| 626 | |
| 627 Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter( | |
| 628 Handle<Name> name, Handle<JSFunction> getter) { | |
| 629 Frontend(receiver(), name); | |
| 630 GenerateLoadViaGetter(masm(), type(), receiver(), getter); | |
| 631 return GetCode(kind(), Code::FAST, name); | |
| 632 } | |
| 633 | |
| 634 | |
| 635 // TODO(verwaest): Cleanup. holder() is actually the receiver. | |
| 636 Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition( | |
| 637 Handle<Map> transition, Handle<Name> name) { | |
| 638 Label miss, slow; | |
| 639 | |
| 640 // Ensure no transitions to deprecated maps are followed. | |
| 641 __ CheckMapDeprecated(transition, scratch1(), &miss); | |
| 642 | |
| 643 // Check that we are allowed to write this. | |
| 644 bool is_nonexistent = holder()->map() == transition->GetBackPointer(); | |
| 645 if (is_nonexistent) { | |
| 646 // Find the top object. | |
| 647 Handle<JSObject> last; | |
| 648 PrototypeIterator iter(isolate(), holder()); | |
| 649 while (!iter.IsAtEnd()) { | |
| 650 last = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
| 651 iter.Advance(); | |
| 652 } | |
| 653 if (!last.is_null()) set_holder(last); | |
| 654 NonexistentFrontendHeader(name, &miss, scratch1(), scratch2()); | |
| 655 } else { | |
| 656 FrontendHeader(receiver(), name, &miss); | |
| 657 DCHECK(holder()->HasFastProperties()); | |
| 658 } | |
| 659 | |
| 660 GenerateStoreTransition(transition, name, receiver(), this->name(), value(), | |
| 661 scratch1(), scratch2(), scratch3(), &miss, &slow); | |
| 662 | |
| 663 GenerateRestoreName(&miss, name); | |
| 664 TailCallBuiltin(masm(), MissBuiltin(kind())); | |
| 665 | |
| 666 GenerateRestoreName(&slow, name); | |
| 667 TailCallBuiltin(masm(), SlowBuiltin(kind())); | |
| 668 return GetCode(kind(), Code::FAST, name); | |
| 669 } | |
| 670 | |
| 671 | |
| 672 Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) { | |
| 673 Label miss; | |
| 674 GenerateStoreField(it, value(), &miss); | |
| 675 __ bind(&miss); | |
| 676 TailCallBuiltin(masm(), MissBuiltin(kind())); | |
| 677 return GetCode(kind(), Code::FAST, it->name()); | |
| 678 } | |
| 679 | |
| 680 | |
| 681 Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter( | |
| 682 Handle<JSObject> object, Handle<Name> name, Handle<JSFunction> setter) { | |
| 683 Frontend(receiver(), name); | |
| 684 GenerateStoreViaSetter(masm(), type(), receiver(), setter); | |
| 685 | |
| 686 return GetCode(kind(), Code::FAST, name); | |
| 687 } | |
| 688 | |
| 689 | |
| 690 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( | |
| 691 Handle<JSObject> object, Handle<Name> name, | |
| 692 const CallOptimization& call_optimization) { | |
| 693 Frontend(receiver(), name); | |
| 694 Register values[] = {value()}; | |
| 695 GenerateFastApiCall(masm(), call_optimization, handle(object->map()), | |
| 696 receiver(), scratch1(), true, 1, values); | |
| 697 return GetCode(kind(), Code::FAST, name); | |
| 698 } | |
| 699 | |
| 700 | |
| 701 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic( | |
| 702 Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) { | |
| 703 ElementsKind elements_kind = receiver_map->elements_kind(); | |
| 704 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; | |
| 705 Handle<Code> stub; | |
| 706 if (receiver_map->has_fast_elements() || | |
| 707 receiver_map->has_external_array_elements() || | |
| 708 receiver_map->has_fixed_typed_array_elements()) { | |
| 709 stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind, | |
| 710 store_mode).GetCode(); | |
| 711 } else { | |
| 712 stub = StoreElementStub(isolate(), is_jsarray, elements_kind, store_mode) | |
| 713 .GetCode(); | |
| 714 } | |
| 715 | |
| 716 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); | |
| 717 | |
| 718 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss); | |
| 719 | |
| 720 return GetCode(kind(), Code::NORMAL, factory()->empty_string()); | |
| 721 } | |
| 722 | |
| 723 | |
| 724 #undef __ | |
| 725 | |
| 726 | |
| 727 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type, | 368 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type, |
| 728 Handle<Name> name, | 369 Handle<Name> name, |
| 729 InlineCacheState state) { | 370 InlineCacheState state) { |
| 730 Code::Flags flags = | 371 Code::Flags flags = |
| 731 Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder()); | 372 Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder()); |
| 732 Handle<Code> code = GetCodeWithFlags(flags, name); | 373 Handle<Code> code = GetCodeWithFlags(flags, name); |
| 733 IC::RegisterWeakMapDependency(code); | 374 IC::RegisterWeakMapDependency(code); |
| 734 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); | 375 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); |
| 735 return code; | 376 return code; |
| 736 } | 377 } |
| 737 | 378 |
| 738 | 379 |
| 739 Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind, | |
| 740 Code::StubType type, | |
| 741 Handle<Name> name) { | |
| 742 Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder()); | |
| 743 Handle<Code> code = GetCodeWithFlags(flags, name); | |
| 744 PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, *name)); | |
| 745 return code; | |
| 746 } | |
| 747 | |
| 748 | |
| 749 void ElementHandlerCompiler::CompileElementHandlers( | |
| 750 MapHandleList* receiver_maps, CodeHandleList* handlers) { | |
| 751 for (int i = 0; i < receiver_maps->length(); ++i) { | |
| 752 Handle<Map> receiver_map = receiver_maps->at(i); | |
| 753 Handle<Code> cached_stub; | |
| 754 | |
| 755 if ((receiver_map->instance_type() & kNotStringTag) == 0) { | |
| 756 cached_stub = isolate()->builtins()->KeyedLoadIC_String(); | |
| 757 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) { | |
| 758 cached_stub = isolate()->builtins()->KeyedLoadIC_Slow(); | |
| 759 } else { | |
| 760 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; | |
| 761 ElementsKind elements_kind = receiver_map->elements_kind(); | |
| 762 | |
| 763 if (IsFastElementsKind(elements_kind) || | |
| 764 IsExternalArrayElementsKind(elements_kind) || | |
| 765 IsFixedTypedArrayElementsKind(elements_kind)) { | |
| 766 cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind) | |
| 767 .GetCode(); | |
| 768 } else if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) { | |
| 769 cached_stub = isolate()->builtins()->KeyedLoadIC_SloppyArguments(); | |
| 770 } else { | |
| 771 DCHECK(elements_kind == DICTIONARY_ELEMENTS); | |
| 772 cached_stub = LoadDictionaryElementStub(isolate()).GetCode(); | |
| 773 } | |
| 774 } | |
| 775 | |
| 776 handlers->Add(cached_stub); | |
| 777 } | |
| 778 } | |
| 779 | |
| 780 | |
| 781 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( | 380 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( |
| 782 MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode) { | 381 MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode) { |
| 783 // Collect MONOMORPHIC stubs for all |receiver_maps|. | 382 // Collect MONOMORPHIC stubs for all |receiver_maps|. |
| 784 CodeHandleList handlers(receiver_maps->length()); | 383 CodeHandleList handlers(receiver_maps->length()); |
| 785 MapHandleList transitioned_maps(receiver_maps->length()); | 384 MapHandleList transitioned_maps(receiver_maps->length()); |
| 786 for (int i = 0; i < receiver_maps->length(); ++i) { | 385 for (int i = 0; i < receiver_maps->length(); ++i) { |
| 787 Handle<Map> receiver_map(receiver_maps->at(i)); | 386 Handle<Map> receiver_map(receiver_maps->at(i)); |
| 788 Handle<Code> cached_stub; | 387 Handle<Code> cached_stub; |
| 789 Handle<Map> transitioned_map = | 388 Handle<Map> transitioned_map = |
| 790 receiver_map->FindTransitionedMap(receiver_maps); | 389 receiver_map->FindTransitionedMap(receiver_maps); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 820 } | 419 } |
| 821 | 420 |
| 822 Handle<Code> code = CompileKeyedStorePolymorphic(receiver_maps, &handlers, | 421 Handle<Code> code = CompileKeyedStorePolymorphic(receiver_maps, &handlers, |
| 823 &transitioned_maps); | 422 &transitioned_maps); |
| 824 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); | 423 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); |
| 825 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, 0)); | 424 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, 0)); |
| 826 return code; | 425 return code; |
| 827 } | 426 } |
| 828 | 427 |
| 829 | 428 |
| 830 void ElementHandlerCompiler::GenerateStoreDictionaryElement( | 429 #define __ ACCESS_MASM(masm()) |
| 831 MacroAssembler* masm) { | 430 |
| 832 KeyedStoreIC::GenerateSlow(masm); | 431 |
| 432 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic( |
| 433 Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) { |
| 434 ElementsKind elements_kind = receiver_map->elements_kind(); |
| 435 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; |
| 436 Handle<Code> stub; |
| 437 if (receiver_map->has_fast_elements() || |
| 438 receiver_map->has_external_array_elements() || |
| 439 receiver_map->has_fixed_typed_array_elements()) { |
| 440 stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind, |
| 441 store_mode).GetCode(); |
| 442 } else { |
| 443 stub = StoreElementStub(isolate(), is_jsarray, elements_kind, store_mode) |
| 444 .GetCode(); |
| 445 } |
| 446 |
| 447 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); |
| 448 |
| 449 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss); |
| 450 |
| 451 return GetCode(kind(), Code::NORMAL, factory()->empty_string()); |
| 833 } | 452 } |
| 834 | 453 |
| 835 | 454 |
| 455 #undef __ |
| 836 } | 456 } |
| 837 } // namespace v8::internal | 457 } // namespace v8::internal |
| OLD | NEW |