Skip to content

Commit c05ff4d

Browse files
committed
Introduce helper node for using PythonBufferAcquireLibrary in GenerateUncached nodes
1 parent 9a77d90 commit c05ff4d

File tree

2 files changed

+205
-5
lines changed

2 files changed

+205
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/*
2+
* Copyright (c) 2021, 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.builtins.objects.buffer;
42+
43+
import com.oracle.graal.python.PythonLanguage;
44+
import com.oracle.graal.python.nodes.IndirectCallNode;
45+
import com.oracle.graal.python.nodes.PNodeWithContext;
46+
import com.oracle.graal.python.nodes.PNodeWithIndirectCall;
47+
import com.oracle.graal.python.nodes.PNodeWithRaiseAndIndirectCall;
48+
import com.oracle.graal.python.runtime.PythonContext;
49+
import com.oracle.truffle.api.Assumption;
50+
import com.oracle.truffle.api.CompilerDirectives;
51+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
52+
import com.oracle.truffle.api.Truffle;
53+
import com.oracle.truffle.api.frame.VirtualFrame;
54+
import com.oracle.truffle.api.nodes.NodeCost;
55+
import com.oracle.truffle.api.utilities.NeverValidAssumption;
56+
57+
/**
58+
* Helper node for using {@link PythonBufferAcquireLibrary} in a node annotated with
59+
* {@link com.oracle.truffle.api.dsl.GenerateUncached}.<br/>
60+
* In order to correctly use {@link PythonBufferAcquireLibrary}, one needs to setup an indirect
61+
* call. Following methods of the library already do that but the caller needs to provide
62+
* appropriate nodes.
63+
* <ul>
64+
* <li>{@link PythonBufferAcquireLibrary#acquireReadonly(Object, VirtualFrame, PNodeWithRaiseAndIndirectCall)}</li>
65+
* <li>{@link PythonBufferAcquireLibrary#acquireReadonly(Object, VirtualFrame, PythonContext, PythonLanguage, IndirectCallNode)}
66+
* </li>
67+
* <li>{@link PythonBufferAcquireLibrary#acquireWritable(Object, VirtualFrame, PNodeWithIndirectCall)}
68+
* </li>
69+
* <li>{@link PythonBufferAcquireLibrary#acquireWritable(Object, VirtualFrame, PythonContext, PythonLanguage, IndirectCallNode)}
70+
* </li>
71+
* </ul>
72+
* However, if the caller is a node with annotation
73+
* {@link com.oracle.truffle.api.dsl.GenerateUncached}, you cannot easily use one of these methods
74+
* because the nodes you need to pass must (1) implement {@link IndirectCallNode}, and (2) be an
75+
* ancestor of the library. Since {@link IndirectCallNode} requires the usage of Java fields, you
76+
* cannot use {@link com.oracle.truffle.api.dsl.GenerateUncached}. This node solves the problem by
77+
* providing an uncached version that fulfills the required interface.
78+
*/
79+
public abstract class BufferAcquireGenerateUncachedNode extends PNodeWithContext implements IndirectCallNode {
80+
81+
public abstract boolean hasBuffer(Object receiver);
82+
83+
public abstract Object acquireReadonly(VirtualFrame frame, Object receiver);
84+
85+
public abstract Object acquireWritable(VirtualFrame frame, Object receiver);
86+
87+
public static BufferAcquireGenerateUncachedNode create(int limit) {
88+
return new IndirectCallHelperCachedNode(PythonBufferAcquireLibrary.getFactory().createDispatched(limit));
89+
}
90+
91+
public static BufferAcquireGenerateUncachedNode create(Object receiver) {
92+
return new IndirectCallHelperCachedNode(PythonBufferAcquireLibrary.getFactory().create(receiver));
93+
}
94+
95+
public static BufferAcquireGenerateUncachedNode getUncached(@SuppressWarnings("unused") int limit) {
96+
return IndirectCallHelperUncachedNode.INSTANCE;
97+
}
98+
99+
static final class IndirectCallHelperCachedNode extends BufferAcquireGenerateUncachedNode {
100+
101+
@Child private PythonBufferAcquireLibrary lib;
102+
103+
@CompilationFinal private Assumption nativeCodeDoesntNeedExceptionState;
104+
@CompilationFinal private Assumption nativeCodeDoesntNeedMyFrame;
105+
106+
IndirectCallHelperCachedNode(PythonBufferAcquireLibrary lib) {
107+
this.lib = lib;
108+
}
109+
110+
@Override
111+
public boolean hasBuffer(Object receiver) {
112+
return lib.hasBuffer(receiver);
113+
}
114+
115+
@Override
116+
public Object acquireReadonly(VirtualFrame frame, Object receiver) {
117+
return lib.acquireReadonly(receiver, frame, getContext(), getLanguage(), this);
118+
}
119+
120+
@Override
121+
public Object acquireWritable(VirtualFrame frame, Object receiver) {
122+
return lib.acquireWritable(receiver, frame, getContext(), getLanguage(), this);
123+
}
124+
125+
@Override
126+
public Assumption needNotPassFrameAssumption() {
127+
if (nativeCodeDoesntNeedMyFrame == null) {
128+
CompilerDirectives.transferToInterpreterAndInvalidate();
129+
nativeCodeDoesntNeedMyFrame = Truffle.getRuntime().createAssumption();
130+
}
131+
return nativeCodeDoesntNeedMyFrame;
132+
}
133+
134+
@Override
135+
public Assumption needNotPassExceptionAssumption() {
136+
if (nativeCodeDoesntNeedExceptionState == null) {
137+
CompilerDirectives.transferToInterpreterAndInvalidate();
138+
nativeCodeDoesntNeedExceptionState = Truffle.getRuntime().createAssumption();
139+
}
140+
return nativeCodeDoesntNeedExceptionState;
141+
}
142+
}
143+
144+
static final class IndirectCallHelperUncachedNode extends BufferAcquireGenerateUncachedNode {
145+
private static final IndirectCallHelperUncachedNode INSTANCE = new IndirectCallHelperUncachedNode();
146+
147+
@Override
148+
public boolean hasBuffer(Object receiver) {
149+
return PythonBufferAcquireLibrary.getUncached().hasBuffer(receiver);
150+
}
151+
152+
@Override
153+
public Object acquireReadonly(VirtualFrame frame, Object receiver) {
154+
return PythonBufferAcquireLibrary.getUncached().acquireReadonly(receiver);
155+
}
156+
157+
@Override
158+
public Object acquireWritable(VirtualFrame frame, Object receiver) {
159+
return PythonBufferAcquireLibrary.getUncached().acquireWritable(receiver);
160+
}
161+
162+
@Override
163+
public Assumption needNotPassFrameAssumption() {
164+
return NeverValidAssumption.INSTANCE;
165+
}
166+
167+
@Override
168+
public Assumption needNotPassExceptionAssumption() {
169+
return NeverValidAssumption.INSTANCE;
170+
}
171+
172+
@Override
173+
public boolean calleeNeedsCallerFrame() {
174+
return true;
175+
}
176+
177+
@Override
178+
public boolean calleeNeedsExceptionState() {
179+
return true;
180+
}
181+
182+
@Override
183+
public void setCalleeNeedsCallerFrame() {
184+
}
185+
186+
@Override
187+
public void setCalleeNeedsExceptionState() {
188+
}
189+
190+
@Override
191+
public boolean isAdoptable() {
192+
return false;
193+
}
194+
195+
@Override
196+
public NodeCost getCost() {
197+
return NodeCost.MEGAMORPHIC;
198+
}
199+
}
200+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyFloatFromString.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@
4343
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
4444
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError;
4545

46+
import com.oracle.graal.python.builtins.objects.buffer.BufferAcquireGenerateUncachedNode;
4647
import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary;
47-
import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAcquireLibrary;
4848
import com.oracle.graal.python.builtins.objects.floats.FloatUtils;
4949
import com.oracle.graal.python.nodes.ErrorMessages;
50-
import com.oracle.graal.python.nodes.PNodeWithIndirectCall;
50+
import com.oracle.graal.python.nodes.PNodeWithContext;
5151
import com.oracle.graal.python.nodes.PRaiseNode;
5252
import com.oracle.graal.python.nodes.util.CannotCastException;
5353
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
@@ -66,7 +66,7 @@
6666
* {@code double}). Raises {@code ValueError} when the conversion fails.
6767
*/
6868
@GenerateUncached
69-
public abstract class PyFloatFromString extends PNodeWithIndirectCall {
69+
public abstract class PyFloatFromString extends PNodeWithContext {
7070
public abstract double execute(Frame frame, Object obj);
7171

7272
public abstract double execute(Frame frame, String obj);
@@ -80,7 +80,7 @@ static double doString(VirtualFrame frame, String object,
8080

8181
@Specialization
8282
double doGeneric(VirtualFrame frame, Object object,
83-
@CachedLibrary(limit = "3") PythonBufferAcquireLibrary bufferAcquireLib,
83+
@Cached(parameters = "3") BufferAcquireGenerateUncachedNode acquireNode,
8484
@CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib,
8585
@Cached CastToJavaStringNode cast,
8686
@Shared("repr") @Cached PyObjectReprAsJavaStringNode reprNode,
@@ -91,7 +91,7 @@ static double doString(VirtualFrame frame, String object,
9191
} catch (CannotCastException e) {
9292
Object buffer = null;
9393
try {
94-
buffer = bufferAcquireLib.acquireReadonly(object, frame, this);
94+
buffer = acquireNode.acquireReadonly(frame, object);
9595
} catch (PException e1) {
9696
// fallthrough
9797
}

0 commit comments

Comments
 (0)