Commit c293bc01 authored by jgruber's avatar jgruber Committed by Commit Bot

[csa] Add and use ToInteger_Inline

This reduces reduces code size by 16 KB while keeping the fast path (in
which the given argument is already a smi) inlined and extracting
remaining logic to a stub call.

Change-Id: I531999c990519eef1247cc3785ad4b16164f7a5e
Reviewed-on: https://chromium-review.googlesource.com/833912Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50224}
parent 9c6bc7af
......@@ -1286,7 +1286,7 @@ class FastArraySliceCodeStubAssembler : public CodeStubAssembler {
TF_BUILTIN(FastArraySlice, FastArraySliceCodeStubAssembler) {
Node* const argc =
ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
Node* const context = Parameter(BuiltinDescriptor::kContext);
TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
Label slow(this, Label::kDeferred), fast_elements_kind(this);
CodeStubArguments args(this, argc);
......@@ -1358,8 +1358,8 @@ TF_BUILTIN(FastArraySlice, FastArraySliceCodeStubAssembler) {
// 5. Let relativeStart be ToInteger(start).
// 6. ReturnIfAbrupt(relativeStart).
Node* arg0 = args.GetOptionalArgumentValue(0, SmiConstant(0));
Node* relative_start = ToInteger(context, arg0);
TNode<Object> arg0 = CAST(args.GetOptionalArgumentValue(0, SmiConstant(0)));
Node* relative_start = ToInteger_Inline(context, arg0);
// 7. If relativeStart < 0, let k be max((len + relativeStart),0);
// else let k be min(relativeStart, len.value()).
......@@ -1377,11 +1377,12 @@ TF_BUILTIN(FastArraySlice, FastArraySliceCodeStubAssembler) {
// 8. If end is undefined, let relativeEnd be len;
// else let relativeEnd be ToInteger(end).
// 9. ReturnIfAbrupt(relativeEnd).
Node* end = args.GetOptionalArgumentValue(1, UndefinedConstant());
TNode<Object> end =
CAST(args.GetOptionalArgumentValue(1, UndefinedConstant()));
Label end_undefined(this), end_done(this);
VARIABLE(relative_end, MachineRepresentation::kTagged);
GotoIf(WordEqual(end, UndefinedConstant()), &end_undefined);
relative_end.Bind(ToInteger(context, end));
relative_end.Bind(ToInteger_Inline(context, end));
Goto(&end_done);
BIND(&end_undefined);
relative_end.Bind(len.value());
......
......@@ -330,7 +330,14 @@ TF_BUILTIN(ToInteger, CodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* input = Parameter(Descriptor::kArgument);
Return(ToInteger(context, input));
Return(ToInteger(context, input, kNoTruncation));
}
TF_BUILTIN(ToInteger_TruncateMinusZero, CodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* input = Parameter(Descriptor::kArgument);
Return(ToInteger(context, input, kTruncateMinusZero));
}
// ES6 section 7.1.13 ToObject (argument)
......
......@@ -190,6 +190,7 @@ namespace internal {
TFC(NumberToString, TypeConversion, 1) \
TFC(ToString, TypeConversion, 1) \
TFC(ToInteger, TypeConversion, 1) \
TFC(ToInteger_TruncateMinusZero, TypeConversion, 1) \
TFC(ToLength, TypeConversion, 1) \
TFC(ClassOf, Typeof, 1) \
TFC(Typeof, Typeof, 1) \
......
......@@ -213,7 +213,7 @@ TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) {
ValidateAtomicIndex(array, index_word32, context);
Node* index_word = ChangeUint32ToWord(index_word32);
Node* value_integer = ToInteger(context, value);
Node* value_integer = ToInteger_Inline(CAST(context), CAST(value));
Node* value_word32 = TruncateTaggedToWord32(context, value_integer);
#if DEBUG
......@@ -266,7 +266,7 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) {
ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
ValidateAtomicIndex(array, index_word32, context);
Node* value_integer = ToInteger(context, value);
Node* value_integer = ToInteger_Inline(CAST(context), CAST(value));
#if DEBUG
DebugSanityCheckAtomicIndex(array, index_word32, context);
......@@ -340,8 +340,8 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) {
ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
ValidateAtomicIndex(array, index_word32, context);
Node* old_value_integer = ToInteger(context, old_value);
Node* new_value_integer = ToInteger(context, new_value);
Node* old_value_integer = ToInteger_Inline(CAST(context), CAST(old_value));
Node* new_value_integer = ToInteger_Inline(CAST(context), CAST(new_value));
#if DEBUG
DebugSanityCheckAtomicIndex(array, index_word32, context);
......@@ -436,7 +436,7 @@ void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon(
ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
ValidateAtomicIndex(array, index_word32, context);
Node* value_integer = ToInteger(context, value);
Node* value_integer = ToInteger_Inline(CAST(context), CAST(value));
#if DEBUG
// In Debug mode, we re-validate the index as a sanity check because
......
......@@ -126,8 +126,8 @@ Node* StringBuiltinsAssembler::PointerToStringDataAtIndex(
void StringBuiltinsAssembler::ConvertAndBoundsCheckStartArgument(
Node* context, Variable* var_start, Node* start, Node* string_length) {
TNode<Object> const start_int =
ToInteger(context, start, CodeStubAssembler::kTruncateMinusZero);
TNode<Object> const start_int = ToInteger_Inline(
CAST(context), CAST(start), CodeStubAssembler::kTruncateMinusZero);
TNode<Smi> const zero = SmiConstant(0);
Label done(this);
......@@ -664,18 +664,19 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
// ES6 #sec-string.prototype.charat
TF_BUILTIN(StringPrototypeCharAt, CodeStubAssembler) {
Node* receiver = Parameter(Descriptor::kReceiver);
Node* position = Parameter(Descriptor::kPosition);
Node* context = Parameter(Descriptor::kContext);
TNode<Object> maybe_position = CAST(Parameter(Descriptor::kPosition));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
// Check that {receiver} is coercible to Object and convert it to a String.
receiver = ToThisString(context, receiver, "String.prototype.charAt");
// Convert the {position} to a Smi and check that it's in bounds of the
// {receiver}.
TNode<Number> position;
{
Label return_emptystring(this, Label::kDeferred);
position =
ToInteger(context, position, CodeStubAssembler::kTruncateMinusZero);
position = ToInteger_Inline(context, maybe_position,
CodeStubAssembler::kTruncateMinusZero);
GotoIfNot(TaggedIsSmi(position), &return_emptystring);
// Determine the actual length of the {receiver} String.
......@@ -693,11 +694,12 @@ TF_BUILTIN(StringPrototypeCharAt, CodeStubAssembler) {
}
// Load the character code at the {position} from the {receiver}.
CSA_ASSERT(this, IntPtrLessThan(SmiUntag(position),
TNode<Smi> position_smi = CAST(position);
CSA_ASSERT(this, IntPtrLessThan(SmiUntag(position_smi),
LoadStringLengthAsWord(receiver)));
CSA_ASSERT(this,
IntPtrGreaterThanOrEqual(SmiUntag(position), IntPtrConstant(0)));
Node* code = StringCharCodeAt(receiver, SmiUntag(position));
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(SmiUntag(position_smi),
IntPtrConstant(0)));
Node* code = StringCharCodeAt(receiver, SmiUntag(position_smi));
// And return the single character string with only that {code}.
Node* result = StringFromCharCode(code);
......@@ -707,18 +709,19 @@ TF_BUILTIN(StringPrototypeCharAt, CodeStubAssembler) {
// ES6 #sec-string.prototype.charcodeat
TF_BUILTIN(StringPrototypeCharCodeAt, CodeStubAssembler) {
Node* receiver = Parameter(Descriptor::kReceiver);
Node* position = Parameter(Descriptor::kPosition);
Node* context = Parameter(Descriptor::kContext);
TNode<Object> maybe_position = CAST(Parameter(Descriptor::kPosition));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
// Check that {receiver} is coercible to Object and convert it to a String.
receiver = ToThisString(context, receiver, "String.prototype.charCodeAt");
// Convert the {position} to a Smi and check that it's in bounds of the
// {receiver}.
TNode<Number> position;
{
Label return_nan(this, Label::kDeferred);
position =
ToInteger(context, position, CodeStubAssembler::kTruncateMinusZero);
position = ToInteger_Inline(context, maybe_position,
CodeStubAssembler::kTruncateMinusZero);
GotoIfNot(TaggedIsSmi(position), &return_nan);
// Determine the actual length of the {receiver} String.
......@@ -736,16 +739,16 @@ TF_BUILTIN(StringPrototypeCharCodeAt, CodeStubAssembler) {
}
// Load the character at the {position} from the {receiver}.
Node* value = StringCharCodeAt(receiver, SmiUntag(position));
Node* value = StringCharCodeAt(receiver, SmiUntag(CAST(position)));
Node* result = SmiFromWord32(value);
Return(result);
}
// ES6 #sec-string.prototype.codepointat
TF_BUILTIN(StringPrototypeCodePointAt, StringBuiltinsAssembler) {
Node* context = Parameter(Descriptor::kContext);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
Node* receiver = Parameter(Descriptor::kReceiver);
Node* position = Parameter(Descriptor::kPosition);
TNode<Object> maybe_position = CAST(Parameter(Descriptor::kPosition));
// Check that {receiver} is coercible to Object and convert it to a String.
receiver = ToThisString(context, receiver, "String.prototype.codePointAt");
......@@ -753,18 +756,19 @@ TF_BUILTIN(StringPrototypeCodePointAt, StringBuiltinsAssembler) {
// Convert the {position} to a Smi and check that it's in bounds of the
// {receiver}.
Label if_inbounds(this), if_outofbounds(this, Label::kDeferred);
position =
ToInteger(context, position, CodeStubAssembler::kTruncateMinusZero);
TNode<Number> position = ToInteger_Inline(
context, maybe_position, CodeStubAssembler::kTruncateMinusZero);
GotoIfNot(TaggedIsSmi(position), &if_outofbounds);
TNode<IntPtrT> untagged_position = SmiUntag(position);
TNode<IntPtrT> receiver_length = LoadStringLengthAsWord(receiver);
TNode<IntPtrT> untagged_position = SmiUntag(CAST(position));
TNode<IntPtrT> receiver_length = LoadStringLengthAsWord(CAST(receiver));
Branch(UintPtrLessThan(untagged_position, receiver_length), &if_inbounds,
&if_outofbounds);
BIND(&if_inbounds);
{
Node* value = LoadSurrogatePairAt(
receiver, receiver_length, untagged_position, UnicodeEncoding::UTF32);
Node* value =
LoadSurrogatePairAt(CAST(receiver), receiver_length, untagged_position,
UnicodeEncoding::UTF32);
Node* result = SmiFromWord32(value);
Return(result);
}
......@@ -1217,16 +1221,17 @@ TF_BUILTIN(StringPrototypeRepeat, StringBuiltinsAssembler) {
Label invalid_count(this), invalid_string_length(this),
return_emptystring(this);
Node* const context = Parameter(Descriptor::kContext);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
Node* const receiver = Parameter(Descriptor::kReceiver);
Node* const count = Parameter(Descriptor::kCount);
TNode<Object> count = CAST(Parameter(Descriptor::kCount));
Node* const string =
ToThisString(context, receiver, "String.prototype.repeat");
Node* const is_stringempty =
SmiEqual(LoadStringLengthAsSmi(string), SmiConstant(0));
VARIABLE(var_count, MachineRepresentation::kTagged,
ToInteger(context, count, CodeStubAssembler::kTruncateMinusZero));
VARIABLE(
var_count, MachineRepresentation::kTagged,
ToInteger_Inline(context, count, CodeStubAssembler::kTruncateMinusZero));
// Verifies a valid count and takes a fast path when the result will be an
// empty string.
......@@ -1713,8 +1718,8 @@ TF_BUILTIN(StringPrototypeSlice, StringBuiltinsAssembler) {
CodeStubArguments args(this, argc);
Node* const receiver = args.GetReceiver();
Node* const start = args.GetOptionalArgumentValue(kStart);
Node* const end = args.GetOptionalArgumentValue(kEnd);
Node* const context = Parameter(BuiltinDescriptor::kContext);
TNode<Object> end = CAST(args.GetOptionalArgumentValue(kEnd));
TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
TNode<Smi> const smi_zero = SmiConstant(0);
......@@ -1737,7 +1742,7 @@ TF_BUILTIN(StringPrototypeSlice, StringBuiltinsAssembler) {
// else let intEnd be ? ToInteger(end).
Node* const end_int =
ToInteger(context, end, CodeStubAssembler::kTruncateMinusZero);
ToInteger_Inline(context, end, CodeStubAssembler::kTruncateMinusZero);
// 7. If intEnd < 0, let to be max(len + intEnd, 0);
// otherwise let to be min(intEnd, len).
......@@ -1893,8 +1898,8 @@ TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) {
Node* const receiver = args.GetReceiver();
Node* const start = args.GetOptionalArgumentValue(kStartArg);
Node* const length = args.GetOptionalArgumentValue(kLengthArg);
Node* const context = Parameter(BuiltinDescriptor::kContext);
TNode<Object> length = CAST(args.GetOptionalArgumentValue(kLengthArg));
TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
Label out(this);
......@@ -1925,8 +1930,8 @@ TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) {
Goto(&if_issmi);
BIND(&if_isnotundefined);
var_length =
ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero);
var_length = ToInteger_Inline(context, length,
CodeStubAssembler::kTruncateMinusZero);
}
TVARIABLE(Smi, var_result_length);
......@@ -1984,7 +1989,7 @@ TNode<Smi> StringBuiltinsAssembler::ToSmiBetweenZeroAnd(
TVARIABLE(Smi, var_result);
TNode<Object> const value_int =
this->ToInteger(context, value, CodeStubAssembler::kTruncateMinusZero);
ToInteger_Inline(context, value, CodeStubAssembler::kTruncateMinusZero);
Label if_issmi(this), if_isnotsmi(this, Label::kDeferred);
Branch(TaggedIsSmi(value_int), &if_issmi, &if_isnotsmi);
......
......@@ -370,18 +370,18 @@ TF_BUILTIN(TypedArrayInitialize, TypedArrayBuiltinsAssembler) {
// ES6 #sec-typedarray-length
TF_BUILTIN(TypedArrayConstructByLength, TypedArrayBuiltinsAssembler) {
Node* holder = Parameter(Descriptor::kHolder);
Node* length = Parameter(Descriptor::kLength);
Node* element_size = Parameter(Descriptor::kElementSize);
Node* context = Parameter(Descriptor::kContext);
TNode<Object> maybe_length = CAST(Parameter(Descriptor::kLength));
TNode<Object> element_size = CAST(Parameter(Descriptor::kElementSize));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
CSA_ASSERT(this, IsJSTypedArray(holder));
CSA_ASSERT(this, TaggedIsPositiveSmi(element_size));
Node* initialize = TrueConstant();
Label invalid_length(this);
length = ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero);
TNode<Number> length = ToInteger_Inline(
context, maybe_length, CodeStubAssembler::kTruncateMinusZero);
// The maximum length of a TypedArray is MaxSmi().
// Note: this is not per spec, but rather a constraint of our current
// representation (which uses smi's).
......@@ -389,7 +389,7 @@ TF_BUILTIN(TypedArrayConstructByLength, TypedArrayBuiltinsAssembler) {
GotoIf(SmiLessThan(length, SmiConstant(0)), &invalid_length);
CallBuiltin(Builtins::kTypedArrayInitialize, context, holder, length,
element_size, initialize);
element_size, TrueConstant());
Return(UndefinedConstant());
BIND(&invalid_length);
......@@ -404,10 +404,10 @@ TF_BUILTIN(TypedArrayConstructByLength, TypedArrayBuiltinsAssembler) {
TF_BUILTIN(TypedArrayConstructByArrayBuffer, TypedArrayBuiltinsAssembler) {
Node* holder = Parameter(Descriptor::kHolder);
Node* buffer = Parameter(Descriptor::kBuffer);
Node* byte_offset = Parameter(Descriptor::kByteOffset);
TNode<Object> byte_offset = CAST(Parameter(Descriptor::kByteOffset));
Node* length = Parameter(Descriptor::kLength);
Node* element_size = Parameter(Descriptor::kElementSize);
Node* context = Parameter(Descriptor::kContext);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
CSA_ASSERT(this, IsJSTypedArray(holder));
CSA_ASSERT(this, IsJSArrayBuffer(buffer));
......@@ -425,8 +425,8 @@ TF_BUILTIN(TypedArrayConstructByArrayBuffer, TypedArrayBuiltinsAssembler) {
GotoIf(IsUndefined(byte_offset), &check_length);
offset.Bind(
ToInteger(context, byte_offset, CodeStubAssembler::kTruncateMinusZero));
offset.Bind(ToInteger_Inline(context, byte_offset,
CodeStubAssembler::kTruncateMinusZero));
Branch(TaggedIsSmi(offset.value()), &offset_is_smi, &offset_not_smi);
// Check that the offset is a multiple of the element size.
......@@ -947,8 +947,8 @@ TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
// Normalize offset argument (using ToInteger) and handle heap number cases.
TNode<Object> offset = args.GetOptionalArgumentValue(1, SmiConstant(0));
TNode<Number> offset_num = ToInteger(context, offset, kTruncateMinusZero);
CSA_ASSERT(this, IsNumberNormalized(offset_num));
TNode<Number> offset_num =
ToInteger_Inline(context, offset, kTruncateMinusZero);
// Since ToInteger always returns a Smi if the given value is within Smi
// range, and the only corner case of -0.0 has already been truncated to 0.0,
......
......@@ -5746,8 +5746,8 @@ Node* CodeStubAssembler::ToSmiIndex(Node* const input, Node* const context,
Branch(IsUndefined(result.value()), &return_zero, &defined);
BIND(&defined);
result.Bind(ToInteger(context, result.value(),
CodeStubAssembler::kTruncateMinusZero));
result.Bind(ToInteger_Inline(CAST(context), CAST(result.value()),
CodeStubAssembler::kTruncateMinusZero));
GotoIfNot(TaggedIsSmi(result.value()), range_error);
CSA_ASSERT(this, TaggedIsSmi(result.value()));
Goto(&negative_check);
......@@ -5771,8 +5771,8 @@ Node* CodeStubAssembler::ToSmiLength(Node* input, Node* const context,
Branch(TaggedIsSmi(result.value()), &negative_check, &to_integer);
BIND(&to_integer);
result.Bind(ToInteger(context, result.value(),
CodeStubAssembler::kTruncateMinusZero));
result.Bind(ToInteger_Inline(CAST(context), CAST(result.value()),
CodeStubAssembler::kTruncateMinusZero));
GotoIf(TaggedIsSmi(result.value()), &negative_check);
// result.value() can still be a negative HeapNumber here.
Branch(IsTrue(CallBuiltin(Builtins::kLessThan, context, result.value(),
......@@ -5800,6 +5800,16 @@ Node* CodeStubAssembler::ToLength_Inline(Node* const context,
MachineRepresentation::kTagged);
}
TNode<Number> CodeStubAssembler::ToInteger_Inline(
TNode<Context> context, TNode<Object> input, ToIntegerTruncationMode mode) {
Builtins::Name builtin = (mode == kNoTruncation)
? Builtins::kToInteger
: Builtins::kToInteger_TruncateMinusZero;
return CAST(Select(TaggedIsSmi(input), [=] { return input; },
[=] { return CallBuiltin(builtin, context, input); },
MachineRepresentation::kTagged));
}
TNode<Number> CodeStubAssembler::ToInteger(SloppyTNode<Context> context,
SloppyTNode<Object> input,
ToIntegerTruncationMode mode) {
......@@ -5858,6 +5868,7 @@ TNode<Number> CodeStubAssembler::ToInteger(SloppyTNode<Context> context,
}
BIND(&out);
if (mode == kTruncateMinusZero) CSA_ASSERT(this, IsNumberNormalized(var_arg));
return CAST(var_arg);
}
......
......@@ -1233,7 +1233,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
// ES6 7.1.15 ToLength, but with inlined fast path.
Node* ToLength_Inline(Node* const context, Node* const input);
// Convert any object to an Integer.
// ES6 7.1.4 ToInteger ( argument )
TNode<Number> ToInteger_Inline(TNode<Context> context, TNode<Object> input,
ToIntegerTruncationMode mode = kNoTruncation);
TNode<Number> ToInteger(SloppyTNode<Context> context,
SloppyTNode<Object> input,
ToIntegerTruncationMode mode = kNoTruncation);
......
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