Skip to content

Commit 134daba

Browse files
committed
Internal Commands for toInteger and toLength
1 parent a343fd8 commit 134daba

15 files changed

+117
-104
lines changed

lib/Backend/BackwardPass.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -6573,6 +6573,8 @@ BackwardPass::TrackBitWiseOrNumberOp(IR::Instr *const instr)
65736573
{
65746574
// Instructions that can cause src values to escape the local scope have already been excluded
65756575

6576+
case Js::OpCode::ToInteger:
6577+
case Js::OpCode::ToLength:
65766578
case Js::OpCode::Conv_Num:
65776579
case Js::OpCode::Div_A:
65786580
case Js::OpCode::Mul_A:
@@ -7003,6 +7005,8 @@ BackwardPass::TrackIntUsage(IR::Instr *const instr)
70037005
case Js::OpCode::Ld_A:
70047006
case Js::OpCode::Conv_Num:
70057007
case Js::OpCode::ShrU_A:
7008+
case Js::OpCode::ToInteger:
7009+
case Js::OpCode::ToLength:
70067010
if(!ignoreIntOverflowCandidate)
70077011
{
70087012
// Int overflow matters for dst, so int overflow also matters for srcs

lib/Backend/GlobOpt.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -8114,6 +8114,24 @@ GlobOpt::TypeSpecializeIntUnary(
81148114
opcode = Js::OpCode::Ld_I4;
81158115
break;
81168116

8117+
case Js::OpCode::ToInteger:
8118+
newMin = min;
8119+
newMax = max;
8120+
opcode = Js::OpCode::Ld_I4;
8121+
isTransfer = true;
8122+
break;
8123+
8124+
case Js::OpCode::ToLength:
8125+
if (min >= 0)
8126+
{
8127+
newMin = min;
8128+
newMax = max;
8129+
opcode = Js::OpCode::Ld_I4;
8130+
isTransfer = true;
8131+
break;
8132+
}
8133+
return false;
8134+
81178135
case Js::OpCode::Neg_A:
81188136
if (min <= 0 && max >= 0)
81198137
{

lib/Backend/IRBuilder.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -1860,6 +1860,11 @@ IRBuilder::BuildReg2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, Js::Re
18601860
return;
18611861
}
18621862

1863+
case Js::OpCode::ToLength:
1864+
case Js::OpCode::ToInteger:
1865+
dstOpnd->SetValueType(ValueType::Int.ToLikely());
1866+
break;
1867+
18631868
case Js::OpCode::Conv_Str:
18641869
dstOpnd->SetValueType(ValueType::String);
18651870
break;

lib/Backend/JnHelperMethodList.h

+2
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ HELPERCALL_MATH(Conv_ToUInt32Core, (uint32(*)(double))Js::JavascriptMath::ToUInt
136136
HELPERCALL_MATH(Op_MaxInAnArray, Js::JavascriptMath::MaxInAnArray, AttrCanThrow)
137137
HELPERCALL_MATH(Op_MinInAnArray, Js::JavascriptMath::MinInAnArray, AttrCanThrow)
138138

139+
HELPERCALLCHK(Op_ToInteger, Js::JavascriptOperators::OP_ToInteger, AttrCanThrow)
140+
HELPERCALLCHK(Op_ToLength, Js::JavascriptOperators::OP_ToLength, AttrCanThrow)
139141
HELPERCALLCHK(Op_ConvString, Js::JavascriptConversion::ToString, AttrCanThrow)
140142
HELPERCALLCHK(Op_ConvPropertyKey, Js::JavascriptOperators::OP_ToPropertyKey, AttrCanThrow)
141143
HELPERCALLCHK(Op_CoerseString, Js::JavascriptConversion::CoerseString, AttrCanThrow)

lib/Backend/Lower.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -3143,6 +3143,14 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
31433143
instrPrev = this->LowerStPropIdArrFromVar(instr);
31443144
break;
31453145

3146+
case Js::OpCode::ToInteger:
3147+
this->LowerUnaryHelperMem(instr, IR::HelperOp_ToInteger);
3148+
break;
3149+
3150+
case Js::OpCode::ToLength:
3151+
this->LowerUnaryHelperMem(instr, IR::HelperOp_ToLength);
3152+
break;
3153+
31463154
#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
31473155
case Js::OpCode::GeneratorOutputBailInTraceLabel:
31483156
#endif

lib/Parser/InternalCommands.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
44
//-------------------------------------------------------------------------------------------------------
55

6-
// This file is designed to be included repeatedly to provide a list of internal commands
7-
// The Command macro should be defined each time before inclusion
6+
// The Internal Command mechanism currently supports OpCodes with one or two parameters
7+
// and a return value. Any such can be enabled as Internal commands by adding them below
88

99
// command name, expected parameters
10-
Command(Conv_Num, 1)
1110
Command(Conv_Obj, 1)
11+
Command(ToInteger, 1)
12+
Command(ToLength, 1)
1213

1314
#undef Command

lib/Runtime/Base/JnDirectFields.h

-2
Original file line numberDiff line numberDiff line change
@@ -650,8 +650,6 @@ ENTRY(methodName)
650650
ENTRY(registerChakraLibraryFunction)
651651
ENTRY(registerFunction)
652652
ENTRY(staticMethod)
653-
ENTRY(toLength)
654-
ENTRY(toInteger)
655653
ENTRY(arraySpeciesCreate)
656654
ENTRY(arrayCreateDataPropertyOrThrow)
657655
ENTRY(Array_values)

lib/Runtime/ByteCode/OpCodes.h

+3
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,9 @@ MACRO_EXTEND_WMS( Conv_Str, Reg2, OpOpndHasImplicitCal
334334
// Operation ToPropertyKey(var)
335335
MACRO_EXTEND_WMS( Conv_Prop, Reg2, OpOpndHasImplicitCall|OpTempNumberSources|OpTempObjectSources|OpCanCSE|OpPostOpDbgBailOut)
336336

337+
MACRO_EXTEND_WMS( ToInteger, Reg2, OpSideEffect|OpTempNumberProducing|OpTempNumberTransfer|OpTempObjectSources|OpOpndHasImplicitCall|OpProducesNumber)
338+
MACRO_EXTEND_WMS( ToLength, Reg2, OpSideEffect|OpTempNumberProducing|OpTempNumberTransfer|OpTempObjectSources|OpOpndHasImplicitCall|OpProducesNumber)
339+
337340
// Conv_Obj:
338341
// OpSideEffect - May throw exception on null/undefined.
339342
// Do not call valueOf/toString no implicit call

lib/Runtime/Language/InterpreterHandler.inl

+2
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ EXDEF2_WMS(A1toA1Mem, Conv_Str, JavascriptConver
9999
EXDEF2_WMS(A1toA1Mem, Conv_Prop, JavascriptOperators::OP_ToPropertyKey)
100100
DEF2_WMS(A1toA1Mem, Conv_Obj, JavascriptOperators::ToObject)
101101
EXDEF2_WMS(A1toA1Mem, NewUnscopablesWrapperObject,JavascriptOperators::ToUnscopablesWrapperObject)
102+
EXDEF2_WMS(A1toA1Mem, ToInteger, JavascriptOperators::OP_ToInteger)
103+
EXDEF2_WMS(A1toA1Mem, ToLength, JavascriptOperators::OP_ToLength)
102104
DEF2_WMS(A1toA1Mem, Conv_Num, JavascriptOperators::ToNumber)
103105
DEF2_WMS(A1toA1Mem, Incr_A, JavascriptMath::Increment)
104106
DEF2_WMS(A1toA1Mem, Decr_A, JavascriptMath::Decrement)

lib/Runtime/Language/JavascriptOperators.cpp

+39
Original file line numberDiff line numberDiff line change
@@ -10471,6 +10471,45 @@ using namespace Js;
1047110471
JIT_HELPER_END(NewAsyncFromSyncIterator);
1047210472
}
1047310473

10474+
Var JavascriptOperators::OP_ToInteger(Var value, ScriptContext* scriptContext)
10475+
{
10476+
JIT_HELPER_REENTRANT_HEADER(Op_ToInteger);
10477+
if (TaggedInt::Is(value))
10478+
{
10479+
return value;
10480+
}
10481+
else if (JavascriptOperators::IsUndefinedOrNull(value))
10482+
{
10483+
return TaggedInt::ToVarUnchecked(0);
10484+
}
10485+
10486+
return JavascriptNumber::ToVarIntCheck(JavascriptConversion::ToInteger(value, scriptContext), scriptContext);
10487+
JIT_HELPER_END(Op_ToInteger);
10488+
}
10489+
10490+
Var JavascriptOperators::OP_ToLength(Var value, ScriptContext* scriptContext)
10491+
{
10492+
JIT_HELPER_REENTRANT_HEADER(Op_ToLength);
10493+
if (TaggedInt::Is(value))
10494+
{
10495+
if (TaggedInt::ToInt32(value) > 0)
10496+
{
10497+
return value;
10498+
}
10499+
else
10500+
{
10501+
return TaggedInt::ToVarUnchecked(0);
10502+
}
10503+
}
10504+
else if (JavascriptOperators::IsUndefinedOrNull(value))
10505+
{
10506+
return TaggedInt::ToVarUnchecked(0);
10507+
}
10508+
10509+
return JavascriptNumber::ToVar(JavascriptConversion::ToLength(value, scriptContext), scriptContext);
10510+
JIT_HELPER_END(Op_ToLength);
10511+
}
10512+
1047410513
Js::Var
1047510514
JavascriptOperators::BoxStackInstance(Js::Var instance, ScriptContext * scriptContext, bool allowStackFunction, bool deepCopy)
1047610515
{

lib/Runtime/Language/JavascriptOperators.h

+3
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,9 @@ namespace Js
653653
static Var OP_ResumeYield(ResumeYieldData* yieldData, RecyclableObject* iterator);
654654
static Var OP_NewAsyncFromSyncIterator(Var syncIterator, ScriptContext* scriptContext);
655655

656+
static Var OP_ToInteger(Var value, ScriptContext* scriptContext);
657+
static Var OP_ToLength(Var value, ScriptContext* scriptContext);
658+
656659
template <typename T>
657660
static void * JitRecyclerAlloc(DECLSPEC_GUARD_OVERFLOW size_t size, Recycler* recycler)
658661
{

lib/Runtime/Library/JavascriptLibrary.cpp

+1-5
Original file line numberDiff line numberDiff line change
@@ -5199,17 +5199,13 @@ namespace Js
51995199
bool JavascriptLibrary::InitializeChakraLibraryObject(DynamicObject * chakraLibraryObject, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode)
52005200
{
52015201
JavascriptLibrary* library = chakraLibraryObject->GetLibrary();
5202-
typeHandler->Convert(chakraLibraryObject, mode, 8);
5202+
typeHandler->Convert(chakraLibraryObject, mode, 5);
52035203

52045204
Field(JavascriptFunction*)* builtinFuncs = library->GetBuiltinFunctions();
52055205
JavascriptFunction * func = nullptr;
52065206

5207-
library->AddFunctionToLibraryObject(chakraLibraryObject, PropertyIds::toLength, &JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_ToLengthFunction, 1);
5208-
library->AddFunctionToLibraryObject(chakraLibraryObject, PropertyIds::toInteger, &JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_ToIntegerFunction, 1);
5209-
library->AddFunctionToLibraryObject(chakraLibraryObject, PropertyIds::GetLength, &JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_GetLength, 1);
52105207
library->AddFunctionToLibraryObject(chakraLibraryObject, PropertyIds::InitInternalProperties, &JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_InitInternalProperties, 1);
52115208
library->AddMember(chakraLibraryObject, PropertyIds::isArray, library->isArrayFunction);
5212-
library->AddMember(chakraLibraryObject, PropertyIds::Object, library->objectConstructor);
52135209
library->AddFunctionToLibraryObject(chakraLibraryObject, PropertyIds::arraySpeciesCreate, &JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_ArraySpeciesCreate, 2);
52145210
library->AddFunctionToLibraryObject(chakraLibraryObject, PropertyIds::arrayCreateDataPropertyOrThrow, &JsBuiltInEngineInterfaceExtensionObject::EntryInfo::JsBuiltIn_Internal_ArrayCreateDataPropertyOrThrow, 3);
52155211
func = library->AddFunctionToLibraryObject(chakraLibraryObject, PropertyIds::builtInCallInstanceFunction, &EngineInterfaceObject::EntryInfo::CallInstanceFunction, 1);

lib/Runtime/Library/JsBuiltIn/JsBuiltIn.js

+28-31
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
return { value: undefined, done: true };
5555
} else {
5656
let index = o.__$nextIndex$__;
57-
let len = __chakraLibrary.isArray(a) ? a.length : __chakraLibrary.GetLength(a);
57+
let len = @@ToLength(a.length);
5858

5959
if (index < len) { // < comparison should happen instead of >= , because len can be NaN
6060
let itemKind = o.__$kind$__;
@@ -118,14 +118,14 @@
118118

119119
platform.registerFunction(platform.FunctionKind.Array_indexOf, function (searchElement, fromIndex = undefined) {
120120
// ECMAScript 2017 #sec-array.prototype.indexof
121-
122-
let {o, len} = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.indexOf");
121+
const o = @@Conv_Obj(this);
122+
const len = @@ToLength(o.length);
123123

124124
if (len === 0) {
125125
return -1;
126126
}
127127

128-
let n = __chakraLibrary.toInteger(fromIndex);
128+
const n = @@ToInteger(fromIndex);
129129
if (n >= len) {
130130
return -1;
131131
}
@@ -163,17 +163,6 @@
163163
return -1;
164164
});
165165

166-
platform.registerChakraLibraryFunction("CheckArrayAndGetLen", function (obj, builtInFunc) {
167-
if (__chakraLibrary.isArray(obj)) {
168-
return { o: obj, len: obj.length };
169-
} else {
170-
if (obj === null || obj === undefined) {
171-
__chakraLibrary.raiseThis_NullOrUndefined(builtInFunc);
172-
}
173-
return { o: @@Conv_Obj(obj), len: __chakraLibrary.toLength(obj["length"]) };
174-
}
175-
});
176-
177166
platform.registerChakraLibraryFunction("MergeSort", function(array, length, compareFn) {
178167
const buffer = [];
179168
buffer.__proto__ = null;
@@ -269,7 +258,8 @@
269258
compareFn = __chakraLibrary.DefaultSortCompare;
270259
}
271260

272-
const {o, len} = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.sort");
261+
const o = @@Conv_Obj(this);
262+
const len = @@ToLength(o.length);
273263

274264
if (len < 2) { // early return if length < 2
275265
return o;
@@ -321,9 +311,9 @@
321311

322312
platform.registerFunction(platform.FunctionKind.Array_filter, function (callbackfn, thisArg = undefined) {
323313
// ECMAScript 2017 #sec-array.prototype.filter
314+
const o = @@Conv_Obj(this);
315+
const len = @@ToLength(o.length);
324316

325-
let {o, len} = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.filter");
326-
327317
if (typeof callbackfn !== "function") {
328318
__chakraLibrary.raiseFunctionArgument_NeedFunction("Array.prototype.filter");
329319
}
@@ -349,7 +339,7 @@
349339
platform.registerChakraLibraryFunction("FlattenIntoArray", function(target, source, sourceLen, start, depth)
350340
{
351341
// this is FlattenIntoArray from the flat/flatMap proposal BUT with no mapperFunction
352-
// a seperate function has been made to handle the case where there is a mapperFunction
342+
// a separate function has been made to handle the case where there is a mapperFunction
353343

354344
//1. Let targetIndex be start.
355345
let targetIndex = start;
@@ -372,7 +362,7 @@
372362
// v. If shouldFlatten is true, then
373363
// 1. Let elementLen be ? ToLength(? Get(element, "length")).
374364
// 2. Set targetIndex to ? FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1).
375-
targetIndex = __chakraLibrary.FlattenIntoArray(target, element, __chakraLibrary.toLength(element.length), targetIndex, depth - 1);
365+
targetIndex = __chakraLibrary.FlattenIntoArray(target, element, @@ToLength(element.length), targetIndex, depth - 1);
376366
} else {
377367
// vi. Else,
378368
// 1. If targetIndex >= 2^53-1, throw a TypeError exception.
@@ -422,7 +412,7 @@
422412
// 2. Set targetIndex to ? FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1).
423413
if (__chakraLibrary.isArray(element)) {
424414
// instead of calling FlattenIntoArray use a simple loop here - as depth is always 0
425-
innerLength = __chakraLibrary.toLength(element.length);
415+
innerLength = @@ToLength(element.length);
426416
innerIndex = 0;
427417
while (innerIndex < innerLength) {
428418
if (innerIndex in element) {
@@ -459,12 +449,13 @@
459449
platform.registerFunction(platform.FunctionKind.Array_flat, function (depth = undefined) {
460450
//1. Let O be ? ToObject(this value).
461451
//2. Let sourceLen be ? ToLength(? Get(O, "length")).
462-
let {o, len} = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.flat");
452+
const o = @@Conv_Obj(this);
453+
const len = @@ToLength(o.length);
463454

464455
//3. Let depthNum be 1.
465456
//4. If depth is not undefined, then
466457
//5. Set depthNum to ? ToInteger(depth).
467-
const depthNum = depth !== undefined ? __chakraLibrary.toInteger(depth) : 1;
458+
const depthNum = depth !== undefined ? @@ToInteger(depth) : 1;
468459
//6. Let A be ? ArraySpeciesCreate(O, 0).
469460
const A = __chakraLibrary.arraySpeciesCreate(o, 0);
470461
//7. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
@@ -476,7 +467,8 @@
476467
platform.registerFunction(platform.FunctionKind.Array_flatMap, function (mapperFunction, thisArg = undefined) {
477468
//1. Let O be ? ToObject(this value).
478469
//2. Let sourceLen be ? ToLength(? Get(O, "length")).
479-
let {o, len} = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.flatMap");
470+
const o = @@Conv_Obj(this);
471+
const len = @@ToLength(o.length);
480472

481473
//3. If IsCallable(mapperFunction) is false throw a TypeError exception
482474
if (typeof mapperFunction !== "function") {
@@ -496,7 +488,8 @@
496488

497489
//Let O be ? ToObject(this value).
498490
//Let len be ? ToLength(? Get(O, "length")).
499-
let {o, len} = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.forEach");
491+
const o = @@Conv_Obj(this);
492+
const len = @@ToLength(o.length);
500493

501494
//If IsCallable(callbackfn) is false, throw a TypeError exception.
502495
if (typeof callbackfn !== "function") {
@@ -530,7 +523,8 @@
530523

531524
//Let O be ? ToObject(this value).
532525
//Let len be ? ToLength(? Get(O, "length")).
533-
let {o, len} = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.some");
526+
const o = @@Conv_Obj(this);
527+
const len = @@ToLength(o.length);
534528

535529
//If IsCallable(callbackfn) is false, throw a TypeError exception.
536530
if (typeof callbackfn !== "function") {
@@ -567,7 +561,8 @@
567561

568562
//Let O be ? ToObject(this value).
569563
//Let len be ? ToLength(? Get(O, "length")).
570-
let {o, len} = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.every");
564+
const o = @@Conv_Obj(this);
565+
const len = @@ToLength(o.length);
571566

572567
//If IsCallable(callbackfn) is false, throw a TypeError exception.
573568
if (typeof callbackfn !== "function") {
@@ -604,7 +599,8 @@
604599

605600
//Let O be ? ToObject(this value).
606601
//Let len be ? ToLength(? Get(O, "length")).
607-
let {o, len} = __chakraLibrary.CheckArrayAndGetLen(this,"Array.prototype.includes");
602+
const o = @@Conv_Obj(this);
603+
const len = @@ToLength(o.length);
608604

609605
//If len is 0, return false.
610606
if (len === 0) {
@@ -613,7 +609,7 @@
613609

614610
//Let n be ? ToInteger(fromIndex).
615611
//Assert: If fromIndex is undefined, then n is 0.
616-
let n = __chakraLibrary.toInteger(fromIndex);
612+
let n = @@ToInteger(fromIndex);
617613
let k;
618614

619615
//If n >= 0, then
@@ -652,7 +648,8 @@
652648

653649
//Let O be ? ToObject(this value).
654650
//Let len be ? ToLength(? Get(O, "length")).
655-
let {o, len} = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.reduce");
651+
const o = @@Conv_Obj(this);
652+
const len = @@ToLength(o.length);
656653

657654
//If IsCallable(callbackfn) is false, throw a TypeError exception.
658655
if (typeof callbackfn !== "function") {
@@ -671,7 +668,7 @@
671668

672669
//If initialValue is present, then
673670
//Set accumulator to initialValue.
674-
if (arguments.length > 1) { //Checking for array length because intialValue could be passed in as undefined
671+
if (arguments.length > 1) { //Checking for array length because initialValue could be passed in as undefined
675672
accumulator = initialValue;
676673
}
677674
//Else initialValue is not present,

0 commit comments

Comments
 (0)