Home | History | Annotate | Download | only in builtins
      1 // Copyright 2016 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/builtins/builtins-utils.h"
      6 #include "src/builtins/builtins.h"
      7 #include "src/code-stub-assembler.h"
      8 #include "src/counters.h"
      9 #include "src/interface-descriptors.h"
     10 #include "src/macro-assembler.h"
     11 #include "src/objects-inl.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 BUILTIN(Illegal) {
     17   UNREACHABLE();
     18   return isolate->heap()->undefined_value();  // Make compiler happy.
     19 }
     20 
     21 BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); }
     22 
     23 BUILTIN(UnsupportedThrower) {
     24   HandleScope scope(isolate);
     25   THROW_NEW_ERROR_RETURN_FAILURE(isolate,
     26                                  NewError(MessageTemplate::kUnsupported));
     27 }
     28 
     29 // -----------------------------------------------------------------------------
     30 // Throwers for restricted function properties and strict arguments object
     31 // properties
     32 
     33 BUILTIN(RestrictedFunctionPropertiesThrower) {
     34   HandleScope scope(isolate);
     35   THROW_NEW_ERROR_RETURN_FAILURE(
     36       isolate, NewTypeError(MessageTemplate::kRestrictedFunctionProperties));
     37 }
     38 
     39 BUILTIN(RestrictedStrictArgumentsPropertiesThrower) {
     40   HandleScope scope(isolate);
     41   THROW_NEW_ERROR_RETURN_FAILURE(
     42       isolate, NewTypeError(MessageTemplate::kStrictPoisonPill));
     43 }
     44 
     45 // -----------------------------------------------------------------------------
     46 // Interrupt and stack checks.
     47 
     48 void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
     49   masm->TailCallRuntime(Runtime::kInterrupt);
     50 }
     51 
     52 void Builtins::Generate_StackCheck(MacroAssembler* masm) {
     53   masm->TailCallRuntime(Runtime::kStackGuard);
     54 }
     55 
     56 // -----------------------------------------------------------------------------
     57 // TurboFan support builtins.
     58 
     59 void Builtins::Generate_CopyFastSmiOrObjectElements(
     60     compiler::CodeAssemblerState* state) {
     61   typedef CodeStubAssembler::Label Label;
     62   typedef compiler::Node Node;
     63   typedef CopyFastSmiOrObjectElementsDescriptor Descriptor;
     64   CodeStubAssembler assembler(state);
     65 
     66   Node* object = assembler.Parameter(Descriptor::kObject);
     67 
     68   // Load the {object}s elements.
     69   Node* source = assembler.LoadObjectField(object, JSObject::kElementsOffset);
     70 
     71   CodeStubAssembler::ParameterMode mode = assembler.OptimalParameterMode();
     72   Node* length = assembler.TaggedToParameter(
     73       assembler.LoadFixedArrayBaseLength(source), mode);
     74 
     75   // Check if we can allocate in new space.
     76   ElementsKind kind = FAST_ELEMENTS;
     77   int max_elements = FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind);
     78   Label if_newspace(&assembler), if_oldspace(&assembler);
     79   assembler.Branch(
     80       assembler.UintPtrOrSmiLessThan(
     81           length, assembler.IntPtrOrSmiConstant(max_elements, mode), mode),
     82       &if_newspace, &if_oldspace);
     83 
     84   assembler.Bind(&if_newspace);
     85   {
     86     Node* target = assembler.AllocateFixedArray(kind, length, mode);
     87     assembler.CopyFixedArrayElements(kind, source, target, length,
     88                                      SKIP_WRITE_BARRIER, mode);
     89     assembler.StoreObjectField(object, JSObject::kElementsOffset, target);
     90     assembler.Return(target);
     91   }
     92 
     93   assembler.Bind(&if_oldspace);
     94   {
     95     Node* target = assembler.AllocateFixedArray(kind, length, mode,
     96                                                 CodeStubAssembler::kPretenured);
     97     assembler.CopyFixedArrayElements(kind, source, target, length,
     98                                      UPDATE_WRITE_BARRIER, mode);
     99     assembler.StoreObjectField(object, JSObject::kElementsOffset, target);
    100     assembler.Return(target);
    101   }
    102 }
    103 
    104 void Builtins::Generate_GrowFastDoubleElements(
    105     compiler::CodeAssemblerState* state) {
    106   typedef CodeStubAssembler::Label Label;
    107   typedef compiler::Node Node;
    108   typedef GrowArrayElementsDescriptor Descriptor;
    109   CodeStubAssembler assembler(state);
    110 
    111   Node* object = assembler.Parameter(Descriptor::kObject);
    112   Node* key = assembler.Parameter(Descriptor::kKey);
    113   Node* context = assembler.Parameter(Descriptor::kContext);
    114 
    115   Label runtime(&assembler, CodeStubAssembler::Label::kDeferred);
    116   Node* elements = assembler.LoadElements(object);
    117   elements = assembler.TryGrowElementsCapacity(
    118       object, elements, FAST_DOUBLE_ELEMENTS, key, &runtime);
    119   assembler.Return(elements);
    120 
    121   assembler.Bind(&runtime);
    122   assembler.TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
    123 }
    124 
    125 void Builtins::Generate_GrowFastSmiOrObjectElements(
    126     compiler::CodeAssemblerState* state) {
    127   typedef CodeStubAssembler::Label Label;
    128   typedef compiler::Node Node;
    129   typedef GrowArrayElementsDescriptor Descriptor;
    130   CodeStubAssembler assembler(state);
    131 
    132   Node* object = assembler.Parameter(Descriptor::kObject);
    133   Node* key = assembler.Parameter(Descriptor::kKey);
    134   Node* context = assembler.Parameter(Descriptor::kContext);
    135 
    136   Label runtime(&assembler, CodeStubAssembler::Label::kDeferred);
    137   Node* elements = assembler.LoadElements(object);
    138   elements = assembler.TryGrowElementsCapacity(object, elements, FAST_ELEMENTS,
    139                                                key, &runtime);
    140   assembler.Return(elements);
    141 
    142   assembler.Bind(&runtime);
    143   assembler.TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
    144 }
    145 
    146 namespace {
    147 
    148 void Generate_NewArgumentsElements(CodeStubAssembler* assembler,
    149                                    compiler::Node* frame,
    150                                    compiler::Node* length) {
    151   typedef CodeStubAssembler::Label Label;
    152   typedef CodeStubAssembler::Variable Variable;
    153   typedef compiler::Node Node;
    154 
    155   // Check if we can allocate in new space.
    156   ElementsKind kind = FAST_ELEMENTS;
    157   int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind);
    158   Label if_newspace(assembler), if_oldspace(assembler, Label::kDeferred);
    159   assembler->Branch(assembler->IntPtrLessThan(
    160                         length, assembler->IntPtrConstant(max_elements)),
    161                     &if_newspace, &if_oldspace);
    162 
    163   assembler->Bind(&if_newspace);
    164   {
    165     // Prefer EmptyFixedArray in case of non-positive {length} (the {length}
    166     // can be negative here for rest parameters).
    167     Label if_empty(assembler), if_notempty(assembler);
    168     assembler->Branch(
    169         assembler->IntPtrLessThanOrEqual(length, assembler->IntPtrConstant(0)),
    170         &if_empty, &if_notempty);
    171 
    172     assembler->Bind(&if_empty);
    173     assembler->Return(assembler->EmptyFixedArrayConstant());
    174 
    175     assembler->Bind(&if_notempty);
    176     {
    177       // Allocate a FixedArray in new space.
    178       Node* result = assembler->AllocateFixedArray(kind, length);
    179 
    180       // Compute the effective {offset} into the {frame}.
    181       Node* offset = assembler->IntPtrAdd(length, assembler->IntPtrConstant(1));
    182 
    183       // Copy the parameters from {frame} (starting at {offset}) to {result}.
    184       Variable var_index(assembler, MachineType::PointerRepresentation());
    185       Label loop(assembler, &var_index), done_loop(assembler);
    186       var_index.Bind(assembler->IntPtrConstant(0));
    187       assembler->Goto(&loop);
    188       assembler->Bind(&loop);
    189       {
    190         // Load the current {index}.
    191         Node* index = var_index.value();
    192 
    193         // Check if we are done.
    194         assembler->GotoIf(assembler->WordEqual(index, length), &done_loop);
    195 
    196         // Load the parameter at the given {index}.
    197         Node* value = assembler->Load(
    198             MachineType::AnyTagged(), frame,
    199             assembler->WordShl(assembler->IntPtrSub(offset, index),
    200                                assembler->IntPtrConstant(kPointerSizeLog2)));
    201 
    202         // Store the {value} into the {result}.
    203         assembler->StoreFixedArrayElement(result, index, value,
    204                                           SKIP_WRITE_BARRIER);
    205 
    206         // Continue with next {index}.
    207         var_index.Bind(
    208             assembler->IntPtrAdd(index, assembler->IntPtrConstant(1)));
    209         assembler->Goto(&loop);
    210       }
    211 
    212       assembler->Bind(&done_loop);
    213       assembler->Return(result);
    214     }
    215   }
    216 
    217   assembler->Bind(&if_oldspace);
    218   {
    219     // Allocate in old space (or large object space).
    220     assembler->TailCallRuntime(
    221         Runtime::kNewArgumentsElements, assembler->NoContextConstant(),
    222         assembler->BitcastWordToTagged(frame), assembler->SmiFromWord(length));
    223   }
    224 }
    225 
    226 }  // namespace
    227 
    228 void Builtins::Generate_NewUnmappedArgumentsElements(
    229     compiler::CodeAssemblerState* state) {
    230   typedef CodeStubAssembler::Label Label;
    231   typedef CodeStubAssembler::Variable Variable;
    232   typedef compiler::Node Node;
    233   typedef NewArgumentsElementsDescriptor Descriptor;
    234   CodeStubAssembler assembler(state);
    235 
    236   Node* formal_parameter_count =
    237       assembler.Parameter(Descriptor::kFormalParameterCount);
    238 
    239   // Determine the frame that holds the parameters.
    240   Label done(&assembler);
    241   Variable var_frame(&assembler, MachineType::PointerRepresentation()),
    242       var_length(&assembler, MachineType::PointerRepresentation());
    243   var_frame.Bind(assembler.LoadParentFramePointer());
    244   var_length.Bind(formal_parameter_count);
    245   Node* parent_frame = assembler.Load(
    246       MachineType::Pointer(), var_frame.value(),
    247       assembler.IntPtrConstant(StandardFrameConstants::kCallerFPOffset));
    248   Node* parent_frame_type =
    249       assembler.Load(MachineType::AnyTagged(), parent_frame,
    250                      assembler.IntPtrConstant(
    251                          CommonFrameConstants::kContextOrFrameTypeOffset));
    252   assembler.GotoIfNot(assembler.MarkerIsFrameType(
    253                           parent_frame_type, StackFrame::ARGUMENTS_ADAPTOR),
    254                       &done);
    255   {
    256     // Determine the length from the ArgumentsAdaptorFrame.
    257     Node* length = assembler.LoadAndUntagSmi(
    258         parent_frame, ArgumentsAdaptorFrameConstants::kLengthOffset);
    259 
    260     // Take the arguments from the ArgumentsAdaptorFrame.
    261     var_frame.Bind(parent_frame);
    262     var_length.Bind(length);
    263   }
    264   assembler.Goto(&done);
    265 
    266   // Allocate the actual FixedArray for the elements.
    267   assembler.Bind(&done);
    268   Generate_NewArgumentsElements(&assembler, var_frame.value(),
    269                                 var_length.value());
    270 }
    271 
    272 void Builtins::Generate_NewRestParameterElements(
    273     compiler::CodeAssemblerState* state) {
    274   typedef CodeStubAssembler::Label Label;
    275   typedef compiler::Node Node;
    276   typedef NewArgumentsElementsDescriptor Descriptor;
    277   CodeStubAssembler assembler(state);
    278 
    279   Node* formal_parameter_count =
    280       assembler.Parameter(Descriptor::kFormalParameterCount);
    281 
    282   // Check if we have an ArgumentsAdaptorFrame, as we will only have rest
    283   // parameters in that case.
    284   Label if_empty(&assembler);
    285   Node* frame = assembler.Load(
    286       MachineType::Pointer(), assembler.LoadParentFramePointer(),
    287       assembler.IntPtrConstant(StandardFrameConstants::kCallerFPOffset));
    288   Node* frame_type =
    289       assembler.Load(MachineType::AnyTagged(), frame,
    290                      assembler.IntPtrConstant(
    291                          CommonFrameConstants::kContextOrFrameTypeOffset));
    292   assembler.GotoIfNot(
    293       assembler.MarkerIsFrameType(frame_type, StackFrame::ARGUMENTS_ADAPTOR),
    294       &if_empty);
    295 
    296   // Determine the length from the ArgumentsAdaptorFrame.
    297   Node* frame_length = assembler.LoadAndUntagSmi(
    298       frame, ArgumentsAdaptorFrameConstants::kLengthOffset);
    299 
    300   // Compute the actual rest parameter length (may be negative).
    301   Node* length = assembler.IntPtrSub(frame_length, formal_parameter_count);
    302 
    303   // Allocate the actual FixedArray for the elements.
    304   Generate_NewArgumentsElements(&assembler, frame, length);
    305 
    306   // No rest parameters, return an empty FixedArray.
    307   assembler.Bind(&if_empty);
    308   assembler.Return(assembler.EmptyFixedArrayConstant());
    309 }
    310 
    311 void Builtins::Generate_ReturnReceiver(compiler::CodeAssemblerState* state) {
    312   CodeStubAssembler assembler(state);
    313   assembler.Return(assembler.Parameter(0));
    314 }
    315 
    316 }  // namespace internal
    317 }  // namespace v8
    318