Skip to content

Commit 66df721

Browse files
committed
[GR-12062] Convert results of foreign attribute READs and foreign INVOKEs
PullRequest: graalpython/228
2 parents 538d50f + 2d9d374 commit 66df721

File tree

4 files changed

+126
-23
lines changed

4 files changed

+126
-23
lines changed

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/interop/JavaInteropTest.java

Lines changed: 109 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,17 @@
6666
import com.oracle.truffle.api.nodes.Node;
6767

6868
public class JavaInteropTest extends PythonTests {
69-
private ByteArrayOutputStream os;
69+
private ByteArrayOutputStream out;
7070
private Context context;
7171
private ByteArrayOutputStream err;
7272

7373
@Before
7474
public void setUpTest() {
75-
os = new ByteArrayOutputStream();
75+
out = new ByteArrayOutputStream();
7676
err = new ByteArrayOutputStream();
7777
Builder builder = Context.newBuilder();
7878
builder.allowAllAccess(true);
79-
builder.out(os);
79+
builder.out(out);
8080
builder.err(err);
8181
context = builder.build();
8282
}
@@ -128,7 +128,7 @@ public void testPassingFloats() throws Exception {
128128
context.eval(script);
129129
Value main = context.getPolyglotBindings().getMember("foo");
130130
main.execute((float) 1.0, (float) 2.0);
131-
assertEquals("2.0\n", os.toString("UTF-8"));
131+
assertEquals("2.0\n", out.toString("UTF-8"));
132132
}
133133

134134
@Test
@@ -141,7 +141,7 @@ public void testAsFunction() throws Exception {
141141
context.eval(script);
142142
Value main = context.getPolyglotBindings().getMember("foo");
143143
main.execute();
144-
assertEquals("Called\n", os.toString("UTF-8"));
144+
assertEquals("Called\n", out.toString("UTF-8"));
145145
}
146146

147147
@Test
@@ -154,7 +154,7 @@ public void testAsFunctionVarArgs() throws Exception {
154154
context.eval(script);
155155
Value main = context.getPolyglotBindings().getMember("foo");
156156
main.execute("Hello", "World");
157-
assertEquals("Hello World\n", os.toString("UTF-8"));
157+
assertEquals("Hello World\n", out.toString("UTF-8"));
158158
}
159159

160160
@Test
@@ -165,7 +165,7 @@ public void mainFunctionsAreImplicitlyImporteable() throws Exception {
165165
context.eval(script);
166166
Value main = context.getBindings("python").getMember("foo");
167167
main.execute("Hello", "World");
168-
assertEquals("Hello World\n", os.toString("UTF-8"));
168+
assertEquals("Hello World\n", out.toString("UTF-8"));
169169
}
170170

171171
@Test
@@ -175,7 +175,7 @@ public void builtinFunctionsAreImporteable() throws Exception {
175175
context.eval(script);
176176
Value main = context.getBindings("python").getMember("__builtins__").getMember("print");
177177
main.execute("Hello", "World");
178-
assertEquals("Hello World\n", os.toString("UTF-8"));
178+
assertEquals("Hello World\n", out.toString("UTF-8"));
179179
}
180180

181181
@Test
@@ -186,15 +186,15 @@ public void testMultipleInvocationsAreInSameScope() throws Exception {
186186
Source script = Source.create("python", source);
187187
Value foo = context.eval(script);
188188
foo.execute("Hello", "World");
189-
assertEquals("Hello World\n", os.toString("UTF-8"));
189+
assertEquals("Hello World\n", out.toString("UTF-8"));
190190

191191
source = "def bar(a, b):\n" +
192192
" foo(a, b)\n" +
193193
"bar";
194194
script = Source.create("python", source);
195195
Value bar = context.eval(script);
196196
bar.execute("Hello", "World");
197-
assertEquals("Hello World\nHello World\n", os.toString("UTF-8"));
197+
assertEquals("Hello World\nHello World\n", out.toString("UTF-8"));
198198

199199
source = "invalid syntax";
200200
script = Source.create("python", source);
@@ -203,9 +203,9 @@ public void testMultipleInvocationsAreInSameScope() throws Exception {
203203
} catch (Throwable t) {
204204
}
205205
bar.execute("Hello", "World");
206-
assertEquals("Hello World\nHello World\nHello World\n", os.toString("UTF-8"));
206+
assertEquals("Hello World\nHello World\nHello World\n", out.toString("UTF-8"));
207207
foo.execute("Hello", "World");
208-
assertEquals("Hello World\nHello World\nHello World\nHello World\n", os.toString("UTF-8"));
208+
assertEquals("Hello World\nHello World\nHello World\nHello World\n", out.toString("UTF-8"));
209209
}
210210

211211
@Test
@@ -335,4 +335,101 @@ public void tryInvokeThenReadExecute() {
335335
assert result[0].equals(ForeignObjectWithOOInvoke.class.getName());
336336
assert result[1].equals(ForeignObjectWithoutOOInvoke.class.getName());
337337
}
338+
339+
public class JavaObject {
340+
public byte byteValue = 1;
341+
public short shortValue = 2;
342+
public int intValue = 3;
343+
public long longValue = 4;
344+
public float floatValue = 5;
345+
public double doubleValue = 6;
346+
public boolean booleanValue = true;
347+
public char charValue = 'c';
348+
349+
public byte getByteValue() {
350+
return byteValue;
351+
}
352+
353+
public short getShortValue() {
354+
return shortValue;
355+
}
356+
357+
public int getIntValue() {
358+
return intValue;
359+
}
360+
361+
public long getLongValue() {
362+
return longValue;
363+
}
364+
365+
public float getFloatValue() {
366+
return floatValue;
367+
}
368+
369+
public double getDoubleValue() {
370+
return doubleValue;
371+
}
372+
373+
public boolean getBooleanValue() {
374+
return booleanValue;
375+
}
376+
377+
public char getCharValue() {
378+
return charValue;
379+
}
380+
}
381+
382+
@Test
383+
public void accessJavaObjectFields() throws IOException {
384+
Source suitePy = Source.newBuilder("python", "" +
385+
"def foo(obj):\n" +
386+
" print(obj.byteValue, type(obj.byteValue))\n" +
387+
" print(obj.shortValue, type(obj.shortValue))\n" +
388+
" print(obj.intValue, type(obj.intValue))\n" +
389+
" print(obj.longValue, type(obj.longValue))\n" +
390+
" print(obj.floatValue, type(obj.floatValue))\n" +
391+
" print(obj.doubleValue, type(obj.doubleValue))\n" +
392+
" print(obj.booleanValue, type(obj.booleanValue))\n" +
393+
" print(obj.charValue, type(obj.charValue))\n" +
394+
"foo",
395+
"suite.py").build();
396+
Value foo = context.eval(suitePy);
397+
foo.execute(new JavaObject());
398+
assertEquals("" +
399+
"1 <class 'int'>\n" +
400+
"2 <class 'int'>\n" +
401+
"3 <class 'int'>\n" +
402+
"4 <class 'int'>\n" +
403+
"5.0 <class 'float'>\n" +
404+
"6.0 <class 'float'>\n" +
405+
"True <class 'bool'>\n" +
406+
"c <class 'str'>\n", out.toString("UTF-8"));
407+
}
408+
409+
@Test
410+
public void accessJavaObjectGetters() throws IOException {
411+
Source suitePy = Source.newBuilder("python", "" +
412+
"def foo(obj):\n" +
413+
" print(obj.getByteValue(), type(obj.getByteValue()))\n" +
414+
" print(obj.getShortValue(), type(obj.getShortValue()))\n" +
415+
" print(obj.getIntValue(), type(obj.getIntValue()))\n" +
416+
" print(obj.getLongValue(), type(obj.getLongValue()))\n" +
417+
" print(obj.getFloatValue(), type(obj.getFloatValue()))\n" +
418+
" print(obj.getDoubleValue(), type(obj.getDoubleValue()))\n" +
419+
" print(obj.getBooleanValue(), type(obj.getBooleanValue()))\n" +
420+
" print(obj.getCharValue(), type(obj.getCharValue()))\n" +
421+
"foo",
422+
"suite.py").build();
423+
Value foo = context.eval(suitePy);
424+
foo.execute(new JavaObject());
425+
assertEquals("" +
426+
"1 <class 'int'>\n" +
427+
"2 <class 'int'>\n" +
428+
"3 <class 'int'>\n" +
429+
"4 <class 'int'>\n" +
430+
"5.0 <class 'float'>\n" +
431+
"6.0 <class 'float'>\n" +
432+
"True <class 'bool'>\n" +
433+
"c <class 'str'>\n", out.toString("UTF-8"));
434+
}
338435
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/TruffleObjectBuiltins.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ protected CastToBooleanNode getCastToBooleanNode() {
136136
}
137137

138138
@Specialization(guards = {"!isNull(self)", "isBoxed(self)"})
139-
Object doForeignBoxed(TruffleObject self) {
139+
boolean doForeignBoxed(TruffleObject self) {
140140
try {
141141
return getCastToBooleanNode().executeWith(unboxLeft(self));
142142
} catch (UnsupportedMessageException e) {
@@ -145,7 +145,7 @@ Object doForeignBoxed(TruffleObject self) {
145145
}
146146

147147
@Specialization(guards = "isForeignArray(self)")
148-
Object doForeignArray(TruffleObject self,
148+
boolean doForeignArray(TruffleObject self,
149149
@Cached("GET_SIZE.createNode()") Node sizeNode) {
150150
try {
151151
return getCastToBooleanNode().executeWith(ForeignAccess.sendGetSize(sizeNode, self));
@@ -155,7 +155,7 @@ Object doForeignArray(TruffleObject self,
155155
}
156156

157157
@Specialization(guards = {"isForeignObject(self)", "!isBoxed(self)", "!isForeignArray(self)"})
158-
Object doForeignObject(TruffleObject self) {
158+
boolean doForeignObject(TruffleObject self) {
159159
return !isNull(self);
160160
}
161161

@@ -778,7 +778,7 @@ Object doForeignMapping(TruffleObject mapping,
778778
}
779779

780780
@Fallback
781-
Object doGeneric(@SuppressWarnings("unused") Object o) {
781+
PNone doGeneric(@SuppressWarnings("unused") Object o) {
782782
return PNone.NONE;
783783
}
784784

@@ -867,13 +867,14 @@ Object doit(TruffleObject object, Object key) {
867867
@GenerateNodeFactory
868868
abstract static class SetattrNode extends UnboxNode {
869869
@Specialization(guards = "isForeignObject(object)")
870-
protected Object doIt(TruffleObject object, Object key, Object value,
870+
protected PNone doIt(TruffleObject object, Object key, Object value,
871871
@Cached("WRITE.createNode()") Node writeNode) {
872872
try {
873-
return ForeignAccess.sendWrite(writeNode, object, key, value);
873+
ForeignAccess.sendWrite(writeNode, object, key, value);
874874
} catch (UnknownIdentifierException | UnsupportedMessageException | UnsupportedTypeException e) {
875875
throw raise(PythonErrorType.AttributeError, "foreign object %s has no attribute %s", object, key);
876876
}
877+
return PNone.NONE;
877878
}
878879
}
879880

@@ -893,13 +894,14 @@ Object doit(TruffleObject object, Object key, Object value) {
893894
@GenerateNodeFactory
894895
abstract static class DelattrNode extends UnboxNode {
895896
@Specialization(guards = "isForeignObject(object)")
896-
protected Object doIt(TruffleObject object, Object key,
897+
protected PNone doIt(TruffleObject object, Object key,
897898
@Cached("REMOVE.createNode()") Node delNode) {
898899
try {
899-
return ForeignAccess.sendRemove(delNode, object, key);
900+
ForeignAccess.sendRemove(delNode, object, key);
900901
} catch (UnknownIdentifierException | UnsupportedMessageException e) {
901902
throw raise(PythonErrorType.AttributeError, "foreign object %s has no attribute %s", object, key);
902903
}
904+
return PNone.NONE;
903905
}
904906
}
905907

@@ -909,7 +911,7 @@ abstract static class DelitemNode extends PythonBinaryBuiltinNode {
909911
AccessForeignItemNodes.RemoveForeignItemNode delForeignItemNode = AccessForeignItemNodes.RemoveForeignItemNode.create();
910912

911913
@Specialization
912-
Object doit(TruffleObject object, Object key) {
914+
PNone doit(TruffleObject object, Object key) {
913915
delForeignItemNode.execute(object, key);
914916
return PNone.NONE;
915917
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/ReadAttributeFromObjectNode.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.oracle.graal.python.builtins.objects.object.PythonObject;
4545
import com.oracle.graal.python.builtins.objects.str.PString;
4646
import com.oracle.graal.python.nodes.PNodeWithContext;
47+
import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode;
4748
import com.oracle.graal.python.nodes.PGuards;
4849
import com.oracle.graal.python.runtime.PythonOptions;
4950
import com.oracle.truffle.api.Assumption;
@@ -175,9 +176,10 @@ protected Object readIndirect(PythonObject object, Object key) {
175176

176177
@Specialization(guards = "isForeignObject(object)")
177178
protected Object readForeign(TruffleObject object, Object key,
179+
@Cached("create()") PForeignToPTypeNode fromForeign,
178180
@Cached("createReadNode()") Node readNode) {
179181
try {
180-
return ForeignAccess.sendRead(readNode, object, attrKey(key));
182+
return fromForeign.executeConvert(ForeignAccess.sendRead(readNode, object, attrKey(key)));
181183
} catch (UnknownIdentifierException | UnsupportedMessageException e) {
182184
return PNone.NO_VALUE;
183185
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/PythonCallNode.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
3939
import com.oracle.graal.python.nodes.expression.ExpressionNode;
4040
import com.oracle.graal.python.nodes.frame.ReadGlobalOrBuiltinNode;
41+
import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode;
4142
import com.oracle.graal.python.runtime.exception.PythonErrorType;
4243
import com.oracle.truffle.api.debug.DebuggerTags;
4344
import com.oracle.truffle.api.dsl.Cached;
@@ -226,6 +227,7 @@ protected static Node createInvoke() {
226227

227228
@Specialization
228229
Object call(VirtualFrame frame, ForeignInvoke callable,
230+
@Cached("create()") PForeignToPTypeNode fromForeign,
229231
@Cached("create()") BranchProfile keywordsError,
230232
@Cached("create()") BranchProfile nameError,
231233
@Cached("create()") BranchProfile typeError,
@@ -239,7 +241,7 @@ Object call(VirtualFrame frame, ForeignInvoke callable,
239241
throw raise(PythonErrorType.TypeError, "foreign invocation does not support keyword arguments");
240242
}
241243
try {
242-
return ForeignAccess.sendInvoke(invokeNode, callable.receiver, callable.identifier, arguments);
244+
return fromForeign.executeConvert(ForeignAccess.sendInvoke(invokeNode, callable.receiver, callable.identifier, arguments));
243245
} catch (UnknownIdentifierException e) {
244246
nameError.enter();
245247
throw raise(PythonErrorType.NameError, e.getMessage());

0 commit comments

Comments
 (0)