Skip to content

Commit 5ab6412

Browse files
committed
Fix unwrapping PCode root node when creating PCode from code units for synthetic root node that embedders and instruments see
1 parent 1eafc08 commit 5ab6412

3 files changed

Lines changed: 144 additions & 1 deletion

File tree

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* Copyright (c) 2026, 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.graal.python.test.runtime;
42+
43+
import static org.junit.Assert.assertEquals;
44+
45+
import java.io.IOException;
46+
import java.util.function.Function;
47+
48+
import org.graalvm.polyglot.Context;
49+
import org.graalvm.polyglot.Engine;
50+
import org.graalvm.polyglot.Instrument;
51+
import org.junit.Test;
52+
53+
import com.oracle.truffle.api.ContextLocal;
54+
import com.oracle.truffle.api.TruffleContext;
55+
import com.oracle.truffle.api.instrumentation.ContextsListener;
56+
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
57+
import com.oracle.truffle.api.nodes.LanguageInfo;
58+
59+
public class ParseWithArgumentsInstrumentTests {
60+
private static final String TEST_INSTRUMENT_ID = "parse-with-arguments-instrument-tests";
61+
62+
@SuppressWarnings("unchecked")
63+
@Test
64+
public void instrumentParseWithArgumentsDuringLanguageContextInitializationExecutes() {
65+
try (Engine engine = Engine.create()) {
66+
Instrument instrument = engine.getInstruments().get(TEST_INSTRUMENT_ID);
67+
Function<org.graalvm.polyglot.Source, Void> registrar = instrument.lookup(Function.class);
68+
registrar.apply(org.graalvm.polyglot.Source.create("python", "x + 1"));
69+
try (Context context = Context.newBuilder("python").engine(engine).allowExperimentalOptions(true).allowAllAccess(true).build()) {
70+
assertEquals(42, context.eval("python", "42").asInt());
71+
}
72+
}
73+
}
74+
75+
@TruffleInstrument.Registration(id = TEST_INSTRUMENT_ID, services = Function.class)
76+
public static final class ParseWithArgumentsInitializationInstrument extends TruffleInstrument {
77+
private final ContextLocal<boolean[]> parsed = locals.createContextLocal((ctx) -> new boolean[1]);
78+
79+
@Override
80+
protected void onCreate(Env env) {
81+
Function<org.graalvm.polyglot.Source, Void> registerSource = (polyglotSource) -> {
82+
com.oracle.truffle.api.source.Source source = com.oracle.truffle.api.source.Source.newBuilder(
83+
polyglotSource.getLanguage(), polyglotSource.getCharacters(), polyglotSource.getName()).build();
84+
env.getInstrumenter().attachContextsListener(new ContextsListener() {
85+
@Override
86+
public void onContextCreated(TruffleContext context) {
87+
}
88+
89+
@Override
90+
public void onLanguageContextCreate(TruffleContext context, LanguageInfo language) {
91+
}
92+
93+
@Override
94+
public void onLanguageContextCreated(TruffleContext context, LanguageInfo language) {
95+
}
96+
97+
@Override
98+
public void onLanguageContextInitialize(TruffleContext context, LanguageInfo language) {
99+
}
100+
101+
@Override
102+
public void onLanguageContextInitialized(TruffleContext context, LanguageInfo language) {
103+
if (!"python".equals(language.getId())) {
104+
return;
105+
}
106+
boolean[] seen = parsed.get(context);
107+
if (seen[0]) {
108+
return;
109+
}
110+
seen[0] = true;
111+
try {
112+
env.parse(source, "x").call(41);
113+
} catch (IOException e) {
114+
throw new AssertionError(e);
115+
}
116+
}
117+
118+
@Override
119+
public void onLanguageContextFinalized(TruffleContext context, LanguageInfo language) {
120+
}
121+
122+
@Override
123+
public void onLanguageContextDisposed(TruffleContext context, LanguageInfo language) {
124+
}
125+
126+
@Override
127+
public void onContextClosed(TruffleContext context) {
128+
}
129+
}, true);
130+
return null;
131+
};
132+
env.registerService(registerSource);
133+
}
134+
}
135+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,13 @@ public String getName() {
741741
}
742742
}
743743

744+
public static RootNode unwrapRootNode(RootNode rootNode) {
745+
if (rootNode instanceof RootNodeWithArguments rootNodeWithArguments) {
746+
return rootNodeWithArguments.innerRootNode;
747+
}
748+
return rootNode;
749+
}
750+
744751
@Override
745752
public ExecutableNode parse(InlineParsingRequest request) {
746753
PythonContext context = PythonContext.get(null);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/PCode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ private static TruffleString[] extractNames(RootNode node) {
310310
}
311311

312312
private static RootNode rootNodeForExtraction(RootNode rootNode) {
313+
rootNode = PythonLanguage.unwrapRootNode(rootNode);
313314
if (PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER) {
314315
return PGenerator.unwrapContinuationRoot(rootNode);
315316
} else {
@@ -502,7 +503,7 @@ public PCode getOrCreateChildCode(int index, BytecodeDSLCodeUnit codeUnit) {
502503

503504
@TruffleBoundary
504505
private PCode createCode(BytecodeDSLCodeUnit codeUnit) {
505-
PBytecodeDSLRootNode outerRootNode = (PBytecodeDSLRootNode) getRootNode();
506+
PBytecodeDSLRootNode outerRootNode = (PBytecodeDSLRootNode) getRootNodeForExtraction();
506507
PythonLanguage language = outerRootNode.getLanguage();
507508
RootCallTarget callTarget = language.createCachedCallTarget(l -> codeUnit.createRootNode(PythonContext.get(null), outerRootNode.getSource()), codeUnit);
508509
PBytecodeDSLRootNode rootNode = (PBytecodeDSLRootNode) callTarget.getRootNode();

0 commit comments

Comments
 (0)