@@ -265,10 +265,6 @@ private Object fallback(Object self) throws Throwable {
265265 */
266266 static class BinaryOpCallSite extends MutableCallSite {
267267
268- /** Handle that marks an empty binary operation slot. */
269- private static final MethodHandle BINARY_EMPTY =
270- SpecialMethod .Signature .BINARY .empty ;
271-
272268 /** Limit on {@link #chainLength}. */
273269 public static final int MAX_CHAIN = 6 ;
274270
@@ -513,383 +509,6 @@ private Object dynamicResult(BaseType vType, Object v,
513509 return r ;
514510 }
515511
516- /**
517- * Compute the result of the call for this particular pair of
518- * arguments, and update the site to do this efficiently for the
519- * same class in the future, if it is safe and effective to do
520- * so. We call this when the class of {@code v} did not match
521- * any of the embedded guards.
522- *
523- * @param v left operand
524- * @param w right operand
525- * @return {@code op(v, w)}
526- * @throws Throwable on errors or if not implemented
527- */
528- private Object fallback_saved (Object v , Object w )
529- throws Throwable {
530- // TODO binary call site with shared representations
531- /*
532- * There is a problem with the logic of this in cases where
533- * v and w have the same representation, that may represent
534- * multiple types (a shared representation). Typically these
535- * are classes defined in Python. The site will be guarded
536- * on class, but precedence, whether we consult the left or
537- * right operand first, depends on the Python type. We can
538- * choose a precedence for the particular objects at hand
539- * using their types, but we cannot validly cache the
540- * decision for the pair of classes.
541- *
542- * If the two arguments have the same representation, and it
543- * is not a SharedRepresentation, they have the same type.
544- * If the representations differ, because the classes
545- * differ, the sub-type relationship will apply to all pairs
546- * of objects from the two classes.
547- */
548- fallbackCount += 1 ;
549-
550- Class <?> vClass = v .getClass ();
551- Representation vRep = registry .get (vClass );
552- BaseType vType = vRep .pythonType (v );
553- MethodHandle vMH ; // e.g. type(v).__sub__
554-
555- Class <?> wClass = w .getClass ();
556- Representation wRep = registry .get (wClass );
557- BaseType wType = wRep .pythonType (w );
558- MethodHandle wMH ; // e.g. type(w).__rsub__
559-
560- MethodHandle mh , targetMH ;
561-
562- /*
563- * CPython would also test: w.__rop__ == v.__op__ as an
564- * optimisation, but that's never the case since we always
565- * use distinct __op__ and __rop__ methods.
566- */
567- if (wType == vType ) {
568- // Same types so only try the op slot
569- mh = singleType (vType , vRep , wRep );
570-
571- } else if (!wType .isSubTypeOf (vType )) {
572- // Ask left (if not empty) then right.
573- mh = leftDominant (vType , vRep , wType , wRep );
574-
575- } else {
576- // Right is sub-class: ask first (if not empty).
577- mh = rightDominant (vType , vRep , wType , wRep );
578- }
579-
580- /*
581- * Compute the result for this case. If the operation
582- * throws, it throws here and we do not bind resultMH as a
583- * new target. If it's a one-off, we'll get another go.
584- */
585- Object result = mh .invokeExact (v , w );
586-
587- // MH for guarded invocation (becomes new target)
588- MethodHandle guardMH =
589- insertArguments (CLASS2_GUARD , 0 , vClass , wClass );
590- targetMH = guardWithTest (guardMH , mh , getTarget ());
591- setTarget (targetMH );
592-
593- return result ;
594- }
595-
596- /**
597- * Compute a method handle in the case where both arguments
598- * {@code (v, w)} have the same Python type, although quite
599- * possibly different Java classes (in the case where that type
600- * has multiple implementations). The returned handle may throw
601- * a Python exception when invoked, if that is the correct
602- * behaviour, but will not return {@code NotImplemented}.
603- *
604- * @param type the Python type of {@code v} and {@code w}
605- * @param vRep operations of the Java class of {@code v}
606- * @param wRep operations of the Java class of {@code w}
607- * @return a handle that provides the result (or throws)
608- */
609- private MethodHandle singleType (BaseType type ,
610- Representation vRep , Representation wRep ) {
611-
612- MethodHandle vMH ;
613-
614- // Does the type define class-specific implementations?
615- BinopGrid binops = type .getBinopGrid (op );
616- if (binops != null ) {
617- /*
618- * Are the nominal implementation classes of v, w
619- * supported as operands? These methods are not allowed
620- * to return NotImplemented, so if there's a match, it's
621- * the answer.
622- */
623- vMH = binops .get (vRep , wRep );
624- if (vMH != BINARY_EMPTY ) { return vMH ; }
625- /*
626- * vType provides class-specific implementations of
627- * op(v,w), but hang on ... both have the same type.
628- */
629- } else {
630- /*
631- * The type provides no class-specific implementation,
632- * so use the handle in the Representation object.
633- * Typically, this will be strongly-typed on the left
634- * implementation class, but will have to test the
635- * right-hand argument against supported types.
636- */
637- vMH = op .handle (vRep );
638- }
639-
640- if (vMH == BINARY_EMPTY ) {
641- // Not defined for this type, so will throw
642- return op .errorHandle ();
643- } else {
644- /*
645- * vMH is a handle that may return Py.NotImplemented,
646- * which we must turn into an error message.
647- */
648- return firstImplementer (vMH , op .errorHandle ());
649- }
650- }
651-
652- /**
653- * Compute a method handle in the case where the left argument
654- * {@code (v)} should be consulted, then the right. The returned
655- * handle may throw a Python exception when invoked, if that is
656- * the correct behaviour, but will not return
657- * {@code NotImplemented}.
658- *
659- * @param vType the Python type of {@code v}
660- * @param vRep operations of the Java class of {@code v}
661- * @param wType the Python type of {@code w}
662- * @param wRep operations of the Java class of {@code w}
663- * @return a handle that provides the result (or throws)
664- */
665- private MethodHandle leftDominant (BaseType vType ,
666- Representation vRep , BaseType wType ,
667- Representation wRep ) {
668-
669- MethodHandle resultMH , vMH , wMH ;
670-
671- // Does vType define class-specific implementations?
672- BinopGrid binops = vType .getBinopGrid (op );
673- if (binops != null ) {
674- /*
675- * Are the nominal implementation classes of v, w
676- * supported as operands? These methods are not allowed
677- * to return NotImplemented, so if there's a match, it's
678- * the answer.
679- */
680- vMH = binops .get (vRep , wRep );
681- if (vMH != BINARY_EMPTY ) { return vMH ; }
682- /*
683- * vType provides class-specific implementations of
684- * op(v,w), but the signature we are looking for is not
685- * amongst them.
686- */
687- assert (vMH == BINARY_EMPTY );
688- } else {
689- /*
690- * vType provides no class-specific implementation of
691- * op(v,w). Get the handle from the Representation
692- * object.
693- */
694- vMH = op .handle (vRep );
695- }
696-
697- // Does wType define class-specific rop implementations?
698- SpecialMethod rop = op .reflected ;
699- binops = wType .getBinopGrid (rop );
700- if (binops != null ) {
701- /*
702- * Are the nominal implementation classes of w, v
703- * supported as operands? These methods are not allowed
704- * to return NotImplemented, so if there's a match, it's
705- * the only alternative to smv.
706- */
707- wMH = binops .get (wRep , vRep );
708- if (wMH != BINARY_EMPTY ) {
709- // wType provides a rop(w,v) - note ordering
710- wMH = permuteArguments (wMH , BINOP , 1 , 0 );
711- if (vMH == BINARY_EMPTY ) {
712- // It's the only offer, so it's the answer.
713- return wMH ;
714- }
715- /*
716- * smv is also a valid offer, which must be given
717- * first refusal. Only if smv returns
718- * Py.NotImplemented, will we try smw.
719- */
720- return firstImplementer (vMH , wMH );
721- }
722- /*
723- * wType provides class-specific implementations of
724- * rop(w,v), but the signature we are looking for is not
725- * amongst them.
726- */
727- assert (wMH == BINARY_EMPTY );
728- } else {
729- /*
730- * wType provides no class-specific implementation of
731- * rop(w,v). Get the handle from the Representation
732- * object.
733- */
734- wMH = rop .handle (wRep );
735- }
736-
737- /*
738- * If we haven't returned a handle yet, we now have smv and
739- * smw, two apparent offers of a handle to compute the
740- * result for the classes at hand. Either may be empty.
741- * Either may return Py.NotImplemented.
742- */
743- if (wMH == BINARY_EMPTY ) {
744- if (vMH == BINARY_EMPTY ) {
745- // Easy case: neither slot was defined. We're done.
746- return op .errorHandle ();
747- } else {
748- // smv was the only one defined
749- resultMH = vMH ;
750- }
751- } else {
752- // smw was defined
753- wMH = permuteArguments (wMH , BINOP , 1 , 0 );
754- if (vMH == BINARY_EMPTY ) {
755- // smv was not, so smw is the only one defined
756- resultMH = wMH ;
757- } else {
758- // Both were defined, so try them in order
759- resultMH = firstImplementer (vMH , wMH );
760- }
761- }
762-
763- /*
764- * resultMH may still return Py.NotImplemented. We use
765- * firstImplementer to turn that into an error message.
766- * Where we could avoid this, we already returned.
767- */
768- return firstImplementer (resultMH , op .errorHandle ());
769- }
770-
771- /**
772- * Compute a method handle in the case where the right argument
773- * {@code (w)} should be consulted, then the left. The returned
774- * handle may throw a Python exception when invoked, if that is
775- * the correct behaviour, but will not return
776- * {@code NotImplemented}.
777- *
778- * @param vType the Python type of {@code v}
779- * @param vRep operations of the Java class of {@code v}
780- * @param wType the Python type of {@code w}
781- * @param wRep operations of the Java class of {@code w}
782- * @return a handle that provides the result (or throws)
783- */
784- private MethodHandle rightDominant (BaseType vType ,
785- Representation vRep , BaseType wType ,
786- Representation wRep ) {
787-
788- MethodHandle resultMH , vMH , wMH ;
789-
790- // Does wType define class-specific rop implementations?
791- SpecialMethod rop = op .reflected ;
792- BinopGrid binops = wType .getBinopGrid (rop );
793- if (binops != null ) {
794- /*
795- * Are the nominal implementation classes of w, v
796- * supported as operands? These methods are not allowed
797- * to return NotImplemented, so if there's a match, it's
798- * the answer.
799- */
800- wMH = binops .get (wRep , vRep );
801- if (wMH != BINARY_EMPTY ) {
802- // wType provides a rop(w,v) - note ordering
803- return permuteArguments (wMH , BINOP , 1 , 0 );
804- }
805- /*
806- * wType provides class-specific implementations of
807- * rop(w,v), but the signature we are looking for is not
808- * amongst them.
809- */
810- assert wMH == BINARY_EMPTY ;
811- } else {
812- /*
813- * wType provides no class-specific implementation of
814- * rop(w,v). Get the handle from the Representation
815- * object.
816- */
817- wMH = rop .handle (wRep );
818- }
819-
820- // Does vType define class-specific implementations?
821- binops = vType .getBinopGrid (op );
822- if (binops != null ) {
823- /*
824- * Are the nominal implementation classes of v, w
825- * supported as operands? These methods are not allowed
826- * to return NotImplemented, so if there's a match, it's
827- * the only alternative to smw.
828- */
829- vMH = binops .get (vRep , wRep );
830- if (vMH != BINARY_EMPTY ) {
831- // vType provides an op(v,w)
832- if (wMH == BINARY_EMPTY ) {
833- // It's the only offer, so it's the answer.
834- return vMH ;
835- }
836- /*
837- * smw is also a valid offer, which must be given
838- * first refusal. Only if smw returns
839- * Py.NotImplemented, will we try smv.
840- */
841- wMH = permuteArguments (wMH , BINOP , 1 , 0 );
842- return firstImplementer (wMH , vMH );
843- }
844- /*
845- * vType provides class-specific implementations of
846- * op(v,w), but the signature we are looking for is not
847- * amongst them.
848- */
849- assert vMH == BINARY_EMPTY ;
850- } else {
851- /*
852- * vType provides no class-specific implementation of
853- * op(v,w). Get the handle from the Representation
854- * object.
855- */
856- vMH = op .handle (vRep );
857- }
858-
859- /*
860- * If we haven't returned a handle yet, we now have smv and
861- * smw, two apparent offers of a handle to compute the
862- * result for the classes at hand. Either may be empty.
863- * Either may return Py.NotImplemented.
864- */
865- if (wMH == BINARY_EMPTY ) {
866- if (vMH == BINARY_EMPTY ) {
867- // Easy case: neither slot was defined. We're done.
868- return op .errorHandle ();
869- } else {
870- // smv was the only one defined
871- resultMH = vMH ;
872- }
873- } else {
874- // smw was defined
875- wMH = permuteArguments (wMH , BINOP , 1 , 0 );
876- if (vMH == BINARY_EMPTY ) {
877- // smw is the only one defined
878- resultMH = wMH ;
879- } else {
880- // Both were defined, so try them in order
881- resultMH = firstImplementer (wMH , vMH );
882- }
883- }
884-
885- /*
886- * resultMH may still return Py.NotImplemented. We use
887- * firstImplementer to turn that into an error message.
888- * Where we could avoid this, we already returned.
889- */
890- return firstImplementer (resultMH , op .errorHandle ());
891- }
892-
893512 /**
894513 * An adapter for two method handles, {@code a} and {@code b},
895514 * such that when the returned handle is invoked, first
0 commit comments