-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Array Iterators in javascript #4095
Conversation
Commits on top of "Merge conflict errors " are new code. Previous commits have been reviewed before in the builtins branch. |
} | ||
|
||
let a = o.arrayObj; | ||
var value, done; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var value, done; [](start = 16, length = 16)
initialize this as undefined and true, then you don't need to have it set two places below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: use let instead of var
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akroshg The jit will copy prop the values in either cases. I don't want to add an unconditional write which need not happen.
throw new TypeError("Array Iterator.prototype.next: 'this' is not an Array Iterator object"); | ||
} | ||
|
||
let a = o.arrayObj; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arrayObj [](start = 26, length = 8)
these are enumerable and visible to the script.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to non - enumerable for now.
Looks like, there are changes related to OS9049104 |
} | ||
else { | ||
let index = o.nextIndex; | ||
let len = Array.isArray(a) ? a.length : __chakraLibrary.GetArrayLength(a); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if Array.isArray is overridden?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That'd be bad. Will need an alternative. Thanks.
} | ||
|
||
let a = o.arrayObj; | ||
var value, done; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: use let instead of var
} | ||
|
||
if (!(o instanceof __chakraLibrary.ArrayIterator)) { | ||
throw new TypeError("Array Iterator.prototype.next: 'this' is not an Array Iterator object"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can user override TypeError?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Will need an alternative here. thanks.
|
||
o.nextIndex = index + 1; | ||
|
||
if (itemKind === 0 /*ArrayIterationKind.Key*/) { // TODO (megupta) : Use clean enums here ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using enums is the approach @dilijev and I have taken on the Intl.js side of things, I think its much cleaner.
var ObjectDefineProperty = function (obj, prop, attributes) { | ||
_objectDefineProperty(obj, prop, setPrototype(attributes, null)); | ||
}; | ||
var CreateObject = platform.builtInJavascriptObjectCreate; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way that we can simplify these aliases for all JsBuiltIns going forward? Like, perhaps we could make the names shorter or have a global standard library written in Javascript that all of these implementation files could use? Something along the lines of https://github.com/Microsoft/ChakraCore/pull/4083/files#diff-fa23cc60499db424efee4a57ac9bafddR105 would be my hope. Having everyone use _.keys or _.defineProperty rather than each files own (hopefully not but possibly) unique alias seems like it would make writing these JsBuiltIns much easier, especially for newer contributors.
#pragma warning(disable:4309) // truncation of constant value | ||
#pragma warning(disable:4838) // conversion from 'int' to 'const char' requires a narrowing conversion | ||
|
||
#pragma warning(pop) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this intentional? it looks like the warning setup for including the bytecode, but as far as I know this is a no-op right now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inherited this from the builtins branch and forgot to clean it up! Thanks.
/* | ||
* First parameter is the object onto which prototype should be set; second is the value | ||
*/ | ||
Var JsBuiltInEngineInterfaceExtensionObject::EntryJsBuiltIn_Internal_SetPrototype(RecyclableObject *function, CallInfo callInfo, ...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way we can share native helpers like this between JsBuiltIns and Intl.js? I know there is a similar function in the Intl extension object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can try moving it to EngineInterfaceObject::InitializeCommonNativeInterfaces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am going to address this as a separate PR. Also - #3962 is incomplete and requires some special handling for EnginerInterfaceObject's deferred type handler.
|
||
o.nextIndex = index + 1; | ||
|
||
if (itemKind === 0 /*ArrayIterationKind.Key*/) { // TODO (megupta) : Use clean enums here ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
give .Value more priority over .Key
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
"scriptType": "eval code", | ||
"lineCount": 1, | ||
"sourceLength": 11 | ||
"sourceLength": 11, | ||
"scriptId": 5, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this change? Is it due to ChakraLib.js?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Due to JsBuiltIn.js
@@ -42,6 +42,8 @@ namespace Js | |||
// Need a constructor cache on every function (script and native) to avoid extra checks on the fast path, if the function isn't fixed. | |||
Field(ConstructorCache*) constructorCache; | |||
|
|||
Field(bool) isJsBuiltInCode; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isJsBuiltInCode [](start = 20, length = 15)
I don't see this field is initialized anywhere? did you do that somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was inherited from the builtins branch. The constructor initialization was missing. It is set in the register* functions and used in a few places. Thanks for catching this!
|
||
if (callInfo.Count < 2) | ||
{ | ||
return scriptContext->GetLibrary()->GetUndefined(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't expect this one right?, the count will always be greater then 2? Should we assert and return 0 instead of undefined?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, converted to assert.
|
||
bool JsBuiltInEngineInterfaceExtensionObject::InitializeJsBuiltInNativeInterfaces(DynamicObject * builtInNativeInterfaces, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode) | ||
{ | ||
typeHandler->Convert(builtInNativeInterfaces, mode, 16); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
16 [](start = 60, length = 2)
curious why 16?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its the initSlotCapacity for the SimpleDictionaryTypeHandler. Changed it to 4, I think that suffices.
public: | ||
static NoProfileFunctionInfo JsBuiltIn_RegisterChakraLibraryFunction; | ||
static NoProfileFunctionInfo JsBuiltIn_RegisterFunction; | ||
static NoProfileFunctionInfo JsBuiltIn_Internal_GetArrayLengthFunction; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GetLength instead of GetArrayLength (as we are fetching the 'length' property).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
4772c90
to
f971233
Compare
I have removed the bug fix at #4051 from the PR's commits. |
DynamicObject* obj = DynamicObject::FromVar(args.Values[1]); | ||
unsigned propCount = TaggedInt::ToUInt32(args.Values[2]); | ||
|
||
Assert(callInfo.Count == 3 + propCount); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you don't need this, right? this function can be used for other functions in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assert will stay the same for all new functions as well. 3 here is this + object on which we want to set property attributes + count of properties
platform.registerChakraLibraryFunction("ArrayIterator", function (arrayObj, iterationKind) { | ||
"use strict"; | ||
__chakraLibrary.InitInternalProperties(this, 4, "__$arrayObj$__", "__$nextIndex$__", "__$kind$__", "__$internalDone$__"); | ||
this.__$arrayObj$__ = arrayObj; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.
$arrayObj$ [](start = 8, length = 19)
make sure you speak with Louis/Ed about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Got approval.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…ebugger trace. Also removed the "arguments" and "caller" property to be spec compliant. I opened an issue about the fact that the built ins methods in C++ are not spec compliant : chakra-core#3043
… the code from the following issue : chakra-core#3140 So BEFORE merging this Pull Request with the Master branch WE MUST fix the issue 3140.
…onfiguration. - fixed the source context id of the JS built ins.
- Remove IndexOf - Remove helper C++ functions toLength and toInteger - Remove IsIn fastpath : found errors in exprgen
b664d1e
to
5b5df92
Compare
return __chakraLibrary.CreateArrayIterator(o, 2 /* ArrayIterationKind.KeyAndValue*/); | ||
}); | ||
|
||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
; [](start = 2, length = 1)
nit: newline at end of file and unnecessary blank line above
throw new TypeError("Array.prototype.keys: 'this' is null or undefined"); | ||
} | ||
let o = __chakraLibrary.Object(this); | ||
return __chakraLibrary.CreateArrayIterator(o, 0 /* ArrayIterationKind.Key*/); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0 /* ArrayIterationKind.Key*/ [](start = 54, length = 29)
Can these magic constants be turned into named constants or and/or members of the Enum?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot declare these constants within the global function we use to set up the library. It should be stored on the chakraLib object. Its not neat, but I want to avoid storing constants on the chakraLib object.
if (itemKind === 1 /*ArrayIterationKind.Value*/) { | ||
value = a[index]; | ||
} | ||
else if (itemKind === 0 /*ArrayIterationKind.Key*/) { // TODO (megupta) : Use clean enums here ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this point we probably need to write a JS coding guideline. FWIW the prevailing pattern in library JS is to do } else if (...) {
on a single line (no newline between }
and else
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I am squashing CR suggestions with my prior commit, please bear with it!
5b5df92
to
32196f0
Compare
Merge pull request #4095 from meg-gupta:jsarrayitnodelay This change adds implementation of Javascript's array iterators in Javascript. This combined with optimization of try finally functions and enabling inlining within functions have try-catch/try-finally improves performance of es6 for-of loops. For large for-of loops the speedup is more than 2.5x.
This change adds implementation of Javascript's array iterators in Javascript.
This combined with optimization of try finally functions and enabling inlining within functions have try-catch/try-finally improves performance of es6 for-of loops.
For large for-of loops the speedup is more than 2.5x.