LCOV - code coverage report
Current view: top level - src/builtins - builtins-internal-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 376 378 99.5 %
Date: 2019-01-20 Functions: 67 69 97.1 %

          Line data    Source code
       1             : // Copyright 2017 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             : #include "src/api.h"
       6             : #include "src/builtins/builtins-utils-gen.h"
       7             : #include "src/builtins/builtins.h"
       8             : #include "src/code-stub-assembler.h"
       9             : #include "src/heap/heap-inl.h"  // crbug.com/v8/8499
      10             : #include "src/ic/accessor-assembler.h"
      11             : #include "src/ic/keyed-store-generic.h"
      12             : #include "src/macro-assembler.h"
      13             : #include "src/objects/debug-objects.h"
      14             : #include "src/objects/shared-function-info.h"
      15             : #include "src/runtime/runtime.h"
      16             : 
      17             : namespace v8 {
      18             : namespace internal {
      19             : 
      20             : template <typename T>
      21             : using TNode = compiler::TNode<T>;
      22             : 
      23             : // -----------------------------------------------------------------------------
      24             : // Interrupt and stack checks.
      25             : 
      26          56 : void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
      27          56 :   masm->TailCallRuntime(Runtime::kInterrupt);
      28          56 : }
      29             : 
      30          56 : void Builtins::Generate_StackCheck(MacroAssembler* masm) {
      31          56 :   masm->TailCallRuntime(Runtime::kStackGuard);
      32          56 : }
      33             : 
      34             : // -----------------------------------------------------------------------------
      35             : // TurboFan support builtins.
      36             : 
      37         168 : TF_BUILTIN(CopyFastSmiOrObjectElements, CodeStubAssembler) {
      38             :   Node* object = Parameter(Descriptor::kObject);
      39             : 
      40             :   // Load the {object}s elements.
      41          56 :   Node* source = LoadObjectField(object, JSObject::kElementsOffset);
      42          56 :   Node* target = CloneFixedArray(source, ExtractFixedArrayFlag::kFixedArrays);
      43          56 :   StoreObjectField(object, JSObject::kElementsOffset, target);
      44          56 :   Return(target);
      45          56 : }
      46             : 
      47         168 : TF_BUILTIN(GrowFastDoubleElements, CodeStubAssembler) {
      48             :   Node* object = Parameter(Descriptor::kObject);
      49             :   Node* key = Parameter(Descriptor::kKey);
      50             :   Node* context = Parameter(Descriptor::kContext);
      51             : 
      52             :   Label runtime(this, Label::kDeferred);
      53             :   Node* elements = LoadElements(object);
      54             :   elements = TryGrowElementsCapacity(object, elements, PACKED_DOUBLE_ELEMENTS,
      55          56 :                                      key, &runtime);
      56          56 :   Return(elements);
      57             : 
      58          56 :   BIND(&runtime);
      59          56 :   TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
      60          56 : }
      61             : 
      62         168 : TF_BUILTIN(GrowFastSmiOrObjectElements, CodeStubAssembler) {
      63             :   Node* object = Parameter(Descriptor::kObject);
      64             :   Node* key = Parameter(Descriptor::kKey);
      65             :   Node* context = Parameter(Descriptor::kContext);
      66             : 
      67             :   Label runtime(this, Label::kDeferred);
      68             :   Node* elements = LoadElements(object);
      69             :   elements =
      70          56 :       TryGrowElementsCapacity(object, elements, PACKED_ELEMENTS, key, &runtime);
      71          56 :   Return(elements);
      72             : 
      73          56 :   BIND(&runtime);
      74          56 :   TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
      75          56 : }
      76             : 
      77         224 : TF_BUILTIN(NewArgumentsElements, CodeStubAssembler) {
      78             :   Node* frame = Parameter(Descriptor::kFrame);
      79          56 :   TNode<IntPtrT> length = SmiToIntPtr(Parameter(Descriptor::kLength));
      80             :   TNode<IntPtrT> mapped_count =
      81             :       SmiToIntPtr(Parameter(Descriptor::kMappedCount));
      82             : 
      83             :   // Check if we can allocate in new space.
      84             :   ElementsKind kind = PACKED_ELEMENTS;
      85          56 :   int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind);
      86          56 :   Label if_newspace(this), if_oldspace(this, Label::kDeferred);
      87         112 :   Branch(IntPtrLessThan(length, IntPtrConstant(max_elements)), &if_newspace,
      88         112 :          &if_oldspace);
      89             : 
      90          56 :   BIND(&if_newspace);
      91             :   {
      92             :     // Prefer EmptyFixedArray in case of non-positive {length} (the {length}
      93             :     // can be negative here for rest parameters).
      94          56 :     Label if_empty(this), if_notempty(this);
      95         112 :     Branch(IntPtrLessThanOrEqual(length, IntPtrConstant(0)), &if_empty,
      96         112 :            &if_notempty);
      97             : 
      98          56 :     BIND(&if_empty);
      99         112 :     Return(EmptyFixedArrayConstant());
     100             : 
     101          56 :     BIND(&if_notempty);
     102             :     {
     103             :       // Allocate a FixedArray in new space.
     104          56 :       TNode<FixedArray> result = CAST(AllocateFixedArray(kind, length));
     105             : 
     106             :       // The elements might be used to back mapped arguments. In that case fill
     107             :       // the mapped elements (i.e. the first {mapped_count}) with the hole, but
     108             :       // make sure not to overshoot the {length} if some arguments are missing.
     109          56 :       TNode<IntPtrT> number_of_holes = IntPtrMin(mapped_count, length);
     110         112 :       Node* the_hole = TheHoleConstant();
     111             : 
     112             :       // Fill the first elements up to {number_of_holes} with the hole.
     113          56 :       TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
     114          56 :       Label loop1(this, &var_index), done_loop1(this);
     115          56 :       Goto(&loop1);
     116          56 :       BIND(&loop1);
     117             :       {
     118             :         // Load the current {index}.
     119             :         TNode<IntPtrT> index = var_index.value();
     120             : 
     121             :         // Check if we are done.
     122         112 :         GotoIf(WordEqual(index, number_of_holes), &done_loop1);
     123             : 
     124             :         // Store the hole into the {result}.
     125          56 :         StoreFixedArrayElement(result, index, the_hole, SKIP_WRITE_BARRIER);
     126             : 
     127             :         // Continue with next {index}.
     128          56 :         var_index = IntPtrAdd(index, IntPtrConstant(1));
     129          56 :         Goto(&loop1);
     130             :       }
     131          56 :       BIND(&done_loop1);
     132             : 
     133             :       // Compute the effective {offset} into the {frame}.
     134          56 :       TNode<IntPtrT> offset = IntPtrAdd(length, IntPtrConstant(1));
     135             : 
     136             :       // Copy the parameters from {frame} (starting at {offset}) to {result}.
     137          56 :       Label loop2(this, &var_index), done_loop2(this);
     138          56 :       Goto(&loop2);
     139          56 :       BIND(&loop2);
     140             :       {
     141             :         // Load the current {index}.
     142             :         TNode<IntPtrT> index = var_index.value();
     143             : 
     144             :         // Check if we are done.
     145         112 :         GotoIf(WordEqual(index, length), &done_loop2);
     146             : 
     147             :         // Load the parameter at the given {index}.
     148             :         TNode<Object> value = BitcastWordToTagged(
     149             :             Load(MachineType::Pointer(), frame,
     150         112 :                  TimesSystemPointerSize(IntPtrSub(offset, index))));
     151             : 
     152             :         // Store the {value} into the {result}.
     153          56 :         StoreFixedArrayElement(result, index, value, SKIP_WRITE_BARRIER);
     154             : 
     155             :         // Continue with next {index}.
     156          56 :         var_index = IntPtrAdd(index, IntPtrConstant(1));
     157          56 :         Goto(&loop2);
     158             :       }
     159          56 :       BIND(&done_loop2);
     160             : 
     161          56 :       Return(result);
     162          56 :     }
     163             :   }
     164             : 
     165          56 :   BIND(&if_oldspace);
     166             :   {
     167             :     // Allocate in old space (or large object space).
     168             :     TailCallRuntime(Runtime::kNewArgumentsElements, NoContextConstant(),
     169             :                     BitcastWordToTagged(frame), SmiFromIntPtr(length),
     170         112 :                     SmiFromIntPtr(mapped_count));
     171          56 :   }
     172          56 : }
     173             : 
     174         168 : TF_BUILTIN(ReturnReceiver, CodeStubAssembler) {
     175          56 :   Return(Parameter(Descriptor::kReceiver));
     176          56 : }
     177             : 
     178         336 : TF_BUILTIN(DebugBreakTrampoline, CodeStubAssembler) {
     179          56 :   Label tailcall_to_shared(this);
     180             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     181          56 :   TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
     182             :   TNode<Int32T> arg_count =
     183          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
     184             :   TNode<JSFunction> function = CAST(Parameter(Descriptor::kJSTarget));
     185             : 
     186             :   // Check break-at-entry flag on the debug info.
     187             :   TNode<SharedFunctionInfo> shared =
     188          56 :       CAST(LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset));
     189             :   TNode<Object> maybe_heap_object_or_smi =
     190          56 :       LoadObjectField(shared, SharedFunctionInfo::kScriptOrDebugInfoOffset);
     191             :   TNode<HeapObject> maybe_debug_info =
     192          56 :       TaggedToHeapObject(maybe_heap_object_or_smi, &tailcall_to_shared);
     193          56 :   GotoIfNot(HasInstanceType(maybe_debug_info, InstanceType::DEBUG_INFO_TYPE),
     194         112 :             &tailcall_to_shared);
     195             : 
     196             :   {
     197             :     TNode<DebugInfo> debug_info = CAST(maybe_debug_info);
     198             :     TNode<Smi> flags =
     199          56 :         CAST(LoadObjectField(debug_info, DebugInfo::kFlagsOffset));
     200         112 :     GotoIfNot(SmiToInt32(SmiAnd(flags, SmiConstant(DebugInfo::kBreakAtEntry))),
     201         112 :               &tailcall_to_shared);
     202             : 
     203             :     CallRuntime(Runtime::kDebugBreakAtEntry, context, function);
     204          56 :     Goto(&tailcall_to_shared);
     205             :   }
     206             : 
     207          56 :   BIND(&tailcall_to_shared);
     208             :   // Tail call into code object on the SharedFunctionInfo.
     209          56 :   TNode<Code> code = GetSharedFunctionInfoCode(shared);
     210          56 :   TailCallJSCode(code, context, function, new_target, arg_count);
     211          56 : }
     212             : 
     213             : class RecordWriteCodeStubAssembler : public CodeStubAssembler {
     214             :  public:
     215             :   explicit RecordWriteCodeStubAssembler(compiler::CodeAssemblerState* state)
     216          56 :       : CodeStubAssembler(state) {}
     217             : 
     218          56 :   Node* IsMarking() {
     219             :     Node* is_marking_addr = ExternalConstant(
     220         112 :         ExternalReference::heap_is_marking_flag_address(this->isolate()));
     221          56 :     return Load(MachineType::Uint8(), is_marking_addr);
     222             :   }
     223             : 
     224         224 :   Node* IsPageFlagSet(Node* object, int mask) {
     225         672 :     Node* page = WordAnd(object, IntPtrConstant(~kPageAlignmentMask));
     226             :     Node* flags = Load(MachineType::Pointer(), page,
     227         448 :                        IntPtrConstant(MemoryChunk::kFlagsOffset));
     228         448 :     return WordNotEqual(WordAnd(flags, IntPtrConstant(mask)),
     229        1120 :                         IntPtrConstant(0));
     230             :   }
     231             : 
     232          56 :   Node* IsWhite(Node* object) {
     233             :     DCHECK_EQ(strcmp(Marking::kWhiteBitPattern, "00"), 0);
     234             :     Node* cell;
     235             :     Node* mask;
     236          56 :     GetMarkBit(object, &cell, &mask);
     237         168 :     mask = TruncateIntPtrToInt32(mask);
     238             :     // Non-white has 1 for the first bit, so we only need to check for the first
     239             :     // bit.
     240         168 :     return Word32Equal(Word32And(Load(MachineType::Int32(), cell), mask),
     241         280 :                        Int32Constant(0));
     242             :   }
     243             : 
     244          56 :   void GetMarkBit(Node* object, Node** cell, Node** mask) {
     245         168 :     Node* page = WordAnd(object, IntPtrConstant(~kPageAlignmentMask));
     246             :     Node* bitmap = Load(MachineType::Pointer(), page,
     247         112 :                         IntPtrConstant(MemoryChunk::kMarkBitmapOffset));
     248             : 
     249             :     {
     250             :       // Temp variable to calculate cell offset in bitmap.
     251             :       Node* r0;
     252             :       int shift = Bitmap::kBitsPerCellLog2 + kTaggedSizeLog2 -
     253             :                   Bitmap::kBytesPerCellLog2;
     254         168 :       r0 = WordShr(object, IntPtrConstant(shift));
     255         112 :       r0 = WordAnd(r0, IntPtrConstant((kPageAlignmentMask >> shift) &
     256         112 :                                       ~(Bitmap::kBytesPerCell - 1)));
     257         112 :       *cell = IntPtrAdd(bitmap, r0);
     258             :     }
     259             :     {
     260             :       // Temp variable to calculate bit offset in cell.
     261             :       Node* r1;
     262         168 :       r1 = WordShr(object, IntPtrConstant(kTaggedSizeLog2));
     263         168 :       r1 = WordAnd(r1, IntPtrConstant((1 << Bitmap::kBitsPerCellLog2) - 1));
     264             :       // It seems that LSB(e.g. cl) is automatically used, so no manual masking
     265             :       // is needed. Uncomment the following line otherwise.
     266             :       // WordAnd(r1, IntPtrConstant((1 << kBitsPerByte) - 1)));
     267         168 :       *mask = WordShl(IntPtrConstant(1), r1);
     268             :     }
     269          56 :   }
     270             : 
     271         168 :   Node* ShouldSkipFPRegs(Node* mode) {
     272         336 :     return WordEqual(mode, SmiConstant(kDontSaveFPRegs));
     273             :   }
     274             : 
     275          56 :   Node* ShouldEmitRememberSet(Node* remembered_set) {
     276         112 :     return WordEqual(remembered_set, SmiConstant(EMIT_REMEMBERED_SET));
     277             :   }
     278             : 
     279         112 :   void CallCFunction1WithCallerSavedRegistersMode(MachineType return_type,
     280             :                                                   MachineType arg0_type,
     281             :                                                   Node* function, Node* arg0,
     282             :                                                   Node* mode, Label* next) {
     283         224 :     Label dont_save_fp(this), save_fp(this);
     284         224 :     Branch(ShouldSkipFPRegs(mode), &dont_save_fp, &save_fp);
     285         112 :     BIND(&dont_save_fp);
     286             :     {
     287             :       CallCFunction1WithCallerSavedRegisters(return_type, arg0_type, function,
     288         112 :                                              arg0, kDontSaveFPRegs);
     289         112 :       Goto(next);
     290             :     }
     291             : 
     292         112 :     BIND(&save_fp);
     293             :     {
     294             :       CallCFunction1WithCallerSavedRegisters(return_type, arg0_type, function,
     295         112 :                                              arg0, kSaveFPRegs);
     296         112 :       Goto(next);
     297         112 :     }
     298         112 :   }
     299             : 
     300          56 :   void CallCFunction3WithCallerSavedRegistersMode(
     301             :       MachineType return_type, MachineType arg0_type, MachineType arg1_type,
     302             :       MachineType arg2_type, Node* function, Node* arg0, Node* arg1, Node* arg2,
     303             :       Node* mode, Label* next) {
     304         112 :     Label dont_save_fp(this), save_fp(this);
     305         112 :     Branch(ShouldSkipFPRegs(mode), &dont_save_fp, &save_fp);
     306          56 :     BIND(&dont_save_fp);
     307             :     {
     308             :       CallCFunction3WithCallerSavedRegisters(return_type, arg0_type, arg1_type,
     309             :                                              arg2_type, function, arg0, arg1,
     310          56 :                                              arg2, kDontSaveFPRegs);
     311          56 :       Goto(next);
     312             :     }
     313             : 
     314          56 :     BIND(&save_fp);
     315             :     {
     316             :       CallCFunction3WithCallerSavedRegisters(return_type, arg0_type, arg1_type,
     317             :                                              arg2_type, function, arg0, arg1,
     318          56 :                                              arg2, kSaveFPRegs);
     319          56 :       Goto(next);
     320          56 :     }
     321          56 :   }
     322             : 
     323         112 :   void InsertToStoreBufferAndGoto(Node* isolate, Node* slot, Node* mode,
     324             :                                   Label* next) {
     325             :     Node* store_buffer_top_addr =
     326         224 :         ExternalConstant(ExternalReference::store_buffer_top(this->isolate()));
     327             :     Node* store_buffer_top =
     328         112 :         Load(MachineType::Pointer(), store_buffer_top_addr);
     329             :     StoreNoWriteBarrier(MachineType::PointerRepresentation(), store_buffer_top,
     330         112 :                         slot);
     331             :     Node* new_store_buffer_top =
     332         336 :         IntPtrAdd(store_buffer_top, IntPtrConstant(kSystemPointerSize));
     333             :     StoreNoWriteBarrier(MachineType::PointerRepresentation(),
     334         112 :                         store_buffer_top_addr, new_store_buffer_top);
     335             : 
     336             :     Node* test = WordAnd(new_store_buffer_top,
     337         336 :                          IntPtrConstant(Heap::store_buffer_mask_constant()));
     338             : 
     339             :     Label overflow(this);
     340         336 :     Branch(WordEqual(test, IntPtrConstant(0)), &overflow, next);
     341             : 
     342         112 :     BIND(&overflow);
     343             :     {
     344             :       Node* function =
     345         224 :           ExternalConstant(ExternalReference::store_buffer_overflow_function());
     346             :       CallCFunction1WithCallerSavedRegistersMode(MachineType::Int32(),
     347             :                                                  MachineType::Pointer(),
     348         112 :                                                  function, isolate, mode, next);
     349         112 :     }
     350         112 :   }
     351             : };
     352             : 
     353         672 : TF_BUILTIN(RecordWrite, RecordWriteCodeStubAssembler) {
     354          56 :   Label generational_wb(this);
     355          56 :   Label incremental_wb(this);
     356          56 :   Label exit(this);
     357             : 
     358             :   Node* remembered_set = Parameter(Descriptor::kRememberedSet);
     359             :   Branch(ShouldEmitRememberSet(remembered_set), &generational_wb,
     360         112 :          &incremental_wb);
     361             : 
     362          56 :   BIND(&generational_wb);
     363             :   {
     364             :     Label test_old_to_new_flags(this);
     365          56 :     Label store_buffer_exit(this), store_buffer_incremental_wb(this);
     366             : 
     367             :     // When incremental marking is not on, we skip cross generation pointer
     368             :     // checking here, because there are checks for
     369             :     // `kPointersFromHereAreInterestingMask` and
     370             :     // `kPointersToHereAreInterestingMask` in
     371             :     // `src/compiler/<arch>/code-generator-<arch>.cc` before calling this stub,
     372             :     // which serves as the cross generation checking.
     373             :     Node* slot = Parameter(Descriptor::kSlot);
     374         112 :     Branch(IsMarking(), &test_old_to_new_flags, &store_buffer_exit);
     375             : 
     376          56 :     BIND(&test_old_to_new_flags);
     377             :     {
     378          56 :       Node* value = Load(MachineType::Pointer(), slot);
     379             : 
     380             :       // TODO(albertnetymk): Try to cache the page flag for value and object,
     381             :       // instead of calling IsPageFlagSet each time.
     382             :       Node* value_in_new_space =
     383          56 :           IsPageFlagSet(value, MemoryChunk::kIsInNewSpaceMask);
     384          56 :       GotoIfNot(value_in_new_space, &incremental_wb);
     385             : 
     386         112 :       Node* object = BitcastTaggedToWord(Parameter(Descriptor::kObject));
     387             :       Node* object_in_new_space =
     388          56 :           IsPageFlagSet(object, MemoryChunk::kIsInNewSpaceMask);
     389             :       Branch(object_in_new_space, &incremental_wb,
     390          56 :              &store_buffer_incremental_wb);
     391             :     }
     392             : 
     393          56 :     BIND(&store_buffer_exit);
     394             :     {
     395             :       Node* isolate_constant =
     396         112 :           ExternalConstant(ExternalReference::isolate_address(isolate()));
     397             :       Node* fp_mode = Parameter(Descriptor::kFPMode);
     398          56 :       InsertToStoreBufferAndGoto(isolate_constant, slot, fp_mode, &exit);
     399             :     }
     400             : 
     401          56 :     BIND(&store_buffer_incremental_wb);
     402             :     {
     403             :       Node* isolate_constant =
     404         112 :           ExternalConstant(ExternalReference::isolate_address(isolate()));
     405             :       Node* fp_mode = Parameter(Descriptor::kFPMode);
     406             :       InsertToStoreBufferAndGoto(isolate_constant, slot, fp_mode,
     407          56 :                                  &incremental_wb);
     408          56 :     }
     409             :   }
     410             : 
     411          56 :   BIND(&incremental_wb);
     412             :   {
     413             :     Label call_incremental_wb(this);
     414             : 
     415             :     Node* slot = Parameter(Descriptor::kSlot);
     416          56 :     Node* value = Load(MachineType::Pointer(), slot);
     417             : 
     418             :     // There are two cases we need to call incremental write barrier.
     419             :     // 1) value_is_white
     420         112 :     GotoIf(IsWhite(value), &call_incremental_wb);
     421             : 
     422             :     // 2) is_compacting && value_in_EC && obj_isnt_skip
     423             :     // is_compacting = true when is_marking = true
     424             :     GotoIfNot(IsPageFlagSet(value, MemoryChunk::kEvacuationCandidateMask),
     425         112 :               &exit);
     426             : 
     427         112 :     Node* object = BitcastTaggedToWord(Parameter(Descriptor::kObject));
     428             :     Branch(
     429             :         IsPageFlagSet(object, MemoryChunk::kSkipEvacuationSlotsRecordingMask),
     430         112 :         &exit, &call_incremental_wb);
     431             : 
     432          56 :     BIND(&call_incremental_wb);
     433             :     {
     434             :       Node* function = ExternalConstant(
     435         112 :           ExternalReference::incremental_marking_record_write_function());
     436             :       Node* isolate_constant =
     437         112 :           ExternalConstant(ExternalReference::isolate_address(isolate()));
     438             :       Node* fp_mode = Parameter(Descriptor::kFPMode);
     439         112 :       Node* object = BitcastTaggedToWord(Parameter(Descriptor::kObject));
     440             :       CallCFunction3WithCallerSavedRegistersMode(
     441             :           MachineType::Int32(), MachineType::Pointer(), MachineType::Pointer(),
     442             :           MachineType::Pointer(), function, object, slot, isolate_constant,
     443          56 :           fp_mode, &exit);
     444          56 :     }
     445             :   }
     446             : 
     447          56 :   BIND(&exit);
     448         168 :   Return(TrueConstant());
     449          56 : }
     450             : 
     451             : class DeletePropertyBaseAssembler : public AccessorAssembler {
     452             :  public:
     453             :   explicit DeletePropertyBaseAssembler(compiler::CodeAssemblerState* state)
     454             :       : AccessorAssembler(state) {}
     455             : 
     456          56 :   void DeleteDictionaryProperty(TNode<Object> receiver,
     457             :                                 TNode<NameDictionary> properties,
     458             :                                 TNode<Name> name, TNode<Context> context,
     459             :                                 Label* dont_delete, Label* notfound) {
     460          56 :     TVARIABLE(IntPtrT, var_name_index);
     461          56 :     Label dictionary_found(this, &var_name_index);
     462             :     NameDictionaryLookup<NameDictionary>(properties, name, &dictionary_found,
     463          56 :                                          &var_name_index, notfound);
     464             : 
     465          56 :     BIND(&dictionary_found);
     466             :     TNode<IntPtrT> key_index = var_name_index.value();
     467             :     TNode<Uint32T> details =
     468             :         LoadDetailsByKeyIndex<NameDictionary>(properties, key_index);
     469          56 :     GotoIf(IsSetWord32(details, PropertyDetails::kAttributesDontDeleteMask),
     470         112 :            dont_delete);
     471             :     // Overwrite the entry itself (see NameDictionary::SetEntry).
     472         112 :     TNode<HeapObject> filler = TheHoleConstant();
     473             :     DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kTheHoleValue));
     474          56 :     StoreFixedArrayElement(properties, key_index, filler, SKIP_WRITE_BARRIER);
     475             :     StoreValueByKeyIndex<NameDictionary>(properties, key_index, filler,
     476             :                                          SKIP_WRITE_BARRIER);
     477             :     StoreDetailsByKeyIndex<NameDictionary>(properties, key_index,
     478          56 :                                            SmiConstant(0));
     479             : 
     480             :     // Update bookkeeping information (see NameDictionary::ElementRemoved).
     481          56 :     TNode<Smi> nof = GetNumberOfElements<NameDictionary>(properties);
     482          56 :     TNode<Smi> new_nof = SmiSub(nof, SmiConstant(1));
     483             :     SetNumberOfElements<NameDictionary>(properties, new_nof);
     484             :     TNode<Smi> num_deleted =
     485          56 :         GetNumberOfDeletedElements<NameDictionary>(properties);
     486          56 :     TNode<Smi> new_deleted = SmiAdd(num_deleted, SmiConstant(1));
     487             :     SetNumberOfDeletedElements<NameDictionary>(properties, new_deleted);
     488             : 
     489             :     // Shrink the dictionary if necessary (see NameDictionary::Shrink).
     490          56 :     Label shrinking_done(this);
     491          56 :     TNode<Smi> capacity = GetCapacity<NameDictionary>(properties);
     492         112 :     GotoIf(SmiGreaterThan(new_nof, SmiShr(capacity, 2)), &shrinking_done);
     493         112 :     GotoIf(SmiLessThan(new_nof, SmiConstant(16)), &shrinking_done);
     494             :     CallRuntime(Runtime::kShrinkPropertyDictionary, context, receiver);
     495          56 :     Goto(&shrinking_done);
     496          56 :     BIND(&shrinking_done);
     497             : 
     498         112 :     Return(TrueConstant());
     499          56 :   }
     500             : };
     501             : 
     502         280 : TF_BUILTIN(DeleteProperty, DeletePropertyBaseAssembler) {
     503             :   TNode<Object> receiver = CAST(Parameter(Descriptor::kObject));
     504             :   TNode<Object> key = CAST(Parameter(Descriptor::kKey));
     505          56 :   TNode<Smi> language_mode = CAST(Parameter(Descriptor::kLanguageMode));
     506             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     507             : 
     508          56 :   VARIABLE(var_index, MachineType::PointerRepresentation());
     509         112 :   VARIABLE(var_unique, MachineRepresentation::kTagged, key);
     510          56 :   Label if_index(this), if_unique_name(this), if_notunique(this),
     511          56 :       if_notfound(this), slow(this);
     512             : 
     513         112 :   GotoIf(TaggedIsSmi(receiver), &slow);
     514          56 :   TNode<Map> receiver_map = LoadMap(CAST(receiver));
     515          56 :   TNode<Int32T> instance_type = LoadMapInstanceType(receiver_map);
     516         112 :   GotoIf(IsCustomElementsReceiverInstanceType(instance_type), &slow);
     517             :   TryToName(key, &if_index, &var_index, &if_unique_name, &var_unique, &slow,
     518          56 :             &if_notunique);
     519             : 
     520          56 :   BIND(&if_index);
     521             :   {
     522          56 :     Comment("integer index");
     523          56 :     Goto(&slow);  // TODO(jkummerow): Implement more smarts here.
     524             :   }
     525             : 
     526          56 :   BIND(&if_unique_name);
     527             :   {
     528          56 :     Comment("key is unique name");
     529          56 :     TNode<Name> unique = CAST(var_unique.value());
     530          56 :     CheckForAssociatedProtector(unique, &slow);
     531             : 
     532          56 :     Label dictionary(this), dont_delete(this);
     533         112 :     GotoIf(IsDictionaryMap(receiver_map), &dictionary);
     534             : 
     535             :     // Fast properties need to clear recorded slots, which can only be done
     536             :     // in C++.
     537          56 :     Goto(&slow);
     538             : 
     539          56 :     BIND(&dictionary);
     540             :     {
     541          56 :       InvalidateValidityCellIfPrototype(receiver_map);
     542             : 
     543             :       TNode<NameDictionary> properties =
     544          56 :           CAST(LoadSlowProperties(CAST(receiver)));
     545             :       DeleteDictionaryProperty(receiver, properties, unique, context,
     546          56 :                                &dont_delete, &if_notfound);
     547             :     }
     548             : 
     549          56 :     BIND(&dont_delete);
     550             :     {
     551             :       STATIC_ASSERT(LanguageModeSize == 2);
     552             :       GotoIf(SmiNotEqual(language_mode, SmiConstant(LanguageMode::kSloppy)),
     553         112 :              &slow);
     554         112 :       Return(FalseConstant());
     555          56 :     }
     556             :   }
     557             : 
     558          56 :   BIND(&if_notunique);
     559             :   {
     560             :     // If the string was not found in the string table, then no object can
     561             :     // have a property with that name.
     562             :     TryInternalizeString(key, &if_index, &var_index, &if_unique_name,
     563          56 :                          &var_unique, &if_notfound, &slow);
     564             :   }
     565             : 
     566          56 :   BIND(&if_notfound);
     567         112 :   Return(TrueConstant());
     568             : 
     569          56 :   BIND(&slow);
     570             :   {
     571             :     TailCallRuntime(Runtime::kDeleteProperty, context, receiver, key,
     572          56 :                     language_mode);
     573          56 :   }
     574          56 : }
     575             : 
     576         168 : TF_BUILTIN(ForInEnumerate, CodeStubAssembler) {
     577             :   Node* receiver = Parameter(Descriptor::kReceiver);
     578             :   Node* context = Parameter(Descriptor::kContext);
     579             : 
     580          56 :   Label if_empty(this), if_runtime(this, Label::kDeferred);
     581          56 :   Node* receiver_map = CheckEnumCache(receiver, &if_empty, &if_runtime);
     582          56 :   Return(receiver_map);
     583             : 
     584          56 :   BIND(&if_empty);
     585         112 :   Return(EmptyFixedArrayConstant());
     586             : 
     587          56 :   BIND(&if_runtime);
     588         112 :   TailCallRuntime(Runtime::kForInEnumerate, context, receiver);
     589          56 : }
     590             : 
     591         168 : TF_BUILTIN(ForInFilter, CodeStubAssembler) {
     592             :   Node* key = Parameter(Descriptor::kKey);
     593             :   Node* object = Parameter(Descriptor::kObject);
     594             :   Node* context = Parameter(Descriptor::kContext);
     595             : 
     596             :   CSA_ASSERT(this, IsString(key));
     597             : 
     598          56 :   Label if_true(this), if_false(this);
     599          56 :   TNode<Oddball> result = HasProperty(context, object, key, kForInHasProperty);
     600         112 :   Branch(IsTrue(result), &if_true, &if_false);
     601             : 
     602          56 :   BIND(&if_true);
     603          56 :   Return(key);
     604             : 
     605          56 :   BIND(&if_false);
     606         168 :   Return(UndefinedConstant());
     607          56 : }
     608             : 
     609         168 : TF_BUILTIN(SameValue, CodeStubAssembler) {
     610             :   Node* lhs = Parameter(Descriptor::kLeft);
     611             :   Node* rhs = Parameter(Descriptor::kRight);
     612             : 
     613          56 :   Label if_true(this), if_false(this);
     614          56 :   BranchIfSameValue(lhs, rhs, &if_true, &if_false);
     615             : 
     616          56 :   BIND(&if_true);
     617         112 :   Return(TrueConstant());
     618             : 
     619          56 :   BIND(&if_false);
     620         168 :   Return(FalseConstant());
     621          56 : }
     622             : 
     623             : class InternalBuiltinsAssembler : public CodeStubAssembler {
     624             :  public:
     625             :   explicit InternalBuiltinsAssembler(compiler::CodeAssemblerState* state)
     626         112 :       : CodeStubAssembler(state) {}
     627             : 
     628             :   template <typename Descriptor>
     629             :   void GenerateAdaptorWithExitFrameType(
     630             :       Builtins::ExitFrameType exit_frame_type);
     631             : };
     632             : 
     633             : template <typename Descriptor>
     634         112 : void InternalBuiltinsAssembler::GenerateAdaptorWithExitFrameType(
     635             :     Builtins::ExitFrameType exit_frame_type) {
     636         112 :   TNode<JSFunction> target = CAST(Parameter(Descriptor::kTarget));
     637         112 :   TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget));
     638             :   TNode<WordT> c_function =
     639         112 :       UncheckedCast<WordT>(Parameter(Descriptor::kCFunction));
     640             : 
     641             :   // The logic contained here is mirrored for TurboFan inlining in
     642             :   // JSTypedLowering::ReduceJSCall{Function,Construct}. Keep these in sync.
     643             : 
     644             :   // Make sure we operate in the context of the called function (for example
     645             :   // ConstructStubs implemented in C++ will be run in the context of the caller
     646             :   // instead of the callee, due to the way that [[Construct]] is defined for
     647             :   // ordinary functions).
     648             :   TNode<Context> context =
     649         112 :       CAST(LoadObjectField(target, JSFunction::kContextOffset));
     650             : 
     651             :   // Update arguments count for CEntry to contain the number of arguments
     652             :   // including the receiver and the extra arguments.
     653             :   TNode<Int32T> argc =
     654         112 :       UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
     655         112 :   argc = Int32Add(
     656             :       argc,
     657             :       Int32Constant(BuiltinExitFrameConstants::kNumExtraArgsWithReceiver));
     658             : 
     659             :   TNode<Code> code = HeapConstant(
     660             :       CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs, kArgvOnStack,
     661         112 :                           exit_frame_type == Builtins::BUILTIN_EXIT));
     662             : 
     663             :   // Unconditionally push argc, target and new target as extra stack arguments.
     664             :   // They will be used by stack frame iterators when constructing stack trace.
     665             :   TailCallStub(CEntry1ArgvOnStackDescriptor{},  // descriptor
     666             :                code, context,       // standard arguments for TailCallStub
     667             :                argc, c_function,    // register arguments
     668             :                TheHoleConstant(),   // additional stack argument 1 (padding)
     669             :                SmiFromInt32(argc),  // additional stack argument 2
     670             :                target,              // additional stack argument 3
     671         224 :                new_target);         // additional stack argument 4
     672         112 : }
     673             : 
     674         168 : TF_BUILTIN(AdaptorWithExitFrame, InternalBuiltinsAssembler) {
     675          56 :   GenerateAdaptorWithExitFrameType<Descriptor>(Builtins::EXIT);
     676           0 : }
     677             : 
     678         168 : TF_BUILTIN(AdaptorWithBuiltinExitFrame, InternalBuiltinsAssembler) {
     679          56 :   GenerateAdaptorWithExitFrameType<Descriptor>(Builtins::BUILTIN_EXIT);
     680           0 : }
     681             : 
     682         168 : TF_BUILTIN(AllocateInNewSpace, CodeStubAssembler) {
     683             :   TNode<IntPtrT> requested_size =
     684             :       UncheckedCast<IntPtrT>(Parameter(Descriptor::kRequestedSize));
     685             : 
     686             :   TailCallRuntime(Runtime::kAllocateInNewSpace, NoContextConstant(),
     687         168 :                   SmiFromIntPtr(requested_size));
     688          56 : }
     689             : 
     690         168 : TF_BUILTIN(AllocateInOldSpace, CodeStubAssembler) {
     691             :   TNode<IntPtrT> requested_size =
     692             :       UncheckedCast<IntPtrT>(Parameter(Descriptor::kRequestedSize));
     693             : 
     694             :   int flags = AllocateTargetSpace::encode(OLD_SPACE);
     695             :   TailCallRuntime(Runtime::kAllocateInTargetSpace, NoContextConstant(),
     696         168 :                   SmiFromIntPtr(requested_size), SmiConstant(flags));
     697          56 : }
     698             : 
     699         168 : TF_BUILTIN(Abort, CodeStubAssembler) {
     700          56 :   TNode<Smi> message_id = CAST(Parameter(Descriptor::kMessageOrMessageId));
     701         112 :   TailCallRuntime(Runtime::kAbort, NoContextConstant(), message_id);
     702          56 : }
     703             : 
     704         168 : TF_BUILTIN(AbortJS, CodeStubAssembler) {
     705          56 :   TNode<String> message = CAST(Parameter(Descriptor::kMessageOrMessageId));
     706         112 :   TailCallRuntime(Runtime::kAbortJS, NoContextConstant(), message);
     707          56 : }
     708             : 
     709          56 : void Builtins::Generate_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit(
     710             :     MacroAssembler* masm) {
     711          56 :   Generate_CEntry(masm, 1, kDontSaveFPRegs, kArgvOnStack, false);
     712          56 : }
     713             : 
     714          56 : void Builtins::Generate_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit(
     715             :     MacroAssembler* masm) {
     716          56 :   Generate_CEntry(masm, 1, kDontSaveFPRegs, kArgvOnStack, true);
     717          56 : }
     718             : 
     719          56 : void Builtins::
     720             :     Generate_CEntry_Return1_DontSaveFPRegs_ArgvInRegister_NoBuiltinExit(
     721             :         MacroAssembler* masm) {
     722          56 :   Generate_CEntry(masm, 1, kDontSaveFPRegs, kArgvInRegister, false);
     723          56 : }
     724             : 
     725          56 : void Builtins::Generate_CEntry_Return1_SaveFPRegs_ArgvOnStack_NoBuiltinExit(
     726             :     MacroAssembler* masm) {
     727          56 :   Generate_CEntry(masm, 1, kSaveFPRegs, kArgvOnStack, false);
     728          56 : }
     729             : 
     730          56 : void Builtins::Generate_CEntry_Return1_SaveFPRegs_ArgvOnStack_BuiltinExit(
     731             :     MacroAssembler* masm) {
     732          56 :   Generate_CEntry(masm, 1, kSaveFPRegs, kArgvOnStack, true);
     733          56 : }
     734             : 
     735          56 : void Builtins::Generate_CEntry_Return2_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit(
     736             :     MacroAssembler* masm) {
     737          56 :   Generate_CEntry(masm, 2, kDontSaveFPRegs, kArgvOnStack, false);
     738          56 : }
     739             : 
     740          56 : void Builtins::Generate_CEntry_Return2_DontSaveFPRegs_ArgvOnStack_BuiltinExit(
     741             :     MacroAssembler* masm) {
     742          56 :   Generate_CEntry(masm, 2, kDontSaveFPRegs, kArgvOnStack, true);
     743          56 : }
     744             : 
     745          56 : void Builtins::
     746             :     Generate_CEntry_Return2_DontSaveFPRegs_ArgvInRegister_NoBuiltinExit(
     747             :         MacroAssembler* masm) {
     748          56 :   Generate_CEntry(masm, 2, kDontSaveFPRegs, kArgvInRegister, false);
     749          56 : }
     750             : 
     751          56 : void Builtins::Generate_CEntry_Return2_SaveFPRegs_ArgvOnStack_NoBuiltinExit(
     752             :     MacroAssembler* masm) {
     753          56 :   Generate_CEntry(masm, 2, kSaveFPRegs, kArgvOnStack, false);
     754          56 : }
     755             : 
     756          56 : void Builtins::Generate_CEntry_Return2_SaveFPRegs_ArgvOnStack_BuiltinExit(
     757             :     MacroAssembler* masm) {
     758          56 :   Generate_CEntry(masm, 2, kSaveFPRegs, kArgvOnStack, true);
     759          56 : }
     760             : 
     761             : #if !defined(V8_TARGET_ARCH_ARM) && !defined(V8_TARGET_ARCH_MIPS)
     762          56 : void Builtins::Generate_MemCopyUint8Uint8(MacroAssembler* masm) {
     763          56 :   masm->Call(BUILTIN_CODE(masm->isolate(), Illegal), RelocInfo::CODE_TARGET);
     764          56 : }
     765             : #endif  // !defined(V8_TARGET_ARCH_ARM) && !defined(V8_TARGET_ARCH_MIPS)
     766             : 
     767             : #ifndef V8_TARGET_ARCH_ARM
     768          56 : void Builtins::Generate_MemCopyUint16Uint8(MacroAssembler* masm) {
     769          56 :   masm->Call(BUILTIN_CODE(masm->isolate(), Illegal), RelocInfo::CODE_TARGET);
     770          56 : }
     771             : #endif  // V8_TARGET_ARCH_ARM
     772             : 
     773             : #ifndef V8_TARGET_ARCH_IA32
     774          56 : void Builtins::Generate_MemMove(MacroAssembler* masm) {
     775          56 :   masm->Call(BUILTIN_CODE(masm->isolate(), Illegal), RelocInfo::CODE_TARGET);
     776          56 : }
     777             : #endif  // V8_TARGET_ARCH_IA32
     778             : 
     779             : // ES6 [[Get]] operation.
     780         168 : TF_BUILTIN(GetProperty, CodeStubAssembler) {
     781             :   Node* object = Parameter(Descriptor::kObject);
     782             :   Node* key = Parameter(Descriptor::kKey);
     783             :   Node* context = Parameter(Descriptor::kContext);
     784          56 :   Label if_notfound(this), if_proxy(this, Label::kDeferred),
     785          56 :       if_slow(this, Label::kDeferred);
     786             : 
     787             :   CodeStubAssembler::LookupInHolder lookup_property_in_holder =
     788             :       [=](Node* receiver, Node* holder, Node* holder_map,
     789             :           Node* holder_instance_type, Node* unique_name, Label* next_holder,
     790          56 :           Label* if_bailout) {
     791          56 :         VARIABLE(var_value, MachineRepresentation::kTagged);
     792         112 :         Label if_found(this);
     793             :         TryGetOwnProperty(context, receiver, holder, holder_map,
     794             :                           holder_instance_type, unique_name, &if_found,
     795          56 :                           &var_value, next_holder, if_bailout);
     796          56 :         BIND(&if_found);
     797         112 :         Return(var_value.value());
     798          56 :       };
     799             : 
     800             :   CodeStubAssembler::LookupInHolder lookup_element_in_holder =
     801             :       [=](Node* receiver, Node* holder, Node* holder_map,
     802             :           Node* holder_instance_type, Node* index, Label* next_holder,
     803             :           Label* if_bailout) {
     804             :         // Not supported yet.
     805          56 :         Use(next_holder);
     806          56 :         Goto(if_bailout);
     807             :       };
     808             : 
     809             :   TryPrototypeChainLookup(object, key, lookup_property_in_holder,
     810             :                           lookup_element_in_holder, &if_notfound, &if_slow,
     811          56 :                           &if_proxy);
     812             : 
     813          56 :   BIND(&if_notfound);
     814         112 :   Return(UndefinedConstant());
     815             : 
     816          56 :   BIND(&if_slow);
     817          56 :   TailCallRuntime(Runtime::kGetProperty, context, object, key);
     818             : 
     819          56 :   BIND(&if_proxy);
     820             :   {
     821             :     // Convert the {key} to a Name first.
     822         112 :     Node* name = CallBuiltin(Builtins::kToName, context, key);
     823             : 
     824             :     // The {object} is a JSProxy instance, look up the {name} on it, passing
     825             :     // {object} both as receiver and holder. If {name} is absent we can safely
     826             :     // return undefined from here.
     827             :     TailCallBuiltin(Builtins::kProxyGetProperty, context, object, name, object,
     828          56 :                     SmiConstant(OnNonExistent::kReturnUndefined));
     829          56 :   }
     830          56 : }
     831             : 
     832             : // ES6 [[Set]] operation.
     833         336 : TF_BUILTIN(SetProperty, CodeStubAssembler) {
     834          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     835          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
     836          56 :   TNode<Object> key = CAST(Parameter(Descriptor::kKey));
     837          56 :   TNode<Object> value = CAST(Parameter(Descriptor::kValue));
     838             : 
     839             :   KeyedStoreGenericGenerator::SetProperty(state(), context, receiver, key,
     840          56 :                                           value, LanguageMode::kStrict);
     841          56 : }
     842             : 
     843             : // ES6 CreateDataProperty(), specialized for the case where objects are still
     844             : // being initialized, and have not yet been made accessible to the user. Thus,
     845             : // any operation here should be unobservable until after the object has been
     846             : // returned.
     847         336 : TF_BUILTIN(SetPropertyInLiteral, CodeStubAssembler) {
     848          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     849          56 :   TNode<JSObject> receiver = CAST(Parameter(Descriptor::kReceiver));
     850          56 :   TNode<Object> key = CAST(Parameter(Descriptor::kKey));
     851          56 :   TNode<Object> value = CAST(Parameter(Descriptor::kValue));
     852             : 
     853             :   KeyedStoreGenericGenerator::SetPropertyInLiteral(state(), context, receiver,
     854          56 :                                                    key, value);
     855          56 : }
     856             : 
     857             : }  // namespace internal
     858       94089 : }  // namespace v8

Generated by: LCOV version 1.10