58
58
import com .oracle .graal .python .builtins .CoreFunctions ;
59
59
import com .oracle .graal .python .builtins .PythonBuiltinClassType ;
60
60
import com .oracle .graal .python .builtins .PythonBuiltins ;
61
+ import com .oracle .graal .python .builtins .modules .TruffleCextBuiltinsFactory .CheckFunctionResultNodeGen ;
61
62
import com .oracle .graal .python .builtins .modules .TruffleCextBuiltinsFactory .GetByteArrayNodeGen ;
62
63
import com .oracle .graal .python .builtins .objects .PNone ;
63
64
import com .oracle .graal .python .builtins .objects .PythonAbstractObject ;
150
151
import com .oracle .truffle .api .nodes .Node ;
151
152
import com .oracle .truffle .api .nodes .RootNode ;
152
153
import com .oracle .truffle .api .profiles .BranchProfile ;
154
+ import com .oracle .truffle .api .profiles .ConditionProfile ;
153
155
154
156
@ CoreFunctions (defineModule = "python_cext" )
155
157
public class TruffleCextBuiltins extends PythonBuiltins {
@@ -502,21 +504,76 @@ private Object getLongItem(PDict nativeMembers, String key) {
502
504
}
503
505
504
506
// roughly equivalent to _Py_CheckFunctionResult in Objects/call.c
505
- public static Object checkFunctionResult (PythonContext context , Node isNullNode , String name , Object result ) {
506
- PException currentException = context .getCurrentException ();
507
- // consume exception
508
- context .setCurrentException (null );
509
- boolean errOccurred = currentException != null ;
510
- if (PGuards .isForeignObject (result ) && ForeignAccess .sendIsNull (isNullNode , (TruffleObject ) result ) || result == PNone .NO_VALUE ) {
511
- if (!errOccurred ) {
512
- throw context .getCore ().raise (PythonErrorType .SystemError , isNullNode , "%s returned NULL without setting an error" , name );
513
- } else {
514
- throw currentException ;
507
+ @ ImportStatic (PGuards .class )
508
+ abstract static class CheckFunctionResultNode extends PBaseNode {
509
+
510
+ @ Child private Node isNullNode ;
511
+
512
+ public abstract Object execute (String name , Object result );
513
+
514
+ @ Specialization
515
+ Object doNativeWrapper (String name , PythonObjectNativeWrapper result ,
516
+ @ Cached ("create()" ) CheckFunctionResultNode recursive ) {
517
+ return recursive .execute (name , result .getDelegate ());
518
+ }
519
+
520
+ @ Specialization (guards = "!isPythonObjectNativeWrapper(result)" )
521
+ Object doPrimitiveWrapper (String name , @ SuppressWarnings ("unused" ) PythonNativeWrapper result ) {
522
+ checkFunctionResult (name , false );
523
+ return result ;
524
+ }
525
+
526
+ @ Specialization (guards = "isNoValue(result)" )
527
+ Object doNoValue (String name , @ SuppressWarnings ("unused" ) PNone result ) {
528
+ checkFunctionResult (name , true );
529
+ return PNone .NO_VALUE ;
530
+ }
531
+
532
+ @ Specialization (guards = "!isNoValue(result)" )
533
+ Object doNativeWrapper (String name , @ SuppressWarnings ("unused" ) PythonAbstractObject result ) {
534
+ checkFunctionResult (name , false );
535
+ return result ;
536
+ }
537
+
538
+ @ Specialization (guards = "isForeignObject(result)" )
539
+ Object doForeign (String name , TruffleObject result ,
540
+ @ Cached ("createBinaryProfile()" ) ConditionProfile isNullProfile ) {
541
+ checkFunctionResult (name , isNullProfile .profile (isNull (result )));
542
+ return result ;
543
+ }
544
+
545
+ private void checkFunctionResult (String name , boolean isNull ) {
546
+ PythonContext context = getContext ();
547
+ PException currentException = context .getCurrentException ();
548
+ // consume exception
549
+ context .setCurrentException (null );
550
+ boolean errOccurred = currentException != null ;
551
+ if (isNull ) {
552
+ if (!errOccurred ) {
553
+ throw context .getCore ().raise (PythonErrorType .SystemError , isNullNode , "%s returned NULL without setting an error" , name );
554
+ } else {
555
+ throw currentException ;
556
+ }
557
+ } else if (errOccurred ) {
558
+ throw context .getCore ().raise (PythonErrorType .SystemError , isNullNode , "%s returned a result with an error set" , name );
515
559
}
516
- } else if (errOccurred ) {
517
- throw context .getCore ().raise (PythonErrorType .SystemError , isNullNode , "%s returned a result with an error set" , name );
518
560
}
519
- return result ;
561
+
562
+ private boolean isNull (TruffleObject result ) {
563
+ if (isNullNode == null ) {
564
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
565
+ isNullNode = Message .IS_NULL .createNode ();
566
+ }
567
+ return ForeignAccess .sendIsNull (isNullNode , result );
568
+ }
569
+
570
+ protected static boolean isPythonObjectNativeWrapper (PythonNativeWrapper object ) {
571
+ return object instanceof PythonObjectNativeWrapper ;
572
+ }
573
+
574
+ public static CheckFunctionResultNode create () {
575
+ return CheckFunctionResultNodeGen .create ();
576
+ }
520
577
}
521
578
522
579
static class ExternalFunctionNode extends RootNode {
@@ -527,7 +584,7 @@ static class ExternalFunctionNode extends RootNode {
527
584
@ Child private Node executeNode ;
528
585
@ Child CExtNodes .AllToSulongNode toSulongNode = CExtNodes .AllToSulongNode .create ();
529
586
@ Child CExtNodes .AsPythonObjectNode asPythonObjectNode = CExtNodes .AsPythonObjectNode .create ();
530
- @ Child private Node isNullNode = Message . IS_NULL . createNode ();
587
+ @ Child private CheckFunctionResultNode checkResultNode = CheckFunctionResultNode . create ();
531
588
@ Child private PForeignToPTypeNode fromForeign = PForeignToPTypeNode .create ();
532
589
533
590
public ExternalFunctionNode (PythonLanguage lang , String name , TruffleObject cwrapper , TruffleObject callable ) {
@@ -564,7 +621,7 @@ public Object execute(VirtualFrame frame) {
564
621
// clear current exception such that native code has clean environment
565
622
getContext ().setCurrentException (null );
566
623
567
- Object result = fromNative (asPythonObjectNode .execute (checkFunctionResult ( getContext (), isNullNode , name , ForeignAccess .sendExecute (executeNode , fun , arguments ))));
624
+ Object result = fromNative (asPythonObjectNode .execute (checkResultNode . execute ( name , ForeignAccess .sendExecute (executeNode , fun , arguments ))));
568
625
569
626
// restore previous exception state
570
627
getContext ().setCurrentException (exceptionState );
0 commit comments