[es6] Introduce %ToInteger and %ToLength.

This adds ES6 compliant Object::ToInteger, Object::ToInt32,
Object::ToUint32 and Object::ToLength, and replaces the old
Execution wrappers of those abstract operations (which were
not using the correct ToPrimitive).

This also introduces proper %ToInteger and %ToLength runtime
entries, with a fast path %_ToInteger supported in fullcodegen
and Crankshaft (for now). Internal JavaScript code should use
TO_INTEGER and TO_LENGTH respectively.

CQ_INCLUDE_TRYBOTS=tryserver.v8:v8_linux_layout_dbg,v8_linux_nosnap_dbg
BUG=v8:4307
LOG=n

Review URL: https://codereview.chromium.org/1378533002

Cr-Commit-Position: refs/heads/master@{#30993}
This commit is contained in:
bmeurer 2015-09-29 00:41:03 -07:00 committed by Commit bot
parent 2839811584
commit 93b2b2622b
33 changed files with 334 additions and 167 deletions

View File

@ -224,7 +224,7 @@ void Accessors::ArrayLengthSetter(
uint32_t length = 0;
if (!FastAsArrayLength(isolate, length_obj, &length)) {
Handle<Object> uint32_v;
if (!Execution::ToUint32(isolate, length_obj).ToHandle(&uint32_v)) {
if (!Object::ToUint32(isolate, length_obj).ToHandle(&uint32_v)) {
isolate->OptionalRescheduleException(false);
return;
}

View File

@ -2937,7 +2937,7 @@ MaybeLocal<Integer> Value::ToInteger(Local<Context> context) const {
PREPARE_FOR_EXECUTION(context, "ToInteger", Integer);
Local<Integer> result;
has_pending_exception =
!ToLocal<Integer>(i::Execution::ToInteger(isolate, obj), &result);
!ToLocal<Integer>(i::Object::ToInteger(isolate, obj), &result);
RETURN_ON_FAILED_EXECUTION(Integer);
RETURN_ESCAPED(result);
}
@ -2954,7 +2954,7 @@ MaybeLocal<Int32> Value::ToInt32(Local<Context> context) const {
Local<Int32> result;
PREPARE_FOR_EXECUTION(context, "ToInt32", Int32);
has_pending_exception =
!ToLocal<Int32>(i::Execution::ToInt32(isolate, obj), &result);
!ToLocal<Int32>(i::Object::ToInt32(isolate, obj), &result);
RETURN_ON_FAILED_EXECUTION(Int32);
RETURN_ESCAPED(result);
}
@ -2969,9 +2969,9 @@ MaybeLocal<Uint32> Value::ToUint32(Local<Context> context) const {
auto obj = Utils::OpenHandle(this);
if (obj->IsSmi()) return ToApiHandle<Uint32>(obj);
Local<Uint32> result;
PREPARE_FOR_EXECUTION(context, "ToUInt32", Uint32);
PREPARE_FOR_EXECUTION(context, "ToUint32", Uint32);
has_pending_exception =
!ToLocal<Uint32>(i::Execution::ToUint32(isolate, obj), &result);
!ToLocal<Uint32>(i::Object::ToUint32(isolate, obj), &result);
RETURN_ON_FAILED_EXECUTION(Uint32);
RETURN_ESCAPED(result);
}
@ -3265,8 +3265,7 @@ Maybe<int64_t> Value::IntegerValue(Local<Context> context) const {
num = obj;
} else {
PREPARE_FOR_EXECUTION_PRIMITIVE(context, "IntegerValue", int64_t);
has_pending_exception =
!i::Execution::ToInteger(isolate, obj).ToHandle(&num);
has_pending_exception = !i::Object::ToInteger(isolate, obj).ToHandle(&num);
RETURN_ON_FAILED_EXECUTION_PRIMITIVE(int64_t);
}
return Just(num->IsSmi() ? static_cast<int64_t>(i::Smi::cast(*num)->value())
@ -3292,7 +3291,7 @@ Maybe<int32_t> Value::Int32Value(Local<Context> context) const {
if (obj->IsNumber()) return Just(NumberToInt32(*obj));
PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Int32Value", int32_t);
i::Handle<i::Object> num;
has_pending_exception = !i::Execution::ToInt32(isolate, obj).ToHandle(&num);
has_pending_exception = !i::Object::ToInt32(isolate, obj).ToHandle(&num);
RETURN_ON_FAILED_EXECUTION_PRIMITIVE(int32_t);
return Just(num->IsSmi() ? i::Smi::cast(*num)->value()
: static_cast<int32_t>(num->Number()));
@ -3311,7 +3310,7 @@ Maybe<uint32_t> Value::Uint32Value(Local<Context> context) const {
if (obj->IsNumber()) return Just(NumberToUint32(*obj));
PREPARE_FOR_EXECUTION_PRIMITIVE(context, "Uint32Value", uint32_t);
i::Handle<i::Object> num;
has_pending_exception = !i::Execution::ToUint32(isolate, obj).ToHandle(&num);
has_pending_exception = !i::Object::ToUint32(isolate, obj).ToHandle(&num);
RETURN_ON_FAILED_EXECUTION_PRIMITIVE(uint32_t);
return Just(num->IsSmi() ? static_cast<uint32_t>(i::Smi::cast(*num)->value())
: static_cast<uint32_t>(num->Number()));

View File

@ -1000,11 +1000,11 @@ bool IterateElements(Isolate* isolate, Handle<JSObject> receiver,
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, val, Runtime::GetObjectProperty(isolate, receiver, key),
false);
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, val,
Object::ToLength(isolate, val), false);
// TODO(caitp): Support larger element indexes (up to 2^53-1).
if (!val->ToUint32(&length)) {
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, val, Execution::ToLength(isolate, val), false);
val->ToUint32(&length);
length = 0;
}
}

View File

@ -246,6 +246,8 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
case Runtime::kInlineGetPrototype:
case Runtime::kInlineRegExpExec:
case Runtime::kInlineSubString:
case Runtime::kInlineToInteger:
case Runtime::kInlineToLength:
case Runtime::kInlineToName:
case Runtime::kInlineToNumber:
case Runtime::kInlineToObject:

View File

@ -83,7 +83,6 @@ enum BindingFlags {
V(REFLECT_CONSTRUCT_INDEX, JSFunction, reflect_construct) \
V(SPREAD_ARGUMENTS_INDEX, JSFunction, spread_arguments) \
V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable) \
V(TO_LENGTH_FUN_INDEX, JSFunction, to_length_fun) \
V(TO_NUMBER_FUN_INDEX, JSFunction, to_number_fun)
@ -159,7 +158,6 @@ enum BindingFlags {
V(TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, JSFunction, \
to_complete_property_descriptor) \
V(TO_DETAIL_STRING_FUN_INDEX, JSFunction, to_detail_string_fun) \
V(TO_INTEGER_FUN_INDEX, JSFunction, to_integer_fun) \
V(TYPE_ERROR_FUNCTION_INDEX, JSFunction, type_error_function) \
V(URI_ERROR_FUNCTION_INDEX, JSFunction, uri_error_function) \
NATIVE_CONTEXT_JS_BUILTINS(V)

View File

@ -438,18 +438,6 @@ MaybeHandle<Object> Execution::ToDetailString(
}
MaybeHandle<Object> Execution::ToInteger(
Isolate* isolate, Handle<Object> obj) {
RETURN_NATIVE_CALL(to_integer, { obj });
}
MaybeHandle<Object> Execution::ToLength(
Isolate* isolate, Handle<Object> obj) {
RETURN_NATIVE_CALL(to_length, { obj });
}
MaybeHandle<Object> Execution::NewDate(Isolate* isolate, double time) {
Handle<Object> time_obj = isolate->factory()->NewNumber(time);
RETURN_NATIVE_CALL(create_date, { time_obj });
@ -459,12 +447,6 @@ MaybeHandle<Object> Execution::NewDate(Isolate* isolate, double time) {
#undef RETURN_NATIVE_CALL
MaybeHandle<Object> Execution::ToInt32(Isolate* isolate, Handle<Object> obj) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Object::ToNumber(obj), Object);
return isolate->factory()->NewNumberFromInt(DoubleToInt32(obj->Number()));
}
MaybeHandle<Object> Execution::ToObject(Isolate* isolate, Handle<Object> obj) {
Handle<JSReceiver> receiver;
if (JSReceiver::ToObject(isolate, obj).ToHandle(&receiver)) {
@ -475,12 +457,6 @@ MaybeHandle<Object> Execution::ToObject(Isolate* isolate, Handle<Object> obj) {
}
MaybeHandle<Object> Execution::ToUint32(Isolate* isolate, Handle<Object> obj) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Object::ToNumber(obj), Object);
return isolate->factory()->NewNumberFromUint(DoubleToUint32(obj->Number()));
}
MaybeHandle<JSRegExp> Execution::NewJSRegExp(Handle<String> pattern,
Handle<String> flags) {
Isolate* isolate = pattern->GetIsolate();

View File

@ -52,23 +52,6 @@ class Execution final : public AllStatic {
Handle<Object> argv[],
MaybeHandle<Object>* exception_out = NULL);
// ECMA-262 9.4
MUST_USE_RESULT static MaybeHandle<Object> ToInteger(
Isolate* isolate, Handle<Object> obj);
// ECMA-262 9.5
MUST_USE_RESULT static MaybeHandle<Object> ToInt32(
Isolate* isolate, Handle<Object> obj);
// ECMA-262 9.6
MUST_USE_RESULT static MaybeHandle<Object> ToUint32(
Isolate* isolate, Handle<Object> obj);
// ES6, draft 10-14-14, section 7.1.15
MUST_USE_RESULT static MaybeHandle<Object> ToLength(
Isolate* isolate, Handle<Object> obj);
// ECMA-262 9.8
MUST_USE_RESULT static MaybeHandle<Object> ToDetailString(
Isolate* isolate, Handle<Object> obj);

View File

@ -3766,6 +3766,23 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
}
void FullCodeGenerator::EmitToInteger(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(1, args->length());
// Load the argument into r0 and convert it.
VisitForAccumulatorValue(args->at(0));
// Convert the object to an integer.
Label done_convert;
__ JumpIfSmi(r0, &done_convert);
__ Push(r0);
__ CallRuntime(Runtime::kToInteger, 1);
__ bind(&done_convert);
context()->Plug(r0);
}
void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(args->length(), 1);

View File

@ -3476,6 +3476,23 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
}
void FullCodeGenerator::EmitToInteger(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(1, args->length());
// Load the argument into x0 and convert it.
VisitForAccumulatorValue(args->at(0));
// Convert the object to an integer.
Label done_convert;
__ JumpIfSmi(x0, &done_convert);
__ Push(x0);
__ CallRuntime(Runtime::kToInteger, 1);
__ bind(&done_convert);
context()->Plug(x0);
}
void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(args->length(), 1);

View File

@ -480,49 +480,50 @@ class FullCodeGenerator: public AstVisitor {
void EmitKeyedCallWithLoadIC(Call* expr, Expression* key);
void EmitKeyedSuperCallWithLoadIC(Call* expr);
#define FOR_EACH_FULL_CODE_INTRINSIC(F) \
F(IsSmi) \
F(IsArray) \
F(IsTypedArray) \
F(IsRegExp) \
F(IsJSProxy) \
F(IsConstructCall) \
F(Call) \
F(CallFunction) \
F(DefaultConstructorCallSuper) \
F(ArgumentsLength) \
F(Arguments) \
F(ValueOf) \
F(SetValueOf) \
F(IsDate) \
F(DateField) \
F(StringCharFromCode) \
F(StringCharAt) \
F(OneByteSeqStringSetChar) \
F(TwoByteSeqStringSetChar) \
F(ObjectEquals) \
F(IsFunction) \
F(IsSpecObject) \
F(IsSimdValue) \
F(MathPow) \
F(IsMinusZero) \
F(HasCachedArrayIndex) \
F(GetCachedArrayIndex) \
F(FastOneByteArrayJoin) \
F(GeneratorNext) \
F(GeneratorThrow) \
F(DebugBreakInOptimizedCode) \
F(ClassOf) \
F(StringCharCodeAt) \
F(StringAdd) \
F(SubString) \
F(RegExpExec) \
F(RegExpConstructResult) \
F(NumberToString) \
F(ToString) \
F(ToName) \
F(ToObject) \
F(DebugIsActive) \
#define FOR_EACH_FULL_CODE_INTRINSIC(F) \
F(IsSmi) \
F(IsArray) \
F(IsTypedArray) \
F(IsRegExp) \
F(IsJSProxy) \
F(IsConstructCall) \
F(Call) \
F(CallFunction) \
F(DefaultConstructorCallSuper) \
F(ArgumentsLength) \
F(Arguments) \
F(ValueOf) \
F(SetValueOf) \
F(IsDate) \
F(DateField) \
F(StringCharFromCode) \
F(StringCharAt) \
F(OneByteSeqStringSetChar) \
F(TwoByteSeqStringSetChar) \
F(ObjectEquals) \
F(IsFunction) \
F(IsSpecObject) \
F(IsSimdValue) \
F(MathPow) \
F(IsMinusZero) \
F(HasCachedArrayIndex) \
F(GetCachedArrayIndex) \
F(FastOneByteArrayJoin) \
F(GeneratorNext) \
F(GeneratorThrow) \
F(DebugBreakInOptimizedCode) \
F(ClassOf) \
F(StringCharCodeAt) \
F(StringAdd) \
F(SubString) \
F(RegExpExec) \
F(RegExpConstructResult) \
F(ToInteger) \
F(NumberToString) \
F(ToString) \
F(ToName) \
F(ToObject) \
F(DebugIsActive) \
F(CreateIterResultObject)
#define GENERATOR_DECLARATION(Name) void Emit##Name(CallRuntime* call);

View File

@ -3664,6 +3664,23 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
}
void FullCodeGenerator::EmitToInteger(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(1, args->length());
// Load the argument into eax and convert it.
VisitForAccumulatorValue(args->at(0));
// Convert the object to an integer.
Label done_convert;
__ JumpIfSmi(eax, &done_convert, Label::kNear);
__ Push(eax);
__ CallRuntime(Runtime::kToInteger, 1);
__ bind(&done_convert);
context()->Plug(eax);
}
void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(args->length(), 1);

View File

@ -3778,6 +3778,23 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
}
void FullCodeGenerator::EmitToInteger(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(1, args->length());
// Load the argument into v0 and convert it.
VisitForAccumulatorValue(args->at(0));
// Convert the object to an integer.
Label done_convert;
__ JumpIfSmi(v0, &done_convert);
__ Push(v0);
__ CallRuntime(Runtime::kToInteger, 1);
__ bind(&done_convert);
context()->Plug(v0);
}
void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(args->length(), 1);

View File

@ -3781,6 +3781,23 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
}
void FullCodeGenerator::EmitToInteger(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(1, args->length());
// Load the argument into v0 and convert it.
VisitForAccumulatorValue(args->at(0));
// Convert the object to an integer.
Label done_convert;
__ JumpIfSmi(v0, &done_convert);
__ Push(v0);
__ CallRuntime(Runtime::kToInteger, 1);
__ bind(&done_convert);
context()->Plug(v0);
}
void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(args->length(), 1);

View File

@ -3780,6 +3780,23 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
}
void FullCodeGenerator::EmitToInteger(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(1, args->length());
// Load the argument into r3 and convert it.
VisitForAccumulatorValue(args->at(0));
// Convert the object to an integer.
Label done_convert;
__ JumpIfSmi(r3, &done_convert);
__ Push(r3);
__ CallRuntime(Runtime::kToInteger, 1);
__ bind(&done_convert);
context()->Plug(r3);
}
void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(args->length(), 1);

View File

@ -3661,6 +3661,23 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
}
void FullCodeGenerator::EmitToInteger(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(1, args->length());
// Load the argument into rax and convert it.
VisitForAccumulatorValue(args->at(0));
// Convert the object to an integer.
Label done_convert;
__ JumpIfSmi(rax, &done_convert, Label::kNear);
__ Push(rax);
__ CallRuntime(Runtime::kToInteger, 1);
__ bind(&done_convert);
context()->Plug(rax);
}
void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(args->length(), 1);

