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

Add JS_TryGetProperty #337

Merged
merged 3 commits into from
Apr 3, 2024
Merged

Conversation

chqrlie
Copy link
Collaborator

@chqrlie chqrlie commented Mar 28, 2024

  • add wrapper around JS_HasProperty / JS_GetProperty
  • further optimisation does not seem useful in the general case
  • optimize JS_TryGetPropertyInt64 for fast arrays

- add wrapper around JS_HasProperty / JS_GetProperty
- further optimisation does not seem useful in the general case
- optimize JS_TryGetPropertyInt64 for fast arrays
@saghul
Copy link
Contributor

saghul commented Mar 29, 2024

IIRC Ben mentioned avoiding to walk the prototype chain twice. Is that still not worth pursuing?

@chqrlie
Copy link
Collaborator Author

chqrlie commented Mar 29, 2024

IIRC Ben mentioned avoiding to walk the prototype chain twice. Is that still not worth pursuing?

As I wrote in the commit comment, avoiding the redundant prototype chain walk is left out for now because the use cases are not critical, except for array indexing, which I address separately in this patch.

Some Array methods should special case fast arrays: js_array_concat and js_array_lastIndexOf for example.

I am investigating 3 other ways to improve property access:

  • JS_GetPropertyInternal could return a way for the caller to determine where the property was found if at all. It already updates the inline cache, so this would not add much overhead and would fully address the purpose of JS_TryGetProperty.
  • We could maintain shape flags to track the presence of getters and/or setters except for __proto__ in the prototype chain. This would simplify JS_SetProperty and remove the need to walk the prototype chain. This requires a tricky change in the prototype chain handling, where a modification of a prototype object shape can be efficiently reflected in all prototype shapes that have a given shape as their own prototype.
  • With this modification in place, a much more efficient inline cache for property access can be implemented that would also cache property access in the prototype chain, hence optimize method calls.

quickjs.c Show resolved Hide resolved
- add wrapper around `JS_HasProperty` / `JS_GetProperty`
- further optimisation does not seem useful in the general case
- optimize `JS_TryGetPropertyInt64` for fast arrays
- add `js_get_fast_array_element()` to special case arrays and typed arrays
- use `js_get_fast_array_element()` in `JS_GetPropertyValue()`,
  `JS_TryGetPropertyInt64()` and `JS_GetPropertyInt64()`.
- simplify `js_array_at()`
Comment on lines +7944 to +7945
case JS_CLASS_ARRAY:
case JS_CLASS_ARGUMENTS:
Copy link
Contributor

Choose a reason for hiding this comment

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

It might make sense to put these together next to the typed array constants inside the enum so they make up a dense range.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's a good point, but it justifies a separate commit as changing the class ID order has subtle implications, among which all array initializers that use class IDs as index values and possibly other ones too.

quickjs.c Outdated
Comment on lines 8038 to 8041
if (res == FALSE) {
*pval = JS_UNDEFINED;
return FALSE;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this is correct, although the problem is probably more with JS_HasProperty.

JS_GetProperty(obj, prop) with obj="bar" and prop=1 returns "a", whereas JS_HasProperty claims the property doesn't exist.

In a similar vein, obj="foo" and prop="length" should produce 3, not property-not-found.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I agree, JS_HasProperty ignores properties of values that are not objects, which is the semantics of ECMA 7.3.12 HasProperty ( O, P ) that requires O to be an Object.

Similarly, JS_TryGetProperty() and JS_TryGetPropertyInt64() must only be called for Objects. These APIs should probably take a JSObject * but changing that would have caused too many modifications.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I am not sure JS_TryGetProperty() is useful after all. Optimizing JS_TryGetPropertyInt64() is definitely a good idea for array methods, but a more general function does not seem to provide a real advantage and may create some confusion. I shall investigate some more and post and updated patch.

Copy link
Contributor

Choose a reason for hiding this comment

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

My main motivation for #105 is to avoid looking up the property twice. In that respect a JS_TryGetProperty that's just JS_HasProperty + JS_GetProperty without caching the lookup indeed isn't useful.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

A better approach to avoiding the double lookup is to use an alternate JS_GetPropertyInternal function that would update a structure argument with the location of the property found: prototype level, fast_array / shape entry, getter?, exotic method call...

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, that's pretty much what I was thinking.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

OK, I shall simplify this PR and keep only the JS_TryGetPropertyInt64.

- add `js_get_fast_array_element()` to special case arrays and typed arrays
- use `js_get_fast_array_element()` in `JS_GetPropertyValue()`,
  `JS_TryGetPropertyInt64()` and `JS_GetPropertyInt64()`.
- simplify `js_array_at()`
@chqrlie chqrlie merged commit c15ef1f into quickjs-ng:master Apr 3, 2024
38 checks passed
@chqrlie chqrlie deleted the try-get-property branch April 3, 2024 03:10
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.

3 participants