code-stub-assembler.h 17 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_CODE_STUB_ASSEMBLER_H_
#define V8_CODE_STUB_ASSEMBLER_H_

#include "src/compiler/code-assembler.h"
#include "src/objects.h"

namespace v8 {
namespace internal {

class CallInterfaceDescriptor;
15 16
class StatsCounter;
class StubCache;
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

// Provides JavaScript-specific "macro-assembler" functionality on top of the
// CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler,
// it's possible to add JavaScript-specific useful CodeAssembler "macros"
// without modifying files in the compiler directory (and requiring a review
// from a compiler directory OWNER).
class CodeStubAssembler : public compiler::CodeAssembler {
 public:
  // Create with CallStub linkage.
  // |result_size| specifies the number of results returned by the stub.
  // TODO(rmcilroy): move result_size to the CallInterfaceDescriptor.
  CodeStubAssembler(Isolate* isolate, Zone* zone,
                    const CallInterfaceDescriptor& descriptor,
                    Code::Flags flags, const char* name,
                    size_t result_size = 1);

  // Create with JSCall linkage.
  CodeStubAssembler(Isolate* isolate, Zone* zone, int parameter_count,
                    Code::Flags flags, const char* name);

37 38
  enum ParameterMode { INTEGER_PARAMETERS, SMI_PARAMETERS };

39 40 41 42 43 44
  compiler::Node* BooleanMapConstant();
  compiler::Node* EmptyStringConstant();
  compiler::Node* HeapNumberMapConstant();
  compiler::Node* NoContextConstant();
  compiler::Node* NullConstant();
  compiler::Node* UndefinedConstant();
45 46
  compiler::Node* TheHoleConstant();
  compiler::Node* HashSeed();
47
  compiler::Node* StaleRegisterConstant();
48

49 50 51 52 53 54
  // Float64 operations.
  compiler::Node* Float64Ceil(compiler::Node* x);
  compiler::Node* Float64Floor(compiler::Node* x);
  compiler::Node* Float64Round(compiler::Node* x);
  compiler::Node* Float64Trunc(compiler::Node* x);

55 56 57 58 59
  // Tag a Word as a Smi value.
  compiler::Node* SmiTag(compiler::Node* value);
  // Untag a Smi value as a Word.
  compiler::Node* SmiUntag(compiler::Node* value);

60 61
  // Smi conversions.
  compiler::Node* SmiToFloat64(compiler::Node* value);
62
  compiler::Node* SmiFromWord(compiler::Node* value) { return SmiTag(value); }
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
  compiler::Node* SmiFromWord32(compiler::Node* value);
  compiler::Node* SmiToWord(compiler::Node* value) { return SmiUntag(value); }
  compiler::Node* SmiToWord32(compiler::Node* value);

  // Smi operations.
  compiler::Node* SmiAdd(compiler::Node* a, compiler::Node* b);
  compiler::Node* SmiAddWithOverflow(compiler::Node* a, compiler::Node* b);
  compiler::Node* SmiSub(compiler::Node* a, compiler::Node* b);
  compiler::Node* SmiSubWithOverflow(compiler::Node* a, compiler::Node* b);
  compiler::Node* SmiEqual(compiler::Node* a, compiler::Node* b);
  compiler::Node* SmiAboveOrEqual(compiler::Node* a, compiler::Node* b);
  compiler::Node* SmiLessThan(compiler::Node* a, compiler::Node* b);
  compiler::Node* SmiLessThanOrEqual(compiler::Node* a, compiler::Node* b);
  compiler::Node* SmiMin(compiler::Node* a, compiler::Node* b);

78
  // Allocate an object of the given size.
79
  compiler::Node* Allocate(compiler::Node* size, AllocationFlags flags = kNone);
80 81
  compiler::Node* Allocate(int size, AllocationFlags flags = kNone);
  compiler::Node* InnerAllocate(compiler::Node* previous, int offset);
82 83
  compiler::Node* InnerAllocate(compiler::Node* previous,
                                compiler::Node* offset);
84

85 86
  void Assert(compiler::Node* condition);

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
  // Check a value for smi-ness
  compiler::Node* WordIsSmi(compiler::Node* a);
  // Check that the value is a positive smi.
  compiler::Node* WordIsPositiveSmi(compiler::Node* a);

  void BranchIfSmiLessThan(compiler::Node* a, compiler::Node* b, Label* if_true,
                           Label* if_false) {
    BranchIf(SmiLessThan(a, b), if_true, if_false);
  }

