diff options
Diffstat (limited to 'src/builtins/builtins-array.cc')
-rw-r--r-- | src/builtins/builtins-array.cc | 2057 |
1 files changed, 1137 insertions, 920 deletions
diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc index c09f11b2..183820e5 100644 --- a/src/builtins/builtins-array.cc +++ b/src/builtins/builtins-array.cc @@ -6,8 +6,14 @@ #include "src/builtins/builtins-utils.h" #include "src/code-factory.h" +#include "src/code-stub-assembler.h" #include "src/contexts.h" +#include "src/counters.h" #include "src/elements.h" +#include "src/isolate.h" +#include "src/lookup.h" +#include "src/objects-inl.h" +#include "src/prototype.h" namespace v8 { namespace internal { @@ -32,7 +38,7 @@ inline bool ClampedToInteger(Isolate* isolate, Object* object, int* out) { *out = static_cast<int>(value); } return true; - } else if (object->IsUndefined(isolate) || object->IsNull(isolate)) { + } else if (object->IsNullOrUndefined(isolate)) { *out = 0; return true; } else if (object->IsBoolean()) { @@ -55,7 +61,13 @@ inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle<JSObject> object, Object* len_obj = object->InObjectPropertyAt(JSArgumentsObject::kLengthIndex); if (!len_obj->IsSmi()) return false; *out = Max(0, Smi::cast(len_obj)->value()); - return *out <= object->elements()->length(); + + FixedArray* parameters = FixedArray::cast(object->elements()); + if (object->HasSloppyArgumentsElements()) { + FixedArray* arguments = FixedArray::cast(parameters->get(1)); + return *out <= arguments->length(); + } + return *out <= parameters->length(); } inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, @@ -144,14 +156,15 @@ MUST_USE_RESULT static Object* CallJsIntrinsic(Isolate* isolate, int argc = args.length() - 1; ScopedVector<Handle<Object>> argv(argc); for (int i = 0; i < argc; ++i) { - argv[i] = args.at<Object>(i + 1); + argv[i] = args.at(i + 1); } RETURN_RESULT_OR_FAILURE( isolate, Execution::Call(isolate, function, args.receiver(), argc, argv.start())); } +} // namespace -Object* DoArrayPush(Isolate* isolate, BuiltinArguments args) { +BUILTIN(ArrayPush) { HandleScope scope(isolate); Handle<Object> receiver = args.receiver(); if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) { @@ -174,19 +187,175 @@ Object* DoArrayPush(Isolate* isolate, BuiltinArguments args) { int new_length = accessor->Push(array, &args, to_add); return Smi::FromInt(new_length); } -} // namespace -BUILTIN(ArrayPush) { return DoArrayPush(isolate, args); } - -// TODO(verwaest): This is a temporary helper until the FastArrayPush stub can -// tailcall to the builtin directly. -RUNTIME_FUNCTION(Runtime_ArrayPush) { - DCHECK_EQ(2, args.length()); - Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); - // Rewrap the arguments as builtins arguments. - int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; - BuiltinArguments caller_args(argc, incoming->arguments() + 1); - return DoArrayPush(isolate, caller_args); +void Builtins::Generate_FastArrayPush(compiler::CodeAssemblerState* state) { + typedef compiler::Node Node; + typedef CodeStubAssembler::Label Label; + typedef CodeStubAssembler::Variable Variable; + CodeStubAssembler assembler(state); + Variable arg_index(&assembler, MachineType::PointerRepresentation()); + Label default_label(&assembler, &arg_index); + Label smi_transition(&assembler); + Label object_push_pre(&assembler); + Label object_push(&assembler, &arg_index); + Label double_push(&assembler, &arg_index); + Label double_transition(&assembler); + Label runtime(&assembler, Label::kDeferred); + + Node* argc = assembler.Parameter(BuiltinDescriptor::kArgumentsCount); + Node* context = assembler.Parameter(BuiltinDescriptor::kContext); + Node* new_target = assembler.Parameter(BuiltinDescriptor::kNewTarget); + + CodeStubArguments args(&assembler, assembler.ChangeInt32ToIntPtr(argc)); + Node* receiver = args.GetReceiver(); + Node* kind = nullptr; + + Label fast(&assembler); + { + assembler.BranchIfFastJSArray( + receiver, context, CodeStubAssembler::FastJSArrayAccessMode::ANY_ACCESS, + &fast, &runtime); + } + + assembler.Bind(&fast); + { + // Disallow pushing onto prototypes. It might be the JSArray prototype. + // Disallow pushing onto non-extensible objects. + assembler.Comment("Disallow pushing onto prototypes"); + Node* map = assembler.LoadMap(receiver); + Node* bit_field2 = assembler.LoadMapBitField2(map); + int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) | + (1 << Map::kIsExtensible); + Node* test = assembler.Word32And(bit_field2, assembler.Int32Constant(mask)); + assembler.GotoIf( + assembler.Word32NotEqual( + test, assembler.Int32Constant(1 << Map::kIsExtensible)), + &runtime); + + // Disallow pushing onto arrays in dictionary named property mode. We need + // to figure out whether the length property is still writable. + assembler.Comment( + "Disallow pushing onto arrays in dictionary named property mode"); + assembler.GotoIf(assembler.IsDictionaryMap(map), &runtime); + + // Check whether the length property is writable. The length property is the + // only default named property on arrays. It's nonconfigurable, hence is + // guaranteed to stay the first property. + Node* descriptors = assembler.LoadMapDescriptors(map); + Node* details = assembler.LoadFixedArrayElement( + descriptors, DescriptorArray::ToDetailsIndex(0)); + assembler.GotoIf( + assembler.IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask), + &runtime); + + arg_index.Bind(assembler.IntPtrConstant(0)); + kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2); + + assembler.GotoIf( + assembler.Int32GreaterThan( + kind, assembler.Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), + &object_push_pre); + + Node* new_length = assembler.BuildAppendJSArray( + FAST_SMI_ELEMENTS, context, receiver, args, arg_index, &smi_transition); + args.PopAndReturn(new_length); + } + + // If the argument is not a smi, then use a heavyweight SetProperty to + // transition the array for only the single next element. If the argument is + // a smi, the failure is due to some other reason and we should fall back on + // the most generic implementation for the rest of the array. + assembler.Bind(&smi_transition); + { + Node* arg = args.AtIndex(arg_index.value()); + assembler.GotoIf(assembler.TaggedIsSmi(arg), &default_label); + Node* length = assembler.LoadJSArrayLength(receiver); + // TODO(danno): Use the KeyedStoreGeneric stub here when possible, + // calling into the runtime to do the elements transition is overkill. + assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, + assembler.SmiConstant(STRICT)); + assembler.Increment(arg_index); + // The runtime SetProperty call could have converted the array to dictionary + // mode, which must be detected to abort the fast-path. + Node* map = assembler.LoadMap(receiver); + Node* bit_field2 = assembler.LoadMapBitField2(map); + Node* kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2); + assembler.GotoIf(assembler.Word32Equal( + kind, assembler.Int32Constant(DICTIONARY_ELEMENTS)), + &default_label); + + assembler.GotoIfNotNumber(arg, &object_push); + assembler.Goto(&double_push); + } + + assembler.Bind(&object_push_pre); + { + assembler.Branch(assembler.Int32GreaterThan( + kind, assembler.Int32Constant(FAST_HOLEY_ELEMENTS)), + &double_push, &object_push); + } + + assembler.Bind(&object_push); + { + Node* new_length = assembler.BuildAppendJSArray( + FAST_ELEMENTS, context, receiver, args, arg_index, &default_label); + args.PopAndReturn(new_length); + } + + assembler.Bind(&double_push); + { + Node* new_length = + assembler.BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, + args, arg_index, &double_transition); + args.PopAndReturn(new_length); + } + + // If the argument is not a double, then use a heavyweight SetProperty to + // transition the array for only the single next element. If the argument is + // a double, the failure is due to some other reason and we should fall back + // on the most generic implementation for the rest of the array. + assembler.Bind(&double_transition); + { + Node* arg = args.AtIndex(arg_index.value()); + assembler.GotoIfNumber(arg, &default_label); + Node* length = assembler.LoadJSArrayLength(receiver); + // TODO(danno): Use the KeyedStoreGeneric stub here when possible, + // calling into the runtime to do the elements transition is overkill. + assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, + assembler.SmiConstant(STRICT)); + assembler.Increment(arg_index); + // The runtime SetProperty call could have converted the array to dictionary + // mode, which must be detected to abort the fast-path. + Node* map = assembler.LoadMap(receiver); + Node* bit_field2 = assembler.LoadMapBitField2(map); + Node* kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2); + assembler.GotoIf(assembler.Word32Equal( + kind, assembler.Int32Constant(DICTIONARY_ELEMENTS)), + &default_label); + assembler.Goto(&object_push); + } + + // Fallback that stores un-processed arguments using the full, heavyweight + // SetProperty machinery. + assembler.Bind(&default_label); + { + args.ForEach( + [&assembler, receiver, context](Node* arg) { + Node* length = assembler.LoadJSArrayLength(receiver); + assembler.CallRuntime(Runtime::kSetProperty, context, receiver, + length, arg, assembler.SmiConstant(STRICT)); + }, + arg_index.value()); + args.PopAndReturn(assembler.LoadJSArrayLength(receiver)); + } + + assembler.Bind(&runtime); + { + Node* target = assembler.LoadFromFrame( + StandardFrameConstants::kFunctionOffset, MachineType::TaggedPointer()); + assembler.TailCallStub(CodeFactory::ArrayPush(assembler.isolate()), context, + target, new_target, argc); + } } BUILTIN(ArrayPop) { @@ -262,6 +431,242 @@ BUILTIN(ArrayUnshift) { return Smi::FromInt(new_length); } +class ForEachCodeStubAssembler : public CodeStubAssembler { + public: + explicit ForEachCodeStubAssembler(compiler::CodeAssemblerState* state) + : CodeStubAssembler(state) {} + + void VisitOneElement(Node* context, Node* this_arg, Node* o, Node* k, + Node* callbackfn) { + Comment("begin VisitOneElement"); + + // a. Let Pk be ToString(k). + Node* p_k = ToString(context, k); + + // b. Let kPresent be HasProperty(O, Pk). + // c. ReturnIfAbrupt(kPresent). + Node* k_present = + CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o); + + // d. If kPresent is true, then + Label not_present(this); + GotoIf(WordNotEqual(k_present, TrueConstant()), ¬_present); + + // i. Let kValue be Get(O, Pk). + // ii. ReturnIfAbrupt(kValue). + Node* k_value = + CallStub(CodeFactory::GetProperty(isolate()), context, o, k); + + // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). + // iv. ReturnIfAbrupt(funcResult). + CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg, k_value, + k, o); + + Goto(¬_present); + Bind(¬_present); + Comment("end VisitOneElement"); + } + + void VisitAllFastElements(Node* context, ElementsKind kind, Node* this_arg, + Node* o, Node* len, Node* callbackfn, + ParameterMode mode) { + Comment("begin VisitAllFastElements"); + Variable original_map(this, MachineRepresentation::kTagged); + original_map.Bind(LoadMap(o)); + VariableList list({&original_map}, zone()); + BuildFastLoop( + list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode), + [context, kind, this, o, &original_map, callbackfn, this_arg, + mode](Node* index) { + Label one_element_done(this), array_changed(this, Label::kDeferred), + hole_element(this); + + // Check if o's map has changed during the callback. If so, we have to + // fall back to the slower spec implementation for the rest of the + // iteration. + Node* o_map = LoadMap(o); + GotoIf(WordNotEqual(o_map, original_map.value()), &array_changed); + + // Check if o's length has changed during the callback and if the + // index is now out of range of the new length. + Node* tagged_index = ParameterToTagged(index, mode); + GotoIf(SmiGreaterThanOrEqual(tagged_index, LoadJSArrayLength(o)), + &array_changed); + + // Re-load the elements array. If may have been resized. + Node* elements = LoadElements(o); + + // Fast case: load the element directly from the elements FixedArray + // and call the callback if the element is not the hole. + DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS); + int base_size = kind == FAST_ELEMENTS + ? FixedArray::kHeaderSize + : (FixedArray::kHeaderSize - kHeapObjectTag); + Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); + Node* value = nullptr; + if (kind == FAST_ELEMENTS) { + value = LoadObjectField(elements, offset); + GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); + } else { + Node* double_value = + LoadDoubleWithHoleCheck(elements, offset, &hole_element); + value = AllocateHeapNumberWithValue(double_value); + } + CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg, + value, tagged_index, o); + Goto(&one_element_done); + + Bind(&hole_element); + BranchIfPrototypesHaveNoElements(o_map, &one_element_done, + &array_changed); + + // O's changed during the forEach. Use the implementation precisely + // specified in the spec for the rest of the iteration, also making + // the failed original_map sticky in case of a subseuent change that + // goes back to the original map. + Bind(&array_changed); + VisitOneElement(context, this_arg, o, ParameterToTagged(index, mode), + callbackfn); + original_map.Bind(UndefinedConstant()); + Goto(&one_element_done); + + Bind(&one_element_done); + }, + 1, mode, IndexAdvanceMode::kPost); + Comment("end VisitAllFastElements"); + } +}; + +TF_BUILTIN(ArrayForEach, ForEachCodeStubAssembler) { + Label non_array(this), examine_elements(this), fast_elements(this), + slow(this), maybe_double_elements(this), fast_double_elements(this); + + Node* receiver = Parameter(ForEachDescriptor::kReceiver); + Node* callbackfn = Parameter(ForEachDescriptor::kCallback); + Node* this_arg = Parameter(ForEachDescriptor::kThisArg); + Node* context = Parameter(ForEachDescriptor::kContext); + + // TODO(danno): Seriously? Do we really need to throw the exact error message + // on null and undefined so that the webkit tests pass? + Label throw_null_undefined_exception(this, Label::kDeferred); + GotoIf(WordEqual(receiver, NullConstant()), &throw_null_undefined_exception); + GotoIf(WordEqual(receiver, UndefinedConstant()), + &throw_null_undefined_exception); + + // By the book: taken directly from the ECMAScript 2015 specification + + // 1. Let O be ToObject(this value). + // 2. ReturnIfAbrupt(O) + Node* o = CallStub(CodeFactory::ToObject(isolate()), context, receiver); + + // 3. Let len be ToLength(Get(O, "length")). + // 4. ReturnIfAbrupt(len). + Variable merged_length(this, MachineRepresentation::kTagged); + Label has_length(this, &merged_length), not_js_array(this); + GotoIf(DoesntHaveInstanceType(o, JS_ARRAY_TYPE), ¬_js_array); + merged_length.Bind(LoadJSArrayLength(o)); + Goto(&has_length); + Bind(¬_js_array); + Node* len_property = + CallStub(CodeFactory::GetProperty(isolate()), context, o, + HeapConstant(isolate()->factory()->length_string())); + merged_length.Bind( + CallStub(CodeFactory::ToLength(isolate()), context, len_property)); + Goto(&has_length); + Bind(&has_length); + Node* len = merged_length.value(); + + // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. + Label type_exception(this, Label::kDeferred); + GotoIf(TaggedIsSmi(callbackfn), &type_exception); + GotoIfNot(IsCallableMap(LoadMap(callbackfn)), &type_exception); + + // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. + // [Already done by the arguments adapter] + + // Non-smi lengths must use the slow path. + GotoIf(TaggedIsNotSmi(len), &slow); + + BranchIfFastJSArray(o, context, + CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, + &examine_elements, &slow); + + Bind(&examine_elements); + + ParameterMode mode = OptimalParameterMode(); + + // Select by ElementsKind + Node* o_map = LoadMap(o); + Node* bit_field2 = LoadMapBitField2(o_map); + Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); + Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), + &maybe_double_elements, &fast_elements); + + Bind(&fast_elements); + { + VisitAllFastElements(context, FAST_ELEMENTS, this_arg, o, len, callbackfn, + mode); + + // No exception, return success + Return(UndefinedConstant()); + } + + Bind(&maybe_double_elements); + Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), + &slow, &fast_double_elements); + + Bind(&fast_double_elements); + { + VisitAllFastElements(context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, + callbackfn, mode); + + // No exception, return success + Return(UndefinedConstant()); + } + + Bind(&slow); + { + // By the book: taken from the ECMAScript 2015 specification (cont.) + + // 7. Let k be 0. + Variable k(this, MachineRepresentation::kTagged); + k.Bind(SmiConstant(0)); + + // 8. Repeat, while k < len + Label loop(this, &k); + Label after_loop(this); + Goto(&loop); + Bind(&loop); + { + GotoUnlessNumberLessThan(k.value(), len, &after_loop); + + VisitOneElement(context, this_arg, o, k.value(), callbackfn); + + // e. Increase k by 1. + k.Bind(NumberInc(k.value())); + Goto(&loop); + } + Bind(&after_loop); + Return(UndefinedConstant()); + } + + Bind(&throw_null_undefined_exception); + { + CallRuntime(Runtime::kThrowTypeError, context, + SmiConstant(MessageTemplate::kCalledOnNullOrUndefined), + HeapConstant(isolate()->factory()->NewStringFromAsciiChecked( + "Array.prototype.forEach"))); + Unreachable(); + } + + Bind(&type_exception); + { + CallRuntime(Runtime::kThrowTypeError, context, + SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn); + Unreachable(); + } +} + BUILTIN(ArraySlice) { HandleScope scope(isolate); Handle<Object> receiver = args.receiver(); @@ -461,8 +866,9 @@ class ArrayConcatVisitor { SeededNumberDictionary::cast(*storage_)); // The object holding this backing store has just been allocated, so // it cannot yet be used as a prototype. - Handle<SeededNumberDictionary> result = - SeededNumberDictionary::AtNumberPut(dict, index, elm, false); + Handle<JSObject> not_a_prototype_holder; + Handle<SeededNumberDictionary> result = SeededNumberDictionary::AtNumberPut( + dict, index, elm, not_a_prototype_holder); if (!result.is_identical_to(dict)) { // Dictionary needed to grow. clear_storage(); @@ -533,9 +939,10 @@ class ArrayConcatVisitor { if (!element->IsTheHole(isolate_)) { // The object holding this backing store has just been allocated, so // it cannot yet be used as a prototype. + Handle<JSObject> not_a_prototype_holder; Handle<SeededNumberDictionary> new_storage = SeededNumberDictionary::AtNumberPut(slow_storage, i, element, - false); + not_a_prototype_holder); if (!new_storage.is_identical_to(slow_storage)) { slow_storage = loop_scope.CloseAndEscape(new_storage); } @@ -1001,8 +1408,9 @@ Object* Slow_ArrayConcat(BuiltinArguments* args, Handle<Object> species, // If estimated number of elements is more than half of length, a // fixed array (fast case) is more time and space-efficient than a // dictionary. - bool fast_case = - is_array_species && (estimate_nof_elements * 2) >= estimate_result_length; + bool fast_case = is_array_species && + (estimate_nof_elements * 2) >= estimate_result_length && + isolate->IsIsConcatSpreadableLookupChainIntact(); if (fast_case && kind == FAST_DOUBLE_ELEMENTS) { Handle<FixedArrayBase> storage = @@ -1202,7 +1610,7 @@ BUILTIN(ArrayConcat) { Handle<Object> receiver = args.receiver(); // TODO(bmeurer): Do we really care about the exact exception message here? - if (receiver->IsNull(isolate) || receiver->IsUndefined(isolate)) { + if (receiver->IsNullOrUndefined(isolate)) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, isolate->factory()->NewStringFromAsciiChecked( @@ -1237,591 +1645,447 @@ BUILTIN(ArrayConcat) { return Slow_ArrayConcat(&args, species, isolate); } -void Builtins::Generate_ArrayIsArray(CodeStubAssembler* assembler) { +void Builtins::Generate_ArrayIsArray(compiler::CodeAssemblerState* state) { typedef compiler::Node Node; typedef CodeStubAssembler::Label Label; + CodeStubAssembler assembler(state); - Node* object = assembler->Parameter(1); - Node* context = assembler->Parameter(4); + Node* object = assembler.Parameter(1); + Node* context = assembler.Parameter(4); - Label call_runtime(assembler), return_true(assembler), - return_false(assembler); + Label call_runtime(&assembler), return_true(&assembler), + return_false(&assembler); - assembler->GotoIf(assembler->TaggedIsSmi(object), &return_false); - Node* instance_type = assembler->LoadInstanceType(object); + assembler.GotoIf(assembler.TaggedIsSmi(object), &return_false); + Node* instance_type = assembler.LoadInstanceType(object); - assembler->GotoIf(assembler->Word32Equal( - instance_type, assembler->Int32Constant(JS_ARRAY_TYPE)), - &return_true); + assembler.GotoIf(assembler.Word32Equal( + instance_type, assembler.Int32Constant(JS_ARRAY_TYPE)), + &return_true); // TODO(verwaest): Handle proxies in-place. - assembler->Branch(assembler->Word32Equal( - instance_type, assembler->Int32Constant(JS_PROXY_TYPE)), - &call_runtime, &return_false); + assembler.Branch(assembler.Word32Equal( + instance_type, assembler.Int32Constant(JS_PROXY_TYPE)), + &call_runtime, &return_false); - assembler->Bind(&return_true); - assembler->Return(assembler->BooleanConstant(true)); + assembler.Bind(&return_true); + assembler.Return(assembler.BooleanConstant(true)); - assembler->Bind(&return_false); - assembler->Return(assembler->BooleanConstant(false)); + assembler.Bind(&return_false); + assembler.Return(assembler.BooleanConstant(false)); - assembler->Bind(&call_runtime); - assembler->Return( - assembler->CallRuntime(Runtime::kArrayIsArray, context, object)); + assembler.Bind(&call_runtime); + assembler.Return( + assembler.CallRuntime(Runtime::kArrayIsArray, context, object)); } -void Builtins::Generate_ArrayIncludes(CodeStubAssembler* assembler) { - typedef compiler::Node Node; - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; +TF_BUILTIN(ArrayIncludes, CodeStubAssembler) { + Node* const array = Parameter(0); + Node* const search_element = Parameter(1); + Node* const start_from = Parameter(2); + Node* const context = Parameter(3 + 2); - Node* array = assembler->Parameter(0); - Node* search_element = assembler->Parameter(1); - Node* start_from = assembler->Parameter(2); - Node* context = assembler->Parameter(3 + 2); + Variable len_var(this, MachineType::PointerRepresentation()), + index_var(this, MachineType::PointerRepresentation()); - Node* intptr_zero = assembler->IntPtrConstant(0); - Node* intptr_one = assembler->IntPtrConstant(1); + Label init_k(this), return_true(this), return_false(this), call_runtime(this); + Label init_len(this), select_loop(this); - Node* the_hole = assembler->TheHoleConstant(); - Node* undefined = assembler->UndefinedConstant(); - Node* heap_number_map = assembler->HeapNumberMapConstant(); - - Variable len_var(assembler, MachineType::PointerRepresentation()), - index_var(assembler, MachineType::PointerRepresentation()), - start_from_var(assembler, MachineType::PointerRepresentation()); - - Label init_k(assembler), return_true(assembler), return_false(assembler), - call_runtime(assembler); - - Label init_len(assembler); - - index_var.Bind(intptr_zero); - len_var.Bind(intptr_zero); + index_var.Bind(IntPtrConstant(0)); + len_var.Bind(IntPtrConstant(0)); // Take slow path if not a JSArray, if retrieving elements requires // traversing prototype, or if access checks are required. - assembler->BranchIfFastJSArray(array, context, &init_len, &call_runtime); + BranchIfFastJSArray(array, context, + CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, + &init_len, &call_runtime); - assembler->Bind(&init_len); + Bind(&init_len); { // Handle case where JSArray length is not an Smi in the runtime - Node* len = assembler->LoadObjectField(array, JSArray::kLengthOffset); - assembler->GotoUnless(assembler->TaggedIsSmi(len), &call_runtime); - - len_var.Bind(assembler->SmiToWord(len)); - assembler->Branch(assembler->WordEqual(len_var.value(), intptr_zero), - &return_false, &init_k); - } + Node* len = LoadObjectField(array, JSArray::kLengthOffset); + GotoIfNot(TaggedIsSmi(len), &call_runtime); - assembler->Bind(&init_k); - { - Label done(assembler), init_k_smi(assembler), init_k_heap_num(assembler), - init_k_zero(assembler), init_k_n(assembler); - Node* tagged_n = assembler->ToInteger(context, start_from); - - assembler->Branch(assembler->TaggedIsSmi(tagged_n), &init_k_smi, - &init_k_heap_num); - - assembler->Bind(&init_k_smi); - { - start_from_var.Bind(assembler->SmiUntag(tagged_n)); - assembler->Goto(&init_k_n); - } - - assembler->Bind(&init_k_heap_num); - { - Label do_return_false(assembler); - // This round is lossless for all valid lengths. - Node* fp_len = assembler->RoundIntPtrToFloat64(len_var.value()); - Node* fp_n = assembler->LoadHeapNumberValue(tagged_n); - assembler->GotoIf(assembler->Float64GreaterThanOrEqual(fp_n, fp_len), - &do_return_false); - start_from_var.Bind(assembler->ChangeInt32ToIntPtr( - assembler->TruncateFloat64ToWord32(fp_n))); - assembler->Goto(&init_k_n); - - assembler->Bind(&do_return_false); - { - index_var.Bind(intptr_zero); - assembler->Goto(&return_false); - } - } - - assembler->Bind(&init_k_n); - { - Label if_positive(assembler), if_negative(assembler), done(assembler); - assembler->Branch( - assembler->IntPtrLessThan(start_from_var.value(), intptr_zero), - &if_negative, &if_positive); - - assembler->Bind(&if_positive); - { - index_var.Bind(start_from_var.value()); - assembler->Goto(&done); - } + len_var.Bind(SmiToWord(len)); - assembler->Bind(&if_negative); - { - index_var.Bind( - assembler->IntPtrAdd(len_var.value(), start_from_var.value())); - assembler->Branch( - assembler->IntPtrLessThan(index_var.value(), intptr_zero), - &init_k_zero, &done); - } - - assembler->Bind(&init_k_zero); - { - index_var.Bind(intptr_zero); - assembler->Goto(&done); - } + GotoIf(IsUndefined(start_from), &select_loop); - assembler->Bind(&done); - } + // Bailout to slow path if startIndex is not an Smi. + Branch(TaggedIsSmi(start_from), &init_k, &call_runtime); } + Bind(&init_k); + CSA_ASSERT(this, TaggedIsSmi(start_from)); + Node* const untagged_start_from = SmiToWord(start_from); + index_var.Bind(Select( + IntPtrGreaterThanOrEqual(untagged_start_from, IntPtrConstant(0)), + [=]() { return untagged_start_from; }, + [=]() { + Node* const index = IntPtrAdd(len_var.value(), untagged_start_from); + return SelectConstant(IntPtrLessThan(index, IntPtrConstant(0)), + IntPtrConstant(0), index, + MachineType::PointerRepresentation()); + }, + MachineType::PointerRepresentation())); + + Goto(&select_loop); + Bind(&select_loop); static int32_t kElementsKind[] = { FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS, FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, }; - Label if_smiorobjects(assembler), if_packed_doubles(assembler), - if_holey_doubles(assembler); + Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this); Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects, &if_smiorobjects, &if_smiorobjects, &if_packed_doubles, &if_holey_doubles}; - Node* map = assembler->LoadMap(array); - Node* elements_kind = assembler->LoadMapElementsKind(map); - Node* elements = assembler->LoadElements(array); - assembler->Switch(elements_kind, &return_false, kElementsKind, - element_kind_handlers, arraysize(kElementsKind)); + Node* map = LoadMap(array); + Node* elements_kind = LoadMapElementsKind(map); + Node* elements = LoadElements(array); + Switch(elements_kind, &return_false, kElementsKind, element_kind_handlers, + arraysize(kElementsKind)); - assembler->Bind(&if_smiorobjects); + Bind(&if_smiorobjects); { - Variable search_num(assembler, MachineRepresentation::kFloat64); - Label ident_loop(assembler, &index_var), - heap_num_loop(assembler, &search_num), - string_loop(assembler, &index_var), simd_loop(assembler), - undef_loop(assembler, &index_var), not_smi(assembler), - not_heap_num(assembler); - - assembler->GotoUnless(assembler->TaggedIsSmi(search_element), ¬_smi); - search_num.Bind(assembler->SmiToFloat64(search_element)); - assembler->Goto(&heap_num_loop); - - assembler->Bind(¬_smi); - assembler->GotoIf(assembler->WordEqual(search_element, undefined), - &undef_loop); - Node* map = assembler->LoadMap(search_element); - assembler->GotoIf(assembler->WordNotEqual(map, heap_number_map), - ¬_heap_num); - search_num.Bind(assembler->LoadHeapNumberValue(search_element)); - assembler->Goto(&heap_num_loop); - - assembler->Bind(¬_heap_num); - Node* search_type = assembler->LoadMapInstanceType(map); - assembler->GotoIf(assembler->IsStringInstanceType(search_type), - &string_loop); - assembler->GotoIf( - assembler->Word32Equal(search_type, - assembler->Int32Constant(SIMD128_VALUE_TYPE)), - &simd_loop); - assembler->Goto(&ident_loop); - - assembler->Bind(&ident_loop); + Variable search_num(this, MachineRepresentation::kFloat64); + Label ident_loop(this, &index_var), heap_num_loop(this, &search_num), + string_loop(this, &index_var), undef_loop(this, &index_var), + not_smi(this), not_heap_num(this); + + GotoIfNot(TaggedIsSmi(search_element), ¬_smi); + search_num.Bind(SmiToFloat64(search_element)); + Goto(&heap_num_loop); + + Bind(¬_smi); + GotoIf(WordEqual(search_element, UndefinedConstant()), &undef_loop); + Node* map = LoadMap(search_element); + GotoIfNot(IsHeapNumberMap(map), ¬_heap_num); + search_num.Bind(LoadHeapNumberValue(search_element)); + Goto(&heap_num_loop); + + Bind(¬_heap_num); + Node* search_type = LoadMapInstanceType(map); + GotoIf(IsStringInstanceType(search_type), &string_loop); + Goto(&ident_loop); + + Bind(&ident_loop); { - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), - &return_false); - Node* element_k = assembler->LoadFixedArrayElement( - elements, index_var.value(), 0, CodeStubAssembler::INTPTR_PARAMETERS); - assembler->GotoIf(assembler->WordEqual(element_k, search_element), - &return_true); - - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(&ident_loop); + GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), + &return_false); + Node* element_k = LoadFixedArrayElement(elements, index_var.value()); + GotoIf(WordEqual(element_k, search_element), &return_true); + + index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); + Goto(&ident_loop); } - assembler->Bind(&undef_loop); + Bind(&undef_loop); { - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), - &return_false); - Node* element_k = assembler->LoadFixedArrayElement( - elements, index_var.value(), 0, CodeStubAssembler::INTPTR_PARAMETERS); - assembler->GotoIf(assembler->WordEqual(element_k, undefined), - &return_true); - assembler->GotoIf(assembler->WordEqual(element_k, the_hole), - &return_true); - - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(&undef_loop); + GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), + &return_false); + Node* element_k = LoadFixedArrayElement(elements, index_var.value()); + GotoIf(WordEqual(element_k, UndefinedConstant()), &return_true); + GotoIf(WordEqual(element_k, TheHoleConstant()), &return_true); + + index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); + Goto(&undef_loop); } - assembler->Bind(&heap_num_loop); + Bind(&heap_num_loop); { - Label nan_loop(assembler, &index_var), - not_nan_loop(assembler, &index_var); - assembler->BranchIfFloat64IsNaN(search_num.value(), &nan_loop, - ¬_nan_loop); + Label nan_loop(this, &index_var), not_nan_loop(this, &index_var); + BranchIfFloat64IsNaN(search_num.value(), &nan_loop, ¬_nan_loop); - assembler->Bind(¬_nan_loop); + Bind(¬_nan_loop); { - Label continue_loop(assembler), not_smi(assembler); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), - &return_false); - Node* element_k = assembler->LoadFixedArrayElement( - elements, index_var.value(), 0, - CodeStubAssembler::INTPTR_PARAMETERS); - assembler->GotoUnless(assembler->TaggedIsSmi(element_k), ¬_smi); - assembler->Branch( - assembler->Float64Equal(search_num.value(), - assembler->SmiToFloat64(element_k)), - &return_true, &continue_loop); - - assembler->Bind(¬_smi); - assembler->GotoIf(assembler->WordNotEqual(assembler->LoadMap(element_k), - heap_number_map), - &continue_loop); - assembler->Branch( - assembler->Float64Equal(search_num.value(), - assembler->LoadHeapNumberValue(element_k)), - &return_true, &continue_loop); - - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(¬_nan_loop); + Label continue_loop(this), not_smi(this); + GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), + &return_false); + Node* element_k = LoadFixedArrayElement(elements, index_var.value()); + GotoIfNot(TaggedIsSmi(element_k), ¬_smi); + Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)), + &return_true, &continue_loop); + + Bind(¬_smi); + GotoIfNot(IsHeapNumber(element_k), &continue_loop); + Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)), + &return_true, &continue_loop); + + Bind(&continue_loop); + index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); + Goto(¬_nan_loop); } - assembler->Bind(&nan_loop); + Bind(&nan_loop); { - Label continue_loop(assembler); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), - &return_false); - Node* element_k = assembler->LoadFixedArrayElement( - elements, index_var.value(), 0, - CodeStubAssembler::INTPTR_PARAMETERS); - assembler->GotoIf(assembler->TaggedIsSmi(element_k), &continue_loop); - assembler->GotoIf(assembler->WordNotEqual(assembler->LoadMap(element_k), - heap_number_map), - &continue_loop); - assembler->BranchIfFloat64IsNaN( - assembler->LoadHeapNumberValue(element_k), &return_true, - &continue_loop); - - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(&nan_loop); + Label continue_loop(this); + GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), + &return_false); + Node* element_k = LoadFixedArrayElement(elements, index_var.value()); + GotoIf(TaggedIsSmi(element_k), &continue_loop); + GotoIfNot(IsHeapNumber(element_k), &continue_loop); + BranchIfFloat64IsNaN(LoadHeapNumberValue(element_k), &return_true, + &continue_loop); + + Bind(&continue_loop); + index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); + Goto(&nan_loop); } } - assembler->Bind(&string_loop); + Bind(&string_loop); { - Label continue_loop(assembler); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), - &return_false); - Node* element_k = assembler->LoadFixedArrayElement( - elements, index_var.value(), 0, CodeStubAssembler::INTPTR_PARAMETERS); - assembler->GotoIf(assembler->TaggedIsSmi(element_k), &continue_loop); - assembler->GotoUnless(assembler->IsStringInstanceType( - assembler->LoadInstanceType(element_k)), - &continue_loop); + Label continue_loop(this); + GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), + &return_false); + Node* element_k = LoadFixedArrayElement(elements, index_var.value()); + GotoIf(TaggedIsSmi(element_k), &continue_loop); + GotoIfNot(IsStringInstanceType(LoadInstanceType(element_k)), + &continue_loop); // TODO(bmeurer): Consider inlining the StringEqual logic here. - Callable callable = CodeFactory::StringEqual(assembler->isolate()); - Node* result = - assembler->CallStub(callable, context, search_element, element_k); - assembler->Branch( - assembler->WordEqual(assembler->BooleanConstant(true), result), - &return_true, &continue_loop); - - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(&string_loop); - } + Node* result = CallStub(CodeFactory::StringEqual(isolate()), context, + search_element, element_k); + Branch(WordEqual(BooleanConstant(true), result), &return_true, + &continue_loop); - assembler->Bind(&simd_loop); - { - Label continue_loop(assembler, &index_var), - loop_body(assembler, &index_var); - Node* map = assembler->LoadMap(search_element); - - assembler->Goto(&loop_body); - assembler->Bind(&loop_body); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), - &return_false); - - Node* element_k = assembler->LoadFixedArrayElement( - elements, index_var.value(), 0, CodeStubAssembler::INTPTR_PARAMETERS); - assembler->GotoIf(assembler->TaggedIsSmi(element_k), &continue_loop); - - Node* map_k = assembler->LoadMap(element_k); - assembler->BranchIfSimd128Equal(search_element, map, element_k, map_k, - &return_true, &continue_loop); - - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(&loop_body); + Bind(&continue_loop); + index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); + Goto(&string_loop); } } - assembler->Bind(&if_packed_doubles); + Bind(&if_packed_doubles); { - Label nan_loop(assembler, &index_var), not_nan_loop(assembler, &index_var), - hole_loop(assembler, &index_var), search_notnan(assembler); - Variable search_num(assembler, MachineRepresentation::kFloat64); + Label nan_loop(this, &index_var), not_nan_loop(this, &index_var), + hole_loop(this, &index_var), search_notnan(this); + Variable search_num(this, MachineRepresentation::kFloat64); - assembler->GotoUnless(assembler->TaggedIsSmi(search_element), - &search_notnan); - search_num.Bind(assembler->SmiToFloat64(search_element)); - assembler->Goto(¬_nan_loop); + GotoIfNot(TaggedIsSmi(search_element), &search_notnan); + search_num.Bind(SmiToFloat64(search_element)); + Goto(¬_nan_loop); - assembler->Bind(&search_notnan); - assembler->GotoIf(assembler->WordNotEqual( - assembler->LoadMap(search_element), heap_number_map), - &return_false); + Bind(&search_notnan); + GotoIfNot(IsHeapNumber(search_element), &return_false); - search_num.Bind(assembler->LoadHeapNumberValue(search_element)); + search_num.Bind(LoadHeapNumberValue(search_element)); - assembler->BranchIfFloat64IsNaN(search_num.value(), &nan_loop, - ¬_nan_loop); + BranchIfFloat64IsNaN(search_num.value(), &nan_loop, ¬_nan_loop); // Search for HeapNumber - assembler->Bind(¬_nan_loop); + Bind(¬_nan_loop); { - Label continue_loop(assembler); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), - &return_false); - Node* element_k = assembler->LoadFixedDoubleArrayElement( - elements, index_var.value(), MachineType::Float64(), 0, - CodeStubAssembler::INTPTR_PARAMETERS); - assembler->Branch(assembler->Float64Equal(element_k, search_num.value()), - &return_true, &continue_loop); - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(¬_nan_loop); + Label continue_loop(this); + GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), + &return_false); + Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(), + MachineType::Float64()); + Branch(Float64Equal(element_k, search_num.value()), &return_true, + &continue_loop); + Bind(&continue_loop); + index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); + Goto(¬_nan_loop); } // Search for NaN - assembler->Bind(&nan_loop); + Bind(&nan_loop); { - Label continue_loop(assembler); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), - &return_false); - Node* element_k = assembler->LoadFixedDoubleArrayElement( - elements, index_var.value(), MachineType::Float64(), 0, - CodeStubAssembler::INTPTR_PARAMETERS); - assembler->BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(&nan_loop); + Label continue_loop(this); + GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), + &return_false); + Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(), + MachineType::Float64()); + BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); + Bind(&continue_loop); + index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); + Goto(&nan_loop); } } - assembler->Bind(&if_holey_doubles); + Bind(&if_holey_doubles); { - Label nan_loop(assembler, &index_var), not_nan_loop(assembler, &index_var), - hole_loop(assembler, &index_var), search_notnan(assembler); - Variable search_num(assembler, MachineRepresentation::kFloat64); + Label nan_loop(this, &index_var), not_nan_loop(this, &index_var), + hole_loop(this, &index_var), search_notnan(this); + Variable search_num(this, MachineRepresentation::kFloat64); - assembler->GotoUnless(assembler->TaggedIsSmi(search_element), - &search_notnan); - search_num.Bind(assembler->SmiToFloat64(search_element)); - assembler->Goto(¬_nan_loop); + GotoIfNot(TaggedIsSmi(search_element), &search_notnan); + search_num.Bind(SmiToFloat64(search_element)); + Goto(¬_nan_loop); - assembler->Bind(&search_notnan); - assembler->GotoIf(assembler->WordEqual(search_element, undefined), - &hole_loop); - assembler->GotoIf(assembler->WordNotEqual( - assembler->LoadMap(search_element), heap_number_map), - &return_false); + Bind(&search_notnan); + GotoIf(WordEqual(search_element, UndefinedConstant()), &hole_loop); + GotoIfNot(IsHeapNumber(search_element), &return_false); - search_num.Bind(assembler->LoadHeapNumberValue(search_element)); + search_num.Bind(LoadHeapNumberValue(search_element)); - assembler->BranchIfFloat64IsNaN(search_num.value(), &nan_loop, - ¬_nan_loop); + BranchIfFloat64IsNaN(search_num.value(), &nan_loop, ¬_nan_loop); // Search for HeapNumber - assembler->Bind(¬_nan_loop); + Bind(¬_nan_loop); { - Label continue_loop(assembler); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), - &return_false); + Label continue_loop(this); + GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), + &return_false); // Load double value or continue if it contains a double hole. - Node* element_k = assembler->LoadFixedDoubleArrayElement( + Node* element_k = LoadFixedDoubleArrayElement( elements, index_var.value(), MachineType::Float64(), 0, CodeStubAssembler::INTPTR_PARAMETERS, &continue_loop); - assembler->Branch(assembler->Float64Equal(element_k, search_num.value()), - &return_true, &continue_loop); - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(¬_nan_loop); + Branch(Float64Equal(element_k, search_num.value()), &return_true, + &continue_loop); + Bind(&continue_loop); + index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); + Goto(¬_nan_loop); } // Search for NaN - assembler->Bind(&nan_loop); + Bind(&nan_loop); { - Label continue_loop(assembler); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), - &return_false); + Label continue_loop(this); + GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), + &return_false); // Load double value or continue if it contains a double hole. - Node* element_k = assembler->LoadFixedDoubleArrayElement( + Node* element_k = LoadFixedDoubleArrayElement( elements, index_var.value(), MachineType::Float64(), 0, CodeStubAssembler::INTPTR_PARAMETERS, &continue_loop); - assembler->BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(&nan_loop); + BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); + Bind(&continue_loop); + index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); + Goto(&nan_loop); } // Search for the Hole - assembler->Bind(&hole_loop); + Bind(&hole_loop); { - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), - &return_false); + GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), + &return_false); // Check if the element is a double hole, but don't load it. - assembler->LoadFixedDoubleArrayElement( + LoadFixedDoubleArrayElement( elements, index_var.value(), MachineType::None(), 0, CodeStubAssembler::INTPTR_PARAMETERS, &return_true); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(&hole_loop); + index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); + Goto(&hole_loop); } } - assembler->Bind(&return_true); - assembler->Return(assembler->BooleanConstant(true)); + Bind(&return_true); + Return(TrueConstant()); - assembler->Bind(&return_false); - assembler->Return(assembler->BooleanConstant(false)); + Bind(&return_false); + Return(FalseConstant()); - assembler->Bind(&call_runtime); - assembler->Return(assembler->CallRuntime(Runtime::kArrayIncludes_Slow, - context, array, search_element, - start_from)); + Bind(&call_runtime); + Return(CallRuntime(Runtime::kArrayIncludes_Slow, context, array, + search_element, start_from)); } -void Builtins::Generate_ArrayIndexOf(CodeStubAssembler* assembler) { +void Builtins::Generate_ArrayIndexOf(compiler::CodeAssemblerState* state) { typedef compiler::Node Node; typedef CodeStubAssembler::Label Label; typedef CodeStubAssembler::Variable Variable; + CodeStubAssembler assembler(state); - Node* array = assembler->Parameter(0); - Node* search_element = assembler->Parameter(1); - Node* start_from = assembler->Parameter(2); - Node* context = assembler->Parameter(3 + 2); + Node* array = assembler.Parameter(0); + Node* search_element = assembler.Parameter(1); + Node* start_from = assembler.Parameter(2); + Node* context = assembler.Parameter(3 + 2); - Node* intptr_zero = assembler->IntPtrConstant(0); - Node* intptr_one = assembler->IntPtrConstant(1); + Node* intptr_zero = assembler.IntPtrConstant(0); + Node* intptr_one = assembler.IntPtrConstant(1); - Node* undefined = assembler->UndefinedConstant(); - Node* heap_number_map = assembler->HeapNumberMapConstant(); + Node* undefined = assembler.UndefinedConstant(); - Variable len_var(assembler, MachineType::PointerRepresentation()), - index_var(assembler, MachineType::PointerRepresentation()), - start_from_var(assembler, MachineType::PointerRepresentation()); + Variable len_var(&assembler, MachineType::PointerRepresentation()), + index_var(&assembler, MachineType::PointerRepresentation()), + start_from_var(&assembler, MachineType::PointerRepresentation()); - Label init_k(assembler), return_found(assembler), return_not_found(assembler), - call_runtime(assembler); + Label init_k(&assembler), return_found(&assembler), + return_not_found(&assembler), call_runtime(&assembler); - Label init_len(assembler); + Label init_len(&assembler); index_var.Bind(intptr_zero); len_var.Bind(intptr_zero); // Take slow path if not a JSArray, if retrieving elements requires // traversing prototype, or if access checks are required. - assembler->BranchIfFastJSArray(array, context, &init_len, &call_runtime); + assembler.BranchIfFastJSArray( + array, context, CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, + &init_len, &call_runtime); - assembler->Bind(&init_len); + assembler.Bind(&init_len); { // Handle case where JSArray length is not an Smi in the runtime - Node* len = assembler->LoadObjectField(array, JSArray::kLengthOffset); - assembler->GotoUnless(assembler->TaggedIsSmi(len), &call_runtime); + Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); + assembler.GotoIfNot(assembler.TaggedIsSmi(len), &call_runtime); - len_var.Bind(assembler->SmiToWord(len)); - assembler->Branch(assembler->WordEqual(len_var.value(), intptr_zero), - &return_not_found, &init_k); + len_var.Bind(assembler.SmiToWord(len)); + assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), + &return_not_found, &init_k); } - assembler->Bind(&init_k); + assembler.Bind(&init_k); { - Label done(assembler), init_k_smi(assembler), init_k_heap_num(assembler), - init_k_zero(assembler), init_k_n(assembler); - Node* tagged_n = assembler->ToInteger(context, start_from); + // For now only deal with undefined and Smis here; we must be really careful + // with side-effects from the ToInteger conversion as the side-effects might + // render our assumptions about the receiver being a fast JSArray and the + // length invalid. + Label done(&assembler), init_k_smi(&assembler), init_k_other(&assembler), + init_k_zero(&assembler), init_k_n(&assembler); - assembler->Branch(assembler->TaggedIsSmi(tagged_n), &init_k_smi, - &init_k_heap_num); + assembler.Branch(assembler.TaggedIsSmi(start_from), &init_k_smi, + &init_k_other); - assembler->Bind(&init_k_smi); + assembler.Bind(&init_k_smi); { - start_from_var.Bind(assembler->SmiUntag(tagged_n)); - assembler->Goto(&init_k_n); + start_from_var.Bind(assembler.SmiUntag(start_from)); + assembler.Goto(&init_k_n); } - assembler->Bind(&init_k_heap_num); + assembler.Bind(&init_k_other); { - Label do_return_not_found(assembler); - // This round is lossless for all valid lengths. - Node* fp_len = assembler->RoundIntPtrToFloat64(len_var.value()); - Node* fp_n = assembler->LoadHeapNumberValue(tagged_n); - assembler->GotoIf(assembler->Float64GreaterThanOrEqual(fp_n, fp_len), - &do_return_not_found); - start_from_var.Bind(assembler->ChangeInt32ToIntPtr( - assembler->TruncateFloat64ToWord32(fp_n))); - assembler->Goto(&init_k_n); - - assembler->Bind(&do_return_not_found); - { - index_var.Bind(intptr_zero); - assembler->Goto(&return_not_found); - } + // The fromIndex must be undefined here, otherwise bailout and let the + // runtime deal with the full ToInteger conversion. + assembler.GotoIfNot(assembler.IsUndefined(start_from), &call_runtime); + start_from_var.Bind(intptr_zero); + assembler.Goto(&init_k_n); } - assembler->Bind(&init_k_n); + assembler.Bind(&init_k_n); { - Label if_positive(assembler), if_negative(assembler), done(assembler); - assembler->Branch( - assembler->IntPtrLessThan(start_from_var.value(), intptr_zero), + Label if_positive(&assembler), if_negative(&assembler), done(&assembler); + assembler.Branch( + assembler.IntPtrLessThan(start_from_var.value(), intptr_zero), &if_negative, &if_positive); - assembler->Bind(&if_positive); + assembler.Bind(&if_positive); { index_var.Bind(start_from_var.value()); - assembler->Goto(&done); + assembler.Goto(&done); } - assembler->Bind(&if_negative); + assembler.Bind(&if_negative); { index_var.Bind( - assembler->IntPtrAdd(len_var.value(), start_from_var.value())); - assembler->Branch( - assembler->IntPtrLessThan(index_var.value(), intptr_zero), + assembler.IntPtrAdd(len_var.value(), start_from_var.value())); + assembler.Branch( + assembler.IntPtrLessThan(index_var.value(), intptr_zero), &init_k_zero, &done); } - assembler->Bind(&init_k_zero); + assembler.Bind(&init_k_zero); { index_var.Bind(intptr_zero); - assembler->Goto(&done); + assembler.Goto(&done); } - assembler->Bind(&done); + assembler.Bind(&done); } } @@ -1830,384 +2094,357 @@ void Builtins::Generate_ArrayIndexOf(CodeStubAssembler* assembler) { FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, }; - Label if_smiorobjects(assembler), if_packed_doubles(assembler), - if_holey_doubles(assembler); + Label if_smiorobjects(&assembler), if_packed_doubles(&assembler), + if_holey_doubles(&assembler); Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects, &if_smiorobjects, &if_smiorobjects, &if_packed_doubles, &if_holey_doubles}; - Node* map = assembler->LoadMap(array); - Node* elements_kind = assembler->LoadMapElementsKind(map); - Node* elements = assembler->LoadElements(array); - assembler->Switch(elements_kind, &return_not_found, kElementsKind, - element_kind_handlers, arraysize(kElementsKind)); + Node* map = assembler.LoadMap(array); + Node* elements_kind = assembler.LoadMapElementsKind(map); + Node* elements = assembler.LoadElements(array); + assembler.Switch(elements_kind, &return_not_found, kElementsKind, + element_kind_handlers, arraysize(kElementsKind)); - assembler->Bind(&if_smiorobjects); + assembler.Bind(&if_smiorobjects); { - Variable search_num(assembler, MachineRepresentation::kFloat64); - Label ident_loop(assembler, &index_var), - heap_num_loop(assembler, &search_num), - string_loop(assembler, &index_var), simd_loop(assembler), - undef_loop(assembler, &index_var), not_smi(assembler), - not_heap_num(assembler); - - assembler->GotoUnless(assembler->TaggedIsSmi(search_element), ¬_smi); - search_num.Bind(assembler->SmiToFloat64(search_element)); - assembler->Goto(&heap_num_loop); - - assembler->Bind(¬_smi); - assembler->GotoIf(assembler->WordEqual(search_element, undefined), - &undef_loop); - Node* map = assembler->LoadMap(search_element); - assembler->GotoIf(assembler->WordNotEqual(map, heap_number_map), - ¬_heap_num); - search_num.Bind(assembler->LoadHeapNumberValue(search_element)); - assembler->Goto(&heap_num_loop); - - assembler->Bind(¬_heap_num); - Node* search_type = assembler->LoadMapInstanceType(map); - assembler->GotoIf(assembler->IsStringInstanceType(search_type), - &string_loop); - assembler->GotoIf( - assembler->Word32Equal(search_type, - assembler->Int32Constant(SIMD128_VALUE_TYPE)), - &simd_loop); - assembler->Goto(&ident_loop); - - assembler->Bind(&ident_loop); + Variable search_num(&assembler, MachineRepresentation::kFloat64); + Label ident_loop(&assembler, &index_var), + heap_num_loop(&assembler, &search_num), + string_loop(&assembler, &index_var), undef_loop(&assembler, &index_var), + not_smi(&assembler), not_heap_num(&assembler); + + assembler.GotoIfNot(assembler.TaggedIsSmi(search_element), ¬_smi); + search_num.Bind(assembler.SmiToFloat64(search_element)); + assembler.Goto(&heap_num_loop); + + assembler.Bind(¬_smi); + assembler.GotoIf(assembler.WordEqual(search_element, undefined), + &undef_loop); + Node* map = assembler.LoadMap(search_element); + assembler.GotoIfNot(assembler.IsHeapNumberMap(map), ¬_heap_num); + search_num.Bind(assembler.LoadHeapNumberValue(search_element)); + assembler.Goto(&heap_num_loop); + + assembler.Bind(¬_heap_num); + Node* search_type = assembler.LoadMapInstanceType(map); + assembler.GotoIf(assembler.IsStringInstanceType(search_type), &string_loop); + assembler.Goto(&ident_loop); + + assembler.Bind(&ident_loop); { - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), + assembler.GotoIfNot( + assembler.UintPtrLessThan(index_var.value(), len_var.value()), &return_not_found); - Node* element_k = assembler->LoadFixedArrayElement( - elements, index_var.value(), 0, CodeStubAssembler::INTPTR_PARAMETERS); - assembler->GotoIf(assembler->WordEqual(element_k, search_element), - &return_found); + Node* element_k = + assembler.LoadFixedArrayElement(elements, index_var.value()); + assembler.GotoIf(assembler.WordEqual(element_k, search_element), + &return_found); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(&ident_loop); + index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one)); + assembler.Goto(&ident_loop); } - assembler->Bind(&undef_loop); + assembler.Bind(&undef_loop); { - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), + assembler.GotoIfNot( + assembler.UintPtrLessThan(index_var.value(), len_var.value()), &return_not_found); - Node* element_k = assembler->LoadFixedArrayElement( - elements, index_var.value(), 0, CodeStubAssembler::INTPTR_PARAMETERS); - assembler->GotoIf(assembler->WordEqual(element_k, undefined), - &return_found); + Node* element_k = + assembler.LoadFixedArrayElement(elements, index_var.value()); + assembler.GotoIf(assembler.WordEqual(element_k, undefined), + &return_found); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(&undef_loop); + index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one)); + assembler.Goto(&undef_loop); } - assembler->Bind(&heap_num_loop); + assembler.Bind(&heap_num_loop); { - Label not_nan_loop(assembler, &index_var); - assembler->BranchIfFloat64IsNaN(search_num.value(), &return_not_found, - ¬_nan_loop); + Label not_nan_loop(&assembler, &index_var); + assembler.BranchIfFloat64IsNaN(search_num.value(), &return_not_found, + ¬_nan_loop); - assembler->Bind(¬_nan_loop); + assembler.Bind(¬_nan_loop); { - Label continue_loop(assembler), not_smi(assembler); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), + Label continue_loop(&assembler), not_smi(&assembler); + assembler.GotoIfNot( + assembler.UintPtrLessThan(index_var.value(), len_var.value()), &return_not_found); - Node* element_k = assembler->LoadFixedArrayElement( - elements, index_var.value(), 0, - CodeStubAssembler::INTPTR_PARAMETERS); - assembler->GotoUnless(assembler->TaggedIsSmi(element_k), ¬_smi); - assembler->Branch( - assembler->Float64Equal(search_num.value(), - assembler->SmiToFloat64(element_k)), + Node* element_k = + assembler.LoadFixedArrayElement(elements, index_var.value()); + assembler.GotoIfNot(assembler.TaggedIsSmi(element_k), ¬_smi); + assembler.Branch( + assembler.Float64Equal(search_num.value(), + assembler.SmiToFloat64(element_k)), &return_found, &continue_loop); - assembler->Bind(¬_smi); - assembler->GotoIf(assembler->WordNotEqual(assembler->LoadMap(element_k), - heap_number_map), - &continue_loop); - assembler->Branch( - assembler->Float64Equal(search_num.value(), - assembler->LoadHeapNumberValue(element_k)), + assembler.Bind(¬_smi); + assembler.GotoIfNot( + assembler.IsHeapNumberMap(assembler.LoadMap(element_k)), + &continue_loop); + assembler.Branch( + assembler.Float64Equal(search_num.value(), + assembler.LoadHeapNumberValue(element_k)), &return_found, &continue_loop); - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(¬_nan_loop); + assembler.Bind(&continue_loop); + index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one)); + assembler.Goto(¬_nan_loop); } } - assembler->Bind(&string_loop); + assembler.Bind(&string_loop); { - Label continue_loop(assembler); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), + Label continue_loop(&assembler); + assembler.GotoIfNot( + assembler.UintPtrLessThan(index_var.value(), len_var.value()), &return_not_found); - Node* element_k = assembler->LoadFixedArrayElement( - elements, index_var.value(), 0, CodeStubAssembler::INTPTR_PARAMETERS); - assembler->GotoIf(assembler->TaggedIsSmi(element_k), &continue_loop); - assembler->GotoUnless(assembler->IsStringInstanceType( - assembler->LoadInstanceType(element_k)), - &continue_loop); + Node* element_k = + assembler.LoadFixedArrayElement(elements, index_var.value()); + assembler.GotoIf(assembler.TaggedIsSmi(element_k), &continue_loop); + assembler.GotoIfNot( + assembler.IsStringInstanceType(assembler.LoadInstanceType(element_k)), + &continue_loop); // TODO(bmeurer): Consider inlining the StringEqual logic here. - Callable callable = CodeFactory::StringEqual(assembler->isolate()); + Callable callable = CodeFactory::StringEqual(assembler.isolate()); Node* result = - assembler->CallStub(callable, context, search_element, element_k); - assembler->Branch( - assembler->WordEqual(assembler->BooleanConstant(true), result), + assembler.CallStub(callable, context, search_element, element_k); + assembler.Branch( + assembler.WordEqual(assembler.BooleanConstant(true), result), &return_found, &continue_loop); - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(&string_loop); - } - - assembler->Bind(&simd_loop); - { - Label continue_loop(assembler, &index_var), - loop_body(assembler, &index_var); - Node* map = assembler->LoadMap(search_element); - - assembler->Goto(&loop_body); - assembler->Bind(&loop_body); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), - &return_not_found); - - Node* element_k = assembler->LoadFixedArrayElement( - elements, index_var.value(), 0, CodeStubAssembler::INTPTR_PARAMETERS); - assembler->GotoIf(assembler->TaggedIsSmi(element_k), &continue_loop); - - Node* map_k = assembler->LoadMap(element_k); - assembler->BranchIfSimd128Equal(search_element, map, element_k, map_k, - &return_found, &continue_loop); - - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(&loop_body); + assembler.Bind(&continue_loop); + index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one)); + assembler.Goto(&string_loop); } } - assembler->Bind(&if_packed_doubles); + assembler.Bind(&if_packed_doubles); { - Label not_nan_loop(assembler, &index_var), search_notnan(assembler); - Variable search_num(assembler, MachineRepresentation::kFloat64); + Label not_nan_loop(&assembler, &index_var), search_notnan(&assembler); + Variable search_num(&assembler, MachineRepresentation::kFloat64); - assembler->GotoUnless(assembler->TaggedIsSmi(search_element), - &search_notnan); - search_num.Bind(assembler->SmiToFloat64(search_element)); - assembler->Goto(¬_nan_loop); + assembler.GotoIfNot(assembler.TaggedIsSmi(search_element), &search_notnan); + search_num.Bind(assembler.SmiToFloat64(search_element)); + assembler.Goto(¬_nan_loop); - assembler->Bind(&search_notnan); - assembler->GotoIf(assembler->WordNotEqual( - assembler->LoadMap(search_element), heap_number_map), - &return_not_found); + assembler.Bind(&search_notnan); + assembler.GotoIfNot( + assembler.IsHeapNumberMap(assembler.LoadMap(search_element)), + &return_not_found); - search_num.Bind(assembler->LoadHeapNumberValue(search_element)); + search_num.Bind(assembler.LoadHeapNumberValue(search_element)); - assembler->BranchIfFloat64IsNaN(search_num.value(), &return_not_found, - ¬_nan_loop); + assembler.BranchIfFloat64IsNaN(search_num.value(), &return_not_found, + ¬_nan_loop); // Search for HeapNumber - assembler->Bind(¬_nan_loop); + assembler.Bind(¬_nan_loop); { - Label continue_loop(assembler); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), + Label continue_loop(&assembler); + assembler.GotoIfNot( + assembler.UintPtrLessThan(index_var.value(), len_var.value()), &return_not_found); - Node* element_k = assembler->LoadFixedDoubleArrayElement( - elements, index_var.value(), MachineType::Float64(), 0, - CodeStubAssembler::INTPTR_PARAMETERS); - assembler->Branch(assembler->Float64Equal(element_k, search_num.value()), - &return_found, &continue_loop); - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(¬_nan_loop); + Node* element_k = assembler.LoadFixedDoubleArrayElement( + elements, index_var.value(), MachineType::Float64()); + assembler.Branch(assembler.Float64Equal(element_k, search_num.value()), + &return_found, &continue_loop); + assembler.Bind(&continue_loop); + index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one)); + assembler.Goto(¬_nan_loop); } } - assembler->Bind(&if_holey_doubles); + assembler.Bind(&if_holey_doubles); { - Label not_nan_loop(assembler, &index_var), search_notnan(assembler); - Variable search_num(assembler, MachineRepresentation::kFloat64); + Label not_nan_loop(&assembler, &index_var), search_notnan(&assembler); + Variable search_num(&assembler, MachineRepresentation::kFloat64); - assembler->GotoUnless(assembler->TaggedIsSmi(search_element), - &search_notnan); - search_num.Bind(assembler->SmiToFloat64(search_element)); - assembler->Goto(¬_nan_loop); + assembler.GotoIfNot(assembler.TaggedIsSmi(search_element), &search_notnan); + search_num.Bind(assembler.SmiToFloat64(search_element)); + assembler.Goto(¬_nan_loop); - assembler->Bind(&search_notnan); - assembler->GotoIf(assembler->WordNotEqual( - assembler->LoadMap(search_element), heap_number_map), - &return_not_found); + assembler.Bind(&search_notnan); + assembler.GotoIfNot( + assembler.IsHeapNumberMap(assembler.LoadMap(search_element)), + &return_not_found); - search_num.Bind(assembler->LoadHeapNumberValue(search_element)); + search_num.Bind(assembler.LoadHeapNumberValue(search_element)); - assembler->BranchIfFloat64IsNaN(search_num.value(), &return_not_found, - ¬_nan_loop); + assembler.BranchIfFloat64IsNaN(search_num.value(), &return_not_found, + ¬_nan_loop); // Search for HeapNumber - assembler->Bind(¬_nan_loop); + assembler.Bind(¬_nan_loop); { - Label continue_loop(assembler); - assembler->GotoUnless( - assembler->UintPtrLessThan(index_var.value(), len_var.value()), + Label continue_loop(&assembler); + assembler.GotoIfNot( + assembler.UintPtrLessThan(index_var.value(), len_var.value()), &return_not_found); // Load double value or continue if it contains a double hole. - Node* element_k = assembler->LoadFixedDoubleArrayElement( + Node* element_k = assembler.LoadFixedDoubleArrayElement( elements, index_var.value(), MachineType::Float64(), 0, CodeStubAssembler::INTPTR_PARAMETERS, &continue_loop); - assembler->Branch(assembler->Float64Equal(element_k, search_num.value()), - &return_found, &continue_loop); - assembler->Bind(&continue_loop); - index_var.Bind(assembler->IntPtrAdd(index_var.value(), intptr_one)); - assembler->Goto(¬_nan_loop); + assembler.Branch(assembler.Float64Equal(element_k, search_num.value()), + &return_found, &continue_loop); + assembler.Bind(&continue_loop); + index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one)); + assembler.Goto(¬_nan_loop); } } - assembler->Bind(&return_found); - assembler->Return(assembler->ChangeInt32ToTagged(index_var.value())); + assembler.Bind(&return_found); + assembler.Return(assembler.SmiTag(index_var.value())); - assembler->Bind(&return_not_found); - assembler->Return(assembler->NumberConstant(-1)); + assembler.Bind(&return_not_found); + assembler.Return(assembler.NumberConstant(-1)); - assembler->Bind(&call_runtime); - assembler->Return(assembler->CallRuntime(Runtime::kArrayIndexOf, context, - array, search_element, start_from)); + assembler.Bind(&call_runtime); + assembler.Return(assembler.CallRuntime(Runtime::kArrayIndexOf, context, array, + search_element, start_from)); } namespace { template <IterationKind kIterationKind> -void Generate_ArrayPrototypeIterationMethod(CodeStubAssembler* assembler) { +void Generate_ArrayPrototypeIterationMethod( + compiler::CodeAssemblerState* state) { typedef compiler::Node Node; typedef CodeStubAssembler::Label Label; typedef CodeStubAssembler::Variable Variable; + CodeStubAssembler assembler(state); - Node* receiver = assembler->Parameter(0); - Node* context = assembler->Parameter(3); + Node* receiver = assembler.Parameter(0); + Node* context = assembler.Parameter(3); - Variable var_array(assembler, MachineRepresentation::kTagged); - Variable var_map(assembler, MachineRepresentation::kTagged); - Variable var_type(assembler, MachineRepresentation::kWord32); + Variable var_array(&assembler, MachineRepresentation::kTagged); + Variable var_map(&assembler, MachineRepresentation::kTagged); + Variable var_type(&assembler, MachineRepresentation::kWord32); - Label if_isnotobject(assembler, Label::kDeferred); - Label create_array_iterator(assembler); + Label if_isnotobject(&assembler, Label::kDeferred); + Label create_array_iterator(&assembler); - assembler->GotoIf(assembler->TaggedIsSmi(receiver), &if_isnotobject); + assembler.GotoIf(assembler.TaggedIsSmi(receiver), &if_isnotobject); var_array.Bind(receiver); - var_map.Bind(assembler->LoadMap(receiver)); - var_type.Bind(assembler->LoadMapInstanceType(var_map.value())); - assembler->Branch(assembler->IsJSReceiverInstanceType(var_type.value()), - &create_array_iterator, &if_isnotobject); + var_map.Bind(assembler.LoadMap(receiver)); + var_type.Bind(assembler.LoadMapInstanceType(var_map.value())); + assembler.Branch(assembler.IsJSReceiverInstanceType(var_type.value()), + &create_array_iterator, &if_isnotobject); - assembler->Bind(&if_isnotobject); + assembler.Bind(&if_isnotobject); { - Callable callable = CodeFactory::ToObject(assembler->isolate()); - Node* result = assembler->CallStub(callable, context, receiver); + Callable callable = CodeFactory::ToObject(assembler.isolate()); + Node* result = assembler.CallStub(callable, context, receiver); var_array.Bind(result); - var_map.Bind(assembler->LoadMap(result)); - var_type.Bind(assembler->LoadMapInstanceType(var_map.value())); - assembler->Goto(&create_array_iterator); + var_map.Bind(assembler.LoadMap(result)); + var_type.Bind(assembler.LoadMapInstanceType(var_map.value())); + assembler.Goto(&create_array_iterator); } - assembler->Bind(&create_array_iterator); - assembler->Return(assembler->CreateArrayIterator( - var_array.value(), var_map.value(), var_type.value(), context, - kIterationKind)); + assembler.Bind(&create_array_iterator); + assembler.Return( + assembler.CreateArrayIterator(var_array.value(), var_map.value(), + var_type.value(), context, kIterationKind)); } } // namespace -void Builtins::Generate_ArrayPrototypeValues(CodeStubAssembler* assembler) { - Generate_ArrayPrototypeIterationMethod<IterationKind::kValues>(assembler); +void Builtins::Generate_ArrayPrototypeValues( + compiler::CodeAssemblerState* state) { + Generate_ArrayPrototypeIterationMethod<IterationKind::kValues>(state); } -void Builtins::Generate_ArrayPrototypeEntries(CodeStubAssembler* assembler) { - Generate_ArrayPrototypeIterationMethod<IterationKind::kEntries>(assembler); +void Builtins::Generate_ArrayPrototypeEntries( + compiler::CodeAssemblerState* state) { + Generate_ArrayPrototypeIterationMethod<IterationKind::kEntries>(state); } -void Builtins::Generate_ArrayPrototypeKeys(CodeStubAssembler* assembler) { - Generate_ArrayPrototypeIterationMethod<IterationKind::kKeys>(assembler); +void Builtins::Generate_ArrayPrototypeKeys( + compiler::CodeAssemblerState* state) { + Generate_ArrayPrototypeIterationMethod<IterationKind::kKeys>(state); } void Builtins::Generate_ArrayIteratorPrototypeNext( - CodeStubAssembler* assembler) { + compiler::CodeAssemblerState* state) { typedef compiler::Node Node; typedef CodeStubAssembler::Label Label; typedef CodeStubAssembler::Variable Variable; + CodeStubAssembler assembler(state); - Node* iterator = assembler->Parameter(0); - Node* context = assembler->Parameter(3); + Handle<String> operation = assembler.factory()->NewStringFromAsciiChecked( + "Array Iterator.prototype.next", TENURED); - Variable var_value(assembler, MachineRepresentation::kTagged); - Variable var_done(assembler, MachineRepresentation::kTagged); + Node* iterator = assembler.Parameter(0); + Node* context = assembler.Parameter(3); + + Variable var_value(&assembler, MachineRepresentation::kTagged); + Variable var_done(&assembler, MachineRepresentation::kTagged); // Required, or else `throw_bad_receiver` fails a DCHECK due to these // variables not being bound along all paths, despite not being used. - var_done.Bind(assembler->TrueConstant()); - var_value.Bind(assembler->UndefinedConstant()); + var_done.Bind(assembler.TrueConstant()); + var_value.Bind(assembler.UndefinedConstant()); - Label throw_bad_receiver(assembler, Label::kDeferred); - Label set_done(assembler); - Label allocate_key_result(assembler); - Label allocate_entry_if_needed(assembler); - Label allocate_iterator_result(assembler); - Label generic_values(assembler); + Label throw_bad_receiver(&assembler, Label::kDeferred); + Label set_done(&assembler); + Label allocate_key_result(&assembler); + Label allocate_entry_if_needed(&assembler); + Label allocate_iterator_result(&assembler); + Label generic_values(&assembler); // If O does not have all of the internal slots of an Array Iterator Instance // (22.1.5.3), throw a TypeError exception - assembler->GotoIf(assembler->TaggedIsSmi(iterator), &throw_bad_receiver); - Node* instance_type = assembler->LoadInstanceType(iterator); - assembler->GotoIf( - assembler->Uint32LessThan( - assembler->Int32Constant(LAST_ARRAY_ITERATOR_TYPE - - FIRST_ARRAY_ITERATOR_TYPE), - assembler->Int32Sub(instance_type, assembler->Int32Constant( - FIRST_ARRAY_ITERATOR_TYPE))), + assembler.GotoIf(assembler.TaggedIsSmi(iterator), &throw_bad_receiver); + Node* instance_type = assembler.LoadInstanceType(iterator); + assembler.GotoIf( + assembler.Uint32LessThan( + assembler.Int32Constant(LAST_ARRAY_ITERATOR_TYPE - + FIRST_ARRAY_ITERATOR_TYPE), + assembler.Int32Sub(instance_type, assembler.Int32Constant( + FIRST_ARRAY_ITERATOR_TYPE))), &throw_bad_receiver); // Let a be O.[[IteratedObject]]. - Node* array = assembler->LoadObjectField( + Node* array = assembler.LoadObjectField( iterator, JSArrayIterator::kIteratedObjectOffset); // Let index be O.[[ArrayIteratorNextIndex]]. Node* index = - assembler->LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset); - Node* orig_map = assembler->LoadObjectField( + assembler.LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset); + Node* orig_map = assembler.LoadObjectField( iterator, JSArrayIterator::kIteratedObjectMapOffset); - Node* array_map = assembler->LoadMap(array); + Node* array_map = assembler.LoadMap(array); - Label if_isfastarray(assembler), if_isnotfastarray(assembler); + Label if_isfastarray(&assembler), if_isnotfastarray(&assembler), + if_isdetached(&assembler, Label::kDeferred); - assembler->Branch(assembler->WordEqual(orig_map, array_map), &if_isfastarray, - &if_isnotfastarray); + assembler.Branch(assembler.WordEqual(orig_map, array_map), &if_isfastarray, + &if_isnotfastarray); - assembler->Bind(&if_isfastarray); + assembler.Bind(&if_isfastarray); { - CSA_ASSERT(assembler, - assembler->Word32Equal(assembler->LoadMapInstanceType(array_map), - assembler->Int32Constant(JS_ARRAY_TYPE))); + CSA_ASSERT(&assembler, + assembler.Word32Equal(assembler.LoadMapInstanceType(array_map), + assembler.Int32Constant(JS_ARRAY_TYPE))); - Node* length = assembler->LoadObjectField(array, JSArray::kLengthOffset); + Node* length = assembler.LoadObjectField(array, JSArray::kLengthOffset); - CSA_ASSERT(assembler, assembler->TaggedIsSmi(length)); - CSA_ASSERT(assembler, assembler->TaggedIsSmi(index)); + CSA_ASSERT(&assembler, assembler.TaggedIsSmi(length)); + CSA_ASSERT(&assembler, assembler.TaggedIsSmi(index)); - assembler->GotoUnless(assembler->SmiBelow(index, length), &set_done); + assembler.GotoIfNot(assembler.SmiBelow(index, length), &set_done); - Node* one = assembler->SmiConstant(Smi::FromInt(1)); - assembler->StoreObjectFieldNoWriteBarrier( - iterator, JSArrayIterator::kNextIndexOffset, - assembler->IntPtrAdd(assembler->BitcastTaggedToWord(index), - assembler->BitcastTaggedToWord(one))); + Node* one = assembler.SmiConstant(Smi::FromInt(1)); + assembler.StoreObjectFieldNoWriteBarrier(iterator, + JSArrayIterator::kNextIndexOffset, + assembler.SmiAdd(index, one)); - var_done.Bind(assembler->FalseConstant()); - Node* elements = assembler->LoadElements(array); + var_done.Bind(assembler.FalseConstant()); + Node* elements = assembler.LoadElements(array); static int32_t kInstanceType[] = { JS_FAST_ARRAY_KEY_ITERATOR_TYPE, @@ -2225,8 +2462,8 @@ void Builtins::Generate_ArrayIteratorPrototypeNext( JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE, }; - Label packed_object_values(assembler), holey_object_values(assembler), - packed_double_values(assembler), holey_double_values(assembler); + Label packed_object_values(&assembler), holey_object_values(&assembler), + packed_double_values(&assembler), holey_double_values(&assembler); Label* kInstanceTypeHandlers[] = { &allocate_key_result, &packed_object_values, &holey_object_values, &packed_object_values, &holey_object_values, &packed_double_values, @@ -2234,216 +2471,192 @@ void Builtins::Generate_ArrayIteratorPrototypeNext( &packed_object_values, &holey_object_values, &packed_double_values, &holey_double_values}; - assembler->Switch(instance_type, &throw_bad_receiver, kInstanceType, - kInstanceTypeHandlers, arraysize(kInstanceType)); + assembler.Switch(instance_type, &throw_bad_receiver, kInstanceType, + kInstanceTypeHandlers, arraysize(kInstanceType)); - assembler->Bind(&packed_object_values); + assembler.Bind(&packed_object_values); { - var_value.Bind(assembler->LoadFixedArrayElement( + var_value.Bind(assembler.LoadFixedArrayElement( elements, index, 0, CodeStubAssembler::SMI_PARAMETERS)); - assembler->Goto(&allocate_entry_if_needed); + assembler.Goto(&allocate_entry_if_needed); } - assembler->Bind(&packed_double_values); + assembler.Bind(&packed_double_values); { - Node* value = assembler->LoadFixedDoubleArrayElement( + Node* value = assembler.LoadFixedDoubleArrayElement( elements, index, MachineType::Float64(), 0, CodeStubAssembler::SMI_PARAMETERS); - var_value.Bind(assembler->AllocateHeapNumberWithValue(value)); - assembler->Goto(&allocate_entry_if_needed); + var_value.Bind(assembler.AllocateHeapNumberWithValue(value)); + assembler.Goto(&allocate_entry_if_needed); } - assembler->Bind(&holey_object_values); + assembler.Bind(&holey_object_values); { // Check the array_protector cell, and take the slow path if it's invalid. Node* invalid = - assembler->SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); - Node* cell = assembler->LoadRoot(Heap::kArrayProtectorRootIndex); + assembler.SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); + Node* cell = assembler.LoadRoot(Heap::kArrayProtectorRootIndex); Node* cell_value = - assembler->LoadObjectField(cell, PropertyCell::kValueOffset); - assembler->GotoIf(assembler->WordEqual(cell_value, invalid), - &generic_values); + assembler.LoadObjectField(cell, PropertyCell::kValueOffset); + assembler.GotoIf(assembler.WordEqual(cell_value, invalid), + &generic_values); - var_value.Bind(assembler->UndefinedConstant()); - Node* value = assembler->LoadFixedArrayElement( + var_value.Bind(assembler.UndefinedConstant()); + Node* value = assembler.LoadFixedArrayElement( elements, index, 0, CodeStubAssembler::SMI_PARAMETERS); - assembler->GotoIf( - assembler->WordEqual(value, assembler->TheHoleConstant()), - &allocate_entry_if_needed); + assembler.GotoIf(assembler.WordEqual(value, assembler.TheHoleConstant()), + &allocate_entry_if_needed); var_value.Bind(value); - assembler->Goto(&allocate_entry_if_needed); + assembler.Goto(&allocate_entry_if_needed); } - assembler->Bind(&holey_double_values); + assembler.Bind(&holey_double_values); { // Check the array_protector cell, and take the slow path if it's invalid. Node* invalid = - assembler->SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); - Node* cell = assembler->LoadRoot(Heap::kArrayProtectorRootIndex); + assembler.SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); + Node* cell = assembler.LoadRoot(Heap::kArrayProtectorRootIndex); Node* cell_value = - assembler->LoadObjectField(cell, PropertyCell::kValueOffset); - assembler->GotoIf(assembler->WordEqual(cell_value, invalid), - &generic_values); + assembler.LoadObjectField(cell, PropertyCell::kValueOffset); + assembler.GotoIf(assembler.WordEqual(cell_value, invalid), + &generic_values); - var_value.Bind(assembler->UndefinedConstant()); - Node* value = assembler->LoadFixedDoubleArrayElement( + var_value.Bind(assembler.UndefinedConstant()); + Node* value = assembler.LoadFixedDoubleArrayElement( elements, index, MachineType::Float64(), 0, CodeStubAssembler::SMI_PARAMETERS, &allocate_entry_if_needed); - var_value.Bind(assembler->AllocateHeapNumberWithValue(value)); - assembler->Goto(&allocate_entry_if_needed); + var_value.Bind(assembler.AllocateHeapNumberWithValue(value)); + assembler.Goto(&allocate_entry_if_needed); } } - assembler->Bind(&if_isnotfastarray); + assembler.Bind(&if_isnotfastarray); { - Label if_istypedarray(assembler), if_isgeneric(assembler); + Label if_istypedarray(&assembler), if_isgeneric(&assembler); // If a is undefined, return CreateIterResultObject(undefined, true) - assembler->GotoIf( - assembler->WordEqual(array, assembler->UndefinedConstant()), - &allocate_iterator_result); + assembler.GotoIf(assembler.WordEqual(array, assembler.UndefinedConstant()), + &allocate_iterator_result); - Node* array_type = assembler->LoadInstanceType(array); - assembler->Branch( - assembler->Word32Equal(array_type, - assembler->Int32Constant(JS_TYPED_ARRAY_TYPE)), + Node* array_type = assembler.LoadInstanceType(array); + assembler.Branch( + assembler.Word32Equal(array_type, + assembler.Int32Constant(JS_TYPED_ARRAY_TYPE)), &if_istypedarray, &if_isgeneric); - assembler->Bind(&if_isgeneric); + assembler.Bind(&if_isgeneric); { - Label if_wasfastarray(assembler); + Label if_wasfastarray(&assembler); Node* length = nullptr; { - Variable var_length(assembler, MachineRepresentation::kTagged); - Label if_isarray(assembler), if_isnotarray(assembler), done(assembler); - assembler->Branch( - assembler->Word32Equal(array_type, - assembler->Int32Constant(JS_ARRAY_TYPE)), + Variable var_length(&assembler, MachineRepresentation::kTagged); + Label if_isarray(&assembler), if_isnotarray(&assembler), + done(&assembler); + assembler.Branch( + assembler.Word32Equal(array_type, + assembler.Int32Constant(JS_ARRAY_TYPE)), &if_isarray, &if_isnotarray); - assembler->Bind(&if_isarray); + assembler.Bind(&if_isarray); { var_length.Bind( - assembler->LoadObjectField(array, JSArray::kLengthOffset)); + assembler.LoadObjectField(array, JSArray::kLengthOffset)); // Invalidate protector cell if needed - assembler->Branch( - assembler->WordNotEqual(orig_map, assembler->UndefinedConstant()), + assembler.Branch( + assembler.WordNotEqual(orig_map, assembler.UndefinedConstant()), &if_wasfastarray, &done); - assembler->Bind(&if_wasfastarray); + assembler.Bind(&if_wasfastarray); { - Label if_invalid(assembler, Label::kDeferred); + Label if_invalid(&assembler, Label::kDeferred); // A fast array iterator transitioned to a slow iterator during // iteration. Invalidate fast_array_iteration_prtoector cell to // prevent potential deopt loops. - assembler->StoreObjectFieldNoWriteBarrier( + assembler.StoreObjectFieldNoWriteBarrier( iterator, JSArrayIterator::kIteratedObjectMapOffset, - assembler->UndefinedConstant()); - assembler->GotoIf( - assembler->Uint32LessThanOrEqual( - instance_type, assembler->Int32Constant( + assembler.UndefinedConstant()); + assembler.GotoIf( + assembler.Uint32LessThanOrEqual( + instance_type, assembler.Int32Constant( JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)), &done); - Node* invalid = assembler->SmiConstant( - Smi::FromInt(Isolate::kProtectorInvalid)); - Node* cell = assembler->LoadRoot( - Heap::kFastArrayIterationProtectorRootIndex); - assembler->StoreObjectFieldNoWriteBarrier(cell, Cell::kValueOffset, - invalid); - assembler->Goto(&done); + Node* invalid = + assembler.SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); + Node* cell = + assembler.LoadRoot(Heap::kFastArrayIterationProtectorRootIndex); + assembler.StoreObjectFieldNoWriteBarrier(cell, Cell::kValueOffset, + invalid); + assembler.Goto(&done); } } - assembler->Bind(&if_isnotarray); + assembler.Bind(&if_isnotarray); { - Node* length_string = assembler->HeapConstant( - assembler->isolate()->factory()->length_string()); - Callable get_property = - CodeFactory::GetProperty(assembler->isolate()); + Node* length_string = assembler.HeapConstant( + assembler.isolate()->factory()->length_string()); + Callable get_property = CodeFactory::GetProperty(assembler.isolate()); Node* length = - assembler->CallStub(get_property, context, array, length_string); - Callable to_length = CodeFactory::ToLength(assembler->isolate()); - var_length.Bind(assembler->CallStub(to_length, context, length)); - assembler->Goto(&done); + assembler.CallStub(get_property, context, array, length_string); + Callable to_length = CodeFactory::ToLength(assembler.isolate()); + var_length.Bind(assembler.CallStub(to_length, context, length)); + assembler.Goto(&done); } - assembler->Bind(&done); + assembler.Bind(&done); length = var_length.value(); } - assembler->GotoUnlessNumberLessThan(index, length, &set_done); + assembler.GotoUnlessNumberLessThan(index, length, &set_done); - assembler->StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset, - assembler->NumberInc(index)); - var_done.Bind(assembler->FalseConstant()); + assembler.StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset, + assembler.NumberInc(index)); + var_done.Bind(assembler.FalseConstant()); - assembler->Branch( - assembler->Uint32LessThanOrEqual( + assembler.Branch( + assembler.Uint32LessThanOrEqual( instance_type, - assembler->Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)), + assembler.Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)), &allocate_key_result, &generic_values); - assembler->Bind(&generic_values); + assembler.Bind(&generic_values); { - Callable get_property = CodeFactory::GetProperty(assembler->isolate()); - var_value.Bind( - assembler->CallStub(get_property, context, array, index)); - assembler->Goto(&allocate_entry_if_needed); + Callable get_property = CodeFactory::GetProperty(assembler.isolate()); + var_value.Bind(assembler.CallStub(get_property, context, array, index)); + assembler.Goto(&allocate_entry_if_needed); } } - assembler->Bind(&if_istypedarray); + assembler.Bind(&if_istypedarray); { - Node* length = nullptr; - { - Variable var_length(assembler, MachineRepresentation::kTagged); - Label if_isdetached(assembler, Label::kDeferred), - if_isnotdetached(assembler), done(assembler); + Node* buffer = + assembler.LoadObjectField(array, JSTypedArray::kBufferOffset); + assembler.GotoIf(assembler.IsDetachedBuffer(buffer), &if_isdetached); - Node* buffer = - assembler->LoadObjectField(array, JSTypedArray::kBufferOffset); - assembler->Branch(assembler->IsDetachedBuffer(buffer), &if_isdetached, - &if_isnotdetached); + Node* length = + assembler.LoadObjectField(array, JSTypedArray::kLengthOffset); - assembler->Bind(&if_isnotdetached); - { - var_length.Bind( - assembler->LoadObjectField(array, JSTypedArray::kLengthOffset)); - assembler->Goto(&done); - } + CSA_ASSERT(&assembler, assembler.TaggedIsSmi(length)); + CSA_ASSERT(&assembler, assembler.TaggedIsSmi(index)); - assembler->Bind(&if_isdetached); - { - // TODO(caitp): If IsDetached(buffer) is true, throw a TypeError, per - // https://github.com/tc39/ecma262/issues/713 - var_length.Bind(assembler->SmiConstant(Smi::kZero)); - assembler->Goto(&done); - } + assembler.GotoIfNot(assembler.SmiBelow(index, length), &set_done); - assembler->Bind(&done); - length = var_length.value(); - } - CSA_ASSERT(assembler, assembler->TaggedIsSmi(length)); - CSA_ASSERT(assembler, assembler->TaggedIsSmi(index)); - - assembler->GotoUnless(assembler->SmiBelow(index, length), &set_done); - - Node* one = assembler->SmiConstant(Smi::FromInt(1)); - assembler->StoreObjectFieldNoWriteBarrier( + Node* one = assembler.SmiConstant(1); + assembler.StoreObjectFieldNoWriteBarrier( iterator, JSArrayIterator::kNextIndexOffset, - assembler->IntPtrAdd(assembler->BitcastTaggedToWord(index), - assembler->BitcastTaggedToWord(one))); - var_done.Bind(assembler->FalseConstant()); + assembler.SmiAdd(index, one)); + var_done.Bind(assembler.FalseConstant()); - Node* elements = assembler->LoadElements(array); - Node* base_ptr = assembler->LoadObjectField( + Node* elements = assembler.LoadElements(array); + Node* base_ptr = assembler.LoadObjectField( elements, FixedTypedArrayBase::kBasePointerOffset); - Node* external_ptr = assembler->LoadObjectField( - elements, FixedTypedArrayBase::kExternalPointerOffset); - Node* data_ptr = assembler->IntPtrAdd(base_ptr, external_ptr); + Node* external_ptr = assembler.LoadObjectField( + elements, FixedTypedArrayBase::kExternalPointerOffset, + MachineType::Pointer()); + Node* data_ptr = assembler.IntPtrAdd( + assembler.BitcastTaggedToWord(base_ptr), external_ptr); static int32_t kInstanceType[] = { JS_TYPED_ARRAY_KEY_ITERATOR_TYPE, @@ -2467,10 +2680,10 @@ void Builtins::Generate_ArrayIteratorPrototypeNext( JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE, }; - Label uint8_values(assembler), int8_values(assembler), - uint16_values(assembler), int16_values(assembler), - uint32_values(assembler), int32_values(assembler), - float32_values(assembler), float64_values(assembler); + Label uint8_values(&assembler), int8_values(&assembler), + uint16_values(&assembler), int16_values(&assembler), + uint32_values(&assembler), int32_values(&assembler), + float32_values(&assembler), float64_values(&assembler); Label* kInstanceTypeHandlers[] = { &allocate_key_result, &uint8_values, &uint8_values, &int8_values, &uint16_values, &int16_values, @@ -2481,152 +2694,156 @@ void Builtins::Generate_ArrayIteratorPrototypeNext( &float64_values, }; - var_done.Bind(assembler->FalseConstant()); - assembler->Switch(instance_type, &throw_bad_receiver, kInstanceType, - kInstanceTypeHandlers, arraysize(kInstanceType)); + var_done.Bind(assembler.FalseConstant()); + assembler.Switch(instance_type, &throw_bad_receiver, kInstanceType, + kInstanceTypeHandlers, arraysize(kInstanceType)); - assembler->Bind(&uint8_values); + assembler.Bind(&uint8_values); { - Node* value_uint8 = assembler->LoadFixedTypedArrayElement( + Node* value_uint8 = assembler.LoadFixedTypedArrayElement( data_ptr, index, UINT8_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS); - var_value.Bind(assembler->SmiFromWord(value_uint8)); - assembler->Goto(&allocate_entry_if_needed); + var_value.Bind(assembler.SmiFromWord32(value_uint8)); + assembler.Goto(&allocate_entry_if_needed); } - assembler->Bind(&int8_values); + assembler.Bind(&int8_values); { - Node* value_int8 = assembler->LoadFixedTypedArrayElement( + Node* value_int8 = assembler.LoadFixedTypedArrayElement( data_ptr, index, INT8_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS); - var_value.Bind(assembler->SmiFromWord(value_int8)); - assembler->Goto(&allocate_entry_if_needed); + var_value.Bind(assembler.SmiFromWord32(value_int8)); + assembler.Goto(&allocate_entry_if_needed); } - assembler->Bind(&uint16_values); + assembler.Bind(&uint16_values); { - Node* value_uint16 = assembler->LoadFixedTypedArrayElement( + Node* value_uint16 = assembler.LoadFixedTypedArrayElement( data_ptr, index, UINT16_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS); - var_value.Bind(assembler->SmiFromWord(value_uint16)); - assembler->Goto(&allocate_entry_if_needed); + var_value.Bind(assembler.SmiFromWord32(value_uint16)); + assembler.Goto(&allocate_entry_if_needed); } - assembler->Bind(&int16_values); + assembler.Bind(&int16_values); { - Node* value_int16 = assembler->LoadFixedTypedArrayElement( + Node* value_int16 = assembler.LoadFixedTypedArrayElement( data_ptr, index, INT16_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS); - var_value.Bind(assembler->SmiFromWord(value_int16)); - assembler->Goto(&allocate_entry_if_needed); + var_value.Bind(assembler.SmiFromWord32(value_int16)); + assembler.Goto(&allocate_entry_if_needed); } - assembler->Bind(&uint32_values); + assembler.Bind(&uint32_values); { - Node* value_uint32 = assembler->LoadFixedTypedArrayElement( + Node* value_uint32 = assembler.LoadFixedTypedArrayElement( data_ptr, index, UINT32_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS); - var_value.Bind(assembler->ChangeUint32ToTagged(value_uint32)); - assembler->Goto(&allocate_entry_if_needed); + var_value.Bind(assembler.ChangeUint32ToTagged(value_uint32)); + assembler.Goto(&allocate_entry_if_needed); } - assembler->Bind(&int32_values); + assembler.Bind(&int32_values); { - Node* value_int32 = assembler->LoadFixedTypedArrayElement( + Node* value_int32 = assembler.LoadFixedTypedArrayElement( data_ptr, index, INT32_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS); - var_value.Bind(assembler->ChangeInt32ToTagged(value_int32)); - assembler->Goto(&allocate_entry_if_needed); + var_value.Bind(assembler.ChangeInt32ToTagged(value_int32)); + assembler.Goto(&allocate_entry_if_needed); } - assembler->Bind(&float32_values); + assembler.Bind(&float32_values); { - Node* value_float32 = assembler->LoadFixedTypedArrayElement( + Node* value_float32 = assembler.LoadFixedTypedArrayElement( data_ptr, index, FLOAT32_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS); - var_value.Bind(assembler->AllocateHeapNumberWithValue( - assembler->ChangeFloat32ToFloat64(value_float32))); - assembler->Goto(&allocate_entry_if_needed); + var_value.Bind(assembler.AllocateHeapNumberWithValue( + assembler.ChangeFloat32ToFloat64(value_float32))); + assembler.Goto(&allocate_entry_if_needed); } - assembler->Bind(&float64_values); + assembler.Bind(&float64_values); { - Node* value_float64 = assembler->LoadFixedTypedArrayElement( + Node* value_float64 = assembler.LoadFixedTypedArrayElement( data_ptr, index, FLOAT64_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS); - var_value.Bind(assembler->AllocateHeapNumberWithValue(value_float64)); - assembler->Goto(&allocate_entry_if_needed); + var_value.Bind(assembler.AllocateHeapNumberWithValue(value_float64)); + assembler.Goto(&allocate_entry_if_needed); } } } - assembler->Bind(&set_done); + assembler.Bind(&set_done); { - assembler->StoreObjectFieldNoWriteBarrier( + assembler.StoreObjectFieldNoWriteBarrier( iterator, JSArrayIterator::kIteratedObjectOffset, - assembler->UndefinedConstant()); - assembler->Goto(&allocate_iterator_result); + assembler.UndefinedConstant()); + assembler.Goto(&allocate_iterator_result); } - assembler->Bind(&allocate_key_result); + assembler.Bind(&allocate_key_result); { var_value.Bind(index); - var_done.Bind(assembler->FalseConstant()); - assembler->Goto(&allocate_iterator_result); + var_done.Bind(assembler.FalseConstant()); + assembler.Goto(&allocate_iterator_result); } - assembler->Bind(&allocate_entry_if_needed); + assembler.Bind(&allocate_entry_if_needed); { - assembler->GotoIf( - assembler->Int32GreaterThan( + assembler.GotoIf( + assembler.Int32GreaterThan( instance_type, - assembler->Int32Constant(LAST_ARRAY_KEY_VALUE_ITERATOR_TYPE)), + assembler.Int32Constant(LAST_ARRAY_KEY_VALUE_ITERATOR_TYPE)), &allocate_iterator_result); - Node* elements = assembler->AllocateFixedArray(FAST_ELEMENTS, - assembler->Int32Constant(2)); - assembler->StoreFixedArrayElement(elements, assembler->Int32Constant(0), - index, SKIP_WRITE_BARRIER); - assembler->StoreFixedArrayElement(elements, assembler->Int32Constant(1), - var_value.value(), SKIP_WRITE_BARRIER); - - Node* entry = assembler->Allocate(JSArray::kSize); - Node* map = assembler->LoadContextElement( - assembler->LoadNativeContext(context), - Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX); - - assembler->StoreMapNoWriteBarrier(entry, map); - assembler->StoreObjectFieldRoot(entry, JSArray::kPropertiesOffset, - Heap::kEmptyFixedArrayRootIndex); - assembler->StoreObjectFieldNoWriteBarrier(entry, JSArray::kElementsOffset, - elements); - assembler->StoreObjectFieldNoWriteBarrier( - entry, JSArray::kLengthOffset, assembler->SmiConstant(Smi::FromInt(2))); + Node* elements = assembler.AllocateFixedArray(FAST_ELEMENTS, + assembler.IntPtrConstant(2)); + assembler.StoreFixedArrayElement(elements, 0, index, SKIP_WRITE_BARRIER); + assembler.StoreFixedArrayElement(elements, 1, var_value.value(), + SKIP_WRITE_BARRIER); + + Node* entry = assembler.Allocate(JSArray::kSize); + Node* map = + assembler.LoadContextElement(assembler.LoadNativeContext(context), + Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX); + + assembler.StoreMapNoWriteBarrier(entry, map); + assembler.StoreObjectFieldRoot(entry, JSArray::kPropertiesOffset, + Heap::kEmptyFixedArrayRootIndex); + assembler.StoreObjectFieldNoWriteBarrier(entry, JSArray::kElementsOffset, + elements); + assembler.StoreObjectFieldNoWriteBarrier( + entry, JSArray::kLengthOffset, assembler.SmiConstant(Smi::FromInt(2))); var_value.Bind(entry); - assembler->Goto(&allocate_iterator_result); + assembler.Goto(&allocate_iterator_result); } - assembler->Bind(&allocate_iterator_result); + assembler.Bind(&allocate_iterator_result); { - Node* result = assembler->Allocate(JSIteratorResult::kSize); + Node* result = assembler.Allocate(JSIteratorResult::kSize); Node* map = - assembler->LoadContextElement(assembler->LoadNativeContext(context), - Context::ITERATOR_RESULT_MAP_INDEX); - assembler->StoreMapNoWriteBarrier(result, map); - assembler->StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset, - Heap::kEmptyFixedArrayRootIndex); - assembler->StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset, - Heap::kEmptyFixedArrayRootIndex); - assembler->StoreObjectFieldNoWriteBarrier( + assembler.LoadContextElement(assembler.LoadNativeContext(context), + Context::ITERATOR_RESULT_MAP_INDEX); + assembler.StoreMapNoWriteBarrier(result, map); + assembler.StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset, + Heap::kEmptyFixedArrayRootIndex); + assembler.StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset, + Heap::kEmptyFixedArrayRootIndex); + assembler.StoreObjectFieldNoWriteBarrier( result, JSIteratorResult::kValueOffset, var_value.value()); - assembler->StoreObjectFieldNoWriteBarrier( + assembler.StoreObjectFieldNoWriteBarrier( result, JSIteratorResult::kDoneOffset, var_done.value()); - assembler->Return(result); + assembler.Return(result); } - assembler->Bind(&throw_bad_receiver); + assembler.Bind(&throw_bad_receiver); { // The {receiver} is not a valid JSArrayIterator. - Node* result = assembler->CallRuntime( - Runtime::kThrowIncompatibleMethodReceiver, context, - assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( - "Array Iterator.prototype.next", TENURED)), - iterator); - assembler->Return(result); + assembler.CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, + assembler.HeapConstant(operation), iterator); + assembler.Unreachable(); + } + + assembler.Bind(&if_isdetached); + { + Node* message = assembler.SmiConstant(MessageTemplate::kDetachedOperation); + assembler.CallRuntime(Runtime::kThrowTypeError, context, message, + assembler.HeapConstant(operation)); + assembler.Unreachable(); } } |