LCOV - code coverage report
Current view: top level - src/ic/x64 - handler-compiler-x64.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 152 157 96.8 %
Date: 2017-10-20 Functions: 14 16 87.5 %

          Line data    Source code
       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
       3             : // found in the LICENSE file.
       4             : 
       5             : #if V8_TARGET_ARCH_X64
       6             : 
       7             : #include "src/ic/handler-compiler.h"
       8             : 
       9             : #include "src/api-arguments.h"
      10             : #include "src/field-type.h"
      11             : #include "src/ic/call-optimization.h"
      12             : #include "src/ic/ic.h"
      13             : #include "src/isolate-inl.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18             : #define __ ACCESS_MASM(masm)
      19             : 
      20      245699 : void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
      21             :                                                 Register slot) {
      22             :   MacroAssembler* masm = this->masm();
      23             :   STATIC_ASSERT(LoadWithVectorDescriptor::kSlot <
      24             :                 LoadWithVectorDescriptor::kVector);
      25             :   STATIC_ASSERT(StoreWithVectorDescriptor::kSlot <
      26             :                 StoreWithVectorDescriptor::kVector);
      27             :   STATIC_ASSERT(StoreTransitionDescriptor::kSlot <
      28             :                 StoreTransitionDescriptor::kVector);
      29      245699 :   __ Push(slot);
      30      245699 :   __ Push(vector);
      31      245699 : }
      32             : 
      33             : 
      34           0 : void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
      35      245683 :   MacroAssembler* masm = this->masm();
      36      245683 :   __ Pop(vector);
      37      245683 :   __ Pop(slot);
      38           0 : }
      39             : 
      40             : 
      41      245699 : void PropertyHandlerCompiler::DiscardVectorAndSlot() {
      42             :   MacroAssembler* masm = this->masm();
      43             :   // Remove vector and slot.
      44      245699 :   __ addp(rsp, Immediate(2 * kPointerSize));
      45      245699 : }
      46             : 
      47         829 : void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
      48             :     MacroAssembler* masm, Label* miss_label, Register receiver,
      49             :     Handle<Name> name, Register scratch0, Register scratch1) {
      50             :   DCHECK(name->IsUniqueName());
      51             :   DCHECK(receiver != scratch0);
      52         829 :   Counters* counters = masm->isolate()->counters();
      53         829 :   __ IncrementCounter(counters->negative_lookups(), 1);
      54         829 :   __ IncrementCounter(counters->negative_lookups_miss(), 1);
      55             : 
      56         829 :   __ movp(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
      57             : 
      58             :   const int kInterceptorOrAccessCheckNeededMask =
      59             :       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
      60             : 
      61             :   // Bail out if the receiver has a named interceptor or requires access checks.
      62             :   __ testb(FieldOperand(scratch0, Map::kBitFieldOffset),
      63         829 :            Immediate(kInterceptorOrAccessCheckNeededMask));
      64         829 :   __ j(not_zero, miss_label);
      65             : 
      66             :   // Check that receiver is a JSObject.
      67         829 :   __ CmpInstanceType(scratch0, FIRST_JS_RECEIVER_TYPE);
      68         829 :   __ j(below, miss_label);
      69             : 
      70             :   // Load properties array.
      71         829 :   Register properties = scratch0;
      72             :   __ movp(properties,
      73             :           FieldOperand(receiver, JSObject::kPropertiesOrHashOffset));
      74             : 
      75             :   // Check that the properties array is a dictionary.
      76             :   __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset),
      77         829 :                  Heap::kHashTableMapRootIndex);
      78         829 :   __ j(not_equal, miss_label);
      79             : 
      80             :   Label done;
      81             :   NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done,
      82         829 :                                                    properties, name, scratch1);
      83         829 :   __ bind(&done);
      84         829 :   __ DecrementCounter(counters->negative_lookups_miss(), 1);
      85         829 : }
      86             : 
      87             : // Generate call to api function.
      88        3786 : void PropertyHandlerCompiler::GenerateApiAccessorCall(
      89             :     MacroAssembler* masm, const CallOptimization& optimization,
      90             :     Handle<Map> receiver_map, Register receiver, Register scratch,
      91             :     bool is_store, Register store_parameter, Register accessor_holder,
      92             :     int accessor_index) {
      93             :   DCHECK(accessor_holder != scratch);
      94             :   DCHECK(optimization.is_simple_api_call());
      95             : 
      96        3786 :   __ PopReturnAddressTo(scratch);
      97             :   // accessor_holder
      98        3786 :   __ Push(accessor_holder);
      99             :   // receiver
     100        3786 :   __ Push(receiver);
     101             :   // Write the arguments to stack frame.
     102        3786 :   if (is_store) {
     103             :     DCHECK(receiver != store_parameter);
     104             :     DCHECK(scratch != store_parameter);
     105         274 :     __ Push(store_parameter);
     106             :   }
     107             :   __ PushReturnAddressFrom(scratch);
     108             :   // Stack now matches JSFunction abi.
     109             : 
     110             :   // Abi for CallApiCallbackStub.
     111             :   Register callee = rdi;
     112             :   Register data = rbx;
     113             :   Register holder = rcx;
     114             :   Register api_function_address = rdx;
     115             :   scratch = no_reg;
     116             : 
     117             :   // Put callee in place.
     118             :   __ LoadAccessor(callee, accessor_holder, accessor_index,
     119        3786 :                   is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
     120             : 
     121             :   // Put holder in place.
     122             :   CallOptimization::HolderLookup holder_lookup;
     123        3786 :   optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
     124        3786 :   switch (holder_lookup) {
     125             :     case CallOptimization::kHolderIsReceiver:
     126        3776 :       __ Move(holder, receiver);
     127        3776 :       break;
     128             :     case CallOptimization::kHolderFound:
     129          10 :       __ movp(holder, FieldOperand(receiver, HeapObject::kMapOffset));
     130             :       __ movp(holder, FieldOperand(holder, Map::kPrototypeOffset));
     131             :       break;
     132             :     case CallOptimization::kHolderNotFound:
     133           0 :       UNREACHABLE();
     134             :       break;
     135             :   }
     136             : 
     137             :   Isolate* isolate = masm->isolate();
     138             :   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
     139             :   // Put call data in place.
     140        3786 :   if (api_call_info->data()->IsUndefined(isolate)) {
     141        3737 :     __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
     142             :   } else {
     143          49 :     if (optimization.is_constant_call()) {
     144             :       __ movp(data,
     145          40 :               FieldOperand(callee, JSFunction::kSharedFunctionInfoOffset));
     146             :       __ movp(data,
     147             :               FieldOperand(data, SharedFunctionInfo::kFunctionDataOffset));
     148             :       __ movp(data, FieldOperand(data, FunctionTemplateInfo::kCallCodeOffset));
     149             :     } else {
     150             :       __ movp(data,
     151           9 :               FieldOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
     152             :     }
     153          49 :     __ movp(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
     154             :   }
     155             : 
     156             :   // Put api_function_address in place.
     157             :   Address function_address = v8::ToCData<Address>(api_call_info->callback());
     158             :   __ Move(api_function_address, function_address,
     159             :           RelocInfo::EXTERNAL_REFERENCE);
     160             : 
     161             :   // Jump to stub.
     162        3786 :   CallApiCallbackStub stub(isolate, is_store, !optimization.is_constant_call());
     163        3786 :   __ TailCallStub(&stub);
     164        3786 : }
     165             : 
     166             : 
     167          91 : void PropertyHandlerCompiler::GenerateCheckPropertyCell(
     168             :     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
     169             :     Register scratch, Label* miss) {
     170             :   Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
     171          91 :       global, name, PropertyCellType::kInvalidated);
     172          91 :   Isolate* isolate = masm->isolate();
     173             :   DCHECK(cell->value()->IsTheHole(isolate));
     174          91 :   Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
     175          91 :   __ LoadWeakValue(scratch, weak_cell, miss);
     176             :   __ Cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
     177          91 :          isolate->factory()->the_hole_value());
     178          91 :   __ j(not_equal, miss);
     179          91 : }
     180             : 
     181             : 
     182      141348 : void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
     183             :     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
     184             :     int accessor_index, int expected_arguments, Register scratch) {
     185             :   // ----------- S t a t e -------------
     186             :   //  -- rsp[0] : return address
     187             :   // -----------------------------------
     188             :   {
     189      141348 :     FrameScope scope(masm, StackFrame::INTERNAL);
     190             : 
     191             :     // Save context register
     192      141348 :     __ pushq(rsi);
     193             :     // Save value register, so we can restore it later.
     194      282696 :     __ Push(value());
     195             : 
     196      141348 :     if (accessor_index >= 0) {
     197             :       DCHECK(holder != scratch);
     198             :       DCHECK(receiver != scratch);
     199             :       DCHECK(value() != scratch);
     200             :       // Call the JavaScript setter with receiver and value on the stack.
     201      141317 :       if (map->IsJSGlobalObjectMap()) {
     202             :         // Swap in the global receiver.
     203             :         __ movp(scratch,
     204             :                 FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
     205          18 :         receiver = scratch;
     206             :       }
     207      141317 :       __ Push(receiver);
     208      141317 :       __ Push(value());
     209      141317 :       __ LoadAccessor(rdi, holder, accessor_index, ACCESSOR_SETTER);
     210      141317 :       __ Set(rax, 1);
     211             :       __ Call(masm->isolate()->builtins()->CallFunction(
     212             :                   ConvertReceiverMode::kNotNullOrUndefined),
     213      141317 :               RelocInfo::CODE_TARGET);
     214             :     } else {
     215             :       // If we generate a global code snippet for deoptimization only, remember
     216             :       // the place to continue after deoptimization.
     217          62 :       masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
     218             :     }
     219             : 
     220             :     // We have to return the passed value, not the return value of the setter.
     221      141348 :     __ Pop(rax);
     222             : 
     223             :     // Restore context register.
     224      141348 :     __ popq(rsi);
     225             :   }
     226      141348 :   __ ret(0);
     227      141348 : }
     228             : 
     229          31 : void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(
     230             :     MacroAssembler* masm) {
     231             :   {
     232          31 :     FrameScope scope(masm, StackFrame::INTERNAL);
     233             :     // Remember the place to continue after deoptimization.
     234          62 :     masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
     235             :     // Restore context register.
     236          31 :     __ popq(rsi);
     237             :   }
     238          31 :   __ ret(0);
     239          31 : }
     240             : 
     241             : #undef __
     242             : #define __ ACCESS_MASM((masm()))
     243             : 
     244             : 
     245      242171 : void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
     246             :                                                     Handle<Name> name) {
     247      242171 :   if (!label->is_unused()) {
     248      484342 :     __ bind(label);
     249      242171 :     __ Move(this->name(), name);
     250             :   }
     251      242171 : }
     252             : 
     253          73 : void PropertyHandlerCompiler::GenerateAccessCheck(
     254             :     Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
     255             :     Label* miss, bool compare_native_contexts_only) {
     256             :   Label done;
     257             :   // Load current native context.
     258          73 :   __ movp(scratch1, NativeContextOperand());
     259             :   // Load expected native context.
     260          73 :   __ LoadWeakValue(scratch2, native_context_cell, miss);
     261          73 :   __ cmpp(scratch1, scratch2);
     262             : 
     263          73 :   if (!compare_native_contexts_only) {
     264          73 :     __ j(equal, &done);
     265             : 
     266             :     // Compare security tokens of current and expected native contexts.
     267          73 :     __ movp(scratch1, ContextOperand(scratch1, Context::SECURITY_TOKEN_INDEX));
     268          73 :     __ movp(scratch2, ContextOperand(scratch2, Context::SECURITY_TOKEN_INDEX));
     269          73 :     __ cmpp(scratch1, scratch2);
     270             :   }
     271          73 :   __ j(not_equal, miss);
     272             : 
     273          73 :   __ bind(&done);
     274          73 : }
     275             : 
     276      245699 : Register PropertyHandlerCompiler::CheckPrototypes(
     277             :     Register object_reg, Register holder_reg, Register scratch1,
     278             :     Register scratch2, Handle<Name> name, Label* miss) {
     279             :   Handle<Map> receiver_map = map();
     280             : 
     281             :   // Make sure there's no overlap between holder and object registers.
     282             :   DCHECK(scratch1 != object_reg && scratch1 != holder_reg);
     283             :   DCHECK(scratch2 != object_reg && scratch2 != holder_reg &&
     284             :          scratch2 != scratch1);
     285             : 
     286             :   Handle<Cell> validity_cell =
     287      881632 :       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
     288      245699 :   if (!validity_cell.is_null()) {
     289             :     DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value());
     290      245683 :     __ Move(scratch1, validity_cell);
     291             :     __ SmiCompare(FieldOperand(scratch1, Cell::kValueOffset),
     292      245683 :                   Smi::FromInt(Map::kPrototypeChainValid));
     293      245683 :     __ j(not_equal, miss);
     294             :   }
     295             : 
     296             :   // Keep track of the current object in register reg.  On the first
     297             :   // iteration, reg is an alias for object_reg, on later iterations,
     298             :   // it is an alias for holder_reg.
     299      245699 :   Register reg = object_reg;
     300             :   int depth = 0;
     301             : 
     302             :   Handle<JSObject> current = Handle<JSObject>::null();
     303      245699 :   if (receiver_map->IsJSGlobalObjectMap()) {
     304          18 :     current = isolate()->global_object();
     305             :   }
     306             : 
     307             :   Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
     308      245699 :                           isolate());
     309             :   Handle<Map> holder_map(holder()->map());
     310             :   // Traverse the prototype chain and check the maps in the prototype chain for
     311             :   // fast and global objects or do negative lookup for normal objects.
     312      778063 :   while (!current_map.is_identical_to(holder_map)) {
     313      286665 :     ++depth;
     314             : 
     315      286665 :     if (current_map->IsJSGlobalObjectMap()) {
     316             :       GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
     317          91 :                                 name, scratch2, miss);
     318      286574 :     } else if (current_map->is_dictionary_map()) {
     319             :       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
     320             :       DCHECK(name->IsUniqueName());
     321             :       DCHECK(current.is_null() ||
     322             :              current->property_dictionary()->FindEntry(name) ==
     323             :                  NameDictionary::kNotFound);
     324             : 
     325         829 :       if (depth > 1) {
     326             :         Handle<WeakCell> weak_cell =
     327          27 :             Map::GetOrCreatePrototypeWeakCell(current, isolate());
     328          27 :         __ LoadWeakValue(reg, weak_cell, miss);
     329             :       }
     330             :       GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
     331         829 :                                        scratch2);
     332             :     }
     333             : 
     334      286665 :     reg = holder_reg;  // From now on the object will be in holder_reg.
     335             :     // Go to the next object in the prototype chain.
     336             :     current = handle(JSObject::cast(current_map->prototype()));
     337             :     current_map = handle(current->map());
     338             :   }
     339             : 
     340             :   DCHECK(!current_map->IsJSGlobalProxyMap());
     341             : 
     342             :   // Log the check depth.
     343      245699 :   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
     344             : 
     345      245699 :   if (depth != 0) {
     346             :     Handle<WeakCell> weak_cell =
     347      144490 :         Map::GetOrCreatePrototypeWeakCell(current, isolate());
     348      144490 :     __ LoadWeakValue(reg, weak_cell, miss);
     349             :   }
     350             : 
     351             :   // Return the register containing the holder.
     352      245699 :   return reg;
     353             : }
     354             : 
     355             : 
     356        3512 : void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
     357        3512 :   if (!miss->is_unused()) {
     358             :     Label success;
     359        3512 :     __ jmp(&success);
     360        3512 :     __ bind(miss);
     361        3512 :     PopVectorAndSlot();
     362        3512 :     TailCallBuiltin(masm(), Builtins::kLoadIC_Miss);
     363        3512 :     __ bind(&success);
     364             :   }
     365        3512 : }
     366             : 
     367             : 
     368      242187 : void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
     369      242187 :   if (!miss->is_unused()) {
     370             :     Label success;
     371      242171 :     __ jmp(&success);
     372      242171 :     GenerateRestoreName(miss, name);
     373      242171 :     PopVectorAndSlot();
     374      242171 :     TailCallBuiltin(masm(), Builtins::kStoreIC_Miss);
     375      242171 :     __ bind(&success);
     376             :   }
     377      242187 : }
     378             : 
     379           0 : void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
     380             :   STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
     381           0 : }
     382             : 
     383      100596 : Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
     384             :     Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
     385             :     LanguageMode language_mode) {
     386      100596 :   Register holder_reg = Frontend(name);
     387             : 
     388      402401 :   __ PopReturnAddressTo(scratch1());
     389      100596 :   __ Push(receiver());
     390      100596 :   __ Push(holder_reg);
     391             :   // If the callback cannot leak, then push the callback directly,
     392             :   // otherwise wrap it in a weak cell.
     393      100613 :   if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
     394      100579 :     __ Push(callback);
     395             :   } else {
     396          17 :     Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
     397          17 :     __ Push(cell);
     398             :   }
     399      100596 :   __ Push(name);
     400      100596 :   __ Push(value());
     401      100596 :   __ Push(Smi::FromEnum(language_mode));
     402             :   __ PushReturnAddressFrom(scratch1());
     403             : 
     404             :   // Do tail-call to the runtime system.
     405      100596 :   __ TailCallRuntime(Runtime::kStoreCallbackProperty);
     406             : 
     407             :   // Return the generated code.
     408      100596 :   return GetCode(name);
     409             : }
     410             : 
     411             : 
     412         274 : Register NamedStoreHandlerCompiler::value() {
     413      383535 :   return StoreDescriptor::ValueRegister();
     414             : }
     415             : 
     416             : 
     417             : #undef __
     418             : }  // namespace internal
     419             : }  // namespace v8
     420             : 
     421             : #endif  // V8_TARGET_ARCH_X64

Generated by: LCOV version 1.10