diff --git a/BUILD.gn b/BUILD.gn index d15d7beb80..fe3eca7a38 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -923,6 +923,7 @@ torque_files = [ "src/builtins/array-slice.tq", "src/builtins/array-splice.tq", "src/builtins/array-unshift.tq", + "src/builtins/collections.tq", "src/builtins/typed-array.tq", "src/builtins/data-view.tq", "src/builtins/iterator.tq", @@ -933,6 +934,7 @@ torque_files = [ torque_namespaces = [ "base", "array", + "collections", "iterator", "typed-array", "data-view", diff --git a/src/builtins/array.tq b/src/builtins/array.tq index 9666ff7221..b922470e71 100644 --- a/src/builtins/array.tq +++ b/src/builtins/array.tq @@ -40,6 +40,45 @@ namespace array { } } + macro LoadElementOrUndefined(a: FixedArray, i: Smi): Object { + const e: Object = a[i]; + return e == Hole ? Undefined : e; + } + + macro LoadElementOrUndefined(a: FixedArray, i: intptr): Object { + const e: Object = a[i]; + return e == Hole ? Undefined : e; + } + + macro LoadElementOrUndefined(a: FixedArray, i: constexpr int31): Object { + return LoadElementOrUndefined(a, Convert(i)); + } + + macro LoadElementOrUndefined(a: FixedDoubleArray, i: Smi): Object { + try { + const f: float64 = LoadDoubleWithHoleCheck(a, i) otherwise IfHole; + return AllocateHeapNumberWithValue(f); + } + label IfHole { + return Undefined; + } + } + + macro LoadElementOrUndefined(a: FixedDoubleArray, i: intptr): Object { + try { + const f: float64 = LoadDoubleWithHoleCheck(a, i) otherwise IfHole; + return AllocateHeapNumberWithValue(f); + } + label IfHole { + return Undefined; + } + } + + macro LoadElementOrUndefined(a: FixedDoubleArray, i: constexpr int31): + Object { + return LoadElementOrUndefined(a, Convert(i)); + } + macro StoreArrayHole(elements: FixedDoubleArray, k: Smi): void { StoreFixedDoubleArrayHoleSmi(elements, k); } diff --git a/src/builtins/base.tq b/src/builtins/base.tq index e1d8f8ad09..f895fe98a9 100644 --- a/src/builtins/base.tq +++ b/src/builtins/base.tq @@ -1262,3 +1262,8 @@ struct IteratorRecord { // iteratorRecord.[[NextMethod]] next: Object; } + +struct KeyValuePair { + key: Object; + value: Object; +} diff --git a/src/builtins/builtins-collections-gen.cc b/src/builtins/builtins-collections-gen.cc index f7d79d8dda..9d179c1b00 100644 --- a/src/builtins/builtins-collections-gen.cc +++ b/src/builtins/builtins-collections-gen.cc @@ -12,6 +12,7 @@ #include "src/objects/hash-table-inl.h" #include "src/objects/js-collection.h" #include "torque-generated/builtins-base-from-dsl-gen.h" +#include "torque-generated/builtins-collections-from-dsl-gen.h" namespace v8 { namespace internal { @@ -19,10 +20,10 @@ namespace internal { template using TVariable = compiler::TypedCodeAssemblerVariable; -class BaseCollectionsAssembler : public BaseBuiltinsFromDSLAssembler { +class BaseCollectionsAssembler : public CollectionsBuiltinsFromDSLAssembler { public: explicit BaseCollectionsAssembler(compiler::CodeAssemblerState* state) - : BaseBuiltinsFromDSLAssembler(state) {} + : CollectionsBuiltinsFromDSLAssembler(state) {} virtual ~BaseCollectionsAssembler() = default; @@ -140,14 +141,6 @@ class BaseCollectionsAssembler : public BaseBuiltinsFromDSLAssembler { // returns `undefined`. TNode LoadAndNormalizeFixedDoubleArrayElement( TNode elements, TNode index); - - // Loads key and value variables with the first and second elements of an - // array. If the array lacks 2 elements, undefined is used. - void LoadKeyValue(TNode context, TNode maybe_array, - TVariable* key, TVariable* value, - Label* if_may_have_side_effects = nullptr, - Label* if_exception = nullptr, - TVariable* var_exception = nullptr); }; void BaseCollectionsAssembler::AddConstructorEntry( @@ -155,22 +148,23 @@ void BaseCollectionsAssembler::AddConstructorEntry( TNode add_function, TNode key_value, Label* if_may_have_side_effects, Label* if_exception, TVariable* var_exception) { + compiler::CodeAssemblerScopedExceptionHandler handler(this, if_exception, + var_exception); CSA_ASSERT(this, Word32BinaryNot(IsTheHole(key_value))); if (variant == kMap || variant == kWeakMap) { - TVARIABLE(Object, key); - TVARIABLE(Object, value); - LoadKeyValue(context, key_value, &key, &value, if_may_have_side_effects, - if_exception, var_exception); - Node* key_n = key.value(); - Node* value_n = value.value(); - Node* ret = CallJS(CodeFactory::Call(isolate()), context, add_function, - collection, key_n, value_n); - GotoIfException(ret, if_exception, var_exception); + BaseBuiltinsFromDSLAssembler::KeyValuePair pair = + if_may_have_side_effects != nullptr + ? LoadKeyValuePairNoSideEffects(context, key_value, + if_may_have_side_effects) + : LoadKeyValuePair(context, key_value); + Node* key_n = pair.key; + Node* value_n = pair.value; + CallJS(CodeFactory::Call(isolate()), context, add_function, collection, + key_n, value_n); } else { DCHECK(variant == kSet || variant == kWeakSet); - Node* ret = CallJS(CodeFactory::Call(isolate()), context, add_function, - collection, key_value); - GotoIfException(ret, if_exception, var_exception); + CallJS(CodeFactory::Call(isolate()), context, add_function, collection, + key_value); } } @@ -318,7 +312,8 @@ void BaseCollectionsAssembler::AddConstructorEntriesFromIterable( TNode add_func = GetAddFunction(variant, context, collection); IteratorBuiltinsAssembler iterator_assembler(this->state()); - IteratorRecord iterator = iterator_assembler.GetIterator(context, iterable); + BaseBuiltinsFromDSLAssembler::IteratorRecord iterator = + iterator_assembler.GetIterator(context, iterable); CSA_ASSERT(this, Word32BinaryNot(IsUndefined(iterator.object))); @@ -564,109 +559,6 @@ TNode BaseCollectionsAssembler::LoadAndNormalizeFixedDoubleArrayElement( return entry.value(); } -void BaseCollectionsAssembler::LoadKeyValue( - TNode context, TNode maybe_array, TVariable* key, - TVariable* value, Label* if_may_have_side_effects, - Label* if_exception, TVariable* var_exception) { - CSA_ASSERT(this, Word32BinaryNot(IsTheHole(maybe_array))); - - Label exit(this), if_fast(this), if_slow(this, Label::kDeferred); - BranchIfFastJSArray(maybe_array, context, &if_fast, &if_slow); - BIND(&if_fast); - { - TNode array = CAST(maybe_array); - TNode length = LoadFastJSArrayLength(array); - TNode elements = LoadElements(array); - TNode elements_kind = LoadElementsKind(array); - - Label if_smiorobjects(this), if_doubles(this); - Branch(IsFastSmiOrTaggedElementsKind(elements_kind), &if_smiorobjects, - &if_doubles); - BIND(&if_smiorobjects); - { - Label if_one(this), if_two(this); - GotoIf(SmiGreaterThan(length, SmiConstant(1)), &if_two); - GotoIf(SmiEqual(length, SmiConstant(1)), &if_one); - { // empty array - *key = UndefinedConstant(); - *value = UndefinedConstant(); - Goto(&exit); - } - BIND(&if_one); - { - *key = LoadAndNormalizeFixedArrayElement(CAST(elements), - IntPtrConstant(0)); - *value = UndefinedConstant(); - Goto(&exit); - } - BIND(&if_two); - { - TNode elements_fixed_array = CAST(elements); - *key = LoadAndNormalizeFixedArrayElement(elements_fixed_array, - IntPtrConstant(0)); - *value = LoadAndNormalizeFixedArrayElement(elements_fixed_array, - IntPtrConstant(1)); - Goto(&exit); - } - } - BIND(&if_doubles); - { - Label if_one(this), if_two(this); - GotoIf(SmiGreaterThan(length, SmiConstant(1)), &if_two); - GotoIf(SmiEqual(length, SmiConstant(1)), &if_one); - { // empty array - *key = UndefinedConstant(); - *value = UndefinedConstant(); - Goto(&exit); - } - BIND(&if_one); - { - *key = LoadAndNormalizeFixedDoubleArrayElement(elements, - IntPtrConstant(0)); - *value = UndefinedConstant(); - Goto(&exit); - } - BIND(&if_two); - { - *key = LoadAndNormalizeFixedDoubleArrayElement(elements, - IntPtrConstant(0)); - *value = LoadAndNormalizeFixedDoubleArrayElement(elements, - IntPtrConstant(1)); - Goto(&exit); - } - } - } - BIND(&if_slow); - { - Label if_notobject(this, Label::kDeferred); - GotoIfNotJSReceiver(maybe_array, &if_notobject); - if (if_may_have_side_effects != nullptr) { - // If the element is not a fast array, we cannot guarantee accessing the - // key and value won't execute user code that will break fast path - // assumptions. - Goto(if_may_have_side_effects); - } else { - *key = UncheckedCast(GetProperty( - context, maybe_array, isolate()->factory()->zero_string())); - GotoIfException(key->value(), if_exception, var_exception); - - *value = UncheckedCast(GetProperty( - context, maybe_array, isolate()->factory()->one_string())); - GotoIfException(value->value(), if_exception, var_exception); - Goto(&exit); - } - BIND(&if_notobject); - { - Node* ret = CallRuntime( - Runtime::kThrowTypeError, context, - SmiConstant(MessageTemplate::kIteratorValueNotAnObject), maybe_array); - GotoIfException(ret, if_exception, var_exception); - Unreachable(); - } - } - BIND(&exit); -} - class CollectionsBuiltinsAssembler : public BaseCollectionsAssembler { public: explicit CollectionsBuiltinsAssembler(compiler::CodeAssemblerState* state) diff --git a/src/builtins/collections.tq b/src/builtins/collections.tq new file mode 100644 index 0000000000..31dcb6fb4a --- /dev/null +++ b/src/builtins/collections.tq @@ -0,0 +1,55 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +namespace collections { + macro LoadKeyValuePairNoSideEffects(implicit context: Context)(o: Object): + KeyValuePair + labels MayHaveSideEffects { + typeswitch (o) { + case (a: FastJSArray): { + const length: Smi = a.length; + typeswitch (a.elements) { + case (elements: FixedArray): { + return KeyValuePair{ + length > 0 ? array::LoadElementOrUndefined(elements, 0) : + Undefined, + length > 1 ? array::LoadElementOrUndefined(elements, 1) : + Undefined + }; + } + case (elements: FixedDoubleArray): { + return KeyValuePair{ + length > 0 ? array::LoadElementOrUndefined(elements, 0) : + Undefined, + length > 1 ? array::LoadElementOrUndefined(elements, 1) : + Undefined + }; + } + case (Object): deferred { + unreachable; + } + } + } + case (receiver: JSReceiver): { + goto MayHaveSideEffects; + } + case (o: Object): deferred { + ThrowTypeError(context, kIteratorValueNotAnObject, o); + } + } + } + + transitioning macro LoadKeyValuePair(implicit context: Context)(o: Object): + KeyValuePair { + try { + return LoadKeyValuePairNoSideEffects(o) otherwise Generic; + } + label Generic { + return KeyValuePair{ + GetProperty(o, Convert(0)), + GetProperty(o, Convert(1)) + }; + } + } +}