Skip to content

Commit 9fdbe23

Browse files
committed
[MERGE #5584 @yullin-ms] implement Array.prototype.forEach in javascript
Merge pull request #5584 from pr/yullin/forEachJS Fixes OS: 18004206 implement array.prototype.forEach as JsBuiltIns.
2 parents 7f24991 + 1545cd0 commit 9fdbe23

10 files changed

+3136
-2787
lines changed

lib/Runtime/Language/amd64/amd64_Thunks.S

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,11 +216,13 @@ NESTED_ENTRY _ZN2Js23AsmJsExternalEntryPointEPNS_16RecyclableObjectENS_8CallInfo
216216
lea rbp, [rsp]
217217

218218
set_cfa_register rbp, (2*8) // Set to compute CFA as: rbp + 16 (sizeof: [rbp] [ReturnAddress])
219-
219+
220220
sub rsp, 40h
221221

222222
mov [rsp + 28h], r12
223+
.cfi_rel_offset r12, -18h
223224
mov [rsp + 30h], r13
225+
.cfi_rel_offset r13, -10h
224226

225227
mov r12, rdi // r12: entryObject
226228
mov r13, rsi // r13: callInfo
@@ -267,7 +269,9 @@ NESTED_ENTRY _ZN2Js23AsmJsExternalEntryPointEPNS_16RecyclableObjectENS_8CallInfo
267269
mov rsp, r13 // restore stack pointer
268270
Epilogue:
269271
mov r12, [rsp + 28h]
272+
.cfi_restore r12
270273
mov r13, [rsp + 30h]
274+
.cfi_restore r13
271275

272276
lea rsp, [rbp]
273277
pop_nonvol_reg rbp

lib/Runtime/Library/EngineInterfaceObjectBuiltIns.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ GlobalBuiltIn(JavascriptObject, EntryGetOwnPropertyNames)
2424
GlobalBuiltIn(JavascriptObject, EntryHasOwnProperty)
2525
GlobalBuiltIn(JavascriptObject, EntryKeys)
2626

27-
GlobalBuiltIn(JavascriptArray, EntryForEach)
2827
GlobalBuiltIn(JavascriptArray, EntryPush)
2928
GlobalBuiltIn(JavascriptArray, EntryJoin)
3029
GlobalBuiltIn(JavascriptArray, EntryMap)

lib/Runtime/Library/JavascriptArray.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8998,6 +8998,7 @@ using namespace Js;
89988998
return scriptContext->GetLibrary()->GetFalse();
89998999
}
90009000

9001+
// There is a Javascript built-in for forEach
90019002
Var JavascriptArray::EntryForEach(RecyclableObject* function, CallInfo callInfo, ...)
90029003
{
90039004
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);

lib/Runtime/Library/JavascriptLibrary.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,9 +1770,6 @@ namespace Js
17701770

17711771
/* No inlining Array_Every */ library->AddFunctionToLibraryObject(arrayPrototype, PropertyIds::every, &JavascriptArray::EntryInfo::Every, 1);
17721772

1773-
/* No inlining Array_ForEach */
1774-
library->AddMember(arrayPrototype, PropertyIds::forEach, library->EnsureArrayPrototypeForEachFunction());
1775-
17761773
builtinFuncs[BuiltinFunction::JavascriptArray_LastIndexOf] = library->AddFunctionToLibraryObject(arrayPrototype, PropertyIds::lastIndexOf, &JavascriptArray::EntryInfo::LastIndexOf, 1);
17771774
/* No inlining Array_Map */ library->AddFunctionToLibraryObject(arrayPrototype, PropertyIds::map, &JavascriptArray::EntryInfo::Map, 1);
17781775
/* No inlining Array_Reduce */ library->AddFunctionToLibraryObject(arrayPrototype, PropertyIds::reduce, &JavascriptArray::EntryInfo::Reduce, 1);
@@ -1804,6 +1801,7 @@ namespace Js
18041801
/* No inlining Array_SymbolIterator */ library->AddMember(arrayPrototype, PropertyIds::_symbolIterator, values);
18051802

18061803
/* No inlining Array_Filter */ library->AddFunctionToLibraryObject(arrayPrototype, PropertyIds::filter, &JavascriptArray::EntryInfo::Filter, 1);
1804+
/* No inlining Array_ForEach */ library->AddMember(arrayPrototype, PropertyIds::forEach, library->EnsureArrayPrototypeForEachFunction());
18071805
}
18081806

18091807
if (scriptContext->GetConfig()->IsES6UnscopablesEnabled())

lib/Runtime/Library/JsBuiltIn/JsBuiltIn.js

Lines changed: 61 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
ArrayFilter: { className: "Array", methodName: "filter", argumentsCount: 1, forceInline: true /*optional*/ },
1717
ArrayFlat: { className: "Array", methodName: "flat", argumentsCount: 0, forceInline: true /*optional*/ },
1818
ArrayFlatMap: { className: "Array", methodName: "flatMap", argumentsCount: 1, forceInline: true /*optional*/ },
19+
ArrayForEach: { className: "Array", methodName: "forEach", argumentsCount: 1, forceInline: true /*optional*/ },
1920
};
2021

