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