LCOV - code coverage report
Current view: top level - src/builtins - builtins-internal-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 159 159 100.0 %
Date: 2017-04-26 Functions: 16 16 100.0 %

          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/builtins/builtins-utils-gen.h"
       6             : #include "src/builtins/builtins.h"
       7             : #include "src/code-stub-assembler.h"
       8             : #include "src/macro-assembler.h"
       9             : #include "src/runtime/runtime.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : 
      14             : // -----------------------------------------------------------------------------
      15             : // Interrupt and stack checks.
      16             : 
      17          43 : void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
      18          43 :   masm->TailCallRuntime(Runtime::kInterrupt);
      19          43 : }
      20             : 
      21          43 : void Builtins::Generate_StackCheck(MacroAssembler* masm) {
      22          43 :   masm->TailCallRuntime(Runtime::kStackGuard);
      23          43 : }
      24             : 
      25             : // -----------------------------------------------------------------------------
      26             : // TurboFan support builtins.
      27             : 
      28         129 : TF_BUILTIN(CopyFastSmiOrObjectElements, CodeStubAssembler) {
      29             :   Node* object = Parameter(Descriptor::kObject);
      30             : 
      31             :   // Load the {object}s elements.
      32          43 :   Node* source = LoadObjectField(object, JSObject::kElementsOffset);
      33             : 
      34             :   ParameterMode mode = OptimalParameterMode();
      35          43 :   Node* length = TaggedToParameter(LoadFixedArrayBaseLength(source), mode);
      36             : 
      37             :   // Check if we can allocate in new space.
      38             :   ElementsKind kind = FAST_ELEMENTS;
      39          43 :   int max_elements = FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind);
      40          43 :   Label if_newspace(this), if_oldspace(this);
      41             :   Branch(UintPtrOrSmiLessThan(length, IntPtrOrSmiConstant(max_elements, mode),
      42             :                               mode),
      43          43 :          &if_newspace, &if_oldspace);
      44             : 
      45          43 :   BIND(&if_newspace);
      46             :   {
      47          43 :     Node* target = AllocateFixedArray(kind, length, mode);
      48             :     CopyFixedArrayElements(kind, source, target, length, SKIP_WRITE_BARRIER,
      49             :                            mode);
      50          43 :     StoreObjectField(object, JSObject::kElementsOffset, target);
      51          43 :     Return(target);
      52             :   }
      53             : 
      54          43 :   BIND(&if_oldspace);
      55             :   {
      56          43 :     Node* target = AllocateFixedArray(kind, length, mode, kPretenured);
      57             :     CopyFixedArrayElements(kind, source, target, length, UPDATE_WRITE_BARRIER,
      58             :                            mode);
      59          43 :     StoreObjectField(object, JSObject::kElementsOffset, target);
      60          43 :     Return(target);
      61          43 :   }
      62          43 : }
      63             : 
      64         129 : TF_BUILTIN(GrowFastDoubleElements, CodeStubAssembler) {
      65             :   Node* object = Parameter(Descriptor::kObject);
      66             :   Node* key = Parameter(Descriptor::kKey);
      67             :   Node* context = Parameter(Descriptor::kContext);
      68             : 
      69             :   Label runtime(this, Label::kDeferred);
      70          43 :   Node* elements = LoadElements(object);
      71             :   elements = TryGrowElementsCapacity(object, elements, FAST_DOUBLE_ELEMENTS,
      72          43 :                                      key, &runtime);
      73          43 :   Return(elements);
      74             : 
      75          43 :   BIND(&runtime);
      76          43 :   TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
      77          43 : }
      78             : 
      79         129 : TF_BUILTIN(GrowFastSmiOrObjectElements, CodeStubAssembler) {
      80             :   Node* object = Parameter(Descriptor::kObject);
      81             :   Node* key = Parameter(Descriptor::kKey);
      82             :   Node* context = Parameter(Descriptor::kContext);
      83             : 
      84             :   Label runtime(this, Label::kDeferred);
      85          43 :   Node* elements = LoadElements(object);
      86             :   elements =
      87          43 :       TryGrowElementsCapacity(object, elements, FAST_ELEMENTS, key, &runtime);
      88          43 :   Return(elements);
      89             : 
      90          43 :   BIND(&runtime);
      91          43 :   TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
      92          43 : }
      93             : 
      94         129 : TF_BUILTIN(NewUnmappedArgumentsElements, CodeStubAssembler) {
      95             :   Node* frame = Parameter(Descriptor::kFrame);
      96          43 :   Node* length = SmiToWord(Parameter(Descriptor::kLength));
      97             : 
      98             :   // Check if we can allocate in new space.
      99             :   ElementsKind kind = FAST_ELEMENTS;
     100          43 :   int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind);
     101          43 :   Label if_newspace(this), if_oldspace(this, Label::kDeferred);
     102             :   Branch(IntPtrLessThan(length, IntPtrConstant(max_elements)), &if_newspace,
     103          43 :          &if_oldspace);
     104             : 
     105          43 :   BIND(&if_newspace);
     106             :   {
     107             :     // Prefer EmptyFixedArray in case of non-positive {length} (the {length}
     108             :     // can be negative here for rest parameters).
     109          43 :     Label if_empty(this), if_notempty(this);
     110             :     Branch(IntPtrLessThanOrEqual(length, IntPtrConstant(0)), &if_empty,
     111          43 :            &if_notempty);
     112             : 
     113          43 :     BIND(&if_empty);
     114          43 :     Return(EmptyFixedArrayConstant());
     115             : 
     116          43 :     BIND(&if_notempty);
     117             :     {
     118             :       // Allocate a FixedArray in new space.
     119          43 :       Node* result = AllocateFixedArray(kind, length);
     120             : 
     121             :       // Compute the effective {offset} into the {frame}.
     122          43 :       Node* offset = IntPtrAdd(length, IntPtrConstant(1));
     123             : 
     124             :       // Copy the parameters from {frame} (starting at {offset}) to {result}.
     125          43 :       VARIABLE(var_index, MachineType::PointerRepresentation());
     126          43 :       Label loop(this, &var_index), done_loop(this);
     127          43 :       var_index.Bind(IntPtrConstant(0));
     128          43 :       Goto(&loop);
     129          43 :       BIND(&loop);
     130             :       {
     131             :         // Load the current {index}.
     132          43 :         Node* index = var_index.value();
     133             : 
     134             :         // Check if we are done.
     135          43 :         GotoIf(WordEqual(index, length), &done_loop);
     136             : 
     137             :         // Load the parameter at the given {index}.
     138             :         Node* value = Load(MachineType::AnyTagged(), frame,
     139             :                            WordShl(IntPtrSub(offset, index),
     140          43 :                                    IntPtrConstant(kPointerSizeLog2)));
     141             : 
     142             :         // Store the {value} into the {result}.
     143          43 :         StoreFixedArrayElement(result, index, value, SKIP_WRITE_BARRIER);
     144             : 
     145             :         // Continue with next {index}.
     146          43 :         var_index.Bind(IntPtrAdd(index, IntPtrConstant(1)));
     147          43 :         Goto(&loop);
     148             :       }
     149             : 
     150          43 :       BIND(&done_loop);
     151          86 :       Return(result);
     152          43 :     }
     153             :   }
     154             : 
     155          43 :   BIND(&if_oldspace);
     156             :   {
     157             :     // Allocate in old space (or large object space).
     158             :     TailCallRuntime(Runtime::kNewArgumentsElements, NoContextConstant(),
     159          43 :                     BitcastWordToTagged(frame), SmiFromWord(length));
     160          43 :   }
     161          43 : }
     162             : 
     163         129 : TF_BUILTIN(ReturnReceiver, CodeStubAssembler) {
     164          43 :   Return(Parameter(Descriptor::kReceiver));
     165          43 : }
     166             : 
     167             : class DeletePropertyBaseAssembler : public CodeStubAssembler {
     168             :  public:
     169             :   explicit DeletePropertyBaseAssembler(compiler::CodeAssemblerState* state)
     170          43 :       : CodeStubAssembler(state) {}
     171             : 
     172          43 :   void DeleteFastProperty(Node* receiver, Node* receiver_map, Node* properties,
     173             :                           Node* name, Label* dont_delete, Label* not_found,
     174             :                           Label* slow) {
     175             :     // This builtin implements a special case for fast property deletion:
     176             :     // when the last property in an object is deleted, then instead of
     177             :     // normalizing the properties, we can undo the last map transition,
     178             :     // with a few prerequisites:
     179             :     // (1) The current map must not be marked stable. Otherwise there could
     180             :     // be optimized code that depends on the assumption that no object that
     181             :     // reached this map transitions away from it (without triggering the
     182             :     // "deoptimize dependent code" mechanism).
     183          43 :     Node* bitfield3 = LoadMapBitField3(receiver_map);
     184          43 :     GotoIfNot(IsSetWord32<Map::IsUnstable>(bitfield3), slow);
     185             :     // (2) The property to be deleted must be the last property.
     186          43 :     Node* descriptors = LoadMapDescriptors(receiver_map);
     187             :     Node* nof = DecodeWord32<Map::NumberOfOwnDescriptorsBits>(bitfield3);
     188          43 :     GotoIf(Word32Equal(nof, Int32Constant(0)), not_found);
     189          43 :     Node* descriptor_number = Int32Sub(nof, Int32Constant(1));
     190          43 :     Node* key_index = DescriptorArrayToKeyIndex(descriptor_number);
     191          43 :     Node* actual_key = LoadFixedArrayElement(descriptors, key_index);
     192             :     // TODO(jkummerow): We could implement full descriptor search in order
     193             :     // to avoid the runtime call for deleting nonexistent properties, but
     194             :     // that's probably a rare case.
     195          43 :     GotoIf(WordNotEqual(actual_key, name), slow);
     196             :     // (3) The property to be deleted must be deletable.
     197             :     Node* details =
     198             :         LoadDetailsByKeyIndex<DescriptorArray>(descriptors, key_index);
     199             :     GotoIf(IsSetWord32(details, PropertyDetails::kAttributesDontDeleteMask),
     200          43 :            dont_delete);
     201             :     // (4) The map must have a back pointer.
     202             :     Node* backpointer =
     203          43 :         LoadObjectField(receiver_map, Map::kConstructorOrBackPointerOffset);
     204          43 :     GotoIfNot(IsMap(backpointer), slow);
     205             :     // (5) The last transition must have been caused by adding a property
     206             :     // (and not any kind of special transition).
     207             :     Node* previous_nof = DecodeWord32<Map::NumberOfOwnDescriptorsBits>(
     208          43 :         LoadMapBitField3(backpointer));
     209          43 :     GotoIfNot(Word32Equal(previous_nof, descriptor_number), slow);
     210             : 
     211             :     // Preconditions successful, perform the map rollback!
     212             :     // Zap the property to avoid keeping objects alive.
     213             :     // Zapping is not necessary for properties stored in the descriptor array.
     214             :     Label zapping_done(this);
     215             :     GotoIf(Word32NotEqual(DecodeWord32<PropertyDetails::LocationField>(details),
     216             :                           Int32Constant(kField)),
     217          86 :            &zapping_done);
     218             :     Node* field_index =
     219          43 :         DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details);
     220          43 :     Node* inobject_properties = LoadMapInobjectProperties(receiver_map);
     221          43 :     Label inobject(this), backing_store(this);
     222             :     // Due to inobject slack tracking, a field currently within the object
     223             :     // could later be between objects. Use the one pointer filler map for
     224             :     // zapping the deleted field to make this safe.
     225          43 :     Node* filler = LoadRoot(Heap::kOnePointerFillerMapRootIndex);
     226             :     DCHECK(Heap::RootIsImmortalImmovable(Heap::kOnePointerFillerMapRootIndex));
     227             :     Branch(UintPtrLessThan(field_index, inobject_properties), &inobject,
     228          43 :            &backing_store);
     229          43 :     BIND(&inobject);
     230             :     {
     231             :       Node* field_offset =
     232             :           IntPtrMul(IntPtrSub(LoadMapInstanceSize(receiver_map),
     233             :                               IntPtrSub(inobject_properties, field_index)),
     234          43 :                     IntPtrConstant(kPointerSize));
     235          43 :       StoreObjectFieldNoWriteBarrier(receiver, field_offset, filler);
     236          43 :       Goto(&zapping_done);
     237             :     }
     238          43 :     BIND(&backing_store);
     239             :     {
     240          43 :       Node* backing_store_index = IntPtrSub(field_index, inobject_properties);
     241             :       StoreFixedArrayElement(properties, backing_store_index, filler,
     242          43 :                              SKIP_WRITE_BARRIER);
     243          43 :       Goto(&zapping_done);
     244             :     }
     245          43 :     BIND(&zapping_done);
     246          43 :     StoreMap(receiver, backpointer);
     247          86 :     Return(TrueConstant());
     248          43 :   }
     249             : 
     250          43 :   void DeleteDictionaryProperty(Node* receiver, Node* properties, Node* name,
     251             :                                 Node* context, Label* dont_delete,
     252             :                                 Label* notfound) {
     253          43 :     VARIABLE(var_name_index, MachineType::PointerRepresentation());
     254          43 :     Label dictionary_found(this, &var_name_index);
     255             :     NameDictionaryLookup<NameDictionary>(properties, name, &dictionary_found,
     256          43 :                                          &var_name_index, notfound);
     257             : 
     258          43 :     BIND(&dictionary_found);
     259          43 :     Node* key_index = var_name_index.value();
     260             :     Node* details =
     261             :         LoadDetailsByKeyIndex<NameDictionary>(properties, key_index);
     262             :     GotoIf(IsSetWord32(details, PropertyDetails::kAttributesDontDeleteMask),
     263          43 :            dont_delete);
     264             :     // Overwrite the entry itself (see NameDictionary::SetEntry).
     265          43 :     Node* filler = TheHoleConstant();
     266             :     DCHECK(Heap::RootIsImmortalImmovable(Heap::kTheHoleValueRootIndex));
     267          43 :     StoreFixedArrayElement(properties, key_index, filler, SKIP_WRITE_BARRIER);
     268             :     StoreValueByKeyIndex<NameDictionary>(properties, key_index, filler,
     269             :                                          SKIP_WRITE_BARRIER);
     270             :     StoreDetailsByKeyIndex<NameDictionary>(properties, key_index,
     271          43 :                                            SmiConstant(Smi::kZero));
     272             : 
     273             :     // Update bookkeeping information (see NameDictionary::ElementRemoved).
     274             :     Node* nof = GetNumberOfElements<NameDictionary>(properties);
     275          43 :     Node* new_nof = SmiSub(nof, SmiConstant(1));
     276             :     SetNumberOfElements<NameDictionary>(properties, new_nof);
     277             :     Node* num_deleted = GetNumberOfDeletedElements<NameDictionary>(properties);
     278          43 :     Node* new_deleted = SmiAdd(num_deleted, SmiConstant(1));
     279             :     SetNumberOfDeletedElements<NameDictionary>(properties, new_deleted);
     280             : 
     281             :     // Shrink the dictionary if necessary (see NameDictionary::Shrink).
     282          43 :     Label shrinking_done(this);
     283             :     Node* capacity = GetCapacity<NameDictionary>(properties);
     284          43 :     GotoIf(SmiGreaterThan(new_nof, SmiShr(capacity, 2)), &shrinking_done);
     285          43 :     GotoIf(SmiLessThan(new_nof, SmiConstant(16)), &shrinking_done);
     286          43 :     CallRuntime(Runtime::kShrinkPropertyDictionary, context, receiver, name);
     287          43 :     Goto(&shrinking_done);
     288          43 :     BIND(&shrinking_done);
     289             : 
     290          86 :     Return(TrueConstant());
     291          43 :   }
     292             : };
     293             : 
     294         172 : TF_BUILTIN(DeleteProperty, DeletePropertyBaseAssembler) {
     295             :   Node* receiver = Parameter(Descriptor::kObject);
     296             :   Node* key = Parameter(Descriptor::kKey);
     297             :   Node* language_mode = Parameter(Descriptor::kLanguageMode);
     298             :   Node* context = Parameter(Descriptor::kContext);
     299             : 
     300          43 :   VARIABLE(var_index, MachineType::PointerRepresentation());
     301          86 :   VARIABLE(var_unique, MachineRepresentation::kTagged, key);
     302          43 :   Label if_index(this), if_unique_name(this), if_notunique(this),
     303          43 :       if_notfound(this), slow(this);
     304             : 
     305          43 :   GotoIf(TaggedIsSmi(receiver), &slow);
     306          43 :   Node* receiver_map = LoadMap(receiver);
     307          43 :   Node* instance_type = LoadMapInstanceType(receiver_map);
     308             :   GotoIf(Int32LessThanOrEqual(instance_type,
     309             :                               Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
     310          43 :          &slow);
     311             :   TryToName(key, &if_index, &var_index, &if_unique_name, &var_unique, &slow,
     312          43 :             &if_notunique);
     313             : 
     314          43 :   BIND(&if_index);
     315             :   {
     316          43 :     Comment("integer index");
     317          43 :     Goto(&slow);  // TODO(jkummerow): Implement more smarts here.
     318             :   }
     319             : 
     320          43 :   BIND(&if_unique_name);
     321             :   {
     322          43 :     Comment("key is unique name");
     323          43 :     Node* unique = var_unique.value();
     324          43 :     CheckForAssociatedProtector(unique, &slow);
     325             : 
     326          43 :     Label dictionary(this), dont_delete(this);
     327          43 :     Node* properties = LoadProperties(receiver);
     328          43 :     Node* properties_map = LoadMap(properties);
     329             :     GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)),
     330          43 :            &dictionary);
     331             :     DeleteFastProperty(receiver, receiver_map, properties, unique, &dont_delete,
     332          43 :                        &if_notfound, &slow);
     333             : 
     334          43 :     BIND(&dictionary);
     335             :     {
     336             :       DeleteDictionaryProperty(receiver, properties, unique, context,
     337          43 :                                &dont_delete, &if_notfound);
     338             :     }
     339             : 
     340          43 :     BIND(&dont_delete);
     341             :     {
     342             :       STATIC_ASSERT(LANGUAGE_END == 2);
     343          43 :       GotoIf(SmiNotEqual(language_mode, SmiConstant(SLOPPY)), &slow);
     344          43 :       Return(FalseConstant());
     345          43 :     }
     346             :   }
     347             : 
     348          43 :   BIND(&if_notunique);
     349             :   {
     350             :     // If the string was not found in the string table, then no object can
     351             :     // have a property with that name.
     352             :     TryInternalizeString(key, &if_index, &var_index, &if_unique_name,
     353          43 :                          &var_unique, &if_notfound, &slow);
     354             :   }
     355             : 
     356          43 :   BIND(&if_notfound);
     357          43 :   Return(TrueConstant());
     358             : 
     359          43 :   BIND(&slow);
     360             :   {
     361             :     TailCallRuntime(Runtime::kDeleteProperty, context, receiver, key,
     362          43 :                     language_mode);
     363          43 :   }
     364          43 : }
     365             : 
     366             : }  // namespace internal
     367             : }  // namespace v8

Generated by: LCOV version 1.10