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

Generated by: LCOV version 1.10