Skip to content

NativeProxy: fix set trap not passing receiver object#2347

Draft
rbri wants to merge 10 commits into
mozilla:masterfrom
HtmlUnit:set_trap_receiver
Draft

NativeProxy: fix set trap not passing receiver object#2347
rbri wants to merge 10 commits into
mozilla:masterfrom
HtmlUnit:set_trap_receiver

Conversation

@rbri

@rbri rbri commented Mar 22, 2026

Copy link
Copy Markdown
Collaborator

Co-authored-by: Lai Quang Duong

This

  • passes the receiver to the set trap
  • passes the receiver to the get trap
  • fixes an StackOverflow exception (became visible after the change for 'passes the receiver to the set trap')
  • adds a bunch of spec hints to the implementation of the NativeReflect class
  • implements a workaround for the missing put return value in class NativeProxy, this workaround is used by NativeReflect to implement a more correct behaviour
  • fixes a check in NativeReflect; now checks for Callable in sync with the spec

This does not make so many more 262 test to pass, but i think is at least a small step forward.

@rbri

rbri commented Mar 22, 2026

Copy link
Copy Markdown
Collaborator Author

will work on the failing tests

@rbri

rbri commented May 28, 2026

Copy link
Copy Markdown
Collaborator Author

This is much bigger than expected, i have to fix the NativeReflect impl (inf fact bring it closer to the spec) to fix the StackOverflow.
Hope i have some time tomorrow to work on this.

@rbri rbri force-pushed the set_trap_receiver branch from ea6714b to 53d53f4 Compare May 29, 2026 06:16
rbri added 2 commits May 29, 2026 08:22
…low in set-mutable-binding-idref-with-proxy-env.js

additionally limited return code handling for put for NativeProxy was implemented and used by NativeReflect. This fixes some more tests
@rbri rbri force-pushed the set_trap_receiver branch from 1b266f5 to 0dab4f7 Compare May 29, 2026 10:21
@rbri rbri force-pushed the set_trap_receiver branch from 2501309 to 0bd9610 Compare May 29, 2026 13:38
@rbri rbri force-pushed the set_trap_receiver branch from 0bd9610 to 5fdb19e Compare May 29, 2026 13:39
@rbri rbri marked this pull request as ready for review May 29, 2026 14:05
@rbri

rbri commented May 29, 2026

Copy link
Copy Markdown
Collaborator Author

@duonglaiquang sorry for being late on this, but is was harder than expected. My plan is to make a HtmlUnit 5.1.0 release this weekend, i fear this will not be reviewed/merged for the release. Hope this is ok for you...

@rbri rbri requested a review from Copilot May 30, 2026 07:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Updates Rhino’s Proxy/Reflect behavior around receiver forwarding (notably for Proxy set and Reflect get/set) and expands the ES6 test suite to cover receiver-sensitive semantics, aiming to align more closely with ECMA-262.

Changes:

  • Add/expand JUnit coverage for Reflect.get, Reflect.set, and Proxy set receiver behavior (including with(proxy) scenarios).
  • Refactor parts of NativeReflect to forward receivers and inline portions of OrdinarySetWithOwnDescriptor.
  • Introduce NativeProxy.putAndReturn(...) helpers to expose a boolean result for use by Reflect.set.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 27 comments.

