LCOV - code coverage report
Current view: top level - src/builtins - builtins-internal-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 408 410 99.5 %
Date: 2019-04-18 Functions: 69 71 97.2 %

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

Generated by: LCOV version 1.10