Commit 3e363204 authored by jkummerow's avatar jkummerow Committed by Commit bot

[cleanup] Refactor remaining builtins-*.cc to use TF_BUILTIN macro

Review-Url: https://codereview.chromium.org/2734323004
Cr-Commit-Position: refs/heads/master@{#43695}
parent f58177dd
...@@ -188,76 +188,63 @@ BUILTIN(ArrayPush) { ...@@ -188,76 +188,63 @@ BUILTIN(ArrayPush) {
return Smi::FromInt(new_length); return Smi::FromInt(new_length);
} }
void Builtins::Generate_FastArrayPush(compiler::CodeAssemblerState* state) { TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
typedef compiler::Node Node; Variable arg_index(this, MachineType::PointerRepresentation());
typedef CodeStubAssembler::Label Label; Label default_label(this, &arg_index);
typedef CodeStubAssembler::Variable Variable; Label smi_transition(this);
CodeStubAssembler assembler(state); Label object_push_pre(this);
Variable arg_index(&assembler, MachineType::PointerRepresentation()); Label object_push(this, &arg_index);
Label default_label(&assembler, &arg_index); Label double_push(this, &arg_index);
Label smi_transition(&assembler); Label double_transition(this);
Label object_push_pre(&assembler); Label runtime(this, Label::kDeferred);
Label object_push(&assembler, &arg_index);
Label double_push(&assembler, &arg_index); Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Label double_transition(&assembler); Node* context = Parameter(BuiltinDescriptor::kContext);
Label runtime(&assembler, Label::kDeferred); Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
Node* argc = assembler.Parameter(BuiltinDescriptor::kArgumentsCount); CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
Node* context = assembler.Parameter(BuiltinDescriptor::kContext);
Node* new_target = assembler.Parameter(BuiltinDescriptor::kNewTarget);
CodeStubArguments args(&assembler, assembler.ChangeInt32ToIntPtr(argc));
Node* receiver = args.GetReceiver(); Node* receiver = args.GetReceiver();
Node* kind = nullptr; Node* kind = nullptr;
Label fast(&assembler); Label fast(this);
{ BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::ANY_ACCESS,
assembler.BranchIfFastJSArray( &fast, &runtime);
receiver, context, CodeStubAssembler::FastJSArrayAccessMode::ANY_ACCESS,
&fast, &runtime);
}
assembler.Bind(&fast); Bind(&fast);
{ {
// Disallow pushing onto prototypes. It might be the JSArray prototype. // Disallow pushing onto prototypes. It might be the JSArray prototype.
// Disallow pushing onto non-extensible objects. // Disallow pushing onto non-extensible objects.
assembler.Comment("Disallow pushing onto prototypes"); Comment("Disallow pushing onto prototypes");
Node* map = assembler.LoadMap(receiver); Node* map = LoadMap(receiver);
Node* bit_field2 = assembler.LoadMapBitField2(map); Node* bit_field2 = LoadMapBitField2(map);
int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) | int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) |
(1 << Map::kIsExtensible); (1 << Map::kIsExtensible);
Node* test = assembler.Word32And(bit_field2, assembler.Int32Constant(mask)); Node* test = Word32And(bit_field2, Int32Constant(mask));
assembler.GotoIf( GotoIf(Word32NotEqual(test, Int32Constant(1 << Map::kIsExtensible)),
assembler.Word32NotEqual( &runtime);
test, assembler.Int32Constant(1 << Map::kIsExtensible)),
&runtime);
// Disallow pushing onto arrays in dictionary named property mode. We need // Disallow pushing onto arrays in dictionary named property mode. We need
// to figure out whether the length property is still writable. // to figure out whether the length property is still writable.
assembler.Comment( Comment("Disallow pushing onto arrays in dictionary named property mode");
"Disallow pushing onto arrays in dictionary named property mode"); GotoIf(IsDictionaryMap(map), &runtime);
assembler.GotoIf(assembler.IsDictionaryMap(map), &runtime);
// Check whether the length property is writable. The length property is the // Check whether the length property is writable. The length property is the
// only default named property on arrays. It's nonconfigurable, hence is // only default named property on arrays. It's nonconfigurable, hence is
// guaranteed to stay the first property. // guaranteed to stay the first property.
Node* descriptors = assembler.LoadMapDescriptors(map); Node* descriptors = LoadMapDescriptors(map);
Node* details = assembler.LoadFixedArrayElement( Node* details =
descriptors, DescriptorArray::ToDetailsIndex(0)); LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0));
assembler.GotoIf( GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask),
assembler.IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask), &runtime);
&runtime);
arg_index.Bind(IntPtrConstant(0));
arg_index.Bind(assembler.IntPtrConstant(0)); kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2);
GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)),
assembler.GotoIf( &object_push_pre);
assembler.Int32GreaterThan(
kind, assembler.Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, context, receiver,
&object_push_pre); args, arg_index, &smi_transition);
Node* new_length = assembler.BuildAppendJSArray(
FAST_SMI_ELEMENTS, context, receiver, args, arg_index, &smi_transition);
args.PopAndReturn(new_length); args.PopAndReturn(new_length);
} }
...@@ -265,48 +252,46 @@ void Builtins::Generate_FastArrayPush(compiler::CodeAssemblerState* state) { ...@@ -265,48 +252,46 @@ void Builtins::Generate_FastArrayPush(compiler::CodeAssemblerState* state) {
// transition the array for only the single next element. If the argument is // 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 // 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. // the most generic implementation for the rest of the array.
assembler.Bind(&smi_transition); Bind(&smi_transition);
{ {
Node* arg = args.AtIndex(arg_index.value()); Node* arg = args.AtIndex(arg_index.value());
assembler.GotoIf(assembler.TaggedIsSmi(arg), &default_label); GotoIf(TaggedIsSmi(arg), &default_label);
Node* length = assembler.LoadJSArrayLength(receiver); Node* length = LoadJSArrayLength(receiver);
// TODO(danno): Use the KeyedStoreGeneric stub here when possible, // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
// calling into the runtime to do the elements transition is overkill. // calling into the runtime to do the elements transition is overkill.
assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
assembler.SmiConstant(STRICT)); SmiConstant(STRICT));
assembler.Increment(arg_index); Increment(arg_index);
// The runtime SetProperty call could have converted the array to dictionary // The runtime SetProperty call could have converted the array to dictionary
// mode, which must be detected to abort the fast-path. // mode, which must be detected to abort the fast-path.
Node* map = assembler.LoadMap(receiver); Node* map = LoadMap(receiver);
Node* bit_field2 = assembler.LoadMapBitField2(map); Node* bit_field2 = LoadMapBitField2(map);
Node* kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2); Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
assembler.GotoIf(assembler.Word32Equal( GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
kind, assembler.Int32Constant(DICTIONARY_ELEMENTS)), &default_label);
&default_label);
assembler.GotoIfNotNumber(arg, &object_push); GotoIfNotNumber(arg, &object_push);
assembler.Goto(&double_push); Goto(&double_push);
} }
assembler.Bind(&object_push_pre); Bind(&object_push_pre);
{ {
assembler.Branch(assembler.Int32GreaterThan( Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)),
kind, assembler.Int32Constant(FAST_HOLEY_ELEMENTS)), &double_push, &object_push);
&double_push, &object_push);
} }
assembler.Bind(&object_push); Bind(&object_push);
{ {
Node* new_length = assembler.BuildAppendJSArray( Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, context, receiver,
FAST_ELEMENTS, context, receiver, args, arg_index, &default_label); args, arg_index, &default_label);
args.PopAndReturn(new_length); args.PopAndReturn(new_length);
} }
assembler.Bind(&double_push); Bind(&double_push);
{ {
Node* new_length = Node* new_length =
assembler.BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, args,
args, arg_index, &double_transition); arg_index, &double_transition);
args.PopAndReturn(new_length); args.PopAndReturn(new_length);
} }
...@@ -314,47 +299,46 @@ void Builtins::Generate_FastArrayPush(compiler::CodeAssemblerState* state) { ...@@ -314,47 +299,46 @@ void Builtins::Generate_FastArrayPush(compiler::CodeAssemblerState* state) {
// transition the array for only the single next element. If the argument is // 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 // 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. // on the most generic implementation for the rest of the array.
assembler.Bind(&double_transition); Bind(&double_transition);
{ {
Node* arg = args.AtIndex(arg_index.value()); Node* arg = args.AtIndex(arg_index.value());
assembler.GotoIfNumber(arg, &default_label); GotoIfNumber(arg, &default_label);
Node* length = assembler.LoadJSArrayLength(receiver); Node* length = LoadJSArrayLength(receiver);
// TODO(danno): Use the KeyedStoreGeneric stub here when possible, // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
// calling into the runtime to do the elements transition is overkill. // calling into the runtime to do the elements transition is overkill.
assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
assembler.SmiConstant(STRICT)); SmiConstant(STRICT));
assembler.Increment(arg_index); Increment(arg_index);
// The runtime SetProperty call could have converted the array to dictionary // The runtime SetProperty call could have converted the array to dictionary
// mode, which must be detected to abort the fast-path. // mode, which must be detected to abort the fast-path.
Node* map = assembler.LoadMap(receiver); Node* map = LoadMap(receiver);
Node* bit_field2 = assembler.LoadMapBitField2(map); Node* bit_field2 = LoadMapBitField2(map);
Node* kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2); Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
assembler.GotoIf(assembler.Word32Equal( GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
kind, assembler.Int32Constant(DICTIONARY_ELEMENTS)), &default_label);
&default_label); Goto(&object_push);
assembler.Goto(&object_push);
} }
// Fallback that stores un-processed arguments using the full, heavyweight // Fallback that stores un-processed arguments using the full, heavyweight
// SetProperty machinery. // SetProperty machinery.
assembler.Bind(&default_label); Bind(&default_label);
{ {
args.ForEach( args.ForEach(
[&assembler, receiver, context](Node* arg) { [this, receiver, context](Node* arg) {
Node* length = assembler.LoadJSArrayLength(receiver); Node* length = LoadJSArrayLength(receiver);
assembler.CallRuntime(Runtime::kSetProperty, context, receiver, CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
length, arg, assembler.SmiConstant(STRICT)); SmiConstant(STRICT));
}, },
arg_index.value()); arg_index.value());
args.PopAndReturn(assembler.LoadJSArrayLength(receiver)); args.PopAndReturn(LoadJSArrayLength(receiver));
} }
assembler.Bind(&runtime); Bind(&runtime);
{ {
Node* target = assembler.LoadFromFrame( Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
StandardFrameConstants::kFunctionOffset, MachineType::TaggedPointer()); MachineType::TaggedPointer());
assembler.TailCallStub(CodeFactory::ArrayPush(assembler.isolate()), context, TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target,
target, new_target, argc); argc);
} }
} }
...@@ -1645,38 +1629,30 @@ BUILTIN(ArrayConcat) { ...@@ -1645,38 +1629,30 @@ BUILTIN(ArrayConcat) {
return Slow_ArrayConcat(&args, species, isolate); return Slow_ArrayConcat(&args, species, isolate);
} }
void Builtins::Generate_ArrayIsArray(compiler::CodeAssemblerState* state) { TF_BUILTIN(ArrayIsArray, CodeStubAssembler) {
typedef compiler::Node Node; Node* object = Parameter(1);
typedef CodeStubAssembler::Label Label; Node* context = Parameter(4);
CodeStubAssembler assembler(state);
Node* object = assembler.Parameter(1);
Node* context = assembler.Parameter(4);
Label call_runtime(&assembler), return_true(&assembler), Label call_runtime(this), return_true(this), return_false(this);
return_false(&assembler);
assembler.GotoIf(assembler.TaggedIsSmi(object), &return_false); GotoIf(TaggedIsSmi(object), &return_false);
Node* instance_type = assembler.LoadInstanceType(object); Node* instance_type = LoadInstanceType(object);
assembler.GotoIf(assembler.Word32Equal( GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)),
instance_type, assembler.Int32Constant(JS_ARRAY_TYPE)), &return_true);
&return_true);
// TODO(verwaest): Handle proxies in-place. // TODO(verwaest): Handle proxies in-place.
assembler.Branch(assembler.Word32Equal( Branch(Word32Equal(instance_type, Int32Constant(JS_PROXY_TYPE)),
instance_type, assembler.Int32Constant(JS_PROXY_TYPE)), &call_runtime, &return_false);
&call_runtime, &return_false);
assembler.Bind(&return_true); Bind(&return_true);
assembler.Return(assembler.BooleanConstant(true)); Return(BooleanConstant(true));
assembler.Bind(&return_false); Bind(&return_false);
assembler.Return(assembler.BooleanConstant(false)); Return(BooleanConstant(false));
assembler.Bind(&call_runtime); Bind(&call_runtime);
assembler.Return( Return(CallRuntime(Runtime::kArrayIsArray, context, object));
assembler.CallRuntime(Runtime::kArrayIsArray, context, object));
} }
TF_BUILTIN(ArrayIncludes, CodeStubAssembler) { TF_BUILTIN(ArrayIncludes, CodeStubAssembler) {
...@@ -1694,8 +1670,7 @@ TF_BUILTIN(ArrayIncludes, CodeStubAssembler) { ...@@ -1694,8 +1670,7 @@ TF_BUILTIN(ArrayIncludes, CodeStubAssembler) {
// Take slow path if not a JSArray, if retrieving elements requires // Take slow path if not a JSArray, if retrieving elements requires
// traversing prototype, or if access checks are required. // traversing prototype, or if access checks are required.
BranchIfFastJSArray(array, context, BranchIfFastJSArray(array, context, FastJSArrayAccessMode::INBOUNDS_READ,
CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ,
&init_len, &call_runtime); &init_len, &call_runtime);
Bind(&init_len); Bind(&init_len);
...@@ -1917,7 +1892,7 @@ TF_BUILTIN(ArrayIncludes, CodeStubAssembler) { ...@@ -1917,7 +1892,7 @@ TF_BUILTIN(ArrayIncludes, CodeStubAssembler) {
// Load double value or continue if it contains a double hole. // Load double value or continue if it contains a double hole.
Node* element_k = LoadFixedDoubleArrayElement( Node* element_k = LoadFixedDoubleArrayElement(
elements, index_var.value(), MachineType::Float64(), 0, elements, index_var.value(), MachineType::Float64(), 0,
CodeStubAssembler::INTPTR_PARAMETERS, &continue_loop); INTPTR_PARAMETERS, &continue_loop);
Branch(Float64Equal(element_k, search_num.value()), &return_true, Branch(Float64Equal(element_k, search_num.value()), &return_true,
&continue_loop); &continue_loop);
...@@ -1935,7 +1910,7 @@ TF_BUILTIN(ArrayIncludes, CodeStubAssembler) { ...@@ -1935,7 +1910,7 @@ TF_BUILTIN(ArrayIncludes, CodeStubAssembler) {
// Load double value or continue if it contains a double hole. // Load double value or continue if it contains a double hole.
Node* element_k = LoadFixedDoubleArrayElement( Node* element_k = LoadFixedDoubleArrayElement(
elements, index_var.value(), MachineType::Float64(), 0, elements, index_var.value(), MachineType::Float64(), 0,
CodeStubAssembler::INTPTR_PARAMETERS, &continue_loop); INTPTR_PARAMETERS, &continue_loop);
BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop);
Bind(&continue_loop); Bind(&continue_loop);
...@@ -1949,9 +1924,9 @@ TF_BUILTIN(ArrayIncludes, CodeStubAssembler) { ...@@ -1949,9 +1924,9 @@ TF_BUILTIN(ArrayIncludes, CodeStubAssembler) {
GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false); GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false);
// Check if the element is a double hole, but don't load it. // Check if the element is a double hole, but don't load it.
LoadFixedDoubleArrayElement( LoadFixedDoubleArrayElement(elements, index_var.value(),
elements, index_var.value(), MachineType::None(), 0, MachineType::None(), 0, INTPTR_PARAMETERS,
CodeStubAssembler::INTPTR_PARAMETERS, &return_true); &return_true);
index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1))); index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
Goto(&hole_loop); Goto(&hole_loop);
...@@ -1969,116 +1944,100 @@ TF_BUILTIN(ArrayIncludes, CodeStubAssembler) { ...@@ -1969,116 +1944,100 @@ TF_BUILTIN(ArrayIncludes, CodeStubAssembler) {
search_element, start_from)); search_element, start_from));
} }
void Builtins::Generate_ArrayIndexOf(compiler::CodeAssemblerState* state) { TF_BUILTIN(ArrayIndexOf, CodeStubAssembler) {
typedef compiler::Node Node; Node* array = Parameter(0);
typedef CodeStubAssembler::Label Label; Node* search_element = Parameter(1);
typedef CodeStubAssembler::Variable Variable; Node* start_from = Parameter(2);
CodeStubAssembler assembler(state); Node* 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);
Node* intptr_zero = assembler.IntPtrConstant(0);
Node* intptr_one = assembler.IntPtrConstant(1);
Node* undefined = assembler.UndefinedConstant(); Node* intptr_zero = IntPtrConstant(0);
Node* intptr_one = IntPtrConstant(1);
Variable len_var(&assembler, MachineType::PointerRepresentation()), Variable len_var(this, MachineType::PointerRepresentation()),
index_var(&assembler, MachineType::PointerRepresentation()), index_var(this, MachineType::PointerRepresentation()),
start_from_var(&assembler, MachineType::PointerRepresentation()); start_from_var(this, MachineType::PointerRepresentation());
Label init_k(&assembler), return_found(&assembler), Label init_k(this), return_found(this), return_not_found(this),
return_not_found(&assembler), call_runtime(&assembler); call_runtime(this);
Label init_len(&assembler); Label init_len(this);
index_var.Bind(intptr_zero); index_var.Bind(intptr_zero);
len_var.Bind(intptr_zero); len_var.Bind(intptr_zero);
// Take slow path if not a JSArray, if retrieving elements requires // Take slow path if not a JSArray, if retrieving elements requires
// traversing prototype, or if access checks are required. // traversing prototype, or if access checks are required.
assembler.BranchIfFastJSArray( BranchIfFastJSArray(array, context, FastJSArrayAccessMode::INBOUNDS_READ,
array, context, CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, &init_len, &call_runtime);
&init_len, &call_runtime);
assembler.Bind(&init_len); Bind(&init_len);
{ {
// JSArray length is always an Smi for fast arrays. // JSArray length is always an Smi for fast arrays.
CSA_ASSERT(&assembler, assembler.TaggedIsSmi(assembler.LoadObjectField( CSA_ASSERT(this,
array, JSArray::kLengthOffset))); TaggedIsSmi(LoadObjectField(array, JSArray::kLengthOffset)));
Node* len = Node* len = LoadAndUntagObjectField(array, JSArray::kLengthOffset);
assembler.LoadAndUntagObjectField(array, JSArray::kLengthOffset);
len_var.Bind(len); len_var.Bind(len);
assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), Branch(WordEqual(len_var.value(), intptr_zero), &return_not_found, &init_k);
&return_not_found, &init_k);
} }
assembler.Bind(&init_k); Bind(&init_k);
{ {
Label done(&assembler), init_k_smi(&assembler), init_k_heap_num(&assembler), Label done(this), init_k_smi(this), init_k_heap_num(this),
init_k_zero(&assembler), init_k_n(&assembler); init_k_zero(this), init_k_n(this);
Node* tagged_n = assembler.ToInteger(context, start_from); Node* tagged_n = ToInteger(context, start_from);
assembler.Branch(assembler.TaggedIsSmi(tagged_n), &init_k_smi, Branch(TaggedIsSmi(tagged_n), &init_k_smi, &init_k_heap_num);
&init_k_heap_num);
assembler.Bind(&init_k_smi); Bind(&init_k_smi);
{ {
start_from_var.Bind(assembler.SmiUntag(tagged_n)); start_from_var.Bind(SmiUntag(tagged_n));
assembler.Goto(&init_k_n); Goto(&init_k_n);
} }
assembler.Bind(&init_k_heap_num); Bind(&init_k_heap_num);
{ {
Label do_return_not_found(&assembler); Label do_return_not_found(this);
// This round is lossless for all valid lengths. // This round is lossless for all valid lengths.
Node* fp_len = assembler.RoundIntPtrToFloat64(len_var.value()); Node* fp_len = RoundIntPtrToFloat64(len_var.value());
Node* fp_n = assembler.LoadHeapNumberValue(tagged_n); Node* fp_n = LoadHeapNumberValue(tagged_n);
assembler.GotoIf(assembler.Float64GreaterThanOrEqual(fp_n, fp_len), GotoIf(Float64GreaterThanOrEqual(fp_n, fp_len), &do_return_not_found);
&do_return_not_found); start_from_var.Bind(ChangeInt32ToIntPtr(TruncateFloat64ToWord32(fp_n)));
start_from_var.Bind(assembler.ChangeInt32ToIntPtr( Goto(&init_k_n);
assembler.TruncateFloat64ToWord32(fp_n)));
assembler.Goto(&init_k_n); Bind(&do_return_not_found);
assembler.Bind(&do_return_not_found);
{ {
index_var.Bind(intptr_zero); index_var.Bind(intptr_zero);
assembler.Goto(&return_not_found); Goto(&return_not_found);
} }
} }
assembler.Bind(&init_k_n); Bind(&init_k_n);
{ {
Label if_positive(&assembler), if_negative(&assembler), done(&assembler); Label if_positive(this), if_negative(this), done(this);
assembler.Branch( Branch(IntPtrLessThan(start_from_var.value(), intptr_zero), &if_negative,
assembler.IntPtrLessThan(start_from_var.value(), intptr_zero), &if_positive);
&if_negative, &if_positive);
assembler.Bind(&if_positive); Bind(&if_positive);
{ {
index_var.Bind(start_from_var.value()); index_var.Bind(start_from_var.value());
assembler.Goto(&done); Goto(&done);
} }
assembler.Bind(&if_negative); Bind(&if_negative);
{ {
index_var.Bind( index_var.Bind(IntPtrAdd(len_var.value(), start_from_var.value()));
assembler.IntPtrAdd(len_var.value(), start_from_var.value())); Branch(IntPtrLessThan(index_var.value(), intptr_zero), &init_k_zero,
assembler.Branch( &done);
assembler.IntPtrLessThan(index_var.value(), intptr_zero),
&init_k_zero, &done);
} }
assembler.Bind(&init_k_zero); Bind(&init_k_zero);
{ {
index_var.Bind(intptr_zero); index_var.Bind(intptr_zero);
assembler.Goto(&done); Goto(&done);
} }
assembler.Bind(&done); Bind(&done);
} }
} }
...@@ -2087,357 +2046,291 @@ void Builtins::Generate_ArrayIndexOf(compiler::CodeAssemblerState* state) { ...@@ -2087,357 +2046,291 @@ void Builtins::Generate_ArrayIndexOf(compiler::CodeAssemblerState* state) {
FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS,
}; };
Label if_smiorobjects(&assembler), if_packed_doubles(&assembler), Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this);
if_holey_doubles(&assembler);
Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects, Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects,
&if_smiorobjects, &if_smiorobjects, &if_smiorobjects, &if_smiorobjects,
&if_packed_doubles, &if_holey_doubles}; &if_packed_doubles, &if_holey_doubles};
Node* map = assembler.LoadMap(array); Node* map = LoadMap(array);
Node* elements_kind = assembler.LoadMapElementsKind(map); Node* elements_kind = LoadMapElementsKind(map);
Node* elements = assembler.LoadElements(array); Node* elements = LoadElements(array);
assembler.Switch(elements_kind, &return_not_found, kElementsKind, Switch(elements_kind, &return_not_found, kElementsKind, element_kind_handlers,
element_kind_handlers, arraysize(kElementsKind)); arraysize(kElementsKind));
assembler.Bind(&if_smiorobjects); Bind(&if_smiorobjects);
{ {
Variable search_num(&assembler, MachineRepresentation::kFloat64); Variable search_num(this, MachineRepresentation::kFloat64);
Label ident_loop(&assembler, &index_var), Label ident_loop(this, &index_var), heap_num_loop(this, &search_num),
heap_num_loop(&assembler, &search_num), string_loop(this, &index_var), not_smi(this), not_heap_num(this);
string_loop(&assembler, &index_var), undef_loop(&assembler, &index_var),
not_smi(&assembler), not_heap_num(&assembler);
assembler.GotoIfNot(assembler.TaggedIsSmi(search_element), &not_smi);
search_num.Bind(assembler.SmiToFloat64(search_element));
assembler.Goto(&heap_num_loop);
assembler.Bind(&not_smi);
assembler.GotoIf(assembler.WordEqual(search_element, undefined),
&undef_loop);
Node* map = assembler.LoadMap(search_element);
assembler.GotoIfNot(assembler.IsHeapNumberMap(map), &not_heap_num);
search_num.Bind(assembler.LoadHeapNumberValue(search_element));
assembler.Goto(&heap_num_loop);
assembler.Bind(&not_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.GotoIfNot(
assembler.UintPtrLessThan(index_var.value(), len_var.value()),
&return_not_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);
}
assembler.Bind(&undef_loop); GotoIfNot(TaggedIsSmi(search_element), &not_smi);
search_num.Bind(SmiToFloat64(search_element));
Goto(&heap_num_loop);
Bind(&not_smi);
Node* map = LoadMap(search_element);
GotoIfNot(IsHeapNumberMap(map), &not_heap_num);
search_num.Bind(LoadHeapNumberValue(search_element));
Goto(&heap_num_loop);
Bind(&not_heap_num);
Node* search_type = LoadMapInstanceType(map);
GotoIf(IsStringInstanceType(search_type), &string_loop);
Goto(&ident_loop);
Bind(&ident_loop);
{ {
assembler.GotoIfNot( GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
assembler.UintPtrLessThan(index_var.value(), len_var.value()), &return_not_found);
&return_not_found); Node* element_k = LoadFixedArrayElement(elements, index_var.value());
Node* element_k = GotoIf(WordEqual(element_k, search_element), &return_found);
assembler.LoadFixedArrayElement(elements, index_var.value());
assembler.GotoIf(assembler.WordEqual(element_k, undefined), index_var.Bind(IntPtrAdd(index_var.value(), intptr_one));
&return_found); Goto(&ident_loop);
index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one));
assembler.Goto(&undef_loop);
} }
assembler.Bind(&heap_num_loop); Bind(&heap_num_loop);
{ {
Label not_nan_loop(&assembler, &index_var); Label not_nan_loop(this, &index_var);
assembler.BranchIfFloat64IsNaN(search_num.value(), &return_not_found, BranchIfFloat64IsNaN(search_num.value(), &return_not_found,
&not_nan_loop); &not_nan_loop);
assembler.Bind(&not_nan_loop); Bind(&not_nan_loop);
{ {
Label continue_loop(&assembler), not_smi(&assembler); Label continue_loop(this), not_smi(this);
assembler.GotoIfNot( GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
assembler.UintPtrLessThan(index_var.value(), len_var.value()), &return_not_found);
&return_not_found); Node* element_k = LoadFixedArrayElement(elements, index_var.value());
Node* element_k = GotoIfNot(TaggedIsSmi(element_k), &not_smi);
assembler.LoadFixedArrayElement(elements, index_var.value()); Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)),
assembler.GotoIfNot(assembler.TaggedIsSmi(element_k), &not_smi); &return_found, &continue_loop);
assembler.Branch(
assembler.Float64Equal(search_num.value(), Bind(&not_smi);
assembler.SmiToFloat64(element_k)), GotoIfNot(IsHeapNumber(element_k), &continue_loop);
&return_found, &continue_loop); Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)),
&return_found, &continue_loop);
assembler.Bind(&not_smi);
assembler.GotoIfNot( Bind(&continue_loop);
assembler.IsHeapNumberMap(assembler.LoadMap(element_k)), index_var.Bind(IntPtrAdd(index_var.value(), intptr_one));
&continue_loop); Goto(&not_nan_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(&not_nan_loop);
} }
} }
assembler.Bind(&string_loop); Bind(&string_loop);
{ {
Label continue_loop(&assembler); Label continue_loop(this);
assembler.GotoIfNot( GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
assembler.UintPtrLessThan(index_var.value(), len_var.value()), &return_not_found);
&return_not_found); Node* element_k = LoadFixedArrayElement(elements, index_var.value());
Node* element_k = GotoIf(TaggedIsSmi(element_k), &continue_loop);
assembler.LoadFixedArrayElement(elements, index_var.value()); GotoIfNot(IsString(element_k), &continue_loop);
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. // TODO(bmeurer): Consider inlining the StringEqual logic here.
Callable callable = CodeFactory::StringEqual(assembler.isolate()); Callable callable = CodeFactory::StringEqual(isolate());
Node* result = Node* result = CallStub(callable, context, search_element, element_k);
assembler.CallStub(callable, context, search_element, element_k); Branch(WordEqual(BooleanConstant(true), result), &return_found,
assembler.Branch( &continue_loop);
assembler.WordEqual(assembler.BooleanConstant(true), result),
&return_found, &continue_loop); Bind(&continue_loop);
index_var.Bind(IntPtrAdd(index_var.value(), intptr_one));
assembler.Bind(&continue_loop); Goto(&string_loop);
index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one));
assembler.Goto(&string_loop);
} }
} }
assembler.Bind(&if_packed_doubles); Bind(&if_packed_doubles);
{ {
Label not_nan_loop(&assembler, &index_var), search_notnan(&assembler); Label not_nan_loop(this, &index_var), search_notnan(this);
Variable search_num(&assembler, MachineRepresentation::kFloat64); Variable search_num(this, MachineRepresentation::kFloat64);
assembler.GotoIfNot(assembler.TaggedIsSmi(search_element), &search_notnan); GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
search_num.Bind(assembler.SmiToFloat64(search_element)); search_num.Bind(SmiToFloat64(search_element));
assembler.Goto(&not_nan_loop); Goto(&not_nan_loop);
assembler.Bind(&search_notnan); Bind(&search_notnan);
assembler.GotoIfNot( GotoIfNot(IsHeapNumber(search_element), &return_not_found);
assembler.IsHeapNumberMap(assembler.LoadMap(search_element)),
&return_not_found);
search_num.Bind(assembler.LoadHeapNumberValue(search_element)); search_num.Bind(LoadHeapNumberValue(search_element));
assembler.BranchIfFloat64IsNaN(search_num.value(), &return_not_found, BranchIfFloat64IsNaN(search_num.value(), &return_not_found, &not_nan_loop);
&not_nan_loop);
// Search for HeapNumber // Search for HeapNumber
assembler.Bind(&not_nan_loop); Bind(&not_nan_loop);
{ {
Label continue_loop(&assembler); GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
assembler.GotoIfNot( &return_not_found);
assembler.UintPtrLessThan(index_var.value(), len_var.value()), Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
&return_not_found); MachineType::Float64());
Node* element_k = assembler.LoadFixedDoubleArrayElement( GotoIf(Float64Equal(element_k, search_num.value()), &return_found);
elements, index_var.value(), MachineType::Float64());
assembler.Branch(assembler.Float64Equal(element_k, search_num.value()), index_var.Bind(IntPtrAdd(index_var.value(), intptr_one));
&return_found, &continue_loop); Goto(&not_nan_loop);
assembler.Bind(&continue_loop);
index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one));
assembler.Goto(&not_nan_loop);
} }
} }
assembler.Bind(&if_holey_doubles); Bind(&if_holey_doubles);
{ {
Label not_nan_loop(&assembler, &index_var), search_notnan(&assembler); Label not_nan_loop(this, &index_var), search_notnan(this);
Variable search_num(&assembler, MachineRepresentation::kFloat64); Variable search_num(this, MachineRepresentation::kFloat64);
assembler.GotoIfNot(assembler.TaggedIsSmi(search_element), &search_notnan); GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
search_num.Bind(assembler.SmiToFloat64(search_element)); search_num.Bind(SmiToFloat64(search_element));
assembler.Goto(&not_nan_loop); Goto(&not_nan_loop);
assembler.Bind(&search_notnan); Bind(&search_notnan);
assembler.GotoIfNot( GotoIfNot(IsHeapNumber(search_element), &return_not_found);
assembler.IsHeapNumberMap(assembler.LoadMap(search_element)),
&return_not_found);
search_num.Bind(assembler.LoadHeapNumberValue(search_element)); search_num.Bind(LoadHeapNumberValue(search_element));
assembler.BranchIfFloat64IsNaN(search_num.value(), &return_not_found, BranchIfFloat64IsNaN(search_num.value(), &return_not_found, &not_nan_loop);
&not_nan_loop);
// Search for HeapNumber // Search for HeapNumber
assembler.Bind(&not_nan_loop); Bind(&not_nan_loop);
{ {
Label continue_loop(&assembler); Label continue_loop(this);
assembler.GotoIfNot( GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
assembler.UintPtrLessThan(index_var.value(), len_var.value()), &return_not_found);
&return_not_found);
// Load double value or continue if it contains a double hole. // 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, elements, index_var.value(), MachineType::Float64(), 0,
CodeStubAssembler::INTPTR_PARAMETERS, &continue_loop); INTPTR_PARAMETERS, &continue_loop);
assembler.Branch(assembler.Float64Equal(element_k, search_num.value()), Branch(Float64Equal(element_k, search_num.value()), &return_found,
&return_found, &continue_loop); &continue_loop);
assembler.Bind(&continue_loop); Bind(&continue_loop);
index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one)); index_var.Bind(IntPtrAdd(index_var.value(), intptr_one));
assembler.Goto(&not_nan_loop); Goto(&not_nan_loop);
} }
} }
assembler.Bind(&return_found); Bind(&return_found);
assembler.Return(assembler.SmiTag(index_var.value())); Return(SmiTag(index_var.value()));
assembler.Bind(&return_not_found); Bind(&return_not_found);
assembler.Return(assembler.NumberConstant(-1)); Return(NumberConstant(-1));
assembler.Bind(&call_runtime); Bind(&call_runtime);
assembler.Return(assembler.CallRuntime(Runtime::kArrayIndexOf, context, array, Return(CallRuntime(Runtime::kArrayIndexOf, context, array, search_element,
search_element, start_from)); start_from));
} }
namespace { class ArrayPrototypeIterationAssembler : public CodeStubAssembler {
public:
template <IterationKind kIterationKind> explicit ArrayPrototypeIterationAssembler(compiler::CodeAssemblerState* state)
void Generate_ArrayPrototypeIterationMethod( : CodeStubAssembler(state) {}
compiler::CodeAssemblerState* state) {
typedef compiler::Node Node;
typedef CodeStubAssembler::Label Label;
typedef CodeStubAssembler::Variable Variable;
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(0); protected:
Node* context = assembler.Parameter(3); void Generate_ArrayPrototypeIterationMethod(IterationKind iteration_kind) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Variable var_array(&assembler, MachineRepresentation::kTagged); Variable var_array(this, MachineRepresentation::kTagged);
Variable var_map(&assembler, MachineRepresentation::kTagged); Variable var_map(this, MachineRepresentation::kTagged);
Variable var_type(&assembler, MachineRepresentation::kWord32); Variable var_type(this, MachineRepresentation::kWord32);
Label if_isnotobject(&assembler, Label::kDeferred); Label if_isnotobject(this, Label::kDeferred);
Label create_array_iterator(&assembler); Label create_array_iterator(this);
assembler.GotoIf(assembler.TaggedIsSmi(receiver), &if_isnotobject); GotoIf(TaggedIsSmi(receiver), &if_isnotobject);
var_array.Bind(receiver); var_array.Bind(receiver);
var_map.Bind(assembler.LoadMap(receiver)); var_map.Bind(LoadMap(receiver));
var_type.Bind(assembler.LoadMapInstanceType(var_map.value())); var_type.Bind(LoadMapInstanceType(var_map.value()));
assembler.Branch(assembler.IsJSReceiverInstanceType(var_type.value()), Branch(IsJSReceiverInstanceType(var_type.value()), &create_array_iterator,
&create_array_iterator, &if_isnotobject); &if_isnotobject);
assembler.Bind(&if_isnotobject); Bind(&if_isnotobject);
{ {
Callable callable = CodeFactory::ToObject(assembler.isolate()); Callable callable = CodeFactory::ToObject(isolate());
Node* result = assembler.CallStub(callable, context, receiver); Node* result = CallStub(callable, context, receiver);
var_array.Bind(result); var_array.Bind(result);
var_map.Bind(assembler.LoadMap(result)); var_map.Bind(LoadMap(result));
var_type.Bind(assembler.LoadMapInstanceType(var_map.value())); var_type.Bind(LoadMapInstanceType(var_map.value()));
assembler.Goto(&create_array_iterator); Goto(&create_array_iterator);
} }
assembler.Bind(&create_array_iterator);
assembler.Return(
assembler.CreateArrayIterator(var_array.value(), var_map.value(),
var_type.value(), context, kIterationKind));
}
} // namespace Bind(&create_array_iterator);
Return(CreateArrayIterator(var_array.value(), var_map.value(),
var_type.value(), context, iteration_kind));
}
};
void Builtins::Generate_ArrayPrototypeValues( TF_BUILTIN(ArrayPrototypeValues, ArrayPrototypeIterationAssembler) {
compiler::CodeAssemblerState* state) { Generate_ArrayPrototypeIterationMethod(IterationKind::kValues);
Generate_ArrayPrototypeIterationMethod<IterationKind::kValues>(state);
} }
void Builtins::Generate_ArrayPrototypeEntries( TF_BUILTIN(ArrayPrototypeEntries, ArrayPrototypeIterationAssembler) {
compiler::CodeAssemblerState* state) { Generate_ArrayPrototypeIterationMethod(IterationKind::kEntries);
Generate_ArrayPrototypeIterationMethod<IterationKind::kEntries>(state);
} }
void Builtins::Generate_ArrayPrototypeKeys( TF_BUILTIN(ArrayPrototypeKeys, ArrayPrototypeIterationAssembler) {
compiler::CodeAssemblerState* state) { Generate_ArrayPrototypeIterationMethod(IterationKind::kKeys);
Generate_ArrayPrototypeIterationMethod<IterationKind::kKeys>(state);
} }
void Builtins::Generate_ArrayIteratorPrototypeNext( TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
compiler::CodeAssemblerState* state) { Handle<String> operation = factory()->NewStringFromAsciiChecked(
typedef compiler::Node Node;
typedef CodeStubAssembler::Label Label;
typedef CodeStubAssembler::Variable Variable;
CodeStubAssembler assembler(state);
Handle<String> operation = assembler.factory()->NewStringFromAsciiChecked(
"Array Iterator.prototype.next", TENURED); "Array Iterator.prototype.next", TENURED);
Node* iterator = assembler.Parameter(0); Node* iterator = Parameter(0);
Node* context = assembler.Parameter(3); Node* context = Parameter(3);
Variable var_value(&assembler, MachineRepresentation::kTagged); Variable var_value(this, MachineRepresentation::kTagged);
Variable var_done(&assembler, MachineRepresentation::kTagged); Variable var_done(this, MachineRepresentation::kTagged);
// Required, or else `throw_bad_receiver` fails a DCHECK due to these // Required, or else `throw_bad_receiver` fails a DCHECK due to these
// variables not being bound along all paths, despite not being used. // variables not being bound along all paths, despite not being used.
var_done.Bind(assembler.TrueConstant()); var_done.Bind(TrueConstant());
var_value.Bind(assembler.UndefinedConstant()); var_value.Bind(UndefinedConstant());
Label throw_bad_receiver(&assembler, Label::kDeferred); Label throw_bad_receiver(this, Label::kDeferred);
Label set_done(&assembler); Label set_done(this);
Label allocate_key_result(&assembler); Label allocate_key_result(this);
Label allocate_entry_if_needed(&assembler); Label allocate_entry_if_needed(this);
Label allocate_iterator_result(&assembler); Label allocate_iterator_result(this);
Label generic_values(&assembler); Label generic_values(this);
// If O does not have all of the internal slots of an Array Iterator Instance // If O does not have all of the internal slots of an Array Iterator Instance
// (22.1.5.3), throw a TypeError exception // (22.1.5.3), throw a TypeError exception
assembler.GotoIf(assembler.TaggedIsSmi(iterator), &throw_bad_receiver); GotoIf(TaggedIsSmi(iterator), &throw_bad_receiver);
Node* instance_type = assembler.LoadInstanceType(iterator); Node* instance_type = LoadInstanceType(iterator);
assembler.GotoIf( GotoIf(
assembler.Uint32LessThan( Uint32LessThan(
assembler.Int32Constant(LAST_ARRAY_ITERATOR_TYPE - Int32Constant(LAST_ARRAY_ITERATOR_TYPE - FIRST_ARRAY_ITERATOR_TYPE),
FIRST_ARRAY_ITERATOR_TYPE), Int32Sub(instance_type, Int32Constant(FIRST_ARRAY_ITERATOR_TYPE))),
assembler.Int32Sub(instance_type, assembler.Int32Constant(
FIRST_ARRAY_ITERATOR_TYPE))),
&throw_bad_receiver); &throw_bad_receiver);
// Let a be O.[[IteratedObject]]. // Let a be O.[[IteratedObject]].
Node* array = assembler.LoadObjectField( Node* array =
iterator, JSArrayIterator::kIteratedObjectOffset); LoadObjectField(iterator, JSArrayIterator::kIteratedObjectOffset);
// Let index be O.[[ArrayIteratorNextIndex]]. // Let index be O.[[ArrayIteratorNextIndex]].
Node* index = Node* index = LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset);
assembler.LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset); Node* orig_map =
Node* orig_map = assembler.LoadObjectField( LoadObjectField(iterator, JSArrayIterator::kIteratedObjectMapOffset);
iterator, JSArrayIterator::kIteratedObjectMapOffset); Node* array_map = LoadMap(array);
Node* array_map = assembler.LoadMap(array);
Label if_isfastarray(&assembler), if_isnotfastarray(&assembler), Label if_isfastarray(this), if_isnotfastarray(this),
if_isdetached(&assembler, Label::kDeferred); if_isdetached(this, Label::kDeferred);
assembler.Branch(assembler.WordEqual(orig_map, array_map), &if_isfastarray, Branch(WordEqual(orig_map, array_map), &if_isfastarray, &if_isnotfastarray);
&if_isnotfastarray);
assembler.Bind(&if_isfastarray); Bind(&if_isfastarray);
{ {
CSA_ASSERT(&assembler, CSA_ASSERT(this, Word32Equal(LoadMapInstanceType(array_map),
assembler.Word32Equal(assembler.LoadMapInstanceType(array_map), Int32Constant(JS_ARRAY_TYPE)));
assembler.Int32Constant(JS_ARRAY_TYPE)));
Node* length = assembler.LoadObjectField(array, JSArray::kLengthOffset); Node* length = LoadObjectField(array, JSArray::kLengthOffset);
CSA_ASSERT(&assembler, assembler.TaggedIsSmi(length)); CSA_ASSERT(this, TaggedIsSmi(length));
CSA_ASSERT(&assembler, assembler.TaggedIsSmi(index)); CSA_ASSERT(this, TaggedIsSmi(index));
assembler.GotoIfNot(assembler.SmiBelow(index, length), &set_done); GotoIfNot(SmiBelow(index, length), &set_done);
Node* one = assembler.SmiConstant(Smi::FromInt(1)); Node* one = SmiConstant(Smi::FromInt(1));
assembler.StoreObjectFieldNoWriteBarrier(iterator, StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset,
JSArrayIterator::kNextIndexOffset, SmiAdd(index, one));
assembler.SmiAdd(index, one));
var_done.Bind(assembler.FalseConstant()); var_done.Bind(FalseConstant());
Node* elements = assembler.LoadElements(array); Node* elements = LoadElements(array);
static int32_t kInstanceType[] = { static int32_t kInstanceType[] = {
JS_FAST_ARRAY_KEY_ITERATOR_TYPE, JS_FAST_ARRAY_KEY_ITERATOR_TYPE,
...@@ -2455,8 +2348,8 @@ void Builtins::Generate_ArrayIteratorPrototypeNext( ...@@ -2455,8 +2348,8 @@ void Builtins::Generate_ArrayIteratorPrototypeNext(
JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE, JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE,
}; };
Label packed_object_values(&assembler), holey_object_values(&assembler), Label packed_object_values(this), holey_object_values(this),
packed_double_values(&assembler), holey_double_values(&assembler); packed_double_values(this), holey_double_values(this);
Label* kInstanceTypeHandlers[] = { Label* kInstanceTypeHandlers[] = {
&allocate_key_result, &packed_object_values, &holey_object_values, &allocate_key_result, &packed_object_values, &holey_object_values,
&packed_object_values, &holey_object_values, &packed_double_values, &packed_object_values, &holey_object_values, &packed_double_values,
...@@ -2464,192 +2357,164 @@ void Builtins::Generate_ArrayIteratorPrototypeNext( ...@@ -2464,192 +2357,164 @@ void Builtins::Generate_ArrayIteratorPrototypeNext(
&packed_object_values, &holey_object_values, &packed_double_values, &packed_object_values, &holey_object_values, &packed_double_values,
&holey_double_values}; &holey_double_values};
assembler.Switch(instance_type, &throw_bad_receiver, kInstanceType, Switch(instance_type, &throw_bad_receiver, kInstanceType,
kInstanceTypeHandlers, arraysize(kInstanceType)); kInstanceTypeHandlers, arraysize(kInstanceType));
assembler.Bind(&packed_object_values); Bind(&packed_object_values);
{ {
var_value.Bind(assembler.LoadFixedArrayElement( var_value.Bind(LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS));
elements, index, 0, CodeStubAssembler::SMI_PARAMETERS)); Goto(&allocate_entry_if_needed);
assembler.Goto(&allocate_entry_if_needed);
} }
assembler.Bind(&packed_double_values); Bind(&packed_double_values);
{ {
Node* value = assembler.LoadFixedDoubleArrayElement( Node* value = LoadFixedDoubleArrayElement(
elements, index, MachineType::Float64(), 0, elements, index, MachineType::Float64(), 0, SMI_PARAMETERS);
CodeStubAssembler::SMI_PARAMETERS); var_value.Bind(AllocateHeapNumberWithValue(value));
var_value.Bind(assembler.AllocateHeapNumberWithValue(value)); Goto(&allocate_entry_if_needed);
assembler.Goto(&allocate_entry_if_needed);
} }
assembler.Bind(&holey_object_values); Bind(&holey_object_values);
{ {
// Check the array_protector cell, and take the slow path if it's invalid. // Check the array_protector cell, and take the slow path if it's invalid.
Node* invalid = Node* invalid = SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid));
assembler.SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); Node* cell = LoadRoot(Heap::kArrayProtectorRootIndex);
Node* cell = assembler.LoadRoot(Heap::kArrayProtectorRootIndex); Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
Node* cell_value = GotoIf(WordEqual(cell_value, invalid), &generic_values);
assembler.LoadObjectField(cell, PropertyCell::kValueOffset);
assembler.GotoIf(assembler.WordEqual(cell_value, invalid), var_value.Bind(UndefinedConstant());
&generic_values); Node* value = LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS);
GotoIf(WordEqual(value, TheHoleConstant()), &allocate_entry_if_needed);
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);
var_value.Bind(value); var_value.Bind(value);
assembler.Goto(&allocate_entry_if_needed); Goto(&allocate_entry_if_needed);
} }
assembler.Bind(&holey_double_values); Bind(&holey_double_values);
{ {
// Check the array_protector cell, and take the slow path if it's invalid. // Check the array_protector cell, and take the slow path if it's invalid.
Node* invalid = Node* invalid = SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid));
assembler.SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); Node* cell = LoadRoot(Heap::kArrayProtectorRootIndex);
Node* cell = assembler.LoadRoot(Heap::kArrayProtectorRootIndex); Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
Node* cell_value = GotoIf(WordEqual(cell_value, invalid), &generic_values);
assembler.LoadObjectField(cell, PropertyCell::kValueOffset);
assembler.GotoIf(assembler.WordEqual(cell_value, invalid), var_value.Bind(UndefinedConstant());
&generic_values); Node* value = LoadFixedDoubleArrayElement(
elements, index, MachineType::Float64(), 0, SMI_PARAMETERS,
var_value.Bind(assembler.UndefinedConstant()); &allocate_entry_if_needed);
Node* value = assembler.LoadFixedDoubleArrayElement( var_value.Bind(AllocateHeapNumberWithValue(value));
elements, index, MachineType::Float64(), 0, Goto(&allocate_entry_if_needed);
CodeStubAssembler::SMI_PARAMETERS, &allocate_entry_if_needed);
var_value.Bind(assembler.AllocateHeapNumberWithValue(value));
assembler.Goto(&allocate_entry_if_needed);
} }
} }
assembler.Bind(&if_isnotfastarray); Bind(&if_isnotfastarray);
{ {
Label if_istypedarray(&assembler), if_isgeneric(&assembler); Label if_istypedarray(this), if_isgeneric(this);
// If a is undefined, return CreateIterResultObject(undefined, true) // If a is undefined, return CreateIterResultObject(undefined, true)
assembler.GotoIf(assembler.WordEqual(array, assembler.UndefinedConstant()), GotoIf(WordEqual(array, UndefinedConstant()), &allocate_iterator_result);
&allocate_iterator_result);
Node* array_type = assembler.LoadInstanceType(array); Node* array_type = LoadInstanceType(array);
assembler.Branch( Branch(Word32Equal(array_type, Int32Constant(JS_TYPED_ARRAY_TYPE)),
assembler.Word32Equal(array_type, &if_istypedarray, &if_isgeneric);
assembler.Int32Constant(JS_TYPED_ARRAY_TYPE)),
&if_istypedarray, &if_isgeneric);
assembler.Bind(&if_isgeneric); Bind(&if_isgeneric);
{ {
Label if_wasfastarray(&assembler); Label if_wasfastarray(this);
Node* length = nullptr; Node* length = nullptr;
{ {
Variable var_length(&assembler, MachineRepresentation::kTagged); Variable var_length(this, MachineRepresentation::kTagged);
Label if_isarray(&assembler), if_isnotarray(&assembler), Label if_isarray(this), if_isnotarray(this), done(this);
done(&assembler); Branch(Word32Equal(array_type, Int32Constant(JS_ARRAY_TYPE)),
assembler.Branch( &if_isarray, &if_isnotarray);
assembler.Word32Equal(array_type,
assembler.Int32Constant(JS_ARRAY_TYPE)), Bind(&if_isarray);
&if_isarray, &if_isnotarray);
assembler.Bind(&if_isarray);
{ {
var_length.Bind( var_length.Bind(LoadObjectField(array, JSArray::kLengthOffset));
assembler.LoadObjectField(array, JSArray::kLengthOffset));
// Invalidate protector cell if needed // Invalidate protector cell if needed
assembler.Branch( Branch(WordNotEqual(orig_map, UndefinedConstant()), &if_wasfastarray,
assembler.WordNotEqual(orig_map, assembler.UndefinedConstant()), &done);
&if_wasfastarray, &done);
assembler.Bind(&if_wasfastarray); Bind(&if_wasfastarray);
{ {
Label if_invalid(&assembler, Label::kDeferred); Label if_invalid(this, Label::kDeferred);
// A fast array iterator transitioned to a slow iterator during // A fast array iterator transitioned to a slow iterator during
// iteration. Invalidate fast_array_iteration_prtoector cell to // iteration. Invalidate fast_array_iteration_prtoector cell to
// prevent potential deopt loops. // prevent potential deopt loops.
assembler.StoreObjectFieldNoWriteBarrier( StoreObjectFieldNoWriteBarrier(
iterator, JSArrayIterator::kIteratedObjectMapOffset, iterator, JSArrayIterator::kIteratedObjectMapOffset,
assembler.UndefinedConstant()); UndefinedConstant());
assembler.GotoIf( GotoIf(Uint32LessThanOrEqual(
assembler.Uint32LessThanOrEqual( instance_type,
instance_type, assembler.Int32Constant( Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)),
JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)), &done);
&done);
Node* invalid = Node* invalid =
assembler.SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid)); SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid));
Node* cell = Node* cell = LoadRoot(Heap::kFastArrayIterationProtectorRootIndex);
assembler.LoadRoot(Heap::kFastArrayIterationProtectorRootIndex); StoreObjectFieldNoWriteBarrier(cell, Cell::kValueOffset, invalid);
assembler.StoreObjectFieldNoWriteBarrier(cell, Cell::kValueOffset, Goto(&done);
invalid);
assembler.Goto(&done);
} }
} }
assembler.Bind(&if_isnotarray); Bind(&if_isnotarray);
{ {
Node* length_string = assembler.HeapConstant( Node* length_string = HeapConstant(factory()->length_string());
assembler.isolate()->factory()->length_string()); Callable get_property = CodeFactory::GetProperty(isolate());
Callable get_property = CodeFactory::GetProperty(assembler.isolate()); Node* length = CallStub(get_property, context, array, length_string);
Node* length = Callable to_length = CodeFactory::ToLength(isolate());
assembler.CallStub(get_property, context, array, length_string); var_length.Bind(CallStub(to_length, context, length));
Callable to_length = CodeFactory::ToLength(assembler.isolate()); Goto(&done);
var_length.Bind(assembler.CallStub(to_length, context, length));
assembler.Goto(&done);
} }
assembler.Bind(&done); Bind(&done);
length = var_length.value(); length = var_length.value();
} }
assembler.GotoUnlessNumberLessThan(index, length, &set_done); GotoUnlessNumberLessThan(index, length, &set_done);
assembler.StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset, StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset,
assembler.NumberInc(index)); NumberInc(index));
var_done.Bind(assembler.FalseConstant()); var_done.Bind(FalseConstant());
assembler.Branch( Branch(
assembler.Uint32LessThanOrEqual( Uint32LessThanOrEqual(
instance_type, instance_type, Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)),
assembler.Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)),
&allocate_key_result, &generic_values); &allocate_key_result, &generic_values);
assembler.Bind(&generic_values); Bind(&generic_values);
{ {
Callable get_property = CodeFactory::GetProperty(assembler.isolate()); Callable get_property = CodeFactory::GetProperty(isolate());
var_value.Bind(assembler.CallStub(get_property, context, array, index)); var_value.Bind(CallStub(get_property, context, array, index));
assembler.Goto(&allocate_entry_if_needed); Goto(&allocate_entry_if_needed);
} }
} }
assembler.Bind(&if_istypedarray); Bind(&if_istypedarray);
{ {
Node* buffer = Node* buffer = LoadObjectField(array, JSTypedArray::kBufferOffset);
assembler.LoadObjectField(array, JSTypedArray::kBufferOffset); GotoIf(IsDetachedBuffer(buffer), &if_isdetached);
assembler.GotoIf(assembler.IsDetachedBuffer(buffer), &if_isdetached);
Node* length = Node* length = LoadObjectField(array, JSTypedArray::kLengthOffset);
assembler.LoadObjectField(array, JSTypedArray::kLengthOffset);
CSA_ASSERT(&assembler, assembler.TaggedIsSmi(length)); CSA_ASSERT(this, TaggedIsSmi(length));
CSA_ASSERT(&assembler, assembler.TaggedIsSmi(index)); CSA_ASSERT(this, TaggedIsSmi(index));
assembler.GotoIfNot(assembler.SmiBelow(index, length), &set_done); GotoIfNot(SmiBelow(index, length), &set_done);
Node* one = assembler.SmiConstant(1); Node* one = SmiConstant(1);
assembler.StoreObjectFieldNoWriteBarrier( StoreObjectFieldNoWriteBarrier(
iterator, JSArrayIterator::kNextIndexOffset, iterator, JSArrayIterator::kNextIndexOffset, SmiAdd(index, one));
assembler.SmiAdd(index, one)); var_done.Bind(FalseConstant());
var_done.Bind(assembler.FalseConstant());
Node* elements = assembler.LoadElements(array); Node* elements = LoadElements(array);
Node* base_ptr = assembler.LoadObjectField( Node* base_ptr =
elements, FixedTypedArrayBase::kBasePointerOffset); LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
Node* external_ptr = assembler.LoadObjectField( Node* external_ptr =
elements, FixedTypedArrayBase::kExternalPointerOffset, LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
MachineType::Pointer()); MachineType::Pointer());
Node* data_ptr = assembler.IntPtrAdd( Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);
assembler.BitcastTaggedToWord(base_ptr), external_ptr);
static int32_t kInstanceType[] = { static int32_t kInstanceType[] = {
JS_TYPED_ARRAY_KEY_ITERATOR_TYPE, JS_TYPED_ARRAY_KEY_ITERATOR_TYPE,
...@@ -2673,10 +2538,9 @@ void Builtins::Generate_ArrayIteratorPrototypeNext( ...@@ -2673,10 +2538,9 @@ void Builtins::Generate_ArrayIteratorPrototypeNext(
JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE, JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE,
}; };
Label uint8_values(&assembler), int8_values(&assembler), Label uint8_values(this), int8_values(this), uint16_values(this),
uint16_values(&assembler), int16_values(&assembler), int16_values(this), uint32_values(this), int32_values(this),
uint32_values(&assembler), int32_values(&assembler), float32_values(this), float64_values(this);
float32_values(&assembler), float64_values(&assembler);
Label* kInstanceTypeHandlers[] = { Label* kInstanceTypeHandlers[] = {
&allocate_key_result, &uint8_values, &uint8_values, &allocate_key_result, &uint8_values, &uint8_values,
&int8_values, &uint16_values, &int16_values, &int8_values, &uint16_values, &int16_values,
...@@ -2687,156 +2551,140 @@ void Builtins::Generate_ArrayIteratorPrototypeNext( ...@@ -2687,156 +2551,140 @@ void Builtins::Generate_ArrayIteratorPrototypeNext(
&float64_values, &float64_values,
}; };
var_done.Bind(assembler.FalseConstant()); var_done.Bind(FalseConstant());
assembler.Switch(instance_type, &throw_bad_receiver, kInstanceType, Switch(instance_type, &throw_bad_receiver, kInstanceType,
kInstanceTypeHandlers, arraysize(kInstanceType)); kInstanceTypeHandlers, arraysize(kInstanceType));
assembler.Bind(&uint8_values); Bind(&uint8_values);
{ {
Node* value_uint8 = assembler.LoadFixedTypedArrayElement( Node* value_uint8 = LoadFixedTypedArrayElement(
data_ptr, index, UINT8_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS); data_ptr, index, UINT8_ELEMENTS, SMI_PARAMETERS);
var_value.Bind(assembler.SmiFromWord32(value_uint8)); var_value.Bind(SmiFromWord32(value_uint8));
assembler.Goto(&allocate_entry_if_needed); Goto(&allocate_entry_if_needed);
} }
Bind(&int8_values);
assembler.Bind(&int8_values);
{ {
Node* value_int8 = assembler.LoadFixedTypedArrayElement( Node* value_int8 = LoadFixedTypedArrayElement(
data_ptr, index, INT8_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS); data_ptr, index, INT8_ELEMENTS, SMI_PARAMETERS);
var_value.Bind(assembler.SmiFromWord32(value_int8)); var_value.Bind(SmiFromWord32(value_int8));
assembler.Goto(&allocate_entry_if_needed); Goto(&allocate_entry_if_needed);
} }
Bind(&uint16_values);
assembler.Bind(&uint16_values);
{ {
Node* value_uint16 = assembler.LoadFixedTypedArrayElement( Node* value_uint16 = LoadFixedTypedArrayElement(
data_ptr, index, UINT16_ELEMENTS, data_ptr, index, UINT16_ELEMENTS, SMI_PARAMETERS);
CodeStubAssembler::SMI_PARAMETERS); var_value.Bind(SmiFromWord32(value_uint16));
var_value.Bind(assembler.SmiFromWord32(value_uint16)); Goto(&allocate_entry_if_needed);
assembler.Goto(&allocate_entry_if_needed);
} }
Bind(&int16_values);
assembler.Bind(&int16_values);
{ {
Node* value_int16 = assembler.LoadFixedTypedArrayElement( Node* value_int16 = LoadFixedTypedArrayElement(
data_ptr, index, INT16_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS); data_ptr, index, INT16_ELEMENTS, SMI_PARAMETERS);
var_value.Bind(assembler.SmiFromWord32(value_int16)); var_value.Bind(SmiFromWord32(value_int16));
assembler.Goto(&allocate_entry_if_needed); Goto(&allocate_entry_if_needed);
} }
Bind(&uint32_values);
assembler.Bind(&uint32_values);
{ {
Node* value_uint32 = assembler.LoadFixedTypedArrayElement( Node* value_uint32 = LoadFixedTypedArrayElement(
data_ptr, index, UINT32_ELEMENTS, data_ptr, index, UINT32_ELEMENTS, SMI_PARAMETERS);
CodeStubAssembler::SMI_PARAMETERS); var_value.Bind(ChangeUint32ToTagged(value_uint32));
var_value.Bind(assembler.ChangeUint32ToTagged(value_uint32)); Goto(&allocate_entry_if_needed);
assembler.Goto(&allocate_entry_if_needed);
} }
assembler.Bind(&int32_values); Bind(&int32_values);
{ {
Node* value_int32 = assembler.LoadFixedTypedArrayElement( Node* value_int32 = LoadFixedTypedArrayElement(
data_ptr, index, INT32_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS); data_ptr, index, INT32_ELEMENTS, SMI_PARAMETERS);
var_value.Bind(assembler.ChangeInt32ToTagged(value_int32)); var_value.Bind(ChangeInt32ToTagged(value_int32));
assembler.Goto(&allocate_entry_if_needed); Goto(&allocate_entry_if_needed);
} }
assembler.Bind(&float32_values); Bind(&float32_values);
{ {
Node* value_float32 = assembler.LoadFixedTypedArrayElement( Node* value_float32 = LoadFixedTypedArrayElement(
data_ptr, index, FLOAT32_ELEMENTS, data_ptr, index, FLOAT32_ELEMENTS, SMI_PARAMETERS);
CodeStubAssembler::SMI_PARAMETERS); var_value.Bind(
var_value.Bind(assembler.AllocateHeapNumberWithValue( AllocateHeapNumberWithValue(ChangeFloat32ToFloat64(value_float32)));
assembler.ChangeFloat32ToFloat64(value_float32))); Goto(&allocate_entry_if_needed);
assembler.Goto(&allocate_entry_if_needed);
} }
assembler.Bind(&float64_values); Bind(&float64_values);
{ {
Node* value_float64 = assembler.LoadFixedTypedArrayElement( Node* value_float64 = LoadFixedTypedArrayElement(
data_ptr, index, FLOAT64_ELEMENTS, data_ptr, index, FLOAT64_ELEMENTS, SMI_PARAMETERS);
CodeStubAssembler::SMI_PARAMETERS); var_value.Bind(AllocateHeapNumberWithValue(value_float64));
var_value.Bind(assembler.AllocateHeapNumberWithValue(value_float64)); Goto(&allocate_entry_if_needed);
assembler.Goto(&allocate_entry_if_needed);
} }
} }
} }
assembler.Bind(&set_done); Bind(&set_done);
{ {
assembler.StoreObjectFieldNoWriteBarrier( StoreObjectFieldNoWriteBarrier(
iterator, JSArrayIterator::kIteratedObjectOffset, iterator, JSArrayIterator::kIteratedObjectOffset, UndefinedConstant());
assembler.UndefinedConstant()); Goto(&allocate_iterator_result);
assembler.Goto(&allocate_iterator_result);
} }
assembler.Bind(&allocate_key_result); Bind(&allocate_key_result);
{ {
var_value.Bind(index); var_value.Bind(index);
var_done.Bind(assembler.FalseConstant()); var_done.Bind(FalseConstant());
assembler.Goto(&allocate_iterator_result); Goto(&allocate_iterator_result);
} }
assembler.Bind(&allocate_entry_if_needed); Bind(&allocate_entry_if_needed);
{ {
assembler.GotoIf( GotoIf(Int32GreaterThan(instance_type,
assembler.Int32GreaterThan( Int32Constant(LAST_ARRAY_KEY_VALUE_ITERATOR_TYPE)),
instance_type, &allocate_iterator_result);
assembler.Int32Constant(LAST_ARRAY_KEY_VALUE_ITERATOR_TYPE)),
&allocate_iterator_result); Node* elements = AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2));
StoreFixedArrayElement(elements, 0, index, SKIP_WRITE_BARRIER);
Node* elements = assembler.AllocateFixedArray(FAST_ELEMENTS, StoreFixedArrayElement(elements, 1, var_value.value(), SKIP_WRITE_BARRIER);
assembler.IntPtrConstant(2));
assembler.StoreFixedArrayElement(elements, 0, index, SKIP_WRITE_BARRIER); Node* entry = Allocate(JSArray::kSize);
assembler.StoreFixedArrayElement(elements, 1, var_value.value(), Node* map = LoadContextElement(LoadNativeContext(context),
SKIP_WRITE_BARRIER); Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX);
Node* entry = assembler.Allocate(JSArray::kSize); StoreMapNoWriteBarrier(entry, map);
Node* map = StoreObjectFieldRoot(entry, JSArray::kPropertiesOffset,
assembler.LoadContextElement(assembler.LoadNativeContext(context), Heap::kEmptyFixedArrayRootIndex);
Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX); StoreObjectFieldNoWriteBarrier(entry, JSArray::kElementsOffset, elements);
StoreObjectFieldNoWriteBarrier(entry, JSArray::kLengthOffset,
assembler.StoreMapNoWriteBarrier(entry, map); SmiConstant(Smi::FromInt(2)));
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); var_value.Bind(entry);
assembler.Goto(&allocate_iterator_result); Goto(&allocate_iterator_result);
} }
assembler.Bind(&allocate_iterator_result); Bind(&allocate_iterator_result);
{ {
Node* result = assembler.Allocate(JSIteratorResult::kSize); Node* result = Allocate(JSIteratorResult::kSize);
Node* map = Node* map = LoadContextElement(LoadNativeContext(context),
assembler.LoadContextElement(assembler.LoadNativeContext(context), Context::ITERATOR_RESULT_MAP_INDEX);
Context::ITERATOR_RESULT_MAP_INDEX); StoreMapNoWriteBarrier(result, map);
assembler.StoreMapNoWriteBarrier(result, map); StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset,
assembler.StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset, Heap::kEmptyFixedArrayRootIndex);
Heap::kEmptyFixedArrayRootIndex); StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset,
assembler.StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset, Heap::kEmptyFixedArrayRootIndex);
Heap::kEmptyFixedArrayRootIndex); StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset,
assembler.StoreObjectFieldNoWriteBarrier( var_value.value());
result, JSIteratorResult::kValueOffset, var_value.value()); StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset,
assembler.StoreObjectFieldNoWriteBarrier( var_done.value());
result, JSIteratorResult::kDoneOffset, var_done.value()); Return(result);
assembler.Return(result); }
}
Bind(&throw_bad_receiver);
assembler.Bind(&throw_bad_receiver);
{ {
// The {receiver} is not a valid JSArrayIterator. // The {receiver} is not a valid JSArrayIterator.
assembler.CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
assembler.HeapConstant(operation), iterator); HeapConstant(operation), iterator);
assembler.Unreachable(); Unreachable();
} }
assembler.Bind(&if_isdetached); Bind(&if_isdetached);
{ {
Node* message = assembler.SmiConstant(MessageTemplate::kDetachedOperation); Node* message = SmiConstant(MessageTemplate::kDetachedOperation);
assembler.CallRuntime(Runtime::kThrowTypeError, context, message, CallRuntime(Runtime::kThrowTypeError, context, message,
assembler.HeapConstant(operation)); HeapConstant(operation));
assembler.Unreachable(); Unreachable();
} }
} }
......
...@@ -11,6 +11,17 @@ ...@@ -11,6 +11,17 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class ConversionBuiltinsAssembler : public CodeStubAssembler {
public:
explicit ConversionBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void Generate_NonPrimitiveToPrimitive(ToPrimitiveHint hint);
void Generate_OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint);
};
Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) { Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) {
switch (hint) { switch (hint) {
case ToPrimitiveHint::kDefault: case ToPrimitiveHint::kDefault:
...@@ -24,192 +35,140 @@ Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) { ...@@ -24,192 +35,140 @@ Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) {
return Handle<Code>::null(); return Handle<Code>::null();
} }
namespace {
// ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] ) // ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] )
void Generate_NonPrimitiveToPrimitive(CodeStubAssembler* assembler, void ConversionBuiltinsAssembler::Generate_NonPrimitiveToPrimitive(
ToPrimitiveHint hint) { ToPrimitiveHint hint) {
typedef CodeStubAssembler::Label Label; Node* input = Parameter(TypeConversionDescriptor::kArgument);
typedef compiler::Node Node; Node* context = Parameter(TypeConversionDescriptor::kContext);
typedef TypeConversionDescriptor Descriptor;
Node* input = assembler->Parameter(Descriptor::kArgument);
Node* context = assembler->Parameter(Descriptor::kContext);
// Lookup the @@toPrimitive property on the {input}. // Lookup the @@toPrimitive property on the {input}.
Callable callable = CodeFactory::GetProperty(assembler->isolate()); Callable callable = CodeFactory::GetProperty(isolate());
Node* to_primitive_symbol = Node* to_primitive_symbol = HeapConstant(factory()->to_primitive_symbol());
assembler->HeapConstant(assembler->factory()->to_primitive_symbol());
Node* exotic_to_prim = Node* exotic_to_prim =
assembler->CallStub(callable, context, input, to_primitive_symbol); CallStub(callable, context, input, to_primitive_symbol);
// Check if {exotic_to_prim} is neither null nor undefined. // Check if {exotic_to_prim} is neither null nor undefined.
Label ordinary_to_primitive(assembler); Label ordinary_to_primitive(this);
assembler->GotoIf( GotoIf(WordEqual(exotic_to_prim, NullConstant()), &ordinary_to_primitive);
assembler->WordEqual(exotic_to_prim, assembler->NullConstant()), GotoIf(WordEqual(exotic_to_prim, UndefinedConstant()),
&ordinary_to_primitive); &ordinary_to_primitive);
assembler->GotoIf(
assembler->WordEqual(exotic_to_prim, assembler->UndefinedConstant()),
&ordinary_to_primitive);
{ {
// Invoke the {exotic_to_prim} method on the {input} with a string // Invoke the {exotic_to_prim} method on the {input} with a string
// representation of the {hint}. // representation of the {hint}.
Callable callable = CodeFactory::Call( Callable callable =
assembler->isolate(), ConvertReceiverMode::kNotNullOrUndefined); CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined);
Node* hint_string = assembler->HeapConstant( Node* hint_string = HeapConstant(factory()->ToPrimitiveHintString(hint));
assembler->factory()->ToPrimitiveHintString(hint)); Node* result =
Node* result = assembler->CallJS(callable, context, exotic_to_prim, input, CallJS(callable, context, exotic_to_prim, input, hint_string);
hint_string);
// Verify that the {result} is actually a primitive. // Verify that the {result} is actually a primitive.
Label if_resultisprimitive(assembler), Label if_resultisprimitive(this),
if_resultisnotprimitive(assembler, Label::kDeferred); if_resultisnotprimitive(this, Label::kDeferred);
assembler->GotoIf(assembler->TaggedIsSmi(result), &if_resultisprimitive); GotoIf(TaggedIsSmi(result), &if_resultisprimitive);
Node* result_instance_type = assembler->LoadInstanceType(result); Node* result_instance_type = LoadInstanceType(result);
STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE); STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
assembler->Branch(assembler->Int32LessThanOrEqual( Branch(Int32LessThanOrEqual(result_instance_type,
result_instance_type, Int32Constant(LAST_PRIMITIVE_TYPE)),
assembler->Int32Constant(LAST_PRIMITIVE_TYPE)), &if_resultisprimitive, &if_resultisnotprimitive);
&if_resultisprimitive, &if_resultisnotprimitive);
assembler->Bind(&if_resultisprimitive); Bind(&if_resultisprimitive);
{ {
// Just return the {result}. // Just return the {result}.
assembler->Return(result); Return(result);
} }
assembler->Bind(&if_resultisnotprimitive); Bind(&if_resultisnotprimitive);
{ {
// Somehow the @@toPrimitive method on {input} didn't yield a primitive. // Somehow the @@toPrimitive method on {input} didn't yield a primitive.
assembler->TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context);
context);
} }
} }
// Convert using the OrdinaryToPrimitive algorithm instead. // Convert using the OrdinaryToPrimitive algorithm instead.
assembler->Bind(&ordinary_to_primitive); Bind(&ordinary_to_primitive);
{ {
Callable callable = CodeFactory::OrdinaryToPrimitive( Callable callable = CodeFactory::OrdinaryToPrimitive(
assembler->isolate(), (hint == ToPrimitiveHint::kString) isolate(), (hint == ToPrimitiveHint::kString)
? OrdinaryToPrimitiveHint::kString ? OrdinaryToPrimitiveHint::kString
: OrdinaryToPrimitiveHint::kNumber); : OrdinaryToPrimitiveHint::kNumber);
assembler->TailCallStub(callable, context, input); TailCallStub(callable, context, input);
} }
} }
} // namespace TF_BUILTIN(NonPrimitiveToPrimitive_Default, ConversionBuiltinsAssembler) {
Generate_NonPrimitiveToPrimitive(ToPrimitiveHint::kDefault);
void Builtins::Generate_NonPrimitiveToPrimitive_Default(
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_NonPrimitiveToPrimitive(&assembler, ToPrimitiveHint::kDefault);
} }
void Builtins::Generate_NonPrimitiveToPrimitive_Number( TF_BUILTIN(NonPrimitiveToPrimitive_Number, ConversionBuiltinsAssembler) {
compiler::CodeAssemblerState* state) { Generate_NonPrimitiveToPrimitive(ToPrimitiveHint::kNumber);
CodeStubAssembler assembler(state);
Generate_NonPrimitiveToPrimitive(&assembler, ToPrimitiveHint::kNumber);
} }
void Builtins::Generate_NonPrimitiveToPrimitive_String( TF_BUILTIN(NonPrimitiveToPrimitive_String, ConversionBuiltinsAssembler) {
compiler::CodeAssemblerState* state) { Generate_NonPrimitiveToPrimitive(ToPrimitiveHint::kString);
CodeStubAssembler assembler(state);
Generate_NonPrimitiveToPrimitive(&assembler, ToPrimitiveHint::kString);
} }
void Builtins::Generate_StringToNumber(compiler::CodeAssemblerState* state) { TF_BUILTIN(StringToNumber, CodeStubAssembler) {
typedef compiler::Node Node; Node* input = Parameter(TypeConversionDescriptor::kArgument);
typedef TypeConversionDescriptor Descriptor; Node* context = Parameter(TypeConversionDescriptor::kContext);
CodeStubAssembler assembler(state);
Node* input = assembler.Parameter(Descriptor::kArgument); Return(StringToNumber(context, input));
Node* context = assembler.Parameter(Descriptor::kContext);
assembler.Return(assembler.StringToNumber(context, input));
} }
void Builtins::Generate_ToName(compiler::CodeAssemblerState* state) { TF_BUILTIN(ToName, CodeStubAssembler) {
typedef compiler::Node Node; Node* input = Parameter(TypeConversionDescriptor::kArgument);
typedef TypeConversionDescriptor Descriptor; Node* context = Parameter(TypeConversionDescriptor::kContext);
CodeStubAssembler assembler(state);
Node* input = assembler.Parameter(Descriptor::kArgument);
Node* context = assembler.Parameter(Descriptor::kContext);
assembler.Return(assembler.ToName(context, input)); Return(ToName(context, input));
} }
// static TF_BUILTIN(NonNumberToNumber, CodeStubAssembler) {
void Builtins::Generate_NonNumberToNumber(compiler::CodeAssemblerState* state) { Node* input = Parameter(TypeConversionDescriptor::kArgument);
typedef compiler::Node Node; Node* context = Parameter(TypeConversionDescriptor::kContext);
typedef TypeConversionDescriptor Descriptor;
CodeStubAssembler assembler(state);
Node* input = assembler.Parameter(Descriptor::kArgument);
Node* context = assembler.Parameter(Descriptor::kContext);
assembler.Return(assembler.NonNumberToNumber(context, input)); Return(NonNumberToNumber(context, input));
} }
// ES6 section 7.1.3 ToNumber ( argument ) // ES6 section 7.1.3 ToNumber ( argument )
void Builtins::Generate_ToNumber(compiler::CodeAssemblerState* state) { TF_BUILTIN(ToNumber, CodeStubAssembler) {
typedef compiler::Node Node; Node* input = Parameter(TypeConversionDescriptor::kArgument);
typedef TypeConversionDescriptor Descriptor; Node* context = Parameter(TypeConversionDescriptor::kContext);
CodeStubAssembler assembler(state);
Node* input = assembler.Parameter(Descriptor::kArgument); Return(ToNumber(context, input));
Node* context = assembler.Parameter(Descriptor::kContext);
assembler.Return(assembler.ToNumber(context, input));
} }
void Builtins::Generate_ToString(compiler::CodeAssemblerState* state) { TF_BUILTIN(ToString, CodeStubAssembler) {
typedef CodeStubAssembler::Label Label; Node* input = Parameter(TypeConversionDescriptor::kArgument);
typedef compiler::Node Node; Node* context = Parameter(TypeConversionDescriptor::kContext);
typedef TypeConversionDescriptor Descriptor;
CodeStubAssembler assembler(state);
Node* input = assembler.Parameter(Descriptor::kArgument);
Node* context = assembler.Parameter(Descriptor::kContext);
Label is_number(&assembler); Label is_number(this);
Label runtime(&assembler); Label runtime(this);
assembler.GotoIf(assembler.TaggedIsSmi(input), &is_number); GotoIf(TaggedIsSmi(input), &is_number);
Node* input_map = assembler.LoadMap(input); Node* input_map = LoadMap(input);
Node* input_instance_type = assembler.LoadMapInstanceType(input_map); Node* input_instance_type = LoadMapInstanceType(input_map);
Label not_string(&assembler); Label not_string(this);
assembler.GotoIfNot(assembler.IsStringInstanceType(input_instance_type), GotoIfNot(IsStringInstanceType(input_instance_type), &not_string);
&not_string); Return(input);
assembler.Return(input);
Label not_heap_number(&assembler); Label not_heap_number(this);
assembler.Bind(&not_string); Bind(&not_string);
{ { Branch(IsHeapNumberMap(input_map), &is_number, &not_heap_number); }
assembler.GotoIfNot(assembler.IsHeapNumberMap(input_map), &not_heap_number);
assembler.Goto(&is_number);
}
assembler.Bind(&is_number); Bind(&is_number);
{ assembler.Return(assembler.NumberToString(context, input)); } { Return(NumberToString(context, input)); }
assembler.Bind(&not_heap_number); Bind(&not_heap_number);
{ {
assembler.GotoIf( GotoIf(Word32NotEqual(input_instance_type, Int32Constant(ODDBALL_TYPE)),
assembler.Word32NotEqual(input_instance_type, &runtime);
assembler.Int32Constant(ODDBALL_TYPE)), Return(LoadObjectField(input, Oddball::kToStringOffset));
&runtime);
assembler.Return(
assembler.LoadObjectField(input, Oddball::kToStringOffset));
} }
assembler.Bind(&runtime); Bind(&runtime);
{ { Return(CallRuntime(Runtime::kToString, context, input)); }
assembler.Return(assembler.CallRuntime(Runtime::kToString, context, input));
}
} }
Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) { Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) {
...@@ -223,284 +182,234 @@ Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) { ...@@ -223,284 +182,234 @@ Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) {
return Handle<Code>::null(); return Handle<Code>::null();
} }
namespace {
// 7.1.1.1 OrdinaryToPrimitive ( O, hint ) // 7.1.1.1 OrdinaryToPrimitive ( O, hint )
void Generate_OrdinaryToPrimitive(CodeStubAssembler* assembler, void ConversionBuiltinsAssembler::Generate_OrdinaryToPrimitive(
OrdinaryToPrimitiveHint hint) { OrdinaryToPrimitiveHint hint) {
typedef CodeStubAssembler::Label Label; Node* input = Parameter(TypeConversionDescriptor::kArgument);
typedef compiler::Node Node; Node* context = Parameter(TypeConversionDescriptor::kContext);
typedef CodeStubAssembler::Variable Variable;
typedef TypeConversionDescriptor Descriptor;
Node* input = assembler->Parameter(Descriptor::kArgument);
Node* context = assembler->Parameter(Descriptor::kContext);
Variable var_result(assembler, MachineRepresentation::kTagged); Variable var_result(this, MachineRepresentation::kTagged);
Label return_result(assembler, &var_result); Label return_result(this, &var_result);
Handle<String> method_names[2]; Handle<String> method_names[2];
switch (hint) { switch (hint) {
case OrdinaryToPrimitiveHint::kNumber: case OrdinaryToPrimitiveHint::kNumber:
method_names[0] = assembler->factory()->valueOf_string(); method_names[0] = factory()->valueOf_string();
method_names[1] = assembler->factory()->toString_string(); method_names[1] = factory()->toString_string();
break; break;
case OrdinaryToPrimitiveHint::kString: case OrdinaryToPrimitiveHint::kString:
method_names[0] = assembler->factory()->toString_string(); method_names[0] = factory()->toString_string();
method_names[1] = assembler->factory()->valueOf_string(); method_names[1] = factory()->valueOf_string();
break; break;
} }
for (Handle<String> name : method_names) { for (Handle<String> name : method_names) {
// Lookup the {name} on the {input}. // Lookup the {name} on the {input}.
Callable callable = CodeFactory::GetProperty(assembler->isolate()); Callable callable = CodeFactory::GetProperty(isolate());
Node* name_string = assembler->HeapConstant(name); Node* name_string = HeapConstant(name);
Node* method = assembler->CallStub(callable, context, input, name_string); Node* method = CallStub(callable, context, input, name_string);
// Check if the {method} is callable. // Check if the {method} is callable.
Label if_methodiscallable(assembler), Label if_methodiscallable(this),
if_methodisnotcallable(assembler, Label::kDeferred); if_methodisnotcallable(this, Label::kDeferred);
assembler->GotoIf(assembler->TaggedIsSmi(method), &if_methodisnotcallable); GotoIf(TaggedIsSmi(method), &if_methodisnotcallable);
Node* method_map = assembler->LoadMap(method); Node* method_map = LoadMap(method);
assembler->Branch(assembler->IsCallableMap(method_map), Branch(IsCallableMap(method_map), &if_methodiscallable,
&if_methodiscallable, &if_methodisnotcallable); &if_methodisnotcallable);
assembler->Bind(&if_methodiscallable); Bind(&if_methodiscallable);
{ {
// Call the {method} on the {input}. // Call the {method} on the {input}.
Callable callable = CodeFactory::Call( Callable callable = CodeFactory::Call(
assembler->isolate(), ConvertReceiverMode::kNotNullOrUndefined); isolate(), ConvertReceiverMode::kNotNullOrUndefined);
Node* result = assembler->CallJS(callable, context, method, input); Node* result = CallJS(callable, context, method, input);
var_result.Bind(result); var_result.Bind(result);
// Return the {result} if it is a primitive. // Return the {result} if it is a primitive.
assembler->GotoIf(assembler->TaggedIsSmi(result), &return_result); GotoIf(TaggedIsSmi(result), &return_result);
Node* result_instance_type = assembler->LoadInstanceType(result); Node* result_instance_type = LoadInstanceType(result);
STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE); STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
assembler->GotoIf(assembler->Int32LessThanOrEqual( GotoIf(Int32LessThanOrEqual(result_instance_type,
result_instance_type, Int32Constant(LAST_PRIMITIVE_TYPE)),
assembler->Int32Constant(LAST_PRIMITIVE_TYPE)), &return_result);
&return_result);
} }
// Just continue with the next {name} if the {method} is not callable. // Just continue with the next {name} if the {method} is not callable.
assembler->Goto(&if_methodisnotcallable); Goto(&if_methodisnotcallable);
assembler->Bind(&if_methodisnotcallable); Bind(&if_methodisnotcallable);
} }
assembler->TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context); TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context);
assembler->Bind(&return_result); Bind(&return_result);
assembler->Return(var_result.value()); Return(var_result.value());
} }
} // namespace TF_BUILTIN(OrdinaryToPrimitive_Number, ConversionBuiltinsAssembler) {
Generate_OrdinaryToPrimitive(OrdinaryToPrimitiveHint::kNumber);
void Builtins::Generate_OrdinaryToPrimitive_Number(
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_OrdinaryToPrimitive(&assembler, OrdinaryToPrimitiveHint::kNumber);
} }
void Builtins::Generate_OrdinaryToPrimitive_String( TF_BUILTIN(OrdinaryToPrimitive_String, ConversionBuiltinsAssembler) {
compiler::CodeAssemblerState* state) { Generate_OrdinaryToPrimitive(OrdinaryToPrimitiveHint::kString);
CodeStubAssembler assembler(state);
Generate_OrdinaryToPrimitive(&assembler, OrdinaryToPrimitiveHint::kString);
} }
// ES6 section 7.1.2 ToBoolean ( argument ) // ES6 section 7.1.2 ToBoolean ( argument )
void Builtins::Generate_ToBoolean(compiler::CodeAssemblerState* state) { TF_BUILTIN(ToBoolean, CodeStubAssembler) {
typedef compiler::Node Node; Node* value = Parameter(TypeConversionDescriptor::kArgument);
typedef CodeStubAssembler::Label Label;
typedef TypeConversionDescriptor Descriptor;
CodeStubAssembler assembler(state);
Node* value = assembler.Parameter(Descriptor::kArgument); Label return_true(this), return_false(this);
BranchIfToBooleanIsTrue(value, &return_true, &return_false);
Label return_true(&assembler), return_false(&assembler); Bind(&return_true);
assembler.BranchIfToBooleanIsTrue(value, &return_true, &return_false); Return(BooleanConstant(true));
assembler.Bind(&return_true); Bind(&return_false);
assembler.Return(assembler.BooleanConstant(true)); Return(BooleanConstant(false));
assembler.Bind(&return_false);
assembler.Return(assembler.BooleanConstant(false));
} }
void Builtins::Generate_ToLength(compiler::CodeAssemblerState* state) { TF_BUILTIN(ToLength, CodeStubAssembler) {
typedef CodeStubAssembler::Label Label; Node* context = Parameter(1);
typedef compiler::Node Node;
typedef CodeStubAssembler::Variable Variable;
CodeStubAssembler assembler(state);
Node* context = assembler.Parameter(1);
// We might need to loop once for ToNumber conversion. // We might need to loop once for ToNumber conversion.
Variable var_len(&assembler, MachineRepresentation::kTagged); Variable var_len(this, MachineRepresentation::kTagged, Parameter(0));
Label loop(&assembler, &var_len); Label loop(this, &var_len);
var_len.Bind(assembler.Parameter(0)); Goto(&loop);
assembler.Goto(&loop); Bind(&loop);
assembler.Bind(&loop);
{ {
// Shared entry points. // Shared entry points.
Label return_len(&assembler), Label return_len(this), return_two53minus1(this, Label::kDeferred),
return_two53minus1(&assembler, Label::kDeferred), return_zero(this, Label::kDeferred);
return_zero(&assembler, Label::kDeferred);
// Load the current {len} value. // Load the current {len} value.
Node* len = var_len.value(); Node* len = var_len.value();
// Check if {len} is a positive Smi. // Check if {len} is a positive Smi.
assembler.GotoIf(assembler.TaggedIsPositiveSmi(len), &return_len); GotoIf(TaggedIsPositiveSmi(len), &return_len);
// Check if {len} is a (negative) Smi. // Check if {len} is a (negative) Smi.
assembler.GotoIf(assembler.TaggedIsSmi(len), &return_zero); GotoIf(TaggedIsSmi(len), &return_zero);
// Check if {len} is a HeapNumber. // Check if {len} is a HeapNumber.
Label if_lenisheapnumber(&assembler), Label if_lenisheapnumber(this),
if_lenisnotheapnumber(&assembler, Label::kDeferred); if_lenisnotheapnumber(this, Label::kDeferred);
assembler.Branch(assembler.IsHeapNumberMap(assembler.LoadMap(len)), Branch(IsHeapNumberMap(LoadMap(len)), &if_lenisheapnumber,
&if_lenisheapnumber, &if_lenisnotheapnumber); &if_lenisnotheapnumber);
assembler.Bind(&if_lenisheapnumber); Bind(&if_lenisheapnumber);
{ {
// Load the floating-point value of {len}. // Load the floating-point value of {len}.
Node* len_value = assembler.LoadHeapNumberValue(len); Node* len_value = LoadHeapNumberValue(len);
// Check if {len} is not greater than zero. // Check if {len} is not greater than zero.
assembler.GotoIfNot(assembler.Float64GreaterThan( GotoIfNot(Float64GreaterThan(len_value, Float64Constant(0.0)),
len_value, assembler.Float64Constant(0.0)), &return_zero);
&return_zero);
// Check if {len} is greater than or equal to 2^53-1. // Check if {len} is greater than or equal to 2^53-1.
assembler.GotoIf( GotoIf(Float64GreaterThanOrEqual(len_value,
assembler.Float64GreaterThanOrEqual( Float64Constant(kMaxSafeInteger)),
len_value, assembler.Float64Constant(kMaxSafeInteger)), &return_two53minus1);
&return_two53minus1);
// Round the {len} towards -Infinity. // Round the {len} towards -Infinity.
Node* value = assembler.Float64Floor(len_value); Node* value = Float64Floor(len_value);
Node* result = assembler.ChangeFloat64ToTagged(value); Node* result = ChangeFloat64ToTagged(value);
assembler.Return(result); Return(result);
} }
assembler.Bind(&if_lenisnotheapnumber); Bind(&if_lenisnotheapnumber);
{ {
// Need to convert {len} to a Number first. // Need to convert {len} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(assembler.isolate()); Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_len.Bind(assembler.CallStub(callable, context, len)); var_len.Bind(CallStub(callable, context, len));
assembler.Goto(&loop); Goto(&loop);
} }
assembler.Bind(&return_len); Bind(&return_len);
assembler.Return(var_len.value()); Return(var_len.value());
assembler.Bind(&return_two53minus1); Bind(&return_two53minus1);
assembler.Return(assembler.NumberConstant(kMaxSafeInteger)); Return(NumberConstant(kMaxSafeInteger));
assembler.Bind(&return_zero); Bind(&return_zero);
assembler.Return(assembler.SmiConstant(Smi::kZero)); Return(SmiConstant(Smi::kZero));
} }
} }
void Builtins::Generate_ToInteger(compiler::CodeAssemblerState* state) { TF_BUILTIN(ToInteger, CodeStubAssembler) {
typedef TypeConversionDescriptor Descriptor; Node* input = Parameter(TypeConversionDescriptor::kArgument);
CodeStubAssembler assembler(state); Node* context = Parameter(TypeConversionDescriptor::kContext);
compiler::Node* input = assembler.Parameter(Descriptor::kArgument);
compiler::Node* context = assembler.Parameter(Descriptor::kContext);
assembler.Return(assembler.ToInteger(context, input)); Return(ToInteger(context, input));
} }
// ES6 section 7.1.13 ToObject (argument) // ES6 section 7.1.13 ToObject (argument)
void Builtins::Generate_ToObject(compiler::CodeAssemblerState* state) { TF_BUILTIN(ToObject, CodeStubAssembler) {
typedef compiler::Node Node; Label if_number(this, Label::kDeferred), if_notsmi(this), if_jsreceiver(this),
typedef CodeStubAssembler::Label Label; if_noconstructor(this, Label::kDeferred), if_wrapjsvalue(this);
typedef CodeStubAssembler::Variable Variable;
typedef TypeConversionDescriptor Descriptor;
CodeStubAssembler assembler(state);
Label if_number(&assembler, Label::kDeferred), if_notsmi(&assembler), Node* object = Parameter(TypeConversionDescriptor::kArgument);
if_jsreceiver(&assembler), if_noconstructor(&assembler, Label::kDeferred), Node* context = Parameter(TypeConversionDescriptor::kContext);
if_wrapjsvalue(&assembler);
Node* object = assembler.Parameter(Descriptor::kArgument); Variable constructor_function_index_var(this,
Node* context = assembler.Parameter(Descriptor::kContext);
Variable constructor_function_index_var(&assembler,
MachineType::PointerRepresentation()); MachineType::PointerRepresentation());
assembler.Branch(assembler.TaggedIsSmi(object), &if_number, &if_notsmi); Branch(TaggedIsSmi(object), &if_number, &if_notsmi);
assembler.Bind(&if_notsmi); Bind(&if_notsmi);
Node* map = assembler.LoadMap(object); Node* map = LoadMap(object);
assembler.GotoIf(assembler.IsHeapNumberMap(map), &if_number); GotoIf(IsHeapNumberMap(map), &if_number);
Node* instance_type = assembler.LoadMapInstanceType(map); Node* instance_type = LoadMapInstanceType(map);
assembler.GotoIf(assembler.IsJSReceiverInstanceType(instance_type), GotoIf(IsJSReceiverInstanceType(instance_type), &if_jsreceiver);
&if_jsreceiver);
Node* constructor_function_index = Node* constructor_function_index = LoadMapConstructorFunctionIndex(map);
assembler.LoadMapConstructorFunctionIndex(map); GotoIf(WordEqual(constructor_function_index,
assembler.GotoIf(assembler.WordEqual(constructor_function_index, IntPtrConstant(Map::kNoConstructorFunctionIndex)),
assembler.IntPtrConstant( &if_noconstructor);
Map::kNoConstructorFunctionIndex)),
&if_noconstructor);
constructor_function_index_var.Bind(constructor_function_index); constructor_function_index_var.Bind(constructor_function_index);
assembler.Goto(&if_wrapjsvalue); Goto(&if_wrapjsvalue);
assembler.Bind(&if_number); Bind(&if_number);
constructor_function_index_var.Bind( constructor_function_index_var.Bind(
assembler.IntPtrConstant(Context::NUMBER_FUNCTION_INDEX)); IntPtrConstant(Context::NUMBER_FUNCTION_INDEX));
assembler.Goto(&if_wrapjsvalue); Goto(&if_wrapjsvalue);
assembler.Bind(&if_wrapjsvalue); Bind(&if_wrapjsvalue);
Node* native_context = assembler.LoadNativeContext(context); Node* native_context = LoadNativeContext(context);
Node* constructor = assembler.LoadFixedArrayElement( Node* constructor = LoadFixedArrayElement(
native_context, constructor_function_index_var.value()); native_context, constructor_function_index_var.value());
Node* initial_map = assembler.LoadObjectField( Node* initial_map =
constructor, JSFunction::kPrototypeOrInitialMapOffset); LoadObjectField(constructor, JSFunction::kPrototypeOrInitialMapOffset);
Node* js_value = assembler.Allocate(JSValue::kSize); Node* js_value = Allocate(JSValue::kSize);
assembler.StoreMapNoWriteBarrier(js_value, initial_map); StoreMapNoWriteBarrier(js_value, initial_map);
assembler.StoreObjectFieldRoot(js_value, JSValue::kPropertiesOffset, StoreObjectFieldRoot(js_value, JSValue::kPropertiesOffset,
Heap::kEmptyFixedArrayRootIndex); Heap::kEmptyFixedArrayRootIndex);
assembler.StoreObjectFieldRoot(js_value, JSObject::kElementsOffset, StoreObjectFieldRoot(js_value, JSObject::kElementsOffset,
Heap::kEmptyFixedArrayRootIndex); Heap::kEmptyFixedArrayRootIndex);
assembler.StoreObjectField(js_value, JSValue::kValueOffset, object); StoreObjectField(js_value, JSValue::kValueOffset, object);
assembler.Return(js_value); Return(js_value);
assembler.Bind(&if_noconstructor); Bind(&if_noconstructor);
assembler.TailCallRuntime( TailCallRuntime(
Runtime::kThrowUndefinedOrNullToObject, context, Runtime::kThrowUndefinedOrNullToObject, context,
assembler.HeapConstant( HeapConstant(factory()->NewStringFromAsciiChecked("ToObject", TENURED)));
assembler.factory()->NewStringFromAsciiChecked("ToObject", TENURED)));
assembler.Bind(&if_jsreceiver); Bind(&if_jsreceiver);
assembler.Return(object); Return(object);
} }
// Deprecated ES5 [[Class]] internal property (used to implement %_ClassOf). // Deprecated ES5 [[Class]] internal property (used to implement %_ClassOf).
void Builtins::Generate_ClassOf(compiler::CodeAssemblerState* state) { TF_BUILTIN(ClassOf, CodeStubAssembler) {
typedef compiler::Node Node; Node* object = Parameter(TypeofDescriptor::kObject);
typedef TypeofDescriptor Descriptor;
CodeStubAssembler assembler(state);
Node* object = assembler.Parameter(Descriptor::kObject);
assembler.Return(assembler.ClassOf(object)); Return(ClassOf(object));
} }
// ES6 section 12.5.5 typeof operator // ES6 section 12.5.5 typeof operator
void Builtins::Generate_Typeof(compiler::CodeAssemblerState* state) { TF_BUILTIN(Typeof, CodeStubAssembler) {
typedef compiler::Node Node; Node* object = Parameter(TypeofDescriptor::kObject);
typedef TypeofDescriptor Descriptor; Node* context = Parameter(TypeofDescriptor::kContext);
CodeStubAssembler assembler(state);
Node* object = assembler.Parameter(Descriptor::kObject);
Node* context = assembler.Parameter(Descriptor::kContext);
assembler.Return(assembler.Typeof(object, context)); Return(Typeof(object, context));
} }
} // namespace internal } // namespace internal
......
...@@ -17,6 +17,15 @@ namespace internal { ...@@ -17,6 +17,15 @@ namespace internal {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// ES6 section 20.3 Date Objects // ES6 section 20.3 Date Objects
class DateBuiltinsAssembler : public CodeStubAssembler {
public:
explicit DateBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void Generate_DatePrototype_GetField(int field_index);
};
namespace { namespace {
// ES6 section 20.3.1.1 Time Values and Time Range // ES6 section 20.3.1.1 Time Values and Time Range
...@@ -895,279 +904,198 @@ BUILTIN(DatePrototypeToJson) { ...@@ -895,279 +904,198 @@ BUILTIN(DatePrototypeToJson) {
} }
} }
namespace { void DateBuiltinsAssembler::Generate_DatePrototype_GetField(int field_index) {
Node* receiver = Parameter(0);
void Generate_DatePrototype_GetField(CodeStubAssembler* assembler, Node* context = Parameter(3);
int field_index) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
Node* receiver = assembler->Parameter(0);
Node* context = assembler->Parameter(3);
Label receiver_not_date(assembler, Label::kDeferred); Label receiver_not_date(this, Label::kDeferred);
assembler->GotoIf(assembler->TaggedIsSmi(receiver), &receiver_not_date); GotoIf(TaggedIsSmi(receiver), &receiver_not_date);
Node* receiver_instance_type = assembler->LoadInstanceType(receiver); Node* receiver_instance_type = LoadInstanceType(receiver);
assembler->GotoIf( GotoIf(Word32NotEqual(receiver_instance_type, Int32Constant(JS_DATE_TYPE)),
assembler->Word32NotEqual(receiver_instance_type, &receiver_not_date);
assembler->Int32Constant(JS_DATE_TYPE)),
&receiver_not_date);
// Load the specified date field, falling back to the runtime as necessary. // Load the specified date field, falling back to the runtime as necessary.
if (field_index == JSDate::kDateValue) { if (field_index == JSDate::kDateValue) {
assembler->Return( Return(LoadObjectField(receiver, JSDate::kValueOffset));
assembler->LoadObjectField(receiver, JSDate::kValueOffset));
} else { } else {
if (field_index < JSDate::kFirstUncachedField) { if (field_index < JSDate::kFirstUncachedField) {
Label stamp_mismatch(assembler, Label::kDeferred); Label stamp_mismatch(this, Label::kDeferred);
Node* date_cache_stamp = assembler->Load( Node* date_cache_stamp = Load(
MachineType::AnyTagged(), MachineType::AnyTagged(),
assembler->ExternalConstant( ExternalConstant(ExternalReference::date_cache_stamp(isolate())));
ExternalReference::date_cache_stamp(assembler->isolate())));
Node* cache_stamp = LoadObjectField(receiver, JSDate::kCacheStampOffset);
Node* cache_stamp = GotoIf(WordNotEqual(date_cache_stamp, cache_stamp), &stamp_mismatch);
assembler->LoadObjectField(receiver, JSDate::kCacheStampOffset); Return(LoadObjectField(
assembler->GotoIf(assembler->WordNotEqual(date_cache_stamp, cache_stamp),
&stamp_mismatch);
assembler->Return(assembler->LoadObjectField(
receiver, JSDate::kValueOffset + field_index * kPointerSize)); receiver, JSDate::kValueOffset + field_index * kPointerSize));
assembler->Bind(&stamp_mismatch); Bind(&stamp_mismatch);
} }
Node* field_index_smi = assembler->SmiConstant(Smi::FromInt(field_index)); Node* field_index_smi = SmiConstant(Smi::FromInt(field_index));
Node* function = assembler->ExternalConstant( Node* function =
ExternalReference::get_date_field_function(assembler->isolate())); ExternalConstant(ExternalReference::get_date_field_function(isolate()));
Node* result = assembler->CallCFunction2( Node* result = CallCFunction2(
MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(),
MachineType::AnyTagged(), function, receiver, field_index_smi); MachineType::AnyTagged(), function, receiver, field_index_smi);
assembler->Return(result); Return(result);
} }
// Raise a TypeError if the receiver is not a date. // Raise a TypeError if the receiver is not a date.
assembler->Bind(&receiver_not_date); Bind(&receiver_not_date);
{ {
assembler->CallRuntime(Runtime::kThrowNotDateError, context); CallRuntime(Runtime::kThrowNotDateError, context);
assembler->Unreachable(); Unreachable();
} }
} }
} // namespace TF_BUILTIN(DatePrototypeGetDate, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kDay);
// static
void Builtins::Generate_DatePrototypeGetDate(
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kDay);
} }
// static TF_BUILTIN(DatePrototypeGetDay, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetDay( Generate_DatePrototype_GetField(JSDate::kWeekday);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kWeekday);
} }
// static TF_BUILTIN(DatePrototypeGetFullYear, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetFullYear( Generate_DatePrototype_GetField(JSDate::kYear);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kYear);
} }
// static TF_BUILTIN(DatePrototypeGetHours, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetHours( Generate_DatePrototype_GetField(JSDate::kHour);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kHour);
} }
// static TF_BUILTIN(DatePrototypeGetMilliseconds, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetMilliseconds( Generate_DatePrototype_GetField(JSDate::kMillisecond);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kMillisecond);
} }
// static TF_BUILTIN(DatePrototypeGetMinutes, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetMinutes( Generate_DatePrototype_GetField(JSDate::kMinute);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kMinute);
} }
// static TF_BUILTIN(DatePrototypeGetMonth, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetMonth( Generate_DatePrototype_GetField(JSDate::kMonth);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kMonth);
} }
// static TF_BUILTIN(DatePrototypeGetSeconds, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetSeconds( Generate_DatePrototype_GetField(JSDate::kSecond);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kSecond);
} }
// static TF_BUILTIN(DatePrototypeGetTime, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetTime( Generate_DatePrototype_GetField(JSDate::kDateValue);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kDateValue);
} }
// static TF_BUILTIN(DatePrototypeGetTimezoneOffset, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetTimezoneOffset( Generate_DatePrototype_GetField(JSDate::kTimezoneOffset);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kTimezoneOffset);
} }
// static TF_BUILTIN(DatePrototypeGetUTCDate, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetUTCDate( Generate_DatePrototype_GetField(JSDate::kDayUTC);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kDayUTC);
} }
// static TF_BUILTIN(DatePrototypeGetUTCDay, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetUTCDay( Generate_DatePrototype_GetField(JSDate::kWeekdayUTC);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kWeekdayUTC);
} }
// static TF_BUILTIN(DatePrototypeGetUTCFullYear, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetUTCFullYear( Generate_DatePrototype_GetField(JSDate::kYearUTC);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kYearUTC);
} }
// static TF_BUILTIN(DatePrototypeGetUTCHours, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetUTCHours( Generate_DatePrototype_GetField(JSDate::kHourUTC);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kHourUTC);
} }
// static TF_BUILTIN(DatePrototypeGetUTCMilliseconds, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetUTCMilliseconds( Generate_DatePrototype_GetField(JSDate::kMillisecondUTC);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kMillisecondUTC);
} }
// static TF_BUILTIN(DatePrototypeGetUTCMinutes, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetUTCMinutes( Generate_DatePrototype_GetField(JSDate::kMinuteUTC);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kMinuteUTC);
} }
// static TF_BUILTIN(DatePrototypeGetUTCMonth, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetUTCMonth( Generate_DatePrototype_GetField(JSDate::kMonthUTC);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kMonthUTC);
} }
// static TF_BUILTIN(DatePrototypeGetUTCSeconds, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeGetUTCSeconds( Generate_DatePrototype_GetField(JSDate::kSecondUTC);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kSecondUTC);
} }
// static TF_BUILTIN(DatePrototypeValueOf, DateBuiltinsAssembler) {
void Builtins::Generate_DatePrototypeValueOf( Generate_DatePrototype_GetField(JSDate::kDateValue);
compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
Generate_DatePrototype_GetField(&assembler, JSDate::kDateValue);
} }
// static TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) {
void Builtins::Generate_DatePrototypeToPrimitive( Node* receiver = Parameter(0);
compiler::CodeAssemblerState* state) { Node* hint = Parameter(1);
CodeStubAssembler assembler(state); Node* context = Parameter(4);
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
Node* receiver = assembler.Parameter(0);
Node* hint = assembler.Parameter(1);
Node* context = assembler.Parameter(4);
// Check if the {receiver} is actually a JSReceiver. // Check if the {receiver} is actually a JSReceiver.
Label receiver_is_invalid(&assembler, Label::kDeferred); Label receiver_is_invalid(this, Label::kDeferred);
assembler.GotoIf(assembler.TaggedIsSmi(receiver), &receiver_is_invalid); GotoIf(TaggedIsSmi(receiver), &receiver_is_invalid);
assembler.GotoIfNot(assembler.IsJSReceiver(receiver), &receiver_is_invalid); GotoIfNot(IsJSReceiver(receiver), &receiver_is_invalid);
// Dispatch to the appropriate OrdinaryToPrimitive builtin. // Dispatch to the appropriate OrdinaryToPrimitive builtin.
Label hint_is_number(&assembler), hint_is_string(&assembler), Label hint_is_number(this), hint_is_string(this),
hint_is_invalid(&assembler, Label::kDeferred); hint_is_invalid(this, Label::kDeferred);
// Fast cases for internalized strings. // Fast cases for internalized strings.
Node* number_string = assembler.LoadRoot(Heap::knumber_stringRootIndex); Node* number_string = LoadRoot(Heap::knumber_stringRootIndex);
assembler.GotoIf(assembler.WordEqual(hint, number_string), &hint_is_number); GotoIf(WordEqual(hint, number_string), &hint_is_number);
Node* default_string = assembler.LoadRoot(Heap::kdefault_stringRootIndex); Node* default_string = LoadRoot(Heap::kdefault_stringRootIndex);
assembler.GotoIf(assembler.WordEqual(hint, default_string), &hint_is_string); GotoIf(WordEqual(hint, default_string), &hint_is_string);
Node* string_string = assembler.LoadRoot(Heap::kstring_stringRootIndex); Node* string_string = LoadRoot(Heap::kstring_stringRootIndex);
assembler.GotoIf(assembler.WordEqual(hint, string_string), &hint_is_string); GotoIf(WordEqual(hint, string_string), &hint_is_string);
// Slow-case with actual string comparisons. // Slow-case with actual string comparisons.
Callable string_equal = CodeFactory::StringEqual(assembler.isolate()); Callable string_equal = CodeFactory::StringEqual(isolate());
assembler.GotoIf(assembler.TaggedIsSmi(hint), &hint_is_invalid); GotoIf(TaggedIsSmi(hint), &hint_is_invalid);
assembler.GotoIfNot(assembler.IsString(hint), &hint_is_invalid); GotoIfNot(IsString(hint), &hint_is_invalid);
assembler.GotoIf(assembler.WordEqual(assembler.CallStub(string_equal, context, GotoIf(WordEqual(CallStub(string_equal, context, hint, number_string),
hint, number_string), TrueConstant()),
assembler.TrueConstant()), &hint_is_number);
&hint_is_number); GotoIf(WordEqual(CallStub(string_equal, context, hint, default_string),
assembler.GotoIf(assembler.WordEqual(assembler.CallStub(string_equal, context, TrueConstant()),
hint, default_string), &hint_is_string);
assembler.TrueConstant()), GotoIf(WordEqual(CallStub(string_equal, context, hint, string_string),
&hint_is_string); TrueConstant()),
assembler.GotoIf(assembler.WordEqual(assembler.CallStub(string_equal, context, &hint_is_string);
hint, string_string), Goto(&hint_is_invalid);
assembler.TrueConstant()),
&hint_is_string);
assembler.Goto(&hint_is_invalid);
// Use the OrdinaryToPrimitive builtin to convert to a Number. // Use the OrdinaryToPrimitive builtin to convert to a Number.
assembler.Bind(&hint_is_number); Bind(&hint_is_number);
{ {
Callable callable = CodeFactory::OrdinaryToPrimitive( Callable callable = CodeFactory::OrdinaryToPrimitive(
assembler.isolate(), OrdinaryToPrimitiveHint::kNumber); isolate(), OrdinaryToPrimitiveHint::kNumber);
Node* result = assembler.CallStub(callable, context, receiver); Node* result = CallStub(callable, context, receiver);
assembler.Return(result); Return(result);
} }
// Use the OrdinaryToPrimitive builtin to convert to a String. // Use the OrdinaryToPrimitive builtin to convert to a String.
assembler.Bind(&hint_is_string); Bind(&hint_is_string);
{ {
Callable callable = CodeFactory::OrdinaryToPrimitive( Callable callable = CodeFactory::OrdinaryToPrimitive(
assembler.isolate(), OrdinaryToPrimitiveHint::kString); isolate(), OrdinaryToPrimitiveHint::kString);
Node* result = assembler.CallStub(callable, context, receiver); Node* result = CallStub(callable, context, receiver);
assembler.Return(result); Return(result);
} }
// Raise a TypeError if the {hint} is invalid. // Raise a TypeError if the {hint} is invalid.
assembler.Bind(&hint_is_invalid); Bind(&hint_is_invalid);
{ {
assembler.CallRuntime(Runtime::kThrowInvalidHint, context, hint); CallRuntime(Runtime::kThrowInvalidHint, context, hint);
assembler.Unreachable(); Unreachable();
} }
// Raise a TypeError if the {receiver} is not a JSReceiver instance. // Raise a TypeError if the {receiver} is not a JSReceiver instance.
assembler.Bind(&receiver_is_invalid); Bind(&receiver_is_invalid);
{ {
assembler.CallRuntime( CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
Runtime::kThrowIncompatibleMethodReceiver, context, HeapConstant(factory()->NewStringFromAsciiChecked(
assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked( "Date.prototype [ @@toPrimitive ]", TENURED)),
"Date.prototype [ @@toPrimitive ]", TENURED)), receiver);
receiver); Unreachable();
assembler.Unreachable();
} }
} }
......
...@@ -272,182 +272,160 @@ Object* DoFunctionBind(Isolate* isolate, BuiltinArguments args) { ...@@ -272,182 +272,160 @@ Object* DoFunctionBind(Isolate* isolate, BuiltinArguments args) {
// ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args ) // ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args )
BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); } BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); }
void Builtins::Generate_FastFunctionPrototypeBind( TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
compiler::CodeAssemblerState* state) { Label slow(this);
using compiler::Node;
typedef CodeStubAssembler::Label Label;
typedef CodeStubAssembler::Variable Variable;
CodeStubAssembler assembler(state); Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Label slow(&assembler); Node* context = Parameter(BuiltinDescriptor::kContext);
Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
Node* argc = assembler.Parameter(BuiltinDescriptor::kArgumentsCount); CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
Node* context = assembler.Parameter(BuiltinDescriptor::kContext);
Node* new_target = assembler.Parameter(BuiltinDescriptor::kNewTarget);
CodeStubArguments args(&assembler, assembler.ChangeInt32ToIntPtr(argc));
// Check that receiver has instance type of JS_FUNCTION_TYPE // Check that receiver has instance type of JS_FUNCTION_TYPE
Node* receiver = args.GetReceiver(); Node* receiver = args.GetReceiver();
assembler.GotoIf(assembler.TaggedIsSmi(receiver), &slow); GotoIf(TaggedIsSmi(receiver), &slow);
Node* receiver_map = assembler.LoadMap(receiver); Node* receiver_map = LoadMap(receiver);
Node* instance_type = assembler.LoadMapInstanceType(receiver_map); Node* instance_type = LoadMapInstanceType(receiver_map);
assembler.GotoIf( GotoIf(Word32NotEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)), &slow);
assembler.Word32NotEqual(instance_type,
assembler.Int32Constant(JS_FUNCTION_TYPE)),
&slow);
// Disallow binding of slow-mode functions. We need to figure out whether the // Disallow binding of slow-mode functions. We need to figure out whether the
// length and name property are in the original state. // length and name property are in the original state.
assembler.Comment("Disallow binding of slow-mode functions"); Comment("Disallow binding of slow-mode functions");
assembler.GotoIf(assembler.IsDictionaryMap(receiver_map), &slow); GotoIf(IsDictionaryMap(receiver_map), &slow);
// Check whether the length and name properties are still present as // Check whether the length and name properties are still present as
// AccessorInfo objects. In that case, their value can be recomputed even if // AccessorInfo objects. In that case, their value can be recomputed even if
// the actual value on the object changes. // the actual value on the object changes.
assembler.Comment("Check descriptor array length"); Comment("Check descriptor array length");
Node* descriptors = assembler.LoadMapDescriptors(receiver_map); Node* descriptors = LoadMapDescriptors(receiver_map);
Node* descriptors_length = assembler.LoadFixedArrayBaseLength(descriptors); Node* descriptors_length = LoadFixedArrayBaseLength(descriptors);
assembler.GotoIf(assembler.SmiLessThanOrEqual(descriptors_length, GotoIf(SmiLessThanOrEqual(descriptors_length, SmiConstant(1)), &slow);
assembler.SmiConstant(1)),
&slow);
// Check whether the length and name properties are still present as // Check whether the length and name properties are still present as
// AccessorInfo objects. In that case, their value can be recomputed even if // AccessorInfo objects. In that case, their value can be recomputed even if
// the actual value on the object changes. // the actual value on the object changes.
assembler.Comment("Check name and length properties"); Comment("Check name and length properties");
const int length_index = JSFunction::kLengthDescriptorIndex; const int length_index = JSFunction::kLengthDescriptorIndex;
Node* maybe_length = assembler.LoadFixedArrayElement( Node* maybe_length = LoadFixedArrayElement(
descriptors, DescriptorArray::ToKeyIndex(length_index)); descriptors, DescriptorArray::ToKeyIndex(length_index));
assembler.GotoIf( GotoIf(WordNotEqual(maybe_length, LoadRoot(Heap::klength_stringRootIndex)),
assembler.WordNotEqual(maybe_length, &slow);
assembler.LoadRoot(Heap::klength_stringRootIndex)),
&slow);
Node* maybe_length_accessor = assembler.LoadFixedArrayElement( Node* maybe_length_accessor = LoadFixedArrayElement(
descriptors, DescriptorArray::ToValueIndex(length_index)); descriptors, DescriptorArray::ToValueIndex(length_index));
assembler.GotoIf(assembler.TaggedIsSmi(maybe_length_accessor), &slow); GotoIf(TaggedIsSmi(maybe_length_accessor), &slow);
Node* length_value_map = assembler.LoadMap(maybe_length_accessor); Node* length_value_map = LoadMap(maybe_length_accessor);
assembler.GotoIfNot(assembler.IsAccessorInfoMap(length_value_map), &slow); GotoIfNot(IsAccessorInfoMap(length_value_map), &slow);
const int name_index = JSFunction::kNameDescriptorIndex; const int name_index = JSFunction::kNameDescriptorIndex;
Node* maybe_name = assembler.LoadFixedArrayElement( Node* maybe_name = LoadFixedArrayElement(
descriptors, DescriptorArray::ToKeyIndex(name_index)); descriptors, DescriptorArray::ToKeyIndex(name_index));
assembler.GotoIf( GotoIf(WordNotEqual(maybe_name, LoadRoot(Heap::kname_stringRootIndex)),
assembler.WordNotEqual(maybe_name, &slow);
assembler.LoadRoot(Heap::kname_stringRootIndex)),
&slow);
Node* maybe_name_accessor = assembler.LoadFixedArrayElement( Node* maybe_name_accessor = LoadFixedArrayElement(
descriptors, DescriptorArray::ToValueIndex(name_index)); descriptors, DescriptorArray::ToValueIndex(name_index));
assembler.GotoIf(assembler.TaggedIsSmi(maybe_name_accessor), &slow); GotoIf(TaggedIsSmi(maybe_name_accessor), &slow);
Node* name_value_map = assembler.LoadMap(maybe_name_accessor); Node* name_value_map = LoadMap(maybe_name_accessor);
assembler.GotoIfNot(assembler.IsAccessorInfoMap(name_value_map), &slow); GotoIfNot(IsAccessorInfoMap(name_value_map), &slow);
// Choose the right bound function map based on whether the target is // Choose the right bound function map based on whether the target is
// constructable. // constructable.
assembler.Comment("Choose the right bound function map"); Comment("Choose the right bound function map");
Variable bound_function_map(&assembler, MachineRepresentation::kTagged); Variable bound_function_map(this, MachineRepresentation::kTagged);
Label with_constructor(&assembler); Label with_constructor(this);
CodeStubAssembler::VariableList vars({&bound_function_map}, assembler.zone()); VariableList vars({&bound_function_map}, zone());
Node* native_context = assembler.LoadNativeContext(context); Node* native_context = LoadNativeContext(context);
Label map_done(&assembler, vars); Label map_done(this, vars);
Node* bit_field = assembler.LoadMapBitField(receiver_map); Node* bit_field = LoadMapBitField(receiver_map);
int mask = static_cast<int>(1 << Map::kIsConstructor); int mask = static_cast<int>(1 << Map::kIsConstructor);
assembler.GotoIf(assembler.IsSetWord32(bit_field, mask), &with_constructor); GotoIf(IsSetWord32(bit_field, mask), &with_constructor);
bound_function_map.Bind(assembler.LoadContextElement( bound_function_map.Bind(LoadContextElement(
native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX)); native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX));
assembler.Goto(&map_done); Goto(&map_done);
assembler.Bind(&with_constructor); Bind(&with_constructor);
bound_function_map.Bind(assembler.LoadContextElement( bound_function_map.Bind(LoadContextElement(
native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX)); native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX));
assembler.Goto(&map_done); Goto(&map_done);
assembler.Bind(&map_done); Bind(&map_done);
// Verify that __proto__ matches that of a the target bound function. // Verify that __proto__ matches that of a the target bound function.
assembler.Comment("Verify that __proto__ matches target bound function"); Comment("Verify that __proto__ matches target bound function");
Node* prototype = assembler.LoadMapPrototype(receiver_map); Node* prototype = LoadMapPrototype(receiver_map);
Node* expected_prototype = Node* expected_prototype = LoadMapPrototype(bound_function_map.value());
assembler.LoadMapPrototype(bound_function_map.value()); GotoIf(WordNotEqual(prototype, expected_prototype), &slow);
assembler.GotoIf(assembler.WordNotEqual(prototype, expected_prototype),
&slow);
// Allocate the arguments array. // Allocate the arguments array.
assembler.Comment("Allocate the arguments array"); Comment("Allocate the arguments array");
Variable argument_array(&assembler, MachineRepresentation::kTagged); Variable argument_array(this, MachineRepresentation::kTagged);
Label empty_arguments(&assembler); Label empty_arguments(this);
Label arguments_done(&assembler, &argument_array); Label arguments_done(this, &argument_array);
assembler.GotoIf( GotoIf(Uint32LessThanOrEqual(argc, Int32Constant(1)), &empty_arguments);
assembler.Uint32LessThanOrEqual(argc, assembler.Int32Constant(1)), Node* elements_length = ChangeUint32ToWord(Int32Sub(argc, Int32Constant(1)));
&empty_arguments); Node* elements = AllocateFixedArray(FAST_ELEMENTS, elements_length);
Node* elements_length = assembler.ChangeUint32ToWord( Variable index(this, MachineType::PointerRepresentation());
assembler.Int32Sub(argc, assembler.Int32Constant(1))); index.Bind(IntPtrConstant(0));
Node* elements = assembler.AllocateFixedArray(FAST_ELEMENTS, elements_length); VariableList foreach_vars({&index}, zone());
Variable index(&assembler, MachineType::PointerRepresentation());
index.Bind(assembler.IntPtrConstant(0));
CodeStubAssembler::VariableList foreach_vars({&index}, assembler.zone());
args.ForEach(foreach_vars, args.ForEach(foreach_vars,
[&assembler, elements, &index](compiler::Node* arg) { [this, elements, &index](Node* arg) {
assembler.StoreFixedArrayElement(elements, index.value(), arg); StoreFixedArrayElement(elements, index.value(), arg);
assembler.Increment(index); Increment(index);
}, },
assembler.IntPtrConstant(1)); IntPtrConstant(1));
argument_array.Bind(elements); argument_array.Bind(elements);
assembler.Goto(&arguments_done); Goto(&arguments_done);
assembler.Bind(&empty_arguments); Bind(&empty_arguments);
argument_array.Bind(assembler.EmptyFixedArrayConstant()); argument_array.Bind(EmptyFixedArrayConstant());
assembler.Goto(&arguments_done); Goto(&arguments_done);
assembler.Bind(&arguments_done); Bind(&arguments_done);
// Determine bound receiver. // Determine bound receiver.
assembler.Comment("Determine bound receiver"); Comment("Determine bound receiver");
Variable bound_receiver(&assembler, MachineRepresentation::kTagged); Variable bound_receiver(this, MachineRepresentation::kTagged);
Label has_receiver(&assembler); Label has_receiver(this);
Label receiver_done(&assembler, &bound_receiver); Label receiver_done(this, &bound_receiver);
assembler.GotoIf(assembler.Word32NotEqual(argc, assembler.Int32Constant(0)), GotoIf(Word32NotEqual(argc, Int32Constant(0)), &has_receiver);
&has_receiver); bound_receiver.Bind(UndefinedConstant());
bound_receiver.Bind(assembler.UndefinedConstant()); Goto(&receiver_done);
assembler.Goto(&receiver_done);
Bind(&has_receiver);
assembler.Bind(&has_receiver);
bound_receiver.Bind(args.AtIndex(0)); bound_receiver.Bind(args.AtIndex(0));
assembler.Goto(&receiver_done); Goto(&receiver_done);
assembler.Bind(&receiver_done); Bind(&receiver_done);
// Allocate the resulting bound function. // Allocate the resulting bound function.
assembler.Comment("Allocate the resulting bound function"); Comment("Allocate the resulting bound function");
Node* bound_function = assembler.Allocate(JSBoundFunction::kSize); Node* bound_function = Allocate(JSBoundFunction::kSize);
assembler.StoreMapNoWriteBarrier(bound_function, bound_function_map.value()); StoreMapNoWriteBarrier(bound_function, bound_function_map.value());
assembler.StoreObjectFieldNoWriteBarrier( StoreObjectFieldNoWriteBarrier(
bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver); bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver);
assembler.StoreObjectFieldNoWriteBarrier(bound_function, StoreObjectFieldNoWriteBarrier(bound_function,
JSBoundFunction::kBoundThisOffset, JSBoundFunction::kBoundThisOffset,
bound_receiver.value()); bound_receiver.value());
assembler.StoreObjectFieldNoWriteBarrier( StoreObjectFieldNoWriteBarrier(bound_function,
bound_function, JSBoundFunction::kBoundArgumentsOffset, JSBoundFunction::kBoundArgumentsOffset,
argument_array.value()); argument_array.value());
Node* empty_fixed_array = assembler.EmptyFixedArrayConstant(); Node* empty_fixed_array = EmptyFixedArrayConstant();
assembler.StoreObjectFieldNoWriteBarrier( StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kPropertiesOffset,
bound_function, JSObject::kPropertiesOffset, empty_fixed_array); empty_fixed_array);
assembler.StoreObjectFieldNoWriteBarrier( StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kElementsOffset,
bound_function, JSObject::kElementsOffset, empty_fixed_array); empty_fixed_array);
args.PopAndReturn(bound_function); args.PopAndReturn(bound_function);
assembler.Bind(&slow); Bind(&slow);
Node* target = assembler.LoadFromFrame( Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
StandardFrameConstants::kFunctionOffset, MachineType::TaggedPointer()); MachineType::TaggedPointer());
assembler.TailCallStub( TailCallStub(CodeFactory::FunctionPrototypeBind(isolate()), context, target,
CodeFactory::FunctionPrototypeBind(assembler.isolate()), context, target, new_target, argc);
new_target, argc);
} }
// TODO(verwaest): This is a temporary helper until the FastFunctionBind stub // TODO(verwaest): This is a temporary helper until the FastFunctionBind stub
...@@ -477,16 +455,12 @@ BUILTIN(FunctionPrototypeToString) { ...@@ -477,16 +455,12 @@ BUILTIN(FunctionPrototypeToString) {
} }
// ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V ) // ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V )
void Builtins::Generate_FunctionPrototypeHasInstance( TF_BUILTIN(FunctionPrototypeHasInstance, CodeStubAssembler) {
compiler::CodeAssemblerState* state) { Node* f = Parameter(0);
using compiler::Node; Node* v = Parameter(1);
CodeStubAssembler assembler(state); Node* context = Parameter(4);
Node* result = OrdinaryHasInstance(context, f, v);
Node* f = assembler.Parameter(0); Return(result);
Node* v = assembler.Parameter(1);
Node* context = assembler.Parameter(4);
Node* result = assembler.OrdinaryHasInstance(context, f, v);
assembler.Return(result);
} }
} // namespace internal } // namespace internal
......
...@@ -104,110 +104,98 @@ BUILTIN(GlobalEval) { ...@@ -104,110 +104,98 @@ BUILTIN(GlobalEval) {
} }
// ES6 section 18.2.2 isFinite ( number ) // ES6 section 18.2.2 isFinite ( number )
void Builtins::Generate_GlobalIsFinite(compiler::CodeAssemblerState* state) { TF_BUILTIN(GlobalIsFinite, CodeStubAssembler) {
typedef CodeStubAssembler::Label Label; Node* context = Parameter(4);
typedef compiler::Node Node;
typedef CodeStubAssembler::Variable Variable;
CodeStubAssembler assembler(state);
Node* context = assembler.Parameter(4); Label return_true(this), return_false(this);
Label return_true(&assembler), return_false(&assembler);
// We might need to loop once for ToNumber conversion. // We might need to loop once for ToNumber conversion.
Variable var_num(&assembler, MachineRepresentation::kTagged); Variable var_num(this, MachineRepresentation::kTagged);
Label loop(&assembler, &var_num); Label loop(this, &var_num);
var_num.Bind(assembler.Parameter(1)); var_num.Bind(Parameter(1));
assembler.Goto(&loop); Goto(&loop);
assembler.Bind(&loop); Bind(&loop);
{ {
// Load the current {num} value.
Node* num = var_num.value(); Node* num = var_num.value();
// Check if {num} is a Smi or a HeapObject. // Check if {num} is a Smi or a HeapObject.
assembler.GotoIf(assembler.TaggedIsSmi(num), &return_true); GotoIf(TaggedIsSmi(num), &return_true);
// Check if {num} is a HeapNumber. // Check if {num} is a HeapNumber.
Label if_numisheapnumber(&assembler), Label if_numisheapnumber(this),
if_numisnotheapnumber(&assembler, Label::kDeferred); if_numisnotheapnumber(this, Label::kDeferred);
assembler.Branch(assembler.IsHeapNumberMap(assembler.LoadMap(num)), Branch(IsHeapNumberMap(LoadMap(num)), &if_numisheapnumber,
&if_numisheapnumber, &if_numisnotheapnumber); &if_numisnotheapnumber);
assembler.Bind(&if_numisheapnumber); Bind(&if_numisheapnumber);
{ {
// Check if {num} contains a finite, non-NaN value. // Check if {num} contains a finite, non-NaN value.
Node* num_value = assembler.LoadHeapNumberValue(num); Node* num_value = LoadHeapNumberValue(num);
assembler.BranchIfFloat64IsNaN(assembler.Float64Sub(num_value, num_value), BranchIfFloat64IsNaN(Float64Sub(num_value, num_value), &return_false,
&return_false, &return_true); &return_true);
} }
assembler.Bind(&if_numisnotheapnumber); Bind(&if_numisnotheapnumber);
{ {
// Need to convert {num} to a Number first. // Need to convert {num} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(assembler.isolate()); Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_num.Bind(assembler.CallStub(callable, context, num)); var_num.Bind(CallStub(callable, context, num));
assembler.Goto(&loop); Goto(&loop);
} }
} }
assembler.Bind(&return_true); Bind(&return_true);
assembler.Return(assembler.BooleanConstant(true)); Return(BooleanConstant(true));
assembler.Bind(&return_false); Bind(&return_false);
assembler.Return(assembler.BooleanConstant(false)); Return(BooleanConstant(false));
} }
// ES6 section 18.2.3 isNaN ( number ) // ES6 section 18.2.3 isNaN ( number )
void Builtins::Generate_GlobalIsNaN(compiler::CodeAssemblerState* state) { TF_BUILTIN(GlobalIsNaN, CodeStubAssembler) {
typedef CodeStubAssembler::Label Label; Node* context = Parameter(4);
typedef compiler::Node Node;
typedef CodeStubAssembler::Variable Variable;
CodeStubAssembler assembler(state);
Node* context = assembler.Parameter(4);
Label return_true(&assembler), return_false(&assembler); Label return_true(this), return_false(this);
// We might need to loop once for ToNumber conversion. // We might need to loop once for ToNumber conversion.
Variable var_num(&assembler, MachineRepresentation::kTagged); Variable var_num(this, MachineRepresentation::kTagged);
Label loop(&assembler, &var_num); Label loop(this, &var_num);
var_num.Bind(assembler.Parameter(1)); var_num.Bind(Parameter(1));
assembler.Goto(&loop); Goto(&loop);
assembler.Bind(&loop); Bind(&loop);
{ {
// Load the current {num} value.
Node* num = var_num.value(); Node* num = var_num.value();
// Check if {num} is a Smi or a HeapObject. // Check if {num} is a Smi or a HeapObject.
assembler.GotoIf(assembler.TaggedIsSmi(num), &return_false); GotoIf(TaggedIsSmi(num), &return_false);
// Check if {num} is a HeapNumber. // Check if {num} is a HeapNumber.
Label if_numisheapnumber(&assembler), Label if_numisheapnumber(this),
if_numisnotheapnumber(&assembler, Label::kDeferred); if_numisnotheapnumber(this, Label::kDeferred);
assembler.Branch(assembler.IsHeapNumberMap(assembler.LoadMap(num)), Branch(IsHeapNumberMap(LoadMap(num)), &if_numisheapnumber,
&if_numisheapnumber, &if_numisnotheapnumber); &if_numisnotheapnumber);
assembler.Bind(&if_numisheapnumber); Bind(&if_numisheapnumber);
{ {
// Check if {num} contains a NaN. // Check if {num} contains a NaN.
Node* num_value = assembler.LoadHeapNumberValue(num); Node* num_value = LoadHeapNumberValue(num);
assembler.BranchIfFloat64IsNaN(num_value, &return_true, &return_false); BranchIfFloat64IsNaN(num_value, &return_true, &return_false);
} }
assembler.Bind(&if_numisnotheapnumber); Bind(&if_numisnotheapnumber);
{ {
// Need to convert {num} to a Number first. // Need to convert {num} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(assembler.isolate()); Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_num.Bind(assembler.CallStub(callable, context, num)); var_num.Bind(CallStub(callable, context, num));
assembler.Goto(&loop); Goto(&loop);
} }
} }
assembler.Bind(&return_true); Bind(&return_true);
assembler.Return(assembler.BooleanConstant(true)); Return(BooleanConstant(true));
assembler.Bind(&return_false); Bind(&return_false);
assembler.Return(assembler.BooleanConstant(false)); Return(BooleanConstant(false));
} }
} // namespace internal } // namespace internal
......
...@@ -56,190 +56,150 @@ void Builtins::Generate_StackCheck(MacroAssembler* masm) { ...@@ -56,190 +56,150 @@ void Builtins::Generate_StackCheck(MacroAssembler* masm) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// TurboFan support builtins. // TurboFan support builtins.
void Builtins::Generate_CopyFastSmiOrObjectElements( TF_BUILTIN(CopyFastSmiOrObjectElements, CodeStubAssembler) {
compiler::CodeAssemblerState* state) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef CopyFastSmiOrObjectElementsDescriptor Descriptor; typedef CopyFastSmiOrObjectElementsDescriptor Descriptor;
CodeStubAssembler assembler(state);
Node* object = assembler.Parameter(Descriptor::kObject); Node* object = Parameter(Descriptor::kObject);
// Load the {object}s elements. // Load the {object}s elements.
Node* source = assembler.LoadObjectField(object, JSObject::kElementsOffset); Node* source = LoadObjectField(object, JSObject::kElementsOffset);
CodeStubAssembler::ParameterMode mode = assembler.OptimalParameterMode(); ParameterMode mode = OptimalParameterMode();
Node* length = assembler.TaggedToParameter( Node* length = TaggedToParameter(LoadFixedArrayBaseLength(source), mode);
assembler.LoadFixedArrayBaseLength(source), mode);
// Check if we can allocate in new space. // Check if we can allocate in new space.
ElementsKind kind = FAST_ELEMENTS; ElementsKind kind = FAST_ELEMENTS;
int max_elements = FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind); int max_elements = FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind);
Label if_newspace(&assembler), if_oldspace(&assembler); Label if_newspace(this), if_oldspace(this);
assembler.Branch( Branch(UintPtrOrSmiLessThan(length, IntPtrOrSmiConstant(max_elements, mode),
assembler.UintPtrOrSmiLessThan( mode),
length, assembler.IntPtrOrSmiConstant(max_elements, mode), mode), &if_newspace, &if_oldspace);
&if_newspace, &if_oldspace);
assembler.Bind(&if_newspace); Bind(&if_newspace);
{ {
Node* target = assembler.AllocateFixedArray(kind, length, mode); Node* target = AllocateFixedArray(kind, length, mode);
assembler.CopyFixedArrayElements(kind, source, target, length, CopyFixedArrayElements(kind, source, target, length, SKIP_WRITE_BARRIER,
SKIP_WRITE_BARRIER, mode); mode);
assembler.StoreObjectField(object, JSObject::kElementsOffset, target); StoreObjectField(object, JSObject::kElementsOffset, target);
assembler.Return(target); Return(target);
} }
assembler.Bind(&if_oldspace); Bind(&if_oldspace);
{ {
Node* target = assembler.AllocateFixedArray(kind, length, mode, Node* target = AllocateFixedArray(kind, length, mode, kPretenured);
CodeStubAssembler::kPretenured); CopyFixedArrayElements(kind, source, target, length, UPDATE_WRITE_BARRIER,
assembler.CopyFixedArrayElements(kind, source, target, length, mode);
UPDATE_WRITE_BARRIER, mode); StoreObjectField(object, JSObject::kElementsOffset, target);
assembler.StoreObjectField(object, JSObject::kElementsOffset, target); Return(target);
assembler.Return(target);
} }
} }
void Builtins::Generate_GrowFastDoubleElements( TF_BUILTIN(GrowFastDoubleElements, CodeStubAssembler) {
compiler::CodeAssemblerState* state) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef GrowArrayElementsDescriptor Descriptor; typedef GrowArrayElementsDescriptor Descriptor;
CodeStubAssembler assembler(state);
Node* object = assembler.Parameter(Descriptor::kObject); Node* object = Parameter(Descriptor::kObject);
Node* key = assembler.Parameter(Descriptor::kKey); Node* key = Parameter(Descriptor::kKey);
Node* context = assembler.Parameter(Descriptor::kContext); Node* context = Parameter(Descriptor::kContext);
Label runtime(&assembler, CodeStubAssembler::Label::kDeferred); Label runtime(this, Label::kDeferred);
Node* elements = assembler.LoadElements(object); Node* elements = LoadElements(object);
elements = assembler.TryGrowElementsCapacity( elements = TryGrowElementsCapacity(object, elements, FAST_DOUBLE_ELEMENTS,
object, elements, FAST_DOUBLE_ELEMENTS, key, &runtime); key, &runtime);
assembler.Return(elements); Return(elements);
assembler.Bind(&runtime); Bind(&runtime);
assembler.TailCallRuntime(Runtime::kGrowArrayElements, context, object, key); TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
} }
void Builtins::Generate_GrowFastSmiOrObjectElements( TF_BUILTIN(GrowFastSmiOrObjectElements, CodeStubAssembler) {
compiler::CodeAssemblerState* state) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef GrowArrayElementsDescriptor Descriptor; typedef GrowArrayElementsDescriptor Descriptor;
CodeStubAssembler assembler(state);
Node* object = assembler.Parameter(Descriptor::kObject); Node* object = Parameter(Descriptor::kObject);
Node* key = assembler.Parameter(Descriptor::kKey); Node* key = Parameter(Descriptor::kKey);
Node* context = assembler.Parameter(Descriptor::kContext); Node* context = Parameter(Descriptor::kContext);
Label runtime(&assembler, CodeStubAssembler::Label::kDeferred); Label runtime(this, Label::kDeferred);
Node* elements = assembler.LoadElements(object); Node* elements = LoadElements(object);
elements = assembler.TryGrowElementsCapacity(object, elements, FAST_ELEMENTS, elements =
key, &runtime); TryGrowElementsCapacity(object, elements, FAST_ELEMENTS, key, &runtime);
assembler.Return(elements); Return(elements);
assembler.Bind(&runtime); Bind(&runtime);
assembler.TailCallRuntime(Runtime::kGrowArrayElements, context, object, key); TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
} }
namespace { TF_BUILTIN(NewUnmappedArgumentsElements, CodeStubAssembler) {
typedef NewArgumentsElementsDescriptor Descriptor;
void Generate_NewArgumentsElements(CodeStubAssembler* assembler, Node* frame = Parameter(Descriptor::kFrame);
compiler::Node* frame, Node* length = SmiToWord(Parameter(Descriptor::kLength));
compiler::Node* length) {
typedef CodeStubAssembler::Label Label;
typedef CodeStubAssembler::Variable Variable;
typedef compiler::Node Node;
// Check if we can allocate in new space. // Check if we can allocate in new space.
ElementsKind kind = FAST_ELEMENTS; ElementsKind kind = FAST_ELEMENTS;
int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind); int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind);
Label if_newspace(assembler), if_oldspace(assembler, Label::kDeferred); Label if_newspace(this), if_oldspace(this, Label::kDeferred);
assembler->Branch(assembler->IntPtrLessThan( Branch(IntPtrLessThan(length, IntPtrConstant(max_elements)), &if_newspace,
length, assembler->IntPtrConstant(max_elements)), &if_oldspace);
&if_newspace, &if_oldspace);
assembler->Bind(&if_newspace); Bind(&if_newspace);
{ {
// Prefer EmptyFixedArray in case of non-positive {length} (the {length} // Prefer EmptyFixedArray in case of non-positive {length} (the {length}
// can be negative here for rest parameters). // can be negative here for rest parameters).
Label if_empty(assembler), if_notempty(assembler); Label if_empty(this), if_notempty(this);
assembler->Branch( Branch(IntPtrLessThanOrEqual(length, IntPtrConstant(0)), &if_empty,
assembler->IntPtrLessThanOrEqual(length, assembler->IntPtrConstant(0)), &if_notempty);
&if_empty, &if_notempty);
assembler->Bind(&if_empty); Bind(&if_empty);
assembler->Return(assembler->EmptyFixedArrayConstant()); Return(EmptyFixedArrayConstant());
assembler->Bind(&if_notempty); Bind(&if_notempty);
{ {
// Allocate a FixedArray in new space. // Allocate a FixedArray in new space.
Node* result = assembler->AllocateFixedArray(kind, length); Node* result = AllocateFixedArray(kind, length);
// Compute the effective {offset} into the {frame}. // Compute the effective {offset} into the {frame}.
Node* offset = assembler->IntPtrAdd(length, assembler->IntPtrConstant(1)); Node* offset = IntPtrAdd(length, IntPtrConstant(1));
// Copy the parameters from {frame} (starting at {offset}) to {result}. // Copy the parameters from {frame} (starting at {offset}) to {result}.
Variable var_index(assembler, MachineType::PointerRepresentation()); Variable var_index(this, MachineType::PointerRepresentation());
Label loop(assembler, &var_index), done_loop(assembler); Label loop(this, &var_index), done_loop(this);
var_index.Bind(assembler->IntPtrConstant(0)); var_index.Bind(IntPtrConstant(0));
assembler->Goto(&loop); Goto(&loop);
assembler->Bind(&loop); Bind(&loop);
{ {
// Load the current {index}. // Load the current {index}.
Node* index = var_index.value(); Node* index = var_index.value();
// Check if we are done. // Check if we are done.
assembler->GotoIf(assembler->WordEqual(index, length), &done_loop); GotoIf(WordEqual(index, length), &done_loop);
// Load the parameter at the given {index}. // Load the parameter at the given {index}.
Node* value = assembler->Load( Node* value = Load(MachineType::AnyTagged(), frame,
MachineType::AnyTagged(), frame, WordShl(IntPtrSub(offset, index),
assembler->WordShl(assembler->IntPtrSub(offset, index), IntPtrConstant(kPointerSizeLog2)));
assembler->IntPtrConstant(kPointerSizeLog2)));
// Store the {value} into the {result}. // Store the {value} into the {result}.
assembler->StoreFixedArrayElement(result, index, value, StoreFixedArrayElement(result, index, value, SKIP_WRITE_BARRIER);
SKIP_WRITE_BARRIER);
// Continue with next {index}. // Continue with next {index}.
var_index.Bind( var_index.Bind(IntPtrAdd(index, IntPtrConstant(1)));
assembler->IntPtrAdd(index, assembler->IntPtrConstant(1))); Goto(&loop);
assembler->Goto(&loop);
} }
assembler->Bind(&done_loop); Bind(&done_loop);
assembler->Return(result); Return(result);
} }
} }
assembler->Bind(&if_oldspace); Bind(&if_oldspace);
{ {
// Allocate in old space (or large object space). // Allocate in old space (or large object space).
assembler->TailCallRuntime( TailCallRuntime(Runtime::kNewArgumentsElements, NoContextConstant(),
Runtime::kNewArgumentsElements, assembler->NoContextConstant(), BitcastWordToTagged(frame), SmiFromWord(length));
assembler->BitcastWordToTagged(frame), assembler->SmiFromWord(length));
} }
} }
} // namespace TF_BUILTIN(ReturnReceiver, CodeStubAssembler) { Return(Parameter(0)); }
void Builtins::Generate_NewUnmappedArgumentsElements(
compiler::CodeAssemblerState* state) {
typedef compiler::Node Node;
typedef NewArgumentsElementsDescriptor Descriptor;
CodeStubAssembler assembler(state);
Node* frame = assembler.Parameter(Descriptor::kFrame);
Node* length = assembler.Parameter(Descriptor::kLength);
Generate_NewArgumentsElements(&assembler, frame, assembler.SmiToWord(length));
}
void Builtins::Generate_ReturnReceiver(compiler::CodeAssemblerState* state) {
CodeStubAssembler assembler(state);
assembler.Return(assembler.Parameter(0));
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -13,10 +13,6 @@ ...@@ -13,10 +13,6 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
typedef compiler::Node Node;
typedef CodeStubAssembler::ParameterMode ParameterMode;
typedef compiler::CodeAssemblerState CodeAssemblerState;
Node* PromiseBuiltinsAssembler::AllocateJSPromise(Node* context) { Node* PromiseBuiltinsAssembler::AllocateJSPromise(Node* context) {
Node* const native_context = LoadNativeContext(context); Node* const native_context = LoadNativeContext(context);
Node* const promise_fun = Node* const promise_fun =
......
...@@ -10,6 +10,24 @@ ...@@ -10,6 +10,24 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
using compiler::Node;
class SharedArrayBufferBuiltinsAssembler : public CodeStubAssembler {
public:
explicit SharedArrayBufferBuiltinsAssembler(
compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void ValidateSharedTypedArray(Node* tagged, Node* context,
Node** out_instance_type,
Node** out_backing_store);
Node* ConvertTaggedAtomicIndexToWord32(Node* tagged, Node* context,
Node** number_index);
void ValidateAtomicIndex(Node* index_word, Node* array_length_word,
Node* context);
};
// ES7 sharedmem 6.3.4.1 get SharedArrayBuffer.prototype.byteLength // ES7 sharedmem 6.3.4.1 get SharedArrayBuffer.prototype.byteLength
BUILTIN(SharedArrayBufferPrototypeGetByteLength) { BUILTIN(SharedArrayBufferPrototypeGetByteLength) {
HandleScope scope(isolate); HandleScope scope(isolate);
...@@ -25,325 +43,296 @@ BUILTIN(SharedArrayBufferPrototypeGetByteLength) { ...@@ -25,325 +43,296 @@ BUILTIN(SharedArrayBufferPrototypeGetByteLength) {
return array_buffer->byte_length(); return array_buffer->byte_length();
} }
namespace { void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray(
Node* tagged, Node* context, Node** out_instance_type,
void ValidateSharedTypedArray(CodeStubAssembler* a, compiler::Node* tagged, Node** out_backing_store) {
compiler::Node* context, Label not_float_or_clamped(this), invalid(this);
compiler::Node** out_instance_type,
compiler::Node** out_backing_store) {
using compiler::Node;
CodeStubAssembler::Label is_smi(a), not_smi(a), is_typed_array(a),
not_typed_array(a), is_shared(a), not_shared(a), is_float_or_clamped(a),
not_float_or_clamped(a), invalid(a);
// Fail if it is not a heap object. // Fail if it is not a heap object.
a->Branch(a->TaggedIsSmi(tagged), &is_smi, &not_smi); GotoIf(TaggedIsSmi(tagged), &invalid);
a->Bind(&is_smi);
a->Goto(&invalid);
// Fail if the array's instance type is not JSTypedArray. // Fail if the array's instance type is not JSTypedArray.
a->Bind(&not_smi); GotoIf(Word32NotEqual(LoadInstanceType(tagged),
a->Branch(a->Word32Equal(a->LoadInstanceType(tagged), Int32Constant(JS_TYPED_ARRAY_TYPE)),
a->Int32Constant(JS_TYPED_ARRAY_TYPE)), &invalid);
&is_typed_array, &not_typed_array);
a->Bind(&not_typed_array);
a->Goto(&invalid);
// Fail if the array's JSArrayBuffer is not shared. // Fail if the array's JSArrayBuffer is not shared.
a->Bind(&is_typed_array); Node* array_buffer = LoadObjectField(tagged, JSTypedArray::kBufferOffset);
Node* array_buffer = a->LoadObjectField(tagged, JSTypedArray::kBufferOffset); Node* bitfield = LoadObjectField(array_buffer, JSArrayBuffer::kBitFieldOffset,
Node* is_buffer_shared = MachineType::Uint32());
a->IsSetWord32<JSArrayBuffer::IsShared>(a->LoadObjectField( GotoIfNot(IsSetWord32<JSArrayBuffer::IsShared>(bitfield), &invalid);
array_buffer, JSArrayBuffer::kBitFieldOffset, MachineType::Uint32()));
a->Branch(is_buffer_shared, &is_shared, &not_shared);
a->Bind(&not_shared);
a->Goto(&invalid);
// Fail if the array's element type is float32, float64 or clamped. // Fail if the array's element type is float32, float64 or clamped.
a->Bind(&is_shared); Node* elements_instance_type =
Node* elements_instance_type = a->LoadInstanceType( LoadInstanceType(LoadObjectField(tagged, JSObject::kElementsOffset));
a->LoadObjectField(tagged, JSObject::kElementsOffset));
STATIC_ASSERT(FIXED_INT8_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); STATIC_ASSERT(FIXED_INT8_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_INT16_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); STATIC_ASSERT(FIXED_INT16_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_INT32_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); STATIC_ASSERT(FIXED_INT32_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_UINT8_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); STATIC_ASSERT(FIXED_UINT8_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_UINT16_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); STATIC_ASSERT(FIXED_UINT16_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_UINT32_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); STATIC_ASSERT(FIXED_UINT32_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
a->Branch(a->Int32LessThan(elements_instance_type, Branch(Int32LessThan(elements_instance_type,
a->Int32Constant(FIXED_FLOAT32_ARRAY_TYPE)), Int32Constant(FIXED_FLOAT32_ARRAY_TYPE)),
&not_float_or_clamped, &is_float_or_clamped); &not_float_or_clamped, &invalid);
a->Bind(&is_float_or_clamped);
a->Goto(&invalid); Bind(&invalid);
{
a->Bind(&invalid); CallRuntime(Runtime::kThrowNotIntegerSharedTypedArrayError, context,
a->CallRuntime(Runtime::kThrowNotIntegerSharedTypedArrayError, context, tagged);
tagged); Unreachable();
a->Unreachable(); }
a->Bind(&not_float_or_clamped); Bind(&not_float_or_clamped);
*out_instance_type = elements_instance_type; *out_instance_type = elements_instance_type;
Node* backing_store = Node* backing_store =
a->LoadObjectField(array_buffer, JSArrayBuffer::kBackingStoreOffset); LoadObjectField(array_buffer, JSArrayBuffer::kBackingStoreOffset);
Node* byte_offset = a->ChangeUint32ToWord(a->TruncateTaggedToWord32( Node* byte_offset = ChangeUint32ToWord(TruncateTaggedToWord32(
context, context, LoadObjectField(tagged, JSArrayBufferView::kByteOffsetOffset)));
a->LoadObjectField(tagged, JSArrayBufferView::kByteOffsetOffset)));
*out_backing_store = *out_backing_store =
a->IntPtrAdd(a->BitcastTaggedToWord(backing_store), byte_offset); IntPtrAdd(BitcastTaggedToWord(backing_store), byte_offset);
} }
// https://tc39.github.io/ecmascript_sharedmem/shmem.html#Atomics.ValidateAtomicAccess // https://tc39.github.io/ecmascript_sharedmem/shmem.html#Atomics.ValidateAtomicAccess
compiler::Node* ConvertTaggedAtomicIndexToWord32( Node* SharedArrayBufferBuiltinsAssembler::ConvertTaggedAtomicIndexToWord32(
CodeStubAssembler* a, compiler::Node* tagged, compiler::Node* context, Node* tagged, Node* context, Node** number_index) {
compiler::Node** number_index) { Variable var_result(this, MachineRepresentation::kWord32);
using compiler::Node;
CodeStubAssembler::Variable var_result(a, MachineRepresentation::kWord32); // TODO(jkummerow): Skip ToNumber call when |tagged| is a number already.
// Maybe this can be unified with other tagged-to-index conversions?
Callable to_number = CodeFactory::ToNumber(a->isolate()); // Why does this return an int32, and not an intptr?
*number_index = a->CallStub(to_number, context, tagged); // Why is there the additional |number_index| output parameter?
CodeStubAssembler::Label done(a, &var_result); Callable to_number = CodeFactory::ToNumber(isolate());
*number_index = CallStub(to_number, context, tagged);
CodeStubAssembler::Label if_numberissmi(a), if_numberisnotsmi(a); Label done(this, &var_result);
a->Branch(a->TaggedIsSmi(*number_index), &if_numberissmi, &if_numberisnotsmi);
Label if_numberissmi(this), if_numberisnotsmi(this);
a->Bind(&if_numberissmi); Branch(TaggedIsSmi(*number_index), &if_numberissmi, &if_numberisnotsmi);
Bind(&if_numberissmi);
{ {
var_result.Bind(a->SmiToWord32(*number_index)); var_result.Bind(SmiToWord32(*number_index));
a->Goto(&done); Goto(&done);
} }
a->Bind(&if_numberisnotsmi); Bind(&if_numberisnotsmi);
{ {
Node* number_index_value = a->LoadHeapNumberValue(*number_index); Node* number_index_value = LoadHeapNumberValue(*number_index);
Node* access_index = a->TruncateFloat64ToWord32(number_index_value); Node* access_index = TruncateFloat64ToWord32(number_index_value);
Node* test_index = a->ChangeInt32ToFloat64(access_index); Node* test_index = ChangeInt32ToFloat64(access_index);
CodeStubAssembler::Label if_indexesareequal(a), if_indexesarenotequal(a); Label if_indexesareequal(this), if_indexesarenotequal(this);
a->Branch(a->Float64Equal(number_index_value, test_index), Branch(Float64Equal(number_index_value, test_index), &if_indexesareequal,
&if_indexesareequal, &if_indexesarenotequal); &if_indexesarenotequal);
a->Bind(&if_indexesareequal); Bind(&if_indexesareequal);
{ {
var_result.Bind(access_index); var_result.Bind(access_index);
a->Goto(&done); Goto(&done);
} }
a->Bind(&if_indexesarenotequal); Bind(&if_indexesarenotequal);
a->CallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context); {
a->Unreachable(); CallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context);
Unreachable();
}
} }
a->Bind(&done); Bind(&done);
return var_result.value(); return var_result.value();
} }
void ValidateAtomicIndex(CodeStubAssembler* a, compiler::Node* index_word, void SharedArrayBufferBuiltinsAssembler::ValidateAtomicIndex(
compiler::Node* array_length_word, Node* index_word, Node* array_length_word, Node* context) {
compiler::Node* context) {
using compiler::Node;
// Check if the index is in bounds. If not, throw RangeError. // Check if the index is in bounds. If not, throw RangeError.
CodeStubAssembler::Label if_inbounds(a), if_notinbounds(a); Label check_passed(this);
// TODO(jkummerow): Use unsigned comparison instead of "i<0 || i>length". GotoIf(Uint32LessThan(index_word, array_length_word), &check_passed);
a->Branch(
a->Word32Or(a->Int32LessThan(index_word, a->Int32Constant(0)),
a->Int32GreaterThanOrEqual(index_word, array_length_word)),
&if_notinbounds, &if_inbounds);
a->Bind(&if_notinbounds);
a->CallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context);
a->Unreachable();
a->Bind(&if_inbounds);
}
} // anonymous namespace CallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context);
Unreachable();
void Builtins::Generate_AtomicsLoad(compiler::CodeAssemblerState* state) { Bind(&check_passed);
using compiler::Node; }
CodeStubAssembler a(state);
Node* array = a.Parameter(1); TF_BUILTIN(AtomicsLoad, SharedArrayBufferBuiltinsAssembler) {
Node* index = a.Parameter(2); Node* array = Parameter(1);
Node* context = a.Parameter(3 + 2); Node* index = Parameter(2);
Node* context = Parameter(3 + 2);
Node* instance_type; Node* instance_type;
Node* backing_store; Node* backing_store;
ValidateSharedTypedArray(&a, array, context, &instance_type, &backing_store); ValidateSharedTypedArray(array, context, &instance_type, &backing_store);
Node* index_integer; Node* index_integer;
Node* index_word32 = Node* index_word32 =
ConvertTaggedAtomicIndexToWord32(&a, index, context, &index_integer); ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
Node* array_length_word32 = a.TruncateTaggedToWord32( Node* array_length_word32 = TruncateTaggedToWord32(
context, a.LoadObjectField(array, JSTypedArray::kLengthOffset)); context, LoadObjectField(array, JSTypedArray::kLengthOffset));
ValidateAtomicIndex(&a, index_word32, array_length_word32, context); ValidateAtomicIndex(index_word32, array_length_word32, context);
Node* index_word = a.ChangeUint32ToWord(index_word32); Node* index_word = ChangeUint32ToWord(index_word32);
CodeStubAssembler::Label i8(&a), u8(&a), i16(&a), u16(&a), i32(&a), u32(&a), Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
other(&a); other(this);
int32_t case_values[] = { int32_t case_values[] = {
FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE,
FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE,
}; };
CodeStubAssembler::Label* case_labels[] = { Label* case_labels[] = {
&i8, &u8, &i16, &u16, &i32, &u32, &i8, &u8, &i16, &u16, &i32, &u32,
}; };
a.Switch(instance_type, &other, case_values, case_labels, Switch(instance_type, &other, case_values, case_labels,
arraysize(case_labels)); arraysize(case_labels));
a.Bind(&i8); Bind(&i8);
a.Return(a.SmiFromWord32( Return(SmiFromWord32(
a.AtomicLoad(MachineType::Int8(), backing_store, index_word))); AtomicLoad(MachineType::Int8(), backing_store, index_word)));
a.Bind(&u8); Bind(&u8);
a.Return(a.SmiFromWord32( Return(SmiFromWord32(
a.AtomicLoad(MachineType::Uint8(), backing_store, index_word))); AtomicLoad(MachineType::Uint8(), backing_store, index_word)));
a.Bind(&i16); Bind(&i16);
a.Return(a.SmiFromWord32(a.AtomicLoad(MachineType::Int16(), backing_store, Return(SmiFromWord32(
a.WordShl(index_word, 1)))); AtomicLoad(MachineType::Int16(), backing_store, WordShl(index_word, 1))));
a.Bind(&u16); Bind(&u16);
a.Return(a.SmiFromWord32(a.AtomicLoad(MachineType::Uint16(), backing_store, Return(SmiFromWord32(AtomicLoad(MachineType::Uint16(), backing_store,
a.WordShl(index_word, 1)))); WordShl(index_word, 1))));
a.Bind(&i32); Bind(&i32);
a.Return(a.ChangeInt32ToTagged(a.AtomicLoad( Return(ChangeInt32ToTagged(
MachineType::Int32(), backing_store, a.WordShl(index_word, 2)))); AtomicLoad(MachineType::Int32(), backing_store, WordShl(index_word, 2))));
a.Bind(&u32); Bind(&u32);
a.Return(a.ChangeUint32ToTagged(a.AtomicLoad( Return(ChangeUint32ToTagged(AtomicLoad(MachineType::Uint32(), backing_store,
MachineType::Uint32(), backing_store, a.WordShl(index_word, 2)))); WordShl(index_word, 2))));
// This shouldn't happen, we've already validated the type. // This shouldn't happen, we've already validated the type.
a.Bind(&other); Bind(&other);
a.Return(a.SmiConstant(0)); Unreachable();
} }
void Builtins::Generate_AtomicsStore(compiler::CodeAssemblerState* state) { TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) {
using compiler::Node; Node* array = Parameter(1);
CodeStubAssembler a(state); Node* index = Parameter(2);
Node* array = a.Parameter(1); Node* value = Parameter(3);
Node* index = a.Parameter(2); Node* context = Parameter(4 + 2);
Node* value = a.Parameter(3);
Node* context = a.Parameter(4 + 2);
Node* instance_type; Node* instance_type;
Node* backing_store; Node* backing_store;
ValidateSharedTypedArray(&a, array, context, &instance_type, &backing_store); ValidateSharedTypedArray(array, context, &instance_type, &backing_store);
Node* index_integer; Node* index_integer;
Node* index_word32 = Node* index_word32 =
ConvertTaggedAtomicIndexToWord32(&a, index, context, &index_integer); ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
Node* array_length_word32 = a.TruncateTaggedToWord32( Node* array_length_word32 = TruncateTaggedToWord32(
context, a.LoadObjectField(array, JSTypedArray::kLengthOffset)); context, LoadObjectField(array, JSTypedArray::kLengthOffset));
ValidateAtomicIndex(&a, index_word32, array_length_word32, context); ValidateAtomicIndex(index_word32, array_length_word32, context);
Node* index_word = a.ChangeUint32ToWord(index_word32); Node* index_word = ChangeUint32ToWord(index_word32);
Node* value_integer = a.ToInteger(context, value); Node* value_integer = ToInteger(context, value);
Node* value_word32 = a.TruncateTaggedToWord32(context, value_integer); Node* value_word32 = TruncateTaggedToWord32(context, value_integer);
CodeStubAssembler::Label u8(&a), u16(&a), u32(&a), other(&a); Label u8(this), u16(this), u32(this), other(this);
int32_t case_values[] = { int32_t case_values[] = {
FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE,
FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE,
}; };
CodeStubAssembler::Label* case_labels[] = { Label* case_labels[] = {
&u8, &u8, &u16, &u16, &u32, &u32, &u8, &u8, &u16, &u16, &u32, &u32,
}; };
a.Switch(instance_type, &other, case_values, case_labels, Switch(instance_type, &other, case_values, case_labels,
arraysize(case_labels)); arraysize(case_labels));
a.Bind(&u8); Bind(&u8);
a.AtomicStore(MachineRepresentation::kWord8, backing_store, index_word, AtomicStore(MachineRepresentation::kWord8, backing_store, index_word,
value_word32); value_word32);
a.Return(value_integer); Return(value_integer);
a.Bind(&u16); Bind(&u16);
a.AtomicStore(MachineRepresentation::kWord16, backing_store, AtomicStore(MachineRepresentation::kWord16, backing_store,
a.WordShl(index_word, 1), value_word32); WordShl(index_word, 1), value_word32);
a.Return(value_integer); Return(value_integer);
a.Bind(&u32); Bind(&u32);
a.AtomicStore(MachineRepresentation::kWord32, backing_store, AtomicStore(MachineRepresentation::kWord32, backing_store,
a.WordShl(index_word, 2), value_word32); WordShl(index_word, 2), value_word32);
a.Return(value_integer); Return(value_integer);
// This shouldn't happen, we've already validated the type. // This shouldn't happen, we've already validated the type.
a.Bind(&other); Bind(&other);
a.Return(a.SmiConstant(0)); Unreachable();
} }
void Builtins::Generate_AtomicsExchange(compiler::CodeAssemblerState* state) { TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) {
using compiler::Node; Node* array = Parameter(1);
CodeStubAssembler a(state); Node* index = Parameter(2);
Node* array = a.Parameter(1); Node* value = Parameter(3);
Node* index = a.Parameter(2); Node* context = Parameter(4 + 2);
Node* value = a.Parameter(3);
Node* context = a.Parameter(4 + 2);
Node* instance_type; Node* instance_type;
Node* backing_store; Node* backing_store;
ValidateSharedTypedArray(&a, array, context, &instance_type, &backing_store); ValidateSharedTypedArray(array, context, &instance_type, &backing_store);
Node* index_integer; Node* index_integer;
Node* index_word32 = Node* index_word32 =
ConvertTaggedAtomicIndexToWord32(&a, index, context, &index_integer); ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
Node* array_length_word32 = a.TruncateTaggedToWord32( Node* array_length_word32 = TruncateTaggedToWord32(
context, a.LoadObjectField(array, JSTypedArray::kLengthOffset)); context, LoadObjectField(array, JSTypedArray::kLengthOffset));
ValidateAtomicIndex(&a, index_word32, array_length_word32, context); ValidateAtomicIndex(index_word32, array_length_word32, context);
Node* value_integer = a.ToInteger(context, value); Node* value_integer = ToInteger(context, value);
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \ #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \
V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X
// Node* index_integer = a.ToInteger(context, index); Return(CallRuntime(Runtime::kAtomicsExchange, context, array, index_integer,
a.Return(a.CallRuntime(Runtime::kAtomicsExchange, context, array, value_integer));
index_integer, value_integer));
#else #else
Node* index_word = a.ChangeUint32ToWord(index_word32); Node* index_word = ChangeUint32ToWord(index_word32);
Node* value_word32 = a.TruncateTaggedToWord32(context, value_integer); Node* value_word32 = TruncateTaggedToWord32(context, value_integer);
CodeStubAssembler::Label i8(&a), u8(&a), i16(&a), u16(&a), i32(&a), u32(&a), Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
other(&a); other(this);
int32_t case_values[] = { int32_t case_values[] = {
FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE,
FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE,
}; };
CodeStubAssembler::Label* case_labels[] = { Label* case_labels[] = {
&i8, &u8, &i16, &u16, &i32, &u32, &i8, &u8, &i16, &u16, &i32, &u32,
}; };
a.Switch(instance_type, &other, case_values, case_labels, Switch(instance_type, &other, case_values, case_labels,
arraysize(case_labels)); arraysize(case_labels));
a.Bind(&i8); Bind(&i8);
a.Return(a.SmiFromWord32(a.AtomicExchange(MachineType::Int8(), backing_store, Return(SmiFromWord32(AtomicExchange(MachineType::Int8(), backing_store,
index_word, value_word32))); index_word, value_word32)));
a.Bind(&u8); Bind(&u8);
a.Return(a.SmiFromWord32(a.AtomicExchange(MachineType::Uint8(), backing_store, Return(SmiFromWord32(AtomicExchange(MachineType::Uint8(), backing_store,
index_word, value_word32))); index_word, value_word32)));
a.Bind(&i16); Bind(&i16);
a.Return(a.SmiFromWord32(a.AtomicExchange(MachineType::Int16(), backing_store, Return(SmiFromWord32(AtomicExchange(MachineType::Int16(), backing_store,
a.WordShl(index_word, 1), WordShl(index_word, 1), value_word32)));
value_word32)));
a.Bind(&u16); Bind(&u16);
a.Return(a.SmiFromWord32( Return(SmiFromWord32(AtomicExchange(MachineType::Uint16(), backing_store,
a.AtomicExchange(MachineType::Uint16(), backing_store, WordShl(index_word, 1), value_word32)));
a.WordShl(index_word, 1), value_word32)));
a.Bind(&i32); Bind(&i32);
a.Return(a.ChangeInt32ToTagged( Return(ChangeInt32ToTagged(AtomicExchange(MachineType::Int32(), backing_store,
a.AtomicExchange(MachineType::Int32(), backing_store, WordShl(index_word, 2),
a.WordShl(index_word, 2), value_word32))); value_word32)));
a.Bind(&u32); Bind(&u32);
a.Return(a.ChangeUint32ToTagged( Return(ChangeUint32ToTagged(
a.AtomicExchange(MachineType::Uint32(), backing_store, AtomicExchange(MachineType::Uint32(), backing_store,
a.WordShl(index_word, 2), value_word32))); WordShl(index_word, 2), value_word32)));
// This shouldn't happen, we've already validated the type. // This shouldn't happen, we've already validated the type.
a.Bind(&other); Bind(&other);
a.Return(a.SmiConstant(0)); Unreachable();
#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64
// || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X // || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X
} }
......
...@@ -68,48 +68,34 @@ BUILTIN(SymbolKeyFor) { ...@@ -68,48 +68,34 @@ BUILTIN(SymbolKeyFor) {
} }
// ES6 section 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint ) // ES6 section 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint )
void Builtins::Generate_SymbolPrototypeToPrimitive( TF_BUILTIN(SymbolPrototypeToPrimitive, CodeStubAssembler) {
compiler::CodeAssemblerState* state) { Node* receiver = Parameter(0);
typedef compiler::Node Node; Node* context = Parameter(4);
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(0); Node* result = ToThisValue(context, receiver, PrimitiveType::kSymbol,
Node* context = assembler.Parameter(4); "Symbol.prototype [ @@toPrimitive ]");
Return(result);
Node* result =
assembler.ToThisValue(context, receiver, PrimitiveType::kSymbol,
"Symbol.prototype [ @@toPrimitive ]");
assembler.Return(result);
} }
// ES6 section 19.4.3.2 Symbol.prototype.toString ( ) // ES6 section 19.4.3.2 Symbol.prototype.toString ( )
void Builtins::Generate_SymbolPrototypeToString( TF_BUILTIN(SymbolPrototypeToString, CodeStubAssembler) {
compiler::CodeAssemblerState* state) { Node* receiver = Parameter(0);
typedef compiler::Node Node; Node* context = Parameter(3);
CodeStubAssembler assembler(state);
Node* value = ToThisValue(context, receiver, PrimitiveType::kSymbol,
Node* receiver = assembler.Parameter(0); "Symbol.prototype.toString");
Node* context = assembler.Parameter(3); Node* result = CallRuntime(Runtime::kSymbolDescriptiveString, context, value);
Return(result);
Node* value = assembler.ToThisValue(context, receiver, PrimitiveType::kSymbol,
"Symbol.prototype.toString");
Node* result =
assembler.CallRuntime(Runtime::kSymbolDescriptiveString, context, value);
assembler.Return(result);
} }
// ES6 section 19.4.3.3 Symbol.prototype.valueOf ( ) // ES6 section 19.4.3.3 Symbol.prototype.valueOf ( )
void Builtins::Generate_SymbolPrototypeValueOf( TF_BUILTIN(SymbolPrototypeValueOf, CodeStubAssembler) {
compiler::CodeAssemblerState* state) { Node* receiver = Parameter(0);
typedef compiler::Node Node; Node* context = Parameter(3);
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(0);
Node* context = assembler.Parameter(3);
Node* result = assembler.ToThisValue( Node* result = ToThisValue(context, receiver, PrimitiveType::kSymbol,
context, receiver, PrimitiveType::kSymbol, "Symbol.prototype.valueOf"); "Symbol.prototype.valueOf");
assembler.Return(result); Return(result);
} }
} // namespace internal } // namespace internal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment