Skip to content
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

FEAT: Implement Symbol.hasInstance for Function.prototype #1751

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

0xe
Copy link
Contributor

@0xe 0xe commented Dec 9, 2024

Adds support for Function.prototype[Symbol.hasInstance].

@0xe 0xe changed the title FEAT: Implement Symbol.hasInstance FEAT: Implement Symbol.hasInstance for Function.prototype Dec 9, 2024
@0xe 0xe requested review from rbri and andreabergia December 12, 2024 01:24
@0xe 0xe force-pushed the scratch/satish/function-prototype-hasinstance branch 2 times, most recently from 732d044 to 5aa5f4a Compare December 12, 2024 01:38
@0xe 0xe marked this pull request as ready for review December 12, 2024 01:40
@0xe 0xe force-pushed the scratch/satish/function-prototype-hasinstance branch 2 times, most recently from 013b02b to 680b2a2 Compare December 12, 2024 05:13
@rbri
Copy link
Collaborator

rbri commented Dec 12, 2024

@0xe thanks for taking care of my comments

Copy link
Collaborator

@gbrail gbrail left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this!

Unless I'm missing something (and in JavaScript I'm usually missing something) there is an existing pattern to add a new symbol-keyed property to a native object -- see the implementation of "SymbolId_Iterator" in NativeString, for instance. This change seems to be doing some of that and some of something else. Can you please try to do it that way? Thanks!

@@ -46,4 +46,15 @@ public static void addSymbolUnscopables(
ScriptableObject.putProperty(unScopablesDescriptor, "writable", false);
constructor.defineOwnProperty(cx, SymbolKey.UNSCOPABLES, unScopablesDescriptor, false);
}

/** Registers the symbol <code>[Symbol.hasInstance]</code> on the given constructor function. */
public static void addSymbolHasInstance(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get what you're trying to do here, but I don't think that we should add a new function to a "ScriptRuntime" class that we're only going to use in one place. I'd suggest that instead of all this, you just call "defineProperty" on the "constructor" object back in BaseFunction and pass it the bitset (I'll put a comment there too).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You were right, those were unnecessary. I've removed them.

Context cx = Context.getCurrentContext();
Object hasInstance = ScriptRuntime.getObjectElem(this, SymbolKey.HAS_INSTANCE, cx);
if (hasInstance instanceof Callable) {
return (boolean)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that I know all the semantics of just casting to boolean here, but if I know anything about JavaScript, it's 90% edge cases.

So, since the function here could literally return anything, you should use "ScriptRuntime.toBoolean" here, which can cast any number of objects correctly to a "boolean".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it.

obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed);
IdFunctionObject constructor = obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed);
if (cx.getLanguageVersion() >= Context.VERSION_ES6) {
ScriptRuntimeES6.addSymbolHasInstance(cx, scope, constructor);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to ask why you don't just call "defineProperty" here, but actually I'm wondering why we need this at all -- adding the new symbol case in the other places that you added it should be enough for this to work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You were right, those were unnecessary. I've removed them.


if (cx != null) {
Scriptable scope = this.getParentScope();
obj =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's great to use a Lambda function here, but since this class still inherits from "IdScriptableObject", you should be able to make it work by adding a case to the switch in the "exec" function for your new "SymbolId_hasInstance" case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, this is way simpler. Changed it to switch on execIdCall.

@0xe
Copy link
Contributor Author

0xe commented Dec 13, 2024

Thanks for working on this!

Unless I'm missing something (and in JavaScript I'm usually missing something) there is an existing pattern to add a new symbol-keyed property to a native object -- see the implementation of "SymbolId_Iterator" in NativeString, for instance. This change seems to be doing some of that and some of something else. Can you please try to do it that way? Thanks!

Thank you. I will try to address these in the coming days.

@0xe 0xe force-pushed the scratch/satish/function-prototype-hasinstance branch from 680b2a2 to 5e7ebb0 Compare December 18, 2024 08:38
@0xe 0xe force-pushed the scratch/satish/function-prototype-hasinstance branch from 7f1364e to 5e7ebb0 Compare January 2, 2025 04:17

Utils.runWithAllOptimizationLevels(
(cx) -> {
cx.setLanguageVersion(Context.VERSION_ES6);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are now some assertThrows.... methods in the Utils, maybe you can use one of these

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I've used Utils.assertEcmaErrorES6()

@0xe 0xe force-pushed the scratch/satish/function-prototype-hasinstance branch 2 times, most recently from ce2c9af to 31bb5ea Compare January 3, 2025 08:14
- Remove unnecessary code
- Simplify implementation to use execIdCall as BaseFunction inherits from IdScriptableObject
- Use Utils.assertEcmaErrorES6
@0xe 0xe force-pushed the scratch/satish/function-prototype-hasinstance branch from 31bb5ea to 6e797d9 Compare January 3, 2025 08:19
@0xe 0xe requested review from gbrail and rbri January 3, 2025 08:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants