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_CODEGEN_CODE_STUB_ASSEMBLER_H_ 6 #define V8_CODEGEN_CODE_STUB_ASSEMBLER_H_ 7 8 #include <functional> 9 10 #include "src/base/macros.h" 11 #include "src/codegen/bailout-reason.h" 12 #include "src/codegen/tnode.h" 13 #include "src/common/globals.h" 14 #include "src/common/message-template.h" 15 #include "src/compiler/code-assembler.h" 16 #include "src/numbers/integer-literal.h" 17 #include "src/objects/arguments.h" 18 #include "src/objects/bigint.h" 19 #include "src/objects/cell.h" 20 #include "src/objects/feedback-vector.h" 21 #include "src/objects/js-function.h" 22 #include "src/objects/js-generator.h" 23 #include "src/objects/js-promise.h" 24 #include "src/objects/objects.h" 25 #include "src/objects/promise.h" 26 #include "src/objects/shared-function-info.h" 27 #include "src/objects/smi.h" 28 #include "src/objects/swiss-name-dictionary.h" 29 #include "src/objects/tagged-index.h" 30 #include "src/roots/roots.h" 31 #include "src/sandbox/external-pointer.h" 32 #include "torque-generated/exported-macros-assembler.h" 33 34 namespace v8 { 35 namespace internal { 36 37 class CallInterfaceDescriptor; 38 class CodeStubArguments; 39 class CodeStubAssembler; 40 class StatsCounter; 41 class StubCache; 42 43 enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol }; 44 45 #define HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(V) \ 46 V(ArrayIteratorProtector, array_iterator_protector, ArrayIteratorProtector) \ 47 V(ArraySpeciesProtector, array_species_protector, ArraySpeciesProtector) \ 48 V(AsyncFunctionAwaitRejectSharedFun, async_function_await_reject_shared_fun, \ 49 AsyncFunctionAwaitRejectSharedFun) \ 50 V(AsyncFunctionAwaitResolveSharedFun, \ 51 async_function_await_resolve_shared_fun, \ 52 AsyncFunctionAwaitResolveSharedFun) \ 53 V(AsyncGeneratorAwaitRejectSharedFun, \ 54 async_generator_await_reject_shared_fun, \ 55 AsyncGeneratorAwaitRejectSharedFun) \ 56 V(AsyncGeneratorAwaitResolveSharedFun, \ 57 async_generator_await_resolve_shared_fun, \ 58 AsyncGeneratorAwaitResolveSharedFun) \ 59 V(AsyncGeneratorReturnClosedRejectSharedFun, \ 60 async_generator_return_closed_reject_shared_fun, \ 61 AsyncGeneratorReturnClosedRejectSharedFun) \ 62 V(AsyncGeneratorReturnClosedResolveSharedFun, \ 63 async_generator_return_closed_resolve_shared_fun, \ 64 AsyncGeneratorReturnClosedResolveSharedFun) \ 65 V(AsyncGeneratorReturnResolveSharedFun, \ 66 async_generator_return_resolve_shared_fun, \ 67 AsyncGeneratorReturnResolveSharedFun) \ 68 V(AsyncGeneratorYieldResolveSharedFun, \ 69 async_generator_yield_resolve_shared_fun, \ 70 AsyncGeneratorYieldResolveSharedFun) \ 71 V(AsyncIteratorValueUnwrapSharedFun, async_iterator_value_unwrap_shared_fun, \ 72 AsyncIteratorValueUnwrapSharedFun) \ 73 V(IsConcatSpreadableProtector, is_concat_spreadable_protector, \ 74 IsConcatSpreadableProtector) \ 75 V(MapIteratorProtector, map_iterator_protector, MapIteratorProtector) \ 76 V(NoElementsProtector, no_elements_protector, NoElementsProtector) \ 77 V(MegaDOMProtector, mega_dom_protector, MegaDOMProtector) \ 78 V(NumberStringCache, number_string_cache, NumberStringCache) \ 79 V(PromiseAllResolveElementSharedFun, promise_all_resolve_element_shared_fun, \ 80 PromiseAllResolveElementSharedFun) \ 81 V(PromiseAllSettledRejectElementSharedFun, \ 82 promise_all_settled_reject_element_shared_fun, \ 83 PromiseAllSettledRejectElementSharedFun) \ 84 V(PromiseAllSettledResolveElementSharedFun, \ 85 promise_all_settled_resolve_element_shared_fun, \ 86 PromiseAllSettledResolveElementSharedFun) \ 87 V(PromiseAnyRejectElementSharedFun, promise_any_reject_element_shared_fun, \ 88 PromiseAnyRejectElementSharedFun) \ 89 V(PromiseCapabilityDefaultRejectSharedFun, \ 90 promise_capability_default_reject_shared_fun, \ 91 PromiseCapabilityDefaultRejectSharedFun) \ 92 V(PromiseCapabilityDefaultResolveSharedFun, \ 93 promise_capability_default_resolve_shared_fun, \ 94 PromiseCapabilityDefaultResolveSharedFun) \ 95 V(PromiseCatchFinallySharedFun, promise_catch_finally_shared_fun, \ 96 PromiseCatchFinallySharedFun) \ 97 V(PromiseGetCapabilitiesExecutorSharedFun, \ 98 promise_get_capabilities_executor_shared_fun, \ 99 PromiseGetCapabilitiesExecutorSharedFun) \ 100 V(PromiseResolveProtector, promise_resolve_protector, \ 101 PromiseResolveProtector) \ 102 V(PromiseSpeciesProtector, promise_species_protector, \ 103 PromiseSpeciesProtector) \ 104 V(PromiseThenFinallySharedFun, promise_then_finally_shared_fun, \ 105 PromiseThenFinallySharedFun) \ 106 V(PromiseThenProtector, promise_then_protector, PromiseThenProtector) \ 107 V(PromiseThrowerFinallySharedFun, promise_thrower_finally_shared_fun, \ 108 PromiseThrowerFinallySharedFun) \ 109 V(PromiseValueThunkFinallySharedFun, promise_value_thunk_finally_shared_fun, \ 110 PromiseValueThunkFinallySharedFun) \ 111 V(ProxyRevokeSharedFun, proxy_revoke_shared_fun, ProxyRevokeSharedFun) \ 112 V(RegExpSpeciesProtector, regexp_species_protector, RegExpSpeciesProtector) \ 113 V(SetIteratorProtector, set_iterator_protector, SetIteratorProtector) \ 114 V(SingleCharacterStringCache, single_character_string_cache, \ 115 SingleCharacterStringCache) \ 116 V(StringIteratorProtector, string_iterator_protector, \ 117 StringIteratorProtector) \ 118 V(TypedArraySpeciesProtector, typed_array_species_protector, \ 119 TypedArraySpeciesProtector) 120 121 #define UNIQUE_INSTANCE_TYPE_IMMUTABLE_IMMOVABLE_MAP_ADAPTER( \ 122 V, rootIndexName, rootAccessorName, class_name) \ 123 V(rootIndexName, rootAccessorName, class_name##Map) 124 125 #define HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(V) \ 126 V(AllocationSiteWithoutWeakNextMap, allocation_site_without_weaknext_map, \ 127 AllocationSiteWithoutWeakNextMap) \ 128 V(AllocationSiteWithWeakNextMap, allocation_site_map, AllocationSiteMap) \ 129 V(arguments_to_string, arguments_to_string, ArgumentsToString) \ 130 V(Array_string, Array_string, ArrayString) \ 131 V(array_to_string, array_to_string, ArrayToString) \ 132 V(BooleanMap, boolean_map, BooleanMap) \ 133 V(boolean_to_string, boolean_to_string, BooleanToString) \ 134 V(ConsOneByteStringMap, cons_one_byte_string_map, ConsOneByteStringMap) \ 135 V(ConsStringMap, cons_string_map, ConsStringMap) \ 136 V(constructor_string, constructor_string, ConstructorString) \ 137 V(date_to_string, date_to_string, DateToString) \ 138 V(default_string, default_string, DefaultString) \ 139 V(EmptyByteArray, empty_byte_array, EmptyByteArray) \ 140 V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \ 141 V(EmptyScopeInfo, empty_scope_info, EmptyScopeInfo) \ 142 V(EmptyPropertyDictionary, empty_property_dictionary, \ 143 EmptyPropertyDictionary) \ 144 V(EmptyOrderedPropertyDictionary, empty_ordered_property_dictionary, \ 145 EmptyOrderedPropertyDictionary) \ 146 V(EmptySwissPropertyDictionary, empty_swiss_property_dictionary, \ 147 EmptySwissPropertyDictionary) \ 148 V(EmptySlowElementDictionary, empty_slow_element_dictionary, \ 149 EmptySlowElementDictionary) \ 150 V(empty_string, empty_string, EmptyString) \ 151 V(error_to_string, error_to_string, ErrorToString) \ 152 V(errors_string, errors_string, ErrorsString) \ 153 V(FalseValue, false_value, False) \ 154 V(FixedArrayMap, fixed_array_map, FixedArrayMap) \ 155 V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap) \ 156 V(Function_string, function_string, FunctionString) \ 157 V(function_to_string, function_to_string, FunctionToString) \ 158 V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \ 159 V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \ 160 V(Infinity_string, Infinity_string, InfinityString) \ 161 V(is_concat_spreadable_symbol, is_concat_spreadable_symbol, \ 162 IsConcatSpreadableSymbol) \ 163 V(iterator_symbol, iterator_symbol, IteratorSymbol) \ 164 V(length_string, length_string, LengthString) \ 165 V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \ 166 V(match_symbol, match_symbol, MatchSymbol) \ 167 V(megamorphic_symbol, megamorphic_symbol, MegamorphicSymbol) \ 168 V(mega_dom_symbol, mega_dom_symbol, MegaDOMSymbol) \ 169 V(message_string, message_string, MessageString) \ 170 V(minus_Infinity_string, minus_Infinity_string, MinusInfinityString) \ 171 V(MinusZeroValue, minus_zero_value, MinusZero) \ 172 V(name_string, name_string, NameString) \ 173 V(NanValue, nan_value, Nan) \ 174 V(NaN_string, NaN_string, NaNString) \ 175 V(next_string, next_string, NextString) \ 176 V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \ 177 V(null_to_string, null_to_string, NullToString) \ 178 V(NullValue, null_value, Null) \ 179 V(number_string, number_string, NumberString) \ 180 V(number_to_string, number_to_string, NumberToString) \ 181 V(Object_string, Object_string, ObjectString) \ 182 V(object_to_string, object_to_string, ObjectToString) \ 183 V(OneByteStringMap, one_byte_string_map, OneByteStringMap) \ 184 V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap) \ 185 V(OnePointerFillerMap, one_pointer_filler_map, OnePointerFillerMap) \ 186 V(PromiseCapabilityMap, promise_capability_map, PromiseCapabilityMap) \ 187 V(promise_forwarding_handler_symbol, promise_forwarding_handler_symbol, \ 188 PromiseForwardingHandlerSymbol) \ 189 V(PromiseFulfillReactionJobTaskMap, promise_fulfill_reaction_job_task_map, \ 190 PromiseFulfillReactionJobTaskMap) \ 191 V(promise_handled_by_symbol, promise_handled_by_symbol, \ 192 PromiseHandledBySymbol) \ 193 V(PromiseReactionMap, promise_reaction_map, PromiseReactionMap) \ 194 V(PromiseRejectReactionJobTaskMap, promise_reject_reaction_job_task_map, \ 195 PromiseRejectReactionJobTaskMap) \ 196 V(PromiseResolveThenableJobTaskMap, promise_resolve_thenable_job_task_map, \ 197 PromiseResolveThenableJobTaskMap) \ 198 V(prototype_string, prototype_string, PrototypeString) \ 199 V(replace_symbol, replace_symbol, ReplaceSymbol) \ 200 V(regexp_to_string, regexp_to_string, RegexpToString) \ 201 V(resolve_string, resolve_string, ResolveString) \ 202 V(return_string, return_string, ReturnString) \ 203 V(search_symbol, search_symbol, SearchSymbol) \ 204 V(species_symbol, species_symbol, SpeciesSymbol) \ 205 V(StaleRegister, stale_register, StaleRegister) \ 206 V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \ 207 V(string_string, string_string, StringString) \ 208 V(string_to_string, string_to_string, StringToString) \ 209 V(StringMap, string_map, StringMap) \ 210 V(TheHoleValue, the_hole_value, TheHole) \ 211 V(then_string, then_string, ThenString) \ 212 V(toString_string, toString_string, ToStringString) \ 213 V(to_primitive_symbol, to_primitive_symbol, ToPrimitiveSymbol) \ 214 V(to_string_tag_symbol, to_string_tag_symbol, ToStringTagSymbol) \ 215 V(TrueValue, true_value, True) \ 216 V(undefined_to_string, undefined_to_string, UndefinedToString) \ 217 V(UndefinedValue, undefined_value, Undefined) \ 218 V(uninitialized_symbol, uninitialized_symbol, UninitializedSymbol) \ 219 V(valueOf_string, valueOf_string, ValueOfString) \ 220 V(wasm_wrapped_object_symbol, wasm_wrapped_object_symbol, \ 221 WasmWrappedObjectSymbol) \ 222 V(zero_string, zero_string, ZeroString) \ 223 UNIQUE_INSTANCE_TYPE_MAP_LIST_GENERATOR( \ 224 UNIQUE_INSTANCE_TYPE_IMMUTABLE_IMMOVABLE_MAP_ADAPTER, V) 225 226 #define HEAP_IMMOVABLE_OBJECT_LIST(V) \ 227 HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(V) \ 228 HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(V) 229 230 #ifdef DEBUG 231 #define CSA_CHECK(csa, x) \ 232 (csa)->Check([&]() -> TNode<BoolT> { return x; }, #x, __FILE__, __LINE__) 233 #else 234 #define CSA_CHECK(csa, x) (csa)->FastCheck(x) 235 #endif 236 237 #ifdef DEBUG 238 // CSA_DCHECK_ARGS generates an 239 // std::initializer_list<CodeStubAssembler::ExtraNode> from __VA_ARGS__. It 240 // currently supports between 0 and 2 arguments. 241 242 // clang-format off 243 #define CSA_DCHECK_0_ARGS(...) {} 244 #define CSA_DCHECK_1_ARG(a, ...) {{a, #a}} 245 #define CSA_DCHECK_2_ARGS(a, b, ...) {{a, #a}, {b, #b}} 246 // clang-format on 247 #define SWITCH_CSA_DCHECK_ARGS(dummy, a, b, FUNC, ...) FUNC(a, b) 248 #define CSA_DCHECK_ARGS(...) \ 249 CALL(SWITCH_CSA_DCHECK_ARGS, (, ##__VA_ARGS__, CSA_DCHECK_2_ARGS, \ 250 CSA_DCHECK_1_ARG, CSA_DCHECK_0_ARGS)) 251 // Workaround for MSVC to skip comma in empty __VA_ARGS__. 252 #define CALL(x, y) x y 253 254 // CSA_DCHECK(csa, <condition>, <extra values to print...>) 255 256 #define CSA_DCHECK(csa, condition_node, ...) \ 257 (csa)->Dcheck(condition_node, #condition_node, __FILE__, __LINE__, \ 258 CSA_DCHECK_ARGS(__VA_ARGS__)) 259 260 // CSA_DCHECK_BRANCH(csa, [](Label* ok, Label* not_ok) {...}, 261 // <extra values to print...>) 262 263 #define CSA_DCHECK_BRANCH(csa, gen, ...) \ 264 (csa)->Dcheck(gen, #gen, __FILE__, __LINE__, CSA_DCHECK_ARGS(__VA_ARGS__)) 265 266 #define CSA_DCHECK_JS_ARGC_OP(csa, Op, op, expected) \ 267 (csa)->Dcheck( \ 268 [&]() -> TNode<BoolT> { \ 269 const TNode<Word32T> argc = (csa)->UncheckedParameter<Word32T>( \ 270 Descriptor::kJSActualArgumentsCount); \ 271 return (csa)->Op(argc, \ 272 (csa)->Int32Constant(i::JSParameterCount(expected))); \ 273 }, \ 274 "argc " #op " " #expected, __FILE__, __LINE__, \ 275 {{SmiFromInt32((csa)->UncheckedParameter<Int32T>( \ 276 Descriptor::kJSActualArgumentsCount)), \ 277 "argc"}}) 278 279 #define CSA_DCHECK_JS_ARGC_EQ(csa, expected) \ 280 CSA_DCHECK_JS_ARGC_OP(csa, Word32Equal, ==, expected) 281 282 #define CSA_DEBUG_INFO(name) \ 283 { #name, __FILE__, __LINE__ } 284 #define BIND(label) Bind(label, CSA_DEBUG_INFO(label)) 285 #define TYPED_VARIABLE_DEF(type, name, ...) \ 286 TVariable<type> name(CSA_DEBUG_INFO(name), __VA_ARGS__) 287 #define TYPED_VARIABLE_CONSTRUCTOR(name, ...) \ 288 name(CSA_DEBUG_INFO(name), __VA_ARGS__) 289 #else // DEBUG 290 #define CSA_DCHECK(csa, ...) ((void)0) 291 #define CSA_DCHECK_BRANCH(csa, ...) ((void)0) 292 #define CSA_DCHECK_JS_ARGC_EQ(csa, expected) ((void)0) 293 #define BIND(label) Bind(label) 294 #define TYPED_VARIABLE_DEF(type, name, ...) TVariable<type> name(__VA_ARGS__) 295 #define TYPED_VARIABLE_CONSTRUCTOR(name, ...) name(__VA_ARGS__) 296 #endif // DEBUG 297 298 #define TVARIABLE(...) EXPAND(TYPED_VARIABLE_DEF(__VA_ARGS__, this)) 299 #define TVARIABLE_CONSTRUCTOR(...) \ 300 EXPAND(TYPED_VARIABLE_CONSTRUCTOR(__VA_ARGS__, this)) 301 302 #ifdef ENABLE_SLOW_DCHECKS 303 #define CSA_SLOW_DCHECK(csa, ...) \ 304 if (FLAG_enable_slow_asserts) { \ 305 CSA_DCHECK(csa, __VA_ARGS__); \ 306 } 307 #else 308 #define CSA_SLOW_DCHECK(csa, ...) ((void)0) 309 #endif 310 311 // Provides JavaScript-specific "macro-assembler" functionality on top of the 312 // CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler, 313 // it's possible to add JavaScript-specific useful CodeAssembler "macros" 314 // without modifying files in the compiler directory (and requiring a review 315 // from a compiler directory OWNER). 316 class V8_EXPORT_PRIVATE CodeStubAssembler 317 : public compiler::CodeAssembler, 318 public TorqueGeneratedExportedMacrosAssembler { 319 public: 320 using ScopedExceptionHandler = compiler::ScopedExceptionHandler; 321 322 template <typename T> 323 using LazyNode = std::function<TNode<T>()>; 324 325 explicit CodeStubAssembler(compiler::CodeAssemblerState* state); 326 327 enum class AllocationFlag : uint8_t { 328 kNone = 0, 329 kDoubleAlignment = 1, 330 kPretenured = 1 << 1, 331 kAllowLargeObjectAllocation = 1 << 2, 332 }; 333 334 enum SlackTrackingMode { kWithSlackTracking, kNoSlackTracking }; 335 336 using AllocationFlags = base::Flags<AllocationFlag>; 337 ParameterToIntPtr(TNode<Smi> value)338 TNode<IntPtrT> ParameterToIntPtr(TNode<Smi> value) { return SmiUntag(value); } ParameterToIntPtr(TNode<IntPtrT> value)339 TNode<IntPtrT> ParameterToIntPtr(TNode<IntPtrT> value) { return value; } ParameterToIntPtr(TNode<UintPtrT> value)340 TNode<IntPtrT> ParameterToIntPtr(TNode<UintPtrT> value) { 341 return Signed(value); 342 } 343 344 enum InitializationMode { 345 kUninitialized, 346 kInitializeToZero, 347 kInitializeToNull 348 }; 349 ParameterToTagged(TNode<Smi> value)350 TNode<Smi> ParameterToTagged(TNode<Smi> value) { return value; } 351 ParameterToTagged(TNode<IntPtrT> value)352 TNode<Smi> ParameterToTagged(TNode<IntPtrT> value) { return SmiTag(value); } 353 354 template <typename TIndex> 355 TNode<TIndex> TaggedToParameter(TNode<Smi> value); 356 ToParameterConstant(TNode<Smi> node,intptr_t * out)357 bool ToParameterConstant(TNode<Smi> node, intptr_t* out) { 358 if (TryToIntPtrConstant(node, out)) { 359 return true; 360 } 361 return false; 362 } 363 ToParameterConstant(TNode<IntPtrT> node,intptr_t * out)364 bool ToParameterConstant(TNode<IntPtrT> node, intptr_t* out) { 365 intptr_t constant; 366 if (TryToIntPtrConstant(node, &constant)) { 367 *out = constant; 368 return true; 369 } 370 return false; 371 } 372 373 #if defined(BINT_IS_SMI) BIntToSmi(TNode<BInt> source)374 TNode<Smi> BIntToSmi(TNode<BInt> source) { return source; } BIntToIntPtr(TNode<BInt> source)375 TNode<IntPtrT> BIntToIntPtr(TNode<BInt> source) { 376 return SmiToIntPtr(source); 377 } SmiToBInt(TNode<Smi> source)378 TNode<BInt> SmiToBInt(TNode<Smi> source) { return source; } IntPtrToBInt(TNode<IntPtrT> source)379 TNode<BInt> IntPtrToBInt(TNode<IntPtrT> source) { 380 return SmiFromIntPtr(source); 381 } 382 #elif defined(BINT_IS_INTPTR) BIntToSmi(TNode<BInt> source)383 TNode<Smi> BIntToSmi(TNode<BInt> source) { return SmiFromIntPtr(source); } BIntToIntPtr(TNode<BInt> source)384 TNode<IntPtrT> BIntToIntPtr(TNode<BInt> source) { return source; } SmiToBInt(TNode<Smi> source)385 TNode<BInt> SmiToBInt(TNode<Smi> source) { return SmiToIntPtr(source); } IntPtrToBInt(TNode<IntPtrT> source)386 TNode<BInt> IntPtrToBInt(TNode<IntPtrT> source) { return source; } 387 #else 388 #error Unknown architecture. 389 #endif 390 391 TNode<IntPtrT> TaggedIndexToIntPtr(TNode<TaggedIndex> value); 392 TNode<TaggedIndex> IntPtrToTaggedIndex(TNode<IntPtrT> value); 393 // TODO(v8:10047): Get rid of these convertions eventually. 394 TNode<Smi> TaggedIndexToSmi(TNode<TaggedIndex> value); 395 TNode<TaggedIndex> SmiToTaggedIndex(TNode<Smi> value); 396 397 // Pointer compression specific. Ensures that the upper 32 bits of a Smi 398 // contain the sign of a lower 32 bits so that the Smi can be directly used 399 // as an index in element offset computation. 400 TNode<Smi> NormalizeSmiIndex(TNode<Smi> smi_index); 401 TaggedToSmi(TNode<Object> value,Label * fail)402 TNode<Smi> TaggedToSmi(TNode<Object> value, Label* fail) { 403 GotoIf(TaggedIsNotSmi(value), fail); 404 return UncheckedCast<Smi>(value); 405 } 406 TaggedToPositiveSmi(TNode<Object> value,Label * fail)407 TNode<Smi> TaggedToPositiveSmi(TNode<Object> value, Label* fail) { 408 GotoIfNot(TaggedIsPositiveSmi(value), fail); 409 return UncheckedCast<Smi>(value); 410 } 411 412 TNode<String> TaggedToDirectString(TNode<Object> value, Label* fail); 413 TaggedToHeapObject(TNode<Object> value,Label * fail)414 TNode<HeapObject> TaggedToHeapObject(TNode<Object> value, Label* fail) { 415 GotoIf(TaggedIsSmi(value), fail); 416 return UncheckedCast<HeapObject>(value); 417 } 418 Uint16Constant(uint16_t t)419 TNode<Uint16T> Uint16Constant(uint16_t t) { 420 return UncheckedCast<Uint16T>(Int32Constant(t)); 421 } 422 HeapObjectToJSDataView(TNode<HeapObject> heap_object,Label * fail)423 TNode<JSDataView> HeapObjectToJSDataView(TNode<HeapObject> heap_object, 424 Label* fail) { 425 GotoIfNot(IsJSDataView(heap_object), fail); 426 return CAST(heap_object); 427 } 428 HeapObjectToJSProxy(TNode<HeapObject> heap_object,Label * fail)429 TNode<JSProxy> HeapObjectToJSProxy(TNode<HeapObject> heap_object, 430 Label* fail) { 431 GotoIfNot(IsJSProxy(heap_object), fail); 432 return CAST(heap_object); 433 } 434 HeapObjectToJSStringIterator(TNode<HeapObject> heap_object,Label * fail)435 TNode<JSStringIterator> HeapObjectToJSStringIterator( 436 TNode<HeapObject> heap_object, Label* fail) { 437 GotoIfNot(IsJSStringIterator(heap_object), fail); 438 return CAST(heap_object); 439 } 440 HeapObjectToCallable(TNode<HeapObject> heap_object,Label * fail)441 TNode<JSReceiver> HeapObjectToCallable(TNode<HeapObject> heap_object, 442 Label* fail) { 443 GotoIfNot(IsCallable(heap_object), fail); 444 return CAST(heap_object); 445 } 446 HeapObjectToString(TNode<HeapObject> heap_object,Label * fail)447 TNode<String> HeapObjectToString(TNode<HeapObject> heap_object, Label* fail) { 448 GotoIfNot(IsString(heap_object), fail); 449 return CAST(heap_object); 450 } 451 HeapObjectToConstructor(TNode<HeapObject> heap_object,Label * fail)452 TNode<JSReceiver> HeapObjectToConstructor(TNode<HeapObject> heap_object, 453 Label* fail) { 454 GotoIfNot(IsConstructor(heap_object), fail); 455 return CAST(heap_object); 456 } 457 HeapObjectToJSFunctionWithPrototypeSlot(TNode<HeapObject> heap_object,Label * fail)458 TNode<JSFunction> HeapObjectToJSFunctionWithPrototypeSlot( 459 TNode<HeapObject> heap_object, Label* fail) { 460 GotoIfNot(IsJSFunctionWithPrototypeSlot(heap_object), fail); 461 return CAST(heap_object); 462 } 463 464 template <typename T> RunLazy(LazyNode<T> lazy)465 TNode<T> RunLazy(LazyNode<T> lazy) { 466 return lazy(); 467 } 468 469 #define PARAMETER_BINOP(OpName, IntPtrOpName, SmiOpName) \ 470 TNode<Smi> OpName(TNode<Smi> a, TNode<Smi> b) { return SmiOpName(a, b); } \ 471 TNode<IntPtrT> OpName(TNode<IntPtrT> a, TNode<IntPtrT> b) { \ 472 return IntPtrOpName(a, b); \ 473 } \ 474 TNode<UintPtrT> OpName(TNode<UintPtrT> a, TNode<UintPtrT> b) { \ 475 return Unsigned(IntPtrOpName(Signed(a), Signed(b))); \ 476 } \ 477 TNode<RawPtrT> OpName(TNode<RawPtrT> a, TNode<RawPtrT> b) { \ 478 return ReinterpretCast<RawPtrT>(IntPtrOpName( \ 479 ReinterpretCast<IntPtrT>(a), ReinterpretCast<IntPtrT>(b))); \ 480 } 481 // TODO(v8:9708): Define BInt operations once all uses are ported. PARAMETER_BINOP(IntPtrOrSmiAdd,IntPtrAdd,SmiAdd)482 PARAMETER_BINOP(IntPtrOrSmiAdd, IntPtrAdd, SmiAdd) 483 PARAMETER_BINOP(IntPtrOrSmiSub, IntPtrSub, SmiSub) 484 #undef PARAMETER_BINOP 485 486 #define PARAMETER_BINOP(OpName, IntPtrOpName, SmiOpName) \ 487 TNode<BoolT> OpName(TNode<Smi> a, TNode<Smi> b) { return SmiOpName(a, b); } \ 488 TNode<BoolT> OpName(TNode<IntPtrT> a, TNode<IntPtrT> b) { \ 489 return IntPtrOpName(a, b); \ 490 } \ 491 TNode<BoolT> OpName(TNode<UintPtrT> a, TNode<UintPtrT> b) { \ 492 return IntPtrOpName(Signed(a), Signed(b)); \ 493 } \ 494 TNode<BoolT> OpName(TNode<RawPtrT> a, TNode<RawPtrT> b) { \ 495 return IntPtrOpName(a, b); \ 496 } 497 // TODO(v8:9708): Define BInt operations once all uses are ported. 498 PARAMETER_BINOP(IntPtrOrSmiEqual, WordEqual, SmiEqual) 499 PARAMETER_BINOP(IntPtrOrSmiNotEqual, WordNotEqual, SmiNotEqual) 500 PARAMETER_BINOP(IntPtrOrSmiLessThanOrEqual, IntPtrLessThanOrEqual, 501 SmiLessThanOrEqual) 502 PARAMETER_BINOP(IntPtrOrSmiGreaterThan, IntPtrGreaterThan, SmiGreaterThan) 503 PARAMETER_BINOP(UintPtrOrSmiLessThan, UintPtrLessThan, SmiBelow) 504 PARAMETER_BINOP(UintPtrOrSmiGreaterThanOrEqual, UintPtrGreaterThanOrEqual, 505 SmiAboveOrEqual) 506 #undef PARAMETER_BINOP 507 508 uintptr_t ConstexprUintPtrShl(uintptr_t a, int32_t b) { return a << b; } ConstexprUintPtrShr(uintptr_t a,int32_t b)509 uintptr_t ConstexprUintPtrShr(uintptr_t a, int32_t b) { return a >> b; } ConstexprIntPtrAdd(intptr_t a,intptr_t b)510 intptr_t ConstexprIntPtrAdd(intptr_t a, intptr_t b) { return a + b; } ConstexprUintPtrAdd(uintptr_t a,uintptr_t b)511 uintptr_t ConstexprUintPtrAdd(uintptr_t a, uintptr_t b) { return a + b; } ConstexprWordNot(intptr_t a)512 intptr_t ConstexprWordNot(intptr_t a) { return ~a; } ConstexprWordNot(uintptr_t a)513 uintptr_t ConstexprWordNot(uintptr_t a) { return ~a; } 514 TaggedEqual(TNode<AnyTaggedT> a,TNode<AnyTaggedT> b)515 TNode<BoolT> TaggedEqual(TNode<AnyTaggedT> a, TNode<AnyTaggedT> b) { 516 if (COMPRESS_POINTERS_BOOL) { 517 return Word32Equal(ReinterpretCast<Word32T>(a), 518 ReinterpretCast<Word32T>(b)); 519 } else { 520 return WordEqual(ReinterpretCast<WordT>(a), ReinterpretCast<WordT>(b)); 521 } 522 } 523 TaggedNotEqual(TNode<AnyTaggedT> a,TNode<AnyTaggedT> b)524 TNode<BoolT> TaggedNotEqual(TNode<AnyTaggedT> a, TNode<AnyTaggedT> b) { 525 return Word32BinaryNot(TaggedEqual(a, b)); 526 } 527 528 TNode<Smi> NoContextConstant(); 529 530 #define HEAP_CONSTANT_ACCESSOR(rootIndexName, rootAccessorName, name) \ 531 TNode<std::remove_pointer<std::remove_reference<decltype( \ 532 std::declval<ReadOnlyRoots>().rootAccessorName())>::type>::type> \ 533 name##Constant(); 534 HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_ACCESSOR) 535 #undef HEAP_CONSTANT_ACCESSOR 536 537 #define HEAP_CONSTANT_ACCESSOR(rootIndexName, rootAccessorName, name) \ 538 TNode<std::remove_pointer<std::remove_reference<decltype( \ 539 std::declval<Heap>().rootAccessorName())>::type>::type> \ 540 name##Constant(); 541 HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_ACCESSOR) 542 #undef HEAP_CONSTANT_ACCESSOR 543 544 #define HEAP_CONSTANT_TEST(rootIndexName, rootAccessorName, name) \ 545 TNode<BoolT> Is##name(TNode<Object> value); \ 546 TNode<BoolT> IsNot##name(TNode<Object> value); 547 HEAP_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_TEST) 548 #undef HEAP_CONSTANT_TEST 549 550 TNode<BInt> BIntConstant(int value); 551 552 template <typename TIndex> 553 TNode<TIndex> IntPtrOrSmiConstant(int value); 554 555 bool TryGetIntPtrOrSmiConstantValue(TNode<Smi> maybe_constant, int* value); 556 bool TryGetIntPtrOrSmiConstantValue(TNode<IntPtrT> maybe_constant, 557 int* value); 558 559 TNode<IntPtrT> PopulationCountFallback(TNode<UintPtrT> value); 560 TNode<Int64T> PopulationCount64(TNode<Word64T> value); 561 TNode<Int32T> PopulationCount32(TNode<Word32T> value); 562 TNode<Int64T> CountTrailingZeros64(TNode<Word64T> value); 563 TNode<Int32T> CountTrailingZeros32(TNode<Word32T> value); 564 TNode<Int64T> CountLeadingZeros64(TNode<Word64T> value); 565 TNode<Int32T> CountLeadingZeros32(TNode<Word32T> value); 566 567 // Round the 32bits payload of the provided word up to the next power of two. 568 TNode<IntPtrT> IntPtrRoundUpToPowerOfTwo32(TNode<IntPtrT> value); 569 // Select the maximum of the two provided IntPtr values. 570 TNode<IntPtrT> IntPtrMax(TNode<IntPtrT> left, TNode<IntPtrT> right); 571 // Select the minimum of the two provided IntPtr values. 572 TNode<IntPtrT> IntPtrMin(TNode<IntPtrT> left, TNode<IntPtrT> right); 573 TNode<UintPtrT> UintPtrMin(TNode<UintPtrT> left, TNode<UintPtrT> right); 574 575 // Float64 operations. 576 TNode<Float64T> Float64Ceil(TNode<Float64T> x); 577 TNode<Float64T> Float64Floor(TNode<Float64T> x); 578 TNode<Float64T> Float64Round(TNode<Float64T> x); 579 TNode<Float64T> Float64RoundToEven(TNode<Float64T> x); 580 TNode<Float64T> Float64Trunc(TNode<Float64T> x); 581 // Select the minimum of the two provided Number values. 582 TNode<Number> NumberMax(TNode<Number> left, TNode<Number> right); 583 // Select the minimum of the two provided Number values. 584 TNode<Number> NumberMin(TNode<Number> left, TNode<Number> right); 585 586 // Returns true iff the given value fits into smi range and is >= 0. 587 TNode<BoolT> IsValidPositiveSmi(TNode<IntPtrT> value); 588 589 // Tag an IntPtr as a Smi value. 590 TNode<Smi> SmiTag(TNode<IntPtrT> value); 591 // Untag a Smi value as an IntPtr. 592 TNode<IntPtrT> SmiUntag(TNode<Smi> value); 593 594 // Smi conversions. 595 TNode<Float64T> SmiToFloat64(TNode<Smi> value); SmiFromIntPtr(TNode<IntPtrT> value)596 TNode<Smi> SmiFromIntPtr(TNode<IntPtrT> value) { return SmiTag(value); } 597 TNode<Smi> SmiFromInt32(TNode<Int32T> value); 598 TNode<Smi> SmiFromUint32(TNode<Uint32T> value); SmiToIntPtr(TNode<Smi> value)599 TNode<IntPtrT> SmiToIntPtr(TNode<Smi> value) { return SmiUntag(value); } 600 TNode<Int32T> SmiToInt32(TNode<Smi> value); 601 602 // Smi operations. 603 #define SMI_ARITHMETIC_BINOP(SmiOpName, IntPtrOpName, Int32OpName) \ 604 TNode<Smi> SmiOpName(TNode<Smi> a, TNode<Smi> b) { \ 605 if (SmiValuesAre32Bits()) { \ 606 return BitcastWordToTaggedSigned( \ 607 IntPtrOpName(BitcastTaggedToWordForTagAndSmiBits(a), \ 608 BitcastTaggedToWordForTagAndSmiBits(b))); \ 609 } else { \ 610 DCHECK(SmiValuesAre31Bits()); \ 611 return BitcastWordToTaggedSigned(ChangeInt32ToIntPtr(Int32OpName( \ 612 TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(a)), \ 613 TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(b))))); \ 614 } \ 615 } 616 SMI_ARITHMETIC_BINOP(SmiAdd, IntPtrAdd, Int32Add) 617 SMI_ARITHMETIC_BINOP(SmiSub, IntPtrSub, Int32Sub) 618 SMI_ARITHMETIC_BINOP(SmiAnd, WordAnd, Word32And) 619 SMI_ARITHMETIC_BINOP(SmiOr, WordOr, Word32Or) 620 SMI_ARITHMETIC_BINOP(SmiXor, WordXor, Word32Xor) 621 #undef SMI_ARITHMETIC_BINOP 622 623 TNode<IntPtrT> TryIntPtrAdd(TNode<IntPtrT> a, TNode<IntPtrT> b, 624 Label* if_overflow); 625 TNode<IntPtrT> TryIntPtrSub(TNode<IntPtrT> a, TNode<IntPtrT> b, 626 Label* if_overflow); 627 TNode<Int32T> TryInt32Mul(TNode<Int32T> a, TNode<Int32T> b, 628 Label* if_overflow); 629 TNode<Smi> TrySmiAdd(TNode<Smi> a, TNode<Smi> b, Label* if_overflow); 630 TNode<Smi> TrySmiSub(TNode<Smi> a, TNode<Smi> b, Label* if_overflow); 631 TNode<Smi> TrySmiAbs(TNode<Smi> a, Label* if_overflow); 632 SmiShl(TNode<Smi> a,int shift)633 TNode<Smi> SmiShl(TNode<Smi> a, int shift) { 634 TNode<Smi> result = BitcastWordToTaggedSigned( 635 WordShl(BitcastTaggedToWordForTagAndSmiBits(a), shift)); 636 // Smi shift have different result to int32 shift when the inputs are not 637 // strictly limited. The CSA_DCHECK is to ensure valid inputs. 638 CSA_DCHECK( 639 this, TaggedEqual(result, BitwiseOp(SmiToInt32(a), Int32Constant(shift), 640 Operation::kShiftLeft))); 641 return result; 642 } 643 SmiShr(TNode<Smi> a,int shift)644 TNode<Smi> SmiShr(TNode<Smi> a, int shift) { 645 TNode<Smi> result; 646 if (kTaggedSize == kInt64Size) { 647 result = BitcastWordToTaggedSigned( 648 WordAnd(WordShr(BitcastTaggedToWordForTagAndSmiBits(a), shift), 649 BitcastTaggedToWordForTagAndSmiBits(SmiConstant(-1)))); 650 } else { 651 // For pointer compressed Smis, we want to make sure that we truncate to 652 // int32 before shifting, to avoid the values of the top 32-bits from 653 // leaking into the sign bit of the smi. 654 result = BitcastWordToTaggedSigned(WordAnd( 655 ChangeInt32ToIntPtr(Word32Shr( 656 TruncateWordToInt32(BitcastTaggedToWordForTagAndSmiBits(a)), 657 shift)), 658 BitcastTaggedToWordForTagAndSmiBits(SmiConstant(-1)))); 659 } 660 // Smi shift have different result to int32 shift when the inputs are not 661 // strictly limited. The CSA_DCHECK is to ensure valid inputs. 662 CSA_DCHECK( 663 this, TaggedEqual(result, BitwiseOp(SmiToInt32(a), Int32Constant(shift), 664 Operation::kShiftRightLogical))); 665 return result; 666 } 667 SmiSar(TNode<Smi> a,int shift)668 TNode<Smi> SmiSar(TNode<Smi> a, int shift) { 669 // The number of shift bits is |shift % 64| for 64-bits value and |shift % 670 // 32| for 32-bits value. The DCHECK is to ensure valid inputs. 671 DCHECK_LT(shift, 32); 672 if (kTaggedSize == kInt64Size) { 673 return BitcastWordToTaggedSigned( 674 WordAnd(WordSar(BitcastTaggedToWordForTagAndSmiBits(a), shift), 675 BitcastTaggedToWordForTagAndSmiBits(SmiConstant(-1)))); 676 } else { 677 // For pointer compressed Smis, we want to make sure that we truncate to 678 // int32 before shifting, to avoid the values of the top 32-bits from 679 // changing the sign bit of the smi. 680 return BitcastWordToTaggedSigned(WordAnd( 681 ChangeInt32ToIntPtr(Word32Sar( 682 TruncateWordToInt32(BitcastTaggedToWordForTagAndSmiBits(a)), 683 shift)), 684 BitcastTaggedToWordForTagAndSmiBits(SmiConstant(-1)))); 685 } 686 } 687 WordOrSmiShr(TNode<Smi> a,int shift)688 TNode<Smi> WordOrSmiShr(TNode<Smi> a, int shift) { return SmiShr(a, shift); } 689 WordOrSmiShr(TNode<IntPtrT> a,int shift)690 TNode<IntPtrT> WordOrSmiShr(TNode<IntPtrT> a, int shift) { 691 return WordShr(a, shift); 692 } 693 694 #define SMI_COMPARISON_OP(SmiOpName, IntPtrOpName, Int32OpName) \ 695 TNode<BoolT> SmiOpName(TNode<Smi> a, TNode<Smi> b) { \ 696 if (kTaggedSize == kInt64Size) { \ 697 return IntPtrOpName(BitcastTaggedToWordForTagAndSmiBits(a), \ 698 BitcastTaggedToWordForTagAndSmiBits(b)); \ 699 } else { \ 700 DCHECK_EQ(kTaggedSize, kInt32Size); \ 701 DCHECK(SmiValuesAre31Bits()); \ 702 return Int32OpName( \ 703 TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(a)), \ 704 TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(b))); \ 705 } \ 706 } 707 SMI_COMPARISON_OP(SmiEqual, WordEqual, Word32Equal) 708 SMI_COMPARISON_OP(SmiNotEqual, WordNotEqual, Word32NotEqual) 709 SMI_COMPARISON_OP(SmiAbove, UintPtrGreaterThan, Uint32GreaterThan) 710 SMI_COMPARISON_OP(SmiAboveOrEqual, UintPtrGreaterThanOrEqual, 711 Uint32GreaterThanOrEqual) 712 SMI_COMPARISON_OP(SmiBelow, UintPtrLessThan, Uint32LessThan) 713 SMI_COMPARISON_OP(SmiLessThan, IntPtrLessThan, Int32LessThan) 714 SMI_COMPARISON_OP(SmiLessThanOrEqual, IntPtrLessThanOrEqual, 715 Int32LessThanOrEqual) 716 SMI_COMPARISON_OP(SmiGreaterThan, IntPtrGreaterThan, Int32GreaterThan) 717 SMI_COMPARISON_OP(SmiGreaterThanOrEqual, IntPtrGreaterThanOrEqual, 718 Int32GreaterThanOrEqual) 719 #undef SMI_COMPARISON_OP 720 TNode<Smi> SmiMax(TNode<Smi> a, TNode<Smi> b); 721 TNode<Smi> SmiMin(TNode<Smi> a, TNode<Smi> b); 722 // Computes a % b for Smi inputs a and b; result is not necessarily a Smi. 723 TNode<Number> SmiMod(TNode<Smi> a, TNode<Smi> b); 724 // Computes a * b for Smi inputs a and b; result is not necessarily a Smi. 725 TNode<Number> SmiMul(TNode<Smi> a, TNode<Smi> b); 726 // Tries to compute dividend / divisor for Smi inputs; branching to bailout 727 // if the division needs to be performed as a floating point operation. 728 TNode<Smi> TrySmiDiv(TNode<Smi> dividend, TNode<Smi> divisor, Label* bailout); 729 730 // Compares two Smis a and b as if they were converted to strings and then 731 // compared lexicographically. Returns: 732 // -1 iff x < y. 733 // 0 iff x == y. 734 // 1 iff x > y. 735 TNode<Smi> SmiLexicographicCompare(TNode<Smi> x, TNode<Smi> y); 736 737 #ifdef BINT_IS_SMI 738 #define BINT_COMPARISON_OP(BIntOpName, SmiOpName, IntPtrOpName) \ 739 TNode<BoolT> BIntOpName(TNode<BInt> a, TNode<BInt> b) { \ 740 return SmiOpName(a, b); \ 741 } 742 #else 743 #define BINT_COMPARISON_OP(BIntOpName, SmiOpName, IntPtrOpName) \ 744 TNode<BoolT> BIntOpName(TNode<BInt> a, TNode<BInt> b) { \ 745 return IntPtrOpName(a, b); \ 746 } 747 #endif 748 BINT_COMPARISON_OP(BIntEqual, SmiEqual, WordEqual) 749 BINT_COMPARISON_OP(BIntNotEqual, SmiNotEqual, WordNotEqual) 750 BINT_COMPARISON_OP(BIntAbove, SmiAbove, UintPtrGreaterThan) 751 BINT_COMPARISON_OP(BIntAboveOrEqual, SmiAboveOrEqual, 752 UintPtrGreaterThanOrEqual) 753 BINT_COMPARISON_OP(BIntBelow, SmiBelow, UintPtrLessThan) 754 BINT_COMPARISON_OP(BIntLessThan, SmiLessThan, IntPtrLessThan) 755 BINT_COMPARISON_OP(BIntLessThanOrEqual, SmiLessThanOrEqual, 756 IntPtrLessThanOrEqual) 757 BINT_COMPARISON_OP(BIntGreaterThan, SmiGreaterThan, IntPtrGreaterThan) 758 BINT_COMPARISON_OP(BIntGreaterThanOrEqual, SmiGreaterThanOrEqual, 759 IntPtrGreaterThanOrEqual) 760 #undef BINT_COMPARISON_OP 761 762 // Smi | HeapNumber operations. 763 TNode<Number> NumberInc(TNode<Number> value); 764 TNode<Number> NumberDec(TNode<Number> value); 765 TNode<Number> NumberAdd(TNode<Number> a, TNode<Number> b); 766 TNode<Number> NumberSub(TNode<Number> a, TNode<Number> b); 767 void GotoIfNotNumber(TNode<Object> value, Label* is_not_number); 768 void GotoIfNumber(TNode<Object> value, Label* is_number); SmiToNumber(TNode<Smi> v)769 TNode<Number> SmiToNumber(TNode<Smi> v) { return v; } 770 771 TNode<Number> BitwiseOp(TNode<Word32T> left32, TNode<Word32T> right32, 772 Operation bitwise_op); 773 TNode<Number> BitwiseSmiOp(TNode<Smi> left32, TNode<Smi> right32, 774 Operation bitwise_op); 775 776 // Allocate an object of the given size. 777 TNode<HeapObject> AllocateInNewSpace( 778 TNode<IntPtrT> size, AllocationFlags flags = AllocationFlag::kNone); 779 TNode<HeapObject> AllocateInNewSpace( 780 int size, AllocationFlags flags = AllocationFlag::kNone); 781 TNode<HeapObject> Allocate(TNode<IntPtrT> size, 782 AllocationFlags flags = AllocationFlag::kNone); 783 784 TNode<HeapObject> Allocate(int size, 785 AllocationFlags flags = AllocationFlag::kNone); 786 787 TNode<BoolT> IsRegularHeapObjectSize(TNode<IntPtrT> size); 788 789 using BranchGenerator = std::function<void(Label*, Label*)>; 790 template <typename T> 791 using NodeGenerator = std::function<TNode<T>()>; 792 using ExtraNode = std::pair<TNode<Object>, const char*>; 793 794 void Dcheck(const BranchGenerator& branch, const char* message, 795 const char* file, int line, 796 std::initializer_list<ExtraNode> extra_nodes = {}); 797 void Dcheck(const NodeGenerator<BoolT>& condition_body, const char* message, 798 const char* file, int line, 799 std::initializer_list<ExtraNode> extra_nodes = {}); 800 void Dcheck(TNode<Word32T> condition_node, const char* message, 801 const char* file, int line, 802 std::initializer_list<ExtraNode> extra_nodes = {}); 803 void Check(const BranchGenerator& branch, const char* message, 804 const char* file, int line, 805 std::initializer_list<ExtraNode> extra_nodes = {}); 806 void Check(const NodeGenerator<BoolT>& condition_body, const char* message, 807 const char* file, int line, 808 std::initializer_list<ExtraNode> extra_nodes = {}); 809 void Check(TNode<Word32T> condition_node, const char* message, 810 const char* file, int line, 811 std::initializer_list<ExtraNode> extra_nodes = {}); 812 void FailAssert(const char* message, 813 const std::vector<FileAndLine>& files_and_lines, 814 std::initializer_list<ExtraNode> extra_nodes = {}); 815 816 void FastCheck(TNode<BoolT> condition); 817 IsCodeTMap(TNode<Map> map)818 TNode<BoolT> IsCodeTMap(TNode<Map> map) { 819 return V8_EXTERNAL_CODE_SPACE_BOOL ? IsCodeDataContainerMap(map) 820 : IsCodeMap(map); 821 } IsCodeT(TNode<HeapObject> object)822 TNode<BoolT> IsCodeT(TNode<HeapObject> object) { 823 return IsCodeTMap(LoadMap(object)); 824 } 825 826 // TODO(v8:11880): remove once Code::bytecode_or_interpreter_data field 827 // is cached in or moved to CodeT. FromCodeT(TNode<CodeT> code)828 TNode<Code> FromCodeT(TNode<CodeT> code) { 829 #ifdef V8_EXTERNAL_CODE_SPACE 830 #if V8_TARGET_BIG_ENDIAN 831 #error "This code requires updating for big-endian architectures" 832 #endif 833 // Given the fields layout we can read the Code reference as a full word. 834 STATIC_ASSERT(CodeDataContainer::kCodeCageBaseUpper32BitsOffset == 835 CodeDataContainer::kCodeOffset + kTaggedSize); 836 TNode<Object> o = BitcastWordToTagged(Load<RawPtrT>( 837 code, IntPtrConstant(CodeDataContainer::kCodeOffset - kHeapObjectTag))); 838 return CAST(o); 839 #else 840 return code; 841 #endif 842 } 843 CodeDataContainerFromCodeT(TNode<CodeT> code)844 TNode<CodeDataContainer> CodeDataContainerFromCodeT(TNode<CodeT> code) { 845 #ifdef V8_EXTERNAL_CODE_SPACE 846 return code; 847 #else 848 return LoadObjectField<CodeDataContainer>(code, 849 Code::kCodeDataContainerOffset); 850 #endif 851 } 852 ToCodeT(TNode<Code> code)853 TNode<CodeT> ToCodeT(TNode<Code> code) { 854 #ifdef V8_EXTERNAL_CODE_SPACE 855 return LoadObjectField<CodeDataContainer>(code, 856 Code::kCodeDataContainerOffset); 857 #else 858 return code; 859 #endif 860 } 861 ToCodeT(TNode<Code> code,TNode<CodeDataContainer> code_data_container)862 TNode<CodeT> ToCodeT(TNode<Code> code, 863 TNode<CodeDataContainer> code_data_container) { 864 #ifdef V8_EXTERNAL_CODE_SPACE 865 return code_data_container; 866 #else 867 return code; 868 #endif 869 } 870 871 TNode<RawPtrT> GetCodeEntry(TNode<CodeT> code); 872 873 // The following Call wrappers call an object according to the semantics that 874 // one finds in the EcmaScript spec, operating on an Callable (e.g. a 875 // JSFunction or proxy) rather than a Code object. 876 template <class... TArgs> Call(TNode<Context> context,TNode<Object> callable,TNode<JSReceiver> receiver,TArgs...args)877 TNode<Object> Call(TNode<Context> context, TNode<Object> callable, 878 TNode<JSReceiver> receiver, TArgs... args) { 879 return CallJS( 880 CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined), 881 context, callable, receiver, args...); 882 } 883 template <class... TArgs> Call(TNode<Context> context,TNode<Object> callable,TNode<Object> receiver,TArgs...args)884 TNode<Object> Call(TNode<Context> context, TNode<Object> callable, 885 TNode<Object> receiver, TArgs... args) { 886 if (IsUndefinedConstant(receiver) || IsNullConstant(receiver)) { 887 return CallJS( 888 CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined), 889 context, callable, receiver, args...); 890 } 891 return CallJS(CodeFactory::Call(isolate()), context, callable, receiver, 892 args...); 893 } 894 895 TNode<Object> CallApiCallback(TNode<Object> context, TNode<RawPtrT> callback, 896 TNode<IntPtrT> argc, TNode<Object> data, 897 TNode<Object> holder, TNode<Object> receiver); 898 899 TNode<Object> CallApiCallback(TNode<Object> context, TNode<RawPtrT> callback, 900 TNode<IntPtrT> argc, TNode<Object> data, 901 TNode<Object> holder, TNode<Object> receiver, 902 TNode<Object> value); 903 904 TNode<Object> CallRuntimeNewArray(TNode<Context> context, 905 TNode<Object> receiver, 906 TNode<Object> length, 907 TNode<Object> new_target, 908 TNode<Object> allocation_site); 909 910 void TailCallRuntimeNewArray(TNode<Context> context, TNode<Object> receiver, 911 TNode<Object> length, TNode<Object> new_target, 912 TNode<Object> allocation_site); 913 914 template <class... TArgs> ConstructWithTarget(TNode<Context> context,TNode<JSReceiver> target,TNode<JSReceiver> new_target,TArgs...args)915 TNode<JSReceiver> ConstructWithTarget(TNode<Context> context, 916 TNode<JSReceiver> target, 917 TNode<JSReceiver> new_target, 918 TArgs... args) { 919 return CAST(ConstructJSWithTarget(CodeFactory::Construct(isolate()), 920 context, target, new_target, 921 implicit_cast<TNode<Object>>(args)...)); 922 } 923 template <class... TArgs> Construct(TNode<Context> context,TNode<JSReceiver> new_target,TArgs...args)924 TNode<JSReceiver> Construct(TNode<Context> context, 925 TNode<JSReceiver> new_target, TArgs... args) { 926 return ConstructWithTarget(context, new_target, new_target, args...); 927 } 928 929 template <typename T> Select(TNode<BoolT> condition,const NodeGenerator<T> & true_body,const NodeGenerator<T> & false_body)930 TNode<T> Select(TNode<BoolT> condition, const NodeGenerator<T>& true_body, 931 const NodeGenerator<T>& false_body) { 932 TVARIABLE(T, value); 933 Label vtrue(this), vfalse(this), end(this); 934 Branch(condition, &vtrue, &vfalse); 935 936 BIND(&vtrue); 937 { 938 value = true_body(); 939 Goto(&end); 940 } 941 BIND(&vfalse); 942 { 943 value = false_body(); 944 Goto(&end); 945 } 946 947 BIND(&end); 948 return value.value(); 949 } 950 951 template <class A> SelectConstant(TNode<BoolT> condition,TNode<A> true_value,TNode<A> false_value)952 TNode<A> SelectConstant(TNode<BoolT> condition, TNode<A> true_value, 953 TNode<A> false_value) { 954 return Select<A>( 955 condition, [=] { return true_value; }, [=] { return false_value; }); 956 } 957 958 TNode<Int32T> SelectInt32Constant(TNode<BoolT> condition, int true_value, 959 int false_value); 960 TNode<IntPtrT> SelectIntPtrConstant(TNode<BoolT> condition, int true_value, 961 int false_value); 962 TNode<Oddball> SelectBooleanConstant(TNode<BoolT> condition); 963 TNode<Smi> SelectSmiConstant(TNode<BoolT> condition, Smi true_value, 964 Smi false_value); SelectSmiConstant(TNode<BoolT> condition,int true_value,Smi false_value)965 TNode<Smi> SelectSmiConstant(TNode<BoolT> condition, int true_value, 966 Smi false_value) { 967 return SelectSmiConstant(condition, Smi::FromInt(true_value), false_value); 968 } SelectSmiConstant(TNode<BoolT> condition,Smi true_value,int false_value)969 TNode<Smi> SelectSmiConstant(TNode<BoolT> condition, Smi true_value, 970 int false_value) { 971 return SelectSmiConstant(condition, true_value, Smi::FromInt(false_value)); 972 } SelectSmiConstant(TNode<BoolT> condition,int true_value,int false_value)973 TNode<Smi> SelectSmiConstant(TNode<BoolT> condition, int true_value, 974 int false_value) { 975 return SelectSmiConstant(condition, Smi::FromInt(true_value), 976 Smi::FromInt(false_value)); 977 } 978 SingleCharacterStringConstant(char const * single_char)979 TNode<String> SingleCharacterStringConstant(char const* single_char) { 980 DCHECK_EQ(strlen(single_char), 1); 981 return HeapConstant( 982 isolate()->factory()->LookupSingleCharacterStringFromCode( 983 single_char[0])); 984 } 985 986 TNode<Int32T> TruncateWordToInt32(TNode<WordT> value); 987 TNode<Int32T> TruncateIntPtrToInt32(TNode<IntPtrT> value); 988 989 // Check a value for smi-ness 990 TNode<BoolT> TaggedIsSmi(TNode<MaybeObject> a); 991 TNode<BoolT> TaggedIsNotSmi(TNode<MaybeObject> a); 992 993 // Check that the value is a non-negative smi. 994 TNode<BoolT> TaggedIsPositiveSmi(TNode<Object> a); 995 // Check that a word has a word-aligned address. 996 TNode<BoolT> WordIsAligned(TNode<WordT> word, size_t alignment); 997 TNode<BoolT> WordIsPowerOfTwo(TNode<IntPtrT> value); 998 999 // Check if lower_limit <= value <= higher_limit. 1000 template <typename U> IsInRange(TNode<Word32T> value,U lower_limit,U higher_limit)1001 TNode<BoolT> IsInRange(TNode<Word32T> value, U lower_limit, U higher_limit) { 1002 DCHECK_LE(lower_limit, higher_limit); 1003 STATIC_ASSERT(sizeof(U) <= kInt32Size); 1004 return Uint32LessThanOrEqual(Int32Sub(value, Int32Constant(lower_limit)), 1005 Int32Constant(higher_limit - lower_limit)); 1006 } 1007 IsInRange(TNode<WordT> value,intptr_t lower_limit,intptr_t higher_limit)1008 TNode<BoolT> IsInRange(TNode<WordT> value, intptr_t lower_limit, 1009 intptr_t higher_limit) { 1010 DCHECK_LE(lower_limit, higher_limit); 1011 return UintPtrLessThanOrEqual(IntPtrSub(value, IntPtrConstant(lower_limit)), 1012 IntPtrConstant(higher_limit - lower_limit)); 1013 } 1014 1015 #if DEBUG 1016 void Bind(Label* label, AssemblerDebugInfo debug_info); 1017 #endif // DEBUG 1018 void Bind(Label* label); 1019 1020 template <class... T> Bind(compiler::CodeAssemblerParameterizedLabel<T...> * label,TNode<T> * ...phis)1021 void Bind(compiler::CodeAssemblerParameterizedLabel<T...>* label, 1022 TNode<T>*... phis) { 1023 CodeAssembler::Bind(label, phis...); 1024 } 1025 BranchIfSmiEqual(TNode<Smi> a,TNode<Smi> b,Label * if_true,Label * if_false)1026 void BranchIfSmiEqual(TNode<Smi> a, TNode<Smi> b, Label* if_true, 1027 Label* if_false) { 1028 Branch(SmiEqual(a, b), if_true, if_false); 1029 } 1030 BranchIfSmiLessThan(TNode<Smi> a,TNode<Smi> b,Label * if_true,Label * if_false)1031 void BranchIfSmiLessThan(TNode<Smi> a, TNode<Smi> b, Label* if_true, 1032 Label* if_false) { 1033 Branch(SmiLessThan(a, b), if_true, if_false); 1034 } 1035 BranchIfSmiLessThanOrEqual(TNode<Smi> a,TNode<Smi> b,Label * if_true,Label * if_false)1036 void BranchIfSmiLessThanOrEqual(TNode<Smi> a, TNode<Smi> b, Label* if_true, 1037 Label* if_false) { 1038 Branch(SmiLessThanOrEqual(a, b), if_true, if_false); 1039 } 1040 BranchIfFloat64IsNaN(TNode<Float64T> value,Label * if_true,Label * if_false)1041 void BranchIfFloat64IsNaN(TNode<Float64T> value, Label* if_true, 1042 Label* if_false) { 1043 Branch(Float64Equal(value, value), if_false, if_true); 1044 } 1045 1046 // Branches to {if_true} if ToBoolean applied to {value} yields true, 1047 // otherwise goes to {if_false}. 1048 void BranchIfToBooleanIsTrue(TNode<Object> value, Label* if_true, 1049 Label* if_false); 1050 1051 // Branches to {if_false} if ToBoolean applied to {value} yields false, 1052 // otherwise goes to {if_true}. BranchIfToBooleanIsFalse(TNode<Object> value,Label * if_false,Label * if_true)1053 void BranchIfToBooleanIsFalse(TNode<Object> value, Label* if_false, 1054 Label* if_true) { 1055 BranchIfToBooleanIsTrue(value, if_true, if_false); 1056 } 1057 1058 void BranchIfJSReceiver(TNode<Object> object, Label* if_true, 1059 Label* if_false); 1060 1061 // Branches to {if_true} when --force-slow-path flag has been passed. 1062 // It's used for testing to ensure that slow path implementation behave 1063 // equivalent to corresponding fast paths (where applicable). 1064 // 1065 // Works only with V8_ENABLE_FORCE_SLOW_PATH compile time flag. Nop otherwise. 1066 void GotoIfForceSlowPath(Label* if_true); 1067 1068 // 1069 // Caged pointer related functionality. 1070 // 1071 1072 // Load a caged pointer value from an object. LoadSandboxedPointerFromObject(TNode<HeapObject> object,int offset)1073 TNode<RawPtrT> LoadSandboxedPointerFromObject(TNode<HeapObject> object, 1074 int offset) { 1075 return LoadSandboxedPointerFromObject(object, IntPtrConstant(offset)); 1076 } 1077 1078 TNode<RawPtrT> LoadSandboxedPointerFromObject(TNode<HeapObject> object, 1079 TNode<IntPtrT> offset); 1080 1081 // Stored a caged pointer value to an object. StoreSandboxedPointerToObject(TNode<HeapObject> object,int offset,TNode<RawPtrT> pointer)1082 void StoreSandboxedPointerToObject(TNode<HeapObject> object, int offset, 1083 TNode<RawPtrT> pointer) { 1084 StoreSandboxedPointerToObject(object, IntPtrConstant(offset), pointer); 1085 } 1086 1087 void StoreSandboxedPointerToObject(TNode<HeapObject> object, 1088 TNode<IntPtrT> offset, 1089 TNode<RawPtrT> pointer); 1090 1091 TNode<RawPtrT> EmptyBackingStoreBufferConstant(); 1092 1093 // 1094 // ExternalPointerT-related functionality. 1095 // 1096 1097 #ifdef V8_SANDBOXED_EXTERNAL_POINTERS 1098 TNode<ExternalPointerT> ChangeIndexToExternalPointer(TNode<Uint32T> index); 1099 TNode<Uint32T> ChangeExternalPointerToIndex(TNode<ExternalPointerT> pointer); 1100 #endif // V8_SANDBOXED_EXTERNAL_POINTERS 1101 1102 // Initialize an external pointer field in an object. InitializeExternalPointerField(TNode<HeapObject> object,int offset)1103 void InitializeExternalPointerField(TNode<HeapObject> object, int offset) { 1104 InitializeExternalPointerField(object, IntPtrConstant(offset)); 1105 } 1106 void InitializeExternalPointerField(TNode<HeapObject> object, 1107 TNode<IntPtrT> offset); 1108 1109 // Initialize an external pointer field in an object with given value. InitializeExternalPointerField(TNode<HeapObject> object,int offset,TNode<RawPtrT> pointer,ExternalPointerTag tag)1110 void InitializeExternalPointerField(TNode<HeapObject> object, int offset, 1111 TNode<RawPtrT> pointer, 1112 ExternalPointerTag tag) { 1113 InitializeExternalPointerField(object, IntPtrConstant(offset), pointer, 1114 tag); 1115 } 1116 InitializeExternalPointerField(TNode<HeapObject> object,TNode<IntPtrT> offset,TNode<RawPtrT> pointer,ExternalPointerTag tag)1117 void InitializeExternalPointerField(TNode<HeapObject> object, 1118 TNode<IntPtrT> offset, 1119 TNode<RawPtrT> pointer, 1120 ExternalPointerTag tag) { 1121 InitializeExternalPointerField(object, offset); 1122 StoreExternalPointerToObject(object, offset, pointer, tag); 1123 } 1124 1125 // Load an external pointer value from an object. LoadExternalPointerFromObject(TNode<HeapObject> object,int offset,ExternalPointerTag tag)1126 TNode<RawPtrT> LoadExternalPointerFromObject(TNode<HeapObject> object, 1127 int offset, 1128 ExternalPointerTag tag) { 1129 return LoadExternalPointerFromObject(object, IntPtrConstant(offset), tag); 1130 } 1131 1132 TNode<RawPtrT> LoadExternalPointerFromObject(TNode<HeapObject> object, 1133 TNode<IntPtrT> offset, 1134 ExternalPointerTag tag); 1135 1136 // Store external object pointer to object. StoreExternalPointerToObject(TNode<HeapObject> object,int offset,TNode<RawPtrT> pointer,ExternalPointerTag tag)1137 void StoreExternalPointerToObject(TNode<HeapObject> object, int offset, 1138 TNode<RawPtrT> pointer, 1139 ExternalPointerTag tag) { 1140 StoreExternalPointerToObject(object, IntPtrConstant(offset), pointer, tag); 1141 } 1142 1143 void StoreExternalPointerToObject(TNode<HeapObject> object, 1144 TNode<IntPtrT> offset, 1145 TNode<RawPtrT> pointer, 1146 ExternalPointerTag tag); 1147 LoadForeignForeignAddressPtr(TNode<Foreign> object)1148 TNode<RawPtrT> LoadForeignForeignAddressPtr(TNode<Foreign> object) { 1149 return LoadExternalPointerFromObject(object, Foreign::kForeignAddressOffset, 1150 kForeignForeignAddressTag); 1151 } 1152 LoadExternalStringResourcePtr(TNode<ExternalString> object)1153 TNode<RawPtrT> LoadExternalStringResourcePtr(TNode<ExternalString> object) { 1154 return LoadExternalPointerFromObject( 1155 object, ExternalString::kResourceOffset, kExternalStringResourceTag); 1156 } 1157 LoadExternalStringResourceDataPtr(TNode<ExternalString> object)1158 TNode<RawPtrT> LoadExternalStringResourceDataPtr( 1159 TNode<ExternalString> object) { 1160 // This is only valid for ExternalStrings where the resource data 1161 // pointer is cached (i.e. no uncached external strings). 1162 CSA_DCHECK(this, Word32NotEqual( 1163 Word32And(LoadInstanceType(object), 1164 Int32Constant(kUncachedExternalStringMask)), 1165 Int32Constant(kUncachedExternalStringTag))); 1166 return LoadExternalPointerFromObject(object, 1167 ExternalString::kResourceDataOffset, 1168 kExternalStringResourceDataTag); 1169 } 1170 LoadJSTypedArrayExternalPointerPtr(TNode<JSTypedArray> holder)1171 TNode<RawPtrT> LoadJSTypedArrayExternalPointerPtr( 1172 TNode<JSTypedArray> holder) { 1173 return LoadSandboxedPointerFromObject(holder, 1174 JSTypedArray::kExternalPointerOffset); 1175 } 1176 StoreJSTypedArrayExternalPointerPtr(TNode<JSTypedArray> holder,TNode<RawPtrT> value)1177 void StoreJSTypedArrayExternalPointerPtr(TNode<JSTypedArray> holder, 1178 TNode<RawPtrT> value) { 1179 StoreSandboxedPointerToObject(holder, JSTypedArray::kExternalPointerOffset, 1180 value); 1181 } 1182 1183 // Load value from current parent frame by given offset in bytes. 1184 TNode<Object> LoadFromParentFrame(int offset); 1185 1186 // Load an object pointer from a buffer that isn't in the heap. LoadBufferObject(TNode<RawPtrT> buffer,int offset)1187 TNode<Object> LoadBufferObject(TNode<RawPtrT> buffer, int offset) { 1188 return LoadFullTagged(buffer, IntPtrConstant(offset)); 1189 } 1190 template <typename T> LoadBufferData(TNode<RawPtrT> buffer,int offset)1191 TNode<T> LoadBufferData(TNode<RawPtrT> buffer, int offset) { 1192 return UncheckedCast<T>( 1193 Load(MachineTypeOf<T>::value, buffer, IntPtrConstant(offset))); 1194 } LoadBufferPointer(TNode<RawPtrT> buffer,int offset)1195 TNode<RawPtrT> LoadBufferPointer(TNode<RawPtrT> buffer, int offset) { 1196 return LoadBufferData<RawPtrT>(buffer, offset); 1197 } LoadBufferSmi(TNode<RawPtrT> buffer,int offset)1198 TNode<Smi> LoadBufferSmi(TNode<RawPtrT> buffer, int offset) { 1199 return CAST(LoadBufferObject(buffer, offset)); 1200 } LoadBufferIntptr(TNode<RawPtrT> buffer,int offset)1201 TNode<IntPtrT> LoadBufferIntptr(TNode<RawPtrT> buffer, int offset) { 1202 return LoadBufferData<IntPtrT>(buffer, offset); 1203 } 1204 TNode<Uint8T> LoadUint8Ptr(TNode<RawPtrT> ptr, TNode<IntPtrT> offset); 1205 1206 // Load a field from an object on the heap. 1207 template <class T, typename std::enable_if< 1208 std::is_convertible<TNode<T>, TNode<Object>>::value && 1209 std::is_base_of<T, Map>::value, 1210 int>::type = 0> LoadObjectField(TNode<HeapObject> object,int offset)1211 TNode<T> LoadObjectField(TNode<HeapObject> object, int offset) { 1212 const MachineType machine_type = offset == HeapObject::kMapOffset 1213 ? MachineType::MapInHeader() 1214 : MachineTypeOf<T>::value; 1215 return CAST(LoadFromObject(machine_type, object, 1216 IntPtrConstant(offset - kHeapObjectTag))); 1217 } 1218 template <class T, typename std::enable_if< 1219 std::is_convertible<TNode<T>, TNode<Object>>::value && 1220 !std::is_base_of<T, Map>::value, 1221 int>::type = 0> LoadObjectField(TNode<HeapObject> object,int offset)1222 TNode<T> LoadObjectField(TNode<HeapObject> object, int offset) { 1223 return CAST(LoadFromObject(MachineTypeOf<T>::value, object, 1224 IntPtrConstant(offset - kHeapObjectTag))); 1225 } 1226 template <class T, typename std::enable_if< 1227 std::is_convertible<TNode<T>, TNode<UntaggedT>>::value, 1228 int>::type = 0> LoadObjectField(TNode<HeapObject> object,int offset)1229 TNode<T> LoadObjectField(TNode<HeapObject> object, int offset) { 1230 return UncheckedCast<T>( 1231 LoadFromObject(MachineTypeOf<T>::value, object, 1232 IntPtrConstant(offset - kHeapObjectTag))); 1233 } LoadObjectField(TNode<HeapObject> object,int offset)1234 TNode<Object> LoadObjectField(TNode<HeapObject> object, int offset) { 1235 return UncheckedCast<Object>( 1236 LoadFromObject(MachineType::AnyTagged(), object, 1237 IntPtrConstant(offset - kHeapObjectTag))); 1238 } LoadObjectField(TNode<HeapObject> object,TNode<IntPtrT> offset)1239 TNode<Object> LoadObjectField(TNode<HeapObject> object, 1240 TNode<IntPtrT> offset) { 1241 return UncheckedCast<Object>( 1242 LoadFromObject(MachineType::AnyTagged(), object, 1243 IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)))); 1244 } 1245 template <class T, typename std::enable_if< 1246 std::is_convertible<TNode<T>, TNode<UntaggedT>>::value, 1247 int>::type = 0> LoadObjectField(TNode<HeapObject> object,TNode<IntPtrT> offset)1248 TNode<T> LoadObjectField(TNode<HeapObject> object, TNode<IntPtrT> offset) { 1249 return UncheckedCast<T>( 1250 LoadFromObject(MachineTypeOf<T>::value, object, 1251 IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)))); 1252 } 1253 // Load a SMI field and untag it. 1254 TNode<IntPtrT> LoadAndUntagObjectField(TNode<HeapObject> object, int offset); 1255 // Load a SMI field, untag it, and convert to Word32. 1256 TNode<Int32T> LoadAndUntagToWord32ObjectField(TNode<HeapObject> object, 1257 int offset); 1258 LoadMaybeWeakObjectField(TNode<HeapObject> object,int offset)1259 TNode<MaybeObject> LoadMaybeWeakObjectField(TNode<HeapObject> object, 1260 int offset) { 1261 return UncheckedCast<MaybeObject>(LoadObjectField(object, offset)); 1262 } 1263 LoadConstructorOrBackPointer(TNode<Map> map)1264 TNode<Object> LoadConstructorOrBackPointer(TNode<Map> map) { 1265 return LoadObjectField(map, 1266 Map::kConstructorOrBackPointerOrNativeContextOffset); 1267 } 1268 LoadSimd128(TNode<IntPtrT> ptr)1269 TNode<Simd128T> LoadSimd128(TNode<IntPtrT> ptr) { 1270 return Load<Simd128T>(ptr); 1271 } 1272 1273 // Reference is the CSA-equivalent of a Torque reference value, representing 1274 // an inner pointer into a HeapObject. 1275 // 1276 // The object can be a HeapObject or an all-zero bitpattern. The latter is 1277 // used for off-heap data, in which case the offset holds the actual address 1278 // and the data must be untagged (i.e. accessed via the Load-/StoreReference 1279 // overloads for TNode<UntaggedT>-convertible types below). 1280 // 1281 // TODO(gsps): Remove in favor of flattened {Load,Store}Reference interface. 1282 struct Reference { 1283 TNode<Object> object; 1284 TNode<IntPtrT> offset; 1285 FlattenReference1286 std::tuple<TNode<Object>, TNode<IntPtrT>> Flatten() const { 1287 return std::make_tuple(object, offset); 1288 } 1289 }; 1290 1291 template <class T, typename std::enable_if< 1292 std::is_convertible<TNode<T>, TNode<Object>>::value, 1293 int>::type = 0> LoadReference(Reference reference)1294 TNode<T> LoadReference(Reference reference) { 1295 if (IsMapOffsetConstant(reference.offset)) { 1296 TNode<Map> map = LoadMap(CAST(reference.object)); 1297 DCHECK((std::is_base_of<T, Map>::value)); 1298 return ReinterpretCast<T>(map); 1299 } 1300 1301 TNode<IntPtrT> offset = 1302 IntPtrSub(reference.offset, IntPtrConstant(kHeapObjectTag)); 1303 CSA_DCHECK(this, TaggedIsNotSmi(reference.object)); 1304 return CAST( 1305 LoadFromObject(MachineTypeOf<T>::value, reference.object, offset)); 1306 } 1307 template <class T, 1308 typename std::enable_if< 1309 std::is_convertible<TNode<T>, TNode<UntaggedT>>::value || 1310 std::is_same<T, MaybeObject>::value, 1311 int>::type = 0> LoadReference(Reference reference)1312 TNode<T> LoadReference(Reference reference) { 1313 DCHECK(!IsMapOffsetConstant(reference.offset)); 1314 TNode<IntPtrT> offset = 1315 IntPtrSub(reference.offset, IntPtrConstant(kHeapObjectTag)); 1316 return UncheckedCast<T>( 1317 LoadFromObject(MachineTypeOf<T>::value, reference.object, offset)); 1318 } 1319 template <class T, typename std::enable_if< 1320 std::is_convertible<TNode<T>, TNode<Object>>::value || 1321 std::is_same<T, MaybeObject>::value, 1322 int>::type = 0> StoreReference(Reference reference,TNode<T> value)1323 void StoreReference(Reference reference, TNode<T> value) { 1324 if (IsMapOffsetConstant(reference.offset)) { 1325 DCHECK((std::is_base_of<T, Map>::value)); 1326 return StoreMap(CAST(reference.object), ReinterpretCast<Map>(value)); 1327 } 1328 MachineRepresentation rep = MachineRepresentationOf<T>::value; 1329 StoreToObjectWriteBarrier write_barrier = StoreToObjectWriteBarrier::kFull; 1330 if (std::is_same<T, Smi>::value) { 1331 write_barrier = StoreToObjectWriteBarrier::kNone; 1332 } else if (std::is_same<T, Map>::value) { 1333 write_barrier = StoreToObjectWriteBarrier::kMap; 1334 } 1335 TNode<IntPtrT> offset = 1336 IntPtrSub(reference.offset, IntPtrConstant(kHeapObjectTag)); 1337 CSA_DCHECK(this, TaggedIsNotSmi(reference.object)); 1338 StoreToObject(rep, reference.object, offset, value, write_barrier); 1339 } 1340 template <class T, typename std::enable_if< 1341 std::is_convertible<TNode<T>, TNode<UntaggedT>>::value, 1342 int>::type = 0> StoreReference(Reference reference,TNode<T> value)1343 void StoreReference(Reference reference, TNode<T> value) { 1344 DCHECK(!IsMapOffsetConstant(reference.offset)); 1345 TNode<IntPtrT> offset = 1346 IntPtrSub(reference.offset, IntPtrConstant(kHeapObjectTag)); 1347 StoreToObject(MachineRepresentationOf<T>::value, reference.object, offset, 1348 value, StoreToObjectWriteBarrier::kNone); 1349 } 1350 GCUnsafeReferenceToRawPtr(TNode<Object> object,TNode<IntPtrT> offset)1351 TNode<RawPtrT> GCUnsafeReferenceToRawPtr(TNode<Object> object, 1352 TNode<IntPtrT> offset) { 1353 return ReinterpretCast<RawPtrT>( 1354 IntPtrAdd(BitcastTaggedToWord(object), 1355 IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)))); 1356 } 1357 1358 // Load the floating point value of a HeapNumber. 1359 TNode<Float64T> LoadHeapNumberValue(TNode<HeapObject> object); 1360 // Load the Map of an HeapObject. 1361 TNode<Map> LoadMap(TNode<HeapObject> object); 1362 // Load the instance type of an HeapObject. 1363 TNode<Uint16T> LoadInstanceType(TNode<HeapObject> object); 1364 // Compare the instance the type of the object against the provided one. 1365 TNode<BoolT> HasInstanceType(TNode<HeapObject> object, InstanceType type); 1366 TNode<BoolT> DoesntHaveInstanceType(TNode<HeapObject> object, 1367 InstanceType type); 1368 TNode<BoolT> TaggedDoesntHaveInstanceType(TNode<HeapObject> any_tagged, 1369 InstanceType type); 1370 1371 TNode<Word32T> IsStringWrapperElementsKind(TNode<Map> map); 1372 void GotoIfMapHasSlowProperties(TNode<Map> map, Label* if_slow); 1373 1374 // Load the properties backing store of a JSReceiver. 1375 TNode<HeapObject> LoadSlowProperties(TNode<JSReceiver> object); 1376 TNode<HeapObject> LoadFastProperties(TNode<JSReceiver> object); 1377 // Load the elements backing store of a JSObject. LoadElements(TNode<JSObject> object)1378 TNode<FixedArrayBase> LoadElements(TNode<JSObject> object) { 1379 return LoadJSObjectElements(object); 1380 } 1381 // Load the length of a JSArray instance. 1382 TNode<Object> LoadJSArgumentsObjectLength(TNode<Context> context, 1383 TNode<JSArgumentsObject> array); 1384 // Load the length of a fast JSArray instance. Returns a positive Smi. 1385 TNode<Smi> LoadFastJSArrayLength(TNode<JSArray> array); 1386 // Load the length of a fixed array base instance. 1387 TNode<Smi> LoadFixedArrayBaseLength(TNode<FixedArrayBase> array); 1388 // Load the length of a fixed array base instance. 1389 TNode<IntPtrT> LoadAndUntagFixedArrayBaseLength(TNode<FixedArrayBase> array); 1390 // Load the length of a WeakFixedArray. 1391 TNode<Smi> LoadWeakFixedArrayLength(TNode<WeakFixedArray> array); 1392 TNode<IntPtrT> LoadAndUntagWeakFixedArrayLength(TNode<WeakFixedArray> array); 1393 // Load the number of descriptors in DescriptorArray. 1394 TNode<Int32T> LoadNumberOfDescriptors(TNode<DescriptorArray> array); 1395 // Load the number of own descriptors of a map. 1396 TNode<Int32T> LoadNumberOfOwnDescriptors(TNode<Map> map); 1397 // Load the bit field of a Map. 1398 TNode<Int32T> LoadMapBitField(TNode<Map> map); 1399 // Load bit field 2 of a map. 1400 TNode<Int32T> LoadMapBitField2(TNode<Map> map); 1401 // Load bit field 3 of a map. 1402 TNode<Uint32T> LoadMapBitField3(TNode<Map> map); 1403 // Load the instance type of a map. 1404 TNode<Uint16T> LoadMapInstanceType(TNode<Map> map); 1405 // Load the ElementsKind of a map. 1406 TNode<Int32T> LoadMapElementsKind(TNode<Map> map); 1407 TNode<Int32T> LoadElementsKind(TNode<HeapObject> object); 1408 // Load the instance descriptors of a map. 1409 TNode<DescriptorArray> LoadMapDescriptors(TNode<Map> map); 1410 // Load the prototype of a map. 1411 TNode<HeapObject> LoadMapPrototype(TNode<Map> map); 1412 // Load the instance size of a Map. 1413 TNode<IntPtrT> LoadMapInstanceSizeInWords(TNode<Map> map); 1414 // Load the inobject properties start of a Map (valid only for JSObjects). 1415 TNode<IntPtrT> LoadMapInobjectPropertiesStartInWords(TNode<Map> map); 1416 // Load the constructor function index of a Map (only for primitive maps). 1417 TNode<IntPtrT> LoadMapConstructorFunctionIndex(TNode<Map> map); 1418 // Load the constructor of a Map (equivalent to Map::GetConstructor()). 1419 TNode<Object> LoadMapConstructor(TNode<Map> map); 1420 // Load the EnumLength of a Map. 1421 TNode<WordT> LoadMapEnumLength(TNode<Map> map); 1422 // Load the back-pointer of a Map. 1423 TNode<Object> LoadMapBackPointer(TNode<Map> map); 1424 // Checks that |map| has only simple properties, returns bitfield3. 1425 TNode<Uint32T> EnsureOnlyHasSimpleProperties(TNode<Map> map, 1426 TNode<Int32T> instance_type, 1427 Label* bailout); 1428 // Load the identity hash of a JSRececiver. 1429 TNode<IntPtrT> LoadJSReceiverIdentityHash(TNode<JSReceiver> receiver, 1430 Label* if_no_hash = nullptr); 1431 1432 // This is only used on a newly allocated PropertyArray which 1433 // doesn't have an existing hash. 1434 void InitializePropertyArrayLength(TNode<PropertyArray> property_array, 1435 TNode<IntPtrT> length); 1436 1437 // Check if the map is set for slow properties. 1438 TNode<BoolT> IsDictionaryMap(TNode<Map> map); 1439 1440 // Load the Name::hash() value of a name as an uint32 value. 1441 // If {if_hash_not_computed} label is specified then it also checks if 1442 // hash is actually computed. 1443 TNode<Uint32T> LoadNameHash(TNode<Name> name, 1444 Label* if_hash_not_computed = nullptr); 1445 TNode<Uint32T> LoadNameHashAssumeComputed(TNode<Name> name); 1446 1447 // Load length field of a String object as Smi value. 1448 TNode<Smi> LoadStringLengthAsSmi(TNode<String> string); 1449 // Load length field of a String object as intptr_t value. 1450 TNode<IntPtrT> LoadStringLengthAsWord(TNode<String> string); 1451 // Load length field of a String object as uint32_t value. 1452 TNode<Uint32T> LoadStringLengthAsWord32(TNode<String> string); 1453 // Load value field of a JSPrimitiveWrapper object. 1454 TNode<Object> LoadJSPrimitiveWrapperValue(TNode<JSPrimitiveWrapper> object); 1455 1456 // Figures out whether the value of maybe_object is: 1457 // - a SMI (jump to "if_smi", "extracted" will be the SMI value) 1458 // - a cleared weak reference (jump to "if_cleared", "extracted" will be 1459 // untouched) 1460 // - a weak reference (jump to "if_weak", "extracted" will be the object 1461 // pointed to) 1462 // - a strong reference (jump to "if_strong", "extracted" will be the object 1463 // pointed to) 1464 void DispatchMaybeObject(TNode<MaybeObject> maybe_object, Label* if_smi, 1465 Label* if_cleared, Label* if_weak, Label* if_strong, 1466 TVariable<Object>* extracted); 1467 // See MaybeObject for semantics of these functions. 1468 TNode<BoolT> IsStrong(TNode<MaybeObject> value); 1469 TNode<HeapObject> GetHeapObjectIfStrong(TNode<MaybeObject> value, 1470 Label* if_not_strong); 1471 1472 TNode<BoolT> IsWeakOrCleared(TNode<MaybeObject> value); 1473 TNode<BoolT> IsCleared(TNode<MaybeObject> value); IsNotCleared(TNode<MaybeObject> value)1474 TNode<BoolT> IsNotCleared(TNode<MaybeObject> value) { 1475 return Word32BinaryNot(IsCleared(value)); 1476 } 1477 1478 // Removes the weak bit + asserts it was set. 1479 TNode<HeapObject> GetHeapObjectAssumeWeak(TNode<MaybeObject> value); 1480 1481 TNode<HeapObject> GetHeapObjectAssumeWeak(TNode<MaybeObject> value, 1482 Label* if_cleared); 1483 1484 // Checks if |maybe_object| is a weak reference to given |heap_object|. 1485 // Works for both any tagged |maybe_object| values. 1486 TNode<BoolT> IsWeakReferenceTo(TNode<MaybeObject> maybe_object, 1487 TNode<HeapObject> heap_object); 1488 // Returns true if the |object| is a HeapObject and |maybe_object| is a weak 1489 // reference to |object|. 1490 // The |maybe_object| must not be a Smi. 1491 TNode<BoolT> IsWeakReferenceToObject(TNode<MaybeObject> maybe_object, 1492 TNode<Object> object); 1493 1494 TNode<MaybeObject> MakeWeak(TNode<HeapObject> value); 1495 1496 void FixedArrayBoundsCheck(TNode<FixedArrayBase> array, TNode<Smi> index, 1497 int additional_offset); 1498 1499 void FixedArrayBoundsCheck(TNode<FixedArrayBase> array, TNode<IntPtrT> index, 1500 int additional_offset); 1501 FixedArrayBoundsCheck(TNode<FixedArrayBase> array,TNode<UintPtrT> index,int additional_offset)1502 void FixedArrayBoundsCheck(TNode<FixedArrayBase> array, TNode<UintPtrT> index, 1503 int additional_offset) { 1504 FixedArrayBoundsCheck(array, Signed(index), additional_offset); 1505 } 1506 1507 // Array is any array-like type that has a fixed header followed by 1508 // tagged elements. 1509 template <typename Array> 1510 TNode<IntPtrT> LoadArrayLength(TNode<Array> array); 1511 1512 // Array is any array-like type that has a fixed header followed by 1513 // tagged elements. 1514 template <typename Array, typename TIndex, typename TValue = MaybeObject> 1515 TNode<TValue> LoadArrayElement(TNode<Array> array, int array_header_size, 1516 TNode<TIndex> index, 1517 int additional_offset = 0); 1518 1519 template <typename TIndex> 1520 TNode<Object> LoadFixedArrayElement( 1521 TNode<FixedArray> object, TNode<TIndex> index, int additional_offset = 0, 1522 CheckBounds check_bounds = CheckBounds::kAlways); 1523 1524 // This doesn't emit a bounds-check. As part of the security-performance 1525 // tradeoff, only use it if it is performance critical. 1526 TNode<Object> UnsafeLoadFixedArrayElement(TNode<FixedArray> object, 1527 TNode<IntPtrT> index, 1528 int additional_offset = 0) { 1529 return LoadFixedArrayElement(object, index, additional_offset, 1530 CheckBounds::kDebugOnly); 1531 } 1532 1533 TNode<Object> LoadFixedArrayElement(TNode<FixedArray> object, int index, 1534 int additional_offset = 0) { 1535 return LoadFixedArrayElement(object, IntPtrConstant(index), 1536 additional_offset); 1537 } 1538 // This doesn't emit a bounds-check. As part of the security-performance 1539 // tradeoff, only use it if it is performance critical. 1540 TNode<Object> UnsafeLoadFixedArrayElement(TNode<FixedArray> object, int index, 1541 int additional_offset = 0) { 1542 return LoadFixedArrayElement(object, IntPtrConstant(index), 1543 additional_offset, CheckBounds::kDebugOnly); 1544 } 1545 1546 TNode<Object> LoadPropertyArrayElement(TNode<PropertyArray> object, 1547 TNode<IntPtrT> index); 1548 TNode<IntPtrT> LoadPropertyArrayLength(TNode<PropertyArray> object); 1549 1550 // Load an element from an array and untag it and return it as Word32. 1551 // Array is any array-like type that has a fixed header followed by 1552 // tagged elements. 1553 template <typename Array> 1554 TNode<Int32T> LoadAndUntagToWord32ArrayElement(TNode<Array> array, 1555 int array_header_size, 1556 TNode<IntPtrT> index, 1557 int additional_offset = 0); 1558 1559 // Load an array element from a FixedArray, untag it and return it as Word32. 1560 TNode<Int32T> LoadAndUntagToWord32FixedArrayElement( 1561 TNode<FixedArray> object, TNode<IntPtrT> index, 1562 int additional_offset = 0); 1563 1564 // Load an array element from a WeakFixedArray. 1565 TNode<MaybeObject> LoadWeakFixedArrayElement(TNode<WeakFixedArray> object, 1566 TNode<IntPtrT> index, 1567 int additional_offset = 0); 1568 1569 // Load an array element from a FixedDoubleArray. 1570 TNode<Float64T> LoadFixedDoubleArrayElement( 1571 TNode<FixedDoubleArray> object, TNode<IntPtrT> index, 1572 Label* if_hole = nullptr, 1573 MachineType machine_type = MachineType::Float64()); 1574 1575 // Load an array element from a FixedArray, FixedDoubleArray or a 1576 // NumberDictionary (depending on the |elements_kind|) and return 1577 // it as a tagged value. Assumes that the |index| passed a length 1578 // check before. Bails out to |if_accessor| if the element that 1579 // was found is an accessor, or to |if_hole| if the element at 1580 // the given |index| is not found in |elements|. 1581 TNode<Object> LoadFixedArrayBaseElementAsTagged( 1582 TNode<FixedArrayBase> elements, TNode<IntPtrT> index, 1583 TNode<Int32T> elements_kind, Label* if_accessor, Label* if_hole); 1584 1585 // Load a feedback slot from a FeedbackVector. 1586 template <typename TIndex> 1587 TNode<MaybeObject> LoadFeedbackVectorSlot( 1588 TNode<FeedbackVector> feedback_vector, TNode<TIndex> slot, 1589 int additional_offset = 0); 1590 1591 TNode<IntPtrT> LoadFeedbackVectorLength(TNode<FeedbackVector>); 1592 TNode<Float64T> LoadDoubleWithHoleCheck(TNode<FixedDoubleArray> array, 1593 TNode<IntPtrT> index, 1594 Label* if_hole = nullptr); 1595 1596 TNode<BoolT> IsDoubleHole(TNode<Object> base, TNode<IntPtrT> offset); 1597 // Load Float64 value by |base| + |offset| address. If the value is a double 1598 // hole then jump to |if_hole|. If |machine_type| is None then only the hole 1599 // check is generated. 1600 TNode<Float64T> LoadDoubleWithHoleCheck( 1601 TNode<Object> base, TNode<IntPtrT> offset, Label* if_hole, 1602 MachineType machine_type = MachineType::Float64()); 1603 TNode<Numeric> LoadFixedTypedArrayElementAsTagged(TNode<RawPtrT> data_pointer, 1604 TNode<UintPtrT> index, 1605 ElementsKind elements_kind); 1606 TNode<Numeric> LoadFixedTypedArrayElementAsTagged( 1607 TNode<RawPtrT> data_pointer, TNode<UintPtrT> index, 1608 TNode<Int32T> elements_kind); 1609 // Parts of the above, factored out for readability: 1610 TNode<BigInt> LoadFixedBigInt64ArrayElementAsTagged( 1611 TNode<RawPtrT> data_pointer, TNode<IntPtrT> offset); 1612 TNode<BigInt> LoadFixedBigUint64ArrayElementAsTagged( 1613 TNode<RawPtrT> data_pointer, TNode<IntPtrT> offset); 1614 // 64-bit platforms only: 1615 TNode<BigInt> BigIntFromInt64(TNode<IntPtrT> value); 1616 TNode<BigInt> BigIntFromUint64(TNode<UintPtrT> value); 1617 // 32-bit platforms only: 1618 TNode<BigInt> BigIntFromInt32Pair(TNode<IntPtrT> low, TNode<IntPtrT> high); 1619 TNode<BigInt> BigIntFromUint32Pair(TNode<UintPtrT> low, TNode<UintPtrT> high); 1620 1621 // ScopeInfo: 1622 TNode<ScopeInfo> LoadScopeInfo(TNode<Context> context); 1623 TNode<BoolT> LoadScopeInfoHasExtensionField(TNode<ScopeInfo> scope_info); 1624 1625 // Context manipulation: 1626 void StoreContextElementNoWriteBarrier(TNode<Context> context, int slot_index, 1627 TNode<Object> value); 1628 TNode<NativeContext> LoadNativeContext(TNode<Context> context); 1629 // Calling this is only valid if there's a module context in the chain. 1630 TNode<Context> LoadModuleContext(TNode<Context> context); 1631 1632 TNode<Object> GetImportMetaObject(TNode<Context> context); 1633 GotoIfContextElementEqual(TNode<Object> value,TNode<NativeContext> native_context,int slot_index,Label * if_equal)1634 void GotoIfContextElementEqual(TNode<Object> value, 1635 TNode<NativeContext> native_context, 1636 int slot_index, Label* if_equal) { 1637 GotoIf(TaggedEqual(value, LoadContextElement(native_context, slot_index)), 1638 if_equal); 1639 } 1640 1641 // Loads the initial map of the the Object constructor. 1642 TNode<Map> LoadObjectFunctionInitialMap(TNode<NativeContext> native_context); 1643 TNode<Map> LoadSlowObjectWithNullPrototypeMap( 1644 TNode<NativeContext> native_context); 1645 1646 TNode<Map> LoadJSArrayElementsMap(ElementsKind kind, 1647 TNode<NativeContext> native_context); 1648 TNode<Map> LoadJSArrayElementsMap(TNode<Int32T> kind, 1649 TNode<NativeContext> native_context); 1650 1651 TNode<BoolT> IsJSFunctionWithPrototypeSlot(TNode<HeapObject> object); 1652 TNode<BoolT> IsGeneratorFunction(TNode<JSFunction> function); 1653 void BranchIfHasPrototypeProperty(TNode<JSFunction> function, 1654 TNode<Int32T> function_map_bit_field, 1655 Label* if_true, Label* if_false); 1656 void GotoIfPrototypeRequiresRuntimeLookup(TNode<JSFunction> function, 1657 TNode<Map> map, Label* runtime); 1658 // Load the "prototype" property of a JSFunction. 1659 TNode<HeapObject> LoadJSFunctionPrototype(TNode<JSFunction> function, 1660 Label* if_bailout); 1661 1662 TNode<BytecodeArray> LoadSharedFunctionInfoBytecodeArray( 1663 TNode<SharedFunctionInfo> shared); 1664 1665 void StoreObjectByteNoWriteBarrier(TNode<HeapObject> object, int offset, 1666 TNode<Word32T> value); 1667 1668 // Store the floating point value of a HeapNumber. 1669 void StoreHeapNumberValue(TNode<HeapNumber> object, TNode<Float64T> value); 1670 1671 // Store a field to an object on the heap. 1672 void StoreObjectField(TNode<HeapObject> object, int offset, TNode<Smi> value); 1673 void StoreObjectField(TNode<HeapObject> object, TNode<IntPtrT> offset, 1674 TNode<Smi> value); 1675 void StoreObjectField(TNode<HeapObject> object, int offset, 1676 TNode<Object> value); 1677 void StoreObjectField(TNode<HeapObject> object, TNode<IntPtrT> offset, 1678 TNode<Object> value); 1679 template <class T> StoreObjectFieldNoWriteBarrier(TNode<HeapObject> object,TNode<IntPtrT> offset,TNode<T> value)1680 void StoreObjectFieldNoWriteBarrier(TNode<HeapObject> object, 1681 TNode<IntPtrT> offset, TNode<T> value) { 1682 int const_offset; 1683 if (TryToInt32Constant(offset, &const_offset)) { 1684 return StoreObjectFieldNoWriteBarrier<T>(object, const_offset, value); 1685 } 1686 StoreNoWriteBarrier(MachineRepresentationOf<T>::value, object, 1687 IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)), 1688 value); 1689 } 1690 template <class T> StoreObjectFieldNoWriteBarrier(TNode<HeapObject> object,int offset,TNode<T> value)1691 void StoreObjectFieldNoWriteBarrier(TNode<HeapObject> object, int offset, 1692 TNode<T> value) { 1693 if (CanBeTaggedPointer(MachineRepresentationOf<T>::value)) { 1694 OptimizedStoreFieldAssertNoWriteBarrier(MachineRepresentationOf<T>::value, 1695 object, offset, value); 1696 } else { 1697 OptimizedStoreFieldUnsafeNoWriteBarrier(MachineRepresentationOf<T>::value, 1698 object, offset, value); 1699 } 1700 } 1701 1702 void UnsafeStoreObjectFieldNoWriteBarrier(TNode<HeapObject> object, 1703 int offset, TNode<Object> value); 1704 1705 // Store the Map of an HeapObject. 1706 void StoreMap(TNode<HeapObject> object, TNode<Map> map); 1707 void StoreMapNoWriteBarrier(TNode<HeapObject> object, 1708 RootIndex map_root_index); 1709 void StoreMapNoWriteBarrier(TNode<HeapObject> object, TNode<Map> map); 1710 void StoreObjectFieldRoot(TNode<HeapObject> object, int offset, 1711 RootIndex root); 1712 1713 // Store an array element to a FixedArray. 1714 void StoreFixedArrayElement( 1715 TNode<FixedArray> object, int index, TNode<Object> value, 1716 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, 1717 CheckBounds check_bounds = CheckBounds::kAlways) { 1718 return StoreFixedArrayElement(object, IntPtrConstant(index), value, 1719 barrier_mode, 0, check_bounds); 1720 } 1721 1722 void StoreFixedArrayElement(TNode<FixedArray> object, int index, 1723 TNode<Smi> value, 1724 CheckBounds check_bounds = CheckBounds::kAlways) { 1725 return StoreFixedArrayElement(object, IntPtrConstant(index), 1726 TNode<Object>{value}, 1727 UNSAFE_SKIP_WRITE_BARRIER, 0, check_bounds); 1728 } 1729 1730 template <typename TIndex> 1731 void StoreFixedArrayElement( 1732 TNode<FixedArray> array, TNode<TIndex> index, TNode<Object> value, 1733 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, 1734 int additional_offset = 0, 1735 CheckBounds check_bounds = CheckBounds::kAlways) { 1736 // TODO(v8:9708): Do we want to keep both IntPtrT and UintPtrT variants? 1737 static_assert(std::is_same<TIndex, Smi>::value || 1738 std::is_same<TIndex, UintPtrT>::value || 1739 std::is_same<TIndex, IntPtrT>::value, 1740 "Only Smi, UintPtrT or IntPtrT index is allowed"); 1741 if (NeedsBoundsCheck(check_bounds)) { 1742 FixedArrayBoundsCheck(array, index, additional_offset); 1743 } 1744 StoreFixedArrayOrPropertyArrayElement(array, index, value, barrier_mode, 1745 additional_offset); 1746 } 1747 1748 template <typename TIndex> 1749 void StoreFixedArrayElement(TNode<FixedArray> array, TNode<TIndex> index, 1750 TNode<Smi> value, int additional_offset = 0) { 1751 static_assert(std::is_same<TIndex, Smi>::value || 1752 std::is_same<TIndex, IntPtrT>::value, 1753 "Only Smi or IntPtrT indeces is allowed"); 1754 StoreFixedArrayElement(array, index, TNode<Object>{value}, 1755 UNSAFE_SKIP_WRITE_BARRIER, additional_offset); 1756 } 1757 1758 // These don't emit a bounds-check. As part of the security-performance 1759 // tradeoff, only use it if it is performance critical. 1760 void UnsafeStoreFixedArrayElement( 1761 TNode<FixedArray> object, int index, TNode<Object> value, 1762 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER) { 1763 return StoreFixedArrayElement(object, IntPtrConstant(index), value, 1764 barrier_mode, 0, CheckBounds::kDebugOnly); 1765 } 1766 UnsafeStoreFixedArrayElement(TNode<FixedArray> object,int index,TNode<Smi> value)1767 void UnsafeStoreFixedArrayElement(TNode<FixedArray> object, int index, 1768 TNode<Smi> value) { 1769 return StoreFixedArrayElement(object, IntPtrConstant(index), value, 1770 UNSAFE_SKIP_WRITE_BARRIER, 0, 1771 CheckBounds::kDebugOnly); 1772 } 1773 1774 void UnsafeStoreFixedArrayElement( 1775 TNode<FixedArray> array, TNode<IntPtrT> index, TNode<Object> value, 1776 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, 1777 int additional_offset = 0) { 1778 return StoreFixedArrayElement(array, index, value, barrier_mode, 1779 additional_offset, CheckBounds::kDebugOnly); 1780 } 1781 UnsafeStoreFixedArrayElement(TNode<FixedArray> array,TNode<IntPtrT> index,TNode<Smi> value,int additional_offset)1782 void UnsafeStoreFixedArrayElement(TNode<FixedArray> array, 1783 TNode<IntPtrT> index, TNode<Smi> value, 1784 int additional_offset) { 1785 return StoreFixedArrayElement(array, index, value, 1786 UNSAFE_SKIP_WRITE_BARRIER, additional_offset, 1787 CheckBounds::kDebugOnly); 1788 } 1789 StorePropertyArrayElement(TNode<PropertyArray> array,TNode<IntPtrT> index,TNode<Object> value)1790 void StorePropertyArrayElement(TNode<PropertyArray> array, 1791 TNode<IntPtrT> index, TNode<Object> value) { 1792 StoreFixedArrayOrPropertyArrayElement(array, index, value, 1793 UPDATE_WRITE_BARRIER); 1794 } 1795 1796 template <typename TIndex> 1797 void StoreFixedDoubleArrayElement( 1798 TNode<FixedDoubleArray> object, TNode<TIndex> index, 1799 TNode<Float64T> value, CheckBounds check_bounds = CheckBounds::kAlways); 1800 1801 void StoreDoubleHole(TNode<HeapObject> object, TNode<IntPtrT> offset); 1802 void StoreFixedDoubleArrayHole(TNode<FixedDoubleArray> array, 1803 TNode<IntPtrT> index); 1804 void StoreFeedbackVectorSlot( 1805 TNode<FeedbackVector> feedback_vector, TNode<UintPtrT> slot, 1806 TNode<AnyTaggedT> value, 1807 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, 1808 int additional_offset = 0); 1809 1810 void StoreJSSharedStructInObjectField(TNode<HeapObject> object, 1811 TNode<IntPtrT> offset, 1812 TNode<Object> value); 1813 StoreJSSharedStructPropertyArrayElement(TNode<PropertyArray> array,TNode<IntPtrT> index,TNode<Object> value)1814 void StoreJSSharedStructPropertyArrayElement(TNode<PropertyArray> array, 1815 TNode<IntPtrT> index, 1816 TNode<Object> value) { 1817 // JSSharedStructs are allocated in the shared old space, which is currently 1818 // collected by stopping the world, so the incremental write barrier is not 1819 // needed. They can only store Smis and other HeapObjects in the shared old 1820 // space, so the generational write barrier is also not needed. 1821 // TODO(v8:12547): Add a safer, shared variant of SKIP_WRITE_BARRIER. 1822 StoreFixedArrayOrPropertyArrayElement(array, index, value, 1823 UNSAFE_SKIP_WRITE_BARRIER); 1824 } 1825 1826 // EnsureArrayPushable verifies that receiver with this map is: 1827 // 1. Is not a prototype. 1828 // 2. Is not a dictionary. 1829 // 3. Has a writeable length property. 1830 // It returns ElementsKind as a node for further division into cases. 1831 TNode<Int32T> EnsureArrayPushable(TNode<Context> context, TNode<Map> map, 1832 Label* bailout); 1833 1834 void TryStoreArrayElement(ElementsKind kind, Label* bailout, 1835 TNode<FixedArrayBase> elements, TNode<BInt> index, 1836 TNode<Object> value); 1837 // Consumes args into the array, and returns tagged new length. 1838 TNode<Smi> BuildAppendJSArray(ElementsKind kind, TNode<JSArray> array, 1839 CodeStubArguments* args, 1840 TVariable<IntPtrT>* arg_index, Label* bailout); 1841 // Pushes value onto the end of array. 1842 void BuildAppendJSArray(ElementsKind kind, TNode<JSArray> array, 1843 TNode<Object> value, Label* bailout); 1844 1845 void StoreFieldsNoWriteBarrier(TNode<IntPtrT> start_address, 1846 TNode<IntPtrT> end_address, 1847 TNode<Object> value); 1848 1849 // Marks the FixedArray copy-on-write without moving it. 1850 void MakeFixedArrayCOW(TNode<FixedArray> array); 1851 1852 TNode<Cell> AllocateCellWithValue( 1853 TNode<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); 1854 TNode<Cell> AllocateSmiCell(int value = 0) { 1855 return AllocateCellWithValue(SmiConstant(value), SKIP_WRITE_BARRIER); 1856 } 1857 1858 TNode<Object> LoadCellValue(TNode<Cell> cell); 1859 1860 void StoreCellValue(TNode<Cell> cell, TNode<Object> value, 1861 WriteBarrierMode mode = UPDATE_WRITE_BARRIER); 1862 1863 // Allocate a HeapNumber without initializing its value. 1864 TNode<HeapNumber> AllocateHeapNumber(); 1865 // Allocate a HeapNumber with a specific value. 1866 TNode<HeapNumber> AllocateHeapNumberWithValue(TNode<Float64T> value); AllocateHeapNumberWithValue(double value)1867 TNode<HeapNumber> AllocateHeapNumberWithValue(double value) { 1868 return AllocateHeapNumberWithValue(Float64Constant(value)); 1869 } 1870 1871 // Allocate a BigInt with {length} digits. Sets the sign bit to {false}. 1872 // Does not initialize the digits. 1873 TNode<BigInt> AllocateBigInt(TNode<IntPtrT> length); 1874 // Like above, but allowing custom bitfield initialization. 1875 TNode<BigInt> AllocateRawBigInt(TNode<IntPtrT> length); 1876 void StoreBigIntBitfield(TNode<BigInt> bigint, TNode<Word32T> bitfield); 1877 void StoreBigIntDigit(TNode<BigInt> bigint, intptr_t digit_index, 1878 TNode<UintPtrT> digit); 1879 void StoreBigIntDigit(TNode<BigInt> bigint, TNode<IntPtrT> digit_index, 1880 TNode<UintPtrT> digit); 1881 1882 TNode<Word32T> LoadBigIntBitfield(TNode<BigInt> bigint); 1883 TNode<UintPtrT> LoadBigIntDigit(TNode<BigInt> bigint, intptr_t digit_index); 1884 TNode<UintPtrT> LoadBigIntDigit(TNode<BigInt> bigint, 1885 TNode<IntPtrT> digit_index); 1886 1887 // Allocate a ByteArray with the given non-zero length. 1888 TNode<ByteArray> AllocateNonEmptyByteArray(TNode<UintPtrT> length, 1889 AllocationFlags flags); 1890 1891 // Allocate a ByteArray with the given length. 1892 TNode<ByteArray> AllocateByteArray( 1893 TNode<UintPtrT> length, AllocationFlags flags = AllocationFlag::kNone); 1894 1895 // Allocate a SeqOneByteString with the given length. 1896 TNode<String> AllocateSeqOneByteString( 1897 uint32_t length, AllocationFlags flags = AllocationFlag::kNone); 1898 using TorqueGeneratedExportedMacrosAssembler::AllocateSeqOneByteString; 1899 1900 // Allocate a SeqTwoByteString with the given length. 1901 TNode<String> AllocateSeqTwoByteString( 1902 uint32_t length, AllocationFlags flags = AllocationFlag::kNone); 1903 using TorqueGeneratedExportedMacrosAssembler::AllocateSeqTwoByteString; 1904 1905 // Allocate a SlicedOneByteString with the given length, parent and offset. 1906 // |length| and |offset| are expected to be tagged. 1907 1908 TNode<String> AllocateSlicedOneByteString(TNode<Uint32T> length, 1909 TNode<String> parent, 1910 TNode<Smi> offset); 1911 // Allocate a SlicedTwoByteString with the given length, parent and offset. 1912 // |length| and |offset| are expected to be tagged. 1913 TNode<String> AllocateSlicedTwoByteString(TNode<Uint32T> length, 1914 TNode<String> parent, 1915 TNode<Smi> offset); 1916 1917 TNode<NameDictionary> AllocateNameDictionary(int at_least_space_for); 1918 TNode<NameDictionary> AllocateNameDictionary( 1919 TNode<IntPtrT> at_least_space_for, 1920 AllocationFlags = AllocationFlag::kNone); 1921 TNode<NameDictionary> AllocateNameDictionaryWithCapacity( 1922 TNode<IntPtrT> capacity, AllocationFlags = AllocationFlag::kNone); 1923 TNode<NameDictionary> CopyNameDictionary(TNode<NameDictionary> dictionary, 1924 Label* large_object_fallback); 1925 1926 TNode<OrderedHashSet> AllocateOrderedHashSet(); 1927 1928 TNode<OrderedHashMap> AllocateOrderedHashMap(); 1929 1930 // Allocates an OrderedNameDictionary of the given capacity. This guarantees 1931 // that |capacity| entries can be added without reallocating. 1932 TNode<OrderedNameDictionary> AllocateOrderedNameDictionary( 1933 TNode<IntPtrT> capacity); 1934 TNode<OrderedNameDictionary> AllocateOrderedNameDictionary(int capacity); 1935 1936 TNode<JSObject> AllocateJSObjectFromMap( 1937 TNode<Map> map, 1938 base::Optional<TNode<HeapObject>> properties = base::nullopt, 1939 base::Optional<TNode<FixedArray>> elements = base::nullopt, 1940 AllocationFlags flags = AllocationFlag::kNone, 1941 SlackTrackingMode slack_tracking_mode = kNoSlackTracking); 1942 1943 void InitializeJSObjectFromMap( 1944 TNode<HeapObject> object, TNode<Map> map, TNode<IntPtrT> instance_size, 1945 base::Optional<TNode<HeapObject>> properties = base::nullopt, 1946 base::Optional<TNode<FixedArray>> elements = base::nullopt, 1947 SlackTrackingMode slack_tracking_mode = kNoSlackTracking); 1948 1949 void InitializeJSObjectBodyWithSlackTracking(TNode<HeapObject> object, 1950 TNode<Map> map, 1951 TNode<IntPtrT> instance_size); 1952 void InitializeJSObjectBodyNoSlackTracking( 1953 TNode<HeapObject> object, TNode<Map> map, TNode<IntPtrT> instance_size, 1954 int start_offset = JSObject::kHeaderSize); 1955 1956 TNode<BoolT> IsValidFastJSArrayCapacity(TNode<IntPtrT> capacity); 1957 1958 // 1959 // Allocate and return a JSArray with initialized header fields and its 1960 // uninitialized elements. 1961 std::pair<TNode<JSArray>, TNode<FixedArrayBase>> 1962 AllocateUninitializedJSArrayWithElements( 1963 ElementsKind kind, TNode<Map> array_map, TNode<Smi> length, 1964 base::Optional<TNode<AllocationSite>> allocation_site, 1965 TNode<IntPtrT> capacity, 1966 AllocationFlags allocation_flags = AllocationFlag::kNone, 1967 int array_header_size = JSArray::kHeaderSize); 1968 1969 // Allocate a JSArray and fill elements with the hole. 1970 TNode<JSArray> AllocateJSArray( 1971 ElementsKind kind, TNode<Map> array_map, TNode<IntPtrT> capacity, 1972 TNode<Smi> length, base::Optional<TNode<AllocationSite>> allocation_site, 1973 AllocationFlags allocation_flags = AllocationFlag::kNone); 1974 TNode<JSArray> AllocateJSArray( 1975 ElementsKind kind, TNode<Map> array_map, TNode<Smi> capacity, 1976 TNode<Smi> length, base::Optional<TNode<AllocationSite>> allocation_site, 1977 AllocationFlags allocation_flags = AllocationFlag::kNone) { 1978 return AllocateJSArray(kind, array_map, SmiUntag(capacity), length, 1979 allocation_site, allocation_flags); 1980 } 1981 TNode<JSArray> AllocateJSArray( 1982 ElementsKind kind, TNode<Map> array_map, TNode<Smi> capacity, 1983 TNode<Smi> length, 1984 AllocationFlags allocation_flags = AllocationFlag::kNone) { 1985 return AllocateJSArray(kind, array_map, SmiUntag(capacity), length, 1986 base::nullopt, allocation_flags); 1987 } 1988 TNode<JSArray> AllocateJSArray( 1989 ElementsKind kind, TNode<Map> array_map, TNode<IntPtrT> capacity, 1990 TNode<Smi> length, 1991 AllocationFlags allocation_flags = AllocationFlag::kNone) { 1992 return AllocateJSArray(kind, array_map, capacity, length, base::nullopt, 1993 allocation_flags); 1994 } 1995 1996 // Allocate a JSArray and initialize the header fields. 1997 TNode<JSArray> AllocateJSArray( 1998 TNode<Map> array_map, TNode<FixedArrayBase> elements, TNode<Smi> length, 1999 base::Optional<TNode<AllocationSite>> allocation_site = base::nullopt, 2000 int array_header_size = JSArray::kHeaderSize); 2001 2002 enum class HoleConversionMode { kDontConvert, kConvertToUndefined }; 2003 // Clone a fast JSArray |array| into a new fast JSArray. 2004 // |convert_holes| tells the function to convert holes into undefined or not. 2005 // If |convert_holes| is set to kConvertToUndefined, but the function did not 2006 // find any hole in |array|, the resulting array will have the same elements 2007 // kind as |array|. If the function did find a hole, it will convert holes in 2008 // |array| to undefined in the resulting array, who will now have 2009 // PACKED_ELEMENTS kind. 2010 // If |convert_holes| is set kDontConvert, holes are also copied to the 2011 // resulting array, who will have the same elements kind as |array|. The 2012 // function generates significantly less code in this case. 2013 TNode<JSArray> CloneFastJSArray( 2014 TNode<Context> context, TNode<JSArray> array, 2015 base::Optional<TNode<AllocationSite>> allocation_site = base::nullopt, 2016 HoleConversionMode convert_holes = HoleConversionMode::kDontConvert); 2017 2018 TNode<JSArray> ExtractFastJSArray(TNode<Context> context, 2019 TNode<JSArray> array, TNode<BInt> begin, 2020 TNode<BInt> count); 2021 2022 template <typename TIndex> 2023 TNode<FixedArrayBase> AllocateFixedArray( 2024 ElementsKind kind, TNode<TIndex> capacity, 2025 AllocationFlags flags = AllocationFlag::kNone, 2026 base::Optional<TNode<Map>> fixed_array_map = base::nullopt); 2027 2028 TNode<NativeContext> GetCreationContext(TNode<JSReceiver> receiver, 2029 Label* if_bailout); 2030 TNode<NativeContext> GetFunctionRealm(TNode<Context> context, 2031 TNode<JSReceiver> receiver, 2032 Label* if_bailout); 2033 TNode<Object> GetConstructor(TNode<Map> map); 2034 2035 TNode<Map> GetInstanceTypeMap(InstanceType instance_type); 2036 AllocateUninitializedFixedArray(intptr_t capacity)2037 TNode<FixedArray> AllocateUninitializedFixedArray(intptr_t capacity) { 2038 return UncheckedCast<FixedArray>(AllocateFixedArray( 2039 PACKED_ELEMENTS, IntPtrConstant(capacity), AllocationFlag::kNone)); 2040 } 2041 AllocateZeroedFixedArray(TNode<IntPtrT> capacity)2042 TNode<FixedArray> AllocateZeroedFixedArray(TNode<IntPtrT> capacity) { 2043 TNode<FixedArray> result = UncheckedCast<FixedArray>( 2044 AllocateFixedArray(PACKED_ELEMENTS, capacity, 2045 AllocationFlag::kAllowLargeObjectAllocation)); 2046 FillFixedArrayWithSmiZero(result, capacity); 2047 return result; 2048 } 2049 AllocateZeroedFixedDoubleArray(TNode<IntPtrT> capacity)2050 TNode<FixedDoubleArray> AllocateZeroedFixedDoubleArray( 2051 TNode<IntPtrT> capacity) { 2052 TNode<FixedDoubleArray> result = UncheckedCast<FixedDoubleArray>( 2053 AllocateFixedArray(PACKED_DOUBLE_ELEMENTS, capacity, 2054 AllocationFlag::kAllowLargeObjectAllocation)); 2055 FillFixedDoubleArrayWithZero(result, capacity); 2056 return result; 2057 } 2058 AllocateFixedArrayWithHoles(TNode<IntPtrT> capacity,AllocationFlags flags)2059 TNode<FixedArray> AllocateFixedArrayWithHoles(TNode<IntPtrT> capacity, 2060 AllocationFlags flags) { 2061 TNode<FixedArray> result = UncheckedCast<FixedArray>( 2062 AllocateFixedArray(PACKED_ELEMENTS, capacity, flags)); 2063 FillFixedArrayWithValue(PACKED_ELEMENTS, result, IntPtrConstant(0), 2064 capacity, RootIndex::kTheHoleValue); 2065 return result; 2066 } 2067 AllocateFixedDoubleArrayWithHoles(TNode<IntPtrT> capacity,AllocationFlags flags)2068 TNode<FixedDoubleArray> AllocateFixedDoubleArrayWithHoles( 2069 TNode<IntPtrT> capacity, AllocationFlags flags) { 2070 TNode<FixedDoubleArray> result = UncheckedCast<FixedDoubleArray>( 2071 AllocateFixedArray(PACKED_DOUBLE_ELEMENTS, capacity, flags)); 2072 FillFixedArrayWithValue(PACKED_DOUBLE_ELEMENTS, result, IntPtrConstant(0), 2073 capacity, RootIndex::kTheHoleValue); 2074 return result; 2075 } 2076 2077 TNode<PropertyArray> AllocatePropertyArray(TNode<IntPtrT> capacity); 2078 2079 TNode<HeapObject> AllocateWasmArray(TNode<IntPtrT> size_in_bytes, 2080 int initialization); 2081 2082 // TODO(v8:9722): Return type should be JSIteratorResult 2083 TNode<JSObject> AllocateJSIteratorResult(TNode<Context> context, 2084 TNode<Object> value, 2085 TNode<Oddball> done); 2086 2087 // TODO(v8:9722): Return type should be JSIteratorResult 2088 TNode<JSObject> AllocateJSIteratorResultForEntry(TNode<Context> context, 2089 TNode<Object> key, 2090 TNode<Object> value); 2091 2092 TNode<JSReceiver> ArraySpeciesCreate(TNode<Context> context, 2093 TNode<Object> originalArray, 2094 TNode<Number> len); 2095 2096 template <typename TIndex> 2097 void FillFixedArrayWithValue(ElementsKind kind, TNode<FixedArrayBase> array, 2098 TNode<TIndex> from_index, TNode<TIndex> to_index, 2099 RootIndex value_root_index); 2100 2101 // Uses memset to effectively initialize the given FixedArray with zeroes. 2102 void FillFixedArrayWithSmiZero(TNode<FixedArray> array, 2103 TNode<IntPtrT> length); 2104 void FillFixedDoubleArrayWithZero(TNode<FixedDoubleArray> array, 2105 TNode<IntPtrT> length); 2106 2107 void FillPropertyArrayWithUndefined(TNode<PropertyArray> array, 2108 TNode<IntPtrT> from_index, 2109 TNode<IntPtrT> to_index); 2110 2111 enum class DestroySource { kNo, kYes }; 2112 2113 // Increment the call count for a CALL_IC or construct call. 2114 // The call count is located at feedback_vector[slot_id + 1]. 2115 void IncrementCallCount(TNode<FeedbackVector> feedback_vector, 2116 TNode<UintPtrT> slot_id); 2117 2118 // Specify DestroySource::kYes if {from_array} is being supplanted by 2119 // {to_array}. This offers a slight performance benefit by simply copying the 2120 // array word by word. The source may be destroyed at the end of this macro. 2121 // 2122 // Otherwise, specify DestroySource::kNo for operations where an Object is 2123 // being cloned, to ensure that mutable HeapNumbers are unique between the 2124 // source and cloned object. 2125 void CopyPropertyArrayValues(TNode<HeapObject> from_array, 2126 TNode<PropertyArray> to_array, 2127 TNode<IntPtrT> length, 2128 WriteBarrierMode barrier_mode, 2129 DestroySource destroy_source); 2130 2131 // Copies all elements from |from_array| of |length| size to 2132 // |to_array| of the same size respecting the elements kind. 2133 template <typename TIndex> 2134 void CopyFixedArrayElements( 2135 ElementsKind kind, TNode<FixedArrayBase> from_array, 2136 TNode<FixedArrayBase> to_array, TNode<TIndex> length, 2137 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER) { 2138 CopyFixedArrayElements(kind, from_array, kind, to_array, 2139 IntPtrOrSmiConstant<TIndex>(0), length, length, 2140 barrier_mode); 2141 } 2142 2143 // Copies |element_count| elements from |from_array| starting from element 2144 // zero to |to_array| of |capacity| size respecting both array's elements 2145 // kinds. 2146 template <typename TIndex> 2147 void CopyFixedArrayElements( 2148 ElementsKind from_kind, TNode<FixedArrayBase> from_array, 2149 ElementsKind to_kind, TNode<FixedArrayBase> to_array, 2150 TNode<TIndex> element_count, TNode<TIndex> capacity, 2151 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER) { 2152 CopyFixedArrayElements(from_kind, from_array, to_kind, to_array, 2153 IntPtrOrSmiConstant<TIndex>(0), element_count, 2154 capacity, barrier_mode); 2155 } 2156 2157 // Copies |element_count| elements from |from_array| starting from element 2158 // |first_element| to |to_array| of |capacity| size respecting both array's 2159 // elements kinds. 2160 // |convert_holes| tells the function whether to convert holes to undefined. 2161 // |var_holes_converted| can be used to signify that the conversion happened 2162 // (i.e. that there were holes). If |convert_holes_to_undefined| is 2163 // HoleConversionMode::kConvertToUndefined, then it must not be the case that 2164 // IsDoubleElementsKind(to_kind). 2165 template <typename TIndex> 2166 void CopyFixedArrayElements( 2167 ElementsKind from_kind, TNode<FixedArrayBase> from_array, 2168 ElementsKind to_kind, TNode<FixedArrayBase> to_array, 2169 TNode<TIndex> first_element, TNode<TIndex> element_count, 2170 TNode<TIndex> capacity, 2171 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, 2172 HoleConversionMode convert_holes = HoleConversionMode::kDontConvert, 2173 TVariable<BoolT>* var_holes_converted = nullptr); 2174 2175 void JumpIfPointersFromHereAreInteresting(TNode<Object> object, 2176 Label* interesting); 2177 2178 // Efficiently copy elements within a single array. The regions 2179 // [src_index, src_index + length) and [dst_index, dst_index + length) 2180 // can be overlapping. 2181 void MoveElements(ElementsKind kind, TNode<FixedArrayBase> elements, 2182 TNode<IntPtrT> dst_index, TNode<IntPtrT> src_index, 2183 TNode<IntPtrT> length); 2184 2185 // Efficiently copy elements from one array to another. The ElementsKind 2186 // needs to be the same. Copy from src_elements at 2187 // [src_index, src_index + length) to dst_elements at 2188 // [dst_index, dst_index + length). 2189 // The function decides whether it can use memcpy. In case it cannot, 2190 // |write_barrier| can help it to skip write barrier. SKIP_WRITE_BARRIER is 2191 // only safe when copying to new space, or when copying to old space and the 2192 // array does not contain object pointers. 2193 void CopyElements(ElementsKind kind, TNode<FixedArrayBase> dst_elements, 2194 TNode<IntPtrT> dst_index, 2195 TNode<FixedArrayBase> src_elements, 2196 TNode<IntPtrT> src_index, TNode<IntPtrT> length, 2197 WriteBarrierMode write_barrier = UPDATE_WRITE_BARRIER); 2198 2199 TNode<FixedArray> HeapObjectToFixedArray(TNode<HeapObject> base, 2200 Label* cast_fail); 2201 HeapObjectToFixedDoubleArray(TNode<HeapObject> base,Label * cast_fail)2202 TNode<FixedDoubleArray> HeapObjectToFixedDoubleArray(TNode<HeapObject> base, 2203 Label* cast_fail) { 2204 GotoIf(TaggedNotEqual(LoadMap(base), FixedDoubleArrayMapConstant()), 2205 cast_fail); 2206 return UncheckedCast<FixedDoubleArray>(base); 2207 } 2208 2209 template <typename T> ClassHasMapConstant()2210 bool ClassHasMapConstant() { 2211 return false; 2212 } 2213 2214 template <typename T> GetClassMapConstant()2215 TNode<Map> GetClassMapConstant() { 2216 UNREACHABLE(); 2217 return TNode<Map>(); 2218 } 2219 2220 enum class ExtractFixedArrayFlag { 2221 kFixedArrays = 1, 2222 kFixedDoubleArrays = 2, 2223 kDontCopyCOW = 4, 2224 kAllFixedArrays = kFixedArrays | kFixedDoubleArrays, 2225 kAllFixedArraysDontCopyCOW = kAllFixedArrays | kDontCopyCOW 2226 }; 2227 2228 using ExtractFixedArrayFlags = base::Flags<ExtractFixedArrayFlag>; 2229 2230 // Copy a portion of an existing FixedArray or FixedDoubleArray into a new 2231 // array, including special appropriate handling for empty arrays and COW 2232 // arrays. The result array will be of the same type as the original array. 2233 // 2234 // * |source| is either a FixedArray or FixedDoubleArray from which to copy 2235 // elements. 2236 // * |first| is the starting element index to copy from, if nullptr is passed 2237 // then index zero is used by default. 2238 // * |count| is the number of elements to copy out of the source array 2239 // starting from and including the element indexed by |start|. If |count| is 2240 // nullptr, then all of the elements from |start| to the end of |source| are 2241 // copied. 2242 // * |capacity| determines the size of the allocated result array, with 2243 // |capacity| >= |count|. If |capacity| is nullptr, then |count| is used as 2244 // the destination array's capacity. 2245 // * |extract_flags| determines whether FixedArrays, FixedDoubleArrays or both 2246 // are detected and copied. Although it's always correct to pass 2247 // kAllFixedArrays, the generated code is more compact and efficient if the 2248 // caller can specify whether only FixedArrays or FixedDoubleArrays will be 2249 // passed as the |source| parameter. 2250 // * |parameter_mode| determines the parameter mode of |first|, |count| and 2251 // |capacity|. 2252 // * If |var_holes_converted| is given, any holes will be converted to 2253 // undefined and the variable will be set according to whether or not there 2254 // were any hole. 2255 // * If |source_elements_kind| is given, the function will try to use the 2256 // runtime elements kind of source to make copy faster. More specifically, it 2257 // can skip write barriers. 2258 template <typename TIndex> 2259 TNode<FixedArrayBase> ExtractFixedArray( 2260 TNode<FixedArrayBase> source, base::Optional<TNode<TIndex>> first, 2261 base::Optional<TNode<TIndex>> count = base::nullopt, 2262 base::Optional<TNode<TIndex>> capacity = base::nullopt, 2263 ExtractFixedArrayFlags extract_flags = 2264 ExtractFixedArrayFlag::kAllFixedArrays, 2265 TVariable<BoolT>* var_holes_converted = nullptr, 2266 base::Optional<TNode<Int32T>> source_elements_kind = base::nullopt); 2267 2268 // Copy a portion of an existing FixedArray or FixedDoubleArray into a new 2269 // FixedArray, including special appropriate handling for COW arrays. 2270 // * |source| is either a FixedArray or FixedDoubleArray from which to copy 2271 // elements. |source| is assumed to be non-empty. 2272 // * |first| is the starting element index to copy from. 2273 // * |count| is the number of elements to copy out of the source array 2274 // starting from and including the element indexed by |start|. 2275 // * |capacity| determines the size of the allocated result array, with 2276 // |capacity| >= |count|. 2277 // * |source_map| is the map of the |source|. 2278 // * |from_kind| is the elements kind that is consistent with |source| being 2279 // a FixedArray or FixedDoubleArray. This function only cares about double vs. 2280 // non-double, so as to distinguish FixedDoubleArray vs. FixedArray. It does 2281 // not care about holeyness. For example, when |source| is a FixedArray, 2282 // PACKED/HOLEY_ELEMENTS can be used, but not PACKED_DOUBLE_ELEMENTS. 2283 // * |allocation_flags| and |extract_flags| influence how the target 2284 // FixedArray is allocated. 2285 // * |convert_holes| is used to signify that the target array should use 2286 // undefined in places of holes. 2287 // * If |convert_holes| is true and |var_holes_converted| not nullptr, then 2288 // |var_holes_converted| is used to signal whether any holes were found and 2289 // converted. The caller should use this information to decide which map is 2290 // compatible with the result array. For example, if the input was of 2291 // HOLEY_SMI_ELEMENTS kind, and a conversion took place, the result will be 2292 // compatible only with HOLEY_ELEMENTS and PACKED_ELEMENTS. 2293 template <typename TIndex> 2294 TNode<FixedArray> ExtractToFixedArray( 2295 TNode<FixedArrayBase> source, TNode<TIndex> first, TNode<TIndex> count, 2296 TNode<TIndex> capacity, TNode<Map> source_map, ElementsKind from_kind, 2297 AllocationFlags allocation_flags, ExtractFixedArrayFlags extract_flags, 2298 HoleConversionMode convert_holes, 2299 TVariable<BoolT>* var_holes_converted = nullptr, 2300 base::Optional<TNode<Int32T>> source_runtime_kind = base::nullopt); 2301 2302 // Attempt to copy a FixedDoubleArray to another FixedDoubleArray. In the case 2303 // where the source array has a hole, produce a FixedArray instead where holes 2304 // are replaced with undefined. 2305 // * |source| is a FixedDoubleArray from which to copy elements. 2306 // * |first| is the starting element index to copy from. 2307 // * |count| is the number of elements to copy out of the source array 2308 // starting from and including the element indexed by |start|. 2309 // * |capacity| determines the size of the allocated result array, with 2310 // |capacity| >= |count|. 2311 // * |source_map| is the map of |source|. It will be used as the map of the 2312 // target array if the target can stay a FixedDoubleArray. Otherwise if the 2313 // target array needs to be a FixedArray, the FixedArrayMap will be used. 2314 // * |var_holes_converted| is used to signal whether a FixedAray 2315 // is produced or not. 2316 // * |allocation_flags| and |extract_flags| influence how the target array is 2317 // allocated. 2318 template <typename TIndex> 2319 TNode<FixedArrayBase> ExtractFixedDoubleArrayFillingHoles( 2320 TNode<FixedArrayBase> source, TNode<TIndex> first, TNode<TIndex> count, 2321 TNode<TIndex> capacity, TNode<Map> source_map, 2322 TVariable<BoolT>* var_holes_converted, AllocationFlags allocation_flags, 2323 ExtractFixedArrayFlags extract_flags); 2324 2325 // Copy the entire contents of a FixedArray or FixedDoubleArray to a new 2326 // array, including special appropriate handling for empty arrays and COW 2327 // arrays. 2328 // 2329 // * |source| is either a FixedArray or FixedDoubleArray from which to copy 2330 // elements. 2331 // * |extract_flags| determines whether FixedArrays, FixedDoubleArrays or both 2332 // are detected and copied. Although it's always correct to pass 2333 // kAllFixedArrays, the generated code is more compact and efficient if the 2334 // caller can specify whether only FixedArrays or FixedDoubleArrays will be 2335 // passed as the |source| parameter. 2336 TNode<FixedArrayBase> CloneFixedArray( 2337 TNode<FixedArrayBase> source, 2338 ExtractFixedArrayFlags flags = 2339 ExtractFixedArrayFlag::kAllFixedArraysDontCopyCOW); 2340 2341 // Loads an element from |array| of |from_kind| elements by given |offset| 2342 // (NOTE: not index!), does a hole check if |if_hole| is provided and 2343 // converts the value so that it becomes ready for storing to array of 2344 // |to_kind| elements. 2345 template <typename TResult> 2346 TNode<TResult> LoadElementAndPrepareForStore(TNode<FixedArrayBase> array, 2347 TNode<IntPtrT> offset, 2348 ElementsKind from_kind, 2349 ElementsKind to_kind, 2350 Label* if_hole); 2351 2352 template <typename TIndex> 2353 TNode<TIndex> CalculateNewElementsCapacity(TNode<TIndex> old_capacity); 2354 2355 // Tries to grow the |elements| array of given |object| to store the |key| 2356 // or bails out if the growing gap is too big. Returns new elements. 2357 TNode<FixedArrayBase> TryGrowElementsCapacity(TNode<HeapObject> object, 2358 TNode<FixedArrayBase> elements, 2359 ElementsKind kind, 2360 TNode<Smi> key, Label* bailout); 2361 2362 // Tries to grow the |capacity|-length |elements| array of given |object| 2363 // to store the |key| or bails out if the growing gap is too big. Returns 2364 // new elements. 2365 template <typename TIndex> 2366 TNode<FixedArrayBase> TryGrowElementsCapacity(TNode<HeapObject> object, 2367 TNode<FixedArrayBase> elements, 2368 ElementsKind kind, 2369 TNode<TIndex> key, 2370 TNode<TIndex> capacity, 2371 Label* bailout); 2372 2373 // Grows elements capacity of given object. Returns new elements. 2374 template <typename TIndex> 2375 TNode<FixedArrayBase> GrowElementsCapacity( 2376 TNode<HeapObject> object, TNode<FixedArrayBase> elements, 2377 ElementsKind from_kind, ElementsKind to_kind, TNode<TIndex> capacity, 2378 TNode<TIndex> new_capacity, Label* bailout); 2379 2380 // Given a need to grow by |growth|, allocate an appropriate new capacity 2381 // if necessary, and return a new elements FixedArray object. Label |bailout| 2382 // is followed for allocation failure. 2383 void PossiblyGrowElementsCapacity(ElementsKind kind, TNode<HeapObject> array, 2384 TNode<BInt> length, 2385 TVariable<FixedArrayBase>* var_elements, 2386 TNode<BInt> growth, Label* bailout); 2387 2388 // Allocation site manipulation 2389 void InitializeAllocationMemento(TNode<HeapObject> base, 2390 TNode<IntPtrT> base_allocation_size, 2391 TNode<AllocationSite> allocation_site); 2392 2393 TNode<IntPtrT> TryTaggedToInt32AsIntPtr(TNode<Object> value, 2394 Label* if_not_possible); 2395 TNode<Float64T> TryTaggedToFloat64(TNode<Object> value, 2396 Label* if_valueisnotnumber); 2397 TNode<Float64T> TruncateTaggedToFloat64(TNode<Context> context, 2398 TNode<Object> value); 2399 TNode<Word32T> TruncateTaggedToWord32(TNode<Context> context, 2400 TNode<Object> value); 2401 void TaggedToWord32OrBigInt(TNode<Context> context, TNode<Object> value, 2402 Label* if_number, TVariable<Word32T>* var_word32, 2403 Label* if_bigint, 2404 TVariable<BigInt>* var_maybe_bigint); 2405 void TaggedToWord32OrBigIntWithFeedback(TNode<Context> context, 2406 TNode<Object> value, Label* if_number, 2407 TVariable<Word32T>* var_word32, 2408 Label* if_bigint, 2409 TVariable<BigInt>* var_maybe_bigint, 2410 TVariable<Smi>* var_feedback); 2411 void TaggedPointerToWord32OrBigIntWithFeedback( 2412 TNode<Context> context, TNode<HeapObject> pointer, Label* if_number, 2413 TVariable<Word32T>* var_word32, Label* if_bigint, 2414 TVariable<BigInt>* var_maybe_bigint, TVariable<Smi>* var_feedback); 2415 2416 TNode<Int32T> TruncateNumberToWord32(TNode<Number> value); 2417 // Truncate the floating point value of a HeapNumber to an Int32. 2418 TNode<Int32T> TruncateHeapNumberValueToWord32(TNode<HeapNumber> object); 2419 2420 // Conversions. 2421 void TryHeapNumberToSmi(TNode<HeapNumber> number, TVariable<Smi>* output, 2422 Label* if_smi); 2423 void TryFloat32ToSmi(TNode<Float32T> number, TVariable<Smi>* output, 2424 Label* if_smi); 2425 void TryFloat64ToSmi(TNode<Float64T> number, TVariable<Smi>* output, 2426 Label* if_smi); 2427 TNode<Number> ChangeFloat32ToTagged(TNode<Float32T> value); 2428 TNode<Number> ChangeFloat64ToTagged(TNode<Float64T> value); 2429 TNode<Number> ChangeInt32ToTagged(TNode<Int32T> value); 2430 TNode<Number> ChangeInt32ToTaggedNoOverflow(TNode<Int32T> value); 2431 TNode<Number> ChangeUint32ToTagged(TNode<Uint32T> value); 2432 TNode<Number> ChangeUintPtrToTagged(TNode<UintPtrT> value); 2433 TNode<Uint32T> ChangeNumberToUint32(TNode<Number> value); 2434 TNode<Float64T> ChangeNumberToFloat64(TNode<Number> value); 2435 2436 TNode<Int32T> ChangeTaggedNonSmiToInt32(TNode<Context> context, 2437 TNode<HeapObject> input); 2438 TNode<Float64T> ChangeTaggedToFloat64(TNode<Context> context, 2439 TNode<Object> input); 2440 2441 TNode<Int32T> ChangeBoolToInt32(TNode<BoolT> b); 2442 2443 void TaggedToNumeric(TNode<Context> context, TNode<Object> value, 2444 TVariable<Numeric>* var_numeric); 2445 void TaggedToNumericWithFeedback(TNode<Context> context, TNode<Object> value, 2446 TVariable<Numeric>* var_numeric, 2447 TVariable<Smi>* var_feedback); 2448 2449 // Ensures that {var_shared_value} is shareable across Isolates, and throws if 2450 // not. 2451 void SharedValueBarrier(TNode<Context> context, 2452 TVariable<Object>* var_shared_value); 2453 2454 TNode<WordT> TimesSystemPointerSize(TNode<WordT> value); TimesSystemPointerSize(TNode<IntPtrT> value)2455 TNode<IntPtrT> TimesSystemPointerSize(TNode<IntPtrT> value) { 2456 return Signed(TimesSystemPointerSize(implicit_cast<TNode<WordT>>(value))); 2457 } TimesSystemPointerSize(TNode<UintPtrT> value)2458 TNode<UintPtrT> TimesSystemPointerSize(TNode<UintPtrT> value) { 2459 return Unsigned(TimesSystemPointerSize(implicit_cast<TNode<WordT>>(value))); 2460 } 2461 2462 TNode<WordT> TimesTaggedSize(TNode<WordT> value); TimesTaggedSize(TNode<IntPtrT> value)2463 TNode<IntPtrT> TimesTaggedSize(TNode<IntPtrT> value) { 2464 return Signed(TimesTaggedSize(implicit_cast<TNode<WordT>>(value))); 2465 } TimesTaggedSize(TNode<UintPtrT> value)2466 TNode<UintPtrT> TimesTaggedSize(TNode<UintPtrT> value) { 2467 return Unsigned(TimesTaggedSize(implicit_cast<TNode<WordT>>(value))); 2468 } 2469 2470 TNode<WordT> TimesDoubleSize(TNode<WordT> value); TimesDoubleSize(TNode<UintPtrT> value)2471 TNode<UintPtrT> TimesDoubleSize(TNode<UintPtrT> value) { 2472 return Unsigned(TimesDoubleSize(implicit_cast<TNode<WordT>>(value))); 2473 } TimesDoubleSize(TNode<IntPtrT> value)2474 TNode<IntPtrT> TimesDoubleSize(TNode<IntPtrT> value) { 2475 return Signed(TimesDoubleSize(implicit_cast<TNode<WordT>>(value))); 2476 } 2477 2478 // Type conversions. 2479 // Throws a TypeError for {method_name} if {value} is not coercible to Object, 2480 // or returns the {value} converted to a String otherwise. 2481 TNode<String> ToThisString(TNode<Context> context, TNode<Object> value, 2482 TNode<String> method_name); ToThisString(TNode<Context> context,TNode<Object> value,char const * method_name)2483 TNode<String> ToThisString(TNode<Context> context, TNode<Object> value, 2484 char const* method_name) { 2485 return ToThisString(context, value, StringConstant(method_name)); 2486 } 2487 2488 // Throws a TypeError for {method_name} if {value} is neither of the given 2489 // {primitive_type} nor a JSPrimitiveWrapper wrapping a value of 2490 // {primitive_type}, or returns the {value} (or wrapped value) otherwise. 2491 TNode<Object> ToThisValue(TNode<Context> context, TNode<Object> value, 2492 PrimitiveType primitive_type, 2493 char const* method_name); 2494 2495 // Throws a TypeError for {method_name} if {value} is not of the given 2496 // instance type. 2497 void ThrowIfNotInstanceType(TNode<Context> context, TNode<Object> value, 2498 InstanceType instance_type, 2499 char const* method_name); 2500 // Throws a TypeError for {method_name} if {value} is not a JSReceiver. 2501 void ThrowIfNotJSReceiver(TNode<Context> context, TNode<Object> value, 2502 MessageTemplate msg_template, 2503 const char* method_name); 2504 void ThrowIfNotCallable(TNode<Context> context, TNode<Object> value, 2505 const char* method_name); 2506 2507 void ThrowRangeError(TNode<Context> context, MessageTemplate message, 2508 base::Optional<TNode<Object>> arg0 = base::nullopt, 2509 base::Optional<TNode<Object>> arg1 = base::nullopt, 2510 base::Optional<TNode<Object>> arg2 = base::nullopt); 2511 void ThrowTypeError(TNode<Context> context, MessageTemplate message, 2512 char const* arg0 = nullptr, char const* arg1 = nullptr); 2513 void ThrowTypeError(TNode<Context> context, MessageTemplate message, 2514 base::Optional<TNode<Object>> arg0, 2515 base::Optional<TNode<Object>> arg1 = base::nullopt, 2516 base::Optional<TNode<Object>> arg2 = base::nullopt); 2517 2518 TNode<HeapObject> GetPendingMessage(); 2519 void SetPendingMessage(TNode<HeapObject> message); 2520 2521 // Type checks. 2522 // Check whether the map is for an object with special properties, such as a 2523 // JSProxy or an object with interceptors. 2524 TNode<BoolT> InstanceTypeEqual(TNode<Int32T> instance_type, int type); 2525 TNode<BoolT> IsNoElementsProtectorCellInvalid(); 2526 TNode<BoolT> IsMegaDOMProtectorCellInvalid(); 2527 TNode<BoolT> IsArrayIteratorProtectorCellInvalid(); 2528 TNode<BoolT> IsBigIntInstanceType(TNode<Int32T> instance_type); 2529 TNode<BoolT> IsBigInt(TNode<HeapObject> object); 2530 TNode<BoolT> IsBoolean(TNode<HeapObject> object); 2531 TNode<BoolT> IsCallableMap(TNode<Map> map); 2532 TNode<BoolT> IsCallable(TNode<HeapObject> object); 2533 TNode<BoolT> TaggedIsCallable(TNode<Object> object); 2534 TNode<BoolT> IsConsStringInstanceType(TNode<Int32T> instance_type); 2535 TNode<BoolT> IsConstructorMap(TNode<Map> map); 2536 TNode<BoolT> IsConstructor(TNode<HeapObject> object); 2537 TNode<BoolT> IsDeprecatedMap(TNode<Map> map); 2538 TNode<BoolT> IsNameDictionary(TNode<HeapObject> object); 2539 TNode<BoolT> IsOrderedNameDictionary(TNode<HeapObject> object); 2540 TNode<BoolT> IsGlobalDictionary(TNode<HeapObject> object); 2541 TNode<BoolT> IsExtensibleMap(TNode<Map> map); 2542 TNode<BoolT> IsExtensibleNonPrototypeMap(TNode<Map> map); 2543 TNode<BoolT> IsExternalStringInstanceType(TNode<Int32T> instance_type); 2544 TNode<BoolT> IsFixedArray(TNode<HeapObject> object); 2545 TNode<BoolT> IsFixedArraySubclass(TNode<HeapObject> object); 2546 TNode<BoolT> IsFixedArrayWithKind(TNode<HeapObject> object, 2547 ElementsKind kind); 2548 TNode<BoolT> IsFixedArrayWithKindOrEmpty(TNode<FixedArrayBase> object, 2549 ElementsKind kind); 2550 TNode<BoolT> IsFunctionWithPrototypeSlotMap(TNode<Map> map); 2551 TNode<BoolT> IsHashTable(TNode<HeapObject> object); 2552 TNode<BoolT> IsEphemeronHashTable(TNode<HeapObject> object); 2553 TNode<BoolT> IsHeapNumberInstanceType(TNode<Int32T> instance_type); 2554 TNode<BoolT> IsOddball(TNode<HeapObject> object); 2555 TNode<BoolT> IsOddballInstanceType(TNode<Int32T> instance_type); 2556 TNode<BoolT> IsIndirectStringInstanceType(TNode<Int32T> instance_type); 2557 TNode<BoolT> IsJSArrayBuffer(TNode<HeapObject> object); 2558 TNode<BoolT> IsJSDataView(TNode<HeapObject> object); 2559 TNode<BoolT> IsJSArrayInstanceType(TNode<Int32T> instance_type); 2560 TNode<BoolT> IsJSArrayMap(TNode<Map> map); 2561 TNode<BoolT> IsJSArray(TNode<HeapObject> object); 2562 TNode<BoolT> IsJSArrayIterator(TNode<HeapObject> object); 2563 TNode<BoolT> IsJSAsyncGeneratorObject(TNode<HeapObject> object); 2564 TNode<BoolT> IsFunctionInstanceType(TNode<Int32T> instance_type); 2565 TNode<BoolT> IsJSFunctionInstanceType(TNode<Int32T> instance_type); 2566 TNode<BoolT> IsJSFunctionMap(TNode<Map> map); 2567 TNode<BoolT> IsJSFunction(TNode<HeapObject> object); 2568 TNode<BoolT> IsJSBoundFunction(TNode<HeapObject> object); 2569 TNode<BoolT> IsJSGeneratorObject(TNode<HeapObject> object); 2570 TNode<BoolT> IsJSGlobalProxyInstanceType(TNode<Int32T> instance_type); 2571 TNode<BoolT> IsJSGlobalProxyMap(TNode<Map> map); 2572 TNode<BoolT> IsJSGlobalProxy(TNode<HeapObject> object); 2573 TNode<BoolT> IsJSObjectInstanceType(TNode<Int32T> instance_type); 2574 TNode<BoolT> IsJSObjectMap(TNode<Map> map); 2575 TNode<BoolT> IsJSObject(TNode<HeapObject> object); 2576 TNode<BoolT> IsJSApiObjectInstanceType(TNode<Int32T> instance_type); 2577 TNode<BoolT> IsJSApiObjectMap(TNode<Map> map); 2578 TNode<BoolT> IsJSApiObject(TNode<HeapObject> object); 2579 TNode<BoolT> IsJSFinalizationRegistryMap(TNode<Map> map); 2580 TNode<BoolT> IsJSFinalizationRegistry(TNode<HeapObject> object); 2581 TNode<BoolT> IsJSPromiseMap(TNode<Map> map); 2582 TNode<BoolT> IsJSPromise(TNode<HeapObject> object); 2583 TNode<BoolT> IsJSProxy(TNode<HeapObject> object); 2584 TNode<BoolT> IsJSStringIterator(TNode<HeapObject> object); 2585 TNode<BoolT> IsJSRegExpStringIterator(TNode<HeapObject> object); 2586 TNode<BoolT> IsJSReceiverInstanceType(TNode<Int32T> instance_type); 2587 TNode<BoolT> IsJSReceiverMap(TNode<Map> map); 2588 TNode<BoolT> IsJSReceiver(TNode<HeapObject> object); 2589 TNode<BoolT> IsJSRegExp(TNode<HeapObject> object); 2590 TNode<BoolT> IsJSTypedArrayInstanceType(TNode<Int32T> instance_type); 2591 TNode<BoolT> IsJSTypedArrayMap(TNode<Map> map); 2592 TNode<BoolT> IsJSTypedArray(TNode<HeapObject> object); 2593 TNode<BoolT> IsJSGeneratorMap(TNode<Map> map); 2594 TNode<BoolT> IsJSPrimitiveWrapperInstanceType(TNode<Int32T> instance_type); 2595 TNode<BoolT> IsJSPrimitiveWrapperMap(TNode<Map> map); 2596 TNode<BoolT> IsJSPrimitiveWrapper(TNode<HeapObject> object); 2597 TNode<BoolT> IsJSSharedStructInstanceType(TNode<Int32T> instance_type); 2598 TNode<BoolT> IsJSSharedStructMap(TNode<Map> map); 2599 TNode<BoolT> IsJSSharedStruct(TNode<HeapObject> object); 2600 TNode<BoolT> IsJSSharedStruct(TNode<Object> object); 2601 TNode<BoolT> IsJSWrappedFunction(TNode<HeapObject> object); 2602 TNode<BoolT> IsMap(TNode<HeapObject> object); 2603 TNode<BoolT> IsName(TNode<HeapObject> object); 2604 TNode<BoolT> IsNameInstanceType(TNode<Int32T> instance_type); 2605 TNode<BoolT> IsNullOrJSReceiver(TNode<HeapObject> object); 2606 TNode<BoolT> IsNullOrUndefined(TNode<Object> object); 2607 TNode<BoolT> IsNumberDictionary(TNode<HeapObject> object); 2608 TNode<BoolT> IsOneByteStringInstanceType(TNode<Int32T> instance_type); 2609 TNode<BoolT> IsSeqOneByteStringInstanceType(TNode<Int32T> instance_type); 2610 TNode<BoolT> IsPrimitiveInstanceType(TNode<Int32T> instance_type); 2611 TNode<BoolT> IsPrivateName(TNode<Symbol> symbol); 2612 TNode<BoolT> IsPropertyArray(TNode<HeapObject> object); 2613 TNode<BoolT> IsPropertyCell(TNode<HeapObject> object); 2614 TNode<BoolT> IsPromiseReactionJobTask(TNode<HeapObject> object); 2615 TNode<BoolT> IsPrototypeInitialArrayPrototype(TNode<Context> context, 2616 TNode<Map> map); 2617 TNode<BoolT> IsPrototypeTypedArrayPrototype(TNode<Context> context, 2618 TNode<Map> map); 2619 2620 TNode<BoolT> IsFastAliasedArgumentsMap(TNode<Context> context, 2621 TNode<Map> map); 2622 TNode<BoolT> IsSlowAliasedArgumentsMap(TNode<Context> context, 2623 TNode<Map> map); 2624 TNode<BoolT> IsSloppyArgumentsMap(TNode<Context> context, TNode<Map> map); 2625 TNode<BoolT> IsStrictArgumentsMap(TNode<Context> context, TNode<Map> map); 2626 2627 TNode<BoolT> IsSequentialStringInstanceType(TNode<Int32T> instance_type); 2628 TNode<BoolT> IsUncachedExternalStringInstanceType( 2629 TNode<Int32T> instance_type); 2630 TNode<BoolT> IsSpecialReceiverInstanceType(TNode<Int32T> instance_type); 2631 TNode<BoolT> IsCustomElementsReceiverInstanceType( 2632 TNode<Int32T> instance_type); 2633 TNode<BoolT> IsSpecialReceiverMap(TNode<Map> map); 2634 TNode<BoolT> IsStringInstanceType(TNode<Int32T> instance_type); 2635 TNode<BoolT> IsString(TNode<HeapObject> object); 2636 TNode<BoolT> IsSeqOneByteString(TNode<HeapObject> object); 2637 TNode<BoolT> IsSwissNameDictionary(TNode<HeapObject> object); 2638 2639 TNode<BoolT> IsSymbolInstanceType(TNode<Int32T> instance_type); 2640 TNode<BoolT> IsInternalizedStringInstanceType(TNode<Int32T> instance_type); 2641 TNode<BoolT> IsSharedStringInstanceType(TNode<Int32T> instance_type); 2642 TNode<BoolT> IsTemporalInstantInstanceType(TNode<Int32T> instance_type); 2643 TNode<BoolT> IsUniqueName(TNode<HeapObject> object); 2644 TNode<BoolT> IsUniqueNameNoIndex(TNode<HeapObject> object); 2645 TNode<BoolT> IsUniqueNameNoCachedIndex(TNode<HeapObject> object); 2646 TNode<BoolT> IsUndetectableMap(TNode<Map> map); 2647 TNode<BoolT> IsNotWeakFixedArraySubclass(TNode<HeapObject> object); 2648 TNode<BoolT> IsZeroOrContext(TNode<Object> object); 2649 2650 TNode<BoolT> IsPromiseResolveProtectorCellInvalid(); 2651 TNode<BoolT> IsPromiseThenProtectorCellInvalid(); 2652 TNode<BoolT> IsArraySpeciesProtectorCellInvalid(); 2653 TNode<BoolT> IsIsConcatSpreadableProtectorCellInvalid(); 2654 TNode<BoolT> IsTypedArraySpeciesProtectorCellInvalid(); 2655 TNode<BoolT> IsRegExpSpeciesProtectorCellInvalid(); 2656 TNode<BoolT> IsPromiseSpeciesProtectorCellInvalid(); 2657 2658 TNode<IntPtrT> LoadBasicMemoryChunkFlags(TNode<HeapObject> object); 2659 LoadRuntimeFlag(ExternalReference address_of_flag)2660 TNode<BoolT> LoadRuntimeFlag(ExternalReference address_of_flag) { 2661 TNode<Word32T> flag_value = UncheckedCast<Word32T>( 2662 Load(MachineType::Uint8(), ExternalConstant(address_of_flag))); 2663 return Word32NotEqual(Word32And(flag_value, Int32Constant(0xFF)), 2664 Int32Constant(0)); 2665 } 2666 IsMockArrayBufferAllocatorFlag()2667 TNode<BoolT> IsMockArrayBufferAllocatorFlag() { 2668 return LoadRuntimeFlag( 2669 ExternalReference::address_of_mock_arraybuffer_allocator_flag()); 2670 } 2671 HasBuiltinSubclassingFlag()2672 TNode<BoolT> HasBuiltinSubclassingFlag() { 2673 return LoadRuntimeFlag( 2674 ExternalReference::address_of_builtin_subclassing_flag()); 2675 } 2676 HasSharedStringTableFlag()2677 TNode<BoolT> HasSharedStringTableFlag() { 2678 return LoadRuntimeFlag( 2679 ExternalReference::address_of_shared_string_table_flag()); 2680 } 2681 2682 // True iff |object| is a Smi or a HeapNumber or a BigInt. 2683 TNode<BoolT> IsNumeric(TNode<Object> object); 2684 2685 // True iff |number| is either a Smi, or a HeapNumber whose value is not 2686 // within Smi range. 2687 TNode<BoolT> IsNumberNormalized(TNode<Number> number); 2688 TNode<BoolT> IsNumberPositive(TNode<Number> number); 2689 TNode<BoolT> IsHeapNumberPositive(TNode<HeapNumber> number); 2690 2691 // True iff {number} is non-negative and less or equal than 2**53-1. 2692 TNode<BoolT> IsNumberNonNegativeSafeInteger(TNode<Number> number); 2693 2694 // True iff {number} represents an integer value. 2695 TNode<BoolT> IsInteger(TNode<Object> number); 2696 TNode<BoolT> IsInteger(TNode<HeapNumber> number); 2697 2698 // True iff abs({number}) <= 2**53 -1 2699 TNode<BoolT> IsSafeInteger(TNode<Object> number); 2700 TNode<BoolT> IsSafeInteger(TNode<HeapNumber> number); 2701 2702 // True iff {number} represents a valid uint32t value. 2703 TNode<BoolT> IsHeapNumberUint32(TNode<HeapNumber> number); 2704 2705 // True iff {number} is a positive number and a valid array index in the range 2706 // [0, 2^32-1). 2707 TNode<BoolT> IsNumberArrayIndex(TNode<Number> number); 2708 2709 template <typename TIndex> 2710 TNode<BoolT> FixedArraySizeDoesntFitInNewSpace(TNode<TIndex> element_count, 2711 int base_size); 2712 IsMetaMap(TNode<HeapObject> o)2713 TNode<BoolT> IsMetaMap(TNode<HeapObject> o) { return IsMapMap(o); } 2714 2715 // ElementsKind helpers: ElementsKindEqual(TNode<Int32T> a,TNode<Int32T> b)2716 TNode<BoolT> ElementsKindEqual(TNode<Int32T> a, TNode<Int32T> b) { 2717 return Word32Equal(a, b); 2718 } ElementsKindEqual(ElementsKind a,ElementsKind b)2719 bool ElementsKindEqual(ElementsKind a, ElementsKind b) { return a == b; } 2720 TNode<BoolT> IsFastElementsKind(TNode<Int32T> elements_kind); IsFastElementsKind(ElementsKind kind)2721 bool IsFastElementsKind(ElementsKind kind) { 2722 return v8::internal::IsFastElementsKind(kind); 2723 } 2724 TNode<BoolT> IsFastOrNonExtensibleOrSealedElementsKind( 2725 TNode<Int32T> elements_kind); 2726 IsDictionaryElementsKind(TNode<Int32T> elements_kind)2727 TNode<BoolT> IsDictionaryElementsKind(TNode<Int32T> elements_kind) { 2728 return ElementsKindEqual(elements_kind, Int32Constant(DICTIONARY_ELEMENTS)); 2729 } 2730 TNode<BoolT> IsDoubleElementsKind(TNode<Int32T> elements_kind); IsDoubleElementsKind(ElementsKind kind)2731 bool IsDoubleElementsKind(ElementsKind kind) { 2732 return v8::internal::IsDoubleElementsKind(kind); 2733 } 2734 TNode<BoolT> IsFastSmiOrTaggedElementsKind(TNode<Int32T> elements_kind); 2735 TNode<BoolT> IsFastSmiElementsKind(TNode<Int32T> elements_kind); 2736 TNode<BoolT> IsHoleyFastElementsKind(TNode<Int32T> elements_kind); 2737 TNode<BoolT> IsHoleyFastElementsKindForRead(TNode<Int32T> elements_kind); 2738 TNode<BoolT> IsElementsKindGreaterThan(TNode<Int32T> target_kind, 2739 ElementsKind reference_kind); 2740 TNode<BoolT> IsElementsKindGreaterThanOrEqual(TNode<Int32T> target_kind, 2741 ElementsKind reference_kind); 2742 TNode<BoolT> IsElementsKindLessThanOrEqual(TNode<Int32T> target_kind, 2743 ElementsKind reference_kind); 2744 // Check if lower_reference_kind <= target_kind <= higher_reference_kind. IsElementsKindInRange(TNode<Int32T> target_kind,ElementsKind lower_reference_kind,ElementsKind higher_reference_kind)2745 TNode<BoolT> IsElementsKindInRange(TNode<Int32T> target_kind, 2746 ElementsKind lower_reference_kind, 2747 ElementsKind higher_reference_kind) { 2748 return IsInRange(target_kind, lower_reference_kind, higher_reference_kind); 2749 } 2750 2751 // String helpers. 2752 // Load a character from a String (might flatten a ConsString). 2753 TNode<Uint16T> StringCharCodeAt(TNode<String> string, TNode<UintPtrT> index); 2754 // Return the single character string with only {code}. 2755 TNode<String> StringFromSingleCharCode(TNode<Int32T> code); 2756 2757 // Type conversion helpers. 2758 enum class BigIntHandling { kConvertToNumber, kThrow }; 2759 // Convert a String to a Number. 2760 TNode<Number> StringToNumber(TNode<String> input); 2761 // Convert a Number to a String. 2762 TNode<String> NumberToString(TNode<Number> input); 2763 TNode<String> NumberToString(TNode<Number> input, Label* bailout); 2764 2765 // Convert a Non-Number object to a Number. 2766 TNode<Number> NonNumberToNumber( 2767 TNode<Context> context, TNode<HeapObject> input, 2768 BigIntHandling bigint_handling = BigIntHandling::kThrow); 2769 // Convert a Non-Number object to a Numeric. 2770 TNode<Numeric> NonNumberToNumeric(TNode<Context> context, 2771 TNode<HeapObject> input); 2772 // Convert any object to a Number. 2773 // Conforms to ES#sec-tonumber if {bigint_handling} == kThrow. 2774 // With {bigint_handling} == kConvertToNumber, matches behavior of 2775 // tc39.github.io/proposal-bigint/#sec-number-constructor-number-value. 2776 TNode<Number> ToNumber( 2777 TNode<Context> context, TNode<Object> input, 2778 BigIntHandling bigint_handling = BigIntHandling::kThrow); 2779 TNode<Number> ToNumber_Inline(TNode<Context> context, TNode<Object> input); 2780 TNode<Numeric> ToNumberOrNumeric( 2781 LazyNode<Context> context, TNode<Object> input, 2782 TVariable<Smi>* var_type_feedback, Object::Conversion mode, 2783 BigIntHandling bigint_handling = BigIntHandling::kThrow); 2784 // Convert any plain primitive to a Number. No need to handle BigInts since 2785 // they are not plain primitives. 2786 TNode<Number> PlainPrimitiveToNumber(TNode<Object> input); 2787 2788 // Try to convert an object to a BigInt. Throws on failure (e.g. for Numbers). 2789 // https://tc39.github.io/proposal-bigint/#sec-to-bigint 2790 TNode<BigInt> ToBigInt(TNode<Context> context, TNode<Object> input); 2791 2792 // Converts |input| to one of 2^32 integer values in the range 0 through 2793 // 2^32-1, inclusive. 2794 // ES#sec-touint32 2795 TNode<Number> ToUint32(TNode<Context> context, TNode<Object> input); 2796 2797 // Convert any object to a String. 2798 TNode<String> ToString_Inline(TNode<Context> context, TNode<Object> input); 2799 2800 TNode<JSReceiver> ToObject(TNode<Context> context, TNode<Object> input); 2801 2802 // Same as ToObject but avoids the Builtin call if |input| is already a 2803 // JSReceiver. 2804 TNode<JSReceiver> ToObject_Inline(TNode<Context> context, 2805 TNode<Object> input); 2806 2807 // ES6 7.1.15 ToLength, but with inlined fast path. 2808 TNode<Number> ToLength_Inline(TNode<Context> context, TNode<Object> input); 2809 2810 TNode<Object> OrdinaryToPrimitive(TNode<Context> context, TNode<Object> input, 2811 OrdinaryToPrimitiveHint hint); 2812 2813 // Returns a node that contains a decoded (unsigned!) value of a bit 2814 // field |BitField| in |word32|. Returns result as an uint32 node. 2815 template <typename BitField> DecodeWord32(TNode<Word32T> word32)2816 TNode<Uint32T> DecodeWord32(TNode<Word32T> word32) { 2817 return DecodeWord32(word32, BitField::kShift, BitField::kMask); 2818 } 2819 2820 // Returns a node that contains a decoded (unsigned!) value of a bit 2821 // field |BitField| in |word|. Returns result as a word-size node. 2822 template <typename BitField> DecodeWord(TNode<WordT> word)2823 TNode<UintPtrT> DecodeWord(TNode<WordT> word) { 2824 return DecodeWord(word, BitField::kShift, BitField::kMask); 2825 } 2826 2827 // Returns a node that contains a decoded (unsigned!) value of a bit 2828 // field |BitField| in |word32|. Returns result as a word-size node. 2829 template <typename BitField> DecodeWordFromWord32(TNode<Word32T> word32)2830 TNode<UintPtrT> DecodeWordFromWord32(TNode<Word32T> word32) { 2831 return DecodeWord<BitField>(ChangeUint32ToWord(word32)); 2832 } 2833 2834 // Returns a node that contains a decoded (unsigned!) value of a bit 2835 // field |BitField| in |word|. Returns result as an uint32 node. 2836 template <typename BitField> DecodeWord32FromWord(TNode<WordT> word)2837 TNode<Uint32T> DecodeWord32FromWord(TNode<WordT> word) { 2838 return UncheckedCast<Uint32T>( 2839 TruncateIntPtrToInt32(Signed(DecodeWord<BitField>(word)))); 2840 } 2841 2842 // Decodes an unsigned (!) value from |word32| to an uint32 node. 2843 TNode<Uint32T> DecodeWord32(TNode<Word32T> word32, uint32_t shift, 2844 uint32_t mask); 2845 2846 // Decodes an unsigned (!) value from |word| to a word-size node. 2847 TNode<UintPtrT> DecodeWord(TNode<WordT> word, uint32_t shift, uintptr_t mask); 2848 2849 // Returns a node that contains the updated values of a |BitField|. 2850 template <typename BitField> 2851 TNode<Word32T> UpdateWord32(TNode<Word32T> word, TNode<Uint32T> value, 2852 bool starts_as_zero = false) { 2853 return UpdateWord32(word, value, BitField::kShift, BitField::kMask, 2854 starts_as_zero); 2855 } 2856 2857 // Returns a node that contains the updated values of a |BitField|. 2858 template <typename BitField> 2859 TNode<WordT> UpdateWord(TNode<WordT> word, TNode<UintPtrT> value, 2860 bool starts_as_zero = false) { 2861 return UpdateWord(word, value, BitField::kShift, BitField::kMask, 2862 starts_as_zero); 2863 } 2864 2865 // Returns a node that contains the updated values of a |BitField|. 2866 template <typename BitField> 2867 TNode<Word32T> UpdateWordInWord32(TNode<Word32T> word, TNode<UintPtrT> value, 2868 bool starts_as_zero = false) { 2869 return UncheckedCast<Uint32T>( 2870 TruncateIntPtrToInt32(Signed(UpdateWord<BitField>( 2871 ChangeUint32ToWord(word), value, starts_as_zero)))); 2872 } 2873 2874 // Returns a node that contains the updated values of a |BitField|. 2875 template <typename BitField> 2876 TNode<WordT> UpdateWord32InWord(TNode<WordT> word, TNode<Uint32T> value, 2877 bool starts_as_zero = false) { 2878 return UpdateWord<BitField>(word, ChangeUint32ToWord(value), 2879 starts_as_zero); 2880 } 2881 2882 // Returns a node that contains the updated {value} inside {word} starting 2883 // at {shift} and fitting in {mask}. 2884 TNode<Word32T> UpdateWord32(TNode<Word32T> word, TNode<Uint32T> value, 2885 uint32_t shift, uint32_t mask, 2886 bool starts_as_zero = false); 2887 2888 // Returns a node that contains the updated {value} inside {word} starting 2889 // at {shift} and fitting in {mask}. 2890 TNode<WordT> UpdateWord(TNode<WordT> word, TNode<UintPtrT> value, 2891 uint32_t shift, uintptr_t mask, 2892 bool starts_as_zero = false); 2893 2894 // Returns true if any of the |T|'s bits in given |word32| are set. 2895 template <typename T> IsSetWord32(TNode<Word32T> word32)2896 TNode<BoolT> IsSetWord32(TNode<Word32T> word32) { 2897 return IsSetWord32(word32, T::kMask); 2898 } 2899 2900 // Returns true if any of the mask's bits in given |word32| are set. IsSetWord32(TNode<Word32T> word32,uint32_t mask)2901 TNode<BoolT> IsSetWord32(TNode<Word32T> word32, uint32_t mask) { 2902 return Word32NotEqual(Word32And(word32, Int32Constant(mask)), 2903 Int32Constant(0)); 2904 } 2905 2906 // Returns true if none of the mask's bits in given |word32| are set. IsNotSetWord32(TNode<Word32T> word32,uint32_t mask)2907 TNode<BoolT> IsNotSetWord32(TNode<Word32T> word32, uint32_t mask) { 2908 return Word32Equal(Word32And(word32, Int32Constant(mask)), 2909 Int32Constant(0)); 2910 } 2911 2912 // Returns true if all of the mask's bits in a given |word32| are set. IsAllSetWord32(TNode<Word32T> word32,uint32_t mask)2913 TNode<BoolT> IsAllSetWord32(TNode<Word32T> word32, uint32_t mask) { 2914 TNode<Int32T> const_mask = Int32Constant(mask); 2915 return Word32Equal(Word32And(word32, const_mask), const_mask); 2916 } 2917 2918 // Returns true if the bit field |BitField| in |word32| is equal to a given 2919 // constant |value|. Avoids a shift compared to using DecodeWord32. 2920 template <typename BitField> IsEqualInWord32(TNode<Word32T> word32,typename BitField::FieldType value)2921 TNode<BoolT> IsEqualInWord32(TNode<Word32T> word32, 2922 typename BitField::FieldType value) { 2923 TNode<Word32T> masked_word32 = 2924 Word32And(word32, Int32Constant(BitField::kMask)); 2925 return Word32Equal(masked_word32, Int32Constant(BitField::encode(value))); 2926 } 2927 2928 // Returns true if the bit field |BitField| in |word32| is not equal to a 2929 // given constant |value|. Avoids a shift compared to using DecodeWord32. 2930 template <typename BitField> IsNotEqualInWord32(TNode<Word32T> word32,typename BitField::FieldType value)2931 TNode<BoolT> IsNotEqualInWord32(TNode<Word32T> word32, 2932 typename BitField::FieldType value) { 2933 return Word32BinaryNot(IsEqualInWord32<BitField>(word32, value)); 2934 } 2935 2936 // Returns true if any of the |T|'s bits in given |word| are set. 2937 template <typename T> IsSetWord(TNode<WordT> word)2938 TNode<BoolT> IsSetWord(TNode<WordT> word) { 2939 return IsSetWord(word, T::kMask); 2940 } 2941 2942 // Returns true if any of the mask's bits in given |word| are set. IsSetWord(TNode<WordT> word,uint32_t mask)2943 TNode<BoolT> IsSetWord(TNode<WordT> word, uint32_t mask) { 2944 return WordNotEqual(WordAnd(word, IntPtrConstant(mask)), IntPtrConstant(0)); 2945 } 2946 2947 // Returns true if any of the mask's bit are set in the given Smi. 2948 // Smi-encoding of the mask is performed implicitly! IsSetSmi(TNode<Smi> smi,int untagged_mask)2949 TNode<BoolT> IsSetSmi(TNode<Smi> smi, int untagged_mask) { 2950 intptr_t mask_word = bit_cast<intptr_t>(Smi::FromInt(untagged_mask)); 2951 return WordNotEqual(WordAnd(BitcastTaggedToWordForTagAndSmiBits(smi), 2952 IntPtrConstant(mask_word)), 2953 IntPtrConstant(0)); 2954 } 2955 2956 // Returns true if all of the |T|'s bits in given |word32| are clear. 2957 template <typename T> IsClearWord32(TNode<Word32T> word32)2958 TNode<BoolT> IsClearWord32(TNode<Word32T> word32) { 2959 return IsClearWord32(word32, T::kMask); 2960 } 2961 2962 // Returns true if all of the mask's bits in given |word32| are clear. IsClearWord32(TNode<Word32T> word32,uint32_t mask)2963 TNode<BoolT> IsClearWord32(TNode<Word32T> word32, uint32_t mask) { 2964 return Word32Equal(Word32And(word32, Int32Constant(mask)), 2965 Int32Constant(0)); 2966 } 2967 2968 // Returns true if all of the |T|'s bits in given |word| are clear. 2969 template <typename T> IsClearWord(TNode<WordT> word)2970 TNode<BoolT> IsClearWord(TNode<WordT> word) { 2971 return IsClearWord(word, T::kMask); 2972 } 2973 2974 // Returns true if all of the mask's bits in given |word| are clear. IsClearWord(TNode<WordT> word,uint32_t mask)2975 TNode<BoolT> IsClearWord(TNode<WordT> word, uint32_t mask) { 2976 return IntPtrEqual(WordAnd(word, IntPtrConstant(mask)), IntPtrConstant(0)); 2977 } 2978 2979 void SetCounter(StatsCounter* counter, int value); 2980 void IncrementCounter(StatsCounter* counter, int delta); 2981 void DecrementCounter(StatsCounter* counter, int delta); 2982 2983 template <typename TIndex> 2984 void Increment(TVariable<TIndex>* variable, int value = 1); 2985 2986 template <typename TIndex> 2987 void Decrement(TVariable<TIndex>* variable, int value = 1) { 2988 Increment(variable, -value); 2989 } 2990 2991 // Generates "if (false) goto label" code. Useful for marking a label as 2992 // "live" to avoid assertion failures during graph building. In the resulting 2993 // code this check will be eliminated. 2994 void Use(Label* label); 2995 2996 // Various building blocks for stubs doing property lookups. 2997 2998 // |if_notinternalized| is optional; |if_bailout| will be used by default. 2999 // Note: If |key| does not yet have a hash, |if_notinternalized| will be taken 3000 // even if |key| is an array index. |if_keyisunique| will never 3001 // be taken for array indices. 3002 void TryToName(TNode<Object> key, Label* if_keyisindex, 3003 TVariable<IntPtrT>* var_index, Label* if_keyisunique, 3004 TVariable<Name>* var_unique, Label* if_bailout, 3005 Label* if_notinternalized = nullptr); 3006 3007 // Call non-allocating runtime String::WriteToFlat using fast C-calls. 3008 void StringWriteToFlatOneByte(TNode<String> source, TNode<RawPtrT> sink, 3009 TNode<Int32T> start, TNode<Int32T> length); 3010 void StringWriteToFlatTwoByte(TNode<String> source, TNode<RawPtrT> sink, 3011 TNode<Int32T> start, TNode<Int32T> length); 3012 3013 // Calls External{One,Two}ByteString::GetChars with a fast C-call. 3014 TNode<RawPtr<Uint8T>> ExternalOneByteStringGetChars( 3015 TNode<ExternalOneByteString> string); 3016 TNode<RawPtr<Uint16T>> ExternalTwoByteStringGetChars( 3017 TNode<ExternalTwoByteString> string); 3018 3019 TNode<RawPtr<Uint8T>> IntlAsciiCollationWeightsL1(); 3020 TNode<RawPtr<Uint8T>> IntlAsciiCollationWeightsL3(); 3021 3022 // Performs a hash computation and string table lookup for the given string, 3023 // and jumps to: 3024 // - |if_index| if the string is an array index like "123"; |var_index| 3025 // will contain the intptr representation of that index. 3026 // - |if_internalized| if the string exists in the string table; the 3027 // internalized version will be in |var_internalized|. 3028 // - |if_not_internalized| if the string is not in the string table (but 3029 // does not add it). 3030 // - |if_bailout| for unsupported cases (e.g. uncachable array index). 3031 void TryInternalizeString(TNode<String> string, Label* if_index, 3032 TVariable<IntPtrT>* var_index, 3033 Label* if_internalized, 3034 TVariable<Name>* var_internalized, 3035 Label* if_not_internalized, Label* if_bailout); 3036 3037 // Calculates array index for given dictionary entry and entry field. 3038 // See Dictionary::EntryToIndex(). 3039 template <typename Dictionary> 3040 TNode<IntPtrT> EntryToIndex(TNode<IntPtrT> entry, int field_index); 3041 template <typename Dictionary> EntryToIndex(TNode<IntPtrT> entry)3042 TNode<IntPtrT> EntryToIndex(TNode<IntPtrT> entry) { 3043 return EntryToIndex<Dictionary>(entry, Dictionary::kEntryKeyIndex); 3044 } 3045 3046 // Loads the details for the entry with the given key_index. 3047 // Returns an untagged int32. 3048 template <class ContainerType> 3049 TNode<Uint32T> LoadDetailsByKeyIndex(TNode<ContainerType> container, 3050 TNode<IntPtrT> key_index); 3051 3052 // Loads the value for the entry with the given key_index. 3053 // Returns a tagged value. 3054 template <class ContainerType> 3055 TNode<Object> LoadValueByKeyIndex(TNode<ContainerType> container, 3056 TNode<IntPtrT> key_index); 3057 3058 // Stores the details for the entry with the given key_index. 3059 // |details| must be a Smi. 3060 template <class ContainerType> 3061 void StoreDetailsByKeyIndex(TNode<ContainerType> container, 3062 TNode<IntPtrT> key_index, TNode<Smi> details); 3063 3064 // Stores the value for the entry with the given key_index. 3065 template <class ContainerType> 3066 void StoreValueByKeyIndex( 3067 TNode<ContainerType> container, TNode<IntPtrT> key_index, 3068 TNode<Object> value, 3069 WriteBarrierMode write_barrier = UPDATE_WRITE_BARRIER); 3070 3071 // Calculate a valid size for the a hash table. 3072 TNode<IntPtrT> HashTableComputeCapacity(TNode<IntPtrT> at_least_space_for); 3073 3074 TNode<IntPtrT> NameToIndexHashTableLookup(TNode<NameToIndexHashTable> table, 3075 TNode<Name> name, Label* not_found); 3076 3077 template <class Dictionary> 3078 TNode<Smi> GetNumberOfElements(TNode<Dictionary> dictionary); 3079 GetNumberDictionaryNumberOfElements(TNode<NumberDictionary> dictionary)3080 TNode<Smi> GetNumberDictionaryNumberOfElements( 3081 TNode<NumberDictionary> dictionary) { 3082 return GetNumberOfElements<NumberDictionary>(dictionary); 3083 } 3084 3085 template <class Dictionary> SetNumberOfElements(TNode<Dictionary> dictionary,TNode<Smi> num_elements_smi)3086 void SetNumberOfElements(TNode<Dictionary> dictionary, 3087 TNode<Smi> num_elements_smi) { 3088 // Not supposed to be used for SwissNameDictionary. 3089 STATIC_ASSERT(!(std::is_same<Dictionary, SwissNameDictionary>::value)); 3090 3091 StoreFixedArrayElement(dictionary, Dictionary::kNumberOfElementsIndex, 3092 num_elements_smi, SKIP_WRITE_BARRIER); 3093 } 3094 3095 template <class Dictionary> GetNumberOfDeletedElements(TNode<Dictionary> dictionary)3096 TNode<Smi> GetNumberOfDeletedElements(TNode<Dictionary> dictionary) { 3097 // Not supposed to be used for SwissNameDictionary. 3098 STATIC_ASSERT(!(std::is_same<Dictionary, SwissNameDictionary>::value)); 3099 3100 return CAST(LoadFixedArrayElement( 3101 dictionary, Dictionary::kNumberOfDeletedElementsIndex)); 3102 } 3103 3104 template <class Dictionary> SetNumberOfDeletedElements(TNode<Dictionary> dictionary,TNode<Smi> num_deleted_smi)3105 void SetNumberOfDeletedElements(TNode<Dictionary> dictionary, 3106 TNode<Smi> num_deleted_smi) { 3107 // Not supposed to be used for SwissNameDictionary. 3108 STATIC_ASSERT(!(std::is_same<Dictionary, SwissNameDictionary>::value)); 3109 3110 StoreFixedArrayElement(dictionary, 3111 Dictionary::kNumberOfDeletedElementsIndex, 3112 num_deleted_smi, SKIP_WRITE_BARRIER); 3113 } 3114 3115 template <class Dictionary> GetCapacity(TNode<Dictionary> dictionary)3116 TNode<Smi> GetCapacity(TNode<Dictionary> dictionary) { 3117 // Not supposed to be used for SwissNameDictionary. 3118 STATIC_ASSERT(!(std::is_same<Dictionary, SwissNameDictionary>::value)); 3119 3120 return CAST( 3121 UnsafeLoadFixedArrayElement(dictionary, Dictionary::kCapacityIndex)); 3122 } 3123 3124 template <class Dictionary> GetNextEnumerationIndex(TNode<Dictionary> dictionary)3125 TNode<Smi> GetNextEnumerationIndex(TNode<Dictionary> dictionary) { 3126 return CAST(LoadFixedArrayElement(dictionary, 3127 Dictionary::kNextEnumerationIndexIndex)); 3128 } 3129 3130 template <class Dictionary> SetNextEnumerationIndex(TNode<Dictionary> dictionary,TNode<Smi> next_enum_index_smi)3131 void SetNextEnumerationIndex(TNode<Dictionary> dictionary, 3132 TNode<Smi> next_enum_index_smi) { 3133 StoreFixedArrayElement(dictionary, Dictionary::kNextEnumerationIndexIndex, 3134 next_enum_index_smi, SKIP_WRITE_BARRIER); 3135 } 3136 3137 // Looks up an entry in a NameDictionaryBase successor. If the entry is found 3138 // control goes to {if_found} and {var_name_index} contains an index of the 3139 // key field of the entry found. If the key is not found control goes to 3140 // {if_not_found}. 3141 enum LookupMode { kFindExisting, kFindInsertionIndex }; 3142 3143 template <typename Dictionary> 3144 TNode<HeapObject> LoadName(TNode<HeapObject> key); 3145 3146 template <typename Dictionary> 3147 void NameDictionaryLookup(TNode<Dictionary> dictionary, 3148 TNode<Name> unique_name, Label* if_found, 3149 TVariable<IntPtrT>* var_name_index, 3150 Label* if_not_found, 3151 LookupMode mode = kFindExisting); 3152 3153 TNode<Word32T> ComputeSeededHash(TNode<IntPtrT> key); 3154 3155 void NumberDictionaryLookup(TNode<NumberDictionary> dictionary, 3156 TNode<IntPtrT> intptr_index, Label* if_found, 3157 TVariable<IntPtrT>* var_entry, 3158 Label* if_not_found); 3159 3160 TNode<Object> BasicLoadNumberDictionaryElement( 3161 TNode<NumberDictionary> dictionary, TNode<IntPtrT> intptr_index, 3162 Label* not_data, Label* if_hole); 3163 3164 template <class Dictionary> 3165 void FindInsertionEntry(TNode<Dictionary> dictionary, TNode<Name> key, 3166 TVariable<IntPtrT>* var_key_index); 3167 3168 template <class Dictionary> 3169 void InsertEntry(TNode<Dictionary> dictionary, TNode<Name> key, 3170 TNode<Object> value, TNode<IntPtrT> index, 3171 TNode<Smi> enum_index); 3172 3173 template <class Dictionary> 3174 void Add(TNode<Dictionary> dictionary, TNode<Name> key, TNode<Object> value, 3175 Label* bailout); 3176 3177 // Tries to check if {object} has own {unique_name} property. 3178 void TryHasOwnProperty(TNode<HeapObject> object, TNode<Map> map, 3179 TNode<Int32T> instance_type, TNode<Name> unique_name, 3180 Label* if_found, Label* if_not_found, 3181 Label* if_bailout); 3182 3183 // Operating mode for TryGetOwnProperty and CallGetterIfAccessor 3184 enum GetOwnPropertyMode { 3185 // kCallJSGetterDontUseCachedName is used when we want to get the result of 3186 // the getter call, and don't use cached_name_property when the getter is 3187 // the function template and it has cached_property_name, which would just 3188 // bailout for the IC system to create a named property handler 3189 kCallJSGetterDontUseCachedName, 3190 // kCallJSGetterUseCachedName is used when we want to get the result of 3191 // the getter call, and use cached_name_property when the getter is 3192 // the function template and it has cached_property_name, which would call 3193 // GetProperty rather than bailout for Generic/NoFeedback load 3194 kCallJSGetterUseCachedName, 3195 // kReturnAccessorPair is used when we're only getting the property 3196 // descriptor 3197 kReturnAccessorPair 3198 }; 3199 // Tries to get {object}'s own {unique_name} property value. If the property 3200 // is an accessor then it also calls a getter. If the property is a double 3201 // field it re-wraps value in an immutable heap number. {unique_name} must be 3202 // a unique name (Symbol or InternalizedString) that is not an array index. 3203 void TryGetOwnProperty(TNode<Context> context, TNode<Object> receiver, 3204 TNode<JSReceiver> object, TNode<Map> map, 3205 TNode<Int32T> instance_type, TNode<Name> unique_name, 3206 Label* if_found_value, TVariable<Object>* var_value, 3207 Label* if_not_found, Label* if_bailout); 3208 void TryGetOwnProperty(TNode<Context> context, TNode<Object> receiver, 3209 TNode<JSReceiver> object, TNode<Map> map, 3210 TNode<Int32T> instance_type, TNode<Name> unique_name, 3211 Label* if_found_value, TVariable<Object>* var_value, 3212 TVariable<Uint32T>* var_details, 3213 TVariable<Object>* var_raw_value, Label* if_not_found, 3214 Label* if_bailout, GetOwnPropertyMode mode); 3215 GetProperty(TNode<Context> context,TNode<Object> receiver,Handle<Name> name)3216 TNode<Object> GetProperty(TNode<Context> context, TNode<Object> receiver, 3217 Handle<Name> name) { 3218 return GetProperty(context, receiver, HeapConstant(name)); 3219 } 3220 GetProperty(TNode<Context> context,TNode<Object> receiver,TNode<Object> name)3221 TNode<Object> GetProperty(TNode<Context> context, TNode<Object> receiver, 3222 TNode<Object> name) { 3223 return CallBuiltin(Builtin::kGetProperty, context, receiver, name); 3224 } 3225 SetPropertyStrict(TNode<Context> context,TNode<Object> receiver,TNode<Object> key,TNode<Object> value)3226 TNode<Object> SetPropertyStrict(TNode<Context> context, 3227 TNode<Object> receiver, TNode<Object> key, 3228 TNode<Object> value) { 3229 return CallBuiltin(Builtin::kSetProperty, context, receiver, key, value); 3230 } 3231 CreateDataProperty(TNode<Context> context,TNode<JSObject> receiver,TNode<Object> key,TNode<Object> value)3232 TNode<Object> CreateDataProperty(TNode<Context> context, 3233 TNode<JSObject> receiver, TNode<Object> key, 3234 TNode<Object> value) { 3235 return CallBuiltin(Builtin::kCreateDataProperty, context, receiver, key, 3236 value); 3237 } 3238 3239 TNode<Object> GetMethod(TNode<Context> context, TNode<Object> object, 3240 Handle<Name> name, Label* if_null_or_undefined); 3241 3242 TNode<Object> GetIteratorMethod(TNode<Context> context, 3243 TNode<HeapObject> heap_obj, 3244 Label* if_iteratorundefined); 3245 3246 TNode<Object> CreateAsyncFromSyncIterator(TNode<Context> context, 3247 TNode<Object> sync_iterator); 3248 3249 template <class... TArgs> CallBuiltin(Builtin id,TNode<Object> context,TArgs...args)3250 TNode<Object> CallBuiltin(Builtin id, TNode<Object> context, TArgs... args) { 3251 return CallStub<Object>(Builtins::CallableFor(isolate(), id), context, 3252 args...); 3253 } 3254 3255 template <class... TArgs> TailCallBuiltin(Builtin id,TNode<Object> context,TArgs...args)3256 void TailCallBuiltin(Builtin id, TNode<Object> context, TArgs... args) { 3257 return TailCallStub(Builtins::CallableFor(isolate(), id), context, args...); 3258 } 3259 3260 void LoadPropertyFromFastObject(TNode<HeapObject> object, TNode<Map> map, 3261 TNode<DescriptorArray> descriptors, 3262 TNode<IntPtrT> name_index, 3263 TVariable<Uint32T>* var_details, 3264 TVariable<Object>* var_value); 3265 3266 void LoadPropertyFromFastObject(TNode<HeapObject> object, TNode<Map> map, 3267 TNode<DescriptorArray> descriptors, 3268 TNode<IntPtrT> name_index, TNode<Uint32T>, 3269 TVariable<Object>* var_value); 3270 3271 template <typename Dictionary> 3272 void LoadPropertyFromDictionary(TNode<Dictionary> dictionary, 3273 TNode<IntPtrT> name_index, 3274 TVariable<Uint32T>* var_details, 3275 TVariable<Object>* var_value); 3276 void LoadPropertyFromGlobalDictionary(TNode<GlobalDictionary> dictionary, 3277 TNode<IntPtrT> name_index, 3278 TVariable<Uint32T>* var_details, 3279 TVariable<Object>* var_value, 3280 Label* if_deleted); 3281 3282 // Generic property lookup generator. If the {object} is fast and 3283 // {unique_name} property is found then the control goes to {if_found_fast} 3284 // label and {var_meta_storage} and {var_name_index} will contain 3285 // DescriptorArray and an index of the descriptor's name respectively. 3286 // If the {object} is slow or global then the control goes to {if_found_dict} 3287 // or {if_found_global} and the {var_meta_storage} and {var_name_index} will 3288 // contain a dictionary and an index of the key field of the found entry. 3289 // If property is not found or given lookup is not supported then 3290 // the control goes to {if_not_found} or {if_bailout} respectively. 3291 // 3292 // Note: this code does not check if the global dictionary points to deleted 3293 // entry! This has to be done by the caller. 3294 void TryLookupProperty(TNode<HeapObject> object, TNode<Map> map, 3295 TNode<Int32T> instance_type, TNode<Name> unique_name, 3296 Label* if_found_fast, Label* if_found_dict, 3297 Label* if_found_global, 3298 TVariable<HeapObject>* var_meta_storage, 3299 TVariable<IntPtrT>* var_name_index, 3300 Label* if_not_found, Label* if_bailout); 3301 3302 // This is a building block for TryLookupProperty() above. Supports only 3303 // non-special fast and dictionary objects. 3304 // TODO(v8:11167, v8:11177) |bailout| only needed for SetDataProperties 3305 // workaround. 3306 void TryLookupPropertyInSimpleObject(TNode<JSObject> object, TNode<Map> map, 3307 TNode<Name> unique_name, 3308 Label* if_found_fast, 3309 Label* if_found_dict, 3310 TVariable<HeapObject>* var_meta_storage, 3311 TVariable<IntPtrT>* var_name_index, 3312 Label* if_not_found, Label* bailout); 3313 3314 // This method jumps to if_found if the element is known to exist. To 3315 // if_absent if it's known to not exist. To if_not_found if the prototype 3316 // chain needs to be checked. And if_bailout if the lookup is unsupported. 3317 void TryLookupElement(TNode<HeapObject> object, TNode<Map> map, 3318 TNode<Int32T> instance_type, 3319 TNode<IntPtrT> intptr_index, Label* if_found, 3320 Label* if_absent, Label* if_not_found, 3321 Label* if_bailout); 3322 3323 // For integer indexed exotic cases, check if the given string cannot be a 3324 // special index. If we are not sure that the given string is not a special 3325 // index with a simple check, return False. Note that "False" return value 3326 // does not mean that the name_string is a special index in the current 3327 // implementation. 3328 void BranchIfMaybeSpecialIndex(TNode<String> name_string, 3329 Label* if_maybe_special_index, 3330 Label* if_not_special_index); 3331 3332 // This is a type of a lookup property in holder generator function. The {key} 3333 // is guaranteed to be an unique name. 3334 using LookupPropertyInHolder = std::function<void( 3335 TNode<HeapObject> receiver, TNode<HeapObject> holder, TNode<Map> map, 3336 TNode<Int32T> instance_type, TNode<Name> key, Label* next_holder, 3337 Label* if_bailout)>; 3338 3339 // This is a type of a lookup element in holder generator function. The {key} 3340 // is an Int32 index. 3341 using LookupElementInHolder = std::function<void( 3342 TNode<HeapObject> receiver, TNode<HeapObject> holder, TNode<Map> map, 3343 TNode<Int32T> instance_type, TNode<IntPtrT> key, Label* next_holder, 3344 Label* if_bailout)>; 3345 3346 // Generic property prototype chain lookup generator. 3347 // For properties it generates lookup using given {lookup_property_in_holder} 3348 // and for elements it uses {lookup_element_in_holder}. 3349 // Upon reaching the end of prototype chain the control goes to {if_end}. 3350 // If it can't handle the case {receiver}/{key} case then the control goes 3351 // to {if_bailout}. 3352 // If {if_proxy} is nullptr, proxies go to if_bailout. 3353 void TryPrototypeChainLookup( 3354 TNode<Object> receiver, TNode<Object> object, TNode<Object> key, 3355 const LookupPropertyInHolder& lookup_property_in_holder, 3356 const LookupElementInHolder& lookup_element_in_holder, Label* if_end, 3357 Label* if_bailout, Label* if_proxy, bool handle_private_names = false); 3358 3359 // Instanceof helpers. 3360 // Returns true if {object} has {prototype} somewhere in it's prototype 3361 // chain, otherwise false is returned. Might cause arbitrary side effects 3362 // due to [[GetPrototypeOf]] invocations. 3363 TNode<Oddball> HasInPrototypeChain(TNode<Context> context, 3364 TNode<HeapObject> object, 3365 TNode<Object> prototype); 3366 // ES6 section 7.3.19 OrdinaryHasInstance (C, O) 3367 TNode<Oddball> OrdinaryHasInstance(TNode<Context> context, 3368 TNode<Object> callable, 3369 TNode<Object> object); 3370 3371 // Load type feedback vector from the stub caller's frame. 3372 TNode<FeedbackVector> LoadFeedbackVectorForStub(); 3373 TNode<FeedbackVector> LoadFeedbackVectorFromBaseline(); 3374 TNode<Context> LoadContextFromBaseline(); 3375 // Load type feedback vector from the stub caller's frame, skipping an 3376 // intermediate trampoline frame. 3377 TNode<FeedbackVector> LoadFeedbackVectorForStubWithTrampoline(); 3378 3379 // Load the value from closure's feedback cell. 3380 TNode<HeapObject> LoadFeedbackCellValue(TNode<JSFunction> closure); 3381 3382 // Load the object from feedback vector cell for the given closure. 3383 // The returned object could be undefined if the closure does not have 3384 // a feedback vector associated with it. 3385 TNode<HeapObject> LoadFeedbackVector(TNode<JSFunction> closure); 3386 3387 // Load the ClosureFeedbackCellArray that contains the feedback cells 3388 // used when creating closures from this function. This array could be 3389 // directly hanging off the FeedbackCell when there is no feedback vector 3390 // or available from the feedback vector's header. 3391 TNode<ClosureFeedbackCellArray> LoadClosureFeedbackArray( 3392 TNode<JSFunction> closure); 3393 3394 // Update the type feedback vector. UpdateFeedbackModeEqual(UpdateFeedbackMode a,UpdateFeedbackMode b)3395 bool UpdateFeedbackModeEqual(UpdateFeedbackMode a, UpdateFeedbackMode b) { 3396 return a == b; 3397 } 3398 void UpdateFeedback(TNode<Smi> feedback, 3399 TNode<HeapObject> maybe_feedback_vector, 3400 TNode<UintPtrT> slot_id, UpdateFeedbackMode mode); 3401 void UpdateFeedback(TNode<Smi> feedback, 3402 TNode<FeedbackVector> feedback_vector, 3403 TNode<UintPtrT> slot_id); 3404 void MaybeUpdateFeedback(TNode<Smi> feedback, 3405 TNode<HeapObject> maybe_feedback_vector, 3406 TNode<UintPtrT> slot_id); 3407 3408 // Report that there was a feedback update, performing any tasks that should 3409 // be done after a feedback update. 3410 void ReportFeedbackUpdate(TNode<FeedbackVector> feedback_vector, 3411 TNode<UintPtrT> slot_id, const char* reason); 3412 3413 // Combine the new feedback with the existing_feedback. Do nothing if 3414 // existing_feedback is nullptr. 3415 void CombineFeedback(TVariable<Smi>* existing_feedback, int feedback); 3416 void CombineFeedback(TVariable<Smi>* existing_feedback, TNode<Smi> feedback); 3417 3418 // Overwrite the existing feedback with new_feedback. Do nothing if 3419 // existing_feedback is nullptr. 3420 void OverwriteFeedback(TVariable<Smi>* existing_feedback, int new_feedback); 3421 3422 // Check if a property name might require protector invalidation when it is 3423 // used for a property store or deletion. 3424 void CheckForAssociatedProtector(TNode<Name> name, Label* if_protector); 3425 3426 TNode<Map> LoadReceiverMap(TNode<Object> receiver); 3427 3428 // Loads script context from the script context table. 3429 TNode<Context> LoadScriptContext(TNode<Context> context, 3430 TNode<IntPtrT> context_index); 3431 3432 TNode<Uint8T> Int32ToUint8Clamped(TNode<Int32T> int32_value); 3433 TNode<Uint8T> Float64ToUint8Clamped(TNode<Float64T> float64_value); 3434 3435 template <typename T> 3436 TNode<T> PrepareValueForWriteToTypedArray(TNode<Object> input, 3437 ElementsKind elements_kind, 3438 TNode<Context> context); 3439 3440 // Store value to an elements array with given elements kind. 3441 // TODO(turbofan): For BIGINT64_ELEMENTS and BIGUINT64_ELEMENTS 3442 // we pass {value} as BigInt object instead of int64_t. We should 3443 // teach TurboFan to handle int64_t on 32-bit platforms eventually. 3444 template <typename TIndex, typename TValue> 3445 void StoreElement(TNode<RawPtrT> elements, ElementsKind kind, 3446 TNode<TIndex> index, TNode<TValue> value); 3447 3448 // Implements the BigInt part of 3449 // https://tc39.github.io/proposal-bigint/#sec-numbertorawbytes, 3450 // including truncation to 64 bits (i.e. modulo 2^64). 3451 // {var_high} is only used on 32-bit platforms. 3452 void BigIntToRawBytes(TNode<BigInt> bigint, TVariable<UintPtrT>* var_low, 3453 TVariable<UintPtrT>* var_high); 3454 3455 void EmitElementStore(TNode<JSObject> object, TNode<Object> key, 3456 TNode<Object> value, ElementsKind elements_kind, 3457 KeyedAccessStoreMode store_mode, Label* bailout, 3458 TNode<Context> context, 3459 TVariable<Object>* maybe_converted_value = nullptr); 3460 3461 TNode<FixedArrayBase> CheckForCapacityGrow( 3462 TNode<JSObject> object, TNode<FixedArrayBase> elements, ElementsKind kind, 3463 TNode<UintPtrT> length, TNode<IntPtrT> key, Label* bailout); 3464 3465 TNode<FixedArrayBase> CopyElementsOnWrite(TNode<HeapObject> object, 3466 TNode<FixedArrayBase> elements, 3467 ElementsKind kind, 3468 TNode<IntPtrT> length, 3469 Label* bailout); 3470 3471 void TransitionElementsKind(TNode<JSObject> object, TNode<Map> map, 3472 ElementsKind from_kind, ElementsKind to_kind, 3473 Label* bailout); 3474 3475 void TrapAllocationMemento(TNode<JSObject> object, Label* memento_found); 3476 3477 TNode<IntPtrT> PageFromAddress(TNode<IntPtrT> address); 3478 3479 // Store a weak in-place reference into the FeedbackVector. 3480 TNode<MaybeObject> StoreWeakReferenceInFeedbackVector( 3481 TNode<FeedbackVector> feedback_vector, TNode<UintPtrT> slot, 3482 TNode<HeapObject> value, int additional_offset = 0); 3483 3484 // Create a new AllocationSite and install it into a feedback vector. 3485 TNode<AllocationSite> CreateAllocationSiteInFeedbackVector( 3486 TNode<FeedbackVector> feedback_vector, TNode<UintPtrT> slot); 3487 3488 TNode<BoolT> HasBoilerplate(TNode<Object> maybe_literal_site); 3489 TNode<Smi> LoadTransitionInfo(TNode<AllocationSite> allocation_site); 3490 TNode<JSObject> LoadBoilerplate(TNode<AllocationSite> allocation_site); 3491 TNode<Int32T> LoadElementsKind(TNode<AllocationSite> allocation_site); 3492 3493 enum class IndexAdvanceMode { kPre, kPost }; 3494 3495 template <typename TIndex> 3496 using FastLoopBody = std::function<void(TNode<TIndex> index)>; 3497 3498 template <typename TIndex> 3499 TNode<TIndex> BuildFastLoop( 3500 const VariableList& var_list, TNode<TIndex> start_index, 3501 TNode<TIndex> end_index, const FastLoopBody<TIndex>& body, int increment, 3502 IndexAdvanceMode advance_mode = IndexAdvanceMode::kPre); 3503 3504 template <typename TIndex> 3505 TNode<TIndex> BuildFastLoop( 3506 TNode<TIndex> start_index, TNode<TIndex> end_index, 3507 const FastLoopBody<TIndex>& body, int increment, 3508 IndexAdvanceMode advance_mode = IndexAdvanceMode::kPre) { 3509 return BuildFastLoop(VariableList(0, zone()), start_index, end_index, body, 3510 increment, advance_mode); 3511 } 3512 3513 enum class ForEachDirection { kForward, kReverse }; 3514 3515 using FastArrayForEachBody = 3516 std::function<void(TNode<HeapObject> array, TNode<IntPtrT> offset)>; 3517 3518 template <typename TIndex> 3519 void BuildFastArrayForEach( 3520 TNode<UnionT<UnionT<FixedArray, PropertyArray>, HeapObject>> array, 3521 ElementsKind kind, TNode<TIndex> first_element_inclusive, 3522 TNode<TIndex> last_element_exclusive, const FastArrayForEachBody& body, 3523 ForEachDirection direction = ForEachDirection::kReverse); 3524 3525 template <typename TIndex> GetArrayAllocationSize(TNode<TIndex> element_count,ElementsKind kind,int header_size)3526 TNode<IntPtrT> GetArrayAllocationSize(TNode<TIndex> element_count, 3527 ElementsKind kind, int header_size) { 3528 return ElementOffsetFromIndex(element_count, kind, header_size); 3529 } 3530 3531 template <typename TIndex> GetFixedArrayAllocationSize(TNode<TIndex> element_count,ElementsKind kind)3532 TNode<IntPtrT> GetFixedArrayAllocationSize(TNode<TIndex> element_count, 3533 ElementsKind kind) { 3534 return GetArrayAllocationSize(element_count, kind, FixedArray::kHeaderSize); 3535 } 3536 GetPropertyArrayAllocationSize(TNode<IntPtrT> element_count)3537 TNode<IntPtrT> GetPropertyArrayAllocationSize(TNode<IntPtrT> element_count) { 3538 return GetArrayAllocationSize(element_count, PACKED_ELEMENTS, 3539 PropertyArray::kHeaderSize); 3540 } 3541 3542 template <typename TIndex> 3543 void GotoIfFixedArraySizeDoesntFitInNewSpace(TNode<TIndex> element_count, 3544 Label* doesnt_fit, 3545 int base_size); 3546 3547 void InitializeFieldsWithRoot(TNode<HeapObject> object, 3548 TNode<IntPtrT> start_offset, 3549 TNode<IntPtrT> end_offset, RootIndex root); 3550 3551 // Goto the given |target| if the context chain starting at |context| has any 3552 // extensions up to the given |depth|. Returns the Context with the 3553 // extensions if there was one, otherwise returns the Context at the given 3554 // |depth|. 3555 TNode<Context> GotoIfHasContextExtensionUpToDepth(TNode<Context> context, 3556 TNode<Uint32T> depth, 3557 Label* target); 3558 3559 TNode<Oddball> RelationalComparison( 3560 Operation op, TNode<Object> left, TNode<Object> right, 3561 TNode<Context> context, TVariable<Smi>* var_type_feedback = nullptr) { 3562 return RelationalComparison( 3563 op, left, right, [=]() { return context; }, var_type_feedback); 3564 } 3565 3566 TNode<Oddball> RelationalComparison( 3567 Operation op, TNode<Object> left, TNode<Object> right, 3568 const LazyNode<Context>& context, 3569 TVariable<Smi>* var_type_feedback = nullptr); 3570 3571 void BranchIfNumberRelationalComparison(Operation op, TNode<Number> left, 3572 TNode<Number> right, Label* if_true, 3573 Label* if_false); 3574 BranchIfNumberEqual(TNode<Number> left,TNode<Number> right,Label * if_true,Label * if_false)3575 void BranchIfNumberEqual(TNode<Number> left, TNode<Number> right, 3576 Label* if_true, Label* if_false) { 3577 BranchIfNumberRelationalComparison(Operation::kEqual, left, right, if_true, 3578 if_false); 3579 } 3580 BranchIfNumberNotEqual(TNode<Number> left,TNode<Number> right,Label * if_true,Label * if_false)3581 void BranchIfNumberNotEqual(TNode<Number> left, TNode<Number> right, 3582 Label* if_true, Label* if_false) { 3583 BranchIfNumberEqual(left, right, if_false, if_true); 3584 } 3585 BranchIfNumberLessThan(TNode<Number> left,TNode<Number> right,Label * if_true,Label * if_false)3586 void BranchIfNumberLessThan(TNode<Number> left, TNode<Number> right, 3587 Label* if_true, Label* if_false) { 3588 BranchIfNumberRelationalComparison(Operation::kLessThan, left, right, 3589 if_true, if_false); 3590 } 3591 BranchIfNumberLessThanOrEqual(TNode<Number> left,TNode<Number> right,Label * if_true,Label * if_false)3592 void BranchIfNumberLessThanOrEqual(TNode<Number> left, TNode<Number> right, 3593 Label* if_true, Label* if_false) { 3594 BranchIfNumberRelationalComparison(Operation::kLessThanOrEqual, left, right, 3595 if_true, if_false); 3596 } 3597 BranchIfNumberGreaterThan(TNode<Number> left,TNode<Number> right,Label * if_true,Label * if_false)3598 void BranchIfNumberGreaterThan(TNode<Number> left, TNode<Number> right, 3599 Label* if_true, Label* if_false) { 3600 BranchIfNumberRelationalComparison(Operation::kGreaterThan, left, right, 3601 if_true, if_false); 3602 } 3603 BranchIfNumberGreaterThanOrEqual(TNode<Number> left,TNode<Number> right,Label * if_true,Label * if_false)3604 void BranchIfNumberGreaterThanOrEqual(TNode<Number> left, TNode<Number> right, 3605 Label* if_true, Label* if_false) { 3606 BranchIfNumberRelationalComparison(Operation::kGreaterThanOrEqual, left, 3607 right, if_true, if_false); 3608 } 3609 BranchIfAccessorPair(TNode<Object> value,Label * if_accessor_pair,Label * if_not_accessor_pair)3610 void BranchIfAccessorPair(TNode<Object> value, Label* if_accessor_pair, 3611 Label* if_not_accessor_pair) { 3612 GotoIf(TaggedIsSmi(value), if_not_accessor_pair); 3613 Branch(IsAccessorPair(CAST(value)), if_accessor_pair, if_not_accessor_pair); 3614 } 3615 3616 void GotoIfNumberGreaterThanOrEqual(TNode<Number> left, TNode<Number> right, 3617 Label* if_false); 3618 3619 TNode<Oddball> Equal(TNode<Object> lhs, TNode<Object> rhs, 3620 TNode<Context> context, 3621 TVariable<Smi>* var_type_feedback = nullptr) { 3622 return Equal( 3623 lhs, rhs, [=]() { return context; }, var_type_feedback); 3624 } 3625 TNode<Oddball> Equal(TNode<Object> lhs, TNode<Object> rhs, 3626 const LazyNode<Context>& context, 3627 TVariable<Smi>* var_type_feedback = nullptr); 3628 3629 TNode<Oddball> StrictEqual(TNode<Object> lhs, TNode<Object> rhs, 3630 TVariable<Smi>* var_type_feedback = nullptr); 3631 3632 // ECMA#sec-samevalue 3633 // Similar to StrictEqual except that NaNs are treated as equal and minus zero 3634 // differs from positive zero. 3635 enum class SameValueMode { kNumbersOnly, kFull }; 3636 void BranchIfSameValue(TNode<Object> lhs, TNode<Object> rhs, Label* if_true, 3637 Label* if_false, 3638 SameValueMode mode = SameValueMode::kFull); 3639 // A part of BranchIfSameValue() that handles two double values. 3640 // Treats NaN == NaN and +0 != -0. 3641 void BranchIfSameNumberValue(TNode<Float64T> lhs_value, 3642 TNode<Float64T> rhs_value, Label* if_true, 3643 Label* if_false); 3644 3645 enum HasPropertyLookupMode { kHasProperty, kForInHasProperty }; 3646 3647 TNode<Oddball> HasProperty(TNode<Context> context, TNode<Object> object, 3648 TNode<Object> key, HasPropertyLookupMode mode); 3649 3650 // Due to naming conflict with the builtin function namespace. HasProperty_Inline(TNode<Context> context,TNode<JSReceiver> object,TNode<Object> key)3651 TNode<Oddball> HasProperty_Inline(TNode<Context> context, 3652 TNode<JSReceiver> object, 3653 TNode<Object> key) { 3654 return HasProperty(context, object, key, 3655 HasPropertyLookupMode::kHasProperty); 3656 } 3657 3658 void ForInPrepare(TNode<HeapObject> enumerator, TNode<UintPtrT> slot, 3659 TNode<HeapObject> maybe_feedback_vector, 3660 TNode<FixedArray>* cache_array_out, 3661 TNode<Smi>* cache_length_out, 3662 UpdateFeedbackMode update_feedback_mode); 3663 3664 TNode<String> Typeof(TNode<Object> value); 3665 3666 TNode<HeapObject> GetSuperConstructor(TNode<JSFunction> active_function); 3667 3668 TNode<JSReceiver> SpeciesConstructor(TNode<Context> context, 3669 TNode<Object> object, 3670 TNode<JSReceiver> default_constructor); 3671 3672 TNode<Oddball> InstanceOf(TNode<Object> object, TNode<Object> callable, 3673 TNode<Context> context); 3674 3675 // Debug helpers 3676 TNode<BoolT> IsDebugActive(); 3677 TNode<BoolT> IsSideEffectFreeDebuggingActive(); 3678 3679 // JSArrayBuffer helpers 3680 TNode<RawPtrT> LoadJSArrayBufferBackingStorePtr( 3681 TNode<JSArrayBuffer> array_buffer); 3682 void ThrowIfArrayBufferIsDetached(TNode<Context> context, 3683 TNode<JSArrayBuffer> array_buffer, 3684 const char* method_name); 3685 3686 // JSArrayBufferView helpers 3687 TNode<JSArrayBuffer> LoadJSArrayBufferViewBuffer( 3688 TNode<JSArrayBufferView> array_buffer_view); 3689 TNode<UintPtrT> LoadJSArrayBufferViewByteLength( 3690 TNode<JSArrayBufferView> array_buffer_view); 3691 3692 TNode<UintPtrT> LoadJSArrayBufferViewByteOffset( 3693 TNode<JSArrayBufferView> array_buffer_view); 3694 void ThrowIfArrayBufferViewBufferIsDetached( 3695 TNode<Context> context, TNode<JSArrayBufferView> array_buffer_view, 3696 const char* method_name); 3697 3698 // JSTypedArray helpers 3699 TNode<UintPtrT> LoadJSTypedArrayLengthAndCheckDetached( 3700 TNode<JSTypedArray> typed_array, Label* detached); 3701 // Helper for length tracking JSTypedArrays and JSTypedArrays backed by 3702 // ResizableArrayBuffer. 3703 TNode<UintPtrT> LoadVariableLengthJSTypedArrayLength( 3704 TNode<JSTypedArray> array, TNode<JSArrayBuffer> buffer, 3705 Label* detached_or_out_of_bounds); 3706 // Helper for length tracking JSTypedArrays and JSTypedArrays backed by 3707 // ResizableArrayBuffer. 3708 TNode<UintPtrT> LoadVariableLengthJSTypedArrayByteLength( 3709 TNode<Context> context, TNode<JSTypedArray> array, 3710 TNode<JSArrayBuffer> buffer); 3711 TNode<UintPtrT> LoadVariableLengthJSArrayBufferViewByteLength( 3712 TNode<JSArrayBufferView> array, TNode<JSArrayBuffer> buffer, 3713 Label* detached_or_out_of_bounds); 3714 3715 void IsJSArrayBufferViewDetachedOrOutOfBounds( 3716 TNode<JSArrayBufferView> array_buffer_view, Label* detached_or_oob, 3717 Label* not_detached_nor_oob); 3718 3719 TNode<BoolT> IsJSArrayBufferViewDetachedOrOutOfBoundsBoolean( 3720 TNode<JSArrayBufferView> array_buffer_view); 3721 3722 void CheckJSTypedArrayIndex(TNode<UintPtrT> index, 3723 TNode<JSTypedArray> typed_array, 3724 Label* detached_or_out_of_bounds); 3725 3726 TNode<IntPtrT> RabGsabElementsKindToElementByteSize( 3727 TNode<Int32T> elementsKind); 3728 TNode<RawPtrT> LoadJSTypedArrayDataPtr(TNode<JSTypedArray> typed_array); 3729 TNode<JSArrayBuffer> GetTypedArrayBuffer(TNode<Context> context, 3730 TNode<JSTypedArray> array); 3731 3732 template <typename TIndex> 3733 TNode<IntPtrT> ElementOffsetFromIndex(TNode<TIndex> index, ElementsKind kind, 3734 int base_size = 0); 3735 3736 // Check that a field offset is within the bounds of the an object. 3737 TNode<BoolT> IsOffsetInBounds(TNode<IntPtrT> offset, TNode<IntPtrT> length, 3738 int header_size, 3739 ElementsKind kind = HOLEY_ELEMENTS); 3740 3741 // Load a builtin's code from the builtin array in the isolate. 3742 TNode<CodeT> LoadBuiltin(TNode<Smi> builtin_id); 3743 3744 // Figure out the SFI's code object using its data field. 3745 // If |data_type_out| is provided, the instance type of the function data will 3746 // be stored in it. In case the code object is a builtin (data is a Smi), 3747 // data_type_out will be set to 0. 3748 // If |if_compile_lazy| is provided then the execution will go to the given 3749 // label in case of an CompileLazy code object. 3750 TNode<CodeT> GetSharedFunctionInfoCode( 3751 TNode<SharedFunctionInfo> shared_info, 3752 TVariable<Uint16T>* data_type_out = nullptr, 3753 Label* if_compile_lazy = nullptr); 3754 3755 TNode<JSFunction> AllocateFunctionWithMapAndContext( 3756 TNode<Map> map, TNode<SharedFunctionInfo> shared_info, 3757 TNode<Context> context); 3758 3759 // Promise helpers 3760 TNode<Uint32T> PromiseHookFlags(); 3761 TNode<BoolT> HasAsyncEventDelegate(); 3762 #ifdef V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS 3763 TNode<BoolT> IsContextPromiseHookEnabled(TNode<Uint32T> flags); 3764 #endif 3765 TNode<BoolT> IsIsolatePromiseHookEnabled(TNode<Uint32T> flags); 3766 TNode<BoolT> IsAnyPromiseHookEnabled(TNode<Uint32T> flags); IsAnyPromiseHookEnabled()3767 TNode<BoolT> IsAnyPromiseHookEnabled() { 3768 return IsAnyPromiseHookEnabled(PromiseHookFlags()); 3769 } 3770 TNode<BoolT> IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate( 3771 TNode<Uint32T> flags); IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate()3772 TNode<BoolT> IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate() { 3773 return IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate( 3774 PromiseHookFlags()); 3775 } 3776 TNode<BoolT> 3777 IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate( 3778 TNode<Uint32T> flags); 3779 TNode<BoolT> IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate()3780 IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() { 3781 return IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate( 3782 PromiseHookFlags()); 3783 } 3784 3785 TNode<BoolT> NeedsAnyPromiseHooks(TNode<Uint32T> flags); NeedsAnyPromiseHooks()3786 TNode<BoolT> NeedsAnyPromiseHooks() { 3787 return NeedsAnyPromiseHooks(PromiseHookFlags()); 3788 } 3789 3790 // for..in helpers 3791 void CheckPrototypeEnumCache(TNode<JSReceiver> receiver, 3792 TNode<Map> receiver_map, Label* if_fast, 3793 Label* if_slow); 3794 TNode<Map> CheckEnumCache(TNode<JSReceiver> receiver, Label* if_empty, 3795 Label* if_runtime); 3796 3797 TNode<Object> GetArgumentValue(TorqueStructArguments args, 3798 TNode<IntPtrT> index); 3799 3800 enum class FrameArgumentsArgcType { 3801 kCountIncludesReceiver, 3802 kCountExcludesReceiver 3803 }; 3804 3805 TorqueStructArguments GetFrameArguments( 3806 TNode<RawPtrT> frame, TNode<IntPtrT> argc, 3807 FrameArgumentsArgcType argc_type = 3808 FrameArgumentsArgcType::kCountExcludesReceiver); 3809 JSParameterCount(int argc_without_receiver)3810 inline TNode<Int32T> JSParameterCount(int argc_without_receiver) { 3811 return Int32Constant(argc_without_receiver + kJSArgcReceiverSlots); 3812 } JSParameterCount(TNode<Word32T> argc_without_receiver)3813 inline TNode<Word32T> JSParameterCount(TNode<Word32T> argc_without_receiver) { 3814 return Int32Add(argc_without_receiver, Int32Constant(kJSArgcReceiverSlots)); 3815 } 3816 3817 // Support for printf-style debugging 3818 void Print(const char* s); 3819 void Print(const char* prefix, TNode<MaybeObject> tagged_value); Print(TNode<MaybeObject> tagged_value)3820 void Print(TNode<MaybeObject> tagged_value) { 3821 return Print(nullptr, tagged_value); 3822 } 3823 3824 template <class... TArgs> MakeTypeError(MessageTemplate message,TNode<Context> context,TArgs...args)3825 TNode<HeapObject> MakeTypeError(MessageTemplate message, 3826 TNode<Context> context, TArgs... args) { 3827 STATIC_ASSERT(sizeof...(TArgs) <= 3); 3828 return CAST(CallRuntime(Runtime::kNewTypeError, context, 3829 SmiConstant(message), args...)); 3830 } 3831 Abort(AbortReason reason)3832 void Abort(AbortReason reason) { 3833 CallRuntime(Runtime::kAbort, NoContextConstant(), SmiConstant(reason)); 3834 Unreachable(); 3835 } 3836 ConstexprBoolNot(bool value)3837 bool ConstexprBoolNot(bool value) { return !value; } ConstexprIntegerLiteralToInt31(const IntegerLiteral & i)3838 int31_t ConstexprIntegerLiteralToInt31(const IntegerLiteral& i) { 3839 return int31_t(i.To<int32_t>()); 3840 } ConstexprIntegerLiteralToInt32(const IntegerLiteral & i)3841 int32_t ConstexprIntegerLiteralToInt32(const IntegerLiteral& i) { 3842 return i.To<int32_t>(); 3843 } ConstexprIntegerLiteralToUint32(const IntegerLiteral & i)3844 uint32_t ConstexprIntegerLiteralToUint32(const IntegerLiteral& i) { 3845 return i.To<uint32_t>(); 3846 } ConstexprIntegerLiteralToInt8(const IntegerLiteral & i)3847 int8_t ConstexprIntegerLiteralToInt8(const IntegerLiteral& i) { 3848 return i.To<int8_t>(); 3849 } ConstexprIntegerLiteralToUint8(const IntegerLiteral & i)3850 uint8_t ConstexprIntegerLiteralToUint8(const IntegerLiteral& i) { 3851 return i.To<uint8_t>(); 3852 } ConstexprIntegerLiteralToUint64(const IntegerLiteral & i)3853 uint64_t ConstexprIntegerLiteralToUint64(const IntegerLiteral& i) { 3854 return i.To<uint64_t>(); 3855 } ConstexprIntegerLiteralToIntptr(const IntegerLiteral & i)3856 intptr_t ConstexprIntegerLiteralToIntptr(const IntegerLiteral& i) { 3857 return i.To<intptr_t>(); 3858 } ConstexprIntegerLiteralToUintptr(const IntegerLiteral & i)3859 uintptr_t ConstexprIntegerLiteralToUintptr(const IntegerLiteral& i) { 3860 return i.To<uintptr_t>(); 3861 } ConstexprIntegerLiteralToFloat64(const IntegerLiteral & i)3862 double ConstexprIntegerLiteralToFloat64(const IntegerLiteral& i) { 3863 int64_t i_value = i.To<int64_t>(); 3864 double d_value = static_cast<double>(i_value); 3865 CHECK_EQ(i_value, static_cast<int64_t>(d_value)); 3866 return d_value; 3867 } ConstexprIntegerLiteralEqual(IntegerLiteral lhs,IntegerLiteral rhs)3868 bool ConstexprIntegerLiteralEqual(IntegerLiteral lhs, IntegerLiteral rhs) { 3869 return lhs == rhs; 3870 } 3871 IntegerLiteral ConstexprIntegerLiteralAdd(const IntegerLiteral& lhs, 3872 const IntegerLiteral& rhs); 3873 IntegerLiteral ConstexprIntegerLiteralLeftShift(const IntegerLiteral& lhs, 3874 const IntegerLiteral& rhs); 3875 IntegerLiteral ConstexprIntegerLiteralBitwiseOr(const IntegerLiteral& lhs, 3876 const IntegerLiteral& rhs); 3877 ConstexprInt31Equal(int31_t a,int31_t b)3878 bool ConstexprInt31Equal(int31_t a, int31_t b) { return a == b; } ConstexprInt31NotEqual(int31_t a,int31_t b)3879 bool ConstexprInt31NotEqual(int31_t a, int31_t b) { return a != b; } ConstexprInt31GreaterThanEqual(int31_t a,int31_t b)3880 bool ConstexprInt31GreaterThanEqual(int31_t a, int31_t b) { return a >= b; } ConstexprUint32Equal(uint32_t a,uint32_t b)3881 bool ConstexprUint32Equal(uint32_t a, uint32_t b) { return a == b; } ConstexprUint32NotEqual(uint32_t a,uint32_t b)3882 bool ConstexprUint32NotEqual(uint32_t a, uint32_t b) { return a != b; } ConstexprInt32Equal(int32_t a,int32_t b)3883 bool ConstexprInt32Equal(int32_t a, int32_t b) { return a == b; } ConstexprInt32NotEqual(int32_t a,int32_t b)3884 bool ConstexprInt32NotEqual(int32_t a, int32_t b) { return a != b; } ConstexprInt32GreaterThanEqual(int32_t a,int32_t b)3885 bool ConstexprInt32GreaterThanEqual(int32_t a, int32_t b) { return a >= b; } ConstexprUint32Add(uint32_t a,uint32_t b)3886 uint32_t ConstexprUint32Add(uint32_t a, uint32_t b) { return a + b; } ConstexprUint32Sub(uint32_t a,uint32_t b)3887 int32_t ConstexprUint32Sub(uint32_t a, uint32_t b) { return a - b; } ConstexprInt32Sub(int32_t a,int32_t b)3888 int32_t ConstexprInt32Sub(int32_t a, int32_t b) { return a - b; } ConstexprInt32Add(int32_t a,int32_t b)3889 int32_t ConstexprInt32Add(int32_t a, int32_t b) { return a + b; } ConstexprInt31Add(int31_t a,int31_t b)3890 int31_t ConstexprInt31Add(int31_t a, int31_t b) { 3891 int32_t val; 3892 CHECK(!base::bits::SignedAddOverflow32(a, b, &val)); 3893 return val; 3894 } ConstexprInt31Mul(int31_t a,int31_t b)3895 int31_t ConstexprInt31Mul(int31_t a, int31_t b) { 3896 int32_t val; 3897 CHECK(!base::bits::SignedMulOverflow32(a, b, &val)); 3898 return val; 3899 } 3900 ConstexprWord32Or(int32_t a,int32_t b)3901 int32_t ConstexprWord32Or(int32_t a, int32_t b) { return a | b; } ConstexprWord32Shl(uint32_t a,int32_t b)3902 uint32_t ConstexprWord32Shl(uint32_t a, int32_t b) { return a << b; } 3903 ConstexprUintPtrLessThan(uintptr_t a,uintptr_t b)3904 bool ConstexprUintPtrLessThan(uintptr_t a, uintptr_t b) { return a < b; } 3905 3906 // CSA does not support 64-bit types on 32-bit platforms so as a workaround 3907 // the kMaxSafeIntegerUint64 is defined as uintptr and allowed to be used only 3908 // inside if constexpr (Is64()) i.e. on 64-bit architectures. MaxSafeIntegerUintPtr()3909 static uintptr_t MaxSafeIntegerUintPtr() { 3910 #if defined(V8_HOST_ARCH_64_BIT) 3911 // This ifdef is required to avoid build issues on 32-bit MSVC which 3912 // complains about static_cast<uintptr_t>(kMaxSafeIntegerUint64). 3913 return kMaxSafeIntegerUint64; 3914 #else 3915 UNREACHABLE(); 3916 #endif 3917 } 3918 3919 void PerformStackCheck(TNode<Context> context); 3920 3921 void SetPropertyLength(TNode<Context> context, TNode<Object> array, 3922 TNode<Number> length); 3923 3924 // Implements DescriptorArray::Search(). 3925 void DescriptorLookup(TNode<Name> unique_name, 3926 TNode<DescriptorArray> descriptors, 3927 TNode<Uint32T> bitfield3, Label* if_found, 3928 TVariable<IntPtrT>* var_name_index, 3929 Label* if_not_found); 3930 3931 // Implements TransitionArray::SearchName() - searches for first transition 3932 // entry with given name (note that there could be multiple entries with 3933 // the same name). 3934 void TransitionLookup(TNode<Name> unique_name, 3935 TNode<TransitionArray> transitions, Label* if_found, 3936 TVariable<IntPtrT>* var_name_index, 3937 Label* if_not_found); 3938 3939 // Implements generic search procedure like i::Search<Array>(). 3940 template <typename Array> 3941 void Lookup(TNode<Name> unique_name, TNode<Array> array, 3942 TNode<Uint32T> number_of_valid_entries, Label* if_found, 3943 TVariable<IntPtrT>* var_name_index, Label* if_not_found); 3944 3945 // Implements generic linear search procedure like i::LinearSearch<Array>(). 3946 template <typename Array> 3947 void LookupLinear(TNode<Name> unique_name, TNode<Array> array, 3948 TNode<Uint32T> number_of_valid_entries, Label* if_found, 3949 TVariable<IntPtrT>* var_name_index, Label* if_not_found); 3950 3951 // Implements generic binary search procedure like i::BinarySearch<Array>(). 3952 template <typename Array> 3953 void LookupBinary(TNode<Name> unique_name, TNode<Array> array, 3954 TNode<Uint32T> number_of_valid_entries, Label* if_found, 3955 TVariable<IntPtrT>* var_name_index, Label* if_not_found); 3956 3957 // Converts [Descriptor/Transition]Array entry number to a fixed array index. 3958 template <typename Array> 3959 TNode<IntPtrT> EntryIndexToIndex(TNode<Uint32T> entry_index); 3960 3961 // Implements [Descriptor/Transition]Array::ToKeyIndex. 3962 template <typename Array> 3963 TNode<IntPtrT> ToKeyIndex(TNode<Uint32T> entry_index); 3964 3965 // Implements [Descriptor/Transition]Array::GetKey. 3966 template <typename Array> 3967 TNode<Name> GetKey(TNode<Array> array, TNode<Uint32T> entry_index); 3968 3969 // Implements DescriptorArray::GetDetails. 3970 TNode<Uint32T> DescriptorArrayGetDetails(TNode<DescriptorArray> descriptors, 3971 TNode<Uint32T> descriptor_number); 3972 3973 using ForEachDescriptorBodyFunction = 3974 std::function<void(TNode<IntPtrT> descriptor_key_index)>; 3975 3976 // Descriptor array accessors based on key_index, which is equal to 3977 // DescriptorArray::ToKeyIndex(descriptor). 3978 TNode<Name> LoadKeyByKeyIndex(TNode<DescriptorArray> container, 3979 TNode<IntPtrT> key_index); 3980 TNode<Uint32T> LoadDetailsByKeyIndex(TNode<DescriptorArray> container, 3981 TNode<IntPtrT> key_index); 3982 TNode<Object> LoadValueByKeyIndex(TNode<DescriptorArray> container, 3983 TNode<IntPtrT> key_index); 3984 TNode<MaybeObject> LoadFieldTypeByKeyIndex(TNode<DescriptorArray> container, 3985 TNode<IntPtrT> key_index); 3986 3987 TNode<IntPtrT> DescriptorEntryToIndex(TNode<IntPtrT> descriptor); 3988 3989 // Descriptor array accessors based on descriptor. 3990 TNode<Name> LoadKeyByDescriptorEntry(TNode<DescriptorArray> descriptors, 3991 TNode<IntPtrT> descriptor); 3992 TNode<Name> LoadKeyByDescriptorEntry(TNode<DescriptorArray> descriptors, 3993 int descriptor); 3994 TNode<Uint32T> LoadDetailsByDescriptorEntry( 3995 TNode<DescriptorArray> descriptors, TNode<IntPtrT> descriptor); 3996 TNode<Uint32T> LoadDetailsByDescriptorEntry( 3997 TNode<DescriptorArray> descriptors, int descriptor); 3998 TNode<Object> LoadValueByDescriptorEntry(TNode<DescriptorArray> descriptors, 3999 TNode<IntPtrT> descriptor); 4000 TNode<Object> LoadValueByDescriptorEntry(TNode<DescriptorArray> descriptors, 4001 int descriptor); 4002 TNode<MaybeObject> LoadFieldTypeByDescriptorEntry( 4003 TNode<DescriptorArray> descriptors, TNode<IntPtrT> descriptor); 4004 4005 using ForEachKeyValueFunction = 4006 std::function<void(TNode<Name> key, TNode<Object> value)>; 4007 4008 // For each JSObject property (in DescriptorArray order), check if the key is 4009 // enumerable, and if so, load the value from the receiver and evaluate the 4010 // closure. 4011 void ForEachEnumerableOwnProperty(TNode<Context> context, TNode<Map> map, 4012 TNode<JSObject> object, 4013 PropertiesEnumerationMode mode, 4014 const ForEachKeyValueFunction& body, 4015 Label* bailout); 4016 4017 TNode<Object> CallGetterIfAccessor( 4018 TNode<Object> value, TNode<HeapObject> holder, TNode<Uint32T> details, 4019 TNode<Context> context, TNode<Object> receiver, TNode<Object> name, 4020 Label* if_bailout, 4021 GetOwnPropertyMode mode = kCallJSGetterDontUseCachedName); 4022 4023 TNode<IntPtrT> TryToIntptr(TNode<Object> key, Label* if_not_intptr, 4024 TVariable<Int32T>* var_instance_type = nullptr); 4025 4026 TNode<JSArray> ArrayCreate(TNode<Context> context, TNode<Number> length); 4027 4028 // Allocate a clone of a mutable primitive, if {object} is a mutable 4029 // HeapNumber. 4030 TNode<Object> CloneIfMutablePrimitive(TNode<Object> object); 4031 4032 TNode<Smi> RefillMathRandom(TNode<NativeContext> native_context); 4033 4034 void RemoveFinalizationRegistryCellFromUnregisterTokenMap( 4035 TNode<JSFinalizationRegistry> finalization_registry, 4036 TNode<WeakCell> weak_cell); 4037 FeedbackIteratorEntrySize()4038 TNode<IntPtrT> FeedbackIteratorEntrySize() { 4039 return IntPtrConstant(FeedbackIterator::kEntrySize); 4040 } 4041 FeedbackIteratorHandlerOffset()4042 TNode<IntPtrT> FeedbackIteratorHandlerOffset() { 4043 return IntPtrConstant(FeedbackIterator::kHandlerOffset); 4044 } 4045 4046 TNode<SwissNameDictionary> AllocateSwissNameDictionary( 4047 TNode<IntPtrT> at_least_space_for); 4048 TNode<SwissNameDictionary> AllocateSwissNameDictionary( 4049 int at_least_space_for); 4050 4051 TNode<SwissNameDictionary> AllocateSwissNameDictionaryWithCapacity( 4052 TNode<IntPtrT> capacity); 4053 4054 // MT stands for "minus tag". 4055 TNode<IntPtrT> SwissNameDictionaryOffsetIntoDataTableMT( 4056 TNode<SwissNameDictionary> dict, TNode<IntPtrT> index, int field_index); 4057 4058 // MT stands for "minus tag". 4059 TNode<IntPtrT> SwissNameDictionaryOffsetIntoPropertyDetailsTableMT( 4060 TNode<SwissNameDictionary> dict, TNode<IntPtrT> capacity, 4061 TNode<IntPtrT> index); 4062 4063 TNode<IntPtrT> LoadSwissNameDictionaryNumberOfElements( 4064 TNode<SwissNameDictionary> table, TNode<IntPtrT> capacity); 4065 4066 TNode<IntPtrT> LoadSwissNameDictionaryNumberOfDeletedElements( 4067 TNode<SwissNameDictionary> table, TNode<IntPtrT> capacity); 4068 4069 // Specialized operation to be used when adding entries: 4070 // If used capacity (= number of present + deleted elements) is less than 4071 // |max_usable|, increment the number of present entries and return the used 4072 // capacity value (prior to the incrementation). Otherwise, goto |bailout|. 4073 TNode<Uint32T> SwissNameDictionaryIncreaseElementCountOrBailout( 4074 TNode<ByteArray> meta_table, TNode<IntPtrT> capacity, 4075 TNode<Uint32T> max_usable_capacity, Label* bailout); 4076 4077 // Specialized operation to be used when deleting entries: Decreases the 4078 // number of present entries and increases the number of deleted ones. Returns 4079 // new (= decremented) number of present entries. 4080 TNode<Uint32T> SwissNameDictionaryUpdateCountsForDeletion( 4081 TNode<ByteArray> meta_table, TNode<IntPtrT> capacity); 4082 4083 void StoreSwissNameDictionaryCapacity(TNode<SwissNameDictionary> table, 4084 TNode<Int32T> capacity); 4085 4086 void StoreSwissNameDictionaryEnumToEntryMapping( 4087 TNode<SwissNameDictionary> table, TNode<IntPtrT> capacity, 4088 TNode<IntPtrT> enum_index, TNode<Int32T> entry); 4089 4090 TNode<Name> LoadSwissNameDictionaryKey(TNode<SwissNameDictionary> dict, 4091 TNode<IntPtrT> entry); 4092 4093 void StoreSwissNameDictionaryKeyAndValue(TNode<SwissNameDictionary> dict, 4094 TNode<IntPtrT> entry, 4095 TNode<Object> key, 4096 TNode<Object> value); 4097 4098 // Equivalent to SwissNameDictionary::SetCtrl, therefore preserves the copy of 4099 // the first group at the end of the control table. 4100 void SwissNameDictionarySetCtrl(TNode<SwissNameDictionary> table, 4101 TNode<IntPtrT> capacity, TNode<IntPtrT> entry, 4102 TNode<Uint8T> ctrl); 4103 4104 TNode<Uint64T> LoadSwissNameDictionaryCtrlTableGroup(TNode<IntPtrT> address); 4105 4106 TNode<Uint8T> LoadSwissNameDictionaryPropertyDetails( 4107 TNode<SwissNameDictionary> table, TNode<IntPtrT> capacity, 4108 TNode<IntPtrT> entry); 4109 4110 void StoreSwissNameDictionaryPropertyDetails(TNode<SwissNameDictionary> table, 4111 TNode<IntPtrT> capacity, 4112 TNode<IntPtrT> entry, 4113 TNode<Uint8T> details); 4114 4115 TNode<SwissNameDictionary> CopySwissNameDictionary( 4116 TNode<SwissNameDictionary> original); 4117 4118 void SwissNameDictionaryFindEntry(TNode<SwissNameDictionary> table, 4119 TNode<Name> key, Label* found, 4120 TVariable<IntPtrT>* var_found_entry, 4121 Label* not_found); 4122 4123 void SwissNameDictionaryAdd(TNode<SwissNameDictionary> table, TNode<Name> key, 4124 TNode<Object> value, 4125 TNode<Uint8T> property_details, 4126 Label* needs_resize); 4127 4128 private: 4129 friend class CodeStubArguments; 4130 4131 void HandleBreakOnNode(); 4132 4133 TNode<HeapObject> AllocateRawDoubleAligned(TNode<IntPtrT> size_in_bytes, 4134 AllocationFlags flags, 4135 TNode<RawPtrT> top_address, 4136 TNode<RawPtrT> limit_address); 4137 TNode<HeapObject> AllocateRawUnaligned(TNode<IntPtrT> size_in_bytes, 4138 AllocationFlags flags, 4139 TNode<RawPtrT> top_address, 4140 TNode<RawPtrT> limit_address); 4141 TNode<HeapObject> AllocateRaw(TNode<IntPtrT> size_in_bytes, 4142 AllocationFlags flags, 4143 TNode<RawPtrT> top_address, 4144 TNode<RawPtrT> limit_address); 4145 4146 // Allocate and return a JSArray of given total size in bytes with header 4147 // fields initialized. 4148 TNode<JSArray> AllocateUninitializedJSArray( 4149 TNode<Map> array_map, TNode<Smi> length, 4150 base::Optional<TNode<AllocationSite>> allocation_site, 4151 TNode<IntPtrT> size_in_bytes); 4152 4153 // Increases the provided capacity to the next valid value, if necessary. 4154 template <typename CollectionType> 4155 TNode<CollectionType> AllocateOrderedHashTable(TNode<IntPtrT> capacity); 4156 4157 // Uses the provided capacity (which must be valid) in verbatim. 4158 template <typename CollectionType> 4159 TNode<CollectionType> AllocateOrderedHashTableWithCapacity( 4160 TNode<IntPtrT> capacity); 4161 SmiShiftBitsConstant()4162 TNode<IntPtrT> SmiShiftBitsConstant() { 4163 return IntPtrConstant(kSmiShiftSize + kSmiTagSize); 4164 } SmiShiftBitsConstant32()4165 TNode<Int32T> SmiShiftBitsConstant32() { 4166 return Int32Constant(kSmiShiftSize + kSmiTagSize); 4167 } 4168 4169 TNode<String> AllocateSlicedString(RootIndex map_root_index, 4170 TNode<Uint32T> length, 4171 TNode<String> parent, TNode<Smi> offset); 4172 4173 // Implements [Descriptor/Transition]Array::number_of_entries. 4174 template <typename Array> 4175 TNode<Uint32T> NumberOfEntries(TNode<Array> array); 4176 4177 // Implements [Descriptor/Transition]Array::GetSortedKeyIndex. 4178 template <typename Array> 4179 TNode<Uint32T> GetSortedKeyIndex(TNode<Array> descriptors, 4180 TNode<Uint32T> entry_index); 4181 4182 TNode<Smi> CollectFeedbackForString(TNode<Int32T> instance_type); 4183 void GenerateEqual_Same(TNode<Object> value, Label* if_equal, 4184 Label* if_notequal, 4185 TVariable<Smi>* var_type_feedback = nullptr); 4186 4187 static const int kElementLoopUnrollThreshold = 8; 4188 4189 // {convert_bigint} is only meaningful when {mode} == kToNumber. 4190 TNode<Numeric> NonNumberToNumberOrNumeric( 4191 TNode<Context> context, TNode<HeapObject> input, Object::Conversion mode, 4192 BigIntHandling bigint_handling = BigIntHandling::kThrow); 4193 4194 void TaggedToNumeric(TNode<Context> context, TNode<Object> value, 4195 TVariable<Numeric>* var_numeric, 4196 TVariable<Smi>* var_feedback); 4197 4198 enum IsKnownTaggedPointer { kNo, kYes }; 4199 template <Object::Conversion conversion> 4200 void TaggedToWord32OrBigIntImpl(TNode<Context> context, TNode<Object> value, 4201 Label* if_number, 4202 TVariable<Word32T>* var_word32, 4203 IsKnownTaggedPointer is_known_tagged_pointer, 4204 Label* if_bigint = nullptr, 4205 TVariable<BigInt>* var_maybe_bigint = nullptr, 4206 TVariable<Smi>* var_feedback = nullptr); 4207 4208 // Low-level accessors for Descriptor arrays. 4209 template <typename T> 4210 TNode<T> LoadDescriptorArrayElement(TNode<DescriptorArray> object, 4211 TNode<IntPtrT> index, 4212 int additional_offset); 4213 4214 // Hide LoadRoot for subclasses of CodeStubAssembler. If you get an error 4215 // complaining about this method, don't make it public, add your root to 4216 // HEAP_(IM)MUTABLE_IMMOVABLE_OBJECT_LIST instead. If you *really* need 4217 // LoadRoot, use CodeAssembler::LoadRoot. LoadRoot(RootIndex root_index)4218 TNode<Object> LoadRoot(RootIndex root_index) { 4219 return CodeAssembler::LoadRoot(root_index); 4220 } 4221 LoadRootMapWord(RootIndex root_index)4222 TNode<AnyTaggedT> LoadRootMapWord(RootIndex root_index) { 4223 return CodeAssembler::LoadRootMapWord(root_index); 4224 } 4225 4226 template <typename TIndex> 4227 void StoreFixedArrayOrPropertyArrayElement( 4228 TNode<UnionT<FixedArray, PropertyArray>> array, TNode<TIndex> index, 4229 TNode<Object> value, WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, 4230 int additional_offset = 0); 4231 4232 template <typename TIndex> 4233 void StoreElementTypedArrayBigInt(TNode<RawPtrT> elements, ElementsKind kind, 4234 TNode<TIndex> index, TNode<BigInt> value); 4235 4236 template <typename TIndex> 4237 void StoreElementTypedArrayWord32(TNode<RawPtrT> elements, ElementsKind kind, 4238 TNode<TIndex> index, TNode<Word32T> value); 4239 4240 // Store value to an elements array with given elements kind. 4241 // TODO(turbofan): For BIGINT64_ELEMENTS and BIGUINT64_ELEMENTS 4242 // we pass {value} as BigInt object instead of int64_t. We should 4243 // teach TurboFan to handle int64_t on 32-bit platforms eventually. 4244 // TODO(solanes): This method can go away and simplify into only one version 4245 // of StoreElement once we have "if constexpr" available to use. 4246 template <typename TArray, typename TIndex, typename TValue> 4247 void StoreElementTypedArray(TNode<TArray> elements, ElementsKind kind, 4248 TNode<TIndex> index, TNode<TValue> value); 4249 4250 template <typename TIndex> 4251 void StoreElement(TNode<FixedArrayBase> elements, ElementsKind kind, 4252 TNode<TIndex> index, TNode<Object> value); 4253 4254 template <typename TIndex> 4255 void StoreElement(TNode<FixedArrayBase> elements, ElementsKind kind, 4256 TNode<TIndex> index, TNode<Float64T> value); 4257 4258 // Converts {input} to a number if {input} is a plain primitve (i.e. String or 4259 // Oddball) and stores the result in {var_result}. Otherwise, it bails out to 4260 // {if_bailout}. 4261 void TryPlainPrimitiveNonNumberToNumber(TNode<HeapObject> input, 4262 TVariable<Number>* var_result, 4263 Label* if_bailout); 4264 4265 void DcheckHasValidMap(TNode<HeapObject> object); 4266 4267 template <typename TValue> 4268 void EmitElementStoreTypedArray(TNode<JSTypedArray> typed_array, 4269 TNode<IntPtrT> key, TNode<Object> value, 4270 ElementsKind elements_kind, 4271 KeyedAccessStoreMode store_mode, 4272 Label* bailout, TNode<Context> context, 4273 TVariable<Object>* maybe_converted_value); 4274 4275 template <typename TValue> 4276 void EmitElementStoreTypedArrayUpdateValue( 4277 TNode<Object> value, ElementsKind elements_kind, 4278 TNode<TValue> converted_value, TVariable<Object>* maybe_converted_value); 4279 }; 4280 4281 class V8_EXPORT_PRIVATE CodeStubArguments { 4282 public: 4283 // |argc| specifies the number of arguments passed to the builtin excluding 4284 // the receiver. The arguments include the receiver. CodeStubArguments(CodeStubAssembler * assembler,TNode<IntPtrT> argc)4285 CodeStubArguments(CodeStubAssembler* assembler, TNode<IntPtrT> argc) 4286 : CodeStubArguments(assembler, argc, TNode<RawPtrT>()) {} CodeStubArguments(CodeStubAssembler * assembler,TNode<Int32T> argc)4287 CodeStubArguments(CodeStubAssembler* assembler, TNode<Int32T> argc) 4288 : CodeStubArguments(assembler, assembler->ChangeInt32ToIntPtr(argc)) {} 4289 CodeStubArguments(CodeStubAssembler* assembler, TNode<IntPtrT> argc, 4290 TNode<RawPtrT> fp); 4291 4292 // Used by Torque to construct arguments based on a Torque-defined 4293 // struct of values. CodeStubArguments(CodeStubAssembler * assembler,TorqueStructArguments torque_arguments)4294 CodeStubArguments(CodeStubAssembler* assembler, 4295 TorqueStructArguments torque_arguments) 4296 : assembler_(assembler), 4297 argc_(torque_arguments.actual_count), 4298 base_(torque_arguments.base), 4299 fp_(torque_arguments.frame) {} 4300 4301 TNode<Object> GetReceiver() const; 4302 // Replaces receiver argument on the expression stack. Should be used only 4303 // for manipulating arguments in trampoline builtins before tail calling 4304 // further with passing all the JS arguments as is. 4305 void SetReceiver(TNode<Object> object) const; 4306 4307 // Computes address of the index'th argument. 4308 TNode<RawPtrT> AtIndexPtr(TNode<IntPtrT> index) const; 4309 4310 // |index| is zero-based and does not include the receiver 4311 TNode<Object> AtIndex(TNode<IntPtrT> index) const; 4312 TNode<Object> AtIndex(int index) const; 4313 4314 // Return the number of arguments (excluding the receiver). 4315 TNode<IntPtrT> GetLengthWithoutReceiver() const; 4316 // Return the number of arguments (including the receiver). 4317 TNode<IntPtrT> GetLengthWithReceiver() const; 4318 GetTorqueArguments()4319 TorqueStructArguments GetTorqueArguments() const { 4320 return TorqueStructArguments{fp_, base_, GetLengthWithoutReceiver(), argc_}; 4321 } 4322 4323 TNode<Object> GetOptionalArgumentValue(TNode<IntPtrT> index, 4324 TNode<Object> default_value); GetOptionalArgumentValue(TNode<IntPtrT> index)4325 TNode<Object> GetOptionalArgumentValue(TNode<IntPtrT> index) { 4326 return GetOptionalArgumentValue(index, assembler_->UndefinedConstant()); 4327 } GetOptionalArgumentValue(int index)4328 TNode<Object> GetOptionalArgumentValue(int index) { 4329 return GetOptionalArgumentValue(assembler_->IntPtrConstant(index)); 4330 } 4331 4332 // Iteration doesn't include the receiver. |first| and |last| are zero-based. 4333 using ForEachBodyFunction = std::function<void(TNode<Object> arg)>; 4334 void ForEach(const ForEachBodyFunction& body, TNode<IntPtrT> first = {}, 4335 TNode<IntPtrT> last = {}) const { 4336 CodeStubAssembler::VariableList list(0, assembler_->zone()); 4337 ForEach(list, body, first, last); 4338 } 4339 void ForEach(const CodeStubAssembler::VariableList& vars, 4340 const ForEachBodyFunction& body, TNode<IntPtrT> first = {}, 4341 TNode<IntPtrT> last = {}) const; 4342 4343 void PopAndReturn(TNode<Object> value); 4344 4345 private: 4346 CodeStubAssembler* assembler_; 4347 TNode<IntPtrT> argc_; 4348 TNode<RawPtrT> base_; 4349 TNode<RawPtrT> fp_; 4350 }; 4351 4352 class ToDirectStringAssembler : public CodeStubAssembler { 4353 private: 4354 enum StringPointerKind { PTR_TO_DATA, PTR_TO_STRING }; 4355 4356 public: 4357 enum Flag { 4358 kDontUnpackSlicedStrings = 1 << 0, 4359 }; 4360 using Flags = base::Flags<Flag>; 4361 4362 ToDirectStringAssembler(compiler::CodeAssemblerState* state, 4363 TNode<String> string, Flags flags = Flags()); 4364 4365 // Converts flat cons, thin, and sliced strings and returns the direct 4366 // string. The result can be either a sequential or external string. 4367 // Jumps to if_bailout if the string if the string is indirect and cannot 4368 // be unpacked. 4369 TNode<String> TryToDirect(Label* if_bailout); 4370 4371 // Returns a pointer to the beginning of the string data. 4372 // Jumps to if_bailout if the external string cannot be unpacked. PointerToData(Label * if_bailout)4373 TNode<RawPtrT> PointerToData(Label* if_bailout) { 4374 return TryToSequential(PTR_TO_DATA, if_bailout); 4375 } 4376 4377 // Returns a pointer that, offset-wise, looks like a String. 4378 // Jumps to if_bailout if the external string cannot be unpacked. PointerToString(Label * if_bailout)4379 TNode<RawPtrT> PointerToString(Label* if_bailout) { 4380 return TryToSequential(PTR_TO_STRING, if_bailout); 4381 } 4382 string()4383 TNode<String> string() { return var_string_.value(); } instance_type()4384 TNode<Int32T> instance_type() { return var_instance_type_.value(); } offset()4385 TNode<IntPtrT> offset() { return var_offset_.value(); } is_external()4386 TNode<Word32T> is_external() { return var_is_external_.value(); } 4387 4388 private: 4389 TNode<RawPtrT> TryToSequential(StringPointerKind ptr_kind, Label* if_bailout); 4390 4391 TVariable<String> var_string_; 4392 TVariable<Int32T> var_instance_type_; 4393 // TODO(v8:9880): Use UintPtrT here. 4394 TVariable<IntPtrT> var_offset_; 4395 TVariable<Word32T> var_is_external_; 4396 4397 const Flags flags_; 4398 }; 4399 4400 // Performs checks on a given prototype (e.g. map identity, property 4401 // verification), intended for use in fast path checks. 4402 class PrototypeCheckAssembler : public CodeStubAssembler { 4403 public: 4404 enum Flag { 4405 kCheckPrototypePropertyConstness = 1 << 0, 4406 kCheckPrototypePropertyIdentity = 1 << 1, 4407 kCheckFull = 4408 kCheckPrototypePropertyConstness | kCheckPrototypePropertyIdentity, 4409 }; 4410 using Flags = base::Flags<Flag>; 4411 4412 // A tuple describing a relevant property. It contains the descriptor index of 4413 // the property (within the descriptor array), the property's expected name 4414 // (stored as a root), and the property's expected value (stored on the native 4415 // context). 4416 struct DescriptorIndexNameValue { 4417 int descriptor_index; 4418 RootIndex name_root_index; 4419 int expected_value_context_index; 4420 }; 4421 4422 PrototypeCheckAssembler(compiler::CodeAssemblerState* state, Flags flags, 4423 TNode<NativeContext> native_context, 4424 TNode<Map> initial_prototype_map, 4425 base::Vector<DescriptorIndexNameValue> properties); 4426 4427 void CheckAndBranch(TNode<HeapObject> prototype, Label* if_unmodified, 4428 Label* if_modified); 4429 4430 private: 4431 const Flags flags_; 4432 const TNode<NativeContext> native_context_; 4433 const TNode<Map> initial_prototype_map_; 4434 const base::Vector<DescriptorIndexNameValue> properties_; 4435 }; 4436 4437 DEFINE_OPERATORS_FOR_FLAGS(CodeStubAssembler::AllocationFlags) 4438 4439 #define CLASS_MAP_CONSTANT_ADAPTER(V, rootIndexName, rootAccessorName, \ 4440 class_name) \ 4441 template <> \ 4442 inline bool CodeStubAssembler::ClassHasMapConstant<class_name>() { \ 4443 return true; \ 4444 } \ 4445 template <> \ 4446 inline TNode<Map> CodeStubAssembler::GetClassMapConstant<class_name>() { \ 4447 return class_name##MapConstant(); \ 4448 } 4449 4450 UNIQUE_INSTANCE_TYPE_MAP_LIST_GENERATOR(CLASS_MAP_CONSTANT_ADAPTER, _) 4451 4452 } // namespace internal 4453 } // namespace v8 4454 #endif // V8_CODEGEN_CODE_STUB_ASSEMBLER_H_ 4455