Skip to content

Commit b892547

Browse files
committed
[GR-21867] A simpler way to check foreign objects
PullRequest: graalpython/954
2 parents d2e1114 + da66d77 commit b892547

20 files changed

+154
-83
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JavaModuleBuiltins.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5151
import com.oracle.graal.python.builtins.PythonBuiltins;
5252
import com.oracle.graal.python.builtins.objects.PNone;
53+
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
5354
import com.oracle.graal.python.builtins.objects.str.PString;
5455
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
5556
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
@@ -64,7 +65,6 @@
6465
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
6566
import com.oracle.truffle.api.dsl.NodeFactory;
6667
import com.oracle.truffle.api.dsl.Specialization;
67-
import com.oracle.truffle.api.interop.InteropLibrary;
6868
import com.oracle.truffle.api.interop.TruffleObject;
6969
import com.oracle.truffle.api.library.CachedLibrary;
7070

@@ -175,10 +175,10 @@ boolean check(Object object) {
175175
@Builtin(name = "instanceof", minNumOfPositionalArgs = 2)
176176
@GenerateNodeFactory
177177
abstract static class InstanceOfNode extends PythonBinaryBuiltinNode {
178-
@Specialization(guards = {"!isForeignObject(object, iLibObject)", "isForeignObject(klass, iLibKlass)"}, limit = "3")
178+
@Specialization(guards = {"!iLibObject.isForeignObject(object)", "iLibKlass.isForeignObject(klass)"}, limit = "3")
179179
boolean check(Object object, TruffleObject klass,
180-
@SuppressWarnings("unused") @CachedLibrary("object") InteropLibrary iLibObject,
181-
@SuppressWarnings("unused") @CachedLibrary("klass") InteropLibrary iLibKlass) {
180+
@SuppressWarnings("unused") @CachedLibrary("object") PythonObjectLibrary iLibObject,
181+
@SuppressWarnings("unused") @CachedLibrary("klass") PythonObjectLibrary iLibKlass) {
182182
Env env = getContext().getEnv();
183183
try {
184184
Object hostKlass = env.asHostObject(klass);
@@ -191,10 +191,10 @@ boolean check(Object object, TruffleObject klass,
191191
return false;
192192
}
193193

194-
@Specialization(guards = {"isForeignObject(object, iLibObject)", "isForeignObject(klass, iLibKlass)"}, limit = "3")
194+
@Specialization(guards = {"iLibObject.isForeignObject(object)", "iLibKlass.isForeignObject(klass)"}, limit = "3")
195195
boolean checkForeign(Object object, TruffleObject klass,
196-
@SuppressWarnings("unused") @CachedLibrary("object") InteropLibrary iLibObject,
197-
@SuppressWarnings("unused") @CachedLibrary("klass") InteropLibrary iLibKlass) {
196+
@SuppressWarnings("unused") @CachedLibrary("object") PythonObjectLibrary iLibObject,
197+
@SuppressWarnings("unused") @CachedLibrary("klass") PythonObjectLibrary iLibKlass) {
198198
Env env = getContext().getEnv();
199199
try {
200200
Object hostObject = env.asHostObject(object);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,13 +547,13 @@ public abstract static class StatNode extends PythonBinaryBuiltinNode {
547547

548548
protected abstract Object executeWith(VirtualFrame frame, Object path, Object followSymlinks);
549549

550-
@Specialization(limit = "1")
550+
@Specialization(limit = "2")
551551
Object doStatPath(VirtualFrame frame, Object path, boolean followSymlinks,
552552
@CachedLibrary("path") PythonObjectLibrary lib) {
553553
return stat(frame, lib.asPath(path), followSymlinks);
554554
}
555555

556-
@Specialization(guards = "isNoValue(followSymlinks)", limit = "1")
556+
@Specialization(guards = "isNoValue(followSymlinks)", limit = "2")
557557
Object doStatDefault(VirtualFrame frame, Object path, @SuppressWarnings("unused") PNone followSymlinks,
558558
@CachedLibrary("path") PythonObjectLibrary lib) {
559559
return stat(frame, lib.asPath(path), true);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/CExtNodes.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -463,15 +463,15 @@ static Object runAbstractObject(@SuppressWarnings("unused") CExtContext cextCont
463463
return PythonObjectNativeWrapper.wrap(object, noWrapperProfile);
464464
}
465465

466-
@Specialization(guards = {"isForeignObject(object, lib)", "!isNativeWrapper(object)", "!isNativeNull(object)"}, limit = "3")
466+
@Specialization(guards = {"lib.isForeignObject(object)", "!isNativeWrapper(object)", "!isNativeNull(object)"}, limit = "3")
467467
static Object doForeignObject(@SuppressWarnings("unused") CExtContext cextContext, TruffleObject object,
468-
@SuppressWarnings("unused") @CachedLibrary("object") InteropLibrary lib) {
468+
@SuppressWarnings("unused") @CachedLibrary("object") PythonObjectLibrary lib) {
469469
return TruffleObjectNativeWrapper.wrap(object);
470470
}
471471

472472
@Specialization(guards = "isFallback(object, lib)", limit = "1")
473473
static Object run(@SuppressWarnings("unused") CExtContext cextContext, Object object,
474-
@SuppressWarnings("unused") @CachedLibrary("object") InteropLibrary lib) {
474+
@SuppressWarnings("unused") @CachedLibrary("object") PythonObjectLibrary lib) {
475475
assert object != null : "Java 'null' cannot be a Sulong value";
476476
assert CApiGuards.isNativeWrapper(object) : "unknown object cannot be a Sulong value";
477477
return object;
@@ -481,10 +481,10 @@ protected static PythonClassNativeWrapper wrapNativeClass(PythonManagedClass obj
481481
return PythonClassNativeWrapper.wrap(object, GetNameNode.doSlowPath(object));
482482
}
483483

484-
static boolean isFallback(Object object, InteropLibrary lib) {
484+
static boolean isFallback(Object object, PythonObjectLibrary lib) {
485485
return !(object instanceof String || object instanceof Boolean || object instanceof Integer || object instanceof Long || object instanceof Double ||
486486
object instanceof PythonNativeNull || object instanceof PythonAbstractObject) &&
487-
!(PGuards.isForeignObject(object, lib) && !CApiGuards.isNativeWrapper(object));
487+
!(lib.isForeignObject(object) && !CApiGuards.isNativeWrapper(object));
488488
}
489489

490490
protected static boolean isNaN(double d) {
@@ -701,24 +701,24 @@ static Object runAbstractObject(@SuppressWarnings("unused") CExtContext cextCont
701701
return PythonObjectNativeWrapper.wrapNewRef(object, noWrapperProfile);
702702
}
703703

704-
@Specialization(guards = {"isForeignObject(object, lib)", "!isNativeWrapper(object)", "!isNativeNull(object)"}, limit = "3")
704+
@Specialization(guards = {"lib.isForeignObject(object)", "!isNativeWrapper(object)", "!isNativeNull(object)"}, limit = "3")
705705
static Object doForeignObject(CExtContext cextContext, TruffleObject object,
706-
@SuppressWarnings("unused") @CachedLibrary("object") InteropLibrary lib) {
706+
@CachedLibrary("object") PythonObjectLibrary lib) {
707707
// this will always be a new wrapper; it's implicitly always a new reference in any case
708708
return ToSulongNode.doForeignObject(cextContext, object, lib);
709709
}
710710

711711
@Specialization(guards = "isFallback(object, lib)", limit = "1")
712712
static Object run(CExtContext cextContext, Object object,
713-
@CachedLibrary("object") InteropLibrary lib) {
713+
@CachedLibrary("object") PythonObjectLibrary lib) {
714714
return ToSulongNode.run(cextContext, object, lib);
715715
}
716716

717717
protected static PythonClassNativeWrapper wrapNativeClass(PythonManagedClass object) {
718718
return PythonClassNativeWrapper.wrap(object, GetNameNode.doSlowPath(object));
719719
}
720720

721-
static boolean isFallback(Object object, InteropLibrary lib) {
721+
static boolean isFallback(Object object, PythonObjectLibrary lib) {
722722
return ToSulongNode.isFallback(object, lib);
723723
}
724724

@@ -860,24 +860,24 @@ static Object runAbstractObject(@SuppressWarnings("unused") CExtContext cextCont
860860
return PythonObjectNativeWrapper.wrapNewRef(object, noWrapperProfile);
861861
}
862862

863-
@Specialization(guards = {"isForeignObject(object, lib)", "!isNativeWrapper(object)", "!isNativeNull(object)"}, limit = "3")
863+
@Specialization(guards = {"lib.isForeignObject(object)", "!isNativeWrapper(object)", "!isNativeNull(object)"}, limit = "3")
864864
static Object doForeignObject(CExtContext cextContext, TruffleObject object,
865-
@SuppressWarnings("unused") @CachedLibrary("object") InteropLibrary lib) {
865+
@CachedLibrary("object") PythonObjectLibrary lib) {
866866
// this will always be a new wrapper; it's implicitly always a new reference in any case
867867
return ToSulongNode.doForeignObject(cextContext, object, lib);
868868
}
869869

870870
@Specialization(guards = "isFallback(object, lib)", limit = "1")
871871
static Object run(CExtContext cextContext, Object object,
872-
@CachedLibrary("object") InteropLibrary lib) {
872+
@CachedLibrary("object") PythonObjectLibrary lib) {
873873
return ToSulongNode.run(cextContext, object, lib);
874874
}
875875

876876
protected static PythonClassNativeWrapper wrapNativeClass(PythonManagedClass object) {
877877
return PythonClassNativeWrapper.wrap(object, GetNameNode.doSlowPath(object));
878878
}
879879

880-
static boolean isFallback(Object object, InteropLibrary lib) {
880+
static boolean isFallback(Object object, PythonObjectLibrary lib) {
881881
return ToSulongNode.isFallback(object, lib);
882882
}
883883

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -549,9 +549,10 @@ abstract static class NewNode extends PythonBuiltinNode {
549549
* A foreign function call specializes on the length of the passed arguments. Any
550550
* optimization based on the callee has to happen on the other side.a
551551
*/
552-
@Specialization(guards = {"isForeignObject(callee, lib)", "!isNoValue(callee)", "keywords.length == 0"})
552+
@Specialization(guards = {"plib.isForeignObject(callee)", "!isNoValue(callee)", "keywords.length == 0"}, limit = "3")
553553
protected Object doInteropCall(Object callee, Object[] arguments, @SuppressWarnings("unused") PKeyword[] keywords,
554-
@CachedLibrary(limit = "3") InteropLibrary lib,
554+
@SuppressWarnings("unused") @CachedLibrary("callee") PythonObjectLibrary plib,
555+
@CachedLibrary("callee") InteropLibrary lib,
555556
@Cached("create()") PTypeToForeignNode toForeignNode,
556557
@Cached("create()") PForeignToPTypeNode toPTypeNode) {
557558
try {
@@ -586,8 +587,9 @@ public final Object executeWithArgs(VirtualFrame frame, Object callee, Object[]
586587
* A foreign function call specializes on the length of the passed arguments. Any
587588
* optimization based on the callee has to happen on the other side.
588589
*/
589-
@Specialization(guards = {"isForeignObject(callee, lib)", "!isNoValue(callee)", "keywords.length == 0"}, limit = "4")
590+
@Specialization(guards = {"plib.isForeignObject(callee)", "!isNoValue(callee)", "keywords.length == 0"}, limit = "4")
590591
protected Object doInteropCall(VirtualFrame frame, Object callee, Object[] arguments, @SuppressWarnings("unused") PKeyword[] keywords,
592+
@SuppressWarnings("unused") @CachedLibrary("callee") PythonObjectLibrary plib,
591593
@CachedLibrary("callee") InteropLibrary lib,
592594
@CachedContext(PythonLanguage.class) PythonContext context,
593595
@Cached PTypeToForeignNode toForeignNode,

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/DefaultPythonObjectExports.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.object;
4242

43+
import com.oracle.graal.python.PythonLanguage;
4344
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4445
import com.oracle.graal.python.builtins.objects.function.PArguments.ThreadState;
4546
import com.oracle.graal.python.builtins.objects.type.LazyPythonClass;
@@ -214,4 +215,17 @@ static int equalsInternal(Object receiver, Object other, ThreadState threadState
214215
static boolean equalsWithState(Object receiver, Object other, PythonObjectLibrary oLib, ThreadState state) {
215216
return receiver == other || oLib.equalsInternal(receiver, other, state) == 1;
216217
}
218+
219+
@ExportMessage
220+
@SuppressWarnings("static-method")
221+
static boolean isForeignObject(Object receiver,
222+
@CachedLibrary("receiver") InteropLibrary lib) {
223+
try {
224+
return !lib.hasLanguage(receiver) || lib.getLanguage(receiver) != PythonLanguage.class;
225+
} catch (UnsupportedMessageException e) {
226+
// cannot happen due to check
227+
CompilerDirectives.transferToInterpreterAndInvalidate();
228+
throw new IllegalStateException(e);
229+
}
230+
}
217231
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/PythonObjectLibrary.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,34 @@ public byte[] getBufferBytes(Object receiver) throws UnsupportedMessageException
658658
throw UnsupportedMessageException.create();
659659
}
660660

661+
/**
662+
* Checks whether the receiver is a Foreign Object.
663+
*
664+
* @see DefaultPythonObjectExports#isForeignObject(Object,
665+
* com.oracle.truffle.api.interop.InteropLibrary) {@code DefaultPythonObjectExports}
666+
* implements the logic of how an unknown object is being checked.
667+
*
668+
* @param receiver
669+
* @return True if the receiver is a Foreign Object
670+
*/
671+
672+
public boolean isForeignObject(Object receiver) {
673+
return false;
674+
}
675+
676+
/**
677+
* When a {@code receiver} is a wrapped primitive object that utilizes a #ReflectionLibrary, the
678+
* value will appear here as primitive contrary to the value in the call cite which should
679+
* represent the {@code receiverOrigin}
680+
*
681+
* @param receiver the receiver Object
682+
* @param receiverOrigin also the receiver Object
683+
* @return True if there has been a reflection
684+
*/
685+
public boolean isRefelectedObject(Object receiver, Object receiverOrigin) {
686+
return receiver != receiverOrigin;
687+
}
688+
661689
public static boolean checkIsIterable(PythonObjectLibrary library, ContextReference<PythonContext> contextRef, VirtualFrame frame, Object object, IndirectCallNode callNode) {
662690
PythonContext context = contextRef.get();
663691
Object state = IndirectCallContext.enter(frame, context, callNode);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/LazyString.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ private static boolean assertChecked(CharSequence left, CharSequence right, int
8383
/**
8484
* Variant of {@link #createChecked} that tries to concatenate a very short string to an already
8585
* short root leaf up-front, e.g. when appending single characters.
86-
*
86+
*
8787
* @param minLazyStringLength
8888
*/
8989
@TruffleBoundary
@@ -138,7 +138,7 @@ public boolean isMaterialized() {
138138

139139
@Override
140140
@TruffleBoundary
141-
public String materialize() {
141+
public final String materialize() {
142142
char[] dst = new char[len];
143143
LazyString.flatten(this, 0, len, dst, 0);
144144
String flattened = new String(dst);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/NativeCharSequence.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public boolean isMaterialized() {
7676
}
7777

7878
@Override
79-
public String materialize() {
79+
public final String materialize() {
8080
if (!isMaterialized()) {
8181
materialized = (String) PCallCapiFunction.getUncached().call(NativeCAPISymbols.FUN_PY_TRUFFLE_CSTR_TO_STRING, ptr);
8282
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/PString.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@ public String getValue() {
7171
}
7272

7373
public static String getValue(CharSequence charSequence) {
74-
if (charSequence instanceof PCharSequence) {
75-
PCharSequence s = (PCharSequence) charSequence;
74+
if (charSequence instanceof LazyString) {
75+
LazyString s = (LazyString) charSequence;
76+
return s.materialize();
77+
} else if (charSequence instanceof NativeCharSequence) {
78+
NativeCharSequence s = (NativeCharSequence) charSequence;
7679
return s.materialize();
7780
} else {
7881
return (String) charSequence;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/LazyPythonClass.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -40,6 +40,7 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.type;
4242

43+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4344
import com.oracle.truffle.api.interop.TruffleObject;
4445

4546
public interface LazyPythonClass extends TruffleObject {
@@ -49,4 +50,17 @@ public interface LazyPythonClass extends TruffleObject {
4950
* is available.
5051
*/
5152
String getName();
53+
54+
static boolean isInstance(Object object) {
55+
return object instanceof PythonBuiltinClassType || PythonAbstractClass.isInstance(object);
56+
}
57+
58+
static LazyPythonClass cast(Object object) {
59+
if (object instanceof PythonBuiltinClassType) {
60+
return (PythonBuiltinClassType) object;
61+
} else {
62+
return PythonAbstractClass.cast(object);
63+
}
64+
}
65+
5266
}

0 commit comments

Comments
 (0)