View File

@ -3655,6 +3655,23 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
}
void FullCodeGenerator::EmitToInteger(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(1, args->length());
// Load the argument into eax and convert it.
VisitForAccumulatorValue(args->at(0));
// Convert the object to an integer.
Label done_convert;
__ JumpIfSmi(eax, &done_convert, Label::kNear);
__ Push(eax);
__ CallRuntime(Runtime::kToInteger, 1);
__ bind(&done_convert);
context()->Plug(eax);
}
void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_EQ(args->length(), 1);

View File

@ -774,6 +774,10 @@ const uint64_t kHoleNanInt64 =
(static_cast<uint64_t>(kHoleNanUpper32) << 32) | kHoleNanLower32;
// ES6 section 20.1.2.6 Number.MAX_SAFE_INTEGER
const double kMaxSafeInteger = 9007199254740991.0; // 2^53-1
// The order of this enum has to be kept in sync with the predicates below.
enum VariableMode {
// User declared variables:

View File

@ -20,7 +20,7 @@ function InnerArrayIncludes(searchElement, fromIndex, array, length) {
return false;
}
var n = $toInteger(fromIndex);
var n = TO_INTEGER(fromIndex);
var k;
if (n >= 0) {
@ -49,7 +49,7 @@ function ArrayIncludes(searchElement, fromIndex) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.includes");
var array = TO_OBJECT(this);
var length = $toLength(array.length);
var length = TO_LENGTH(array.length);
return InnerArrayIncludes(searchElement, fromIndex, array, length);
}

View File

@ -85,7 +85,7 @@ function ArrayCopyWithin(target, start, end) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.copyWithin");
var array = TO_OBJECT(this);
var length = $toLength(array.length);
var length = TO_LENGTH(array.length);
return InnerArrayCopyWithin(target, start, end, array, length);
}
@ -110,7 +110,7 @@ function ArrayFind(predicate, thisArg) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.find");
var array = TO_OBJECT(this);
var length = $toInteger(array.length);
var length = TO_INTEGER(array.length);
return InnerArrayFind(predicate, thisArg, array, length);
}
@ -135,7 +135,7 @@ function ArrayFindIndex(predicate, thisArg) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.findIndex");
var array = TO_OBJECT(this);
var length = $toInteger(array.length);
var length = TO_INTEGER(array.length);
return InnerArrayFindIndex(predicate, thisArg, array, length);
}
@ -233,7 +233,7 @@ function ArrayFrom(arrayLike, mapfn, receiver) {
k++;
}
} else {
var len = $toLength(items.length);
var len = TO_LENGTH(items.length);
result = %IsConstructor(this) ? new this(len) : new GlobalArray(len);
for (k = 0; k < len; ++k) {

View File

@ -41,7 +41,7 @@ function CheckSharedInteger32TypedArray(ia) {
function AtomicsCompareExchangeJS(sta, index, oldValue, newValue) {
CheckSharedIntegerTypedArray(sta);
index = $toInteger(index);
index = TO_INTEGER(index);
if (index < 0 || index >= %_TypedArrayGetLength(sta)) {
return UNDEFINED;
}
@ -52,7 +52,7 @@ function AtomicsCompareExchangeJS(sta, index, oldValue, newValue) {
function AtomicsLoadJS(sta, index) {
CheckSharedIntegerTypedArray(sta);
index = $toInteger(index);
index = TO_INTEGER(index);
if (index < 0 || index >= %_TypedArrayGetLength(sta)) {
return UNDEFINED;
}
@ -61,7 +61,7 @@ function AtomicsLoadJS(sta, index) {
function AtomicsStoreJS(sta, index, value) {
CheckSharedIntegerTypedArray(sta);
index = $toInteger(index);
index = TO_INTEGER(index);
if (index < 0 || index >= %_TypedArrayGetLength(sta)) {
return UNDEFINED;
}
@ -71,7 +71,7 @@ function AtomicsStoreJS(sta, index, value) {
function AtomicsAddJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
index = $toInteger(index);
index = TO_INTEGER(index);
if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
return UNDEFINED;
}
@ -81,7 +81,7 @@ function AtomicsAddJS(ia, index, value) {
function AtomicsSubJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
index = $toInteger(index);
index = TO_INTEGER(index);
if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
return UNDEFINED;
}
@ -91,7 +91,7 @@ function AtomicsSubJS(ia, index, value) {
function AtomicsAndJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
index = $toInteger(index);
index = TO_INTEGER(index);
if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
return UNDEFINED;
}
@ -101,7 +101,7 @@ function AtomicsAndJS(ia, index, value) {
function AtomicsOrJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
index = $toInteger(index);
index = TO_INTEGER(index);
if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
return UNDEFINED;
}
@ -111,7 +111,7 @@ function AtomicsOrJS(ia, index, value) {
function AtomicsXorJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
index = $toInteger(index);
index = TO_INTEGER(index);
if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
return UNDEFINED;
}
@ -121,7 +121,7 @@ function AtomicsXorJS(ia, index, value) {
function AtomicsExchangeJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
index = $toInteger(index);
index = TO_INTEGER(index);
if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
return UNDEFINED;
}
@ -137,7 +137,7 @@ function AtomicsIsLockFreeJS(size) {
function AtomicsFutexWaitJS(ia, index, value, timeout) {
CheckSharedInteger32TypedArray(ia);
index = $toInteger(index);
index = TO_INTEGER(index);
if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
return UNDEFINED;
}
@ -156,20 +156,20 @@ function AtomicsFutexWaitJS(ia, index, value, timeout) {
function AtomicsFutexWakeJS(ia, index, count) {
CheckSharedInteger32TypedArray(ia);
index = $toInteger(index);
index = TO_INTEGER(index);
if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
return UNDEFINED;
}
count = MathMax(0, $toInteger(count));
count = MathMax(0, TO_INTEGER(count));
return %AtomicsFutexWake(ia, index, count);
}
function AtomicsFutexWakeOrRequeueJS(ia, index1, count, value, index2) {
CheckSharedInteger32TypedArray(ia);
index1 = $toInteger(index1);
count = MathMax(0, $toInteger(count));
index1 = TO_INTEGER(index1);
count = MathMax(0, TO_INTEGER(count));
value = TO_INT32(value);
index2 = $toInteger(index2);
index2 = TO_INTEGER(index2);
if (index1 < 0 || index1 >= %_TypedArrayGetLength(ia) ||
index2 < 0 || index2 >= %_TypedArrayGetLength(ia)) {
return UNDEFINED;

View File

@ -12217,6 +12217,33 @@ void HOptimizedGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
}
void HOptimizedGraphBuilder::GenerateToInteger(CallRuntime* call) {
DCHECK_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* input = Pop();
if (input->type().IsSmi()) {
return ast_context()->ReturnValue(input);
} else {
IfBuilder if_inputissmi(this);
if_inputissmi.If<HIsSmiAndBranch>(input);
if_inputissmi.Then();
{
// Return the input value.
Push(input);
Add<HSimulate>(call->id(), FIXED_SIMULATE);
}
if_inputissmi.Else();
{
Add<HPushArguments>(input);
Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kToInteger), 1));
Add<HSimulate>(call->id(), FIXED_SIMULATE);
}
if_inputissmi.End();
return ast_context()->ReturnValue(Pop());
}
}
void HOptimizedGraphBuilder::GenerateToObject(CallRuntime* call) {
DCHECK_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));

View File

@ -2223,6 +2223,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
F(OneByteSeqStringSetChar) \
F(TwoByteSeqStringSetChar) \
F(ObjectEquals) \
F(ToInteger) \
F(ToObject) \
F(ToString) \
F(IsFunction) \

View File

@ -217,7 +217,7 @@ function JSONStringify(value, replacer, space) {
}
var gap;
if (IS_NUMBER(space)) {
space = MathMax(0, MathMin($toInteger(space), 10));
space = MathMax(0, MathMin(TO_INTEGER(space), 10));
gap = %_SubString(" ", 0, space);
} else if (IS_STRING(space)) {
if (space.length > 10) {

View File

@ -141,12 +141,12 @@ define kBoundArgumentsStartIndex = 2;
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || ((arg == arg) && (arg != 1/0) && (arg != -1/0)));
macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToInteger(ToNumber(arg)));
macro TO_INTEGER_FOR_SIDE_EFFECT(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : ToNumber(arg));
macro TO_INTEGER(arg) = (%_ToInteger(arg));
macro TO_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg)));
macro TO_INT32(arg) = (arg | 0);
macro TO_UINT32(arg) = (arg >>> 0);
macro TO_LENGTH_OR_UINT32(arg) = (harmony_tolength ? $toLength(arg) : TO_UINT32(arg));
macro TO_LENGTH(arg) = (%ToLength(arg));
macro TO_LENGTH_OR_UINT32(arg) = (harmony_tolength ? TO_LENGTH(arg) : TO_UINT32(arg));
macro TO_STRING(arg) = (%_ToString(arg));
macro TO_NUMBER_INLINE(arg) = (IS_NUMBER(%IS_VAR(arg)) ? arg : $nonNumberToNumber(arg));
macro TO_OBJECT(arg) = (%_ToObject(arg));

View File

@ -330,7 +330,7 @@ function ConvertAcceptListToTypeMap(arg) {
if (!IS_SPEC_OBJECT(arg)) throw MakeTypeError(kObserveInvalidAccept);
var len = $toInteger(arg.length);
var len = TO_INTEGER(arg.length);
if (len < 0) len = 0;
return TypeMapCreateFromList(arg, len);

View File

@ -132,6 +132,27 @@ MaybeHandle<Object> Object::ToNumber(Handle<Object> input) {
}
// static
MaybeHandle<Object> Object::ToInteger(Isolate* isolate, Handle<Object> input) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
}
// static
MaybeHandle<Object> Object::ToInt32(Isolate* isolate, Handle<Object> input) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
}
// static
MaybeHandle<Object> Object::ToUint32(Isolate* isolate, Handle<Object> input) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
}
// static
MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
while (true) {
@ -159,6 +180,19 @@ MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
}
// static
MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
double len = DoubleToInteger(input->Number());
if (len <= 0.0) {
len = 0.0;
} else if (len >= kMaxSafeInteger) {
len = kMaxSafeInteger;
}
return isolate->factory()->NewNumber(len);
}
bool Object::BooleanValue() {
if (IsBoolean()) return IsTrue();
if (IsSmi()) return Smi::cast(this)->value() != 0;

View File

@ -1127,10 +1127,26 @@ class Object {
// ES6 section 7.1.3 ToNumber
MUST_USE_RESULT static MaybeHandle<Object> ToNumber(Handle<Object> input);
// ES6 section 7.1.4 ToInteger
MUST_USE_RESULT static MaybeHandle<Object> ToInteger(Isolate* isolate,
Handle<Object> input);
// ES6 section 7.1.5 ToInt32
MUST_USE_RESULT static MaybeHandle<Object> ToInt32(Isolate* isolate,
Handle<Object> input);
// ES6 section 7.1.6 ToUint32
MUST_USE_RESULT static MaybeHandle<Object> ToUint32(Isolate* isolate,
Handle<Object> input);
// ES6 section 7.1.12 ToString
MUST_USE_RESULT static MaybeHandle<String> ToString(Isolate* isolate,
Handle<Object> input);
// ES6 section 7.1.15 ToLength
MUST_USE_RESULT static MaybeHandle<Object> ToLength(Isolate* isolate,
Handle<Object> input);
// ES6 section 7.3.9 GetMethod
MUST_USE_RESULT static MaybeHandle<Object> GetMethod(
Handle<JSReceiver> receiver, Handle<Name> name);

View File

@ -15,8 +15,6 @@ var $NaN;
var $nonNumberToNumber;
var $sameValue;
var $sameValueZero;
var $toInteger;
var $toLength;
var $toNumber;
var $toPositiveInteger;
@ -97,7 +95,7 @@ function REFLECT_APPLY_PREPARE(args) {
throw %make_type_error(kWrongArgs, "Reflect.apply");
}
length = %to_length_fun(args.length);
length = TO_LENGTH(args.length);
// We can handle any number of apply arguments if the stack is
// big enough, but sanity check the value to avoid overflow when
@ -147,7 +145,7 @@ function REFLECT_CONSTRUCT_PREPARE(
throw %make_type_error(kWrongArgs, "Reflect.construct");
}
length = %to_length_fun(args.length);
length = TO_LENGTH(args.length);
// We can handle any number of apply arguments if the stack is
// big enough, but sanity check the value to avoid overflow when
@ -216,21 +214,6 @@ function ToString(x) {
}
// ECMA-262, section 9.4, page 34.
function ToInteger(x) {
if (%_IsSmi(x)) return x;
return %NumberToInteger(ToNumber(x));
}
// ES6, draft 08-24-14, section 7.1.15
function ToLength(arg) {
arg = ToInteger(arg);
if (arg < 0) return 0;
return arg < kMaxSafeInteger ? arg : kMaxSafeInteger;
}
// ES5, section 9.12
function SameValue(x, y) {
if (typeof x != typeof y) return false;
@ -348,8 +331,6 @@ $NaN = %GetRootNaN();
$nonNumberToNumber = NonNumberToNumber;
$sameValue = SameValue;
$sameValueZero = SameValueZero;
$toInteger = ToInteger;
$toLength = ToLength;
$toNumber = ToNumber;
$toPositiveInteger = ToPositiveInteger;
@ -363,14 +344,11 @@ $toPositiveInteger = ToPositiveInteger;
%InstallToContext([
"concat_iterable_to_array", ConcatIterableToArray,
"non_number_to_number", NonNumberToNumber,
"to_integer_fun", ToInteger,
"to_length_fun", ToLength,
"to_number_fun", ToNumber,
]);
utils.Export(function(to) {
to.ToBoolean = ToBoolean;
to.ToLength = ToLength;
to.ToNumber = ToNumber;
to.ToString = ToString;
});

View File

@ -171,15 +171,6 @@ RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) {
}
RUNTIME_FUNCTION(Runtime_NumberToInteger) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_DOUBLE_ARG_CHECKED(number, 0);
return *isolate->factory()->NewNumber(DoubleToInteger(number));
}
RUNTIME_FUNCTION(Runtime_NumberToIntegerMapMinusZero) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);