  void BranchIfSmiLessThanOrEqual(compiler::Node* a, compiler::Node* b,
                                  Label* if_true, Label* if_false) {
    BranchIf(SmiLessThanOrEqual(a, b), if_true, if_false);
  }

  void BranchIfFloat64IsNaN(compiler::Node* value, Label* if_true,
                            Label* if_false) {
    BranchIfFloat64Equal(value, value, if_false, if_true);
  }

107 108 109 110 111 112 113
  // Load value from current frame by given offset in bytes.
  compiler::Node* LoadFromFrame(int offset,
                                MachineType rep = MachineType::AnyTagged());
  // Load value from current parent frame by given offset in bytes.
  compiler::Node* LoadFromParentFrame(
      int offset, MachineType rep = MachineType::AnyTagged());

114 115 116 117 118 119 120 121 122 123 124 125
  // Load an object pointer from a buffer that isn't in the heap.
  compiler::Node* LoadBufferObject(compiler::Node* buffer, int offset,
                                   MachineType rep = MachineType::AnyTagged());
  // Load a field from an object on the heap.
  compiler::Node* LoadObjectField(compiler::Node* object, int offset,
                                  MachineType rep = MachineType::AnyTagged());
  // Load the floating point value of a HeapNumber.
  compiler::Node* LoadHeapNumberValue(compiler::Node* object);
  // Load the Map of an HeapObject.
  compiler::Node* LoadMap(compiler::Node* object);
  // Load the instance type of an HeapObject.
  compiler::Node* LoadInstanceType(compiler::Node* object);
126 127
  // Checks that given heap object has given instance type.
  void AssertInstanceType(compiler::Node* object, InstanceType instance_type);
128 129
  // Load the properties backing store of a JSObject.
  compiler::Node* LoadProperties(compiler::Node* object);
130 131 132 133 134 135 136 137 138 139 140 141 142 143
  // Load the elements backing store of a JSObject.
  compiler::Node* LoadElements(compiler::Node* object);
  // Load the length of a fixed array base instance.
  compiler::Node* LoadFixedArrayBaseLength(compiler::Node* array);
  // Load the bit field of a Map.
  compiler::Node* LoadMapBitField(compiler::Node* map);
  // Load bit field 2 of a map.
  compiler::Node* LoadMapBitField2(compiler::Node* map);
  // Load bit field 3 of a map.
  compiler::Node* LoadMapBitField3(compiler::Node* map);
  // Load the instance type of a map.
  compiler::Node* LoadMapInstanceType(compiler::Node* map);
  // Load the instance descriptors of a map.
  compiler::Node* LoadMapDescriptors(compiler::Node* map);
144 145
  // Load the prototype of a map.
  compiler::Node* LoadMapPrototype(compiler::Node* map);
146 147
  // Load the instance size of a Map.
  compiler::Node* LoadMapInstanceSize(compiler::Node* map);
148

149 150 151 152 153 154 155 156 157 158 159
  // Load the hash field of a name.
  compiler::Node* LoadNameHashField(compiler::Node* name);
  // Load the hash value of a name. If {if_hash_not_computed} label
  // is specified then it also checks if hash is actually computed.
  compiler::Node* LoadNameHash(compiler::Node* name,
                               Label* if_hash_not_computed = nullptr);

  // Load length field of a String object.
  compiler::Node* LoadStringLength(compiler::Node* object);
  // Load value field of a JSValue object.
  compiler::Node* LoadJSValueValue(compiler::Node* object);
160
  // Load value field of a WeakCell object.
161 162
  compiler::Node* LoadWeakCellValue(compiler::Node* weak_cell,
                                    Label* if_cleared = nullptr);
163

164 165
  compiler::Node* AllocateUninitializedFixedArray(compiler::Node* length);

166
  // Load an array element from a FixedArray.
167 168 169 170
  compiler::Node* LoadFixedArrayElement(
      compiler::Node* object, compiler::Node* int32_index,
      int additional_offset = 0,
      ParameterMode parameter_mode = INTEGER_PARAMETERS);
171 172 173 174 175
  // Load an array element from a FixedDoubleArray.
  compiler::Node* LoadFixedDoubleArrayElement(
      compiler::Node* object, compiler::Node* int32_index,
      MachineType machine_type, int additional_offset = 0,
      ParameterMode parameter_mode = INTEGER_PARAMETERS);
176

177 178 179
  // Context manipulation
  compiler::Node* LoadNativeContext(compiler::Node* context);

180 181 182
  compiler::Node* LoadJSArrayElementsMap(ElementsKind kind,
                                         compiler::Node* native_context);

183 184 185 186
  // Store the floating point value of a HeapNumber.
  compiler::Node* StoreHeapNumberValue(compiler::Node* object,
                                       compiler::Node* value);
  // Store a field to an object on the heap.
187 188
  compiler::Node* StoreObjectField(
      compiler::Node* object, int offset, compiler::Node* value);
189 190 191 192 193 194 195
  compiler::Node* StoreObjectFieldNoWriteBarrier(
      compiler::Node* object, int offset, compiler::Node* value,
      MachineRepresentation rep = MachineRepresentation::kTagged);
  // Store the Map of an HeapObject.
  compiler::Node* StoreMapNoWriteBarrier(compiler::Node* object,
                                         compiler::Node* map);
  // Store an array element to a FixedArray.
196 197 198 199 200 201 202 203
  compiler::Node* StoreFixedArrayElement(
      compiler::Node* object, compiler::Node* index, compiler::Node* value,
      WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
      ParameterMode parameter_mode = INTEGER_PARAMETERS);

