[builtins] Implement LoadKeyValuePair in Torque

Change-Id: I0652a75f6d1f6abfb40ba9bf35afeadfd4533336
Reviewed-on: https://chromium-review.googlesource.com/c/1328801
Commit-Queue: Daniel Clifford <danno@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57531}
This commit is contained in:
Daniel Clifford 2018-11-15 09:55:27 +01:00 committed by Commit Bot
parent 5eef688616
commit 33f41e41d8
5 changed files with 119 additions and 126 deletions

View File

@ -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",

View File

@ -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<intptr>(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<intptr>(i));
}
macro StoreArrayHole(elements: FixedDoubleArray, k: Smi): void {
StoreFixedDoubleArrayHoleSmi(elements, k);
}

View File

@ -1262,3 +1262,8 @@ struct IteratorRecord {
// iteratorRecord.[[NextMethod]]
next: Object;
}
struct KeyValuePair {
key: Object;
value: Object;
}

View File

@ -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 <class T>
using TVariable = compiler::TypedCodeAssemblerVariable<T>;
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<Object> LoadAndNormalizeFixedDoubleArrayElement(
TNode<HeapObject> elements, TNode<IntPtrT> 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> context, TNode<Object> maybe_array,
TVariable<Object>* key, TVariable<Object>* value,
Label* if_may_have_side_effects = nullptr,
Label* if_exception = nullptr,
TVariable<Object>* var_exception = nullptr);
};
void BaseCollectionsAssembler::AddConstructorEntry(
@ -155,22 +148,23 @@ void BaseCollectionsAssembler::AddConstructorEntry(
TNode<Object> add_function, TNode<Object> key_value,
Label* if_may_have_side_effects, Label* if_exception,
TVariable<Object>* 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<Object> 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<Object> BaseCollectionsAssembler::LoadAndNormalizeFixedDoubleArrayElement(
return entry.value();
}
void BaseCollectionsAssembler::LoadKeyValue(
TNode<Context> context, TNode<Object> maybe_array, TVariable<Object>* key,
TVariable<Object>* value, Label* if_may_have_side_effects,
Label* if_exception, TVariable<Object>* 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<JSArray> array = CAST(maybe_array);
TNode<Smi> length = LoadFastJSArrayLength(array);
TNode<FixedArrayBase> elements = LoadElements(array);
TNode<Int32T> 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<FixedArray> 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<Object>(GetProperty(
context, maybe_array, isolate()->factory()->zero_string()));
GotoIfException(key->value(), if_exception, var_exception);
*value = UncheckedCast<Object>(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)

View File

@ -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<Smi>(0)),
GetProperty(o, Convert<Smi>(1))
};
}
}
}