View File

@ -1446,6 +1446,28 @@ RUNTIME_FUNCTION(Runtime_ToNumber) {
}
RUNTIME_FUNCTION(Runtime_ToInteger) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
Object::ToInteger(isolate, input));
return *result;
}
RUNTIME_FUNCTION(Runtime_ToLength) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
Object::ToLength(isolate, input));
return *result;
}
RUNTIME_FUNCTION(Runtime_ToString) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());

View File

@ -413,7 +413,6 @@ namespace internal {
F(StringParseFloat, 1, 1) \
F(NumberToString, 1, 1) \
F(NumberToStringSkipCache, 1, 1) \
F(NumberToInteger, 1, 1) \
F(NumberToIntegerMapMinusZero, 1, 1) \
F(NumberToSmi, 1, 1) \
F(NumberImul, 2, 1) \
@ -485,6 +484,8 @@ namespace internal {
F(ToPrimitive_Number, 1, 1) \
F(ToPrimitive_String, 1, 1) \
F(ToNumber, 1, 1) \
F(ToInteger, 1, 1) \
F(ToLength, 1, 1) \
F(ToString, 1, 1) \
F(ToName, 1, 1) \
F(Equals, 2, 1) \

View File

@ -155,8 +155,7 @@ function StringMatchJS(regexp) {
if (IS_REGEXP(regexp)) {
// Emulate RegExp.prototype.exec's side effect in step 5, even though
// value is discarded.
var lastIndex = regexp.lastIndex;
TO_INTEGER_FOR_SIDE_EFFECT(lastIndex);
var lastIndex = TO_INTEGER(regexp.lastIndex);
if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
var result = %StringMatch(subject, regexp, RegExpLastMatchInfo);
if (result !== null) $regexpLastMatchInfoOverride = null;
@ -227,8 +226,7 @@ function StringReplace(search, replace) {
if (IS_REGEXP(search)) {
// Emulate RegExp.prototype.exec's side effect in step 5, even if
// value is discarded.
var lastIndex = search.lastIndex;
TO_INTEGER_FOR_SIDE_EFFECT(lastIndex);
var lastIndex = TO_INTEGER(search.lastIndex);
if (!IS_CALLABLE(replace)) {
replace = TO_STRING(replace);
@ -936,7 +934,7 @@ function StringRepeat(count) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.repeat");
var s = TO_STRING(this);
var n = $toInteger(count);
var n = TO_INTEGER(count);
// The maximum string length is stored in a smi, so a longer repeat
// must result in a range error.
if (n < 0 || n > %_MaxSmi()) throw MakeRangeError(kInvalidCountValue);
@ -966,7 +964,7 @@ function StringStartsWith(searchString /* position */) { // length == 1
if (%_ArgumentsLength() > 1) {
var arg = %_Arguments(1); // position
if (!IS_UNDEFINED(arg)) {
pos = $toInteger(arg);
pos = TO_INTEGER(arg);
}
}
@ -1005,7 +1003,7 @@ function StringEndsWith(searchString /* position */) { // length == 1
if (%_ArgumentsLength() > 1) {
var arg = %_Arguments(1); // position
if (!IS_UNDEFINED(arg)) {
pos = $toInteger(arg);
pos = TO_INTEGER(arg);
}
}
@ -1115,7 +1113,7 @@ function StringRaw(callSite) {
var numberOfSubstitutions = %_ArgumentsLength();
var cooked = TO_OBJECT(callSite);
var raw = TO_OBJECT(cooked.raw);
var literalSegments = $toLength(raw.length);
var literalSegments = TO_LENGTH(raw.length);
if (literalSegments <= 0) return "";
var result = TO_STRING(raw[0]);

View File

@ -334,7 +334,7 @@ function TypedArraySet(obj, offset) {
}
return;
}
l = $toLength(l);
l = TO_LENGTH(l);
if (intOffset + l > this.length) {
throw MakeRangeError(kTypedArraySetSourceTooLarge);
}