  compiler::Node* StoreFixedDoubleArrayElement(
      compiler::Node* object, compiler::Node* index, compiler::Node* value,
      ParameterMode parameter_mode = INTEGER_PARAMETERS);
204 205 206 207 208 209 210

  // Allocate a HeapNumber without initializing its value.
  compiler::Node* AllocateHeapNumber();
  // Allocate a HeapNumber with a specific value.
  compiler::Node* AllocateHeapNumberWithValue(compiler::Node* value);
  // Allocate a SeqOneByteString with the given length.
  compiler::Node* AllocateSeqOneByteString(int length);
211 212
  compiler::Node* AllocateSeqOneByteString(compiler::Node* context,
                                           compiler::Node* length);
213 214
  // Allocate a SeqTwoByteString with the given length.
  compiler::Node* AllocateSeqTwoByteString(int length);
215 216
  compiler::Node* AllocateSeqTwoByteString(compiler::Node* context,
                                           compiler::Node* length);
217
  // Allocated an JSArray
218
  compiler::Node* AllocateJSArray(ElementsKind kind, compiler::Node* array_map,
219 220 221 222
                                  compiler::Node* capacity,
                                  compiler::Node* length,
                                  compiler::Node* allocation_site = nullptr,
                                  ParameterMode mode = INTEGER_PARAMETERS);
223 224 225 226 227

  // Allocation site manipulation
  void InitializeAllocationMemento(compiler::Node* base_allocation,
                                   int base_allocation_size,
                                   compiler::Node* allocation_site);
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261

  compiler::Node* TruncateTaggedToFloat64(compiler::Node* context,
                                          compiler::Node* value);
  compiler::Node* TruncateTaggedToWord32(compiler::Node* context,
                                         compiler::Node* value);
  // Truncate the floating point value of a HeapNumber to an Int32.
  compiler::Node* TruncateHeapNumberValueToWord32(compiler::Node* object);

  // Conversions.
  compiler::Node* ChangeFloat64ToTagged(compiler::Node* value);
  compiler::Node* ChangeInt32ToTagged(compiler::Node* value);
  compiler::Node* ChangeUint32ToTagged(compiler::Node* value);

  // Type conversions.
  // Throws a TypeError for {method_name} if {value} is not coercible to Object,
  // or returns the {value} converted to a String otherwise.
  compiler::Node* ToThisString(compiler::Node* context, compiler::Node* value,
                               char const* method_name);

  // String helpers.
  // Load a character from a String (might flatten a ConsString).
  compiler::Node* StringCharCodeAt(compiler::Node* string,
                                   compiler::Node* smi_index);
  // Return the single character string with only {code}.
  compiler::Node* StringFromCharCode(compiler::Node* code);

  // Returns a node that is true if the given bit is set in |word32|.
  template <typename T>
  compiler::Node* BitFieldDecode(compiler::Node* word32) {
    return BitFieldDecode(word32, T::kShift, T::kMask);
  }

  compiler::Node* BitFieldDecode(compiler::Node* word32, uint32_t shift,
                                 uint32_t mask);
262

263 264 265 266
  void SetCounter(StatsCounter* counter, int value);
  void IncrementCounter(StatsCounter* counter, int delta);
  void DecrementCounter(StatsCounter* counter, int delta);

267 268
  // Various building blocks for stubs doing property lookups.
  void TryToName(compiler::Node* key, Label* if_keyisindex, Variable* var_index,
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
                 Label* if_keyisunique, Label* if_bailout);

