Skip to content

Commit 82369d9

Browse files
committed
[GR-71433] Converting values injected by instruments.
PullRequest: js/3632
2 parents 36b266d + f950f84 commit 82369d9

File tree

3 files changed

+139
-6
lines changed

3 files changed

+139
-6
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.truffle.js.test.tools;
42+
43+
import static org.junit.Assert.assertEquals;
44+
45+
import org.graalvm.polyglot.Context;
46+
import org.graalvm.polyglot.Value;
47+
import org.junit.Test;
48+
49+
import com.oracle.truffle.api.frame.VirtualFrame;
50+
import com.oracle.truffle.api.instrumentation.EventContext;
51+
import com.oracle.truffle.api.instrumentation.ExecutionEventNode;
52+
import com.oracle.truffle.api.instrumentation.ExecutionEventNodeFactory;
53+
import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
54+
import com.oracle.truffle.api.instrumentation.StandardTags;
55+
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
56+
import com.oracle.truffle.api.interop.InteropException;
57+
import com.oracle.truffle.api.interop.InteropLibrary;
58+
import com.oracle.truffle.api.interop.NodeLibrary;
59+
import com.oracle.truffle.js.test.JSTest;
60+
61+
public class GR71433 {
62+
private static final String INJECT_SHORT_INSTRUMENT_NAME = "InjectShortInstrument";
63+
64+
@TruffleInstrument.Registration(id = INJECT_SHORT_INSTRUMENT_NAME, services = InjectShortInstrument.class)
65+
static class InjectShortInstrument extends TruffleInstrument {
66+
67+
@Override
68+
protected void onCreate(Env env) {
69+
env.registerService(this);
70+
71+
ExecutionEventNodeFactory eenf = new ExecutionEventNodeFactory() {
72+
@Override
73+
public ExecutionEventNode create(final EventContext eventContext) {
74+
return new ExecutionEventNode() {
75+
@Override
76+
protected void onEnter(final VirtualFrame frame) {
77+
try {
78+
Object scope = NodeLibrary.getUncached().getScope(eventContext.getInstrumentedNode(), frame, false);
79+
InteropLibrary interop = InteropLibrary.getUncached(scope);
80+
if (interop.isMemberWritable(scope, "scopeWrite")) {
81+
interop.writeMember(scope, "scopeWrite", (short) 42);
82+
} else if (interop.isMemberWritable(scope, "unwind")) {
83+
throw eventContext.createUnwind(null);
84+
}
85+
} catch (InteropException iex) {
86+
throw new RuntimeException(iex);
87+
}
88+
}
89+
90+
@Override
91+
protected Object onUnwind(final VirtualFrame frame, final Object info) {
92+
return (short) 211;
93+
}
94+
95+
};
96+
}
97+
};
98+
SourceSectionFilter filter = SourceSectionFilter.newBuilder().tagIs(StandardTags.StatementTag.class).build();
99+
env.getInstrumenter().attachExecutionEventFactory(filter, eenf);
100+
}
101+
102+
}
103+
104+
@Test
105+
public void testShortInScopeWrite() {
106+
try (Context context = JSTest.newContextBuilder().build()) {
107+
context.getEngine().getInstruments().get(INJECT_SHORT_INSTRUMENT_NAME).lookup(InjectShortInstrument.class);
108+
Value result = context.eval("js", "(() => { var scopeWrite; return scopeWrite; })()");
109+
assertEquals(42, result.asInt());
110+
}
111+
}
112+
113+
@Test
114+
public void testShortInUnwind() {
115+
try (Context context = JSTest.newContextBuilder().build()) {
116+
context.getEngine().getInstruments().get(INJECT_SHORT_INSTRUMENT_NAME).lookup(InjectShortInstrument.class);
117+
Value result = context.eval("js", "(() => { var unwind; return unwind; })()");
118+
assertEquals(211, result.asInt());
119+
}
120+
}
121+
122+
}

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/JavaScriptNode.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import com.oracle.truffle.js.runtime.Errors;
6868
import com.oracle.truffle.js.runtime.JSArguments;
6969
import com.oracle.truffle.js.runtime.JSFrameUtil;
70+
import com.oracle.truffle.js.runtime.JSRuntime;
7071
import com.oracle.truffle.js.runtime.JavaScriptRootNode;
7172
import com.oracle.truffle.js.runtime.interop.ScopeVariables;
7273
import com.oracle.truffle.js.runtime.objects.JSModuleRecord;
@@ -106,6 +107,11 @@ public WrapperNode createWrapper(ProbeNode probe) {
106107
return new JavaScriptNodeWrapper(this, probe);
107108
}
108109

