Home | History | Annotate | Download | only in src
      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 #ifndef V8_CODE_STUB_ASSEMBLER_H_
      6 #define V8_CODE_STUB_ASSEMBLER_H_
      7 
      8 #include "src/compiler/code-assembler.h"
      9 #include "src/objects.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 class CallInterfaceDescriptor;
     15 class StatsCounter;
     16 class StubCache;
     17 
     18 // Provides JavaScript-specific "macro-assembler" functionality on top of the
     19 // CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler,
     20 // it's possible to add JavaScript-specific useful CodeAssembler "macros"
     21 // without modifying files in the compiler directory (and requiring a review
     22 // from a compiler directory OWNER).
     23 class CodeStubAssembler : public compiler::CodeAssembler {
     24  public:
     25   // Create with CallStub linkage.
     26   // |result_size| specifies the number of results returned by the stub.
     27   // TODO(rmcilroy): move result_size to the CallInterfaceDescriptor.
     28   CodeStubAssembler(Isolate* isolate, Zone* zone,
     29                     const CallInterfaceDescriptor& descriptor,
     30                     Code::Flags flags, const char* name,
     31                     size_t result_size = 1);
     32 
     33   // Create with JSCall linkage.
     34   CodeStubAssembler(Isolate* isolate, Zone* zone, int parameter_count,
     35                     Code::Flags flags, const char* name);
     36 
     37   enum ParameterMode { INTEGER_PARAMETERS, SMI_PARAMETERS };
     38 
     39   compiler::Node* BooleanMapConstant();
     40   compiler::Node* EmptyStringConstant();
     41   compiler::Node* HeapNumberMapConstant();
     42   compiler::Node* NoContextConstant();
     43   compiler::Node* NullConstant();
     44   compiler::Node* UndefinedConstant();
     45   compiler::Node* TheHoleConstant();
     46   compiler::Node* HashSeed();
     47   compiler::Node* StaleRegisterConstant();
     48 
     49   // Float64 operations.
     50   compiler::Node* Float64Ceil(compiler::Node* x);
     51   compiler::Node* Float64Floor(compiler::Node* x);
     52   compiler::Node* Float64Round(compiler::Node* x);
     53   compiler::Node* Float64Trunc(compiler::Node* x);
     54 
     55   // Tag a Word as a Smi value.
     56   compiler::Node* SmiTag(compiler::Node* value);
     57   // Untag a Smi value as a Word.
     58   compiler::Node* SmiUntag(compiler::Node* value);
     59 
     60   // Smi conversions.
     61   compiler::Node* SmiToFloat64(compiler::Node* value);
     62   compiler::Node* SmiFromWord(compiler::Node* value) { return SmiTag(value); }
     63   compiler::Node* SmiFromWord32(compiler::Node* value);
     64   compiler::Node* SmiToWord(compiler::Node* value) { return SmiUntag(value); }
     65   compiler::Node* SmiToWord32(compiler::Node* value);
     66 
     67   // Smi operations.
     68   compiler::Node* SmiAdd(compiler::Node* a, compiler::Node* b);
     69   compiler::Node* SmiAddWithOverflow(compiler::Node* a, compiler::Node* b);
     70   compiler::Node* SmiSub(compiler::Node* a, compiler::Node* b);
     71   compiler::Node* SmiSubWithOverflow(compiler::Node* a, compiler::Node* b);
     72   compiler::Node* SmiEqual(compiler::Node* a, compiler::Node* b);
     73   compiler::Node* SmiAboveOrEqual(compiler::Node* a, compiler::Node* b);
     74   compiler::Node* SmiLessThan(compiler::Node* a, compiler::Node* b);
     75   compiler::Node* SmiLessThanOrEqual(compiler::Node* a, compiler::Node* b);
     76   compiler::Node* SmiMin(compiler::Node* a, compiler::Node* b);
     77 
     78   // Allocate an object of the given size.
     79   compiler::Node* Allocate(compiler::Node* size, AllocationFlags flags = kNone);
     80   compiler::Node* Allocate(int size, AllocationFlags flags = kNone);
     81   compiler::Node* InnerAllocate(compiler::Node* previous, int offset);
     82   compiler::Node* InnerAllocate(compiler::Node* previous,
     83                                 compiler::Node* offset);
     84 
     85   void Assert(compiler::Node* condition);
     86 
     87   // Check a value for smi-ness
     88   compiler::Node* WordIsSmi(compiler::Node* a);
     89   // Check that the value is a positive smi.
     90   compiler::Node* WordIsPositiveSmi(compiler::Node* a);
     91 
     92   void BranchIfSmiLessThan(compiler::Node* a, compiler::Node* b, Label* if_true,
     93                            Label* if_false) {
     94     BranchIf(SmiLessThan(a, b), if_true, if_false);
     95   }
     96 
     97   void BranchIfSmiLessThanOrEqual(compiler::Node* a, compiler::Node* b,
     98                                   Label* if_true, Label* if_false) {
     99     BranchIf(SmiLessThanOrEqual(a, b), if_true, if_false);
    100   }
    101 
    102   void BranchIfFloat64IsNaN(compiler::Node* value, Label* if_true,
    103                             Label* if_false) {
    104     BranchIfFloat64Equal(value, value, if_false, if_true);
    105   }
    106 
    107   // Load value from current frame by given offset in bytes.
    108   compiler::Node* LoadFromFrame(int offset,
    109                                 MachineType rep = MachineType::AnyTagged());
    110   // Load value from current parent frame by given offset in bytes.
    111   compiler::Node* LoadFromParentFrame(
    112       int offset, MachineType rep = MachineType::AnyTagged());
    113 
    114   // Load an object pointer from a buffer that isn't in the heap.
    115   compiler::Node* LoadBufferObject(compiler::Node* buffer, int offset,
    116                                    MachineType rep = MachineType::AnyTagged());
    117   // Load a field from an object on the heap.
    118   compiler::Node* LoadObjectField(compiler::Node* object, int offset,
    119                                   MachineType rep = MachineType::AnyTagged());
    120   compiler::Node* LoadObjectField(compiler::Node* object,
    121                                   compiler::Node* offset,
    122                                   MachineType rep = MachineType::AnyTagged());
    123 
    124   // Load the floating point value of a HeapNumber.
    125   compiler::Node* LoadHeapNumberValue(compiler::Node* object);
    126   // Load the Map of an HeapObject.
    127   compiler::Node* LoadMap(compiler::Node* object);
    128   // Load the instance type of an HeapObject.
    129   compiler::Node* LoadInstanceType(compiler::Node* object);
    130   // Checks that given heap object has given instance type.
    131   void AssertInstanceType(compiler::Node* object, InstanceType instance_type);
    132   // Load the properties backing store of a JSObject.
    133   compiler::Node* LoadProperties(compiler::Node* object);
    134   // Load the elements backing store of a JSObject.
    135   compiler::Node* LoadElements(compiler::Node* object);
    136   // Load the length of a fixed array base instance.
    137   compiler::Node* LoadFixedArrayBaseLength(compiler::Node* array);
    138   // Load the bit field of a Map.
    139   compiler::Node* LoadMapBitField(compiler::Node* map);
    140   // Load bit field 2 of a map.
    141   compiler::Node* LoadMapBitField2(compiler::Node* map);
    142   // Load bit field 3 of a map.
    143   compiler::Node* LoadMapBitField3(compiler::Node* map);
    144   // Load the instance type of a map.
    145   compiler::Node* LoadMapInstanceType(compiler::Node* map);
    146   // Load the instance descriptors of a map.
    147   compiler::Node* LoadMapDescriptors(compiler::Node* map);
    148   // Load the prototype of a map.
    149   compiler::Node* LoadMapPrototype(compiler::Node* map);
    150   // Load the instance size of a Map.
    151   compiler::Node* LoadMapInstanceSize(compiler::Node* map);
    152   // Load the inobject properties count of a Map (valid only for JSObjects).
    153   compiler::Node* LoadMapInobjectProperties(compiler::Node* map);
    154 
    155   // Load the hash field of a name.
    156   compiler::Node* LoadNameHashField(compiler::Node* name);
    157   // Load the hash value of a name. If {if_hash_not_computed} label
    158   // is specified then it also checks if hash is actually computed.
    159   compiler::Node* LoadNameHash(compiler::Node* name,
    160                                Label* if_hash_not_computed = nullptr);
    161 
    162   // Load length field of a String object.
    163   compiler::Node* LoadStringLength(compiler::Node* object);
    164   // Load value field of a JSValue object.
    165   compiler::Node* LoadJSValueValue(compiler::Node* object);
    166   // Load value field of a WeakCell object.
    167   compiler::Node* LoadWeakCellValue(compiler::Node* weak_cell,
    168                                     Label* if_cleared = nullptr);
    169 
    170   compiler::Node* AllocateUninitializedFixedArray(compiler::Node* length);
    171 
    172   // Load an array element from a FixedArray.
    173   compiler::Node* LoadFixedArrayElement(
    174       compiler::Node* object, compiler::Node* int32_index,
    175       int additional_offset = 0,
    176       ParameterMode parameter_mode = INTEGER_PARAMETERS);
    177   // Load an array element from a FixedDoubleArray.
    178   compiler::Node* LoadFixedDoubleArrayElement(
    179       compiler::Node* object, compiler::Node* int32_index,
    180       MachineType machine_type, int additional_offset = 0,
    181       ParameterMode parameter_mode = INTEGER_PARAMETERS);
    182 
    183   // Context manipulation
    184   compiler::Node* LoadNativeContext(compiler::Node* context);
    185 
    186   compiler::Node* LoadJSArrayElementsMap(ElementsKind kind,
    187                                          compiler::Node* native_context);
    188 
    189   // Store the floating point value of a HeapNumber.
    190   compiler::Node* StoreHeapNumberValue(compiler::Node* object,
    191                                        compiler::Node* value);
    192   // Store a field to an object on the heap.
    193   compiler::Node* StoreObjectField(
    194       compiler::Node* object, int offset, compiler::Node* value);
    195   compiler::Node* StoreObjectFieldNoWriteBarrier(
    196       compiler::Node* object, int offset, compiler::Node* value,
    197       MachineRepresentation rep = MachineRepresentation::kTagged);
    198   // Store the Map of an HeapObject.
    199   compiler::Node* StoreMapNoWriteBarrier(compiler::Node* object,
    200                                          compiler::Node* map);
    201   // Store an array element to a FixedArray.
    202   compiler::Node* StoreFixedArrayElement(
    203       compiler::Node* object, compiler::Node* index, compiler::Node* value,
    204       WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
    205       ParameterMode parameter_mode = INTEGER_PARAMETERS);
    206 
    207   compiler::Node* StoreFixedDoubleArrayElement(
    208       compiler::Node* object, compiler::Node* index, compiler::Node* value,
    209       ParameterMode parameter_mode = INTEGER_PARAMETERS);
    210 
    211   // Allocate a HeapNumber without initializing its value.
    212   compiler::Node* AllocateHeapNumber();
    213   // Allocate a HeapNumber with a specific value.
    214   compiler::Node* AllocateHeapNumberWithValue(compiler::Node* value);
    215   // Allocate a SeqOneByteString with the given length.
    216   compiler::Node* AllocateSeqOneByteString(int length);
    217   compiler::Node* AllocateSeqOneByteString(compiler::Node* context,
    218                                            compiler::Node* length);
    219   // Allocate a SeqTwoByteString with the given length.
    220   compiler::Node* AllocateSeqTwoByteString(int length);
    221   compiler::Node* AllocateSeqTwoByteString(compiler::Node* context,
    222                                            compiler::Node* length);
    223   // Allocated an JSArray
    224   compiler::Node* AllocateJSArray(ElementsKind kind, compiler::Node* array_map,
    225                                   compiler::Node* capacity,
    226                                   compiler::Node* length,
    227                                   compiler::Node* allocation_site = nullptr,
    228                                   ParameterMode mode = INTEGER_PARAMETERS);
    229 
    230   // Allocation site manipulation
    231   void InitializeAllocationMemento(compiler::Node* base_allocation,
    232                                    int base_allocation_size,
    233                                    compiler::Node* allocation_site);
    234 
    235   compiler::Node* TruncateTaggedToFloat64(compiler::Node* context,
    236                                           compiler::Node* value);
    237   compiler::Node* TruncateTaggedToWord32(compiler::Node* context,
    238                                          compiler::Node* value);
    239   // Truncate the floating point value of a HeapNumber to an Int32.
    240   compiler::Node* TruncateHeapNumberValueToWord32(compiler::Node* object);
    241 
    242   // Conversions.
    243   compiler::Node* ChangeFloat64ToTagged(compiler::Node* value);
    244   compiler::Node* ChangeInt32ToTagged(compiler::Node* value);
    245   compiler::Node* ChangeUint32ToTagged(compiler::Node* value);
    246 
    247   // Type conversions.
    248   // Throws a TypeError for {method_name} if {value} is not coercible to Object,
    249   // or returns the {value} converted to a String otherwise.
    250   compiler::Node* ToThisString(compiler::Node* context, compiler::Node* value,
    251                                char const* method_name);
    252 
    253   // String helpers.
    254   // Load a character from a String (might flatten a ConsString).
    255   compiler::Node* StringCharCodeAt(compiler::Node* string,
    256                                    compiler::Node* smi_index);
    257   // Return the single character string with only {code}.
    258   compiler::Node* StringFromCharCode(compiler::Node* code);
    259 
    260   // Returns a node that is true if the given bit is set in |word32|.
    261   template <typename T>
    262   compiler::Node* BitFieldDecode(compiler::Node* word32) {
    263     return BitFieldDecode(word32, T::kShift, T::kMask);
    264   }
    265 
    266   compiler::Node* BitFieldDecode(compiler::Node* word32, uint32_t shift,
    267                                  uint32_t mask);
    268 
    269   void SetCounter(StatsCounter* counter, int value);
    270   void IncrementCounter(StatsCounter* counter, int delta);
    271   void DecrementCounter(StatsCounter* counter, int delta);
    272 
    273   // Various building blocks for stubs doing property lookups.
    274   void TryToName(compiler::Node* key, Label* if_keyisindex, Variable* var_index,
    275                  Label* if_keyisunique, Label* if_bailout);
    276 
    277   // Calculates array index for given dictionary entry and entry field.
    278   // See Dictionary::EntryToIndex().
    279   template <typename Dictionary>
    280   compiler::Node* EntryToIndex(compiler::Node* entry, int field_index);
    281   template <typename Dictionary>
    282   compiler::Node* EntryToIndex(compiler::Node* entry) {
    283     return EntryToIndex<Dictionary>(entry, Dictionary::kEntryKeyIndex);
    284   }
    285 
    286   // Looks up an entry in a NameDictionaryBase successor. If the entry is found
    287   // control goes to {if_found} and {var_name_index} contains an index of the
    288   // key field of the entry found. If the key is not found control goes to
    289   // {if_not_found}.
    290   static const int kInlinedDictionaryProbes = 4;
    291   template <typename Dictionary>
    292   void NameDictionaryLookup(compiler::Node* dictionary,
    293                             compiler::Node* unique_name, Label* if_found,
    294                             Variable* var_name_index, Label* if_not_found,
    295                             int inlined_probes = kInlinedDictionaryProbes);
    296 
    297   compiler::Node* ComputeIntegerHash(compiler::Node* key, compiler::Node* seed);
    298 
    299   template <typename Dictionary>
    300   void NumberDictionaryLookup(compiler::Node* dictionary, compiler::Node* key,
    301                               Label* if_found, Variable* var_entry,
    302                               Label* if_not_found);
    303 
    304   // Tries to check if {object} has own {unique_name} property.
    305   void TryHasOwnProperty(compiler::Node* object, compiler::Node* map,
    306                          compiler::Node* instance_type,
    307                          compiler::Node* unique_name, Label* if_found,
    308                          Label* if_not_found, Label* if_bailout);
    309 
    310   // Tries to get {object}'s own {unique_name} property value. If the property
    311   // is an accessor then it also calls a getter. If the property is a double
    312   // field it re-wraps value in an immutable heap number.
    313   void TryGetOwnProperty(compiler::Node* context, compiler::Node* receiver,
    314                          compiler::Node* object, compiler::Node* map,
    315                          compiler::Node* instance_type,
    316                          compiler::Node* unique_name, Label* if_found,
    317                          Variable* var_value, Label* if_not_found,
    318                          Label* if_bailout);
    319 
    320   void LoadPropertyFromFastObject(compiler::Node* object, compiler::Node* map,
    321                                   compiler::Node* descriptors,
    322                                   compiler::Node* name_index,
    323                                   Variable* var_details, Variable* var_value);
    324 
    325   void LoadPropertyFromNameDictionary(compiler::Node* dictionary,
    326                                       compiler::Node* entry,
    327                                       Variable* var_details,
    328                                       Variable* var_value);
    329 
    330   void LoadPropertyFromGlobalDictionary(compiler::Node* dictionary,
    331                                         compiler::Node* entry,
    332                                         Variable* var_details,
    333                                         Variable* var_value, Label* if_deleted);
    334 
    335   // Generic property lookup generator. If the {object} is fast and
    336   // {unique_name} property is found then the control goes to {if_found_fast}
    337   // label and {var_meta_storage} and {var_name_index} will contain
    338   // DescriptorArray and an index of the descriptor's name respectively.
    339   // If the {object} is slow or global then the control goes to {if_found_dict}
    340   // or {if_found_global} and the {var_meta_storage} and {var_name_index} will
    341   // contain a dictionary and an index of the key field of the found entry.
    342   // If property is not found or given lookup is not supported then
    343   // the control goes to {if_not_found} or {if_bailout} respectively.
    344   //
    345   // Note: this code does not check if the global dictionary points to deleted
    346   // entry! This has to be done by the caller.
    347   void TryLookupProperty(compiler::Node* object, compiler::Node* map,
    348                          compiler::Node* instance_type,
    349                          compiler::Node* unique_name, Label* if_found_fast,
    350                          Label* if_found_dict, Label* if_found_global,
    351                          Variable* var_meta_storage, Variable* var_name_index,
    352                          Label* if_not_found, Label* if_bailout);
    353 
    354   void TryLookupElement(compiler::Node* object, compiler::Node* map,
    355                         compiler::Node* instance_type, compiler::Node* index,
    356                         Label* if_found, Label* if_not_found,
    357                         Label* if_bailout);
    358 
    359   // Instanceof helpers.
    360   // ES6 section 7.3.19 OrdinaryHasInstance (C, O)
    361   compiler::Node* OrdinaryHasInstance(compiler::Node* context,
    362                                       compiler::Node* callable,
    363                                       compiler::Node* object);
    364 
    365   // LoadIC helpers.
    366   struct LoadICParameters {
    367     LoadICParameters(compiler::Node* context, compiler::Node* receiver,
    368                      compiler::Node* name, compiler::Node* slot,
    369                      compiler::Node* vector)
    370         : context(context),
    371           receiver(receiver),
    372           name(name),
    373           slot(slot),
    374           vector(vector) {}
    375 
    376     compiler::Node* context;
    377     compiler::Node* receiver;
    378     compiler::Node* name;
    379     compiler::Node* slot;
    380     compiler::Node* vector;
    381   };
    382 
    383   // Load type feedback vector from the stub caller's frame.
    384   compiler::Node* LoadTypeFeedbackVectorForStub();
    385 
    386   compiler::Node* LoadReceiverMap(compiler::Node* receiver);
    387 
    388   // Checks monomorphic case. Returns {feedback} entry of the vector.
    389   compiler::Node* TryMonomorphicCase(const LoadICParameters* p,
    390                                      compiler::Node* receiver_map,
    391                                      Label* if_handler, Variable* var_handler,
    392                                      Label* if_miss);
    393   void HandlePolymorphicCase(const LoadICParameters* p,
    394                              compiler::Node* receiver_map,
    395                              compiler::Node* feedback, Label* if_handler,
    396                              Variable* var_handler, Label* if_miss,
    397                              int unroll_count);
    398 
    399   compiler::Node* StubCachePrimaryOffset(compiler::Node* name,
    400                                          Code::Flags flags,
    401                                          compiler::Node* map);
    402 
    403   compiler::Node* StubCacheSecondaryOffset(compiler::Node* name,
    404                                            Code::Flags flags,
    405                                            compiler::Node* seed);
    406 
    407   // This enum is used here as a replacement for StubCache::Table to avoid
    408   // including stub cache header.
    409   enum StubCacheTable : int;
    410 
    411   void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
    412                               compiler::Node* entry_offset,
    413                               compiler::Node* name, Code::Flags flags,
    414                               compiler::Node* map, Label* if_handler,
    415                               Variable* var_handler, Label* if_miss);
    416 
    417   void TryProbeStubCache(StubCache* stub_cache, Code::Flags flags,
    418                          compiler::Node* receiver, compiler::Node* name,
    419                          Label* if_handler, Variable* var_handler,
    420                          Label* if_miss);
    421 
    422   void LoadIC(const LoadICParameters* p);
    423   void LoadGlobalIC(const LoadICParameters* p);
    424 
    425  private:
    426   compiler::Node* ElementOffsetFromIndex(compiler::Node* index,
    427                                          ElementsKind kind, ParameterMode mode,
    428                                          int base_size = 0);
    429 
    430   compiler::Node* AllocateRawAligned(compiler::Node* size_in_bytes,
    431                                      AllocationFlags flags,
    432                                      compiler::Node* top_address,
    433                                      compiler::Node* limit_address);
    434   compiler::Node* AllocateRawUnaligned(compiler::Node* size_in_bytes,
    435                                        AllocationFlags flags,
    436                                        compiler::Node* top_adddress,
    437                                        compiler::Node* limit_address);
    438 
    439   static const int kElementLoopUnrollThreshold = 8;
    440 };
    441 
    442 }  // namespace internal
    443 }  // namespace v8
    444 #endif  // V8_CODE_STUB_ASSEMBLER_H_
    445