Implict Casts in Truffle DSL

Christian Humer christian.humer at gmail.com
Sat Apr 5 00:12:26 UTC 2014


Hi Wei,

SLMulNode does not use doubles. just longs. Therefore it makes no
difference which Node is used. There are no guarantees in which order
ambiguous specializations are used. Implicit casts are limited to the use
between types which are just different representations of the same guest
language type or if the operations are defined in the same way. Do not use
them for explicit type casts. Also the @TypeCheck and @TypeCast are not
suitable to do casts between types. For that we usually insert separate
specializing cast nodes on the operands which do the job.

- Christian Humer


On Sat, Apr 5, 2014 at 1:51 AM, Wei Zhang <ndrzmansn at gmail.com> wrote:

> But if SLMulNode has a specialization for doubles, SLMulBigIntegerNode
> will rewrite to SLMulDoubleNode before it reaches the code that builds up
> the polymorphic chain.
> The SLMulDoubleNode produces a double which is wrong.
> This is the problem that I had in ZipPy.
>
> I agree that simply reduce the minimalState by one does not cover the case
> that you described.
> But it is less likely to happen..
>
> Thanks,
>
> /Wei
>
>
> On Fri, Apr 4, 2014 at 4:08 PM, Christian Humer <christian.humer at gmail.com
> > wrote:
>
>> Hi Wei,
>>
>> I suggest to just decrease the minimumState value by 1, but you might
>>> have better solutions.
>>
>>
>> One of the important properties of Truffle ASTs is that they have to
>> reach a stable state at some point. If the minimumState would be reduced by
>> one and the values come in with alternating (implicit) types we would end
>> up in a rewrite loop. That's the kind of behavior that is fatal for
>> performance since the enclosed method will always get invalidated.
>>
>> In case of the SLMulNode if the types are alternating long and BigInteger
>> the generated code will build up a polymorphic chain of specializations to
>> cope with this case. Try to run this patch. It contains an example which
>> illustrates my point. Debug the run with a breakpoint in
>> executeAndSpecialize0 in SLMulBaseNode.
>>
>>
>> diff -r a31d807757ee graal/
>> com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java
>> --- a/graal/
>> com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java Thu
>> Apr 03 19:06:58 2014 +0200
>> +++ b/graal/
>> com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java Sat
>> Apr 05 01:00:56 2014 +0200
>> @@ -26,6 +26,7 @@
>>
>>  import com.oracle.truffle.api.*;
>>  import com.oracle.truffle.api.dsl.*;
>> +import com.oracle.truffle.api.frame.*;
>>  import com.oracle.truffle.api.nodes.*;
>>  import com.oracle.truffle.sl.nodes.*;
>>
>> @@ -44,4 +45,25 @@
>>      protected BigInteger mul(BigInteger left, BigInteger right) {
>>          return left.multiply(right);
>>      }
>> +
>> +    public abstract Object executeEvaluated(VirtualFrame frame, Object
>> left, Object right);
>> +
>> +    public static void main(String[] args) {
>> +        final SLMulNode mulNode = SLMulNodeFactory.create(null, null);
>> +        RootNode root = new RootNode() {
>> +            @Child SLMulNode child = mulNode;
>> +
>> +            @Override
>> +            public Object execute(VirtualFrame frame) {
>> +                child.executeEvaluated(null, 1L, 1L);
>> +                child.executeEvaluated(null, BigInteger.valueOf(1L), 1L);
>> +                child.executeEvaluated(null, 1L, BigInteger.valueOf(1L));
>> +                return null;
>> +            }
>> +        };
>> +        root.adoptChildren();
>> +        root.execute(null);
>> +
>> +        NodeUtil.printTree(System.out, root);
>> +    }
>>  }
>>
>> Hope this helps.
>>
>>
>>
>> - Christian Humer
>>
>>
>> On Thu, Apr 3, 2014 at 2:20 AM, Wei Zhang <ndrzmansn at gmail.com> wrote:
>>
>>> Hi Christian,
>>>
>>> A generated node using @ImplicitCast rewrites itself with the
>>> minimunState value of itself.
>>> This value prevents a node re-specialization to the same type but with a
>>> promoted operand type.
>>>
>>> Say a SLMulBigIntegerNode has a long operand and a BigInteger operand.
>>> At some point, the long operand become a BigInteger, and the node starts
>>> to rewrite.
>>> It should replace itself with another SLMulBigIntegerNode but with
>>> updated operand implicit types.
>>>
>>> I hope that make sense to you.
>>> I suggest to just decrease the minimumState value by 1, but you might
>>> have better solutions.
>>>
>>> Thanks,
>>>
>>>
>>> /Wei
>>>
>>>
>>> On Wed, Apr 2, 2014 at 3:46 PM, Christian Humer <
>>> christian.humer at gmail.com> wrote:
>>>
>>>> Unfortunately you have to specify all transitive implicit casts. That
>>>> gives you more control, but is also more verbose. Let me know if the number
>>>> of casts explodes. If so we could add a feature for that.
>>>>
>>>> (Sent using Android)
>>>> Am 02.04.2014 23:27 schrieb "Wei Zhang" <ndrzmansn at gmail.com>:
>>>>
>>>> Thanks for the patch. It works nicely!
>>>>>
>>>>> Yes, I'm planning to simplify the uses of @TypeCheck and @TypeCast,
>>>>> and use @ImplicitCast instead for most of the cases.
>>>>> However, I have a further question on that.
>>>>> To implement multiple levels of implicit type coercions, e.g., from
>>>>> bool to int and then to double, do I have to specify all possible
>>>>> conversions separately?
>>>>> Or can the generated code chain more than one @ImplicitCasts together
>>>>> to convert a bool directly to double?
>>>>>
>>>>> Thanks,
>>>>>
>>>>> /Wei
>>>>>
>>>>>
>>>>> On Wed, Apr 2, 2014 at 8:50 AM, Christian Humer <
>>>>> christian.humer at gmail.com> wrote:
>>>>>
>>>>>> Ups that was too quick. Forget my previous patch and use the one
>>>>>> below instead. In principle the DSL supports execute methods without a
>>>>>> VirtualFrame parameter. However there are some glitches here and there. So
>>>>>> please try to avoid them for now and always add a VirtualFrame parameter to
>>>>>> execute methods.
>>>>>>
>>>>>> diff -r ed373ed4b717
>>>>>> graal/edu.uci.python.nodes/src/edu/uci/python/nodes/expression/CastToBooleanNode.java
>>>>>> ---
>>>>>> a/graal/edu.uci.python.nodes/src/edu/uci/python/nodes/expression/CastToBooleanNode.java Wed
>>>>>> Apr 02 00:06:40 2014 -0700
>>>>>> +++
>>>>>> b/graal/edu.uci.python.nodes/src/edu/uci/python/nodes/expression/CastToBooleanNode.java Wed
>>>>>> Apr 02 17:47:21 2014 +0200
>>>>>> @@ -40,7 +40,7 @@
>>>>>>
>>>>>>  public abstract class CastToBooleanNode extends UnaryOpNode {
>>>>>>
>>>>>> -    public abstract boolean executeBoolean(Object value);
>>>>>> +    public abstract boolean executeBoolean(VirtualFrame frame,
>>>>>> Object value);
>>>>>>
>>>>>>      @Override
>>>>>>      public abstract boolean executeBoolean(VirtualFrame frame);
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> - Christian Humer
>>>>>>
>>>>>>
>>>>>> On Wed, Apr 2, 2014 at 4:43 PM, Christian Humer <
>>>>>> christian.humer at gmail.com> wrote:
>>>>>>
>>>>>>> Hi Wei,
>>>>>>>
>>>>>>> You found a bug. Thanks for the report. In the future don't hesitate
>>>>>>> to send a report even if you are not sure if it is already fixed. Here is a
>>>>>>> temporary patch for you. I will push this fix with my next greater push to
>>>>>>> openjdk.
>>>>>>>
>>>>>>> BTW.: you should get rid of your overly complicated @TypeCheck and
>>>>>>> @TypeCast implementations in the type system. There may be a major
>>>>>>> performance problem hidden here. Ideally you should only use the ones that
>>>>>>> are generated by default. I think you can get rid of them mostly by using
>>>>>>> ImplicitCasts. But maybe that's the thing you wanted to do anyway. Feel
>>>>>>> free to contact me again if you need help with that.
>>>>>>>
>>>>>>> diff -r ed373ed4b717
>>>>>>> graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java
>>>>>>> ---
>>>>>>> a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Wed
>>>>>>> Apr 02 00:06:40 2014 -0700
>>>>>>> +++
>>>>>>> b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Wed
>>>>>>> Apr 02 16:34:32 2014 +0200
>>>>>>> @@ -2032,7 +2032,11 @@
>>>>>>>
>>>>>>>              CodeExecutableElement method = new
>>>>>>> CodeExecutableElement(modifiers(PROTECTED, expectType != null ? STATIC :
>>>>>>> FINAL), param.getType(), childExecuteName);
>>>>>>>
>>>>>>>  method.getThrownTypes().add(getContext().getTruffleTypes().getUnexpectedValueException());
>>>>>>> -            method.addParameter(new
>>>>>>> CodeVariableElement(getContext().getTruffleTypes().getFrame(),
>>>>>>> "frameValue"));
>>>>>>> +
>>>>>>> +            if (expectType == null) {
>>>>>>> +                method.addParameter(new
>>>>>>> CodeVariableElement(getContext().getTruffleTypes().getFrame(),
>>>>>>> "frameValue"));
>>>>>>> +            }
>>>>>>> +
>>>>>>>              if (expectType != null) {
>>>>>>>                  method.addParameter(new
>>>>>>> CodeVariableElement(expectType.getPrimitiveType(),
>>>>>>> valueNameEvaluated(param)));
>>>>>>>              }
>>>>>>>
>>>>>>>
>>>>>>> - Christian Humer
>>>>>>>
>>>>>>>
>>>>>>> On Tue, Apr 1, 2014 at 10:10 PM, Wei Zhang <ndrzmansn at gmail.com>wrote:
>>>>>>>
>>>>>>>> Hi Christian,
>>>>>>>>
>>>>>>>> I'm experiencing a problem when using @ImplicitCast.
>>>>>>>>
>>>>>>>> I added the following code in PythonTypes.java:
>>>>>>>>
>>>>>>>> @ImplicitCast
>>>>>>>> public String unboxPString(PString value) {
>>>>>>>>       return value.getValue();
>>>>>>>> }
>>>>>>>>
>>>>>>>> This use causes a javac error in the generated
>>>>>>>> CastToBooleanNodeFactory.java.
>>>>>>>>
>>>>>>>> You can pull the latest change from ZipPy to reproduce this.
>>>>>>>> I've commented the use of @ImplicitCast in PythonTypes.
>>>>>>>> I did not report this problem earlier because I have not merge with
>>>>>>>> the Graal repo for a while and expected that it might be fixed in a recent
>>>>>>>> commit.
>>>>>>>>
>>>>>>>> Any suggestion?
>>>>>>>> Thanks,
>>>>>>>>
>>>>>>>> /Wei
>>>>>>>>
>>>>>>>>
>>>>>>>> On Sat, Dec 21, 2013 at 8:49 AM, Christian Humer <
>>>>>>>> christian.humer at gmail.com> wrote:
>>>>>>>>
>>>>>>>>> Hey folks,
>>>>>>>>>
>>>>>>>>> There were some questions floating around about the ImplicitCast
>>>>>>>>> feature in Truffle DSL.
>>>>>>>>> So here is a short description of what it does:
>>>>>>>>>
>>>>>>>>> The idea behind ImplicitCasts is that it tries to reduce the
>>>>>>>>> number of specializations required to define an operation. Imagine you got
>>>>>>>>> arithmetics with tree different types. That could be int, double and
>>>>>>>>> complex. However in our guest language we have several different
>>>>>>>>> representations of the same type for optimization reasons. For instance an
>>>>>>>>> int could be represented as Java int, IntSequence, IntVector or even as
>>>>>>>>> LogicalToIntVectorClosure (this example is borrowed from R).
>>>>>>>>> This makes a lot of combinations of types in binary operation to
>>>>>>>>> fully specialize itself. So assuming that double and complex have the same
>>>>>>>>> number of different representations and their number may even rise, the
>>>>>>>>> number of specializations will explode at some point in time.
>>>>>>>>> The solution for this problem was to introduce a new concept to
>>>>>>>>> the DSL, namely @ImplicitCast. The idea behind is that you can define
>>>>>>>>> casts that are inserted before a specialization is called on
>>>>>>>>> demand.
>>>>>>>>>
>>>>>>>>> So assume we have defined the specializations for a binary
>>>>>>>>> operation which fully specializes for the types int and IntVector. Without
>>>>>>>>> implicit casts you would have to define these four
>>>>>>>>> specializations.
>>>>>>>>>
>>>>>>>>> @Specialization int doOp(int left, int right) {...}
>>>>>>>>> @Specialization int doOp(IntVector left, int right) {...}
>>>>>>>>> @Specialization int doOp(int left, IntVector right) {...}
>>>>>>>>> @Specialization int doOp(IntVector left, IntVector right) {...}
>>>>>>>>>
>>>>>>>>> However if we assume that all four specializations would want to
>>>>>>>>> specialize to basically the same code we can use implicit casts to
>>>>>>>>> declare this more elegantly. For this we introduce a new interface called
>>>>>>>>> AbstractIntVector which is the base interface for IntVector, IntSequence
>>>>>>>>> etc. and we have to define some implicit casts in the type system
>>>>>>>>> like this:
>>>>>>>>>
>>>>>>>>>     @ImplicitCast
>>>>>>>>>     public AbstractIntVector toAbstractIntVector(int value) {
>>>>>>>>>         return DataFactory.createIntVectorFromScalar(value);
>>>>>>>>>     }
>>>>>>>>>     @ImplicitCast
>>>>>>>>>     public AbstractIntVector toAbstractIntVector(IntVector vector)
>>>>>>>>> {
>>>>>>>>>         return vector;
>>>>>>>>>     }
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> @Specialization int
>>>>>>>>> doOp(AbstractIntVector left, AbstractIntVector right) {...}
>>>>>>>>>
>>>>>>>>> Now we can just define one specialization and we get the same
>>>>>>>>> specialization combinations as in the first example. Please be aware that
>>>>>>>>> this is not completely the same thing as before since the implicit
>>>>>>>>>  cast method toAbstractIntVector is invoked prior to the
>>>>>>>>> invocation of the specialization. However Graal/Truffle is pretty good in
>>>>>>>>> removing unnecessary allocations for boxing if it sees the position of
>>>>>>>>> boxing as well as the position of the unboxing.
>>>>>>>>>
>>>>>>>>> You may even combine both the upper with the lower approach, like
>>>>>>>>> this:
>>>>>>>>>
>>>>>>>>> @Specialization int doOp(int left, int right) {...}
>>>>>>>>> @Specialization int
>>>>>>>>> doOp(AbstractIntVector left, AbstractIntVector right) {...}
>>>>>>>>>
>>>>>>>>> In this case you can provide a more optimized version for (int,
>>>>>>>>> int) but not having to specialize all the other combinations.
>>>>>>>>> Implicit casts are even more useful if the number of
>>>>>>>>> representations of the same logical type is high. This enables you to keep
>>>>>>>>> the number of specializations in binary nodes under control without
>>>>>>>>> breaking your fingers.
>>>>>>>>>
>>>>>>>>> Please note: On the contrary to custom @TypeCheck and @TypeCast
>>>>>>>>> methods, @ImplicitCasts are inserted on-demand. This means that they do not
>>>>>>>>> introduce additional overhead in compiled code as custom @TypeCheck or
>>>>>>>>> @TypeCast methods would.
>>>>>>>>>
>>>>>>>>> Feel free to ask further questions.
>>>>>>>>>
>>>>>>>>> - Christian Humer
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>
>>
>


More information about the graal-dev mailing list