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 Object.fromEntries #5622
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
ArrayFlat: { className: "Array", methodName: "flat", argumentsCount: 0, forceInline: true /*optional*/ }, | ||
ArrayFlatMap: { className: "Array", methodName: "flatMap", argumentsCount: 1, forceInline: true /*optional*/ }, | ||
ArrayForEach: { className: "Array", methodName: "forEach", argumentsCount: 1, forceInline: true /*optional*/ }, | ||
ObjectFromEntries: { className: "Object", staticMethod: true, methodName: "fromEntries", argumentsCount: 1, forceInline: true /*optional*/ }, | ||
}; | ||
|
||
var setPrototype = platform.builtInSetPrototype; | ||
|
@@ -39,10 +40,13 @@ | |
__chakraLibrary.ArrayIterator.prototype = CreateObject(iteratorPrototype); | ||
__chakraLibrary.raiseNeedObjectOfType = platform.raiseNeedObjectOfType; | ||
__chakraLibrary.raiseThis_NullOrUndefined = platform.raiseThis_NullOrUndefined; | ||
__chakraLibrary.raiseNeedObject = platform.raiseNeedObject; | ||
__chakraLibrary.raiseNonObjectFromIterable = platform.raiseNonObjectFromIterable; | ||
__chakraLibrary.raiseLengthIsTooBig = platform.raiseLengthIsTooBig; | ||
__chakraLibrary.raiseFunctionArgument_NeedFunction = platform.raiseFunctionArgument_NeedFunction; | ||
__chakraLibrary.callInstanceFunc = platform.builtInCallInstanceFunction; | ||
__chakraLibrary.functionBind = platform.builtInJavascriptFunctionEntryBind; | ||
__chakraLibrary.objectDefineProperty = _objectDefineProperty; | ||
|
||
_objectDefineProperty(__chakraLibrary.ArrayIterator.prototype, 'next', | ||
// Object's getter and setter can get overriden on the prototype, in that case while setting the value attributes, we will end up with TypeError | ||
|
@@ -440,4 +444,32 @@ | |
|
||
return undefined; | ||
}); | ||
|
||
platform.registerFunction(FunctionsEnum.ObjectFromEntries, function (iterable) { | ||
// #sec-object.fromentries | ||
"use strict"; | ||
if (iterable === null || iterable === undefined) { | ||
__chakraLibrary.raiseNeedObject("Object.fromEntries"); | ||
} | ||
|
||
const o = {}; | ||
const propDescriptor = { | ||
enumerable : true, | ||
configurable : true, | ||
writable : true, | ||
value : undefined | ||
}; | ||
|
||
let key; | ||
for (const entry of iterable) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be tainted by overwriting There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per the proposed spec this method is specifically meant to use the iterator method of the provided iterable - i.e. if using an array and Array.prototype[Symbol.iterator] is overwritten it's meant to behave differently. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, weird. All of the Intl things that iterate through arrays call out There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's because the method is designed to be usable with other iterables, not just arrays e.g. generator functions etc. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, see DETAILS.md in the proposal. This is to match the very similar behavior of the Map constructor (which is in fact defined using the same abstract operation).
There's one in test262! Not sure if you're using that or would consider it sufficient, just thought I'd mention. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bakkot I ran this against test262 before submitting the PR but the Chakracore CI doesn't run test262 so I've added alternate tests for this - check the diff of this PR for tests. |
||
if (typeof entry !== "object" || entry === null) { | ||
__chakraLibrary.raiseNonObjectFromIterable("Object.fromEntries"); | ||
} | ||
|
||
key = entry[0]; | ||
propDescriptor.value = entry[1]; | ||
__chakraLibrary.objectDefineProperty(o, key, propDescriptor); | ||
} | ||
return o; | ||
}); | ||
}); |
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.
Turns out this bit here is causing some problems in our internal tests that were initially obscured by the baseline changes.
@jackhorton how do we deal with the Intl object? We do lazy initialization there right? Perhaps we need to do the same here?
The specific issue is that when calling into script from here, there is a check that we can handle stack overflow, and that is failing in some cases.
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.
Oh right, this is the lazy initialization of the
Object
object, so this is already a similar pattern to what we do for intl.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 simply copied what was done for the array prototype - is there some difference between doing it for a prototype vs a constructor.
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 believe that the difference is in the calling code, not here. I believe I'll need to add some additional error handling elsewhere since that code path also doesn't seem to handle calling into a JS builtin at all, despite sounding like it should.
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.
A quick look shows that the EnsureBuiltInEngineIsReady doesn't have try/catch whereas EnsureIntlObjectReady does - what's confusing to me is that the EnsureBuiltInEngineIsReady method was previously used for ArrayPrototype without any problems.