Show a summary per file
File Description
tests/testsrc/test262.properties Updates recorded test262 support/unsupported counts for Proxy/Reflect.
tests/src/test/java/org/mozilla/javascript/tests/es6/NativeReflectTest.java Adds extensive coverage for Reflect.get/Reflect.set receiver semantics and related invariants.
tests/src/test/java/org/mozilla/javascript/tests/es6/NativeProxyTest.java Adds tests asserting Proxy set trap receives a receiver and exercises with(proxy) behavior.
rhino/src/main/java/org/mozilla/javascript/NativeReflect.java Adjusts Reflect operations to use receiver-aware access and implements a custom set path.
rhino/src/main/java/org/mozilla/javascript/NativeProxy.java Adds putAndReturn(...) overloads and changes set trap invocation argument list.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 568 to 573
Function trap = getTrap(TRAP_SET);
if (trap != null) {
boolean booleanTrapResult =
ScriptRuntime.toBoolean(callTrap(trap, new Object[] {target, name, value}));
ScriptRuntime.toBoolean(
callTrap(trap, new Object[] {target, name, value, this}));
if (!booleanTrapResult) {
Comment on lines 634 to +642
Function trap = getTrap(TRAP_SET);
if (trap != null) {
boolean booleanTrapResult =
ScriptRuntime.toBoolean(
callTrap(
trap,
new Object[] {target, ScriptRuntime.toString(index), value}));
new Object[] {
target, ScriptRuntime.toString(index), value, this
}));
Comment on lines 707 to 712
Function trap = getTrap(TRAP_SET);
if (trap != null) {
boolean booleanTrapResult =
ScriptRuntime.toBoolean(callTrap(trap, new Object[] {target, key, value}));
ScriptRuntime.toBoolean(
callTrap(trap, new Object[] {target, key, value, this}));
if (!booleanTrapResult) {
Comment on lines 470 to 498
// receiver == target (or target has no own property P):
// delegate to [[Set]] on the receiver, which correctly fires any proxy
// set trap when receiver/target is a Proxy.

// For a NativeProxy, we use putAndReturn() to capture the result.
if (target instanceof NativeProxy proxyTarget) {
if (key instanceof Symbol) {
return proxyTarget.putAndReturn((Symbol) key, receiver, args[2]);
}

StringIdOrIndex soi = ScriptRuntime.toStringIdOrIndex(key);
if (soi.stringId == null) {
return proxyTarget.putAndReturn(soi.index, receiver, args[2]);
}
return proxyTarget.putAndReturn(soi.stringId, receiver, args[2]);
}

if (ScriptRuntime.isSymbol(args[1])) {
receiver.put((Symbol) args[1], receiver, args[2]);
// For a plain ScriptableObject put() has no return value, we
// assume true.
if (key instanceof Symbol) {
receiver.put((Symbol) key, receiver, args[2]);
} else {
StringIdOrIndex soi = ScriptRuntime.toStringIdOrIndex(args[1]);
StringIdOrIndex soi = ScriptRuntime.toStringIdOrIndex(key);
if (soi.stringId == null) {
receiver.put(soi.index, receiver, args[2]);
} else {
receiver.put(soi.stringId, receiver, args[2]);
}
}
Comment on lines +261 to 264
// Step 3: default receiver to target when not supplied.
Scriptable receiver =
(args.length > 2 && args[2] instanceof Scriptable) ? (Scriptable) args[2] : target;

Comment on lines +261 to 264
// Step 3: default receiver to target when not supplied.
Scriptable receiver =
(args.length > 2 && args[2] instanceof Scriptable) ? (Scriptable) args[2] : target;

Comment on lines +436 to +440
// Step 3: default receiver to target when not supplied (args[3]).
// Note: receiver is intentionally typed as Scriptable, not ScriptableObject,
// because the caller may pass any object (e.g. a Proxy) as the receiver.
Scriptable receiver = args.length > 3 ? ScriptableObject.ensureScriptable(args[3]) : target;

Comment on lines 431 to 434
ScriptableObject target = checkTarget(args);
if (args.length < 2) {
return true;
}
Comment on lines +436 to +440
// Step 3: default receiver to target when not supplied (args[3]).
// Note: receiver is intentionally typed as Scriptable, not ScriptableObject,
// because the caller may pass any object (e.g. a Proxy) as the receiver.
Scriptable receiver = args.length > 3 ? ScriptableObject.ensureScriptable(args[3]) : target;

Comment on lines 431 to 434
ScriptableObject target = checkTarget(args);
if (args.length < 2) {
return true;
}
@rbri

rbri commented May 30, 2026

Copy link
Copy Markdown
Collaborator Author

will work on all the sugestions... at least some looking correct ;-)

@rbri rbri requested a review from Copilot May 30, 2026 10:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Comment on lines +87 to +90
if (!(args[0] instanceof Callable)) {
throw ScriptRuntime.notFunctionError(args[0]);
}
Scriptable callable = (Scriptable) args[0];
Comment on lines 203 to 216
Object key = args[1];

try {
if (key instanceof Symbol) {
return target.defineOwnProperty(cx, key, desc);
} else {
String propertyKey =
ScriptRuntime.toString(
ScriptRuntime.toPrimitive(key, ScriptRuntime.StringClass));
return target.defineOwnProperty(cx, propertyKey, desc);
}

String propertyKey =
ScriptRuntime.toString(
ScriptRuntime.toPrimitive(key, ScriptRuntime.StringClass));
return target.defineOwnProperty(cx, propertyKey, desc);
} catch (EcmaError e) {
// Rhino throws where the spec says [[DefineOwnProperty]] should return false.
// Map those back to the spec-correct false return value.
return false;
}
Comment on lines 431 to 435
ScriptableObject target = checkTarget(args);
if (args.length < 2) {
return true;
}

key = ScriptRuntime.toString(args[1]); // coerce to String
}

if (receiver != target) {
Comment on lines +483 to +487
if (receiver instanceof ScriptableObject receiverObj) {
DescriptorInfo newDesc = new DescriptorInfo(true, true, true, args[2]);
receiverObj.defineOwnProperty(cx, key, newDesc);
}
return true;
Comment on lines +588 to +589
receiverObj.defineOwnProperty(cx, key, valueDesc);
return true;
Comment on lines +594 to +595
receiverObj.defineOwnProperty(cx, key, newDesc);
return true;
@rbri rbri marked this pull request as draft May 30, 2026 13:42
@rbri

rbri commented May 30, 2026

Copy link
Copy Markdown
Collaborator Author

this seems to be a rabbit hole, i have to think about a good way to fix this step by step. Back to Draft...

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.

2 participants