2122
var setPrototype = platform.builtInSetPrototype;
@@ -185,23 +186,27 @@
185186
return -1;
186187
});
187188

188-
platform.registerFunction(FunctionsEnum.ArrayFilter, function (callbackfn, thisArg) {
189-
// ECMAScript 2017 #sec-array.prototype.filter
189+
platform.registerChakraLibraryFunction("CheckArrayAndGetLen", function (obj, builtInFunc) {
190190
"use strict";
191191

192-
if (this === null || this === undefined) {
193-
__chakraLibrary.raiseThis_NullOrUndefined("Array.prototype.filter");
192+
if (__chakraLibrary.isArray(obj)) {
193+
return { o: obj, len: obj.length }
194194
}
195-
196-
let o;
197-
let len
198-
if (__chakraLibrary.isArray(this)) {
199-
o = this;
200-
len = o.length;
201-
} else {
202-
o = __chakraLibrary.Object(this);
203-
len = __chakraLibrary.GetLength(o);
195+
else {
196+
if (this === null || this === undefined) {
197+
__chakraLibrary.raiseThis_NullOrUndefined(builtInFunc);
198+
}
199+
return { o: __chakraLibrary.Object(obj), len: __chakraLibrary.GetLength(obj) }
204200
}
201+
});
202+
203+
platform.registerFunction(FunctionsEnum.ArrayFilter, function (callbackfn, thisArg) {
204+
// ECMAScript 2017 #sec-array.prototype.filter
205+
"use strict";
206+
207+
let objInfo = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.filter");
208+
let o = objInfo.o;
209+
let len = objInfo.len;
205210

206211
if (typeof callbackfn !== "function") {
207212
__chakraLibrary.raiseFunctionArgument_NeedFunction("Array.prototype.filter");
@@ -358,18 +363,9 @@
358363
"use strict";
359364
//1. Let O be ? ToObject(this value).
360365
//2. Let sourceLen be ? ToLength(? Get(O, "length")).
361-
let o, sourceLen;
362-
363-
if (__chakraLibrary.isArray(this)) {
364-
o = this;
365-
sourceLen = o.length;
366-
} else {
367-
if (this === null || this === undefined) {
368-
__chakraLibrary.raiseThis_NullOrUndefined("Array.prototype.flat");
369-
}
370-
o = __chakraLibrary.Object(this);
371-
sourceLen = __chakraLibrary.GetLength(o);
372-
}
366+
let objInfo = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.flat");
367+
let o = objInfo.o;
368+
let sourceLen = objInfo.len;
373369
//3. Let depthNum be 1.
374370
//4. If depth is not undefined, then
375371
//5. Set depthNum to ? ToInteger(depth).
@@ -386,17 +382,11 @@
386382
"use strict";
387383
//1. Let O be ? ToObject(this value).
388384
//2. Let sourceLen be ? ToLength(? Get(O, "length")).
389-
let o, sourceLen;
390-
if (__chakraLibrary.isArray(this)) {
391-
o = this;
392-
sourceLen = o.length;
393-
} else {
394-
if (this === null || this === undefined) {
395-
__chakraLibrary.raiseThis_NullOrUndefined("Array.prototype.flatMap");
396-
}
397-
o = __chakraLibrary.Object(this);
398-
sourceLen = __chakraLibrary.GetLength(o);
399-
}
385+
386+
let objInfo = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.flatMap");
387+
let o = objInfo.o;
388+
let sourceLen = objInfo.len;
389+
400390
//3. If IsCallable(mapperFunction) is false throw a TypeError exception
401391
if (typeof mapperFunction !== "function") {
402392
__chakraLibrary.raiseFunctionArgument_NeedFunction("Array.prototype.flatMap");
@@ -415,4 +405,39 @@
415405
return A;
416406
});
417407

408+
platform.registerFunction(FunctionsEnum.ArrayForEach, function (callbackfn, thisArg) {
409+
// ECMAScript 2017 #sec-array.prototype.foreach
410+
"use strict";
411+
412+
let objInfo = __chakraLibrary.CheckArrayAndGetLen(this, "Array.prototype.forEach");
413+
let o = objInfo.o;
414+
let len = objInfo.len;
415+
416+
if (typeof callbackfn !== "function") {
417+
__chakraLibrary.raiseFunctionArgument_NeedFunction("Array.prototype.forEach");
418+
}
419+
420+
let k = 0;
421+
422+
if (thisArg === undefined) {
423+
while (k < len) {
424+
if (k in o) {
425+
let kValue = o[k];
426+
callbackfn(kValue, k, o);
427+
}
428+
k++;
429+
}
430+
} else {
431+
let boundCallback = __chakraLibrary.callInstanceFunc(__chakraLibrary.functionBind, callbackfn, thisArg);
432+
while (k < len) {
433+
if (k in o) {
434+
let kValue = o[k];
435+
boundCallback(kValue, k, o);
436+
}
437+
k++;
438+
}
439+
}
440+
441+
return undefined;
442+
});
418443
});

0 commit comments

Comments
 (0)