  static const int kInlinedDictionaryProbes = 4;
  template <typename Dictionary>
  void NameDictionaryLookup(compiler::Node* dictionary,
                            compiler::Node* unique_name, Label* if_found,
                            Variable* var_entry, Label* if_not_found,
                            int inlined_probes = kInlinedDictionaryProbes);

  compiler::Node* ComputeIntegerHash(compiler::Node* key, compiler::Node* seed);

  template <typename Dictionary>
  void NumberDictionaryLookup(compiler::Node* dictionary, compiler::Node* key,
                              Label* if_found, Variable* var_entry,
                              Label* if_not_found);
284 285

  void TryLookupProperty(compiler::Node* object, compiler::Node* map,
286 287 288
                         compiler::Node* instance_type,
                         compiler::Node* unique_name, Label* if_found,
                         Label* if_not_found, Label* if_bailout);
289 290 291 292

  void TryLookupElement(compiler::Node* object, compiler::Node* map,
                        compiler::Node* instance_type, compiler::Node* index,
                        Label* if_found, Label* if_not_found,
293
                        Label* if_bailout);
294

295 296 297 298 299 300
  // Instanceof helpers.
  // ES6 section 7.3.19 OrdinaryHasInstance (C, O)
  compiler::Node* OrdinaryHasInstance(compiler::Node* context,
                                      compiler::Node* callable,
                                      compiler::Node* object);

301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
  // LoadIC helpers.
  struct LoadICParameters {
    LoadICParameters(compiler::Node* context, compiler::Node* receiver,
                     compiler::Node* name, compiler::Node* slot,
                     compiler::Node* vector)
        : context(context),
          receiver(receiver),
          name(name),
          slot(slot),
          vector(vector) {}

    compiler::Node* context;
    compiler::Node* receiver;
    compiler::Node* name;
    compiler::Node* slot;
    compiler::Node* vector;
  };

  // Load type feedback vector from the stub caller's frame.
  compiler::Node* LoadTypeFeedbackVectorForStub();

  compiler::Node* LoadReceiverMap(compiler::Node* receiver);

  // Checks monomorphic case. Returns {feedback} entry of the vector.
  compiler::Node* TryMonomorphicCase(const LoadICParameters* p,
                                     compiler::Node* receiver_map,
                                     Label* if_handler, Variable* var_handler,
                                     Label* if_miss);
  void HandlePolymorphicCase(const LoadICParameters* p,
                             compiler::Node* receiver_map,
                             compiler::Node* feedback, Label* if_handler,
                             Variable* var_handler, Label* if_miss,
                             int unroll_count);

  compiler::Node* StubCachePrimaryOffset(compiler::Node* name,
                                         Code::Flags flags,
                                         compiler::Node* map);

  compiler::Node* StubCacheSecondaryOffset(compiler::Node* name,
                                           Code::Flags flags,
                                           compiler::Node* seed);

  // This enum is used here as a replacement for StubCache::Table to avoid
  // including stub cache header.
  enum StubCacheTable : int;

  void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
                              compiler::Node* entry_offset,
                              compiler::Node* name, Code::Flags flags,
                              compiler::Node* map, Label* if_handler,
                              Variable* var_handler, Label* if_miss);

  void TryProbeStubCache(StubCache* stub_cache, Code::Flags flags,
                         compiler::Node* receiver, compiler::Node* name,
                         Label* if_handler, Variable* var_handler,
                         Label* if_miss);

358 359
  void LoadIC(const LoadICParameters* p);
  void LoadGlobalIC(const LoadICParameters* p);
360

361
 private:
362 363 364 365
  compiler::Node* ElementOffsetFromIndex(compiler::Node* index,
                                         ElementsKind kind, ParameterMode mode,
                                         int base_size = 0);

366 367 368 369 370 371 372 373
  compiler::Node* AllocateRawAligned(compiler::Node* size_in_bytes,
                                     AllocationFlags flags,
                                     compiler::Node* top_address,
                                     compiler::Node* limit_address);
  compiler::Node* AllocateRawUnaligned(compiler::Node* size_in_bytes,
                                       AllocationFlags flags,
                                       compiler::Node* top_adddress,
                                       compiler::Node* limit_address);
374 375

  static const int kElementLoopUnrollThreshold = 8;
376 377 378 379 380
};

}  // namespace internal
}  // namespace v8
#endif  // V8_CODE_STUB_ASSEMBLER_H_