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 <functional> 9 10 #include "src/compiler/code-assembler.h" 11 #include "src/globals.h" 12 #include "src/objects.h" 13 14 namespace v8 { 15 namespace internal { 16 17 class CallInterfaceDescriptor; 18 class StatsCounter; 19 class StubCache; 20 21 enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol }; 22 23 #define HEAP_CONSTANT_LIST(V) \ 24 V(BooleanMap, BooleanMap) \ 25 V(CodeMap, CodeMap) \ 26 V(empty_string, EmptyString) \ 27 V(EmptyFixedArray, EmptyFixedArray) \ 28 V(FalseValue, False) \ 29 V(FixedArrayMap, FixedArrayMap) \ 30 V(FixedCOWArrayMap, FixedCOWArrayMap) \ 31 V(FixedDoubleArrayMap, FixedDoubleArrayMap) \ 32 V(HeapNumberMap, HeapNumberMap) \ 33 V(MinusZeroValue, MinusZero) \ 34 V(NanValue, Nan) \ 35 V(NullValue, Null) \ 36 V(TheHoleValue, TheHole) \ 37 V(TrueValue, True) \ 38 V(UndefinedValue, Undefined) 39 40 // Provides JavaScript-specific "macro-assembler" functionality on top of the 41 // CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler, 42 // it's possible to add JavaScript-specific useful CodeAssembler "macros" 43 // without modifying files in the compiler directory (and requiring a review 44 // from a compiler directory OWNER). 45 class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { 46 public: 47 // Create with CallStub linkage. 48 // |result_size| specifies the number of results returned by the stub. 49 // TODO(rmcilroy): move result_size to the CallInterfaceDescriptor. 50 CodeStubAssembler(Isolate* isolate, Zone* zone, 51 const CallInterfaceDescriptor& descriptor, 52 Code::Flags flags, const char* name, 53 size_t result_size = 1); 54 55 // Create with JSCall linkage. 56 CodeStubAssembler(Isolate* isolate, Zone* zone, int parameter_count, 57 Code::Flags flags, const char* name); 58 59 enum AllocationFlag : uint8_t { 60 kNone = 0, 61 kDoubleAlignment = 1, 62 kPretenured = 1 << 1 63 }; 64 65 typedef base::Flags<AllocationFlag> AllocationFlags; 66 67 // TODO(ishell): Fix all loads/stores from arrays by int32 offsets/indices 68 // and eventually remove INTEGER_PARAMETERS in favour of INTPTR_PARAMETERS. 69 enum ParameterMode { INTEGER_PARAMETERS, SMI_PARAMETERS, INTPTR_PARAMETERS }; 70 71 // On 32-bit platforms, there is a slight performance advantage to doing all 72 // of the array offset/index arithmetic with SMIs, since it's possible 73 // to save a few tag/untag operations without paying an extra expense when 74 // calculating array offset (the smi math can be folded away) and there are 75 // fewer live ranges. Thus only convert indices to untagged value on 64-bit 76 // platforms. OptimalParameterMode()77 ParameterMode OptimalParameterMode() const { 78 return Is64() ? INTPTR_PARAMETERS : SMI_PARAMETERS; 79 } 80 UntagParameter(compiler::Node * value,ParameterMode mode)81 compiler::Node* UntagParameter(compiler::Node* value, ParameterMode mode) { 82 if (mode != SMI_PARAMETERS) value = SmiUntag(value); 83 return value; 84 } 85 TagParameter(compiler::Node * value,ParameterMode mode)86 compiler::Node* TagParameter(compiler::Node* value, ParameterMode mode) { 87 if (mode != SMI_PARAMETERS) value = SmiTag(value); 88 return value; 89 } 90 91 compiler::Node* NoContextConstant(); 92 #define HEAP_CONSTANT_ACCESSOR(rootName, name) compiler::Node* name##Constant(); 93 HEAP_CONSTANT_LIST(HEAP_CONSTANT_ACCESSOR) 94 #undef HEAP_CONSTANT_ACCESSOR 95 96 #define HEAP_CONSTANT_TEST(rootName, name) \ 97 compiler::Node* Is##name(compiler::Node* value); 98 HEAP_CONSTANT_LIST(HEAP_CONSTANT_TEST) 99 #undef HEAP_CONSTANT_TEST 100 101 compiler::Node* HashSeed(); 102 compiler::Node* StaleRegisterConstant(); 103 104 compiler::Node* IntPtrOrSmiConstant(int value, ParameterMode mode); 105 106 compiler::Node* IntPtrAddFoldConstants(compiler::Node* left, 107 compiler::Node* right); 108 compiler::Node* IntPtrSubFoldConstants(compiler::Node* left, 109 compiler::Node* right); 110 // Round the 32bits payload of the provided word up to the next power of two. 111 compiler::Node* IntPtrRoundUpToPowerOfTwo32(compiler::Node* value); 112 compiler::Node* IntPtrMax(compiler::Node* left, compiler::Node* right); 113 114 // Float64 operations. 115 compiler::Node* Float64Ceil(compiler::Node* x); 116 compiler::Node* Float64Floor(compiler::Node* x); 117 compiler::Node* Float64Round(compiler::Node* x); 118 compiler::Node* Float64RoundToEven(compiler::Node* x); 119 compiler::Node* Float64Trunc(compiler::Node* x); 120 121 // Tag a Word as a Smi value. 122 compiler::Node* SmiTag(compiler::Node* value); 123 // Untag a Smi value as a Word. 124 compiler::Node* SmiUntag(compiler::Node* value); 125 126 // Smi conversions. 127 compiler::Node* SmiToFloat64(compiler::Node* value); SmiFromWord(compiler::Node * value)128 compiler::Node* SmiFromWord(compiler::Node* value) { return SmiTag(value); } 129 compiler::Node* SmiFromWord32(compiler::Node* value); SmiToWord(compiler::Node * value)130 compiler::Node* SmiToWord(compiler::Node* value) { return SmiUntag(value); } 131 compiler::Node* SmiToWord32(compiler::Node* value); 132 133 // Smi operations. 134 compiler::Node* SmiAdd(compiler::Node* a, compiler::Node* b); 135 compiler::Node* SmiSub(compiler::Node* a, compiler::Node* b); 136 compiler::Node* SmiEqual(compiler::Node* a, compiler::Node* b); 137 compiler::Node* SmiAbove(compiler::Node* a, compiler::Node* b); 138 compiler::Node* SmiAboveOrEqual(compiler::Node* a, compiler::Node* b); 139 compiler::Node* SmiBelow(compiler::Node* a, compiler::Node* b); 140 compiler::Node* SmiLessThan(compiler::Node* a, compiler::Node* b); 141 compiler::Node* SmiLessThanOrEqual(compiler::Node* a, compiler::Node* b); 142 compiler::Node* SmiMax(compiler::Node* a, compiler::Node* b); 143 compiler::Node* SmiMin(compiler::Node* a, compiler::Node* b); 144 // Computes a % b for Smi inputs a and b; result is not necessarily a Smi. 145 compiler::Node* SmiMod(compiler::Node* a, compiler::Node* b); 146 // Computes a * b for Smi inputs a and b; result is not necessarily a Smi. 147 compiler::Node* SmiMul(compiler::Node* a, compiler::Node* b); SmiOr(compiler::Node * a,compiler::Node * b)148 compiler::Node* SmiOr(compiler::Node* a, compiler::Node* b) { 149 return BitcastWordToTaggedSigned( 150 WordOr(BitcastTaggedToWord(a), BitcastTaggedToWord(b))); 151 } 152 153 // Smi | HeapNumber operations. 154 compiler::Node* NumberInc(compiler::Node* value); 155 156 // Allocate an object of the given size. 157 compiler::Node* Allocate(compiler::Node* size, AllocationFlags flags = kNone); 158 compiler::Node* Allocate(int size, AllocationFlags flags = kNone); 159 compiler::Node* InnerAllocate(compiler::Node* previous, int offset); 160 compiler::Node* InnerAllocate(compiler::Node* previous, 161 compiler::Node* offset); 162 compiler::Node* IsRegularHeapObjectSize(compiler::Node* size); 163 164 typedef std::function<compiler::Node*()> ConditionBody; 165 void Assert(ConditionBody condition_body, const char* string = nullptr, 166 const char* file = nullptr, int line = 0); 167 168 // Check a value for smi-ness 169 compiler::Node* TaggedIsSmi(compiler::Node* a); 170 // Check that the value is a non-negative smi. 171 compiler::Node* WordIsPositiveSmi(compiler::Node* a); 172 // Check that a word has a word-aligned address. 173 compiler::Node* WordIsWordAligned(compiler::Node* word); 174 compiler::Node* WordIsPowerOfTwo(compiler::Node* value); 175 BranchIfSmiEqual(compiler::Node * a,compiler::Node * b,Label * if_true,Label * if_false)176 void BranchIfSmiEqual(compiler::Node* a, compiler::Node* b, Label* if_true, 177 Label* if_false) { 178 Branch(SmiEqual(a, b), if_true, if_false); 179 } 180 BranchIfSmiLessThan(compiler::Node * a,compiler::Node * b,Label * if_true,Label * if_false)181 void BranchIfSmiLessThan(compiler::Node* a, compiler::Node* b, Label* if_true, 182 Label* if_false) { 183 Branch(SmiLessThan(a, b), if_true, if_false); 184 } 185 BranchIfSmiLessThanOrEqual(compiler::Node * a,compiler::Node * b,Label * if_true,Label * if_false)186 void BranchIfSmiLessThanOrEqual(compiler::Node* a, compiler::Node* b, 187 Label* if_true, Label* if_false) { 188 Branch(SmiLessThanOrEqual(a, b), if_true, if_false); 189 } 190 BranchIfFloat64IsNaN(compiler::Node * value,Label * if_true,Label * if_false)191 void BranchIfFloat64IsNaN(compiler::Node* value, Label* if_true, 192 Label* if_false) { 193 Branch(Float64Equal(value, value), if_false, if_true); 194 } 195 196 // Branches to {if_true} if ToBoolean applied to {value} yields true, 197 // otherwise goes to {if_false}. 198 void BranchIfToBooleanIsTrue(compiler::Node* value, Label* if_true, 199 Label* if_false); 200 201 void BranchIfSimd128Equal(compiler::Node* lhs, compiler::Node* lhs_map, 202 compiler::Node* rhs, compiler::Node* rhs_map, 203 Label* if_equal, Label* if_notequal); BranchIfSimd128Equal(compiler::Node * lhs,compiler::Node * rhs,Label * if_equal,Label * if_notequal)204 void BranchIfSimd128Equal(compiler::Node* lhs, compiler::Node* rhs, 205 Label* if_equal, Label* if_notequal) { 206 BranchIfSimd128Equal(lhs, LoadMap(lhs), rhs, LoadMap(rhs), if_equal, 207 if_notequal); 208 } 209 210 void BranchIfJSReceiver(compiler::Node* object, Label* if_true, 211 Label* if_false); 212 void BranchIfJSObject(compiler::Node* object, Label* if_true, 213 Label* if_false); 214 void BranchIfFastJSArray(compiler::Node* object, compiler::Node* context, 215 Label* if_true, Label* if_false); 216 217 // Load value from current frame by given offset in bytes. 218 compiler::Node* LoadFromFrame(int offset, 219 MachineType rep = MachineType::AnyTagged()); 220 // Load value from current parent frame by given offset in bytes. 221 compiler::Node* LoadFromParentFrame( 222 int offset, MachineType rep = MachineType::AnyTagged()); 223 224 // Load an object pointer from a buffer that isn't in the heap. 225 compiler::Node* LoadBufferObject(compiler::Node* buffer, int offset, 226 MachineType rep = MachineType::AnyTagged()); 227 // Load a field from an object on the heap. 228 compiler::Node* LoadObjectField(compiler::Node* object, int offset, 229 MachineType rep = MachineType::AnyTagged()); 230 compiler::Node* LoadObjectField(compiler::Node* object, 231 compiler::Node* offset, 232 MachineType rep = MachineType::AnyTagged()); 233 // Load a SMI field and untag it. 234 compiler::Node* LoadAndUntagObjectField(compiler::Node* object, int offset); 235 // Load a SMI field, untag it, and convert to Word32. 236 compiler::Node* LoadAndUntagToWord32ObjectField(compiler::Node* object, 237 int offset); 238 // Load a SMI and untag it. 239 compiler::Node* LoadAndUntagSmi(compiler::Node* base, int index); 240 // Load a SMI root, untag it, and convert to Word32. 241 compiler::Node* LoadAndUntagToWord32Root(Heap::RootListIndex root_index); 242 243 // Load the floating point value of a HeapNumber. 244 compiler::Node* LoadHeapNumberValue(compiler::Node* object); 245 // Load the Map of an HeapObject. 246 compiler::Node* LoadMap(compiler::Node* object); 247 // Load the instance type of an HeapObject. 248 compiler::Node* LoadInstanceType(compiler::Node* object); 249 // Compare the instance the type of the object against the provided one. 250 compiler::Node* HasInstanceType(compiler::Node* object, InstanceType type); 251 // Load the properties backing store of a JSObject. 252 compiler::Node* LoadProperties(compiler::Node* object); 253 // Load the elements backing store of a JSObject. 254 compiler::Node* LoadElements(compiler::Node* object); 255 // Load the length of a JSArray instance. 256 compiler::Node* LoadJSArrayLength(compiler::Node* array); 257 // Load the length of a fixed array base instance. 258 compiler::Node* LoadFixedArrayBaseLength(compiler::Node* array); 259 // Load the length of a fixed array base instance. 260 compiler::Node* LoadAndUntagFixedArrayBaseLength(compiler::Node* array); 261 // Load the bit field of a Map. 262 compiler::Node* LoadMapBitField(compiler::Node* map); 263 // Load bit field 2 of a map. 264 compiler::Node* LoadMapBitField2(compiler::Node* map); 265 // Load bit field 3 of a map. 266 compiler::Node* LoadMapBitField3(compiler::Node* map); 267 // Load the instance type of a map. 268 compiler::Node* LoadMapInstanceType(compiler::Node* map); 269 // Load the ElementsKind of a map. 270 compiler::Node* LoadMapElementsKind(compiler::Node* map); 271 // Load the instance descriptors of a map. 272 compiler::Node* LoadMapDescriptors(compiler::Node* map); 273 // Load the prototype of a map. 274 compiler::Node* LoadMapPrototype(compiler::Node* map); 275 // Load the prototype info of a map. The result has to be checked if it is a 276 // prototype info object or not. 277 compiler::Node* LoadMapPrototypeInfo(compiler::Node* map, 278 Label* if_has_no_proto_info); 279 // Load the instance size of a Map. 280 compiler::Node* LoadMapInstanceSize(compiler::Node* map); 281 // Load the inobject properties count of a Map (valid only for JSObjects). 282 compiler::Node* LoadMapInobjectProperties(compiler::Node* map); 283 // Load the constructor function index of a Map (only for primitive maps). 284 compiler::Node* LoadMapConstructorFunctionIndex(compiler::Node* map); 285 // Load the constructor of a Map (equivalent to Map::GetConstructor()). 286 compiler::Node* LoadMapConstructor(compiler::Node* map); 287 // Check if the map is set for slow properties. 288 compiler::Node* IsDictionaryMap(compiler::Node* map); 289 290 // Load the hash field of a name as an uint32 value. 291 compiler::Node* LoadNameHashField(compiler::Node* name); 292 // Load the hash value of a name as an uint32 value. 293 // If {if_hash_not_computed} label is specified then it also checks if 294 // hash is actually computed. 295 compiler::Node* LoadNameHash(compiler::Node* name, 296 Label* if_hash_not_computed = nullptr); 297 298 // Load length field of a String object. 299 compiler::Node* LoadStringLength(compiler::Node* object); 300 // Load value field of a JSValue object. 301 compiler::Node* LoadJSValueValue(compiler::Node* object); 302 // Load value field of a WeakCell object. 303 compiler::Node* LoadWeakCellValueUnchecked(compiler::Node* weak_cell); 304 compiler::Node* LoadWeakCellValue(compiler::Node* weak_cell, 305 Label* if_cleared = nullptr); 306 307 // Load an array element from a FixedArray. 308 compiler::Node* LoadFixedArrayElement( 309 compiler::Node* object, compiler::Node* index, int additional_offset = 0, 310 ParameterMode parameter_mode = INTEGER_PARAMETERS); 311 // Load an array element from a FixedArray, untag it and return it as Word32. 312 compiler::Node* LoadAndUntagToWord32FixedArrayElement( 313 compiler::Node* object, compiler::Node* index, int additional_offset = 0, 314 ParameterMode parameter_mode = INTEGER_PARAMETERS); 315 // Load an array element from a FixedDoubleArray. 316 compiler::Node* LoadFixedDoubleArrayElement( 317 compiler::Node* object, compiler::Node* index, MachineType machine_type, 318 int additional_offset = 0, 319 ParameterMode parameter_mode = INTEGER_PARAMETERS, 320 Label* if_hole = nullptr); 321 322 // Load Float64 value by |base| + |offset| address. If the value is a double 323 // hole then jump to |if_hole|. If |machine_type| is None then only the hole 324 // check is generated. 325 compiler::Node* LoadDoubleWithHoleCheck( 326 compiler::Node* base, compiler::Node* offset, Label* if_hole, 327 MachineType machine_type = MachineType::Float64()); 328 compiler::Node* LoadFixedTypedArrayElement( 329 compiler::Node* data_pointer, compiler::Node* index_node, 330 ElementsKind elements_kind, 331 ParameterMode parameter_mode = INTEGER_PARAMETERS); 332 333 // Context manipulation 334 compiler::Node* LoadContextElement(compiler::Node* context, int slot_index); 335 compiler::Node* LoadContextElement(compiler::Node* context, 336 compiler::Node* slot_index); 337 compiler::Node* StoreContextElement(compiler::Node* context, int slot_index, 338 compiler::Node* value); 339 compiler::Node* StoreContextElement(compiler::Node* context, 340 compiler::Node* slot_index, 341 compiler::Node* value); 342 compiler::Node* LoadNativeContext(compiler::Node* context); 343 344 compiler::Node* LoadJSArrayElementsMap(ElementsKind kind, 345 compiler::Node* native_context); 346 347 // Store the floating point value of a HeapNumber. 348 compiler::Node* StoreHeapNumberValue(compiler::Node* object, 349 compiler::Node* value); 350 // Store a field to an object on the heap. 351 compiler::Node* StoreObjectField( 352 compiler::Node* object, int offset, compiler::Node* value); 353 compiler::Node* StoreObjectField(compiler::Node* object, 354 compiler::Node* offset, 355 compiler::Node* value); 356 compiler::Node* StoreObjectFieldNoWriteBarrier( 357 compiler::Node* object, int offset, compiler::Node* value, 358 MachineRepresentation rep = MachineRepresentation::kTagged); 359 compiler::Node* StoreObjectFieldNoWriteBarrier( 360 compiler::Node* object, compiler::Node* offset, compiler::Node* value, 361 MachineRepresentation rep = MachineRepresentation::kTagged); 362 // Store the Map of an HeapObject. 363 compiler::Node* StoreMapNoWriteBarrier(compiler::Node* object, 364 compiler::Node* map); 365 compiler::Node* StoreObjectFieldRoot(compiler::Node* object, int offset, 366 Heap::RootListIndex root); 367 // Store an array element to a FixedArray. 368 compiler::Node* StoreFixedArrayElement( 369 compiler::Node* object, int index, compiler::Node* value, 370 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, 371 ParameterMode parameter_mode = INTEGER_PARAMETERS) { 372 return StoreFixedArrayElement(object, Int32Constant(index), value, 373 barrier_mode, parameter_mode); 374 } 375 376 compiler::Node* StoreFixedArrayElement( 377 compiler::Node* object, compiler::Node* index, compiler::Node* value, 378 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, 379 ParameterMode parameter_mode = INTEGER_PARAMETERS); 380 381 compiler::Node* StoreFixedDoubleArrayElement( 382 compiler::Node* object, compiler::Node* index, compiler::Node* value, 383 ParameterMode parameter_mode = INTEGER_PARAMETERS); 384 385 void StoreFieldsNoWriteBarrier(compiler::Node* start_address, 386 compiler::Node* end_address, 387 compiler::Node* value); 388 389 // Allocate a HeapNumber without initializing its value. 390 compiler::Node* AllocateHeapNumber(MutableMode mode = IMMUTABLE); 391 // Allocate a HeapNumber with a specific value. 392 compiler::Node* AllocateHeapNumberWithValue(compiler::Node* value, 393 MutableMode mode = IMMUTABLE); 394 // Allocate a SeqOneByteString with the given length. 395 compiler::Node* AllocateSeqOneByteString(int length, 396 AllocationFlags flags = kNone); 397 compiler::Node* AllocateSeqOneByteString( 398 compiler::Node* context, compiler::Node* length, 399 ParameterMode mode = INTPTR_PARAMETERS, AllocationFlags flags = kNone); 400 // Allocate a SeqTwoByteString with the given length. 401 compiler::Node* AllocateSeqTwoByteString(int length, 402 AllocationFlags flags = kNone); 403 compiler::Node* AllocateSeqTwoByteString( 404 compiler::Node* context, compiler::Node* length, 405 ParameterMode mode = INTPTR_PARAMETERS, AllocationFlags flags = kNone); 406 407 // Allocate a SlicedOneByteString with the given length, parent and offset. 408 // |length| and |offset| are expected to be tagged. 409 compiler::Node* AllocateSlicedOneByteString(compiler::Node* length, 410 compiler::Node* parent, 411 compiler::Node* offset); 412 // Allocate a SlicedTwoByteString with the given length, parent and offset. 413 // |length| and |offset| are expected to be tagged. 414 compiler::Node* AllocateSlicedTwoByteString(compiler::Node* length, 415 compiler::Node* parent, 416 compiler::Node* offset); 417 418 // Allocate a one-byte ConsString with the given length, first and second 419 // parts. |length| is expected to be tagged, and |first| and |second| are 420 // expected to be one-byte strings. 421 compiler::Node* AllocateOneByteConsString(compiler::Node* length, 422 compiler::Node* first, 423 compiler::Node* second, 424 AllocationFlags flags = kNone); 425 // Allocate a two-byte ConsString with the given length, first and second 426 // parts. |length| is expected to be tagged, and |first| and |second| are 427 // expected to be two-byte strings. 428 compiler::Node* AllocateTwoByteConsString(compiler::Node* length, 429 compiler::Node* first, 430 compiler::Node* second, 431 AllocationFlags flags = kNone); 432 433 // Allocate an appropriate one- or two-byte ConsString with the first and 434 // second parts specified by |first| and |second|. 435 compiler::Node* NewConsString(compiler::Node* context, compiler::Node* length, 436 compiler::Node* left, compiler::Node* right, 437 AllocationFlags flags = kNone); 438 439 // Allocate a RegExpResult with the given length (the number of captures, 440 // including the match itself), index (the index where the match starts), 441 // and input string. |length| and |index| are expected to be tagged, and 442 // |input| must be a string. 443 compiler::Node* AllocateRegExpResult(compiler::Node* context, 444 compiler::Node* length, 445 compiler::Node* index, 446 compiler::Node* input); 447 448 compiler::Node* AllocateNameDictionary(int capacity); 449 compiler::Node* AllocateNameDictionary(compiler::Node* capacity); 450 451 compiler::Node* AllocateJSObjectFromMap(compiler::Node* map, 452 compiler::Node* properties = nullptr, 453 compiler::Node* elements = nullptr); 454 455 void InitializeJSObjectFromMap(compiler::Node* object, compiler::Node* map, 456 compiler::Node* size, 457 compiler::Node* properties = nullptr, 458 compiler::Node* elements = nullptr); 459 460 void InitializeJSObjectBody(compiler::Node* object, compiler::Node* map, 461 compiler::Node* size, 462 int start_offset = JSObject::kHeaderSize); 463 464 // Allocate a JSArray without elements and initialize the header fields. 465 compiler::Node* AllocateUninitializedJSArrayWithoutElements( 466 ElementsKind kind, compiler::Node* array_map, compiler::Node* length, 467 compiler::Node* allocation_site); 468 // Allocate and return a JSArray with initialized header fields and its 469 // uninitialized elements. 470 // The ParameterMode argument is only used for the capacity parameter. 471 std::pair<compiler::Node*, compiler::Node*> 472 AllocateUninitializedJSArrayWithElements( 473 ElementsKind kind, compiler::Node* array_map, compiler::Node* length, 474 compiler::Node* allocation_site, compiler::Node* capacity, 475 ParameterMode capacity_mode = INTEGER_PARAMETERS); 476 // Allocate a JSArray and fill elements with the hole. 477 // The ParameterMode argument is only used for the capacity parameter. 478 compiler::Node* AllocateJSArray( 479 ElementsKind kind, compiler::Node* array_map, compiler::Node* capacity, 480 compiler::Node* length, compiler::Node* allocation_site = nullptr, 481 ParameterMode capacity_mode = INTEGER_PARAMETERS); 482 483 compiler::Node* AllocateFixedArray(ElementsKind kind, 484 compiler::Node* capacity, 485 ParameterMode mode = INTEGER_PARAMETERS, 486 AllocationFlags flags = kNone); 487 488 // Perform CreateArrayIterator (ES6 #sec-createarrayiterator). 489 compiler::Node* CreateArrayIterator(compiler::Node* array, 490 compiler::Node* array_map, 491 compiler::Node* array_type, 492 compiler::Node* context, 493 IterationKind mode); 494 495 compiler::Node* AllocateJSArrayIterator(compiler::Node* array, 496 compiler::Node* array_map, 497 compiler::Node* map); 498 499 void FillFixedArrayWithValue(ElementsKind kind, compiler::Node* array, 500 compiler::Node* from_index, 501 compiler::Node* to_index, 502 Heap::RootListIndex value_root_index, 503 ParameterMode mode = INTEGER_PARAMETERS); 504 505 // Copies all elements from |from_array| of |length| size to 506 // |to_array| of the same size respecting the elements kind. 507 void CopyFixedArrayElements( 508 ElementsKind kind, compiler::Node* from_array, compiler::Node* to_array, 509 compiler::Node* length, 510 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, 511 ParameterMode mode = INTEGER_PARAMETERS) { 512 CopyFixedArrayElements(kind, from_array, kind, to_array, length, length, 513 barrier_mode, mode); 514 } 515 516 // Copies |element_count| elements from |from_array| to |to_array| of 517 // |capacity| size respecting both array's elements kinds. 518 void CopyFixedArrayElements( 519 ElementsKind from_kind, compiler::Node* from_array, ElementsKind to_kind, 520 compiler::Node* to_array, compiler::Node* element_count, 521 compiler::Node* capacity, 522 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, 523 ParameterMode mode = INTEGER_PARAMETERS); 524 525 // Copies |character_count| elements from |from_string| to |to_string| 526 // starting at the |from_index|'th character. |from_string| and |to_string| 527 // can either be one-byte strings or two-byte strings, although if 528 // |from_string| is two-byte, then |to_string| must be two-byte. 529 // |from_index|, |to_index| and |character_count| must be either Smis or 530 // intptr_ts depending on |mode| s.t. 0 <= |from_index| <= |from_index| + 531 // |character_count| <= from_string.length and 0 <= |to_index| <= |to_index| + 532 // |character_count| <= to_string.length. 533 void CopyStringCharacters(compiler::Node* from_string, 534 compiler::Node* to_string, 535 compiler::Node* from_index, 536 compiler::Node* to_index, 537 compiler::Node* character_count, 538 String::Encoding from_encoding, 539 String::Encoding to_encoding, ParameterMode mode); 540 541 // Loads an element from |array| of |from_kind| elements by given |offset| 542 // (NOTE: not index!), does a hole check if |if_hole| is provided and 543 // converts the value so that it becomes ready for storing to array of 544 // |to_kind| elements. 545 compiler::Node* LoadElementAndPrepareForStore(compiler::Node* array, 546 compiler::Node* offset, 547 ElementsKind from_kind, 548 ElementsKind to_kind, 549 Label* if_hole); 550 551 compiler::Node* CalculateNewElementsCapacity( 552 compiler::Node* old_capacity, ParameterMode mode = INTEGER_PARAMETERS); 553 554 // Tries to grow the |elements| array of given |object| to store the |key| 555 // or bails out if the growing gap is too big. Returns new elements. 556 compiler::Node* TryGrowElementsCapacity(compiler::Node* object, 557 compiler::Node* elements, 558 ElementsKind kind, 559 compiler::Node* key, Label* bailout); 560 561 // Tries to grow the |capacity|-length |elements| array of given |object| 562 // to store the |key| or bails out if the growing gap is too big. Returns 563 // new elements. 564 compiler::Node* TryGrowElementsCapacity(compiler::Node* object, 565 compiler::Node* elements, 566 ElementsKind kind, 567 compiler::Node* key, 568 compiler::Node* capacity, 569 ParameterMode mode, Label* bailout); 570 571 // Grows elements capacity of given object. Returns new elements. 572 compiler::Node* GrowElementsCapacity( 573 compiler::Node* object, compiler::Node* elements, ElementsKind from_kind, 574 ElementsKind to_kind, compiler::Node* capacity, 575 compiler::Node* new_capacity, ParameterMode mode, Label* bailout); 576 577 // Allocation site manipulation 578 void InitializeAllocationMemento(compiler::Node* base_allocation, 579 int base_allocation_size, 580 compiler::Node* allocation_site); 581 582 compiler::Node* TryTaggedToFloat64(compiler::Node* value, 583 Label* if_valueisnotnumber); 584 compiler::Node* TruncateTaggedToFloat64(compiler::Node* context, 585 compiler::Node* value); 586 compiler::Node* TruncateTaggedToWord32(compiler::Node* context, 587 compiler::Node* value); 588 // Truncate the floating point value of a HeapNumber to an Int32. 589 compiler::Node* TruncateHeapNumberValueToWord32(compiler::Node* object); 590 591 // Conversions. 592 compiler::Node* ChangeFloat64ToTagged(compiler::Node* value); 593 compiler::Node* ChangeInt32ToTagged(compiler::Node* value); 594 compiler::Node* ChangeUint32ToTagged(compiler::Node* value); 595 596 // Type conversions. 597 // Throws a TypeError for {method_name} if {value} is not coercible to Object, 598 // or returns the {value} converted to a String otherwise. 599 compiler::Node* ToThisString(compiler::Node* context, compiler::Node* value, 600 char const* method_name); 601 // Throws a TypeError for {method_name} if {value} is neither of the given 602 // {primitive_type} nor a JSValue wrapping a value of {primitive_type}, or 603 // returns the {value} (or wrapped value) otherwise. 604 compiler::Node* ToThisValue(compiler::Node* context, compiler::Node* value, 605 PrimitiveType primitive_type, 606 char const* method_name); 607 608 // Throws a TypeError for {method_name} if {value} is not of the given 609 // instance type. Returns {value}'s map. 610 compiler::Node* ThrowIfNotInstanceType(compiler::Node* context, 611 compiler::Node* value, 612 InstanceType instance_type, 613 char const* method_name); 614 615 // Type checks. 616 // Check whether the map is for an object with special properties, such as a 617 // JSProxy or an object with interceptors. 618 compiler::Node* IsSpecialReceiverMap(compiler::Node* map); 619 compiler::Node* IsSpecialReceiverInstanceType(compiler::Node* instance_type); 620 compiler::Node* IsStringInstanceType(compiler::Node* instance_type); 621 compiler::Node* IsString(compiler::Node* object); 622 compiler::Node* IsJSObject(compiler::Node* object); 623 compiler::Node* IsJSGlobalProxy(compiler::Node* object); 624 compiler::Node* IsJSReceiverInstanceType(compiler::Node* instance_type); 625 compiler::Node* IsJSReceiver(compiler::Node* object); 626 compiler::Node* IsMap(compiler::Node* object); 627 compiler::Node* IsCallableMap(compiler::Node* map); 628 compiler::Node* IsName(compiler::Node* object); 629 compiler::Node* IsJSValue(compiler::Node* object); 630 compiler::Node* IsJSArray(compiler::Node* object); 631 compiler::Node* IsNativeContext(compiler::Node* object); 632 compiler::Node* IsWeakCell(compiler::Node* object); 633 compiler::Node* IsFixedDoubleArray(compiler::Node* object); 634 compiler::Node* IsHashTable(compiler::Node* object); 635 compiler::Node* IsDictionary(compiler::Node* object); 636 compiler::Node* IsUnseededNumberDictionary(compiler::Node* object); 637 638 // ElementsKind helpers: 639 compiler::Node* IsFastElementsKind(compiler::Node* elements_kind); 640 compiler::Node* IsHoleyFastElementsKind(compiler::Node* elements_kind); 641 642 // String helpers. 643 // Load a character from a String (might flatten a ConsString). 644 compiler::Node* StringCharCodeAt(compiler::Node* string, 645 compiler::Node* smi_index); 646 // Return the single character string with only {code}. 647 compiler::Node* StringFromCharCode(compiler::Node* code); 648 // Return a new string object which holds a substring containing the range 649 // [from,to[ of string. |from| and |to| are expected to be tagged. 650 compiler::Node* SubString(compiler::Node* context, compiler::Node* string, 651 compiler::Node* from, compiler::Node* to); 652 653 // Return a new string object produced by concatenating |first| with |second|. 654 compiler::Node* StringAdd(compiler::Node* context, compiler::Node* first, 655 compiler::Node* second, 656 AllocationFlags flags = kNone); 657 658 // Return the first index >= {from} at which {needle_char} was found in 659 // {string}, or -1 if such an index does not exist. The returned value is 660 // a Smi, {string} is expected to be a String, {needle_char} is an intptr, 661 // and {from} is expected to be tagged. 662 compiler::Node* StringIndexOfChar(compiler::Node* context, 663 compiler::Node* string, 664 compiler::Node* needle_char, 665 compiler::Node* from); 666 667 compiler::Node* StringFromCodePoint(compiler::Node* codepoint, 668 UnicodeEncoding encoding); 669 670 // Type conversion helpers. 671 // Convert a String to a Number. 672 compiler::Node* StringToNumber(compiler::Node* context, 673 compiler::Node* input); 674 compiler::Node* NumberToString(compiler::Node* context, 675 compiler::Node* input); 676 // Convert an object to a name. 677 compiler::Node* ToName(compiler::Node* context, compiler::Node* input); 678 // Convert a Non-Number object to a Number. 679 compiler::Node* NonNumberToNumber(compiler::Node* context, 680 compiler::Node* input); 681 // Convert any object to a Number. 682 compiler::Node* ToNumber(compiler::Node* context, compiler::Node* input); 683 684 // Convert any object to a String. 685 compiler::Node* ToString(compiler::Node* context, compiler::Node* input); 686 687 // Convert any object to a Primitive. 688 compiler::Node* JSReceiverToPrimitive(compiler::Node* context, 689 compiler::Node* input); 690 691 // Convert a String to a flat String. 692 compiler::Node* FlattenString(compiler::Node* string); 693 694 enum ToIntegerTruncationMode { 695 kNoTruncation, 696 kTruncateMinusZero, 697 }; 698 699 // Convert any object to an Integer. 700 compiler::Node* ToInteger(compiler::Node* context, compiler::Node* input, 701 ToIntegerTruncationMode mode = kNoTruncation); 702 703 // Returns a node that contains a decoded (unsigned!) value of a bit 704 // field |T| in |word32|. Returns result as an uint32 node. 705 template <typename T> DecodeWord32(compiler::Node * word32)706 compiler::Node* DecodeWord32(compiler::Node* word32) { 707 return DecodeWord32(word32, T::kShift, T::kMask); 708 } 709 710 // Returns a node that contains a decoded (unsigned!) value of a bit 711 // field |T| in |word|. Returns result as a word-size node. 712 template <typename T> DecodeWord(compiler::Node * word)713 compiler::Node* DecodeWord(compiler::Node* word) { 714 return DecodeWord(word, T::kShift, T::kMask); 715 } 716 717 // Returns a node that contains a decoded (unsigned!) value of a bit 718 // field |T| in |word32|. Returns result as a word-size node. 719 template <typename T> DecodeWordFromWord32(compiler::Node * word32)720 compiler::Node* DecodeWordFromWord32(compiler::Node* word32) { 721 return DecodeWord<T>(ChangeUint32ToWord(word32)); 722 } 723 724 // Decodes an unsigned (!) value from |word32| to an uint32 node. 725 compiler::Node* DecodeWord32(compiler::Node* word32, uint32_t shift, 726 uint32_t mask); 727 728 // Decodes an unsigned (!) value from |word| to a word-size node. 729 compiler::Node* DecodeWord(compiler::Node* word, uint32_t shift, 730 uint32_t mask); 731 732 // Returns true if any of the |T|'s bits in given |word32| are set. 733 template <typename T> IsSetWord32(compiler::Node * word32)734 compiler::Node* IsSetWord32(compiler::Node* word32) { 735 return IsSetWord32(word32, T::kMask); 736 } 737 738 // Returns true if any of the mask's bits in given |word32| are set. IsSetWord32(compiler::Node * word32,uint32_t mask)739 compiler::Node* IsSetWord32(compiler::Node* word32, uint32_t mask) { 740 return Word32NotEqual(Word32And(word32, Int32Constant(mask)), 741 Int32Constant(0)); 742 } 743 744 // Returns true if any of the |T|'s bits in given |word| are set. 745 template <typename T> IsSetWord(compiler::Node * word)746 compiler::Node* IsSetWord(compiler::Node* word) { 747 return WordNotEqual(WordAnd(word, IntPtrConstant(T::kMask)), 748 IntPtrConstant(0)); 749 } 750 751 void SetCounter(StatsCounter* counter, int value); 752 void IncrementCounter(StatsCounter* counter, int delta); 753 void DecrementCounter(StatsCounter* counter, int delta); 754 755 // Generates "if (false) goto label" code. Useful for marking a label as 756 // "live" to avoid assertion failures during graph building. In the resulting 757 // code this check will be eliminated. 758 void Use(Label* label); 759 760 // Various building blocks for stubs doing property lookups. 761 void TryToName(compiler::Node* key, Label* if_keyisindex, Variable* var_index, 762 Label* if_keyisunique, Label* if_bailout); 763 764 // Calculates array index for given dictionary entry and entry field. 765 // See Dictionary::EntryToIndex(). 766 template <typename Dictionary> 767 compiler::Node* EntryToIndex(compiler::Node* entry, int field_index); 768 template <typename Dictionary> EntryToIndex(compiler::Node * entry)769 compiler::Node* EntryToIndex(compiler::Node* entry) { 770 return EntryToIndex<Dictionary>(entry, Dictionary::kEntryKeyIndex); 771 } 772 // Calculate a valid size for the a hash table. 773 compiler::Node* HashTableComputeCapacity(compiler::Node* at_least_space_for); 774 775 // Looks up an entry in a NameDictionaryBase successor. If the entry is found 776 // control goes to {if_found} and {var_name_index} contains an index of the 777 // key field of the entry found. If the key is not found control goes to 778 // {if_not_found}. 779 static const int kInlinedDictionaryProbes = 4; 780 template <typename Dictionary> 781 void NameDictionaryLookup(compiler::Node* dictionary, 782 compiler::Node* unique_name, Label* if_found, 783 Variable* var_name_index, Label* if_not_found, 784 int inlined_probes = kInlinedDictionaryProbes); 785 786 compiler::Node* ComputeIntegerHash(compiler::Node* key, compiler::Node* seed); 787 788 template <typename Dictionary> 789 void NumberDictionaryLookup(compiler::Node* dictionary, 790 compiler::Node* intptr_index, Label* if_found, 791 Variable* var_entry, Label* if_not_found); 792 793 // Tries to check if {object} has own {unique_name} property. 794 void TryHasOwnProperty(compiler::Node* object, compiler::Node* map, 795 compiler::Node* instance_type, 796 compiler::Node* unique_name, Label* if_found, 797 Label* if_not_found, Label* if_bailout); 798 799 // Tries to get {object}'s own {unique_name} property value. If the property 800 // is an accessor then it also calls a getter. If the property is a double 801 // field it re-wraps value in an immutable heap number. 802 void TryGetOwnProperty(compiler::Node* context, compiler::Node* receiver, 803 compiler::Node* object, compiler::Node* map, 804 compiler::Node* instance_type, 805 compiler::Node* unique_name, Label* if_found, 806 Variable* var_value, Label* if_not_found, 807 Label* if_bailout); 808 809 void LoadPropertyFromFastObject(compiler::Node* object, compiler::Node* map, 810 compiler::Node* descriptors, 811 compiler::Node* name_index, 812 Variable* var_details, Variable* var_value); 813 814 void LoadPropertyFromNameDictionary(compiler::Node* dictionary, 815 compiler::Node* entry, 816 Variable* var_details, 817 Variable* var_value); 818 819 void LoadPropertyFromGlobalDictionary(compiler::Node* dictionary, 820 compiler::Node* entry, 821 Variable* var_details, 822 Variable* var_value, Label* if_deleted); 823 824 // Generic property lookup generator. If the {object} is fast and 825 // {unique_name} property is found then the control goes to {if_found_fast} 826 // label and {var_meta_storage} and {var_name_index} will contain 827 // DescriptorArray and an index of the descriptor's name respectively. 828 // If the {object} is slow or global then the control goes to {if_found_dict} 829 // or {if_found_global} and the {var_meta_storage} and {var_name_index} will 830 // contain a dictionary and an index of the key field of the found entry. 831 // If property is not found or given lookup is not supported then 832 // the control goes to {if_not_found} or {if_bailout} respectively. 833 // 834 // Note: this code does not check if the global dictionary points to deleted 835 // entry! This has to be done by the caller. 836 void TryLookupProperty(compiler::Node* object, compiler::Node* map, 837 compiler::Node* instance_type, 838 compiler::Node* unique_name, Label* if_found_fast, 839 Label* if_found_dict, Label* if_found_global, 840 Variable* var_meta_storage, Variable* var_name_index, 841 Label* if_not_found, Label* if_bailout); 842 843 void TryLookupElement(compiler::Node* object, compiler::Node* map, 844 compiler::Node* instance_type, 845 compiler::Node* intptr_index, Label* if_found, 846 Label* if_not_found, Label* if_bailout); 847 848 // This is a type of a lookup in holder generator function. In case of a 849 // property lookup the {key} is guaranteed to be a unique name and in case of 850 // element lookup the key is an Int32 index. 851 typedef std::function<void(compiler::Node* receiver, compiler::Node* holder, 852 compiler::Node* map, compiler::Node* instance_type, 853 compiler::Node* key, Label* next_holder, 854 Label* if_bailout)> 855 LookupInHolder; 856 857 // Generic property prototype chain lookup generator. 858 // For properties it generates lookup using given {lookup_property_in_holder} 859 // and for elements it uses {lookup_element_in_holder}. 860 // Upon reaching the end of prototype chain the control goes to {if_end}. 861 // If it can't handle the case {receiver}/{key} case then the control goes 862 // to {if_bailout}. 863 void TryPrototypeChainLookup(compiler::Node* receiver, compiler::Node* key, 864 LookupInHolder& lookup_property_in_holder, 865 LookupInHolder& lookup_element_in_holder, 866 Label* if_end, Label* if_bailout); 867 868 // Instanceof helpers. 869 // ES6 section 7.3.19 OrdinaryHasInstance (C, O) 870 compiler::Node* OrdinaryHasInstance(compiler::Node* context, 871 compiler::Node* callable, 872 compiler::Node* object); 873 874 // Load/StoreIC helpers. 875 struct LoadICParameters { LoadICParametersLoadICParameters876 LoadICParameters(compiler::Node* context, compiler::Node* receiver, 877 compiler::Node* name, compiler::Node* slot, 878 compiler::Node* vector) 879 : context(context), 880 receiver(receiver), 881 name(name), 882 slot(slot), 883 vector(vector) {} 884 885 compiler::Node* context; 886 compiler::Node* receiver; 887 compiler::Node* name; 888 compiler::Node* slot; 889 compiler::Node* vector; 890 }; 891 892 struct StoreICParameters : public LoadICParameters { StoreICParametersStoreICParameters893 StoreICParameters(compiler::Node* context, compiler::Node* receiver, 894 compiler::Node* name, compiler::Node* value, 895 compiler::Node* slot, compiler::Node* vector) 896 : LoadICParameters(context, receiver, name, slot, vector), 897 value(value) {} 898 compiler::Node* value; 899 }; 900 901 // Load type feedback vector from the stub caller's frame. 902 compiler::Node* LoadTypeFeedbackVectorForStub(); 903 904 // Update the type feedback vector. 905 void UpdateFeedback(compiler::Node* feedback, 906 compiler::Node* type_feedback_vector, 907 compiler::Node* slot_id); 908 909 compiler::Node* LoadReceiverMap(compiler::Node* receiver); 910 911 // Checks monomorphic case. Returns {feedback} entry of the vector. 912 compiler::Node* TryMonomorphicCase(compiler::Node* slot, 913 compiler::Node* vector, 914 compiler::Node* receiver_map, 915 Label* if_handler, Variable* var_handler, 916 Label* if_miss); 917 void HandlePolymorphicCase(compiler::Node* receiver_map, 918 compiler::Node* feedback, Label* if_handler, 919 Variable* var_handler, Label* if_miss, 920 int unroll_count); 921 void HandleKeyedStorePolymorphicCase(compiler::Node* receiver_map, 922 compiler::Node* feedback, 923 Label* if_handler, Variable* var_handler, 924 Label* if_transition_handler, 925 Variable* var_transition_map_cell, 926 Label* if_miss); 927 928 compiler::Node* StubCachePrimaryOffset(compiler::Node* name, 929 compiler::Node* map); 930 931 compiler::Node* StubCacheSecondaryOffset(compiler::Node* name, 932 compiler::Node* seed); 933 934 // This enum is used here as a replacement for StubCache::Table to avoid 935 // including stub cache header. 936 enum StubCacheTable : int; 937 938 void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id, 939 compiler::Node* entry_offset, 940 compiler::Node* name, compiler::Node* map, 941 Label* if_handler, Variable* var_handler, 942 Label* if_miss); 943 944 void TryProbeStubCache(StubCache* stub_cache, compiler::Node* receiver, 945 compiler::Node* name, Label* if_handler, 946 Variable* var_handler, Label* if_miss); 947 948 // Extends properties backing store by JSObject::kFieldsAdded elements. 949 void ExtendPropertiesBackingStore(compiler::Node* object); 950 951 compiler::Node* PrepareValueForWrite(compiler::Node* value, 952 Representation representation, 953 Label* bailout); 954 955 void StoreNamedField(compiler::Node* object, FieldIndex index, 956 Representation representation, compiler::Node* value, 957 bool transition_to_field); 958 959 void StoreNamedField(compiler::Node* object, compiler::Node* offset, 960 bool is_inobject, Representation representation, 961 compiler::Node* value, bool transition_to_field); 962 963 // Emits keyed sloppy arguments load. Returns either the loaded value. LoadKeyedSloppyArguments(compiler::Node * receiver,compiler::Node * key,Label * bailout)964 compiler::Node* LoadKeyedSloppyArguments(compiler::Node* receiver, 965 compiler::Node* key, 966 Label* bailout) { 967 return EmitKeyedSloppyArguments(receiver, key, nullptr, bailout); 968 } 969 970 // Emits keyed sloppy arguments store. StoreKeyedSloppyArguments(compiler::Node * receiver,compiler::Node * key,compiler::Node * value,Label * bailout)971 void StoreKeyedSloppyArguments(compiler::Node* receiver, compiler::Node* key, 972 compiler::Node* value, Label* bailout) { 973 DCHECK_NOT_NULL(value); 974 EmitKeyedSloppyArguments(receiver, key, value, bailout); 975 } 976 977 // Loads script context from the script context table. 978 compiler::Node* LoadScriptContext(compiler::Node* context, int context_index); 979 980 compiler::Node* Int32ToUint8Clamped(compiler::Node* int32_value); 981 compiler::Node* Float64ToUint8Clamped(compiler::Node* float64_value); 982 983 compiler::Node* PrepareValueForWriteToTypedArray(compiler::Node* key, 984 ElementsKind elements_kind, 985 Label* bailout); 986 987 // Store value to an elements array with given elements kind. 988 void StoreElement(compiler::Node* elements, ElementsKind kind, 989 compiler::Node* index, compiler::Node* value, 990 ParameterMode mode); 991 992 void EmitElementStore(compiler::Node* object, compiler::Node* key, 993 compiler::Node* value, bool is_jsarray, 994 ElementsKind elements_kind, 995 KeyedAccessStoreMode store_mode, Label* bailout); 996 997 compiler::Node* CheckForCapacityGrow(compiler::Node* object, 998 compiler::Node* elements, 999 ElementsKind kind, 1000 compiler::Node* length, 1001 compiler::Node* key, ParameterMode mode, 1002 bool is_js_array, Label* bailout); 1003 1004 compiler::Node* CopyElementsOnWrite(compiler::Node* object, 1005 compiler::Node* elements, 1006 ElementsKind kind, compiler::Node* length, 1007 ParameterMode mode, Label* bailout); 1008 1009 void LoadIC(const LoadICParameters* p); 1010 void LoadICProtoArray(const LoadICParameters* p, compiler::Node* handler); 1011 void LoadGlobalIC(const LoadICParameters* p); 1012 void KeyedLoadIC(const LoadICParameters* p); 1013 void KeyedLoadICGeneric(const LoadICParameters* p); 1014 void StoreIC(const StoreICParameters* p); 1015 void KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode); 1016 1017 void TransitionElementsKind(compiler::Node* object, compiler::Node* map, 1018 ElementsKind from_kind, ElementsKind to_kind, 1019 bool is_jsarray, Label* bailout); 1020 1021 void TrapAllocationMemento(compiler::Node* object, Label* memento_found); 1022 1023 compiler::Node* PageFromAddress(compiler::Node* address); 1024 1025 // Get the enumerable length from |map| and return the result as a Smi. 1026 compiler::Node* EnumLength(compiler::Node* map); 1027 1028 // Check the cache validity for |receiver|. Branch to |use_cache| if 1029 // the cache is valid, otherwise branch to |use_runtime|. 1030 void CheckEnumCache(compiler::Node* receiver, 1031 CodeStubAssembler::Label* use_cache, 1032 CodeStubAssembler::Label* use_runtime); 1033 1034 // Create a new weak cell with a specified value and install it into a 1035 // feedback vector. 1036 compiler::Node* CreateWeakCellInFeedbackVector( 1037 compiler::Node* feedback_vector, compiler::Node* slot, 1038 compiler::Node* value); 1039 1040 // Create a new AllocationSite and install it into a feedback vector. 1041 compiler::Node* CreateAllocationSiteInFeedbackVector( 1042 compiler::Node* feedback_vector, compiler::Node* slot); 1043 1044 enum class IndexAdvanceMode { kPre, kPost }; 1045 1046 void BuildFastLoop( 1047 const VariableList& var_list, MachineRepresentation index_rep, 1048 compiler::Node* start_index, compiler::Node* end_index, 1049 std::function<void(CodeStubAssembler* assembler, compiler::Node* index)> 1050 body, 1051 int increment, IndexAdvanceMode mode = IndexAdvanceMode::kPre); 1052 1053 void BuildFastLoop( 1054 MachineRepresentation index_rep, compiler::Node* start_index, 1055 compiler::Node* end_index, 1056 std::function<void(CodeStubAssembler* assembler, compiler::Node* index)> 1057 body, 1058 int increment, IndexAdvanceMode mode = IndexAdvanceMode::kPre) { 1059 BuildFastLoop(VariableList(0, zone()), index_rep, start_index, end_index, 1060 body, increment, mode); 1061 } 1062 1063 enum class ForEachDirection { kForward, kReverse }; 1064 1065 void BuildFastFixedArrayForEach( 1066 compiler::Node* fixed_array, ElementsKind kind, 1067 compiler::Node* first_element_inclusive, 1068 compiler::Node* last_element_exclusive, 1069 std::function<void(CodeStubAssembler* assembler, 1070 compiler::Node* fixed_array, compiler::Node* offset)> 1071 body, 1072 ParameterMode mode = INTPTR_PARAMETERS, 1073 ForEachDirection direction = ForEachDirection::kReverse); 1074 GetArrayAllocationSize(compiler::Node * element_count,ElementsKind kind,ParameterMode mode,int header_size)1075 compiler::Node* GetArrayAllocationSize(compiler::Node* element_count, 1076 ElementsKind kind, ParameterMode mode, 1077 int header_size) { 1078 return ElementOffsetFromIndex(element_count, kind, mode, header_size); 1079 } 1080 GetFixedArrayAllocationSize(compiler::Node * element_count,ElementsKind kind,ParameterMode mode)1081 compiler::Node* GetFixedArrayAllocationSize(compiler::Node* element_count, 1082 ElementsKind kind, 1083 ParameterMode mode) { 1084 return GetArrayAllocationSize(element_count, kind, mode, 1085 FixedArray::kHeaderSize); 1086 } 1087 1088 enum RelationalComparisonMode { 1089 kLessThan, 1090 kLessThanOrEqual, 1091 kGreaterThan, 1092 kGreaterThanOrEqual 1093 }; 1094 1095 compiler::Node* RelationalComparison(RelationalComparisonMode mode, 1096 compiler::Node* lhs, compiler::Node* rhs, 1097 compiler::Node* context); 1098 1099 void BranchIfNumericRelationalComparison(RelationalComparisonMode mode, 1100 compiler::Node* lhs, 1101 compiler::Node* rhs, Label* if_true, 1102 Label* if_false); 1103 1104 void GotoUnlessNumberLessThan(compiler::Node* lhs, compiler::Node* rhs, 1105 Label* if_false); 1106 1107 enum ResultMode { kDontNegateResult, kNegateResult }; 1108 1109 compiler::Node* Equal(ResultMode mode, compiler::Node* lhs, 1110 compiler::Node* rhs, compiler::Node* context); 1111 1112 compiler::Node* StrictEqual(ResultMode mode, compiler::Node* lhs, 1113 compiler::Node* rhs, compiler::Node* context); 1114 1115 // ECMA#sec-samevalue 1116 // Similar to StrictEqual except that NaNs are treated as equal and minus zero 1117 // differs from positive zero. 1118 // Unlike Equal and StrictEqual, returns a value suitable for use in Branch 1119 // instructions, e.g. Branch(SameValue(...), &label). 1120 compiler::Node* SameValue(compiler::Node* lhs, compiler::Node* rhs, 1121 compiler::Node* context); 1122 1123 compiler::Node* HasProperty( 1124 compiler::Node* object, compiler::Node* key, compiler::Node* context, 1125 Runtime::FunctionId fallback_runtime_function_id = Runtime::kHasProperty); 1126 compiler::Node* ForInFilter(compiler::Node* key, compiler::Node* object, 1127 compiler::Node* context); 1128 1129 compiler::Node* Typeof(compiler::Node* value, compiler::Node* context); 1130 1131 compiler::Node* InstanceOf(compiler::Node* object, compiler::Node* callable, 1132 compiler::Node* context); 1133 1134 // TypedArray/ArrayBuffer helpers 1135 compiler::Node* IsDetachedBuffer(compiler::Node* buffer); 1136 1137 compiler::Node* ElementOffsetFromIndex(compiler::Node* index, 1138 ElementsKind kind, ParameterMode mode, 1139 int base_size = 0); 1140 1141 protected: 1142 void HandleStoreICHandlerCase(const StoreICParameters* p, 1143 compiler::Node* handler, Label* miss); 1144 1145 private: 1146 friend class CodeStubArguments; 1147 1148 enum ElementSupport { kOnlyProperties, kSupportElements }; 1149 1150 void DescriptorLookupLinear(compiler::Node* unique_name, 1151 compiler::Node* descriptors, compiler::Node* nof, 1152 Label* if_found, Variable* var_name_index, 1153 Label* if_not_found); 1154 compiler::Node* CallGetterIfAccessor(compiler::Node* value, 1155 compiler::Node* details, 1156 compiler::Node* context, 1157 compiler::Node* receiver, 1158 Label* if_bailout); 1159 1160 void HandleLoadICHandlerCase( 1161 const LoadICParameters* p, compiler::Node* handler, Label* miss, 1162 ElementSupport support_elements = kOnlyProperties); 1163 1164 void HandleLoadICSmiHandlerCase(const LoadICParameters* p, 1165 compiler::Node* holder, 1166 compiler::Node* smi_handler, Label* miss, 1167 ElementSupport support_elements); 1168 1169 void HandleLoadICProtoHandler(const LoadICParameters* p, 1170 compiler::Node* handler, Variable* var_holder, 1171 Variable* var_smi_handler, 1172 Label* if_smi_handler, Label* miss); 1173 1174 compiler::Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, 1175 compiler::Node* handler, 1176 compiler::Node* handler_length, 1177 compiler::Node* handler_flags, 1178 Label* miss); 1179 1180 void CheckPrototype(compiler::Node* prototype_cell, compiler::Node* name, 1181 Label* miss); 1182 1183 void NameDictionaryNegativeLookup(compiler::Node* object, 1184 compiler::Node* name, Label* miss); 1185 1186 // If |transition| is nullptr then the normal field store is generated or 1187 // transitioning store otherwise. 1188 void HandleStoreFieldAndReturn(compiler::Node* handler_word, 1189 compiler::Node* holder, 1190 Representation representation, 1191 compiler::Node* value, 1192 compiler::Node* transition, Label* miss); 1193 1194 // If |transition| is nullptr then the normal field store is generated or 1195 // transitioning store otherwise. 1196 void HandleStoreICSmiHandlerCase(compiler::Node* handler_word, 1197 compiler::Node* holder, 1198 compiler::Node* value, 1199 compiler::Node* transition, Label* miss); 1200 1201 void HandleStoreICProtoHandler(const StoreICParameters* p, 1202 compiler::Node* handler, Label* miss); 1203 1204 compiler::Node* TryToIntptr(compiler::Node* key, Label* miss); 1205 void EmitFastElementsBoundsCheck(compiler::Node* object, 1206 compiler::Node* elements, 1207 compiler::Node* intptr_index, 1208 compiler::Node* is_jsarray_condition, 1209 Label* miss); 1210 void EmitElementLoad(compiler::Node* object, compiler::Node* elements, 1211 compiler::Node* elements_kind, compiler::Node* key, 1212 compiler::Node* is_jsarray_condition, Label* if_hole, 1213 Label* rebox_double, Variable* var_double_value, 1214 Label* unimplemented_elements_kind, Label* out_of_bounds, 1215 Label* miss); 1216 void BranchIfPrototypesHaveNoElements(compiler::Node* receiver_map, 1217 Label* definitely_no_elements, 1218 Label* possibly_elements); 1219 1220 compiler::Node* AllocateRawAligned(compiler::Node* size_in_bytes, 1221 AllocationFlags flags, 1222 compiler::Node* top_address, 1223 compiler::Node* limit_address); 1224 compiler::Node* AllocateRawUnaligned(compiler::Node* size_in_bytes, 1225 AllocationFlags flags, 1226 compiler::Node* top_adddress, 1227 compiler::Node* limit_address); 1228 // Allocate and return a JSArray of given total size in bytes with header 1229 // fields initialized. 1230 compiler::Node* AllocateUninitializedJSArray(ElementsKind kind, 1231 compiler::Node* array_map, 1232 compiler::Node* length, 1233 compiler::Node* allocation_site, 1234 compiler::Node* size_in_bytes); 1235 1236 compiler::Node* SmiShiftBitsConstant(); 1237 1238 // Emits keyed sloppy arguments load if the |value| is nullptr or store 1239 // otherwise. Returns either the loaded value or |value|. 1240 compiler::Node* EmitKeyedSloppyArguments(compiler::Node* receiver, 1241 compiler::Node* key, 1242 compiler::Node* value, 1243 Label* bailout); 1244 1245 compiler::Node* AllocateSlicedString(Heap::RootListIndex map_root_index, 1246 compiler::Node* length, 1247 compiler::Node* parent, 1248 compiler::Node* offset); 1249 1250 compiler::Node* AllocateConsString(Heap::RootListIndex map_root_index, 1251 compiler::Node* length, 1252 compiler::Node* first, 1253 compiler::Node* second, 1254 AllocationFlags flags); 1255 1256 static const int kElementLoopUnrollThreshold = 8; 1257 }; 1258 1259 class CodeStubArguments { 1260 public: 1261 // |argc| specifies the number of arguments passed to the builtin excluding 1262 // the receiver. 1263 CodeStubArguments(CodeStubAssembler* assembler, compiler::Node* argc, 1264 CodeStubAssembler::ParameterMode mode = 1265 CodeStubAssembler::INTPTR_PARAMETERS); 1266 1267 compiler::Node* GetReceiver(); 1268 1269 // |index| is zero-based and does not include the receiver 1270 compiler::Node* AtIndex(compiler::Node* index, 1271 CodeStubAssembler::ParameterMode mode = 1272 CodeStubAssembler::INTPTR_PARAMETERS); 1273 1274 compiler::Node* AtIndex(int index); 1275 1276 typedef std::function<void(CodeStubAssembler* assembler, compiler::Node* arg)> 1277 ForEachBodyFunction; 1278 1279 // Iteration doesn't include the receiver. |first| and |last| are zero-based. 1280 void ForEach(ForEachBodyFunction body, compiler::Node* first = nullptr, 1281 compiler::Node* last = nullptr, 1282 CodeStubAssembler::ParameterMode mode = 1283 CodeStubAssembler::INTPTR_PARAMETERS) { 1284 CodeStubAssembler::VariableList list(0, assembler_->zone()); 1285 ForEach(list, body, first, last); 1286 } 1287 1288 // Iteration doesn't include the receiver. |first| and |last| are zero-based. 1289 void ForEach(const CodeStubAssembler::VariableList& vars, 1290 ForEachBodyFunction body, compiler::Node* first = nullptr, 1291 compiler::Node* last = nullptr, 1292 CodeStubAssembler::ParameterMode mode = 1293 CodeStubAssembler::INTPTR_PARAMETERS); 1294 1295 void PopAndReturn(compiler::Node* value); 1296 1297 private: 1298 compiler::Node* GetArguments(); 1299 1300 CodeStubAssembler* assembler_; 1301 compiler::Node* argc_; 1302 compiler::Node* arguments_; 1303 compiler::Node* fp_; 1304 }; 1305 1306 #ifdef DEBUG 1307 #define CSA_ASSERT(csa, x) \ 1308 (csa)->Assert([&] { return (x); }, #x, __FILE__, __LINE__) 1309 #else 1310 #define CSA_ASSERT(csa, x) ((void)0) 1311 #endif 1312 1313 #ifdef ENABLE_SLOW_DCHECKS 1314 #define CSA_SLOW_ASSERT(csa, x) \ 1315 if (FLAG_enable_slow_asserts) { \ 1316 (csa)->Assert([&] { return (x); }, #x, __FILE__, __LINE__); \ 1317 } 1318 #else 1319 #define CSA_SLOW_ASSERT(csa, x) ((void)0) 1320 #endif 1321 1322 DEFINE_OPERATORS_FOR_FLAGS(CodeStubAssembler::AllocationFlags); 1323 1324 } // namespace internal 1325 } // namespace v8 1326 #endif // V8_CODE_STUB_ASSEMBLER_H_ 1327