110+
@GenerateWrapper.IncomingConverter
111+
public Object convertIncomingValue(Object value) {
112+
return JSRuntime.importValue(value);
113+
}
114+
109115
/**
110116
* Executes this node using the specified context and frame and returns the result value.
111117
*

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/interop/ScopeVariables.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
4848
import com.oracle.truffle.api.RootCallTarget;
4949
import com.oracle.truffle.api.dsl.Cached;
50+
import com.oracle.truffle.api.dsl.Cached.Shared;
5051
import com.oracle.truffle.api.dsl.Specialization;
5152
import com.oracle.truffle.api.frame.Frame;
5253
import com.oracle.truffle.api.frame.FrameDescriptor;
@@ -72,6 +73,7 @@
7273
import com.oracle.truffle.js.nodes.access.ScopeFrameNode;
7374
import com.oracle.truffle.js.nodes.access.WriteNode;
7475
import com.oracle.truffle.js.nodes.function.BlockScopeNode;
76+
import com.oracle.truffle.js.nodes.interop.ImportValueNode;
7577
import com.oracle.truffle.js.nodes.module.ReadImportBindingNode;
7678
import com.oracle.truffle.js.runtime.JSArguments;
7779
import com.oracle.truffle.js.runtime.JSConfig;
@@ -355,27 +357,30 @@ static void doCached(ScopeVariables receiver, @SuppressWarnings("unused") String
355357
@Cached("member") String cachedMember,
356358
// We cache the member's write node for fast-path access
357359
@Cached(value = "findSlot(member, receiver)") ResolvedSlot resolvedSlot,
358-
@Cached(value = "findWriteNode(resolvedSlot)") WriteNode writeNode) throws UnknownIdentifierException {
359-
doWrite(receiver, cachedMember, value, writeNode, resolvedSlot);
360+
@Cached(value = "findWriteNode(resolvedSlot)") WriteNode writeNode,
361+
@Cached @Shared ImportValueNode importNode) throws UnknownIdentifierException {
362+
doWrite(receiver, cachedMember, value, writeNode, resolvedSlot, importNode);
360363
}
361364

362365
@Specialization(replaces = "doCached")
363366
@TruffleBoundary
364-
static void doGeneric(ScopeVariables receiver, String member, Object value) throws UnknownIdentifierException {
367+
static void doGeneric(ScopeVariables receiver, String member, Object value,
368+
@Cached @Shared ImportValueNode importNode) throws UnknownIdentifierException {
365369
ResolvedSlot resolvedSlot = findSlot(member, receiver);
366370
WriteNode writeNode = findWriteNode(resolvedSlot);
367-
doWrite(receiver, member, value, writeNode, resolvedSlot);
371+
doWrite(receiver, member, value, writeNode, resolvedSlot, importNode);
368372
}
369373

370-
private static void doWrite(ScopeVariables receiver, String member, Object value, WriteNode writeNode, ResolvedSlot resolvedSlot) throws UnknownIdentifierException {
374+
private static void doWrite(ScopeVariables receiver, String member, Object value, WriteNode writeNode, ResolvedSlot resolvedSlot, ImportValueNode importNode)
375+
throws UnknownIdentifierException {
371376
if (writeNode == null) {
372377
throw UnknownIdentifierException.create(member);
373378
}
374379
Frame frame = resolvedSlot.isFunctionFrame() ? receiver.functionFrame : receiver.frame;
375380
if (frame == null) {
376381
throw UnknownIdentifierException.create(member);
377382
}
378-
writeNode.executeWrite((VirtualFrame) frame, value);
383+
writeNode.executeWrite((VirtualFrame) frame, importNode.executeWithTarget(value));
379384
}
380385
}
381386

0 commit comments

Comments
 (0)