# HG changeset patch # User Christian Humer # Date 1356115471 28800 # Node ID a748e4d44694b9b8a15a178292339a2e52d89bce # Parent a81db08fe930607b9eee331882a34779b2a6d2ad Truffle API to specify type-specalized Node classes; annotation processor for automatic code generation of the type-specialized Node classes during the build process diff -r a81db08fe930 -r a748e4d44694 .hgignore --- a/.hgignore Fri Dec 21 10:21:24 2012 +0100 +++ b/.hgignore Fri Dec 21 10:44:31 2012 -0800 @@ -12,6 +12,8 @@ ^work/ \.checkstyle$ \.classpath +\.factorypath +\.externalToolBuilders \.project \.settings/ \.metadata/ @@ -43,6 +45,7 @@ ^test-output/ scratch/ bin/ +src_gen/ ^local/ ^src/share/tools/hsdis/build/ ^src/share/tools/IdealGraphVisualizer/[a-zA-Z0-9]*/build/ @@ -59,3 +62,7 @@ syntax: glob *.bgv core.* +*.jar +eclipse-build.xml +rebuild-launch.out + diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/ExtensionAnnotation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/ExtensionAnnotation.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + + +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.ANNOTATION_TYPE}) +public @interface ExtensionAnnotation { + + String processorClassName(); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GeneratedBy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GeneratedBy.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + +/** + * Marks a type to be generated by another class. + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE}) +public @interface GeneratedBy { + + Class< ? > value(); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Generic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Generic.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + +/** + * + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD}) +public @interface Generic { +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GuardCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GuardCheck.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + +/** + * + * + * @see SpecializationGuard + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD}) +public @interface GuardCheck { + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Operation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Operation.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; +import com.oracle.truffle.api.nodes.*; + +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE}) +public @interface Operation { + + Class< ? > typeSystem(); + + Class baseClass() default Node.class; + + String[] values() default {}; + + String[] shortCircuitValues() default {}; + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/ShortCircuit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/ShortCircuit.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD}) +public @interface ShortCircuit { + + String value(); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD}) +public @interface Specialization { + + int DEFAULT_ORDER = -1; + + int order() default DEFAULT_ORDER; + + SpecializationThrows[] exceptions() default {}; + + SpecializationGuard[] guards() default {}; + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationGuard.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationGuard.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + +/** + * Specifies the use of a guard for a specialization. + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD}) +public @interface SpecializationGuard { + + /** + * Specifies the name of the guard method annotated by {@link GuardCheck} specified as method in the + * {@link TypeSystem} or {@link Operation} class. + */ + String methodName(); + + /** + * Determines if a guard check is invoked on specialization. Defaults to true. + */ + boolean onSpecialization() default true; + + /** + * Determines if a guard check is invoked on execution. Defaults to true. + */ + boolean onExecution() default true; + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationListener.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD}) +public @interface SpecializationListener { +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationThrows.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationThrows.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD}) +public @interface SpecializationThrows { + + Class< ? extends Throwable> javaClass(); + + String transitionTo(); +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeCast.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeCast.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + + +/** + * + * + * + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD}) +public @interface TypeCast { + + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeCheck.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + +/** + *

+ * Provides a way to define a custom type check for a defined type. The name of the annotated method must fit to the + * pattern is${typeName} (eg. isInteger), where ${typeName} must be a valid type defined in the parent + * {@link TypeSystem}. The annotated method must have exactly one argument where the type of the argument is the generic + * type {@link Object} or a more specific one from the {@link TypeSystem}. You can define multiple overloaded + * {@link TypeCheck} methods for the same type. This can be used to reduce the boxing overhead in type conversions. + *

+ * + *

+ * By default the system generates type checks for all types in the parent {@link TypeSystem} which look like the + * follows: + * + *

+ * @TypeCheck
+ * boolean is${typeName}(Object value) {
+ *         return value instanceof ${typeName};
+ * }
+ * 
+ * + *

+ * + * Example: + *

+ * A type check for BigInteger with one overloaded optimized variant to reduce boxing. + *

+ * + *
+ *
+ *
+ * @TypeSystem(types = {int.class, BigInteger.class, String.class}, nodeBaseClass = TypedNode.class)
+ * public abstract class Types {
+ *
+ *     @TypeCheck
+ *     public boolean isBigInteger(Object value) {
+ *         return value instanceof Integer || value instanceof BigInteger;
+ *     }
+ *
+ *     @TypeCheck
+ *     public boolean isBigInteger(int value) {
+ *         return true;
+ *     }
+ *
+ * }
+ * 
+ * + * + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD}) +public @interface TypeCheck { + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + +import com.oracle.truffle.api.nodes.*; + +/** + *

+ * Annotates a type system class that represents type information for a node. Generates code for converting and managing + * types. Methods contained in the type system may be annotated with {@link TypeCast}, {@link TypeCheck} or + * {@link GuardCheck}. These methods alter the default behavior of the type system. + *

+ * + * + * Example: + *

+ * Shows a @TypeSystem definition with three types. In this example BigIntegers can be also treated as + * integers if their bit width is less than 32. + *

+ * + *
+ *
+ * @TypeSystem(types = {int.class, BigInteger.class, String.class}, nodeBaseClass = TypedNode.class)
+ * public abstract class Types {
+ *
+ *     @TypeCheck
+ *     public boolean isInteger(Object value) {
+ *         return value instanceof Integer || (value instanceof BigInteger && ((BigInteger) value).bitLength() < Integer.SIZE);
+ *     }
+ *
+ *     @TypeCast
+ *     public int asInteger(Object value) {
+ *         if (value instanceof Integer) {
+ *             return (int) value;
+ *         } else {
+ *             return ((BigInteger) value).intValue();
+ *         }
+ *     }
+ * }
+ * 
+ * + * @see TypeCast + * @see TypeCheck + * @see GuardCheck + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE}) +public @interface TypeSystem { + + /** + * Sets the types contained by this type system. The order of types also determines the order of specialization. + */ + Class[] types(); + + /** + * Specifies whether the node base class has an executeVoid method or not. Operations derived from this type system + * will automatically implement executeVoid for all generated nodes. Defaults to false. + */ + boolean hasVoid() default false; + + /** + * Specifies the node base class used for generated code that uses this type system. The node base class must extend + * {@link Node} and provide a public non-final method ${type} execute${typeName}(VirtualFrame) for all + * types specified in the types attribute. + */ + Class< ? extends Node> nodeBaseClass(); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/META-INF/services/javax.annotation.processing.Processor --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/META-INF/services/javax.annotation.processing.Processor Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,1 @@ +com.oracle.truffle.codegen.processor.TruffleProcessor \ No newline at end of file diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor; + +import java.lang.annotation.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; + +import com.oracle.truffle.codegen.processor.template.*; + +/** + * THIS IS NOT PUBLIC API. + */ +public abstract class AbstractParser { + + protected final ProcessorContext context; + protected final ProcessingEnvironment processingEnv; + protected RoundEnvironment roundEnv; + + protected final Log log; + + public AbstractParser(ProcessorContext c) { + this.context = c; + this.processingEnv = c.getEnvironment(); + this.log = c.getLog(); + } + + public final M parse(RoundEnvironment env, Element element) { + this.roundEnv = env; + try { + AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, element.getAnnotationMirrors(), getAnnotationType()); + if (!context.getTruffleTypes().verify(context, element, mirror)) { + return null; + } + return parse(element, mirror); + } finally { + this.roundEnv = null; + } + } + + protected abstract M parse(Element element, AnnotationMirror mirror); + + public abstract Class< ? extends Annotation> getAnnotationType(); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AnnotationProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AnnotationProcessor.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor; + +import java.io.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.tools.*; + +import com.oracle.truffle.codegen.processor.ast.*; +import com.oracle.truffle.codegen.processor.codewriter.*; +import com.oracle.truffle.codegen.processor.compiler.*; +import com.oracle.truffle.codegen.processor.template.*; + +/** + * THIS IS NOT PUBLIC API. + */ +class AnnotationProcessor { + + private final AbstractParser parser; + private final CompilationUnitFactory factory; + private final ProcessorContext context; + + private final Set processedElements = new HashSet<>(); + + public AnnotationProcessor(ProcessorContext context, AbstractParser parser, CompilationUnitFactory factory) { + this.context = context; + this.parser = parser; + this.factory = factory; + } + + public AbstractParser getParser() { + return parser; + } + + public ProcessorContext getContext() { + return context; + } + + @SuppressWarnings({"unchecked"}) + public void process(RoundEnvironment env, Element element, boolean callback) { + + // since it is not guaranteed to be called only once by the compiler + // we check for already processed elements to avoid errors when writing files. + if (!callback && element instanceof TypeElement) { + String qualifiedName = Utils.getQualifiedName((TypeElement) element); + if (processedElements.contains(qualifiedName)) { + return; + } + processedElements.add(qualifiedName); + } + + TypeElement type = (TypeElement) element; + + M model = (M) context.getTemplate(type.asType(), false); + boolean firstRun = !context.containsTemplate(type); + + if (firstRun || !callback) { + context.registerTemplate(type, null); + model = parser.parse(env, element); + context.registerTemplate(type, model); + + if (model != null) { + CodeCompilationUnit unit = (CodeCompilationUnit) factory.process(model); + unit.setGeneratorAnnotationMirror(model.getTemplateTypeAnnotation()); + unit.setGeneratorElement(model.getTemplateType()); + + DeclaredType overrideType = (DeclaredType) context.getType(Override.class); + DeclaredType unusedType = (DeclaredType) context.getType(SuppressWarnings.class); + unit.accept(new GenerateOverrideVisitor(overrideType), null); + unit.accept(new FixWarningsVisitor(context, unusedType, overrideType), null); + + if (!callback) { + unit.accept(new CodeWriter(context.getEnvironment(), element), null); + } + } + } + } + + private static class CodeWriter extends AbstractCodeWriter { + + private final Element orignalElement; + private final ProcessingEnvironment env; + + public CodeWriter(ProcessingEnvironment env, Element originalElement) { + this.env = env; + this.orignalElement = originalElement; + } + + @Override + protected Writer createWriter(CodeTypeElement clazz) throws IOException { + JavaFileObject jfo = env.getFiler().createSourceFile(clazz.getQualifiedName(), orignalElement); + return jfo.openWriter(); + } + + @Override + protected void writeHeader() { + if (env == null) { + return; + } + String comment = CompilerFactory.getCompiler(orignalElement).getHeaderComment(env, orignalElement); + if (comment != null) { + writeLn(comment); + } + } + + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.tools.Diagnostic.Kind; + +import com.oracle.truffle.codegen.processor.ast.*; + +/** + * THIS IS NOT PUBLIC API. + */ +public class Log { + + private final ProcessingEnvironment processingEnv; + + public Log(ProcessingEnvironment env) { + this.processingEnv = env; + } + + public void warning(Element element, String format, Object ... args) { + message(Kind.WARNING, element, null, null, format, args); + } + + public void warning(Element element, AnnotationMirror mirror, String format, Object ... args) { + message(Kind.WARNING, element, mirror, null, format, args); + } + + public void error(Element element, String format, Object... args) { + message(Kind.ERROR, element, null, null, format, args); + } + + public void error(Element element, AnnotationMirror mirror, String format, Object... args) { + message(Kind.ERROR, element, mirror, null, format, args); + } + + public void error(Element element, AnnotationMirror mirror, AnnotationValue value, String format, Object... args) { + message(Kind.ERROR, element, mirror, value, format, args); + } + + public void message(Kind kind, Element element, AnnotationMirror mirror, AnnotationValue value, String format, Object... args) { + AnnotationMirror usedMirror = mirror; + Element usedElement = element; + AnnotationValue usedValue = value; + String message = String.format(format, args); + + if (element instanceof GeneratedElement) { + usedMirror = ((GeneratedElement) element).getGeneratorAnnotationMirror(); + usedElement = ((GeneratedElement) element).getGeneratorElement(); + usedValue = null; + if (usedElement != null) { + message = String.format("Element %s: %s", element, message); + } + } + processingEnv.getMessager().printMessage(kind, message, usedElement, usedMirror, usedValue); + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ProcessorContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ProcessorContext.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor; + +import static com.oracle.truffle.codegen.processor.Utils.*; + +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.ast.CodeTypeMirror.ArrayCodeTypeMirror; +import com.oracle.truffle.codegen.processor.template.*; + +/** + * THIS IS NOT PUBLIC API. + */ +public class ProcessorContext { + + private final ProcessingEnvironment environment; + + private final Map models = new HashMap<>(); + private final Map> generatedClasses = new HashMap<>(); + + private final ProcessCallback callback; + private final Log log; + private final TruffleTypes truffleTypes; + + public ProcessorContext(ProcessingEnvironment env, ProcessCallback callback) { + this.environment = env; + this.callback = callback; + this.log = new Log(environment); + this.truffleTypes = new TruffleTypes(this); + } + + public TruffleTypes getTruffleTypes() { + return truffleTypes; + } + + public Log getLog() { + return log; + } + + public ProcessingEnvironment getEnvironment() { + return environment; + } + + public boolean containsTemplate(TypeElement element) { + return models.containsKey(Utils.getQualifiedName(element)); + } + + public void registerTemplate(TypeElement element, Template model) { + models.put(Utils.getQualifiedName(element), model); + } + + public void registerType(TypeElement templateType, TypeMirror generatedTypeMirror) { + String templateQualifiedName = getQualifiedName(templateType); + Map simpleNameToType = generatedClasses.get(templateQualifiedName); + if (simpleNameToType == null) { + simpleNameToType = new HashMap<>(); + generatedClasses.put(templateQualifiedName, simpleNameToType); + } + String generatedSimpleName = getSimpleName(generatedTypeMirror); + simpleNameToType.put(generatedSimpleName, generatedTypeMirror); + } + + public Template getTemplate(TypeMirror templateTypeMirror, boolean invokeCallback) { + String qualifiedName = Utils.getQualifiedName(templateTypeMirror); + Template model = models.get(qualifiedName); + if (model == null && invokeCallback) { + callback.callback(Utils.fromTypeMirror(templateTypeMirror)); + model = models.get(qualifiedName); + } + return model; + } + + public TypeMirror resolveNotYetCompiledType(TypeMirror mirror, Template templateHint) { + TypeMirror resolvedType = null; + if (mirror.getKind() == TypeKind.ARRAY) { + TypeMirror originalComponentType = ((ArrayType) mirror).getComponentType(); + TypeMirror resolvedComponent = resolveNotYetCompiledType(originalComponentType, templateHint); + if (resolvedComponent != originalComponentType) { + return new ArrayCodeTypeMirror(resolvedComponent); + } + } + + if (mirror.getKind() == TypeKind.ERROR) { + Element element = ((ErrorType) mirror).asElement(); + ElementKind kind = element.getKind(); + if (kind == ElementKind.CLASS || kind == ElementKind.PARAMETER || kind == ElementKind.ENUM) { + String simpleName = element.getSimpleName().toString(); + resolvedType = findGeneratedClassBySimpleName(simpleName, templateHint); + } + } else { + resolvedType = mirror; + } + + return resolvedType; + } + + public TypeMirror findGeneratedClassBySimpleName(String simpleName, Template templateHint) { + if (templateHint == null) { + // search all + for (String qualifiedTemplateName : generatedClasses.keySet()) { + Map mirrors = generatedClasses.get(qualifiedTemplateName); + if (mirrors.get(simpleName) != null) { + return mirrors.get(simpleName); + } + } + return null; + } else { + String templateQualifiedName = getQualifiedName(templateHint.getTemplateType()); + Map simpleNameToType = generatedClasses.get(templateQualifiedName); + if (simpleNameToType == null) { + return null; + } + return simpleNameToType.get(simpleName); + } + } + + public TypeMirror getType(String className) { + TypeElement element = environment.getElementUtils().getTypeElement(className); + if (element != null) { + return element.asType(); + } + return null; + } + + public TypeMirror getType(Class< ? > element) { + TypeMirror mirror; + if (element.isPrimitive()) { + if (element == boolean.class) { + mirror = environment.getTypeUtils().getPrimitiveType(TypeKind.BOOLEAN); + } else if (element == byte.class) { + mirror = environment.getTypeUtils().getPrimitiveType(TypeKind.BYTE); + } else if (element == short.class) { + mirror = environment.getTypeUtils().getPrimitiveType(TypeKind.SHORT); + } else if (element == char.class) { + mirror = environment.getTypeUtils().getPrimitiveType(TypeKind.CHAR); + } else if (element == int.class) { + mirror = environment.getTypeUtils().getPrimitiveType(TypeKind.INT); + } else if (element == long.class) { + mirror = environment.getTypeUtils().getPrimitiveType(TypeKind.LONG); + } else if (element == float.class) { + mirror = environment.getTypeUtils().getPrimitiveType(TypeKind.FLOAT); + } else if (element == double.class) { + mirror = environment.getTypeUtils().getPrimitiveType(TypeKind.DOUBLE); + } else if (element == void.class) { + mirror = environment.getTypeUtils().getNoType(TypeKind.VOID); + } else { + assert false; + return null; + } + } else { + TypeElement typeElement = environment.getElementUtils().getTypeElement(element.getCanonicalName()); + mirror = typeElement.asType(); + } + return mirror; + } + + public interface ProcessCallback { + + void callback(TypeElement template); + + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor; + +import java.lang.annotation.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; + +import com.oracle.truffle.codegen.processor.ProcessorContext.ProcessCallback; +import com.oracle.truffle.codegen.processor.operation.*; +import com.oracle.truffle.codegen.processor.typesystem.*; + +/** + * THIS IS NOT PUBLIC API. + */ +//@SupportedAnnotationTypes({"com.oracle.truffle.codegen.Operation", "com.oracle.truffle.codegen.TypeLattice"}) +@SupportedSourceVersion(SourceVersion.RELEASE_7) +public class TruffleProcessor extends AbstractProcessor implements ProcessCallback { + + private ProcessorContext context; + private List> generators; + + private RoundEnvironment round; + + @Override + public boolean process(Set< ? extends TypeElement> annotations, RoundEnvironment roundEnv) { + if (!roundEnv.processingOver()) { + processImpl(roundEnv); + } + return false; + } + + @SuppressWarnings("unchecked") + private void processImpl(RoundEnvironment env) { + this.round = env; + // TODO run verifications that other annotations are not processed out of scope of the operation or typelattice. + try { + for (AnnotationProcessor generator : getGenerators()) { + for (Element e : env.getElementsAnnotatedWith(generator.getParser().getAnnotationType())) { + processElement(env, generator, e, false); + } + } + } finally { + this.round = null; + } + } + + private static void processElement(RoundEnvironment env, AnnotationProcessor generator, Element e, boolean callback) { + try { + generator.process(env, e, callback); + } catch (Throwable e1) { + handleThrowable(generator, e1, e); + } + } + + private static void handleThrowable(AnnotationProcessor generator, Throwable t, Element e) { + String message = "Uncaught error in " + generator.getClass().getSimpleName() + " while processing " + e; + generator.getContext().getLog().error(e, message + ": " + Utils.printException(t)); + } + + @SuppressWarnings("unchecked") + @Override + public void callback(TypeElement template) { + for (AnnotationProcessor generator : generators) { + Annotation annotation = template.getAnnotation(generator.getParser().getAnnotationType()); + if (annotation != null) { + processElement(round, generator, template, true); + } + } + } + + @Override + public Set getSupportedAnnotationTypes() { + Set annotations = new HashSet<>(); + for (AnnotationProcessor< ? > generator : getGenerators()) { + annotations.add(generator.getParser().getAnnotationType().getCanonicalName()); + } + return annotations; + } + + private List> getGenerators() { + if (generators == null && processingEnv != null) { + generators = new ArrayList<>(); + generators.add(new AnnotationProcessor<>(getContext(), new TypeSystemParser(getContext()), new TypeSystemCodeGenerator(getContext()))); + generators.add(new AnnotationProcessor<>(getContext(), new OperationParser(getContext()), new OperationCodeGenerator(getContext()))); + } + return generators; + } + + private ProcessorContext getContext() { + if (context == null) { + context = new ProcessorContext(processingEnv, this); + } + return context; + } + + @Override + public synchronized void init(ProcessingEnvironment env) { + this.processingEnv = env; + super.init(env); + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.nodes.Node.Children; + +/** + * THIS IS NOT PUBLIC API. + */ +public final class TruffleTypes { + + private final TypeMirror node; + private final TypeMirror nodeArray; + private final TypeMirror unexpectedValueException; + private final TypeMirror frame; + private final TypeMirror stableAnnotation; + private final TypeMirror contentStableAnnotation; + private final TypeMirror typeConversion; + + private final List errors = new ArrayList<>(); + + public TruffleTypes(ProcessorContext context) { + node = getRequired(context, Node.class); + nodeArray = context.getEnvironment().getTypeUtils().getArrayType(node); + unexpectedValueException = getRequired(context, UnexpectedResultException.class); + frame = getRequired(context, VirtualFrame.class); + stableAnnotation = getRequired(context, Child.class); + contentStableAnnotation = getRequired(context, Children.class); + typeConversion = getRequired(context, TypeConversion.class); + } + + public boolean verify(ProcessorContext context, Element element, AnnotationMirror mirror) { + if (errors.isEmpty()) { + return true; + } + + for (String error : errors) { + context.getLog().error(element, mirror, error); + } + + return false; + } + + private TypeMirror getRequired(ProcessorContext context, Class clazz) { + TypeMirror type = context.getType(clazz); + if (type == null) { + errors.add(String.format("Could not find required type: %s", clazz.getSimpleName())); + } + return type; + } + + public TypeMirror getTypeConversion() { + return typeConversion; + } + + public TypeMirror getNode() { + return node; + } + + public TypeMirror getNodeArray() { + return nodeArray; + } + + public TypeMirror getFrame() { + return frame; + } + + public TypeMirror getUnexpectedValueException() { + return unexpectedValueException; + } + + public TypeMirror getStableAnnotation() { + return stableAnnotation; + } + + public TypeMirror getContentStableAnnotation() { + return contentStableAnnotation; + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor; + +import java.io.*; +import java.lang.annotation.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.codegen.processor.ast.*; +import com.oracle.truffle.codegen.processor.compiler.*; + +/** + * THIS IS NOT PUBLIC API. + */ +public class Utils { + + public static String getMethodBody(ProcessingEnvironment env, ExecutableElement method) { + if (method instanceof CodeExecutableElement) { + return ((CodeExecutableElement) method).getBody(); + } else { + return CompilerFactory.getCompiler(method).getMethodBody(env, method); + } + } + + public static List collectAnnotations( + ProcessorContext context, + AnnotationMirror markerAnnotation, String elementName, Element element, + Class< ? extends Annotation> annotationClass) { + List result = Utils.getAnnotationValueList(markerAnnotation, elementName); + AnnotationMirror explicit = Utils.findAnnotationMirror(context.getEnvironment(), element, annotationClass); + if (explicit != null) { + result.add(explicit); + } + + for (AnnotationMirror mirror : result) { + assert Utils.typeEquals(mirror.getAnnotationType(), context.getType(annotationClass)); + } + return result; + } + + public static boolean hasError(TypeMirror mirror) { + switch (mirror.getKind()) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case SHORT: + case LONG: + case DECLARED: + case VOID: + case TYPEVAR: + return false; + case ARRAY: + return hasError(((ArrayType) mirror).getComponentType()); + case ERROR: + return true; + default: + throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); + } + } + + /** + * True if t1 is assignable to t2. + */ + public static boolean isAssignable(TypeMirror t1, TypeMirror t2) { + if (typeEquals(t1, t2)) { + return true; + } + if (isPrimitive(t1) || isPrimitive(t2)) { + // non-equal primitive types + return false; + } + if (t1 instanceof ArrayType && t2 instanceof ArrayType) { + return isAssignable(((ArrayType) t1).getComponentType(), ((ArrayType) t2).getComponentType()); + } + + TypeElement e1 = fromTypeMirror(t1); + TypeElement e2 = fromTypeMirror(t2); + if (e1 == null || e2 == null) { + return false; + } + + List superTypes = getSuperTypes(e1); + for (TypeElement superType : superTypes) { + if (typeEquals(superType.asType(), t2)) { + return true; + } + } + return false; + } + + public static Set modifiers(Modifier... modifier) { + return new LinkedHashSet<>(Arrays.asList(modifier)); + } + + public static String getSimpleName(TypeElement element) { + return getSimpleName(element.asType()); + } + + public static String getSimpleName(TypeMirror mirror) { + switch (mirror.getKind()) { + case BOOLEAN: + return "boolean"; + case BYTE: + return "byte"; + case CHAR: + return "char"; + case DOUBLE: + return "double"; + case FLOAT: + return "float"; + case SHORT: + return "short"; + case INT: + return "int"; + case LONG: + return "long"; + case DECLARED: + return getGenericName(fromTypeMirror(mirror)); + case ARRAY: + return getSimpleName(((ArrayType) mirror).getComponentType()) + "[]"; + case VOID: + return "void"; + case TYPEVAR: + return ((TypeParameterElement) ((TypeVariable) mirror).asElement()).getSimpleName().toString(); + default: + throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); + } + } + + + private static String getGenericName(TypeElement element) { + String simpleName = element.getSimpleName().toString(); + + if (element.getTypeParameters().size() == 0) { + return simpleName; + } + + StringBuilder b = new StringBuilder(simpleName); + b.append("<"); + if (element.getTypeParameters().size() > 0) { + for (int i = 0; i < element.getTypeParameters().size(); i++) { + b.append("?"); + if (i < element.getTypeParameters().size() - 1) { + b.append(", "); + } + } + } + b.append(">"); + return b.toString(); + } + + public static String getQualifiedName(TypeElement element) { + return element.getQualifiedName().toString(); + } + + public static String getQualifiedName(TypeMirror mirror) { + switch (mirror.getKind()) { + case BOOLEAN: + return "boolean"; + case BYTE: + return "byte"; + case CHAR: + return "char"; + case DOUBLE: + return "double"; + case SHORT: + return "short"; + case FLOAT: + return "float"; + case INT: + return "int"; + case LONG: + return "long"; + case DECLARED: + return getQualifiedName(fromTypeMirror(mirror)); + case ARRAY: + return getQualifiedName(((ArrayType) mirror).getComponentType()); + case VOID: + return "void"; + case TYPEVAR: + return getSimpleName(mirror); + default: + throw new RuntimeException("Unknown type specified " + mirror + " mirror: " + mirror); + } + } + + public static boolean isVoid(TypeMirror mirror) { + return mirror.getKind() == TypeKind.VOID; + } + + public static boolean isPrimitive(TypeMirror mirror) { + return mirror.getKind().isPrimitive(); + } + + public static List getQualifiedSuperTypeNames(TypeElement element) { + List types = getSuperTypes(element); + List qualifiedNames = new ArrayList<>(); + for (TypeElement type : types) { + qualifiedNames.add(getQualifiedName(type)); + } + return qualifiedNames; + } + + public static List getDeclaredTypes(TypeElement element) { + return ElementFilter.typesIn(element.getEnclosedElements()); + } + + public static VariableElement findDeclaredField(TypeMirror type, String singletonName) { + List elements = ElementFilter.fieldsIn(fromTypeMirror(type).getEnclosedElements()); + for (VariableElement var : elements) { + if (var.getSimpleName().toString().equals(singletonName)) { + return var; + } + } + return null; + } + + public static TypeElement findEnclosingType(Element element) { + Element enclosing = element.getEnclosingElement(); + while (enclosing.getKind() != ElementKind.CLASS && enclosing.getKind() != ElementKind.ENUM && enclosing.getKind() != ElementKind.INTERFACE) { + enclosing = element.getEnclosingElement(); + } + + return (TypeElement) enclosing; + } + + public static List getSuperTypes(TypeElement element) { + List types = new ArrayList<>(); + List superTypes = null; + List superInterfaces = null; + if (element.getSuperclass() != null) { + TypeElement superElement = fromTypeMirror(element.getSuperclass()); + if (superElement != null) { + types.add(superElement); + superTypes = getSuperTypes(superElement); + } + } + for (TypeMirror interfaceMirror : element.getInterfaces()) { + TypeElement interfaceElement = fromTypeMirror(interfaceMirror); + if (interfaceElement != null) { + types.add(interfaceElement); + superInterfaces = getSuperTypes(interfaceElement); + } + } + + if (superTypes != null) { + types.addAll(superTypes); + } + + if (superInterfaces != null) { + types.addAll(superInterfaces); + } + + return types; + } + + public static String getPackageName(TypeElement element) { + return findPackageElement(element).getQualifiedName().toString(); + } + + public static String getPackageName(TypeMirror mirror) { + switch (mirror.getKind()) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case SHORT: + case INT: + case LONG: + case VOID: + case TYPEVAR: + return null; + case DECLARED: + PackageElement pack = findPackageElement(fromTypeMirror(mirror)); + if (pack == null) { + throw new IllegalArgumentException("No package element found for declared type " + getSimpleName(mirror)); + } + return pack.getQualifiedName().toString(); + case ARRAY: + return getSimpleName(((ArrayType) mirror).getComponentType()); + default: + throw new RuntimeException("Unknown type specified " + mirror.getKind()); + } + } + + public static String createConstantName(String simpleName) { + //TODO use camel case to produce underscores. + return simpleName.toString().toUpperCase(); + } + + public static TypeElement fromTypeMirror(TypeMirror mirror) { + switch (mirror.getKind()) { + case DECLARED: + return (TypeElement) ((DeclaredType) mirror).asElement(); + case ARRAY: + return fromTypeMirror(((ArrayType) mirror).getComponentType()); + default: + return null; + } + } + + @SuppressWarnings("unchecked") + public static List getAnnotationValueList(AnnotationMirror mirror, String name) { + List result = new ArrayList<>(); + List< ? extends AnnotationValue> values = (List< ? extends AnnotationValue>) getAnnotationValue(mirror, name).getValue(); + for (AnnotationValue value : values) { + result.add((T) value.getValue()); + } + return result; + } + + public static TypeMirror getAnnotationValueType(AnnotationMirror mirror, String name) { + return (TypeMirror) getAnnotationValue(mirror, name).getValue(); + } + + public static TypeMirror getAnnotationValueTypeMirror(AnnotationMirror mirror, String name) { + return (TypeMirror) getAnnotationValue(mirror, name).getValue(); + } + + public static String getAnnotationValueString(AnnotationMirror mirror, String name) { + return (String) getAnnotationValue(mirror, name).getValue(); + } + + public static int getAnnotationValueInt(AnnotationMirror mirror, String name) { + return (int) getAnnotationValue(mirror, name).getValue(); + } + + public static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) { + ExecutableElement valueMethod = null; + for (ExecutableElement method : ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) { + if (method.getSimpleName().toString().equals(name)) { + valueMethod = method; + break; + } + } + + if (valueMethod == null) { + return null; + } + + AnnotationValue value = mirror.getElementValues().get(valueMethod); + if (value == null) { + value = valueMethod.getDefaultValue(); + } + return value; + } + + public static boolean getAnnotationValueBoolean(AnnotationMirror mirror, String name) { + return (Boolean) getAnnotationValue(mirror, name).getValue(); + } + + public static String printException(Throwable e) { + StringWriter string = new StringWriter(); + PrintWriter writer = new PrintWriter(string); + e.printStackTrace(writer); + writer.flush(); + return e.getMessage() + "\r\n" + string.toString(); + } + + public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, Element element, Class< ? > annotationClass) { + return findAnnotationMirror(processingEnv, element.getAnnotationMirrors(), annotationClass); + } + + public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, List< ? extends AnnotationMirror> mirrors, Class< ? > annotationClass) { + TypeElement expectedAnnotationType = processingEnv.getElementUtils().getTypeElement(annotationClass.getName()); + for (AnnotationMirror mirror : mirrors) { + DeclaredType annotationType = mirror.getAnnotationType(); + TypeElement actualAnnotationType = (TypeElement) annotationType.asElement(); + if (actualAnnotationType.equals(expectedAnnotationType)) { + return mirror; + } + } + return null; + } + + private static PackageElement findPackageElement(Element type) { + Element searchType = type; + while (searchType.getEnclosingElement() != null && searchType.getEnclosingElement().getKind() != ElementKind.PACKAGE) { + searchType = type.getEnclosingElement(); + } + return (PackageElement) searchType.getEnclosingElement(); + } + + public static String firstLetterUpperCase(String name) { + if (name == null || name.isEmpty()) { + return name; + } + return Character.toUpperCase(name.charAt(0)) + name.substring(1, name.length()); + } + + public static String firstLetterLowerCase(String name) { + if (name == null || name.isEmpty()) { + return name; + } + return Character.toLowerCase(name.charAt(0)) + name.substring(1, name.length()); + } + + private static ExecutableElement getDeclaredMethod(TypeElement element, String name, TypeMirror[] params) { + List methods = ElementFilter.methodsIn(element.getEnclosedElements()); + method: for (ExecutableElement method : methods) { + if (!method.getSimpleName().toString().equals(name)) { + continue; + } + if (method.getParameters().size() != params.length) { + continue; + } + for (int i = 0; i < params.length; i++) { + TypeMirror param1 = params[i]; + TypeMirror param2 = method.getParameters().get(i).asType(); + if (!getQualifiedName(param1).equals(getQualifiedName(param2))) { + continue method; + } + } + return method; + } + return null; + } + + private static boolean isDeclaredMethod(TypeElement element, String name, TypeMirror[] params) { + return getDeclaredMethod(element, name, params) != null; + } + + public static boolean isDeclaredMethodInSuperType(TypeElement element, String name, TypeMirror[] params) { + List superElements = getSuperTypes(element); + + for (TypeElement typeElement : superElements) { + if (isDeclaredMethod(typeElement, name, params)) { + return true; + } + } + return false; + } + + private static ExecutableElement getDeclaredMethodInSuperType(TypeElement element, String name, TypeMirror[] params) { + List superElements = getSuperTypes(element); + + for (TypeElement typeElement : superElements) { + ExecutableElement declared = getDeclaredMethod(typeElement, name, params); + if (declared != null) { + return declared; + } + } + return null; + } + + public static ExecutableElement getDeclaredMethodRecursive(TypeElement element, String name, TypeMirror[] params) { + ExecutableElement declared = getDeclaredMethod(element, name, params); + if (declared != null) { + return declared; + } + return getDeclaredMethodInSuperType(element, name, params); + } + + public static boolean typeEquals(TypeMirror type1, TypeMirror type2) { + if (type1 == null && type2 == null) { + return true; + } else if (type1 == null || type2 == null) { + return false; + } + String qualified1 = getQualifiedName(type1); + String qualified2 = getQualifiedName(type2); + return qualified1.equals(qualified2); + } + + + public static int compareByTypeHierarchy(TypeMirror t1, TypeMirror t2) { + if (typeEquals(t1, t2)) { + return 0; + } + Set t1SuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(t1))); + if (t1SuperSet.contains(getQualifiedName(t2))) { + return -1; + } + + Set t2SuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(t2))); + if (t2SuperSet.contains(getQualifiedName(t1))) { + return 1; + } + return 0; + } + + + public static boolean canThrowType(List thrownTypes, TypeMirror exceptionType) { + if (Utils.containsType(thrownTypes, exceptionType)) { + return true; + } + + if (isRuntimeException(exceptionType)) { + return true; + } + + // search for any supertypes + TypeElement exceptionTypeElement = fromTypeMirror(exceptionType); + List superTypes = getSuperTypes(exceptionTypeElement); + for (TypeElement typeElement : superTypes) { + if (Utils.containsType(thrownTypes, typeElement.asType())) { + return true; + } + } + + return false; + } + + private static boolean isRuntimeException(TypeMirror type) { + Set typeSuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(type))); + String typeName = getQualifiedName(type); + if (!typeSuperSet.contains(Throwable.class.getCanonicalName()) && !typeName.equals(Throwable.class.getCanonicalName())) { + throw new IllegalArgumentException("Given does not extend Throwable."); + } + return typeSuperSet.contains(RuntimeException.class.getCanonicalName()) || typeName.equals(RuntimeException.class.getCanonicalName()); + } + + private static boolean containsType(Collection collection, TypeMirror type) { + for (TypeMirror otherTypeMirror : collection) { + if (typeEquals(otherTypeMirror, type)) { + return true; + } + } + return false; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/ExtensionContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/ExtensionContext.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.api; + +import javax.annotation.processing.*; + +import com.oracle.truffle.codegen.processor.api.element.*; + + +public interface ExtensionContext { + + ProcessingEnvironment getProcessingEnvironment(); + + RoundEnvironment getRoundEnvironment(); + + WritableElementFactory getElementFactory(); + + void addGeneratedElement(WritableElement element); + + void removeGeneratedElement(WritableElement element); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/ExtensionProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/ExtensionProcessor.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.api; + +import javax.lang.model.element.*; + + +public interface ExtensionProcessor { + + void process(ExtensionContext context, AnnotationMirror mirror, Element element); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableAnnotationMirror.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableAnnotationMirror.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.api.element; + +import javax.lang.model.element.*; + +public interface WritableAnnotationMirror extends AnnotationMirror { + + void setElementValue(ExecutableElement valueName, AnnotationValue value); + + AnnotationValue getElementValue(ExecutableElement valueName); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableElement.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.api.element; + +import javax.lang.model.element.*; + + +public interface WritableElement extends Element { + + void addAnnotationMirror(AnnotationMirror annotationMirror); + + void removeAnnotationMirror(AnnotationMirror annotationMirror); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableElementFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableElementFactory.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.api.element; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + + +public interface WritableElementFactory { + + WritableExecutableElement cloneExecutableElement(ExecutableElement method); + WritableVariableElement cloneVariableElement(VariableElement parameter); + WritableAnnotationMirror cloneAnnotationMirror(AnnotationMirror mirror); + + WritableVariableElement createParameter(TypeMirror type, String simpleName); + WritableExecutableElement createExecutableElement(TypeMirror returnType, String methodName); + WritableAnnotationMirror createAnnotationMirror(DeclaredType annotationClass); + + Name createName(String name); + AnnotationValue createAnnotationValue(Object value); + TypeMirror createTypeMirror(Class javaClass); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableExecutableElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableExecutableElement.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.api.element; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public interface WritableExecutableElement extends ExecutableElement, WritableElement { + + void setReturnType(TypeMirror type); + void setDefaultValue(AnnotationValue defaultValue); + + void addParameter(VariableElement parameter); + void removeParamter(VariableElement parameter); + + void addThrownType(TypeMirror thrownType); + void removeThrownType(TypeMirror thrownType); + + void setSimpleName(Name name); + void setVarArgs(boolean varargs); + + void setBody(String body); + String getBody(); +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableVariableElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableVariableElement.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.api.element; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public interface WritableVariableElement extends VariableElement, WritableElement { + + void setSimpleName(Name name); + void setType(TypeMirror type); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeAnnotationMirror.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeAnnotationMirror.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.codegen.processor.api.element.*; + +public class CodeAnnotationMirror implements WritableAnnotationMirror { + + private final DeclaredType annotationType; + private final Map values = new LinkedHashMap<>(); + + public CodeAnnotationMirror(DeclaredType annotationType) { + this.annotationType = annotationType; + } + + @Override + public DeclaredType getAnnotationType() { + return annotationType; + } + + @Override + public Map< ? extends ExecutableElement, ? extends AnnotationValue> getElementValues() { + return values; + } + + @Override + public AnnotationValue getElementValue(ExecutableElement method) { + return values.get(method); + } + + @Override + public void setElementValue(ExecutableElement method, AnnotationValue value) { + values.put(method, value); + } + + public ExecutableElement findExecutableElement(String name) { + List elements = ElementFilter.methodsIn(annotationType.asElement().getEnclosedElements()); + for (ExecutableElement executableElement : elements) { + if (executableElement.getSimpleName().toString().equals(name)) { + return executableElement; + } + } + return null; + } + + public static CodeAnnotationMirror clone(AnnotationMirror mirror) { + CodeAnnotationMirror copy = new CodeAnnotationMirror(mirror.getAnnotationType()); + for (ExecutableElement key : mirror.getElementValues().keySet()) { + copy.setElementValue(key, mirror.getElementValues().get(key)); + } + return copy; + } + + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeAnnotationValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeAnnotationValue.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class CodeAnnotationValue implements AnnotationValue { + + private final Object value; + + public CodeAnnotationValue(Object value) { + Objects.requireNonNull(value); + if ((value instanceof AnnotationMirror) || (value instanceof List< ? >) + || (value instanceof Boolean) || (value instanceof Byte) + || (value instanceof Character) || (value instanceof Double) + || (value instanceof VariableElement) || (value instanceof Float) + || (value instanceof Integer) || (value instanceof Long) + || (value instanceof Short) || (value instanceof String) + || (value instanceof TypeMirror)) { + this.value = value; + } else { + throw new IllegalArgumentException("Invalid annotation value type " + value.getClass().getName()); + } + } + + @Override + public Object getValue() { + return value; + } + + @SuppressWarnings("unchecked") + @Override + public R accept(AnnotationValueVisitor v, P p) { + if (value instanceof AnnotationMirror) { + return v.visitAnnotation((AnnotationMirror) value, p); + } else if (value instanceof List< ? >) { + return v.visitArray((List< ? extends AnnotationValue>) value, p); + } else if (value instanceof Boolean) { + return v.visitBoolean((boolean) value, p); + } else if (value instanceof Byte) { + return v.visitByte((byte) value, p); + } else if (value instanceof Character) { + return v.visitChar((char) value, p); + } else if (value instanceof Double) { + return v.visitDouble((double) value, p); + } else if (value instanceof VariableElement) { + return v.visitEnumConstant((VariableElement) value, p); + } else if (value instanceof Float) { + return v.visitFloat((float) value, p); + } else if (value instanceof Integer) { + return v.visitInt((int) value, p); + } else if (value instanceof Long) { + return v.visitLong((long) value, p); + } else if (value instanceof Short) { + return v.visitShort((short) value, p); + } else if (value instanceof String) { + return v.visitString((String) value, p); + } else if (value instanceof TypeMirror) { + return v.visitType((TypeMirror) value, p); + } else { + return v.visitUnknown(this, p); + } + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeCompilationUnit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeCompilationUnit.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class CodeCompilationUnit extends CodeElement { + + public CodeCompilationUnit() { + super(Collections. emptySet()); + } + + @Override + public TypeMirror asType() { + throw new UnsupportedOperationException(); + } + + @Override + public ElementKind getKind() { + return ElementKind.OTHER; + } + + @Override + public Name getSimpleName() { + throw new UnsupportedOperationException(); + } + + @Override + public R accept(ElementVisitor v, P p) { + for (TypeElement type : getEnclosedElements()) { + type.accept(v, p); + } + return null; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeElement.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import java.io.*; +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.codegen.processor.api.element.*; +import com.oracle.truffle.codegen.processor.codewriter.*; + +public abstract class CodeElement implements WritableElement, GeneratedElement { + + private final Set modifiers; + private List annotations; + private List enclosedElements; + + private Element enclosingElement; + + private Element generatorElement; + private AnnotationMirror generatorAnnotationMirror; + + public CodeElement() { + this.modifiers = new LinkedHashSet<>(); + } + + + @Override + public void setGeneratorAnnotationMirror(AnnotationMirror mirror) { + this.generatorAnnotationMirror = mirror; + } + + @Override + public void setGeneratorElement(Element element) { + this.generatorElement = element; + } + + @Override + public AnnotationMirror getGeneratorAnnotationMirror() { + return generatorAnnotationMirror; + } + + @Override + public Element getGeneratorElement() { + return generatorElement; + } + + public CodeElement(Set modifiers) { + this.modifiers = new LinkedHashSet<>(modifiers); + } + + public E add(E element) { + if (element == null) { + throw new NullPointerException(); + } + getEnclosedElements().add(element); + return element; + } + + public void remove(E element) { + getEnclosedElements().remove(element); + } + + @Override + public Set getModifiers() { + return modifiers; + } + + @Override + public List getEnclosedElements() { + if (enclosedElements == null) { + enclosedElements = parentableList(this, new ArrayList()); + } + return enclosedElements; + } + + @Override + public List getAnnotationMirrors() { + if (annotations == null) { + annotations = parentableList(this, new ArrayList()); + } + return annotations; + } + + @Override + public A getAnnotation(Class annotationType) { + throw new UnsupportedOperationException(); + } + + @Override + public void addAnnotationMirror(AnnotationMirror annotationMirror) { + getAnnotationMirrors().add(annotationMirror); + } + + public void removeAnnotationMirror(AnnotationMirror annotationMirror) { + getAnnotationMirrors().remove(annotationMirror); + } + + void setEnclosingElement(Element parent) { + if (this.enclosingElement != null && parent != null) { + throw new IllegalStateException("Element already added to " + parent); + } + this.enclosingElement = parent; + } + + public Element getEnclosingElement() { + return enclosingElement; + } + + public CodeTypeElement getEnclosingClass() { + Element p = enclosingElement; + while (p != null && p.getKind() != ElementKind.CLASS + && p.getKind() != ElementKind.ENUM) { + p = p.getEnclosingElement(); + } + return (CodeTypeElement) p; + } + + List parentableList(Element parent, List list) { + return new ParentableList<>(parent, list); + } + + + @Override + public String toString() { + StringBuilderCodeWriter codeWriter = new StringBuilderCodeWriter(); + accept(codeWriter, null); + return codeWriter.getString(); + } + + private static class StringBuilderCodeWriter extends AbstractCodeWriter { + + public StringBuilderCodeWriter() { + this.writer = new CharArrayWriter(); + } + + @Override + protected Writer createWriter(CodeTypeElement clazz) throws IOException { + return writer; + } + public String getString() { + return new String(((CharArrayWriter) writer).toCharArray()); + } + + } + + + private static class ParentableList implements List { + + private final Element parent; + private final List delegate; + + public ParentableList(Element parent, List delegate) { + this.parent = parent; + this.delegate = delegate; + } + + private void addImpl(T element) { + if (element != null) { + if (element instanceof CodeElement) { + ((CodeElement) element).setEnclosingElement(parent); + } + } + } + + private static void removeImpl(Object element) { + if (element instanceof CodeElement) { + ((CodeElement) element).setEnclosingElement(null); + } + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return delegate.contains(o); + } + + @Override + public Iterator iterator() { + return delegate.iterator(); + } + + @Override + public Object[] toArray() { + return delegate.toArray(); + } + + @Override + public E[] toArray(E[] a) { + return delegate.toArray(a); + } + + @Override + public boolean add(T e) { + addImpl(e); + return delegate.add(e); + } + + @Override + public boolean remove(Object o) { + boolean removed = delegate.remove(o); + if (removed) { + removeImpl(o); + } + return removed; + } + + @Override + public boolean containsAll(Collection< ? > c) { + return delegate.containsAll(c); + } + + @Override + public boolean addAll(Collection< ? extends T> c) { + if (c != null) { + for (T t : c) { + addImpl(t); + } + } + return delegate.addAll(c); + } + + @Override + public boolean addAll(int index, Collection< ? extends T> c) { + if (c != null) { + for (T t : c) { + addImpl(t); + } + } + return delegate.addAll(index, c); + } + + @Override + public boolean removeAll(Collection< ? > c) { + if (c != null) { + for (Object t : c) { + removeImpl(t); + } + } + return delegate.removeAll(c); + } + + @Override + public String toString() { + return delegate.toString(); + } + + @Override + public boolean retainAll(Collection< ? > c) { + throw new UnsupportedOperationException("Not supported by parentable list"); + } + + @Override + public void clear() { + for (Object e : this) { + removeImpl(e); + } + delegate.clear(); + } + + @Override + public T get(int index) { + return delegate.get(index); + } + + @Override + public T set(int index, T element) { + removeImpl(delegate.get(index)); + addImpl(element); + return delegate.set(index, element); + } + + @Override + public void add(int index, T element) { + addImpl(element); + delegate.add(index, element); + } + + @Override + public T remove(int index) { + T element = delegate.remove(index); + removeImpl(element); + return element; + } + + @Override + public int indexOf(Object o) { + return delegate.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return delegate.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return delegate.listIterator(); + } + + @Override + public ListIterator listIterator(int index) { + return delegate.listIterator(index); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return new ParentableList<>(parent, delegate.subList(fromIndex, toIndex)); + } + + } + + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeElementScanner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeElementScanner.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import javax.lang.model.element.*; +import javax.lang.model.util.*; + +public abstract class CodeElementScanner extends ElementScanner7{ + + @Override + public final R visitExecutable(ExecutableElement e, P p) { + return visitExecutable(cast(e, CodeExecutableElement.class), p); + } + + public R visitExecutable(CodeExecutableElement e, P p) { + R ret = super.visitExecutable(e, p); + if (e.getBodyTree() != null) { + visitTree(e.getBodyTree(), p); + } + return ret; + } + + @Override + public R visitPackage(PackageElement e, P p) { + return super.visitPackage(e, p); + } + + @Override + public final R visitType(TypeElement e, P p) { + return visitType(cast(e, CodeTypeElement.class), p); + } + + public R visitType(CodeTypeElement e, P p) { + return super.visitType(e, p); + } + + @Override + public R visitTypeParameter(TypeParameterElement e, P p) { + return super.visitTypeParameter(e, p); + } + + private static E cast(Element element, Class clazz) { + return clazz.cast(element); + } + + public void visitTree(CodeTree e, P p) { + for (CodeTree tree : e.getEnclosedElements()) { + tree.acceptCodeElementScanner(this, p); + } + } + + @SuppressWarnings("unused") + public void visitImport(CodeImport e, P p) { + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.api.element.*; + +public class CodeExecutableElement extends CodeElement implements WritableExecutableElement { + + private final List throwables = new ArrayList<>(); + private final List parameters = parentableList(this, new ArrayList()); + + private TypeMirror returnType; + private Name name; + + private CodeTree bodyTree; + private String body; + private AnnotationValue defaultValue; + private boolean varArgs; + + public CodeExecutableElement(TypeMirror returnType, String name) { + super(Utils.modifiers()); + this.returnType = returnType; + this.name = CodeNames.of(name); + } + + public CodeExecutableElement(Set modifiers, TypeMirror returnType, String name, CodeVariableElement... parameters) { + super(modifiers); + this.returnType = returnType; + this.name = CodeNames.of(name); + for (CodeVariableElement codeParameter : parameters) { + addParameter(codeParameter); + } + } + + @Override + public List getThrownTypes() { + return throwables; + } + + @Override + public TypeMirror asType() { + return returnType; + } + + @Override + public ElementKind getKind() { + return ElementKind.METHOD; + } + + @Override + public List< ? extends TypeParameterElement> getTypeParameters() { + return Collections.emptyList(); + } + + @Override + public void setVarArgs(boolean varargs) { + this.varArgs = varargs; + } + + @Override + public boolean isVarArgs() { + return varArgs; + } + + @Override + public void setDefaultValue(AnnotationValue defaultValue) { + this.defaultValue = defaultValue; + } + + @Override + public AnnotationValue getDefaultValue() { + return defaultValue; + } + + @Override + public Name getSimpleName() { + return name; + } + + public CodeTreeBuilder createBuilder() { + CodeTreeBuilder builder = new CodeTreeBuilder(); + this.bodyTree = builder.getTree(); + this.bodyTree.setEnclosingElement(this); + return builder; + } + + public void setBodyTree(CodeTree body) { + this.bodyTree = body; + } + + public CodeTree getBodyTree() { + return bodyTree; + } + + public TypeMirror getReturnType() { + return returnType; + } + + @Override + public List getParameters() { + return parameters; + } + + public TypeMirror[] getParameterTypes() { + TypeMirror[] types = new TypeMirror[getParameters().size()]; + for (int i = 0; i < types.length; i++) { + types[i] = parameters.get(i).asType(); + } + return types; + } + + @Override + public void setReturnType(TypeMirror type) { + returnType = type; + } + + @Override + public void addParameter(VariableElement parameter) { + parameters.add(parameter); + } + + @Override + public void removeParamter(VariableElement parameter) { + parameters.remove(parameter); + } + + @Override + public void addThrownType(TypeMirror thrownType) { + throwables.add(thrownType); + } + + @Override + public void removeThrownType(TypeMirror thrownType) { + throwables.remove(thrownType); + } + + @Override + public void setSimpleName(Name name) { + this.name = name; + } + + @Override + public void setBody(String body) { + this.body = body; + } + + @Override + public String getBody() { + return body; + } + + @Override + public R accept(ElementVisitor v, P p) { + return v.visitExecutable(this, p); + } + + + public static CodeExecutableElement clone(ProcessingEnvironment env, ExecutableElement method) { + CodeExecutableElement copy = new CodeExecutableElement(method.getReturnType(), method.getSimpleName().toString()); + for (TypeMirror thrownType : method.getThrownTypes()) { + copy.addThrownType(thrownType); + } + copy.setDefaultValue(method.getDefaultValue()); + + for (AnnotationMirror mirror : method.getAnnotationMirrors()) { + copy.addAnnotationMirror(mirror); + } + for (VariableElement var : method.getParameters()) { + copy.addParameter(var); + } + for (Element element : method.getEnclosedElements()) { + copy.add(element); + } + copy.setBody(Utils.getMethodBody(env, method)); + copy.getModifiers().addAll(method.getModifiers()); + return copy; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeImport.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeImport.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import javax.lang.model.type.*; + +public class CodeImport implements Comparable { + + private final TypeMirror importType; + private final String importString; + private final boolean staticImport; + + public CodeImport(TypeMirror importedType, String importString, boolean staticImport) { + this.importType = importedType; + this.importString = importString; + this.staticImport = staticImport; + } + + public TypeMirror getImportType() { + return importType; + } + + public boolean isStaticImport() { + return staticImport; + } + + public String getImportString() { + return importString; + } + + @Override + public int compareTo(CodeImport o) { + if (staticImport && !o.staticImport) { + return 1; + } else if (!staticImport && o.staticImport) { + return -1; + } else { + return importString.compareTo(o.getImportString()); + } + } + + public

void accept(CodeElementScanner s, P p) { + s.visitImport(this, p); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((importString == null) ? 0 : importString.hashCode()); + result = prime * result + (staticImport ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + CodeImport other = (CodeImport) obj; + if (importString == null) { + if (other.importString != null) { + return false; + } + } else if (!importString.equals(other.importString)) { + return false; + } + if (staticImport != other.staticImport) { + return false; + } + return true; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeNames.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeNames.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import java.util.*; + +import javax.lang.model.element.*; + +public abstract class CodeNames { + + private static Map names = new HashMap<>(); + + public static Name of(String value) { + Name name = names.get(value); + if (name == null) { + name = new NameImpl(value); + names.put(value, name); + } + return name; + } + + private static class NameImpl implements Name { + + private final String name; + + public NameImpl(String name) { + this.name = name; + } + + @Override + public int length() { + return name.length(); + } + + @Override + public char charAt(int index) { + return name.charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) { + return name.subSequence(start, end); + } + + @Override + public boolean contentEquals(CharSequence cs) { + return name.contentEquals(cs); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Name) { + return ((Name) obj).contentEquals(name); + } + return super.equals(obj); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + return name; + } + + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTree.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class CodeTree extends CodeElement { + + private final CodeTreeKind kind; + + private final TypeMirror type; + private final String string; + + public CodeTree(CodeTreeKind kind, TypeMirror type, String string) { + this.kind = kind; + this.type = type; + this.string = string; + } + + public TypeMirror getType() { + return type; + } + + public CodeTreeKind getCodeKind() { + return kind; + } + + public String getString() { + return string; + } + + public

void acceptCodeElementScanner(CodeElementScanner s, P p) { + s.visitTree(this, p); + } + + @Override + public TypeMirror asType() { + return type; + } + + @Override + public ElementKind getKind() { + return ElementKind.OTHER; + } + + @Override + public Name getSimpleName() { + return CodeNames.of(getString()); + } + + @Override + public R accept(ElementVisitor v, P p) { + if (v instanceof CodeElementScanner) { + acceptCodeElementScanner((CodeElementScanner) v, p); + return null; + } else { + throw new UnsupportedOperationException(); + } + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,705 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import static com.oracle.truffle.codegen.processor.ast.CodeTreeKind.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; + +public class CodeTreeBuilder { + + private BuilderCodeTree currentElement; + private final BuilderCodeTree root; + + public CodeTreeBuilder() { + this.root = new BuilderCodeTree(GROUP, null, null); + this.currentElement = root; + } + + public CodeTreeBuilder(CodeTree tree) { + this.root = (BuilderCodeTree) tree; + this.currentElement = root; + } + + public CodeTreeBuilder statement(String statement) { + return startStatement().string(statement).end(); + } + + public CodeTreeBuilder statement(CodeTree statement) { + return startStatement().tree(statement).end(); + } + + public static CodeTreeBuilder createBuilder() { + return new CodeTreeBuilder(); + } + + public static CodeTree singleString(String s) { + return new CodeTreeBuilder().string(s).getTree(); + } + + private CodeTreeBuilder push(CodeTreeKind kind) { + return push(new BuilderCodeTree(kind, null, null)); + } + + private CodeTreeBuilder push(String string) { + return push(new BuilderCodeTree(CodeTreeKind.STRING, null, string)); + } + + private CodeTreeBuilder push(TypeMirror type) { + return push(new BuilderCodeTree(CodeTreeKind.TYPE, type, null)); + } + + private CodeTreeBuilder push(CodeTreeKind kind, TypeMirror type, String string) { + return push(new BuilderCodeTree(kind, type, string)); + } + + private CodeTreeBuilder push(BuilderCodeTree tree) { + if (currentElement != null) { + currentElement.add(tree); + } + switch (tree.getCodeKind()) { + case COMMA_GROUP: + case GROUP: + case INDENT: + currentElement = tree; + break; + } + return this; + } + + private void clearLast(CodeTreeKind kind) { + clearLastRec(kind, currentElement.getEnclosedElements()); + } + + public CodeTreeBuilder startStatement() { + startGroup(); + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + string(";").newLine(); + } + + @Override + public void afterEnd() { + } + }); + return this; + } + + public CodeTreeBuilder startGroup() { + return push(CodeTreeKind.GROUP); + } + + public CodeTreeBuilder startCommaGroup() { + return push(CodeTreeKind.COMMA_GROUP); + } + + public CodeTreeBuilder startCall(String callSite) { + return startCall(null, callSite); + } + + public CodeTreeBuilder startCall(String receiver, String callSite) { + if (receiver == null) { + return startGroup().string(callSite).startParanthesesCommaGroup().endAfter(); + } else { + return startGroup().string(receiver).string(".").string(callSite).startParanthesesCommaGroup().endAfter(); + } + } + + public CodeTreeBuilder startStaticCall(TypeMirror type, String methodName) { + return startGroup().push(CodeTreeKind.STATIC_METHOD_REFERENCE, type, methodName).startParanthesesCommaGroup().endAfter(); + } + + public CodeTreeBuilder startStaticCall(ExecutableElement method) { + return startStaticCall(Utils.findEnclosingType(method).asType(), method.getSimpleName().toString()); + } + + public CodeTreeBuilder staticReference(TypeMirror type, String fieldName) { + return push(CodeTreeKind.STATIC_FIELD_REFERENCE, type, fieldName); + } + + private CodeTreeBuilder endAndWhitespaceAfter() { + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + } + + @Override + public void afterEnd() { + string(" "); + end(); + } + }); + return this; + } + + private CodeTreeBuilder endAfter() { + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + } + + @Override + public void afterEnd() { + end(); + } + }); + return this; + } + + private CodeTreeBuilder startParanthesesCommaGroup() { + startGroup(); + string("(").startCommaGroup(); + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + } + + @Override + public void afterEnd() { + string(")"); + } + }); + endAfter(); + return this; + } + + public CodeTreeBuilder startParantheses() { + startGroup(); + string("(").startGroup(); + registerCallBack(new EndCallback() { + @Override + public void beforeEnd() { + } + @Override + public void afterEnd() { + string(")"); + } + }); + endAfter(); + return this; + } + + public CodeTreeBuilder startDoubleQuote() { + startGroup().string("\""); + registerCallBack(new EndCallback() { + @Override + public void beforeEnd() { + } + @Override + public void afterEnd() { + string("\""); + } + }); + return this; + } + + public CodeTreeBuilder string(String chunk1) { + return push(chunk1); + } + + public CodeTreeBuilder string(String chunk1, String chunk2) { + return push(GROUP).string(chunk1).string(chunk2).end(); + } + + public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3) { + return push(GROUP).string(chunk1).string(chunk2).string(chunk3).end(); + } + + public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3, String chunk4) { + return push(GROUP).string(chunk1).string(chunk2).string(chunk3).string(chunk4).end(); + } + + public CodeTreeBuilder tree(CodeTree treeToAdd) { + return push((BuilderCodeTree) treeToAdd).end(); + } + + public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3, String chunk4, String... chunks) { + push(GROUP).string(chunk1).string(chunk2).string(chunk3).string(chunk4); + for (int i = 0; i < chunks.length; i++) { + string(chunks[i]); + } + return end(); + } + + public CodeTreeBuilder dot() { + return string("."); + } + + public CodeTreeBuilder newLine() { + return push(NEW_LINE); + } + + public CodeTreeBuilder startWhile() { + return startGroup().string("while ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); + } + + public CodeTreeBuilder startIf() { + return startGroup().string("if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); + } + + public CodeTreeBuilder startElseIf() { + clearLast(CodeTreeKind.NEW_LINE); + return startGroup().string(" else if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); + } + + public CodeTreeBuilder startElseBlock() { + clearLast(CodeTreeKind.NEW_LINE); + return startGroup().string(" else ").startBlock().endAfter(); + } + + private boolean clearLastRec(CodeTreeKind kind, List children) { + for (int i = children.size() - 1; i >= 0; i--) { + CodeTree child = children.get(i); + if (child.getCodeKind() == kind) { + children.remove(children.get(i)); + return true; + } else { + if (clearLastRec(kind, child.getEnclosedElements())) { + return true; + } + } + } + return false; + } + + public CodeTreeBuilder startCase() { + startGroup().string("case "); + registerCallBack(new EndCallback() { + @Override + public void beforeEnd() { + string(" :").newLine(); + } + @Override + public void afterEnd() { + } + }); + return this; + } + + public CodeTreeBuilder caseDefault() { + return startGroup().string("default :").newLine().end(); + } + + public CodeTreeBuilder startSwitch() { + return startGroup().string("switch ").startParanthesesCommaGroup().endAndWhitespaceAfter(); + } + + public CodeTreeBuilder startReturn() { + ExecutableElement method = findMethod(); + if (method != null && Utils.isVoid(method.getReturnType())) { + startStatement(); + return this; + } else { + return startStatement().string("return "); + } + } + + public CodeTreeBuilder startAssert() { + return startStatement().string("assert "); + } + + public CodeTreeBuilder startNew(TypeMirror uninializedNodeClass) { + return startGroup().string("new ").type(uninializedNodeClass).startParanthesesCommaGroup().endAfter(); + } + + public CodeTreeBuilder startNew(String typeName) { + return startGroup().string("new ").string(typeName).startParanthesesCommaGroup().endAfter(); + } + + public CodeTreeBuilder startIndention() { + return push(CodeTreeKind.INDENT); + } + + public CodeTreeBuilder end() { + BuilderCodeTree tree = currentElement; + EndCallback callback = tree.getAtEndListener(); + if (callback != null) { + callback.beforeEnd(); + toParent(); + callback.afterEnd(); + } else { + toParent(); + } + return this; + } + + private void toParent() { + Element parent = currentElement.getEnclosingElement(); + if (currentElement != root) { + this.currentElement = (BuilderCodeTree) parent; + } else { + this.currentElement = root; + } + } + + public CodeTreeBuilder startBlock() { + startGroup(); + string("{").newLine().startIndention(); + registerCallBack(new EndCallback() { + @Override + public void beforeEnd() { + } + @Override + public void afterEnd() { + string("}").newLine(); + } + }); + endAfter(); + return this; + } + + private void registerCallBack(EndCallback callback) { + currentElement.registerAtEnd(callback); + } + + public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTree init) { + if (Utils.isVoid(type)) { + startStatement(); + tree(init); + end(); + } else { + startStatement(); + type(type); + string(" "); + string(name); + if (init != null) { + string(" = "); + tree(init); + } + end(); // statement + } + return this; + } + + public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTreeBuilder init) { + if (init == this) { + throw new IllegalArgumentException("Recursive builder usage."); + } + return declaration(type, name, init.getTree()); + } + + public CodeTreeBuilder declaration(TypeMirror type, String name) { + return declaration(type, name, (CodeTree) null); + } + + public CodeTreeBuilder create() { + return new CodeTreeBuilder(); + } + + public CodeTreeBuilder type(TypeMirror type) { + return push(type); + } + + public CodeTreeBuilder typeLiteral(TypeMirror type) { + return startGroup().type(type).string(".class").end(); + } + + private void assertRoot() { + if (currentElement != root) { + throw new IllegalStateException("CodeTreeBuilder was not ended properly."); + } + } + + public CodeTreeBuilder startCaseBlock() { + return startIndention(); + } + + public CodeTreeBuilder startThrow() { + return startStatement().string("throw "); + } + + public CodeTree getTree() { + assertRoot(); + return root; + } + + public CodeTree getRoot() { + return root; + } + + public CodeTreeBuilder cast(TypeMirror type, CodeTree content) { + if (Utils.isVoid(type)) { + tree(content); + return this; + } else if (Utils.getQualifiedName(type).equals("java.lang.Object")) { + tree(content); + return this; + } else { + return startGroup().string("(").type(type).string(")").string(" ").tree(content).end(); + } + } + + public CodeTreeBuilder startSuperCall() { + return string("super").startParanthesesCommaGroup(); + } + + public CodeTreeBuilder returnFalse() { + return startReturn().string("false").end(); + } + + public CodeTreeBuilder returnStatement() { + return statement("return"); + } + + private ExecutableElement findMethod() { + Element element = currentElement; + while (element != null && (element.getKind() != ElementKind.METHOD)) { + element = element.getEnclosingElement(); + } + return element != null ? (ExecutableElement) element : null; + } + + public CodeTreeBuilder returnTrue() { + return startReturn().string("true").end(); + } + + public CodeTreeBuilder instanceOf(String var, TypeMirror type) { + string(var); + TypeElement element = Utils.fromTypeMirror(type); + if (element == null) { + throw new IllegalArgumentException("Cannot call instanceof for a non supported type: " + type.getKind()); + } + + string(" instanceof ").type(type); + return this; + } + + public CodeTreeBuilder defaultValue(TypeMirror mirror) { + switch (mirror.getKind()) { + case VOID: + return string(""); + case ARRAY: + case DECLARED: + case PACKAGE: + case NULL: + return string("null"); + case BOOLEAN: + return string("false"); + case BYTE: + return string("(byte) 0"); + case CHAR: + return string("(char) 0"); + case DOUBLE: + return string("0.0D"); + case LONG: + return string("0L"); + case INT: + return string("0"); + case FLOAT: + return string("0.0F"); + case SHORT: + return string("(short) 0"); + default: + throw new AssertionError(); + } + } + + public CodeTreeBuilder assertFalse() { + return startAssert().string("false").end(); + } + + public CodeTreeBuilder breakStatement() { + return statement("break"); + } + + public CodeTreeBuilder isNull() { + return string(" == null"); + } + + public CodeTreeBuilder isNotNull() { + return string(" != null"); + } + + public CodeTreeBuilder is(CodeTree tree) { + return string(" == ").tree(tree); + } + + public CodeTreeBuilder startTryBlock() { + return string("try ").startBlock(); + } + + public CodeTreeBuilder startCatchBlock(TypeMirror exceptionType, String localVarName) { + clearLast(CodeTreeKind.NEW_LINE); + string(" catch (").type(exceptionType).string(" ").string(localVarName).string(") "); + return startBlock(); + } + + public CodeTreeBuilder startFinallyBlock() { + clearLast(CodeTreeKind.NEW_LINE); + string(" finally "); + return startBlock(); + } + + public CodeTreeBuilder null_() { + return string("null"); + } + + private static class BuilderCodeTree extends CodeTree { + + private EndCallback atEndListener; + + public BuilderCodeTree(CodeTreeKind kind, TypeMirror type, String string) { + super(kind, type, string); + } + + public void registerAtEnd(EndCallback atEnd) { + if (this.atEndListener != null) { + this.atEndListener = new CompoundCallback(this.atEndListener, atEnd); + } else { + this.atEndListener = atEnd; + } + } + + public EndCallback getAtEndListener() { + return atEndListener; + } + + @Override + public String toString() { + final StringBuilder b = new StringBuilder(); + acceptCodeElementScanner(new Printer(b), null); + return b.toString(); + } + + private static class CompoundCallback implements EndCallback { + + private final EndCallback callback1; + private final EndCallback callback2; + + public CompoundCallback(EndCallback callback1, EndCallback callback2) { + this.callback1 = callback1; + this.callback2 = callback2; + } + + @Override + public void afterEnd() { + callback1.afterEnd(); + callback2.afterEnd(); + } + + @Override + public void beforeEnd() { + callback1.beforeEnd(); + callback1.beforeEnd(); + } + } + + } + + private interface EndCallback { + + void beforeEnd(); + + void afterEnd(); + } + + private static class Printer extends CodeElementScanner { + + private int indent; + private boolean newLine; + private final String ln = "\n"; + + private final StringBuilder b; + + Printer(StringBuilder b) { + this.b = b; + } + + @Override + public void visitTree(CodeTree e, Void p) { + switch (e.getCodeKind()) { + case COMMA_GROUP: + List children = e.getEnclosedElements(); + for (int i = 0; i < children.size(); i++) { + children.get(i).acceptCodeElementScanner(this, p); + if (i < e.getEnclosedElements().size() - 1) { + b.append(", "); + } + } + break; + case GROUP: + super.visitTree(e, p); + break; + case INDENT: + indent(); + super.visitTree(e, p); + dedent(); + break; + case NEW_LINE: + writeLn(); + break; + case STRING: + if (e.getString() != null) { + write(e.getString()); + } else { + write("null"); + } + break; + case TYPE: + write(Utils.getSimpleName(e.getType())); + break; + default: + assert false; + return; + } + } + + private void indent() { + indent++; + } + + private void dedent() { + indent--; + } + + private void writeLn() { + write(ln); + newLine = true; + } + + private void write(String m) { + if (newLine && m != ln) { + writeIndent(); + newLine = false; + } + b.append(m); + } + + private void writeIndent() { + for (int i = 0; i < indent; i++) { + b.append(" "); + } + } + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeKind.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeKind.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +public enum CodeTreeKind { + STATIC_FIELD_REFERENCE, STATIC_METHOD_REFERENCE, GROUP, COMMA_GROUP, INDENT, STRING, NEW_LINE, TYPE; +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeElement.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.codegen.processor.ast.CodeTypeMirror.DeclaredCodeTypeMirror; + +public class CodeTypeElement extends CodeElement implements TypeElement { + + private final List imports = parentableList(this, new ArrayList()); + + private final PackageElement packageElement; + + private final Name simpleName; + private final Name packageName; + private Name qualifiedName; + + private final List implementsInterfaces = new ArrayList<>(); + private final ElementKind kind; + private TypeMirror superClass; + + private final DeclaredCodeTypeMirror mirror = new DeclaredCodeTypeMirror(this); + + public CodeTypeElement(Set modifiers, ElementKind kind, PackageElement packageElement, String simpleName) { + super(modifiers); + this.kind = kind; + this.packageElement = packageElement; + this.simpleName = CodeNames.of(simpleName); + if (this.packageElement != null) { + this.packageName = packageElement.getQualifiedName(); + } else { + this.packageName = CodeNames.of("default"); + } + this.qualifiedName = createQualifiedName(); + } + + @Override + public TypeMirror asType() { + return mirror; + } + + @Override + public ElementKind getKind() { + return kind; + } + + public boolean containsField(String name) { + for (VariableElement field : getFields()) { + if (field.getSimpleName().toString().equals(name)) { + return true; + } + } + return false; + } + + @Override + public NestingKind getNestingKind() { + return isTopLevelClass() ? NestingKind.TOP_LEVEL : NestingKind.LOCAL; + } + + @Override + public Element getEnclosingElement() { + if (isTopLevelClass()) { + return packageElement; + } else { + return super.getEnclosingElement(); + } + } + + @Override + public TypeMirror getSuperclass() { + return superClass; + } + + @Override + public List getInterfaces() { + return implementsInterfaces; + } + + @Override + public List< ? extends TypeParameterElement> getTypeParameters() { + return Collections.emptyList(); + } + + public boolean isTopLevelClass() { + return super.getEnclosingElement() instanceof CodeCompilationUnit; + } + + public CodeVariableElement getField(String name) { + for (VariableElement field : ElementFilter.fieldsIn(getEnclosedElements())) { + if (field.getSimpleName().toString().equals(name)) { + return (CodeVariableElement) field; + } + } + return null; + } + + private Name createQualifiedName() { + TypeElement enclosingType = getEnclosingClass(); + if (enclosingType == null) { + return CodeNames.of(packageName + "." + simpleName); + } else { + return CodeNames.of(enclosingType.getQualifiedName() + "." + simpleName); + } + } + + @Override + void setEnclosingElement(Element element) { + super.setEnclosingElement(element); + + // update qualified name on container change + this.qualifiedName = createQualifiedName(); + } + + public Name getPackageName() { + return packageName; + } + + @Override + public Name getQualifiedName() { + return qualifiedName; + } + + @Override + public Name getSimpleName() { + return simpleName; + } + + public void setSuperClass(TypeMirror superType) { + this.superClass = superType; + } + + public List getImports() { + return imports; + } + + public List getImplements() { + return implementsInterfaces; + } + + @Override + public int hashCode() { + return getQualifiedName().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj instanceof TypeElement) { + return getQualifiedName().equals(((TypeElement) obj).getQualifiedName()); + } + return false; + } + + public List getFields() { + return ElementFilter.fieldsIn(getEnclosedElements()); + } + + public List getMethods() { + return ElementFilter.methodsIn(getEnclosedElements()); + } + + public List getInnerClasses() { + return ElementFilter.typesIn(getEnclosedElements()); + } + + @Override + public String toString() { + return getQualifiedName().toString(); + } + + @Override + public R accept(ElementVisitor v, P p) { + return v.visitType(this, p); + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeMirror.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeMirror.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class CodeTypeMirror implements TypeMirror { + + private final TypeKind kind; + + public CodeTypeMirror(TypeKind kind) { + this.kind = kind; + } + + @Override + public TypeKind getKind() { + return kind; + } + + @Override + public R accept(TypeVisitor v, P p) { + throw new UnsupportedOperationException(); + } + + public static class ArrayCodeTypeMirror extends CodeTypeMirror implements ArrayType { + + private final TypeMirror component; + + public ArrayCodeTypeMirror(TypeMirror component) { + super(TypeKind.ARRAY); + this.component = component; + } + + @Override + public TypeMirror getComponentType() { + return component; + } + + } + + public static class DeclaredCodeTypeMirror extends CodeTypeMirror implements DeclaredType { + + private final CodeTypeElement clazz; + + public DeclaredCodeTypeMirror(CodeTypeElement clazz) { + super(TypeKind.DECLARED); + this.clazz = clazz; + } + + @Override + public Element asElement() { + return clazz; + } + + @Override + public TypeMirror getEnclosingType() { + return clazz.getEnclosingElement().asType(); + } + + @Override + public List< ? extends TypeMirror> getTypeArguments() { + return Collections.emptyList(); + } + + @Override + public String toString() { + return clazz.getQualifiedName().toString(); + } + + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeVariableElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeVariableElement.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.api.element.*; + +public final class CodeVariableElement extends CodeElement implements WritableVariableElement { + + private Name name; + private TypeMirror type; + private Object constantValue; + + private CodeTree init; + + public CodeVariableElement(TypeMirror type, String name) { + super(Utils.modifiers()); + this.type = type; + this.name = CodeNames.of(name); + } + + public CodeVariableElement(Set modifiers, TypeMirror type, String name) { + super(modifiers); + this.type = type; + this.name = CodeNames.of(name); + } + + public CodeVariableElement(Set modifiers, TypeMirror type, String name, String init) { + this(modifiers, type, name); + if (init != null) { + this.init = new CodeTree(CodeTreeKind.STRING, null, init); + } + } + + public CodeTreeBuilder createInitBuilder() { + CodeTreeBuilder builder = new CodeTreeBuilder(); + init = builder.getTree(); + init.setEnclosingElement(this); + return builder; + } + + public void setInit(CodeTree init) { + this.init = init; + } + + public CodeTree getInit() { + return init; + } + + public Name getSimpleName() { + return name; + } + + public TypeMirror getType() { + return type; + } + + @Override + public TypeMirror asType() { + return type; + } + + @Override + public ElementKind getKind() { + if (getEnclosingElement() instanceof ExecutableElement) { + return ElementKind.PARAMETER; + } else if (getEnclosingElement() instanceof TypeElement) { + return ElementKind.FIELD; + } else { + return ElementKind.PARAMETER; + } + } + + public void setConstantValue(Object constantValue) { + this.constantValue = constantValue; + } + + @Override + public Object getConstantValue() { + return constantValue; + } + + public String getName() { + return getSimpleName().toString(); + } + + @Override + public void setSimpleName(Name name) { + this.name = name; + } + + public void setName(String name) { + this.name = CodeNames.of(name); + } + + @Override + public void setType(TypeMirror type) { + this.type = type; + } + + @Override + public R accept(ElementVisitor v, P p) { + return v.visitVariable(this, p); + } + + public static CodeVariableElement clone(VariableElement var) { + CodeVariableElement copy = new CodeVariableElement(var.getModifiers(), var.asType(), var.getSimpleName().toString()); + copy.setConstantValue(var.getConstantValue()); + for (AnnotationMirror mirror : var.getAnnotationMirrors()) { + copy.addAnnotationMirror(mirror); + } + for (Element element : var.getEnclosedElements()) { + copy.add(element); + } + return copy; + } + + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/GeneratedElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/GeneratedElement.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ast; + +import javax.lang.model.element.*; + + +public interface GeneratedElement { + + AnnotationMirror getGeneratorAnnotationMirror(); + void setGeneratorAnnotationMirror(AnnotationMirror mirror); + + Element getGeneratorElement(); + void setGeneratorElement(Element element); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,608 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.codewriter; + +import static com.oracle.truffle.codegen.processor.Utils.*; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.ast.*; + +public abstract class AbstractCodeWriter extends CodeElementScanner { + + protected Writer writer; + private int indent; + private boolean newLine; + + private OrganizedImports imports; + + public void visitCompilationUnit(CodeCompilationUnit e) { + for (TypeElement clazz : e.getEnclosedElements()) { + clazz.accept(this, null); + } + } + + protected abstract Writer createWriter(CodeTypeElement clazz) throws IOException; + + @Override + public Void visitType(CodeTypeElement e, Void p) { + if (e.isTopLevelClass()) { + Writer w = null; + try { + imports = OrganizedImports.organize(e); + + w = createWriter(e); + writer = w; + writeRootClass(e); + } catch (IOException ex) { + throw new RuntimeException(ex); + } finally { + if (w != null) { + try { + w.close(); + } catch (Throwable e1) { + // see eclipse bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=361378 + // TODO temporary suppress errors on close. + } + } + writer = null; + } + } else { + writeClassImpl(e); + } + return null; + } + + private void writeRootClass(CodeTypeElement e) { + writeHeader(); + write("package ").write(e.getPackageName()).write(";").writeLn(); + writeEmptyLn(); + + Set generateImports = imports.generateImports(); + List typeImports = new ArrayList<>(); + List staticImports = new ArrayList<>(); + + for (CodeImport codeImport : generateImports) { + if (codeImport.isStaticImport()) { + staticImports.add(codeImport); + } else { + typeImports.add(codeImport); + } + } + Collections.sort(typeImports); + Collections.sort(staticImports); + + for (CodeImport imp : staticImports) { + imp.accept(this, null); + writeLn(); + } + if (!staticImports.isEmpty()) { + writeEmptyLn(); + } + + for (CodeImport imp : typeImports) { + imp.accept(this, null); + writeLn(); + } + if (!typeImports.isEmpty()) { + writeEmptyLn(); + } + + writeClassImpl(e); + } + + private void writeClassImpl(CodeTypeElement e) { + for (AnnotationMirror annotation : e.getAnnotationMirrors()) { + visitAnnotation(annotation); + writeLn(); + } + + writeModifiers(e.getModifiers()); + if (e.getKind() == ElementKind.ENUM) { + write("enum "); + } else { + write("class "); + } + write(e.getSimpleName()); + if (e.getSuperclass() != null && !getQualifiedName(e.getSuperclass()).equals("java.lang.Object")) { + write(" extends ").write(typeSimpleName(e.getSuperclass())); + } + if (e.getImplements().size() > 0) { + write(" implements "); + for (int i = 0; i < e.getImplements().size(); i++) { + write(typeSimpleName(e.getImplements().get(i))); + if (i < e.getImplements().size() - 1) { + write(", "); + } + } + } + + write(" {").writeLn(); + writeEmptyLn(); + indent(); + + List staticFields = getStaticFields(e); + List instanceFields = getInstanceFields(e); + + for (int i = 0; i < staticFields.size(); i++) { + VariableElement field = staticFields.get(i); + field.accept(this, null); + if (e.getKind() == ElementKind.ENUM && i < staticFields.size() - 1) { + write(","); + writeLn(); + } else { + write(";"); + writeLn(); + } + } + + if (staticFields.size() > 0) { + writeEmptyLn(); + } + + for (VariableElement field : instanceFields) { + field.accept(this, null); + write(";"); + writeLn(); + } + if (instanceFields.size() > 0) { + writeEmptyLn(); + } + + for (ExecutableElement method : getInstanceMethods(e)) { + method.accept(this, null); + } + + for (ExecutableElement method : getStaticMethods(e)) { + method.accept(this, null); + } + + for (TypeElement clazz : e.getInnerClasses()) { + clazz.accept(this, null); + } + + dedent(); + write("}"); + writeEmptyLn(); + } + + private static List getStaticFields(CodeTypeElement clazz) { + List staticFields = new ArrayList<>(); + for (VariableElement field : clazz.getFields()) { + if (field.getModifiers().contains(Modifier.STATIC)) { + staticFields.add(field); + } + } + return staticFields; + } + + private static List getInstanceFields(CodeTypeElement clazz) { + List instanceFields = new ArrayList<>(); + for (VariableElement field : clazz.getFields()) { + if (!field.getModifiers().contains(Modifier.STATIC)) { + instanceFields.add(field); + } + } + return instanceFields; + } + + private static List getStaticMethods(CodeTypeElement clazz) { + List staticMethods = new ArrayList<>(); + for (ExecutableElement method : clazz.getMethods()) { + if (method.getModifiers().contains(Modifier.STATIC)) { + staticMethods.add(method); + } + } + return staticMethods; + } + + private static List getInstanceMethods(CodeTypeElement clazz) { + List instanceMethods = new ArrayList<>(); + for (ExecutableElement method : clazz.getMethods()) { + if (!method.getModifiers().contains(Modifier.STATIC)) { + instanceMethods.add(method); + } + } + return instanceMethods; + } + + @Override + public Void visitVariable(VariableElement f, Void p) { + Element parent = f.getEnclosingElement(); + + for (AnnotationMirror annotation : f.getAnnotationMirrors()) { + visitAnnotation(annotation); + writeLn(); + } + + CodeTree init = null; + if (f instanceof CodeVariableElement) { + init = ((CodeVariableElement) f).getInit(); + } + + + if (parent.getKind() == ElementKind.ENUM && f.getModifiers().contains(Modifier.STATIC)) { + write(f.getSimpleName()); + if (init != null) { + if (init != null) { + write("("); + init.acceptCodeElementScanner(this, p); + write(")"); + } + } + } else { + writeModifiers(f.getModifiers()); + write(typeSimpleName(f.asType())); + write(" "); + write(f.getSimpleName()); + if (init != null) { + write(" = "); + init.acceptCodeElementScanner(this, p); + } + } + return null; + } + + public void visitAnnotation(AnnotationMirror e) { + write("@").write(typeSimpleName(e.getAnnotationType())); + + if (!e.getElementValues().isEmpty()) { + write("("); + final ExecutableElement defaultElement = findExecutableElement(e.getAnnotationType(), "value"); + + Map values = e.getElementValues(); + if (defaultElement != null && values.size() == 1 && values.get(defaultElement) != null) { + visitAnnotationValue(values.get(defaultElement)); + } else { + Set methodsSet = values.keySet(); + List methodsList = new ArrayList<>(); + for (ExecutableElement method : methodsSet) { + if (values.get(method) == null) { + continue; + } + methodsList.add(method); + } + + Collections.sort(methodsList, new Comparator() { + @Override + public int compare(ExecutableElement o1, ExecutableElement o2) { + return o1.getSimpleName().toString().compareTo(o2.getSimpleName().toString()); + } + }); + + for (int i = 0; i < methodsList.size(); i++) { + ExecutableElement method = methodsList.get(i); + AnnotationValue value = values.get(method); + write(method.getSimpleName().toString()); + write(" = "); + visitAnnotationValue(value); + + if (i < methodsList.size() - 1) { + write(", "); + } + } + } + + write(")"); + } + } + + public void visitAnnotationValue(AnnotationValue e) { + e.accept(new AnnotationValueWriterVisitor(), null); + } + + private class AnnotationValueWriterVisitor extends AbstractAnnotationValueVisitor7 { + @Override + public Void visitBoolean(boolean b, Void p) { + write(Boolean.toString(b)); + return null; + } + @Override + public Void visitByte(byte b, Void p) { + write(Byte.toString(b)); + return null; + } + @Override + public Void visitChar(char c, Void p) { + write(Character.toString(c)); + return null; + } + @Override + public Void visitDouble(double d, Void p) { + write(Double.toString(d)); + return null; + } + @Override + public Void visitFloat(float f, Void p) { + write(Float.toString(f)); + return null; + } + @Override + public Void visitInt(int i, Void p) { + write(Integer.toString(i)); + return null; + } + @Override + public Void visitLong(long i, Void p) { + write(Long.toString(i)); + return null; + } + @Override + public Void visitShort(short s, Void p) { + write(Short.toString(s)); + return null; + } + @Override + public Void visitString(String s, Void p) { + write("\""); + write(s); + write("\""); + return null; + } + @Override + public Void visitType(TypeMirror t, Void p) { + write(typeSimpleName(t)); + write(".class"); + return null; + } + @Override + public Void visitEnumConstant(VariableElement c, Void p) { + write(typeSimpleName(c.asType())); + write("."); + write(c.getSimpleName().toString()); + return null; + } + @Override + public Void visitAnnotation(AnnotationMirror a, Void p) { + AbstractCodeWriter.this.visitAnnotation(a); + return null; + } + @Override + public Void visitArray(List< ? extends AnnotationValue> vals, Void p) { + write("{"); + for (int i = 0; i < vals.size(); i++) { + AnnotationValue value = vals.get(i); + AbstractCodeWriter.this.visitAnnotationValue(value); + if (i < vals.size() - 1) { + write(", "); + } + } + write("}"); + return null; + } + } + + public ExecutableElement findExecutableElement(DeclaredType type, String name) { + List elements = ElementFilter.methodsIn(type.asElement().getEnclosedElements()); + for (ExecutableElement executableElement : elements) { + if (executableElement.getSimpleName().toString().equals(name)) { + return executableElement; + } + } + return null; + } + + @Override + public void visitImport(CodeImport e, Void p) { + if (e.isStaticImport()) { + write("import static ").write(e.getImportString()).write(";"); + } else { + write("import ").write(e.getImportString()).write(";"); + } + } + +// @Override +// public void visitParameter(CodeVariableElement e) { +// for (CodeAnnotationMirror annotation : e.getAnnotationMirrors()) { +// annotation.accept(this); +// } +// write(typeSimpleName(e.getType())); +// write(" "); +// write(e.getSimpleName()); +// } + + @Override + public Void visitExecutable(CodeExecutableElement e, Void p) { + for (AnnotationMirror annotation : e.getAnnotationMirrors()) { + visitAnnotation(annotation); + writeLn(); + } + + writeModifiers(e.getModifiers()); + + if (e.getReturnType() != null) { + write(typeSimpleName(e.getReturnType())); + write(" "); + } + write(e.getSimpleName()); + write("("); + + for (int i = 0; i < e.getParameters().size(); i++) { + VariableElement param = e.getParameters().get(i); + param.accept(this, p); + if (i < e.getParameters().size() - 1) { + write(", "); + } + } + write(")"); + + List throwables = e.getThrownTypes(); + if (throwables.size() > 0) { + write(" throws "); + for (int i = 0; i < throwables.size(); i++) { + write(typeSimpleName(throwables.get(i))); + if (i < throwables.size() - 1) { + write(", "); + } + } + } + + if (e.getModifiers().contains(Modifier.ABSTRACT)) { + writeLn(";"); + } else if (e.getBodyTree() != null) { + writeLn(" {"); + indent(); + e.getBodyTree().acceptCodeElementScanner(this, p); + dedent(); + writeLn("}"); + } else if (e.getBody() != null) { + write(" {"); + write(e.getBody()); + writeLn("}"); + } else { + writeLn("{ }"); + } + writeEmptyLn(); + return null; + } + + @Override + public void visitTree(CodeTree e, Void p) { + CodeTreeKind kind = e.getCodeKind(); + + switch (kind) { + case COMMA_GROUP: + List children = e.getEnclosedElements(); + for (int i = 0; i < children.size(); i++) { + children.get(i).acceptCodeElementScanner(this, p); + if (i < e.getEnclosedElements().size() - 1) { + write(", "); + } + } + break; + case GROUP: + for (CodeTree tree : e.getEnclosedElements()) { + tree.acceptCodeElementScanner(this, p); + } + break; + case INDENT: + indent(); + for (CodeTree tree : e.getEnclosedElements()) { + tree.acceptCodeElementScanner(this, p); + } + dedent(); + break; + case NEW_LINE: + writeLn(); + break; + case STRING: + if (e.getString() != null) { + write(e.getString()); + } else { + write("null"); + } + break; + case STATIC_FIELD_REFERENCE: + if (e.getString() != null) { + write(imports.useStaticFieldImport(e.getType(), e.getString())); + } else { + write("null"); + } + break; + case STATIC_METHOD_REFERENCE: + if (e.getString() != null) { + write(imports.useStaticMethodImport(e.getType(), e.getString())); + } else { + write("null"); + } + break; + case TYPE: + write(imports.useImport(e.getType())); + break; + default: + assert false; + return; + } + } + + private static String typeSimpleName(TypeMirror type) { + return Utils.getSimpleName(type); + } + + protected void writeHeader() { + // default implementation does nothing + } + + private void writeModifiers(Set modifiers) { + if (modifiers != null) { + for (Modifier modifier : modifiers) { + write(modifier.toString()); + write(" "); + } + } + } + + private static final String LN = "\n"; + + protected void indent() { + indent++; + } + + protected void dedent() { + indent--; + } + + protected void writeLn() { + write(LN); + newLine = true; + } + + protected void writeLn(String text) { + write(text); + write(LN); + newLine = true; + } + + protected void writeEmptyLn() { + writeLn(); + } + + private AbstractCodeWriter write(Name name) { + return write(name.toString()); + } + + private AbstractCodeWriter write(String m) { + try { + if (newLine && m != LN) { + writeIndent(); + newLine = false; + } + writer.write(m); + } catch (IOException e) { + throw new RuntimeException(e); + } + return this; + } + + private void writeIndent() throws IOException { + for (int i = 0; i < indent; i++) { + writer.write(" "); + } + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/FixWarningsVisitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/FixWarningsVisitor.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.codewriter; + +import static com.oracle.truffle.codegen.processor.Utils.*; +import static javax.lang.model.element.Modifier.*; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.ast.*; + + +public class FixWarningsVisitor extends CodeElementScanner{ + + + private final Set symbolsUsed = new HashSet<>(); + + private final ProcessorContext context; + private final DeclaredType unusedAnnotation; + private final DeclaredType overrideType; + + public FixWarningsVisitor(ProcessorContext context, DeclaredType unusedAnnotation, DeclaredType overrideType) { + this.context = context; + this.unusedAnnotation = unusedAnnotation; + this.overrideType = overrideType; + } + + @Override + public Void visitType(CodeTypeElement e, Void p) { + List superTypes = Utils.getSuperTypes(e); + for (TypeElement type : superTypes) { + String qualifiedName = Utils.getQualifiedName(type); + if (qualifiedName.equals(Serializable.class.getCanonicalName())) { + if (!e.containsField("serialVersionUID")) { + e.add(new CodeVariableElement(modifiers(PRIVATE, STATIC, FINAL), context.getType(long.class), "serialVersionUID", "1L")); + } + break; + } + } + + return super.visitType(e, p); + } + + @Override + public Void visitExecutable(CodeExecutableElement e, Void p) { + if (e.getParameters().isEmpty()) { + return null; + } else if (e.getModifiers().contains(Modifier.ABSTRACT)) { + return null; + } else if (containsOverride(e)) { + return null; + } + + symbolsUsed.clear(); + super.visitExecutable(e, p); + if (e.getBodyTree() == null && e.getBody() != null) { + computeSymbols(e.getBody()); + } + + for (VariableElement parameter : e.getParameters()) { + if (!symbolsUsed.contains(parameter.getSimpleName().toString())) { + e.getAnnotationMirrors().add(createUnusedAnnotationMirror()); + break; + } + } + return null; + } + + private boolean containsOverride(CodeExecutableElement e) { + for (AnnotationMirror mirror : e.getAnnotationMirrors()) { + if (Utils.typeEquals(overrideType, mirror.getAnnotationType())) { + return true; + } + } + return false; + } + + private CodeAnnotationMirror createUnusedAnnotationMirror() { + CodeAnnotationMirror mirror = new CodeAnnotationMirror(unusedAnnotation); + mirror.setElementValue(mirror.findExecutableElement("value"), new CodeAnnotationValue("unused")); + return mirror; + } + + @Override + public void visitTree(CodeTree e, Void p) { + if (e.getString() != null) { + computeSymbols(e.getString()); + } + super.visitTree(e, p); + } + + private void computeSymbols(String s) { + // TODO there should not be any need for a StringTokenizer if we have a real AST for + // method bodies. Also the current solution is not perfect. What if one token + // is spread across multiple CodeTree instances? But for now that works. + StringTokenizer tokenizer = new StringTokenizer(s, ".= :,()[];{}\"\"'' ", false); + while (tokenizer.hasMoreElements()) { + String token = tokenizer.nextToken().trim(); + if (token.length() > 0) { + symbolsUsed.add(token); + } + } + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/GenerateOverrideVisitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/GenerateOverrideVisitor.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.codewriter; + +import static com.oracle.truffle.codegen.processor.Utils.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.ast.*; + +public class GenerateOverrideVisitor extends CodeElementScanner { + + private final DeclaredType overrideType; + + public GenerateOverrideVisitor(DeclaredType overrideType) { + this.overrideType = overrideType; + } + + @Override + public Void visitExecutable(CodeExecutableElement e, Void p) { + if (!e.getModifiers().contains(Modifier.STATIC) && !e.getModifiers().contains(Modifier.PRIVATE)) { + String name = e.getSimpleName().toString(); + TypeMirror[] params = e.getParameterTypes(); + + if (isDeclaredMethodInSuperType(e.getEnclosingClass(), name, params)) { + e.addAnnotationMirror(new CodeAnnotationMirror(overrideType)); + } + } + return super.visitExecutable(e, p); + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.codewriter; + +import static com.oracle.truffle.codegen.processor.Utils.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.ast.*; + +public final class OrganizedImports { + + private final Map importUsage = new HashMap<>(); + private final Map staticImportUsage = new HashMap<>(); + + private final Map simpleNamesUsed = new HashMap<>(); + + private final Set declaredStaticMethods = new HashSet<>(); + private final Set declaredStaticFields = new HashSet<>(); + private final Set ambiguousStaticMethods = new HashSet<>(); + private final Set ambiguousStaticFields = new HashSet<>(); + + private final CodeTypeElement topLevelClass; + + private OrganizedImports(CodeTypeElement topLevelClass) { + this.topLevelClass = topLevelClass; + } + + public static OrganizedImports organize(CodeTypeElement topLevelClass) { + OrganizedImports organized = new OrganizedImports(topLevelClass); + + OrganizedImports.ReferenceCollector reference = new ReferenceCollector(); + topLevelClass.accept(reference, null); + + OrganizedImports.ImportResolver resolver = new ImportResolver(reference, organized); + topLevelClass.accept(resolver, null); + return organized; + } + + public String useImport(TypeMirror type) { + String simpleName = getSimpleName(type); + TypeMirror usedByType = simpleNamesUsed.get(type); + if (usedByType == null) { + simpleNamesUsed.put(simpleName, type); + usedByType = type; + } else if (!typeEquals(type, usedByType)) { + // we need a qualified name + return getQualifiedName(type); + } + + // we can use the simple name + addUsage(type, importUsage); + return simpleName; + } + + public String useStaticFieldImport(TypeMirror type, String fieldName) { + return useStaticImport(type, fieldName, ambiguousStaticFields, declaredStaticFields); + } + + public String useStaticMethodImport(TypeMirror type, String methodName) { + return useStaticImport(type, methodName, ambiguousStaticMethods, declaredStaticMethods); + } + + private String useStaticImport(TypeMirror type, String name, Set ambiguousSymbols, Set declaredSymbols) { + if (ambiguousSymbols.contains(name)) { + // ambiguous import + return useImport(type) + "." + name; + } else if (!declaredSymbols.contains(name)) { + // not imported at all + return useImport(type) + "." + name; + } else { + // import declared and not ambiguous + addUsage(type, staticImportUsage); + return name; + } + } + + public Set generateImports() { + Set imports = new HashSet<>(); + + imports.addAll(generateImports(topLevelClass, importUsage.keySet())); + imports.addAll(generateStaticImports(topLevelClass, staticImportUsage.keySet())); + + return imports; + } + + void clearStaticImports() { + declaredStaticFields.clear(); + declaredStaticMethods.clear(); + ambiguousStaticFields.clear(); + ambiguousStaticMethods.clear(); + } + + boolean processStaticImports(TypeElement element) { + Set importedMethods = new HashSet<>(); + List methods = ElementFilter.methodsIn(element.getEnclosedElements()); + for (ExecutableElement method : methods) { + if (method.getModifiers().contains(Modifier.STATIC)) { + importedMethods.add(method.getSimpleName().toString()); + } + } + + boolean allMethodsAmbiguous = processStaticImportElements(importedMethods, this.ambiguousStaticMethods, this.declaredStaticMethods); + + Set importedFields = new HashSet<>(); + List fields = ElementFilter.fieldsIn(element.getEnclosedElements()); + for (VariableElement field : fields) { + if (field.getModifiers().contains(Modifier.STATIC)) { + importedFields.add(field.getSimpleName().toString()); + } + } + + boolean allFieldsAmbiguous = processStaticImportElements(importedFields, this.ambiguousStaticFields, this.declaredStaticFields); + + return allMethodsAmbiguous && allFieldsAmbiguous; + } + + private static boolean processStaticImportElements(Set newElements, Set ambiguousElements, Set declaredElements) { + boolean allAmbiguous = false; + if (declaredElements.containsAll(newElements)) { + // all types already declared -> we can remove the import completely -> they will all get ambiguous + allAmbiguous = true; + } + Set newAmbiguous = new HashSet<>(); + Set newDeclared = new HashSet<>(); + + for (String newElement : newElements) { + if (declaredElements.contains(newElement)) { + newAmbiguous.add(newElement); + } else if (ambiguousElements.contains(newElement)) { + // nothing to do + } else { + newDeclared.add(newElement); + } + } + + ambiguousElements.addAll(newAmbiguous); + declaredElements.addAll(newDeclared); + return allAmbiguous; + } + + private static Set generateImports(CodeTypeElement e, Set toGenerate) { + Set autoImportedTypes = new HashSet<>(); + + // if type is declared inside a super type of this class -> no import + collectSuperTypeImports(e, autoImportedTypes); + collectInnerTypeImports(e, autoImportedTypes); + + TreeSet importObjects = new TreeSet<>(); + for (TypeMirror importType : toGenerate) { + String importTypePackageName = getPackageName(importType); + if (importTypePackageName == null) { + continue; // no package name -> no import + } + + if (importTypePackageName.equals("java.lang")) { + continue; // java.lang is automatically imported + } + + if (importTypePackageName.equals(getPackageName(e))) { + continue; // same package name -> no import + } + + String qualifiedName = getQualifiedName(importType); + + if (autoImportedTypes.contains(qualifiedName)) { + continue; + } + + importObjects.add(new CodeImport(importType, getQualifiedName(importType), false)); + } + + return importObjects; + } + + private static void collectInnerTypeImports(TypeElement e, Set autoImportedTypes) { + for (TypeElement innerClass : ElementFilter.typesIn(e.getEnclosedElements())) { + collectSuperTypeImports(innerClass, autoImportedTypes); + collectInnerTypeImports(innerClass, autoImportedTypes); + } + } + + private static void collectSuperTypeImports(TypeElement e, Set autoImportedTypes) { + List superTypes = getSuperTypes(e); + for (TypeElement superType : superTypes) { + List declaredTypes = getDeclaredTypes(superType); + for (TypeElement declaredType : declaredTypes) { + autoImportedTypes.add(getQualifiedName(declaredType)); + } + } + } + + private static Set generateStaticImports(CodeTypeElement e, Set toGenerate) { + Set autoImportedStaticTypes = new HashSet<>(); + + // if type is declared inside a super type of this class -> no import + autoImportedStaticTypes.add(getQualifiedName(e)); + autoImportedStaticTypes.addAll(getQualifiedSuperTypeNames(e)); + + TreeSet importObjects = new TreeSet<>(); + for (TypeMirror importType : toGenerate) { + if (getPackageName(importType) == null) { + continue; // no package name -> no import + } + + String qualifiedName = getQualifiedName(importType); + if (autoImportedStaticTypes.contains(qualifiedName)) { + continue; + } + + importObjects.add(new CodeImport(importType, qualifiedName + ".*", true)); + } + + return importObjects; + } + + private static void addUsage(TypeMirror type, Map usageMap) { + if (type != null) { + Integer value = usageMap.get(type); + if (value == null) { + usageMap.put(type, 1); + } else { + usageMap.put(type, value + 1); + } + } + } + + private static class ReferenceCollector extends CodeElementScanner { + + final Map typeReferences = new HashMap<>(); + final Map staticTypeReferences = new HashMap<>(); + + @Override + public void visitTree(CodeTree e, Void p) { + if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) { + addStaticImport(e.getType()); + } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) { + addStaticImport(e.getType()); + } else { + addImport(e.getType()); + } + super.visitTree(e, p); + } + + @Override + public Void visitExecutable(CodeExecutableElement e, Void p) { + visitAnnotations(e.getAnnotationMirrors()); + if (e.getReturnType() != null) { + addImport(e.getReturnType()); + } + for (TypeMirror type : e.getThrownTypes()) { + addImport(type); + } + return super.visitExecutable(e, p); + } + + @Override + public Void visitType(CodeTypeElement e, Void p) { + visitAnnotations(e.getAnnotationMirrors()); + + addImport(e.getSuperclass()); + for (TypeMirror type : e.getImplements()) { + addImport(type); + } + + return super.visitType(e, p); + } + + @Override + public Void visitVariable(VariableElement f, Void p) { + visitAnnotations(f.getAnnotationMirrors()); + addImport(f.asType()); + return super.visitVariable(f, p); + } + + private void visitAnnotations(List mirrors) { + for (AnnotationMirror mirror : mirrors) { + visitAnnotation(mirror); + } + } + + public void visitAnnotation(AnnotationMirror e) { + addImport(e.getAnnotationType()); + } + + @Override + public void visitImport(CodeImport e, Void p) { + } + + private void addStaticImport(TypeMirror type) { + addUsage(type, staticTypeReferences); + } + + private void addImport(TypeMirror type) { + addUsage(type, typeReferences); + } + + } + + private static class ImportResolver extends CodeElementScanner { + + private final ReferenceCollector collector; + private final OrganizedImports organizedImports; + + public ImportResolver(OrganizedImports.ReferenceCollector collector, OrganizedImports organizedImports) { + this.collector = collector; + this.organizedImports = organizedImports; + } + + @Override + public Void visitType(CodeTypeElement e, Void p) { + if (e.isTopLevelClass()) { + organizedImports.clearStaticImports(); + + organizedImports.processStaticImports(e); + List types = Utils.getSuperTypes(e); + for (TypeElement typeElement : types) { + organizedImports.processStaticImports(typeElement); + } + + for (TypeMirror type : collector.staticTypeReferences.keySet()) { + TypeElement element = fromTypeMirror(type); + if (element != null) { + // already processed by supertype + if (types.contains(element)) { + continue; + } + organizedImports.processStaticImports(element); + } + } + + for (TypeMirror imp : collector.typeReferences.keySet()) { + organizedImports.useImport(imp); + } + } + return super.visitType(e, p); + } + + @Override + public void visitTree(CodeTree e, Void p) { + if (e.getCodeKind() == CodeTreeKind.TYPE) { + organizedImports.useImport(e.getType()); + } else if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) { + organizedImports.useStaticFieldImport(e.getType(), e.getString()); + } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) { + organizedImports.useStaticMethodImport(e.getType(), e.getString()); + } + super.visitTree(e, p); + } + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/AbstractCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/AbstractCompiler.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.compiler; + +import java.lang.reflect.*; + + +public abstract class AbstractCompiler implements Compiler { + + + protected static Object method(Object o, String methodName) throws Exception { + Method method = o.getClass().getMethod(methodName); + method.setAccessible(true); + return method.invoke(o); + } + + protected static Object method(Object o, String methodName, Class[] paramTypes, Object ... values) throws Exception { + Method method = o.getClass().getMethod(methodName, paramTypes); + method.setAccessible(true); + return method.invoke(o, values); + } + + protected static Object field(Object o, String fieldName) throws Exception { + Field field = o.getClass().getField(fieldName); + field.setAccessible(true); + return field.get(o); + } + + protected static String parseHeader(String content) { + int index = content.indexOf("/*"); + if (index == -1) { + return null; + } + if (!content.substring(0, index).trim().equals("")) { + // just whitespace before + return null; + } + + int endIndex = content.indexOf("*/", index); + if (endIndex == -1) { + return null; + } + return content.substring(index, endIndex + 2); + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/Compiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/Compiler.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.compiler; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; + + +public interface Compiler { + + String getMethodBody(ProcessingEnvironment env, ExecutableElement method); + + String getHeaderComment(ProcessingEnvironment env, Element type); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/CompilerFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/CompilerFactory.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.compiler; + +import javax.lang.model.element.*; + +public class CompilerFactory { + + private static Compiler javac; + private static Compiler jdt; + + public static Compiler getCompiler(Element currentElement) { + if (JavaCCompiler.isValidElement(currentElement)) { + if (javac == null) { + javac = new JavaCCompiler(); + } + return javac; + } else if (JDTCompiler.isValidElement(currentElement)) { + if (jdt == null) { + jdt = new JDTCompiler(); + } + return jdt; + } else { + throw new UnsupportedOperationException("Unsupported compiler for element " + currentElement.getClass().getName() + "."); + } + } + + + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/JDTCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/JDTCompiler.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.compiler; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; + +import com.oracle.truffle.codegen.processor.*; + +public class JDTCompiler extends AbstractCompiler { + + public static boolean isValidElement(Element currentElement) { + try { + Class elementClass = Class.forName("org.eclipse.jdt.internal.compiler.apt.model.ElementImpl"); + return elementClass.isAssignableFrom(currentElement.getClass()); + } catch (ClassNotFoundException e) { + return false; + } + } + + @Override + public String getMethodBody(ProcessingEnvironment env, ExecutableElement method) { + try { + + char[] source = getSource(method); + if (source == null) { + return null; + } + + /* + AbstractMethodDeclaration decl = ((MethodBinding)(((ElementImpl)method)._binding)).sourceMethod(); + int bodyStart = decl.bodyStart; + int bodyEnd = decl.bodyEnd; + */ + Object decl = method(field(method, "_binding"), "sourceMethod"); + int bodyStart = (int) field(decl, "bodyStart"); + int bodyEnd = (int) field(decl, "bodyEnd"); + + int length = bodyEnd - bodyStart; + char[] target = new char[length]; + System.arraycopy(source, bodyStart, target, 0, length); + + return new String(target); + } catch (Exception e) { + return Utils.printException(e); + } + } + + + private static char[] getSource(Element element) throws Exception { + /* + Binding binding = ((ElementImpl)element)._binding; + char[] source = null; + if (binding instanceof MethodBinding) { + source = ((MethodBinding) binding).sourceMethod().compilationResult.getCompilationUnit().getContents(); + } else if (binding instanceof SourceTypeBinding) { + source = ((SourceTypeBinding)binding).scope.referenceContext.compilationResult.compilationUnit.getContents(); + } + return source; + */ + + Object binding = field(element, "_binding"); + Class methodBindingClass = Class.forName("org.eclipse.jdt.internal.compiler.lookup.MethodBinding"); + Class referenceBindingClass = Class.forName("org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding"); + + char[] source = null; + if (methodBindingClass.isAssignableFrom(binding.getClass())) { + Object sourceMethod = method(binding, "sourceMethod"); + if (sourceMethod == null) { + return null; + } + source = (char[]) method(method(field(sourceMethod, "compilationResult"), "getCompilationUnit"), "getContents"); + } else if (referenceBindingClass.isAssignableFrom(binding.getClass())) { + source = (char[]) method(field(field(field(field(binding, "scope"), "referenceContext"), "compilationResult"), "compilationUnit"), "getContents"); + } + return source; + } + + + @Override + public String getHeaderComment(ProcessingEnvironment env, Element type) { + try { + char[] source = getSource(type); + if (source == null) { + return null; + } + return parseHeader(new String(source)); + } catch (Exception e) { + return Utils.printException(e); + } + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/JavaCCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/JavaCCompiler.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.compiler; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; + +import com.oracle.truffle.codegen.processor.*; + + +public class JavaCCompiler extends AbstractCompiler { + + public static boolean isValidElement(Element currentElement) { + try { + Class elementClass = Class.forName("com.sun.tools.javac.code.Symbol"); + return elementClass.isAssignableFrom(currentElement.getClass()); + } catch (ClassNotFoundException e) { + return false; + } + } + + private static final Class[] getTreeAndTopLevelSignature = new Class[]{Element.class, AnnotationMirror.class, AnnotationValue.class}; + private static final Class[] getCharContentSignature = new Class[]{boolean.class}; + + @Override + public String getMethodBody(ProcessingEnvironment env, ExecutableElement method) { + try { + /* + if (false) { + Pair treeAndTopLevel = ((JavacElements) env.getElementUtils()).getTreeAndTopLevel(method, null, null); + JCBlock block = ((JCMethodDecl) treeAndTopLevel.fst).getBody(); + int startPos = block.pos; + int endPos = block.endpos; + String methodBody = treeAndTopLevel.snd.getSourceFile().getCharContent(true).subSequence(startPos + 1, endPos).toString(); + return methodBody; + } + */ + + Object treeAndTopLevel = getTreeAndTopLevel(env, method); + Object block = method(field(treeAndTopLevel, "fst"), "getBody"); + int startPos = (int) field(block, "pos"); + int endPos = (int) field(block, "endpos"); + return getContent(treeAndTopLevel).subSequence(startPos + 1, endPos).toString(); + } catch (Exception e) { + return Utils.printException(e); + } + } + + private static CharSequence getContent(Object treeAndTopLevel) throws Exception { + /* + * CharSequence content = treeAndTopLevel.snd.getSourceFile().getCharContent(true); + */ + return (CharSequence) method(method(field(treeAndTopLevel, "snd"), "getSourceFile"), "getCharContent", getCharContentSignature, true); + } + + private static Object getTreeAndTopLevel(ProcessingEnvironment env, Element element) throws Exception { + /* + * Pair treeAndTopLevel = ((JavacElements) env.getElementUtils()).getTreeAndTopLevel(method, null, null); + */ + return method(method(env, "getElementUtils"), "getTreeAndTopLevel", getTreeAndTopLevelSignature, element, null, null); + } + + @Override + public String getHeaderComment(ProcessingEnvironment env, Element type) { + try { + String content = getContent(getTreeAndTopLevel(env, type)).toString(); + return parseHeader(content); + } catch (Exception e) { + return Utils.printException(e); + } + } + + + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionCodeElementFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionCodeElementFactory.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ext; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.api.element.*; +import com.oracle.truffle.codegen.processor.ast.*; + + +final class ExtensionCodeElementFactory implements WritableElementFactory { + + private final ProcessorContext context; + + Element generatorElement; + AnnotationMirror generatorAnnotationMirror; + + public ExtensionCodeElementFactory(ProcessorContext context) { + this.context = context; + } + + @Override + public WritableExecutableElement cloneExecutableElement(ExecutableElement method) { + return updateGenerators(CodeExecutableElement.clone(context.getEnvironment(), method)); + } + + @Override + public WritableVariableElement cloneVariableElement(VariableElement var) { + return updateGenerators(CodeVariableElement.clone(var)); + } + + @Override + public WritableAnnotationMirror cloneAnnotationMirror(AnnotationMirror mirror) { + return CodeAnnotationMirror.clone(mirror); + } + + @Override + public WritableVariableElement createParameter(TypeMirror type, String simpleName) { + return updateGenerators(new CodeVariableElement(Utils.modifiers(), type, simpleName)); + } + + @Override + public WritableExecutableElement createExecutableElement(TypeMirror returnType, String methodName) { + return updateGenerators(new CodeExecutableElement(returnType, methodName)); + } + + @Override + public TypeMirror createTypeMirror(Class javaClass) { + return context.getType(javaClass); + } + + @Override + public WritableAnnotationMirror createAnnotationMirror(DeclaredType typeMirror) { + return new CodeAnnotationMirror(typeMirror); + } + + @Override + public Name createName(String name) { + return CodeNames.of(name); + } + + @Override + public AnnotationValue createAnnotationValue(Object value) { + return new CodeAnnotationValue(value); + } + + private E updateGenerators(E element) { + element.setGeneratorElement(generatorElement); + element.setGeneratorAnnotationMirror(generatorAnnotationMirror); + return element; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionContextImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionContextImpl.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ext; + +import java.util.*; + +import javax.annotation.processing.*; + +import com.oracle.truffle.codegen.processor.api.*; +import com.oracle.truffle.codegen.processor.api.element.*; + + +public class ExtensionContextImpl implements ExtensionContext { + + private final ProcessingEnvironment env; + private final RoundEnvironment round; + private final WritableElementFactory factory; + + private final List elements = new ArrayList<>(); + + public ExtensionContextImpl(ProcessingEnvironment env, RoundEnvironment round, WritableElementFactory factory) { + this.env = env; + this.round = round; + this.factory = factory; + } + + + List returnElements() { + List returnElements = new ArrayList<>(this.elements); + this.elements.clear(); + return returnElements; + } + + @Override + public ProcessingEnvironment getProcessingEnvironment() { + return env; + } + + @Override + public RoundEnvironment getRoundEnvironment() { + return round; + } + + @Override + public WritableElementFactory getElementFactory() { + return factory; + } + + @Override + public void addGeneratedElement(WritableElement element) { + elements.add(element); + } + + @Override + public void removeGeneratedElement(WritableElement element) { + elements.remove(element); + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.ext; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.api.*; +import com.oracle.truffle.codegen.processor.api.element.*; + + +public class ExtensionParser { + + private final Map extensions = new HashMap<>(); + private final ProcessorContext context; + private final ExtensionCodeElementFactory factory; + private final ExtensionContextImpl extensionContext; + + public ExtensionParser(ProcessorContext context) { + this.context = context; + this.factory = new ExtensionCodeElementFactory(context); + this.extensionContext = new ExtensionContextImpl(context.getEnvironment(), null, factory); + } + + public List parseAll(TypeElement typeElement) { + List generatedMethods = new ArrayList<>(); + parseElement(generatedMethods, typeElement); + + List methods = ElementFilter.methodsIn(typeElement.getEnclosedElements()); + for (ExecutableElement method : methods) { + for (VariableElement var : method.getParameters()) { + parseElement(generatedMethods, var); + } + parseElement(generatedMethods, method); + } + + return generatedMethods; + } + + private void parseElement(List elements, Element element) { + List mirrors = element.getAnnotationMirrors(); + for (AnnotationMirror mirror : mirrors) { + ExtensionProcessor processor = findProcessor(element, mirror); + if (processor != null) { + try { + factory.generatorAnnotationMirror = mirror; + factory.generatorElement = element; + processor.process(extensionContext, mirror, element); + elements.addAll(extensionContext.returnElements()); + } catch (Throwable e) { + context.getLog().error(element, mirror, "Processor for '%s' failed with exception: \n\n%s.", Utils.getQualifiedName(mirror.getAnnotationType()), Utils.printException(e)); + } finally { + factory.generatorAnnotationMirror = null; + factory.generatorElement = null; + } + } + } + } + + private ExtensionProcessor findProcessor(Element element, AnnotationMirror mirror) { + String processorName = Utils.getQualifiedName(mirror.getAnnotationType()); + ExtensionProcessor processor = null; + if (extensions.containsKey(processorName)) { + processor = extensions.get(processorName); + } else { + AnnotationMirror foundExtension = Utils.findAnnotationMirror(context.getEnvironment(), mirror.getAnnotationType().asElement(), ExtensionAnnotation.class); + if (foundExtension != null) { + String className = Utils.getAnnotationValueString(foundExtension, "processorClassName"); + Class processorClass; + try { + processorClass = Class.forName(className); + } catch (ClassNotFoundException e) { + context.getLog().error(element, mirror, "Could not find processor class '%s' configured in '@%s'.", className, processorName); + return null; + } + try { + processor = (ExtensionProcessor) processorClass.newInstance(); + } catch (InstantiationException e) { + context.getLog().error(element, mirror, "Could not instantiate processor class '%s' configured in '@%s'.", className, processorName); + return null; + } catch (IllegalAccessException e) { + context.getLog().error(element, mirror, "Could not access processor class '%s' configured in '@%s'.", className, processorName); + return null; + } catch (ClassCastException e) { + context.getLog().error(element, mirror, "Processor class '%s' configured in '@%s' does not implement '%s'.", className, processorName, ExtensionProcessor.class.getName()); + return null; + } + } + extensions.put(processorName, processor); + } + return processor; + } + + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/GenericParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/GenericParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import java.lang.annotation.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; + +public class GenericParser extends OperationMethodParser { + + public GenericParser(ProcessorContext context, OperationData operation) { + super(context, operation); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + return createDefaultMethodSpec(null); + } + + @Override + protected ParameterSpec createValueParameterSpec(String valueName) { + return new ParameterSpec(valueName, getOperation().getTypeSystem().getGenericType(), Kind.EXECUTE, false); + } + + @Override + protected ParameterSpec createReturnParameterSpec() { + return new ParameterSpec("returnValue", getOperation().getTypeSystem(), Kind.EXECUTE, false, Cardinality.ONE); + } + + @Override + public SpecializationData create(TemplateMethod method) { + return new SpecializationData(method, true, false); + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return Generic.class; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationCodeGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationCodeGenerator.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,903 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import static com.oracle.truffle.codegen.processor.Utils.*; +import static javax.lang.model.element.Modifier.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.ast.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; +import com.oracle.truffle.codegen.processor.typesystem.*; + +public class OperationCodeGenerator extends CompilationUnitFactory { + + private static final String OPERATION_FIELD_NAME = "operation"; + + public OperationCodeGenerator(ProcessorContext context) { + super(context); + } + + private TypeMirror getUnexpectedValueException() { + return getContext().getTruffleTypes().getUnexpectedValueException(); + } + + private static String operationClassName(OperationData operation) { + return Utils.getSimpleName(operation.getTemplateType().asType()); + } + + private static String factoryClassName(OperationData operation) { + return operationClassName(operation) + "Factory"; + } + + private static String nodeClassName(OperationData operation) { + String name = operationClassName(operation); + if (name.length() > 2 && name.endsWith("Op")) { + name = name.substring(0, name.length() - 2); + } + return name + "Node"; + } + + private static String nodeClassName(SpecializationData specialization) { + String name = ""; + if (specialization.getOperation().getAllMethods().length > 1) { + name = specialization.getMethodName(); + if (name.startsWith("do")) { + name = name.substring(2); + } + } + return name + nodeClassName(specialization.getOperation()); + } + + private static String nodeVariableName(ParameterSpec spec) { + if (spec.getKind() == Kind.EXECUTE) { + return spec.getName() + "Node"; + } + return spec.getName(); + } + + private static String nodeVariableName(ActualParameter param) { + return nodeVariableName(param.getSpecification()); + } + + private static String valueVariableName(ParameterSpec spec) { + if (spec.getKind() == Kind.EXECUTE) { + return spec.getName() + "Value"; + } + return spec.getName(); + } + + private static String valueVariableName(ActualParameter param) { + return valueVariableName(param.getSpecification()); + } + + public static String executeMethodName(TypeData type) { + if (type.isGeneric()) { + return "executeGeneric"; + } + return "execute" + Utils.getSimpleName(type.getBoxedType()); + } + + private static EnumSet kinds(Kind... values) { + EnumSet result = EnumSet.noneOf(Kind.class); + for (Kind value : values) { + result.add(value); + } + return result; + } + + private static void addNodeParameters(CodeExecutableElement method, OperationData operation, EnumSet included) { + for (ParameterSpec spec : operation.getSpecification().getParameters()) { + if (included.contains(spec.getKind())) { + if (spec.getKind() == Kind.EXECUTE) { + method.addParameter(new CodeVariableElement(operation.getTypeSystem().getNodeType(), nodeVariableName(spec))); + } else { + method.addParameter(new CodeVariableElement(spec.getValueType(), nodeVariableName(spec))); + } + } + } + if (included.contains(Kind.CONSTRUCTOR_FIELD)) { + for (OperationFieldData field : operation.getConstructorFields()) { + method.addParameter(new CodeVariableElement(field.getJavaClass(), field.getName())); + } + } + } + + private static void addValueParameters(CodeExecutableElement method, OperationData operation, EnumSet included) { + for (ParameterSpec spec : operation.getSpecification().getParameters()) { + if (included.contains(spec.getKind())) { + method.addParameter(new CodeVariableElement(spec.getValueType(), valueVariableName(spec))); + } + } + if (included.contains(Kind.CONSTRUCTOR_FIELD)) { + for (OperationFieldData field : operation.getConstructorFields()) { + method.addParameter(new CodeVariableElement(field.getJavaClass(), field.getName())); + } + } + } + + private static void addOperationFieldName(CodeTreeBuilder body, OperationData operation) { + if (!operation.isUseSingleton()) { + body.string(OPERATION_FIELD_NAME); + } + } + + private static void addOperationVariable(Set modifiers, Element element, OperationData operation, CodeTypeElement operationGen) { + if (!operation.isUseSingleton()) { + TypeMirror type = findOperationType(operation, operationGen); + if (element instanceof CodeExecutableElement) { + ((CodeExecutableElement) element).addParameter(new CodeVariableElement(modifiers, type, OPERATION_FIELD_NAME)); + } else if (element instanceof CodeTypeElement) { + ((CodeTypeElement) element).add(new CodeVariableElement(modifiers, type, OPERATION_FIELD_NAME)); + } + } + } + + private static void addNodeNames(CodeTreeBuilder body, OperationData operation, EnumSet included) { + for (ParameterSpec spec : operation.getSpecification().getParameters()) { + if (included.contains(spec.getKind())) { + body.string(nodeVariableName(spec)); + } + } + if (included.contains(Kind.CONSTRUCTOR_FIELD)) { + for (OperationFieldData field : operation.getConstructorFields()) { + body.string(field.getName()); + } + } + } + + private static void addValueNames(CodeTreeBuilder body, OperationData operation, EnumSet included) { + for (ParameterSpec spec : operation.getSpecification().getParameters()) { + if (included.contains(spec.getKind())) { + body.string(valueVariableName(spec)); + } + } + if (included.contains(Kind.CONSTRUCTOR_FIELD)) { + for (OperationFieldData field : operation.getConstructorFields()) { + body.string(field.getName()); + } + } + } + + private static void addValueNamesWithCasts(ProcessorContext context, CodeTreeBuilder body, SpecializationData specialization, EnumSet included) { + for (ActualParameter spec : specialization.getParameters()) { + if (included.contains(spec.getSpecification().getKind())) { + TypeData typeData = spec.getActualTypeData(specialization.getOperation().getTypeSystem()); + if (typeData.isGeneric()) { + body.string(valueVariableName(spec)); + } else { + String methodName = TypeSystemCodeGenerator.asTypeMethodName(typeData); + startCallTypeSystemMethod(context, body, specialization.getOperation(), methodName); + body.string(valueVariableName(spec)); + body.end().end(); + } + } + } + } + + public static VariableElement findSingleton(ProcessorContext context, OperationData operation) { + TypeMirror type = context.findGeneratedClassBySimpleName(OperationCodeGenerator.genClassName(operation), operation); + return Utils.findDeclaredField(type, OperationCodeGenerator.singletonName(operation)); + } + + private static TypeMirror findOperationType(OperationData operation, CodeTypeElement operationGen) { + if (operation.hasExtensions()) { + // return generated type + return operationGen.asType(); + } else { + // return default type + return operation.getTemplateType().asType(); + } + } + + private static String genClassName(OperationData operation) { + String name = getSimpleName(operation.getTemplateType()); + return name + "Gen"; + } + + private static String singletonName(OperationData operation) { + return createConstantName(getSimpleName(operation.getTemplateType().asType())); + } + + private static void startCallOperationMethod(CodeTreeBuilder body, OperationData operation, TemplateMethod method) { + body.startGroup(); + + if (operation.isUseSingleton()) { + body.string(singletonName(operation)); + body.string(".").startCall(method.getMethodName()); + } else { + body.string(OPERATION_FIELD_NAME); + body.string("."); + body.startCall(method.getMethodName()); + } + } + + private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, OperationData operation, String methodName) { + VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, operation.getTypeSystem()); + assert singleton != null; + + body.startGroup(); + body.staticReference(singleton.getEnclosingElement().asType(), singleton.getSimpleName().toString()); + body.string(".").startCall(methodName); + } + + private static void emitGuards(ProcessorContext context, CodeTreeBuilder body, String prefix, SpecializationData specialization, boolean onSpecialization, boolean needsCast) { + // Implict guards based on method signature + String andOperator = prefix; + for (ActualParameter param : specialization.getParameters()) { + if (param.getSpecification().getKind() == Kind.EXECUTE && !param.getActualTypeData(specialization.getOperation().getTypeSystem()).isGeneric()) { + body.string(andOperator); + startCallTypeSystemMethod(context, body, specialization.getOperation(), + TypeSystemCodeGenerator.isTypeMethodName(param.getActualTypeData(specialization.getOperation().getTypeSystem()))); + body.string(valueVariableName(param)); + body.end().end(); // call + andOperator = " && "; + } + } + + if (specialization.getGuards().length > 0) { + // Explicitly specified guards + for (SpecializationGuardData guard : specialization.getGuards()) { + if ((guard.isOnSpecialization() && onSpecialization) + || (guard.isOnExecution() && !onSpecialization)) { + body.string(andOperator); + + if (guard.getGuardDeclaration().getOrigin() == specialization.getOperation()) { + startCallOperationMethod(body, specialization.getOperation(), guard.getGuardDeclaration()); + } else { + startCallTypeSystemMethod(context, body, specialization.getOperation(), guard.getGuardMethod()); + } + + if (needsCast) { + addValueNamesWithCasts(context, body, specialization, kinds(Kind.EXECUTE, Kind.SHORT_CIRCUIT)); + } else { + addValueNames(body, specialization.getOperation(), kinds(Kind.EXECUTE, Kind.SHORT_CIRCUIT)); + } + body.end().end(); // call + andOperator = " && "; + } + } + } + } + + @Override + protected void createChildren(OperationData m) { + CodeTypeElement operationGen = null; + if (m.hasExtensions()) { + OperationGenFactory factory = new OperationGenFactory(context); + add(factory, m); + operationGen = (CodeTypeElement) factory.getElement(); + } + if (m.generateFactory) { + add(new OperationNodeFactory(context, operationGen), m); + } + } + + protected class OperationGenFactory extends ClassElementFactory { + + public OperationGenFactory(ProcessorContext context) { + super(context); + } + + @Override + protected CodeTypeElement create(OperationData operation) { + CodeTypeElement clazz = createClass(operation, modifiers(PUBLIC), genClassName(operation), operation.getTemplateType().asType(), false); + + clazz.add(createConstructorUsingFields(modifiers(PUBLIC), clazz)); + + if (operation.getExtensionElements() != null) { + clazz.getEnclosedElements().addAll(operation.getExtensionElements()); + } + return clazz; + } + + } + + + + protected class OperationNodeFactory extends ClassElementFactory { + + private final CodeTypeElement operationGen; + + public OperationNodeFactory(ProcessorContext context, CodeTypeElement operationGen) { + super(context); + this.operationGen = operationGen; + } + + @Override + protected CodeTypeElement create(OperationData operation) { + CodeTypeElement clazz = createClass(operation, modifiers(PUBLIC, FINAL), factoryClassName(operation), null, false); + + if (operation.isUseSingleton()) { + TypeMirror type = findOperationType(operation, operationGen); + CodeVariableElement singleton = new CodeVariableElement(modifiers(PRIVATE, STATIC, FINAL), type, singletonName(operation)); + clazz.add(singleton); + CodeTreeBuilder singletonInit = singleton.createInitBuilder(); + singletonInit.startNew(type).end(); + } + + clazz.add(createConstructorUsingFields(modifiers(PRIVATE), clazz)); + clazz.add(createCreateMethod(operation)); + if (operation.getAllMethods().length > 1) { + clazz.add(createCreateSpecializedMethod(operation)); + } + if (operation.needsRewrites()) { + clazz.add(createSpecializeMethod(operation)); + clazz.add(createGeneratedGenericMethod(operation)); + } + + return clazz; + } + + @Override + protected void createChildren(OperationData operation) { + for (SpecializationData specialization : operation.getAllMethods()) { + add(new SpecializationNodeFactory(context, operationGen), specialization); + } + } + + private CodeExecutableElement createCreateMethod(OperationData operation) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), operation.getNodeType(), "create"); + addNodeParameters(method, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE, Kind.CONSTRUCTOR_FIELD)); + + CodeTreeBuilder body = method.createBuilder(); + body.startReturn(); + if (operation.getAllMethods().length == 0) { + body.null_(); + } else { + body.startNew(nodeClassName(operation.getAllMethods()[0])); + emitNewOperation(body, operation); + addNodeNames(body, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + body.end(); + } + body.end(); + + return method; + } + + private void emitNewOperation(CodeTreeBuilder body, OperationData operation) { + if (!operation.isUseSingleton()) { + body.startGroup(); + if (operation.hasExtensions()) { + body.startNew(genClassName(operation)); + } else { + body.startNew(operation.getTemplateType().asType()); + } + addNodeNames(body, operation, kinds(Kind.CONSTRUCTOR_FIELD)); + body.end(); + body.end(); + } + } + + private CodeExecutableElement createCreateSpecializedMethod(OperationData operation) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), operation.getNodeType(), "createSpecialized"); + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "specializationClass")); + addOperationVariable(modifiers(), method, operation, operationGen); + addNodeParameters(method, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + + CodeTreeBuilder body = method.createBuilder(); + + boolean first = true; + for (TypeData type : operation.getTypeSystem().getTypes()) { + SpecializationData specialization = operation.findUniqueSpecialization(type); + if (specialization != null && !type.isGeneric()) { + if (first) { + body.startIf(); + first = false; + } else { + body.startElseIf(); + } + body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock(); + body.startReturn().startNew(nodeClassName(specialization)); + addOperationFieldName(body, operation); + addNodeNames(body, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + body.end().end(); + body.end(); + } + } + body.startReturn().startNew(nodeClassName(operation.getGenericSpecialization())); + addOperationFieldName(body, operation); + addNodeNames(body, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + body.end().end(); + return method; + } + + private CodeExecutableElement createSpecializeMethod(OperationData operation) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), operation.getNodeType(), "specialize"); + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); + addOperationVariable(modifiers(), method, operation, operationGen); + addValueParameters(method, operation, kinds(Kind.EXECUTE)); + addNodeParameters(method, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + + CodeTreeBuilder body = method.createBuilder(); + body.startStatement().string("boolean allowed = (minimumState == ").string(nodeClassName(operation.getAllMethods()[0])).string(".class)").end(); + + for (int i = 1; i < operation.getAllMethods().length; i++) { + SpecializationData specialization = operation.getAllMethods()[i]; + body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end(); + + if (specialization.isGeneric()) { + body.startIf().string("allowed").end().startBlock(); + } else { + body.startIf().string("allowed"); + emitGuards(getContext(), body, " && ", specialization, true, true); + body.end().startBlock(); + } + body.startReturn().startNew(nodeClassName(specialization)); + + addOperationFieldName(body, operation); + addNodeNames(body, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + body.end().end(); + body.end(); // block + } + body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); + + return method; + } + + + private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization) { + if (specialization.getExceptions().length > 0) { + builder.startTryBlock(); + } + + builder.startReturn(); + startCallOperationMethod(builder, specialization.getOperation(), specialization); + for (ActualParameter param : specialization.getParameters()) { + boolean needsCast = param.getSpecification().getKind() == Kind.EXECUTE && !param.getActualTypeData(specialization.getOperation().getTypeSystem()).isGeneric(); + if (needsCast) { + startCallTypeSystemMethod(getContext(), builder, specialization.getOperation(), TypeSystemCodeGenerator.asTypeMethodName(param.getActualTypeData(specialization.getOperation().getTypeSystem()))); + } + builder.string(valueVariableName(param)); + if (needsCast) { + builder.end().end(); + } + } + builder.end().end(); // start call operation + builder.end(); // return + + if (specialization.getExceptions().length > 0) { + for (SpecializationThrowsData exception : specialization.getExceptions()) { + builder.end().startCatchBlock(exception.getJavaClass(), "ex"); + emitInvokeDoMethod(builder, exception.getTransitionTo()); + } + builder.end(); + } + } + + private CodeExecutableElement createGeneratedGenericMethod(OperationData operation) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), operation.getGenericSpecialization().getReturnType().getActualType(), "generatedGeneric"); + addOperationVariable(modifiers(), method, operation, operationGen); + addValueParameters(method, operation, kinds(Kind.SIGNATURE, Kind.EXECUTE, Kind.SHORT_CIRCUIT, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + + CodeTreeBuilder builder = method.createBuilder(); + boolean ifStarted = false; + for (int i = 0; i < operation.getSpecializations().length; i++) { + SpecializationData specialization = operation.getSpecializations()[i]; + if (specialization.isUninitialized()) { + continue; + } + if (!specialization.isGeneric()) { + if (!ifStarted) { + builder.startIf(); + ifStarted = true; + } else { + builder.startElseIf(); + } + emitGuards(getContext(), builder, "", specialization, false, true); + builder.end().startBlock(); + } else { + builder.startElseBlock(); + } + + emitInvokeDoMethod(builder, specialization); + builder.end(); + } + return method; + } + } + + protected class SpecializationNodeFactory extends ClassElementFactory { + + private CodeTypeElement operationGen; + + public SpecializationNodeFactory(ProcessorContext context, CodeTypeElement operationGen) { + super(context); + this.operationGen = operationGen; + } + + @Override + public CodeTypeElement create(SpecializationData specialization) { + OperationData operation = specialization.getOperation(); + CodeTypeElement clazz = createClass(operation, modifiers(PRIVATE, STATIC, FINAL), nodeClassName(specialization), operation.getNodeType(), false); + + + CodeExecutableElement constructor = new CodeExecutableElement(modifiers(PROTECTED), null, clazz.getSimpleName().toString()); + clazz.add(constructor); + + CodeTreeBuilder builder = constructor.createBuilder(); + builder.startStatement().startSuperCall(); + addNodeNames(builder, operation, kinds(Kind.SUPER_ATTRIBUTE)); + builder.end().end(); + + if (!operation.isUseSingleton()) { + addOperationVariable(modifiers(), constructor, operation, operationGen); + addOperationVariable(modifiers(PRIVATE, FINAL), clazz, operation, operationGen); + builder.startStatement(); + builder.string("this."); + addOperationFieldName(builder, operation); + builder.string(" = "); + addOperationFieldName(builder, operation); + builder.end(); + } + addNodeParameters(constructor, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + + + for (ParameterSpec spec : operation.getSpecification().getParameters()) { + String name = nodeVariableName(spec); + + boolean isNodeAttribute = spec.getKind() == Kind.ATTRIBUTE && getContext().getEnvironment().getTypeUtils().isAssignable(spec.getValueType(), getContext().getTruffleTypes().getNode()); + boolean isNodeArrayAttribute = spec.getKind() == Kind.ATTRIBUTE && + getContext().getEnvironment().getTypeUtils().isAssignable(spec.getValueType(), getContext().getTruffleTypes().getNodeArray()); + if (spec.getKind() == Kind.EXECUTE || isNodeAttribute || isNodeArrayAttribute) { + CodeVariableElement field = new CodeVariableElement(modifiers(PRIVATE), operation.getTypeSystem().getNodeType(), name); + clazz.add(field); + field.addAnnotationMirror(new CodeAnnotationMirror((DeclaredType) getContext().getTruffleTypes().getStableAnnotation())); + if (isNodeArrayAttribute) { + field.addAnnotationMirror(new CodeAnnotationMirror((DeclaredType) getContext().getTruffleTypes().getContentStableAnnotation())); + } + builder.startStatement().string("this.").string(name).string(" = adoptChild(").string(name).string(")").end(); + } else if (spec.getKind() == Kind.ATTRIBUTE) { + clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), spec.getValueType(), name)); + builder.startStatement().string("this.").string(name).string(" = ").string(name).end(); + } + } + + TypeSystemData typeSystem = operation.getTypeSystem(); + for (TypeData type : typeSystem.getTypes()) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), executeMethodName(type)); + clazz.add(method); + addValueParameters(method, operation, kinds(Kind.SIGNATURE)); + if (!type.isGeneric()) { + method.addThrownType(getUnexpectedValueException()); + } + + if (specialization.getReturnType().getActualTypeData(typeSystem) == type) { + buildFunctionalExecuteMethod(method.createBuilder(), operation, specialization); + } else { + buildCastingExecuteMethod(method.createBuilder(), operation, specialization, type); + } + } + + if (typeSystem.getVoidType() != null) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), typeSystem.getVoidType().getPrimitiveType(), executeMethodName(typeSystem.getVoidType())); + addValueParameters(method, operation, kinds(Kind.SIGNATURE)); + buildCastingExecuteMethod(method.createBuilder(), operation, specialization, typeSystem.getVoidType()); + clazz.add(method); + } + + if (operation.needsRewrites() && !specialization.isGeneric() && !specialization.isUninitialized()) { + buildSpecializeStateMethod(clazz, operation); + } + buildSpecializeClassMethod(clazz, operation); + + return clazz; + } + + private void buildCastingExecuteMethod(CodeTreeBuilder builder, OperationData operation, SpecializationData specialization, TypeData type) { + if (!type.isVoid()) { + builder.startStatement().type(specialization.getReturnType().getActualType()).string(" result").end(); + } + + boolean needsTry = !specialization.getReturnType().getActualTypeData(operation.getTypeSystem()).isGeneric(); + if (needsTry) { + builder.startTryBlock(); + } + + builder.startStatement(); + if (!type.isVoid()) { + builder.string("result = "); + } + builder.startCall(executeMethodName(specialization.getReturnType().getActualTypeData(operation.getTypeSystem()))).string("frame").end(); + builder.end(); // statement + + if (needsTry) { + builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); + + if (!type.isVoid()) { + builder.startReturn(); + if (!type.isGeneric()) { + startCallTypeSystemMethod(getContext(), builder, operation, TypeSystemCodeGenerator.expectTypeMethodName(type)); + } + + builder.string("ex.getResult()"); + + if (!type.isGeneric()) { + builder.end().end(); + } + builder.end(); // return + } else { + builder.string("// ignore").newLine(); + } + } + builder.end(); // try/catch + + if (!type.isVoid()) { + builder.startReturn(); + if (!type.isGeneric()) { + startCallTypeSystemMethod(getContext(), builder, operation, TypeSystemCodeGenerator.expectTypeMethodName(type)); + } + builder.string("result"); + if (!type.isGeneric()) { + builder.end().end(); + } + builder.end(); // return + } + } + + private void buildFunctionalExecuteMethod(CodeTreeBuilder builder, OperationData operation, SpecializationData specialization) { + ActualParameter previousShortCircuitParameter = null; + for (ActualParameter param : specialization.getParameters()) { + if (param.getSpecification().getKind() != Kind.EXECUTE) { + // Nothing to do. + } else if (param.getActualTypeData(operation.getTypeSystem()).isGeneric()) { + buildGenericValueExecute(builder, operation, param, null); + } else { + buildSpecializedValueExecute(builder, operation, specialization, param); + } + + assert param.getSpecification().getKind() == Kind.SHORT_CIRCUIT || previousShortCircuitParameter == null; + } + + if (specialization.hasDynamicGuards()) { + builder.startIf(); + emitGuards(getContext(), builder, "", specialization, false, false); + builder.end().startBlock(); + } + if (specialization.getExceptions().length > 0) { + builder.startTryBlock(); + } + + if (specialization.isUninitialized() && operation.needsRewrites()) { + for (TemplateMethod listener : operation.getSpecializationListeners()) { + builder.startStatement(); + startCallOperationMethod(builder, operation, listener); + for (ActualParameter param : listener.getParameters()) { + builder.string(valueVariableName(param)); + } + builder.end().end(); + builder.end(); // statement + } + + builder.startStatement(); + builder.startCall("replace"); + builder.startCall(factoryClassName(operation), "specialize"); + builder.typeLiteral(builder.getRoot().getEnclosingClass().asType()); + addOperationFieldName(builder, operation); + addValueNames(builder, operation, kinds(Kind.EXECUTE)); + addNodeNames(builder, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + builder.end().end().end(); + } + + if ((specialization.isUninitialized() || specialization.isGeneric()) && operation.needsRewrites()) { + builder.startReturn().startCall(factoryClassName(specialization.getOperation()), "generatedGeneric"); + addOperationFieldName(builder, operation); + addValueNames(builder, operation, kinds(Kind.SIGNATURE, Kind.EXECUTE, Kind.SHORT_CIRCUIT, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + builder.end().end(); + } else { + builder.startReturn(); + + if (specialization.isUninitialized()) { + startCallOperationMethod(builder, specialization.getOperation(), specialization.getOperation().getGenericSpecialization()); + } else { + startCallOperationMethod(builder, specialization.getOperation(), specialization); + } + for (ActualParameter param : specialization.getParameters()) { + builder.string(valueVariableName(param)); + } + builder.end().end(); // operation call + builder.end(); // return + } + + if (specialization.getExceptions().length > 0) { + for (SpecializationThrowsData exception : specialization.getExceptions()) { + builder.end().startCatchBlock(exception.getJavaClass(), "ex"); + buildThrowSpecialize(builder, operation, exception.getTransitionTo(), null); + } + builder.end(); + } + if (specialization.hasDynamicGuards()) { + builder.end().startElseBlock(); + buildThrowSpecialize(builder, operation, specialization.findNextSpecialization(), null); + builder.end(); + } + } + + private void buildGenericValueExecute(CodeTreeBuilder builder, OperationData operation, ActualParameter param, ParameterSpec exceptionSpec) { + boolean shortCircuit = startShortCircuit(builder, operation.getGenericSpecialization(), + operation.getGenericSpecialization().findParameter(param.getSpecification().getName()), exceptionSpec); + + builder.startStatement(); + if (!shortCircuit) { + builder.type(operation.getTypeSystem().getGenericType()); + builder.string(" "); + } + builder.string(valueVariableName(param)); + builder.string(" = ").startCall(nodeVariableName(param), executeMethodName(operation.getTypeSystem().getGenericTypeData())).string("frame").end(); + builder.end(); + + endShortCircuit(builder, shortCircuit); + } + + private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, + ActualParameter forParam, ParameterSpec exceptionParam) { + ActualParameter shortCircuitParam = specialization.getPreviousParam(forParam); + if (shortCircuitParam == null || shortCircuitParam.getSpecification().getKind() != Kind.SHORT_CIRCUIT) { + return false; + } + + int shortCircuitIndex = 0; + for (ActualParameter parameter : specialization.getParameters()) { + if (parameter.getSpecification().getKind() == Kind.SHORT_CIRCUIT) { + if (parameter == shortCircuitParam) { + break; + } + shortCircuitIndex++; + } + } + + builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(shortCircuitParam.getSpecification().getName()).string(" = "); + ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex]; + + startCallOperationMethod(builder, specialization.getOperation(), shortCircuitData); + for (ActualParameter callParam : shortCircuitData.getParameters()) { + ParameterSpec spec = callParam.getSpecification(); + if (spec.getKind() == Kind.EXECUTE || spec.getKind() == Kind.SHORT_CIRCUIT || spec.getKind() == Kind.SIGNATURE) { + if (exceptionParam != null && callParam.getSpecification().getName().equals(exceptionParam.getName())) { + builder.string("ex.getResult()"); + } else { + builder.string(valueVariableName(spec)); + } + } + } + builder.end().end(); // call operation + + builder.end(); // statement + + builder.declaration(forParam.getActualType(), valueVariableName(forParam), + CodeTreeBuilder.createBuilder().defaultValue(forParam.getActualType())); + builder.startIf().string(valueVariableName(shortCircuitParam)).end(); + builder.startBlock(); + + return true; + } + + + private void endShortCircuit(CodeTreeBuilder builder, boolean shortCircuit) { + if (shortCircuit) { + builder.end(); + } + } + + private void buildSpecializedValueExecute(CodeTreeBuilder builder, OperationData operation, SpecializationData specialization, ActualParameter param) { + boolean shortCircuit = startShortCircuit(builder, specialization, param, null); + + if (!shortCircuit) { + builder.startStatement().type(param.getActualType()).string(" ").string(valueVariableName(param)).end(); + } + + builder.startTryBlock(); + builder.startStatement().string(valueVariableName(param)).string(" = "); + builder.startCall(nodeVariableName(param), executeMethodName(param.getActualTypeData(operation.getTypeSystem()))).string("frame").end(); + builder.end(); + + builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); + boolean execute = false; + for (ActualParameter exParam : specialization.getParameters()) { + if (exParam.getSpecification().getKind() != Kind.EXECUTE) { + // Nothing to do. + } else if (execute) { + buildGenericValueExecute(builder, operation, exParam, param.getSpecification()); + } else if (exParam == param) { + execute = true; + } + } + + buildThrowSpecialize(builder, operation, specialization.findNextSpecialization(), param.getSpecification()); + builder.end(); // catch block + + endShortCircuit(builder, shortCircuit); + builder.newLine(); + } + + private void buildThrowSpecialize(CodeTreeBuilder builder, OperationData operation, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) { + builder.startThrow().startCall("specialize"); + builder.string(nodeClassName(nextSpecialization) + ".class"); + addValueNames(builder, operation, kinds(Kind.SIGNATURE)); + for (ParameterSpec spec : operation.getSpecification().getParameters()) { + if (spec.getKind() == Kind.EXECUTE || spec.getKind() == Kind.SHORT_CIRCUIT) { + if (spec == exceptionSpec) { + builder.string("ex.getResult()"); + } else { + builder.string(valueVariableName(spec)); + } + } + } + builder.end().end(); + } + + private void buildSpecializeStateMethod(CodeTypeElement clazz, OperationData operation) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), getUnexpectedValueException(), "specialize"); + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); + addValueParameters(method, operation, kinds(Kind.SIGNATURE, Kind.EXECUTE, Kind.SHORT_CIRCUIT)); + clazz.add(method); + CodeTreeBuilder builder = method.createBuilder(); + + for (TemplateMethod listener : operation.getSpecializationListeners()) { + builder.startStatement(); + startCallOperationMethod(builder, operation, listener); + for (ActualParameter param : listener.getParameters()) { + builder.string(valueVariableName(param)); + } + builder.end().end(); + builder.end(); // statement + } + + builder.startStatement(); + builder.startCall("replace"); + builder.startCall(factoryClassName(operation), "specialize").string("minimumState"); + addOperationFieldName(builder, operation); + addValueNames(builder, operation, kinds(Kind.EXECUTE)); + addNodeNames(builder, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + builder.end().end().end(); + + builder.startReturn().startNew(getUnexpectedValueException()).startCall(factoryClassName(operation), "generatedGeneric"); + addOperationFieldName(builder, operation); + addValueNames(builder, operation, kinds(Kind.SIGNATURE, Kind.EXECUTE, Kind.SHORT_CIRCUIT, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + builder.end().end().end(); + } + + private void buildSpecializeClassMethod(CodeTypeElement clazz, OperationData operation) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), getContext().getType(void.class), "specialize"); + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "specializationClass")); + if (!isDeclaredMethodInSuperType(clazz, method.getSimpleName().toString(), method.getParameterTypes())) { + return; + } + clazz.add(method); + CodeTreeBuilder builder = method.createBuilder(); + + builder.startStatement(); + builder.startCall("replace"); + builder.startCall(factoryClassName(operation), "createSpecialized").string("specializationClass"); + addOperationFieldName(builder, operation); + addNodeNames(builder, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); + builder.end().end().end(); + } + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationData.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.typesystem.*; + +public class OperationData extends Template { + + private final TypeSystemData typeSystem; + private final String[] values; + private final String[] shortCircuitValues; + private final OperationFieldData[] operationFields; + private final OperationFieldData[] constructorFields; + private final OperationFieldData[] superFields; + private final TypeMirror nodeType; + + private MethodSpec specification; + private SpecializationData genericSpecialization; + private SpecializationData[] specializations; + private TemplateMethod[] specializationListeners; + private GuardData[] guards; + + boolean generateFactory = true; + + public OperationData(TypeElement templateType, AnnotationMirror templateTypeAnnotation, + TypeSystemData typeSystem, TypeMirror nodeType, + String[] values, String[] shortCircuitValues, + OperationFieldData[] operationFields, + OperationFieldData[] constructorFields, + OperationFieldData[] superFields) { + super(templateType, templateTypeAnnotation); + this.nodeType = nodeType; + this.typeSystem = typeSystem; + this.values = values; + this.shortCircuitValues = shortCircuitValues; + this.operationFields = operationFields; + this.constructorFields = constructorFields; + this.superFields = superFields; + } + + public boolean isUseSingleton() { + return constructorFields.length == 0; + } + + public boolean hasExtensions() { + return !getExtensionElements().isEmpty(); + } + + public List findGuards(String name) { + List foundGuards = new ArrayList<>(); + for (GuardData guardData : guards) { + if (guardData.getMethodName().equals(name)) { + foundGuards.add(guardData); + } + } + for (GuardData guardData : getTypeSystem().getGuards()) { + if (guardData.getMethodName().equals(name)) { + foundGuards.add(guardData); + } + } + return foundGuards; + } + + + void setGuards(GuardData[] guards) { + this.guards = guards; + } + + void setSpecification(MethodSpec specification) { + this.specification = specification; + } + + void setGenericSpecialization(SpecializationData genericSpecialization) { + this.genericSpecialization = genericSpecialization; + } + + void setSpecializations(SpecializationData[] specializations) { + this.specializations = specializations; + for (SpecializationData specialization : specializations) { + specialization.setOperation(this); + } + } + + void setSpecializationListeners(TemplateMethod[] specializationListeners) { + this.specializationListeners = specializationListeners; + } + + public String[] getValues() { + return values; + } + + public OperationFieldData[] getOperationFields() { + return operationFields; + } + + public String[] getShortCircuitValues() { + return shortCircuitValues; + } + + public TypeSystemData getTypeSystem() { + return typeSystem; + } + + public TypeMirror getNodeType() { + return nodeType; + } + + public SpecializationData[] getSpecializations() { + return specializations; + } + + public SpecializationData getGenericSpecialization() { + return genericSpecialization; + } + + public OperationFieldData[] getConstructorFields() { + return constructorFields; + } + + public OperationFieldData[] getSuperFields() { + return superFields; + } + + public MethodSpec getSpecification() { + return specification; + } + + public SpecializationData[] getAllMethods() { + return specializations; + } + + public boolean needsRewrites() { + boolean needsRewrites = getValues().length > 0 || getShortCircuitValues().length > 0; + needsRewrites &= specializations.length >= 2; + return needsRewrites; + } + + public TemplateMethod[] getSpecializationListeners() { + return specializationListeners; + } + + public GuardData[] getGuards() { + return guards; + } + + public SpecializationData findUniqueSpecialization(TypeData type) { + SpecializationData result = null; + for (SpecializationData specialization : specializations) { + if (specialization.getReturnType().getActualTypeData(getTypeSystem()) == type) { + if (result != null) { + // Result not unique; + return null; + } + result = specialization; + } + } + return result; + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationFieldData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationFieldData.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; + +public class OperationFieldData { + + private final String name; + private final TypeMirror javaClass; + + public OperationFieldData(String name, TypeMirror javaClass) { + this.name = name; + this.javaClass = javaClass; + } + + public String getName() { + return name; + } + + public TypeMirror getJavaClass() { + return javaClass; + } + + @Override + public String toString() { + return Utils.getSimpleName(javaClass); + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationMethodParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationMethodParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import java.util.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; + + +public abstract class OperationMethodParser extends TemplateMethodParser{ + + private final OperationData operation; + + public OperationMethodParser(ProcessorContext context, OperationData operation) { + super(context); + this.operation = operation; + } + + public OperationData getOperation() { + return operation; + } + + protected ParameterSpec createValueParameterSpec(String valueName) { + return new ParameterSpec(valueName, operation.getTypeSystem(), + Kind.EXECUTE, false, Cardinality.ONE); + } + + protected ParameterSpec createReturnParameterSpec() { + return createValueParameterSpec("operation"); + } + + protected final MethodSpec createDefaultMethodSpec(String shortCircuitName) { + List defaultParameters = new ArrayList<>(); + ParameterSpec frameSpec = new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), Kind.SIGNATURE, true); + defaultParameters.add(frameSpec); + + for (String valueName : operation.getValues()) { + defaultParameters.add(createValueParameterSpec(valueName)); + } + + for (String valueName : operation.getShortCircuitValues()) { + if (shortCircuitName != null && valueName.equals(shortCircuitName)) { + break; + } + + defaultParameters.add(new ParameterSpec(shortCircuitValueName(valueName), + getContext().getType(boolean.class), Kind.SHORT_CIRCUIT, false)); + + defaultParameters.add(createValueParameterSpec(valueName)); + } + + for (OperationFieldData field : operation.getSuperFields()) { + defaultParameters.add(new ParameterSpec(field.getName(), field.getJavaClass(), Kind.SUPER_ATTRIBUTE, true)); + } + + for (OperationFieldData field : operation.getOperationFields()) { + defaultParameters.add(new ParameterSpec(field.getName(), field.getJavaClass(), Kind.ATTRIBUTE, false)); + } + + return new MethodSpec(createReturnParameterSpec(), defaultParameters); + } + + private static String shortCircuitValueName(String valueName) { + return "has" + Utils.firstLetterUpperCase(valueName) + "Value"; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.ast.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; +import com.oracle.truffle.codegen.processor.typesystem.*; + +public class OperationParser extends TemplateParser { + + public OperationParser(ProcessorContext c) { + super(c); + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return com.oracle.truffle.api.codegen.Operation.class; + } + + @Override + protected OperationData parse(Element element, AnnotationMirror templateTypeAnnotation) { + TypeElement templateType = (TypeElement) element; + + if (!verifyTemplateType(templateType, templateTypeAnnotation)) { + return null; + } + + TypeMirror typeSystemMirror = Utils.getAnnotationValueType(templateTypeAnnotation, "typeSystem"); + final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSystemMirror, true); + if (typeSystem == null) { + log.error(templateType, templateTypeAnnotation, "Type system '%s' is invalid.", Utils.getQualifiedName(typeSystemMirror)); + return null; + } + + TypeMirror nodeType = Utils.getAnnotationValueType(templateTypeAnnotation, "baseClass"); + if (Utils.typeEquals(nodeType, context.getTruffleTypes().getNode())) { + nodeType = typeSystem.getNodeType(); + } + + if (!Utils.isAssignable(nodeType, typeSystem.getNodeType())) { + log.error(templateType, templateTypeAnnotation, + Utils.getAnnotationValue(templateTypeAnnotation, "baseClass"), + "The baseClass does not extend the base class of the type system '%s'.", Utils.getQualifiedName(typeSystem.getNodeType())); + return null; + } + + for (VariableElement field : ElementFilter.fieldsIn(templateType.getEnclosedElements())) { + if (!field.getModifiers().contains(Modifier.STATIC) + && !field.getModifiers().contains(Modifier.FINAL)) { + log.error(field, "Field must be final."); + return null; + } + } + + + List valueNames = Utils.getAnnotationValueList(templateTypeAnnotation, "values"); + List shortCircuitNames = Utils.getAnnotationValueList(templateTypeAnnotation, "shortCircuitValues"); + + List names = new ArrayList<>(); + names.addAll(valueNames); + names.addAll(shortCircuitNames); + + List fieldAnnotations = Collections.emptyList(); // call collectionAnnotations instead if you want OperationField support enabled. + List fields = new ArrayList<>(); + for (AnnotationMirror fieldMirror : fieldAnnotations) { + String name = Utils.getAnnotationValueString(fieldMirror, "name"); + TypeMirror javaClass = Utils.getAnnotationValueType(fieldMirror, "javaClass"); + fields.add(new OperationFieldData(name, javaClass)); + names.add(name); + } + + List constructorFields = parseConstructorFields(templateType, true); + if (constructorFields == null) { + return null; + } + + List superConstructorFields = parseConstructorFields(Utils.fromTypeMirror(nodeType), false); + if (superConstructorFields == null) { + return null; + } + + List protectedSuperFields = parseProtectedFields(Utils.fromTypeMirror(nodeType)); + if (protectedSuperFields == null) { + return null; + } + + List matchedSuperFields = matchFields(superConstructorFields, protectedSuperFields); + if (matchedSuperFields == null) { + log.error(templateType, templateTypeAnnotation, Utils.getAnnotationValue(templateTypeAnnotation, "baseClass"), + "The signature of the protected fields (%s) and the first constructor(%s) in %s does not match.", + protectedSuperFields.toString(), + superConstructorFields.toString(), + Utils.getQualifiedName(nodeType)); + return null; + } + + for (OperationFieldData field : constructorFields) { + names.add(field.getName()); + } + + for (OperationFieldData field : matchedSuperFields) { + names.add(field.getName()); + } + + if (!verifyNames(templateType, templateTypeAnnotation, names)) { + return null; + } + + OperationData operationData = new OperationData(templateType, templateTypeAnnotation, typeSystem, nodeType, + valueNames.toArray(new String[valueNames.size()]), + shortCircuitNames.toArray(new String[shortCircuitNames.size()]), + fields.toArray(new OperationFieldData[fields.size()]), + constructorFields.toArray(new OperationFieldData[constructorFields.size()]), + matchedSuperFields.toArray(new OperationFieldData[matchedSuperFields.size()])); + + if (!verifyExclusiveMethodAnnotation(templateType, + Specialization.class, Generic.class, SpecializationListener.class, ShortCircuit.class, GuardCheck.class)) { + return noFactory(operationData); + } + + operationData.setExtensionElements(getExtensionParser().parseAll(templateType)); + + List genericSpecializations = parseMethods(operationData, new GenericParser(context, operationData)); + List guards = parseMethods(operationData, new GuardParser(context, operationData.getTypeSystem(), operationData)); + operationData.setGuards(guards.toArray(new GuardData[guards.size()])); + + SpecializationParser specializationParser = new SpecializationParser(context, operationData); + operationData.setSpecification(specializationParser.getSpecification()); + List specializations = parseMethods(operationData, specializationParser); + List shortCircuits = parseMethods(operationData, new ShortCircuitParser(context, operationData)); + List listeners = parseMethods(operationData, new SpecializationListenerParser(context, operationData)); + + if (specializations == null || genericSpecializations == null || shortCircuits == null || listeners == null || guards == null) { + return noFactory(operationData); + } + + + SpecializationData genericSpecialization = null; + if (genericSpecializations.size() > 1) { + for (SpecializationData generic : genericSpecializations) { + log.error(generic.getMethod(), "Only one method with @%s is allowed per operation.", Generic.class.getSimpleName()); + } + return noFactory(operationData); + } else if (genericSpecializations.size() == 1) { + genericSpecialization = genericSpecializations.get(0); + } + + if (specializations.size() > 1 && genericSpecialization == null) { + log.error(templateType, "Need a @%s method.", Generic.class.getSimpleName()); + return noFactory(operationData); + } + + Collections.sort(specializations, new Comparator() { + @Override + public int compare(SpecializationData o1, SpecializationData o2) { + return compareSpecialization(typeSystem, o1, o2); + } + }); + + List allSpecializations = new ArrayList<>(specializations); + if (genericSpecialization != null) { + allSpecializations.add(genericSpecialization); + TemplateMethod uninializedMethod = new TemplateMethod(genericSpecialization.getSpecification(), new CodeExecutableElement(context.getType(void.class), "doUninialized"), + genericSpecialization.getMarkerAnnotation(), genericSpecialization.getReturnType(), genericSpecialization.getParameters()); + allSpecializations.add(0, new SpecializationData(uninializedMethod, false, true)); + } + + // verify order is not ambiguous + verifySpecializationOrder(typeSystem, specializations); + + operationData.setGenericSpecialization(genericSpecialization); + operationData.setSpecializations(allSpecializations.toArray(new SpecializationData[allSpecializations.size()])); + operationData.setSpecializationListeners(listeners.toArray(new TemplateMethod[listeners.size()])); + + if (!assignShortCircuitsToSpecializations(operationData, allSpecializations, shortCircuits)) { + return null; + } + + if (!verifyNamingConvention(specializations, "do")) { + return noFactory(operationData); + } + + if (!verifyNamesUnique(specializations)) { + return noFactory(operationData); + } + + if (!verifyNamingConvention(shortCircuits, "needs")) { + return noFactory(operationData); + } + + if (!verifySpecializationThrows(typeSystem, specializations)) { + return noFactory(operationData); + } + + return operationData; + } + + private static List matchFields(List params, + List fields) { + + if (params.size() != fields.size()) { + return null; + } + + List matchedFields = new ArrayList<>(); + for (int i = 0; i < params.size(); i++) { + OperationFieldData param = params.get(i); + OperationFieldData field = fields.get(i); + if (!Utils.typeEquals(param.getJavaClass(), field.getJavaClass())) { + return null; + } + matchedFields.add(new OperationFieldData(field.getName(), param.getJavaClass())); + } + + return matchedFields; + } + + private static List parseProtectedFields(Element element) { + List opFields = new ArrayList<>(); + List fields = ElementFilter.fieldsIn(element.getEnclosedElements()); + for (VariableElement var : fields) { + if (var.getModifiers().contains(Modifier.STATIC)) { + continue; + } + + if (var.getModifiers().contains(Modifier.PROTECTED)) { + opFields.add(new OperationFieldData(var.getSimpleName().toString(), var.asType())); + } + } + return opFields; + + } + + private List parseConstructorFields(Element element, boolean failOnMultipleConstructors) { + if (element == null) { + return Collections.emptyList(); + } + + List constructors = ElementFilter.constructorsIn(element.getEnclosedElements()); + ExecutableElement constructor = null; + if (constructors.size() > 1) { + if (failOnMultipleConstructors) { + for (ExecutableElement c : constructors) { + log.error(c, "The Operation annotated class must not define multiple constructors."); + } + return null; + } else { + // take first constructor + constructor = constructors.get(0); + } + } else if (constructors.size() == 1) { + constructor = constructors.get(0); + } + + List constructorFields = new ArrayList<>(); + if (constructor != null) { + for (VariableElement var : constructor.getParameters()) { + constructorFields.add(new OperationFieldData(var.getSimpleName().toString(), var.asType())); + } + } + return constructorFields; + } + + private static OperationData noFactory(OperationData data) { + data.generateFactory = false; + return data; + } + + private boolean verifySpecializationThrows(TypeSystemData typeSystem, List specializations) { + Map specializationMap = new HashMap<>(); + for (SpecializationData spec : specializations) { + specializationMap.put(spec.getMethodName(), spec); + } + boolean valid = true; + for (SpecializationData sourceSpecialization : specializations) { + if (sourceSpecialization.getExceptions() != null) { + for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) { + SpecializationData targetSpecialization = specializationMap.get(throwsData.getTransitionToName()); + AnnotationValue value = Utils.getAnnotationValue(throwsData.getAnnotationMirror(), "transitionTo"); + if (targetSpecialization == null) { + log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), value, + "Specialization with name '%s' not found.", throwsData.getTransitionToName()); + valid = false; + } else if (compareSpecialization(typeSystem, sourceSpecialization, targetSpecialization) >= 0) { + log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), value, + "The order of the target specializalization must be higher than the source specialization.", throwsData.getTransitionToName()); + valid = false; + } + + for (SpecializationThrowsData otherThrowsData : sourceSpecialization.getExceptions()) { + if (otherThrowsData != throwsData + && Utils.typeEquals(otherThrowsData.getJavaClass(), throwsData.getJavaClass())) { + AnnotationValue javaClassValue = Utils.getAnnotationValue(throwsData.getAnnotationMirror(), "javaClass"); + log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), javaClassValue, + "Duplicate exception type.", throwsData.getTransitionToName()); + valid = false; + } + } + } + } + } + return valid; + } + + + private boolean assignShortCircuitsToSpecializations(OperationData operation, + List specializations, + List shortCircuits) { + + Map> groupedShortCircuits = groupShortCircuits(shortCircuits); + + boolean valid = true; + + for (String valueName : operation.getShortCircuitValues()) { + List availableCircuits = groupedShortCircuits.get(valueName); + + if (availableCircuits == null || availableCircuits.isEmpty()) { + log.error(operation.getTemplateType(), operation.getTemplateTypeAnnotation(), + "@%s method for short cut value '%s' required.", + ShortCircuit.class.getSimpleName(), valueName); + valid = false; + continue; + } + + + boolean sameMethodName = true; + String methodName = availableCircuits.get(0).getMethodName(); + for (ShortCircuitData circuit : availableCircuits) { + if (!circuit.getMethodName().equals(methodName)) { + sameMethodName = false; + } + } + + if (!sameMethodName) { + for (ShortCircuitData circuit : availableCircuits) { + log.error(circuit.getMethod(), circuit.getMarkerAnnotation(), "All short circuits for short cut value '%s' must have the same method name.", valueName); + } + valid = false; + continue; + } + + ShortCircuitData genericCircuit = null; + for (ShortCircuitData circuit : availableCircuits) { + if (isGenericShortCutMethod(circuit, operation.getTypeSystem().getGenericType())) { + genericCircuit = circuit; + break; + } + } + + if (genericCircuit == null) { + log.error(operation.getTemplateType(), operation.getTemplateTypeAnnotation(), + "No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName); + valid = false; + continue; + } + + for (ShortCircuitData circuit : availableCircuits) { + if (circuit != genericCircuit) { + circuit.setGenericShortCircuitMethod(genericCircuit); + } + } + } + + if (!valid) { + return valid; + } + + for (SpecializationData specialization : specializations) { + ShortCircuitData[] assignedShortCuts = new ShortCircuitData[operation.getShortCircuitValues().length]; + + for (int i = 0; i < operation.getShortCircuitValues().length; i++) { + List availableShortCuts = groupedShortCircuits.get(operation.getShortCircuitValues()[i]); + + ShortCircuitData genericShortCircuit = null; + for (ShortCircuitData circuit : availableShortCuts) { + if (circuit.isGeneric()) { + genericShortCircuit = circuit; + } else if (circuit.isCompatibleTo(specialization)) { + assignedShortCuts[i] = circuit; + } + } + + if (assignedShortCuts[i] == null) { + assignedShortCuts[i] = genericShortCircuit; + } + } + specialization.setShortCircuits(assignedShortCuts); + } + return true; + } + + private static boolean isGenericShortCutMethod(TemplateMethod method, TypeMirror genericType) { + for (ActualParameter parameter : method.getParameters()) { + if (parameter.getSpecification().getKind() == Kind.EXECUTE) { + if (!Utils.typeEquals(genericType, parameter.getActualType())) { + return false; + } + } + } + return true; + } + + private static Map> groupShortCircuits(List shortCircuits) { + Map> group = new HashMap<>(); + for (ShortCircuitData shortCircuit : shortCircuits) { + List circuits = group.get(shortCircuit.getValueName()); + if (circuits == null) { + circuits = new ArrayList<>(); + group.put(shortCircuit.getValueName(), circuits); + } + circuits.add(shortCircuit); + } + return group; + } + + private boolean verifyNamingConvention(List methods, String prefix) { + boolean valid = true; + for (int i = 0; i < methods.size(); i++) { + TemplateMethod m1 = methods.get(i); + if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) { + log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Naming convention: method name must start with '%s'.", prefix); + valid = false; + } + } + return valid; + } + + private boolean verifyNamesUnique(List methods) { + boolean valid = true; + for (int i = 0; i < methods.size(); i++) { + TemplateMethod m1 = methods.get(i); + for (int j = i + 1; j < methods.size(); j++) { + TemplateMethod m2 = methods.get(j); + + if (m1.getMethodName().equalsIgnoreCase(m2.getMethodName())) { + log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName()); + log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName()); + return false; + } + } + } + return valid; + } + + private boolean verifySpecializationOrder(TypeSystemData typeSystem, List specializations) { + for (int i = 0; i < specializations.size(); i++) { + SpecializationData m1 = specializations.get(i); + for (int j = i + 1; j < specializations.size(); j++) { + SpecializationData m2 = specializations.get(j); + int inferredOrder = compareSpecializationWithoutOrder(typeSystem, m1, m2); + + if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { + int specOrder = m1.getOrder() - m2.getOrder(); + if (specOrder == 0) { + log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder()); + log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder()); + return false; + } else if ((specOrder < 0 && inferredOrder > 0) || (specOrder > 0 && inferredOrder < 0)) { + log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); + log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); + return false; + } + } else if (inferredOrder == 0) { + SpecializationData m = (m1.getOrder() == Specialization.DEFAULT_ORDER ? m1 : m2); + log.error(m.getMethod(), m.getMarkerAnnotation(), "Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this."); + return false; + } + } + } + return true; + } + + private static int compareSpecialization(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) { + int result = compareSpecializationWithoutOrder(typeSystem, m1, m2); + if (result == 0) { + if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { + return m1.getOrder() - m2.getOrder(); + } + } + return result; + } + + private static int compareSpecializationWithoutOrder(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) { + if (m1.getSpecification() != m2.getSpecification()) { + throw new UnsupportedOperationException("Cannot compare two specializations with different specifications."); + } + + int result = compareActualParameter(typeSystem, m1.getReturnType(), m2.getReturnType()); + + for (ParameterSpec spec : m1.getSpecification().getParameters()) { + ActualParameter p1 = m1.findParameter(spec); + ActualParameter p2 = m2.findParameter(spec); + + if (p1 != null && p2 != null && !Utils.typeEquals(p1.getActualType(), p2.getActualType())) { + int typeResult = compareActualParameter(typeSystem, p1, p2); + if (result == 0) { + result = typeResult; + } else if (Math.signum(result) != Math.signum(typeResult)) { + // We cannot define an order. + return 0; + } + } + } + return result; + } + + private static int compareActualParameter(TypeSystemData typeSystem, ActualParameter p1, ActualParameter p2) { + int index1 = typeSystem.findType(p1.getActualType()); + int index2 = typeSystem.findType(p2.getActualType()); + + assert index1 != index2; + assert !(index1 == -1 ^ index2 == -1); + + return index1 - index2; + } + + private boolean verifyNames(TypeElement element, AnnotationMirror mirror, List names) { + boolean valid = true; + + for (int i = 0; i < names.size(); i++) { + String name = names.get(i); + if (!JavaName.isValid(name)) { + log.error(element, mirror, "Name '%s' is not a valid java identifier.", name); + valid = false; + } else if (JavaName.isReserved(name)) { + log.error(element, mirror, "Name '%s' is a reserved java identifier.", name); + valid = false; + } + for (int j = i + 1; j < names.size(); j++) { + String otherName = names.get(j); + if (name.equalsIgnoreCase(otherName)) { + log.error(element, mirror, "Name '%s' is not unique.", name); + valid = false; + } + } + } + return valid; + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/ShortCircuitData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/ShortCircuitData.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; + + +public class ShortCircuitData extends TemplateMethod { + + private ShortCircuitData genericShortCircuitMethod; + + private final String valueName; + + public ShortCircuitData(TemplateMethod template, String valueName) { + super(template); + this.valueName = valueName; + } + + public String getValueName() { + return valueName; + } + + public void setGenericShortCircuitMethod(ShortCircuitData genericShortCircuitMethod) { + this.genericShortCircuitMethod = genericShortCircuitMethod; + } + + public boolean isGeneric() { + return genericShortCircuitMethod == null; + } + + public ShortCircuitData getGeneric() { + if (isGeneric()) { + return this; + } else { + return genericShortCircuitMethod; + } + } + + public boolean isCompatibleTo(SpecializationData specialization) { + if (isGeneric() && specialization.isGeneric()) { + return true; + } + + for (ActualParameter param : getParameters()) { + ParameterSpec paramSpec = param.getSpecification(); + if (paramSpec.getKind() == Kind.EXECUTE) { + ActualParameter specializationParam = specialization.findParameter(paramSpec.getName()); + if (!Utils.typeEquals(param.getActualType(), specializationParam.getActualType())) { + return false; + } + } + } + return true; + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/ShortCircuitParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/ShortCircuitParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; + + +public class ShortCircuitParser extends OperationMethodParser { + + private final Set shortCircuitValues; + + public ShortCircuitParser(ProcessorContext context, OperationData operation) { + super(context, operation); + shortCircuitValues = new HashSet<>(Arrays.asList(operation.getShortCircuitValues())); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + String shortCircuitValue = Utils.getAnnotationValueString(mirror, "value"); + + if (!shortCircuitValues.contains(shortCircuitValue)) { + getContext().getLog().error(method, mirror, "Invalid short circuit value %s.", shortCircuitValue); + return null; + } + + return createDefaultMethodSpec(shortCircuitValue); + } + + @Override + protected ParameterSpec createReturnParameterSpec() { + return new ParameterSpec("has", getContext().getType(boolean.class), Kind.SHORT_CIRCUIT, false); + } + + @Override + public ShortCircuitData create(TemplateMethod method) { + String shortCircuitValue = Utils.getAnnotationValueString(method.getMarkerAnnotation(), "value"); + assert shortCircuitValue != null; + assert shortCircuitValues.contains(shortCircuitValue); + return new ShortCircuitData(method, shortCircuitValue); + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return ShortCircuit.class; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationData.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.template.*; + +public class SpecializationData extends TemplateMethod { + + private final int order; + private final boolean generic; + private final boolean uninitialized; + private final SpecializationThrowsData[] exceptions; + private SpecializationGuardData[] guards; + private ShortCircuitData[] shortCircuits; + + private OperationData operation; + + public SpecializationData(TemplateMethod template, int order, SpecializationThrowsData[] exceptions) { + super(template.getSpecification(), template.getMethod(), template.getMarkerAnnotation(), template.getReturnType(), template.getParameters()); + this.order = order; + this.generic = false; + this.uninitialized = false; + this.exceptions = exceptions; + + for (SpecializationThrowsData exception : exceptions) { + exception.setSpecialization(this); + } + } + + public SpecializationData(TemplateMethod template, boolean generic, boolean uninitialized) { + super(template.getSpecification(), template.getMethod(), template.getMarkerAnnotation(), template.getReturnType(), template.getParameters()); + this.order = Specialization.DEFAULT_ORDER; + this.generic = generic; + this.uninitialized = uninitialized; + this.exceptions = new SpecializationThrowsData[0]; + this.guards = new SpecializationGuardData[0]; + } + + public void setOperation(OperationData operation) { + this.operation = operation; + } + + void setGuards(SpecializationGuardData[] guards) { + this.guards = guards; + } + + public OperationData getOperation() { + return operation; + } + + public int getOrder() { + return order; + } + + public boolean isGeneric() { + return generic; + } + + public boolean isUninitialized() { + return uninitialized; + } + + public SpecializationThrowsData[] getExceptions() { + return exceptions; + } + + public SpecializationGuardData[] getGuards() { + return guards; + } + + public void setShortCircuits(ShortCircuitData[] shortCircuits) { + this.shortCircuits = shortCircuits; + } + + public ShortCircuitData[] getShortCircuits() { + return shortCircuits; + } + + public SpecializationData findNextSpecialization() { + SpecializationData[] allMethods = operation.getAllMethods(); + for (int i = 0; i < allMethods.length - 1; i++) { + if (allMethods[i] == this) { + return allMethods[i + 1]; + } + } + throw new IllegalArgumentException(); + } + + public boolean hasDynamicGuards() { + for (SpecializationGuardData guard : getGuards()) { + if (guard.isOnExecution()) { + return true; + } + } + return false; + } + + public ActualParameter getPreviousParam(ActualParameter searchParam) { + ActualParameter prev = null; + for (ActualParameter param : getParameters()) { + if (param == searchParam) { + return prev; + } + prev = param; + } + return prev; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationGuardData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationGuardData.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import com.oracle.truffle.codegen.processor.typesystem.*; + +public class SpecializationGuardData { + + private final String guardMethod; + private final boolean onSpecialization; + private final boolean onExecution; + + private GuardData guardDeclaration; + + public SpecializationGuardData(String guardMethod, boolean onSpecialization, boolean onExecution) { + this.guardMethod = guardMethod; + this.onSpecialization = onSpecialization; + this.onExecution = onExecution; + } + + public String getGuardMethod() { + return guardMethod; + } + + public boolean isOnExecution() { + return onExecution; + } + + public boolean isOnSpecialization() { + return onSpecialization; + } + + void setGuardDeclaration(GuardData compatibleGuard) { + this.guardDeclaration = compatibleGuard; + } + + public GuardData getGuardDeclaration() { + return guardDeclaration; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationListenerParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationListenerParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import java.lang.annotation.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; + + +public class SpecializationListenerParser extends OperationMethodParser { + + private final MethodSpec specification; + + public SpecializationListenerParser(ProcessorContext context, OperationData operation) { + super(context, operation); + this.specification = createDefaultMethodSpec(null); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + return specification; + } + + @Override + protected ParameterSpec createReturnParameterSpec() { + return new ParameterSpec("void", getContext().getType(void.class), Kind.ATTRIBUTE, false); + } + + @Override + public TemplateMethod create(TemplateMethod method) { + return method; + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return SpecializationListener.class; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; +import com.oracle.truffle.codegen.processor.typesystem.*; + + +public class SpecializationParser extends OperationMethodParser { + + private final MethodSpec specification; + + public SpecializationParser(ProcessorContext context, OperationData operation) { + super(context, operation); + this.specification = createDefaultMethodSpec(null); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + return specification; + } + public MethodSpec getSpecification() { + return specification; + } + + @Override + public SpecializationData create(TemplateMethod method) { + return parseSpecialization(method); + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return Specialization.class; + } + + private SpecializationData parseSpecialization(TemplateMethod template) { + int order = Utils.getAnnotationValueInt(template.getMarkerAnnotation(), "order"); + if (order < 0 && order != Specialization.DEFAULT_ORDER) { + getContext().getLog().error(template.getMethod(), template.getMarkerAnnotation(), "Invalid order attribute %d. The value must be >= 0 or the default value."); + return null; + } + + List exceptionDefs = Utils.collectAnnotations(getContext(), template.getMarkerAnnotation(), "exceptions", template.getMethod(), SpecializationThrows.class); + SpecializationThrowsData[] exceptionData = new SpecializationThrowsData[exceptionDefs.size()]; + for (int i = 0; i < exceptionData.length; i++) { + AnnotationMirror mirror = exceptionDefs.get(i); + TypeMirror javaClass = Utils.getAnnotationValueType(mirror, "javaClass"); + String transitionTo = Utils.getAnnotationValueString(mirror, "transitionTo"); + exceptionData[i] = new SpecializationThrowsData(mirror, javaClass, transitionTo); + + if (!Utils.canThrowType(template.getMethod().getThrownTypes(), javaClass)) { + getContext().getLog().error(template.getMethod(), "Method must specify a throws clause with the exception type '%s'.", Utils.getQualifiedName(javaClass)); + return null; + } + } + + Arrays.sort(exceptionData, new Comparator() { + @Override + public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) { + return Utils.compareByTypeHierarchy(o1.getJavaClass(), o2.getJavaClass()); + } + }); + SpecializationData specialization = new SpecializationData(template, order, exceptionData); + + boolean valid = true; + List guardDefs = Utils.collectAnnotations(getContext(), template.getMarkerAnnotation(), "guards", template.getMethod(), SpecializationGuard.class); + SpecializationGuardData[] guardData = new SpecializationGuardData[guardDefs.size()]; + for (int i = 0; i < guardData.length; i++) { + AnnotationMirror guardMirror = guardDefs.get(i); + String guardMethod = Utils.getAnnotationValueString(guardMirror, "methodName"); + boolean onSpecialization = Utils.getAnnotationValueBoolean(guardMirror, "onSpecialization"); + boolean onExecution = Utils.getAnnotationValueBoolean(guardMirror, "onExecution"); + + if (!onSpecialization && !onExecution) { + String message = "Either onSpecialization, onExecution or both must be enabled."; + getContext().getLog().error(template.getMethod(), guardMirror, message); + valid = false; + continue; + } + + guardData[i] = new SpecializationGuardData(guardMethod, onSpecialization, onExecution); + + GuardData compatibleGuard = matchSpecializationGuard(guardMirror, specialization, guardData[i]); + if (compatibleGuard != null) { + guardData[i].setGuardDeclaration(compatibleGuard); + } else { + valid = false; + } + } + + if (!valid) { + return null; + } + + specialization.setGuards(guardData); + + return specialization; + } + + private GuardData matchSpecializationGuard(AnnotationMirror mirror, SpecializationData specialization, SpecializationGuardData specializationGuard) { + List foundGuards = getOperation().findGuards(specializationGuard.getGuardMethod()); + GuardData compatibleGuard = null; + for (GuardData guardData : foundGuards) { + if (isGuardCompatible(specialization, guardData)) { + compatibleGuard = guardData; + break; + } + } + + if (compatibleGuard == null) { + ParameterSpec returnTypeSpec = new ParameterSpec("returnValue", getContext().getType(boolean.class), Kind.ATTRIBUTE, false); + List expectedParameterSpecs = new ArrayList<>(); + + for (ActualParameter param : filterGuardParameters(specialization)) { + ParameterSpec spec = param.getSpecification(); + expectedParameterSpecs.add(new ParameterSpec(spec.getName(), param.getActualType(), Kind.ATTRIBUTE, false)); + } + String expectedSignature = TemplateMethodParser.createExpectedSignature(specializationGuard.getGuardMethod(), returnTypeSpec, expectedParameterSpecs); + AnnotationValue value = Utils.getAnnotationValue(mirror, "methodName"); + getContext().getLog().error(specialization.getMethod(), mirror, value, "No guard with signature '%s' found in type system.", expectedSignature); + return null; + } + + return compatibleGuard; + } + + private static boolean isGuardCompatible(SpecializationData specialization, GuardData guard) { + Iterator guardParameters = Arrays.asList(guard.getParameters()).iterator(); + for (ActualParameter param : filterGuardParameters(specialization)) { + if (!guardParameters.hasNext()) { + return false; + } + ActualParameter guardParam = guardParameters.next(); + if (!Utils.typeEquals(guardParam.getActualType(), param.getActualType())) { + return false; + } + } + if (guardParameters.hasNext()) { + return false; + } + return true; + } + + private static List filterGuardParameters(SpecializationData specialization) { + List parameters = new ArrayList<>(); + for (ActualParameter param : specialization.getParameters()) { + if (param.getSpecification().getKind() != Kind.EXECUTE + && param.getSpecification().getKind() != Kind.SHORT_CIRCUIT) { + continue; + } + parameters.add(param); + } + return parameters; + } + + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationThrowsData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationThrowsData.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.operation; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class SpecializationThrowsData { + + private final AnnotationMirror annotationMirror; + private final TypeMirror javaClass; + private final String transitionTo; + private SpecializationData specialization; + + public SpecializationThrowsData(AnnotationMirror annotationMirror, TypeMirror javaClass, String transitionTo) { + this.annotationMirror = annotationMirror; + this.javaClass = javaClass; + this.transitionTo = transitionTo; + } + + + void setSpecialization(SpecializationData specialization) { + this.specialization = specialization; + } + + public TypeMirror getJavaClass() { + return javaClass; + } + + public SpecializationData getSpecialization() { + return specialization; + } + + public AnnotationMirror getAnnotationMirror() { + return annotationMirror; + } + + public String getTransitionToName() { + return transitionTo; + } + + public SpecializationData getTransitionTo() { + for (SpecializationData s : specialization.getOperation().getAllMethods()) { + if (s.getMethodName().equals(transitionTo)) { + return s; + } + } + throw new IllegalArgumentException(); + } +} + diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.template; + +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.typesystem.*; + +public class ActualParameter { + + private final ParameterSpec specification; + private final TypeMirror actualType; + + public ActualParameter(ParameterSpec specification, TypeMirror actualType) { + this.specification = specification; + this.actualType = actualType; + } + + public ParameterSpec getSpecification() { + return specification; + } + + public TypeMirror getActualType() { + return actualType; + } + + public TypeData getActualTypeData(TypeSystemData typeSystem) { + return typeSystem.getTypes()[typeSystem.findType(actualType)]; + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.template; + +import static com.oracle.truffle.codegen.processor.Utils.*; +import static javax.lang.model.element.Modifier.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.ast.*; + +public abstract class ClassElementFactory extends CodeElementFactory { + + public ClassElementFactory(ProcessorContext context) { + super(context); + } + + @Override + protected abstract CodeTypeElement create(M m); + + protected CodeExecutableElement createConstructorUsingFields(Set modifiers, CodeTypeElement clazz) { + CodeExecutableElement method = new CodeExecutableElement(modifiers, null, clazz.getSimpleName().toString()); + CodeTreeBuilder builder = method.createBuilder(); + TypeElement superClass = fromTypeMirror(clazz.getSuperclass()); + ExecutableElement constructor = findConstructor(superClass); + if (constructor != null && constructor.getParameters().size() > 0) { + builder.startStatement(); + builder.startSuperCall(); + for (VariableElement parameter : constructor.getParameters()) { + method.addParameter(new CodeVariableElement(parameter.asType(), parameter.getSimpleName().toString())); + builder.string(parameter.getSimpleName().toString()); + } + builder.end(); // super + builder.end(); // statement + } + + for (VariableElement field : clazz.getFields()) { + if (field.getModifiers().contains(STATIC)) { + continue; + } + String fieldName = field.getSimpleName().toString(); + method.addParameter(new CodeVariableElement(field.asType(), fieldName)); + builder.startStatement(); + builder.string("this."); + builder.string(fieldName); + builder.string(" = "); + if (isAssignable(field.asType(), getContext().getTruffleTypes().getNode())) { + builder.string("adoptChild(").string(fieldName).string(")"); + } else { + builder.string(fieldName); + } + builder.end(); // statement + } + + return method; + } + + private static ExecutableElement findConstructor(TypeElement clazz) { + List constructors = ElementFilter.constructorsIn(clazz.getEnclosedElements()); + if (constructors.isEmpty()) { + return null; + } else { + return constructors.get(0); + } + } + + protected CodeTypeElement createClass(Template model, Set modifiers, String simpleName, TypeMirror superType, boolean enumType) { + TypeElement templateType = model.getTemplateType(); + + PackageElement pack = getContext().getEnvironment().getElementUtils().getPackageOf(templateType); + CodeTypeElement clazz = new CodeTypeElement(modifiers, enumType ? ElementKind.ENUM : ElementKind.CLASS, pack, simpleName); + TypeMirror resolvedSuperType = superType; + if (resolvedSuperType == null) { + resolvedSuperType = getContext().getType(Object.class); + } + clazz.setSuperClass(resolvedSuperType); + + CodeAnnotationMirror generatedByAnnotation = new CodeAnnotationMirror((DeclaredType) getContext().getType(GeneratedBy.class)); + generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("value"), new CodeAnnotationValue(templateType.asType())); + clazz.addAnnotationMirror(generatedByAnnotation); + + context.registerType(model.getTemplateType(), clazz.asType()); + + return clazz; + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/CodeElementFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/CodeElementFactory.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.template; + +import javax.lang.model.element.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.ast.*; + +public abstract class CodeElementFactory { + + protected final ProcessorContext context; + private M model; + + private CodeElement element; + + public CodeElementFactory(ProcessorContext context) { + this.context = context; + } + + protected abstract CodeElement create(M m); + + @SuppressWarnings("unused") + protected void createChildren(M m) { } + + @SuppressWarnings("unchecked") + public final CodeElement process(M m) { + model = m; + element = (CodeElement) create(model); + if (element != null) { + createChildren(model); + } + return element; + } + + public CodeElement getElement() { + return element; + } + + protected void add(CodeElementFactory factory, MO m) { + this.element.add(factory.process(m)); + } + + public ProcessorContext getContext() { + return context; + } + + public M getModel() { + return model; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/CompilationUnitFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/CompilationUnitFactory.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.template; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.ast.*; + +public abstract class CompilationUnitFactory extends CodeElementFactory { + + public CompilationUnitFactory(ProcessorContext context) { + super(context); + } + + @Override + public final CodeCompilationUnit create(M m) { + return new CodeCompilationUnit(); + } + + @Override + protected abstract void createChildren(M m); + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/JavaName.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/JavaName.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.template; + +import java.util.*; +import java.util.regex.*; + + +public final class JavaName { + + private static final String[] RESERVED_NAMES = new String[]{"abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized", "boolean", "do", "if", + "private", "this", "break", "double", "implements", "protected", "throw", "byte", "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", + "catch", "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally", "long", "strictfp", "volatile", "const", "float", "native", "super", + "while"}; + + private static final Set RESERVED_NAMES_SET = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(RESERVED_NAMES))); + + private static final Pattern VALID_JAVA_NAME_PATTERN = Pattern.compile("[_a-zA-z][_a-zA-Z0-9]*"); + + private JavaName() { + super(); + } + + public static boolean isReserved(String name) { + return RESERVED_NAMES_SET.contains(name); + } + + public static boolean isValid(String typeName) { + return VALID_JAVA_NAME_PATTERN.matcher(typeName).matches(); + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.template; + +import java.util.*; + +public class MethodSpec { + + private final ParameterSpec returnType; + private final List parameters; + + public MethodSpec(ParameterSpec returnType, List parameters) { + this.returnType = returnType; + this.parameters = parameters; + } + + public ParameterSpec getReturnType() { + return returnType; + } + + public List getParameters() { + return parameters; + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.template; + +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.typesystem.*; + +public class ParameterSpec { + + public enum Kind { + EXECUTE, SIGNATURE, SUPER_ATTRIBUTE, ATTRIBUTE, CONSTRUCTOR_FIELD, SHORT_CIRCUIT + } + + public enum Cardinality { + ONE, MULTIPLE; + } + + private final String name; + private final TypeMirror[] allowedTypes; + private final TypeMirror valueType; + private final Kind kind; + private final boolean optional; + private final Cardinality cardinality; + + public ParameterSpec(String name, TypeMirror[] allowedTypes, TypeMirror valueType, Kind kind, boolean optional, Cardinality cardinality) { + this.valueType = valueType; + this.allowedTypes = allowedTypes; + this.name = name; + this.kind = kind; + this.optional = optional; + this.cardinality = cardinality; + } + + public ParameterSpec(String name, TypeMirror singleFixedType, Kind kind, boolean optional) { + this(name, new TypeMirror[]{singleFixedType}, singleFixedType, kind, optional, Cardinality.ONE); + } + + public ParameterSpec(String name, TypeSystemData typeSystem, Kind kind, boolean optional, Cardinality cardinality) { + this(name, typeSystem.getPrimitiveTypeMirrors(), typeSystem.getGenericType(), kind, optional, cardinality); + } + + public final String getName() { + return name; + } + + public Kind getKind() { + return kind; + } + + public final boolean isOptional() { + return optional; + } + + public final Cardinality getCardinality() { + return cardinality; + } + + public TypeMirror[] getAllowedTypes() { + return allowedTypes; + } + + public boolean matches(TypeMirror actualType) { + for (int i = 0; i < allowedTypes.length; i++) { + TypeMirror mirror = allowedTypes[i]; + if (Utils.typeEquals(actualType, mirror)) { + return true; + } + } + return false; + } + + public TypeMirror getValueType() { + return valueType; + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.template; + +import java.util.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.api.element.*; + +public abstract class Template { + + private final TypeElement templateType; + private final AnnotationMirror annotation; + + private List extensionElements; + + public Template(TypeElement templateType, AnnotationMirror annotation) { + this.templateType = templateType; + this.annotation = annotation; + } + + public TypeElement getTemplateType() { + return templateType; + } + + public AnnotationMirror getTemplateTypeAnnotation() { + return annotation; + } + + public List< ? extends WritableElement> getExtensionElements() { + return extensionElements; + } + + public void setExtensionElements(List< ? extends WritableElement> extensionMethods) { + this.extensionElements = extensionMethods; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + Utils.getSimpleName(getTemplateType()) + "]"; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.template; + +import javax.lang.model.element.*; + +public class TemplateMethod { + + private final MethodSpec specification; + private final ExecutableElement method; + private final AnnotationMirror markerAnnotation; + private final ActualParameter returnType; + private final ActualParameter[] parameters; + + public TemplateMethod(MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, ActualParameter[] parameters) { + this.specification = specification; + this.method = method; + this.markerAnnotation = markerAnnotation; + this.returnType = returnType; + this.parameters = parameters; + } + + public TemplateMethod(TemplateMethod method) { + this.specification = method.specification; + this.method = method.method; + this.markerAnnotation = method.markerAnnotation; + this.returnType = method.returnType; + this.parameters = method.parameters; + } + + + public MethodSpec getSpecification() { + return specification; + } + + public ActualParameter getReturnType() { + return returnType; + } + + public ActualParameter[] getParameters() { + return parameters; + } + + public ActualParameter findParameter(String valueName) { + for (ActualParameter param : getParameters()) { + if (param.getSpecification().getName().equals(valueName)) { + return param; + } + } + return null; + } + + public ActualParameter findParameter(ParameterSpec spec) { + for (ActualParameter param : getParameters()) { + if (param.getSpecification() == spec) { + return param; + } + } + return null; + } + + public ExecutableElement getMethod() { + return method; + } + + public String getMethodName() { + return getMethod().getSimpleName().toString(); + } + + public AnnotationMirror getMarkerAnnotation() { + return markerAnnotation; + } + + @Override + public String toString() { + return getClass().getSimpleName() + " [method = " + method + "]"; + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.template; + +import static com.oracle.truffle.codegen.processor.Utils.*; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; + +public abstract class TemplateMethodParser { + + private final ProcessorContext context; + + public TemplateMethodParser(ProcessorContext context) { + this.context = context; + } + + public ProcessorContext getContext() { + return context; + } + + public abstract MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror); + + public abstract E create(TemplateMethod method); + + public abstract Class getAnnotationType(); + + public final E parse(ExecutableElement method, AnnotationMirror annotation, Template template) { + MethodSpec methodSpecification = createSpecification(method, annotation); + if (methodSpecification == null) { + return null; + } + + ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); + List parameterSpecs = new ArrayList<>(); + parameterSpecs.addAll(methodSpecification.getParameters()); + + ActualParameter returnTypeMirror = resolveTypeMirror(returnTypeSpec, method.getReturnType(), template); + if (returnTypeMirror == null) { + String expectedReturnType = createTypeSignature(returnTypeSpec, true); + String actualReturnType = Utils.getSimpleName(method.getReturnType()); + + String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, + createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs)); + + context.getLog().error(method, annotation, message); + return null; + } + + Iterator< ? extends VariableElement> variableIterator = method.getParameters().iterator(); + Iterator< ? extends ParameterSpec> specificationIterator = parameterSpecs.iterator(); + + List resolvedMirrors = new ArrayList<>(); + VariableElement parameter = null; + ParameterSpec specification = null; + while (specificationIterator.hasNext() || specification != null) { + if (specification == null) { + specification = specificationIterator.next(); + } + + if (parameter == null && variableIterator.hasNext()) { + parameter = variableIterator.next(); + } + + if (parameter == null) { + if (specification.getCardinality() == Cardinality.MULTIPLE) { + specification = null; + continue; + } else if (!specification.isOptional()) { + // non option type specification found -> argument missing + String expectedType = createTypeSignature(specification, false); + + String message = String.format("Missing argument \"%s\".\nExpected signature: \n %s", expectedType, + createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs)); + + context.getLog().error(method, message); + return null; + } else { + // specification is optional -> continue + specification = null; + continue; + } + } + + ActualParameter resolvedMirror = resolveTypeMirror(specification, parameter.asType(), template); + + if (resolvedMirror == null) { + if (specification.isOptional()) { + specification = null; + continue; + } + + String expectedReturnType = createTypeSignature(specification, false); + String actualReturnType = Utils.getSimpleName(parameter.asType()) + " " + parameter.getSimpleName(); + + String message = String.format("The provided argument type \"%s\" does not match expected type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, + createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs)); + + context.getLog().error(parameter, message); + return null; + } + + resolvedMirrors.add(resolvedMirror); + parameter = null; // consume parameter + + if (specification.getCardinality() != Cardinality.MULTIPLE) { + specification = null; + } + } + + if (variableIterator.hasNext()) { + parameter = variableIterator.next(); + String actualReturnType = Utils.getSimpleName(parameter.asType()) + " " + parameter.getSimpleName(); + String message = String.format("No argument expected but found \"%s\".\nExpected signature: \n %s", actualReturnType, + createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs)); + + context.getLog().error(parameter, message); + return null; + } + + ActualParameter[] paramMirrors = resolvedMirrors.toArray(new ActualParameter[resolvedMirrors.size()]); + return create(new TemplateMethod(methodSpecification, method, annotation, returnTypeMirror, paramMirrors)); + } + + private ActualParameter resolveTypeMirror(ParameterSpec specification, TypeMirror mirror, Template typeSystem) { + TypeMirror resolvedType = mirror; + if (hasError(resolvedType)) { + resolvedType = context.resolveNotYetCompiledType(mirror, typeSystem); + } + + if (!specification.matches(resolvedType)) { + return null; + } + return new ActualParameter(specification, resolvedType); + } + + public static String createExpectedSignature(String methodName, ParameterSpec returnType, List< ? extends ParameterSpec> parameters) { + StringBuilder b = new StringBuilder(); + + b.append(" "); + b.append(createTypeSignature(returnType, true)); + + b.append(" "); + b.append(methodName); + b.append("("); + + for (int i = 0; i < parameters.size(); i++) { + ParameterSpec specification = parameters.get(i); + if (specification.isOptional()) { + b.append("["); + } + if (specification.getCardinality() == Cardinality.MULTIPLE) { + b.append("{"); + } + + b.append(createTypeSignature(specification, false)); + + if (specification.isOptional()) { + b.append("]"); + } + + if (specification.getCardinality() == Cardinality.MULTIPLE) { + b.append("}"); + } + + if (i < parameters.size() - 1) { + b.append(", "); + } + + } + + b.append(")"); + + TypeMirror[] types = null; + + //TODO allowed types may differ so different must be generated. + if (returnType.getAllowedTypes().length > 1) { + types = returnType.getAllowedTypes(); + } + for (ParameterSpec param : parameters) { + if (param.getAllowedTypes().length > 1) { + types = param.getAllowedTypes(); + } + } + if (types != null) { + b.append("\n\n "); + b.append(" = {"); + String separator = ""; + for (TypeMirror type : types) { + b.append(separator).append(Utils.getSimpleName(type)); + separator = ", "; + } + b.append("}"); + } + return b.toString(); + } + + private static String createTypeSignature(ParameterSpec spec, boolean typeOnly) { + StringBuilder builder = new StringBuilder(); + if (spec.getAllowedTypes().length > 1) { + builder.append(""); + } else if (spec.getAllowedTypes().length == 1) { + builder.append(Utils.getSimpleName(spec.getAllowedTypes()[0])); + } else { + builder.append("void"); + } + if (!typeOnly) { + builder.append(" "); + builder.append(spec.getName()); + } + return builder.toString(); + } + + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.template; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.api.element.*; +import com.oracle.truffle.codegen.processor.ext.*; + +public abstract class TemplateParser extends AbstractParser { + + private final ExtensionParser extensionParser; + + public TemplateParser(ProcessorContext c) { + super(c); + extensionParser = new ExtensionParser(c); + } + + public ExtensionParser getExtensionParser() { + return extensionParser; + } + + protected boolean verifyExclusiveMethodAnnotation(TypeElement type, Class ... annotationTypes) { + boolean valid = true; + List methods = ElementFilter.methodsIn(type.getEnclosedElements()); + for (ExecutableElement method : methods) { + List foundAnnotations = new ArrayList<>(); + for (int i = 0; i < annotationTypes.length; i++) { + Class annotationType = annotationTypes[i]; + AnnotationMirror mirror = Utils.findAnnotationMirror(context.getEnvironment(), method, annotationType); + if (mirror != null) { + foundAnnotations.add(mirror); + } + } + if (foundAnnotations.size() > 1) { + List annotationNames = new ArrayList<>(); + for (AnnotationMirror mirror : foundAnnotations) { + annotationNames.add("@" + Utils.getSimpleName(mirror.getAnnotationType())); + } + + for (AnnotationMirror mirror : foundAnnotations) { + context.getLog().error(method, mirror, "Non exclusive usage of annotations %s.", annotationNames); + } + valid = false; + } + } + return valid; + } + + protected boolean verifyTemplateType(TypeElement template, AnnotationMirror annotation) { + // annotation type on class path!? + boolean valid = true; + TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName()); + if (annotationTypeElement == null) { + log.error(template, annotation, "Required class " + getAnnotationType().getName() + " is not on the classpath."); + valid = false; + } + if (template.getModifiers().contains(Modifier.PRIVATE)) { + log.error(template, annotation, "The annotated class must have at least package protected visibility."); + valid = false; + } + + if (template.getModifiers().contains(Modifier.FINAL)) { + log.error(template, annotation, "The annotated class must not be final."); + valid = false; + } + + return valid; + } + + protected List parseMethods(Template template, TemplateMethodParser parser) { + TypeElement type = template.getTemplateType(); + + List methods = new ArrayList<>(); + methods.addAll(ElementFilter.methodsIn(type.getEnclosedElements())); + if (template.getExtensionElements() != null) { + for (WritableElement e : template.getExtensionElements()) { + if (e instanceof ExecutableElement) { + methods.add((ExecutableElement) e); + } + } + } + + List parsedMethods = new ArrayList<>(); + boolean valid = true; + for (ExecutableElement method : methods) { + AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, parser.getAnnotationType()); + if (mirror != null) { + if (method.getModifiers().contains(Modifier.PRIVATE)) { + log.error(method, "Methods annotated with @%s must not be private.", parser.getAnnotationType().getSimpleName()); + valid = false; + continue; + } + E parsedMethod = parser.parse(method, mirror, template); + if (parsedMethod != null) { + parsedMethods.add(parsedMethod); + } else { + valid = false; + } + } + } + if (!valid) { + return null; + } + return parsedMethods; + } + + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.typesystem; + +import com.oracle.truffle.codegen.processor.template.*; + + +public class GuardData extends TemplateMethod { + + private final Template origin; + + public GuardData(TemplateMethod method, Template origin) { + super(method); + this.origin = origin; + } + + public Template getOrigin() { + return origin; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.typesystem; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; + + +public class GuardParser extends TypeSystemMethodParser { + + private final Template origin; + + public GuardParser(ProcessorContext context, TypeSystemData typeSystem, Template origin) { + super(context, typeSystem); + this.origin = origin; + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + List specs = new ArrayList<>(); + specs.add(new ParameterSpec("value1", getTypeSystem(), Kind.EXECUTE, false, Cardinality.ONE)); + specs.add(new ParameterSpec("valueN", getTypeSystem(), Kind.EXECUTE, false, Cardinality.MULTIPLE)); + ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), Kind.ATTRIBUTE, false); + return new MethodSpec(returnTypeSpec, specs); + } + + @Override + public GuardData create(TemplateMethod method) { + return new GuardData(method, origin); + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return GuardCheck.class; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastData.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.typesystem; + +import com.oracle.truffle.codegen.processor.template.*; + +public class TypeCastData extends TemplateMethod { + + private final TypeData targetType; + private final TypeData sourceType; + + public TypeCastData(TemplateMethod method, TypeData sourceType, TypeData targetType) { + super(method); + this.sourceType = sourceType; + this.targetType = targetType; + } + + public boolean isGeneric() { + return sourceType.isGeneric(); + } + + public TypeData getSourceType() { + return sourceType; + } + + public TypeData getTargetType() { + return targetType; + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.typesystem; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; + + +class TypeCastParser extends TypeSystemMethodParser { + + public TypeCastParser(ProcessorContext context, TypeSystemData typeSystem) { + super(context, typeSystem); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + TypeData targetType = findTypeByMethodName(method, mirror, "as"); + if (targetType == null) { + return null; + } + List specs = new ArrayList<>(); + specs.add(new ParameterSpec("value", getTypeSystem(), Kind.EXECUTE, false, Cardinality.ONE)); + ParameterSpec returnTypeSpec = new ParameterSpec("returnType", targetType.getPrimitiveType(), Kind.ATTRIBUTE, false); + MethodSpec spec = new MethodSpec(returnTypeSpec, specs); + return spec; + } + + @Override + public TypeCastData create(TemplateMethod method) { + TypeData targetType = findTypeByMethodName(method.getMethod(), method.getMarkerAnnotation(), "as"); + ActualParameter parameter = method.findParameter("value"); + return new TypeCastData(method, parameter.getActualTypeData(getTypeSystem()), targetType); + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return TypeCast.class; + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckData.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.typesystem; + +import com.oracle.truffle.codegen.processor.template.*; + +public class TypeCheckData extends TemplateMethod { + + private final TypeData checkedType; + private final TypeData valueType; + + public TypeCheckData(TemplateMethod method, TypeData checkedType, TypeData valueType) { + super(method); + this.checkedType = checkedType; + this.valueType = valueType; + } + + public boolean isGeneric() { + return valueType.isGeneric(); + } + + public TypeData getCheckedType() { + return checkedType; + } + + public TypeData getValueType() { + return valueType; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.typesystem; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; + +class TypeCheckParser extends TypeSystemMethodParser { + + public TypeCheckParser(ProcessorContext context, TypeSystemData typeSystem) { + super(context, typeSystem); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + TypeData targetType = findTypeByMethodName(method, mirror, "is"); + if (targetType == null) { + return null; + } + List specs = new ArrayList<>(); + specs.add(new ParameterSpec("value", getTypeSystem(), Kind.EXECUTE, false, Cardinality.ONE)); + ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), Kind.ATTRIBUTE, false); + MethodSpec spec = new MethodSpec(returnTypeSpec, specs); + return spec; + } + + @Override + public TypeCheckData create(TemplateMethod method) { + TypeData checkedType = findTypeByMethodName(method.getMethod(), method.getMarkerAnnotation(), "is"); + assert checkedType != null; + ActualParameter parameter = method.findParameter("value"); + assert parameter != null; + return new TypeCheckData(method, checkedType, parameter.getActualTypeData(getTypeSystem())); + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return TypeCheck.class; + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.typesystem; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; + +public class TypeData extends Template { + + protected TypeSystemData typeSystem; + private final TypeMirror primitiveType; + private final TypeMirror boxedType; + + private final List typeCasts = new ArrayList<>(); + private final List typeChecks = new ArrayList<>(); + + public TypeData(TypeElement templateType, AnnotationMirror annotation, + TypeMirror primitiveType, TypeMirror boxedType) { + super(templateType, annotation); + this.primitiveType = primitiveType; + this.boxedType = boxedType; + } + + void addTypeCast(TypeCastData typeCast) { + this.typeCasts.add(typeCast); + } + + void addTypeCheck(TypeCheckData typeCheck) { + this.typeChecks.add(typeCheck); + } + + public List getTypeCasts() { + return typeCasts; + } + + public List getTypeChecks() { + return typeChecks; + } + + public TypeSystemData getTypeSystem() { + return typeSystem; + } + + public TypeMirror getPrimitiveType() { + return primitiveType; + } + + public TypeMirror getBoxedType() { + return boxedType; + } + + public boolean isGeneric() { + return Utils.typeEquals(boxedType, getTypeSystem().getGenericType()); + } + + public boolean isVoid() { + if (getTypeSystem().getVoidType() == null) { + return false; + } + return Utils.typeEquals(boxedType, getTypeSystem().getVoidType().getBoxedType()); + } +} + diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.typesystem; + +import static com.oracle.truffle.codegen.processor.Utils.*; +import static javax.lang.model.element.Modifier.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.ast.*; +import com.oracle.truffle.codegen.processor.template.*; + +public class TypeSystemCodeGenerator extends CompilationUnitFactory { + + public TypeSystemCodeGenerator(ProcessorContext context) { + super(context); + } + + public static String isTypeMethodName(TypeData type) { + return "is" + Utils.getSimpleName(type.getBoxedType()); + } + + public static String asTypeMethodName(TypeData type) { + return "as" + Utils.getSimpleName(type.getBoxedType()); + } + + public static String expectTypeMethodName(TypeData type) { + return "expect" + Utils.getSimpleName(type.getBoxedType()); + } + + /** + * Finds the generated singleton field for a TypeSytemData instance. TypeSystemCodeGenerator must be applied to the + * TypeSystemData model before use. + */ + public static VariableElement findSingleton(ProcessorContext context, TypeSystemData typeSystem) { + TypeMirror type = context.findGeneratedClassBySimpleName(TypeClassFactory.typeName(typeSystem), typeSystem); + return Utils.findDeclaredField(type, TypeClassFactory.singletonName(typeSystem.getTemplateType().asType())); + } + + @Override + protected void createChildren(TypeSystemData m) { + add(new TypeClassFactory(context), m); + } + + protected static class TypeClassFactory extends ClassElementFactory { + + private static final String LOCAL_VALUE = "value"; + + public TypeClassFactory(ProcessorContext context) { + super(context); + } + + @Override + public CodeTypeElement create(TypeSystemData typeSystem) { + String name = typeName(typeSystem); + CodeTypeElement clazz = createClass(typeSystem, modifiers(PUBLIC), name, typeSystem.getTemplateType().asType(), false); + + clazz.getImplements().add(getContext().getTruffleTypes().getTypeConversion()); + + clazz.add(createConstructorUsingFields(modifiers(PROTECTED), clazz)); + CodeVariableElement singleton = createSingleton(clazz); + clazz.add(singleton); + + clazz.add(createGetTopType(typeSystem)); + clazz.add(createConvertTo(typeSystem, singleton)); + + for (TypeData type : typeSystem.getTypes()) { + if (!type.isGeneric()) { + CodeExecutableElement isType = createIsTypeMethod(type); + if (isType != null) { + clazz.add(isType); + } + CodeExecutableElement asType = createAsTypeMethod(type); + if (asType != null) { + clazz.add(asType); + } + + for (TypeData sourceType : collectExpectSourceTypes(type)) { + CodeExecutableElement expect = createExpectTypeMethod(type, sourceType); + if (expect != null) { + clazz.add(expect); + } + } + } + } + + clazz.getEnclosedElements().addAll(typeSystem.getExtensionElements()); + + return clazz; + } + + private static List collectExpectSourceTypes(TypeData type) { + Set sourceTypes = new HashSet<>(); + sourceTypes.add(type.getTypeSystem().getGenericTypeData()); + for (TypeCastData cast : type.getTypeCasts()) { + sourceTypes.add(cast.getSourceType()); + } + for (TypeCheckData cast : type.getTypeChecks()) { + sourceTypes.add(cast.getCheckedType()); + } + return new ArrayList<>(sourceTypes); + } + + + private CodeExecutableElement createConvertTo(TypeSystemData typeSystem, CodeVariableElement singleton) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(Object.class), "convertTo"); + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "targetType")); + method.addParameter(new CodeVariableElement(getContext().getType(Object.class), "value")); + + CodeTreeBuilder builder = method.createBuilder(); + + boolean first = true; + for (TypeData type : typeSystem.getTypes()) { + if (first) { + builder.startIf(); + first = false; + } else { + builder.startElseIf(); + } + builder.string("targetType").string(" == ").typeLiteral(type.getBoxedType()); + builder.end(); // if + builder.startBlock(); + + builder.startReturn(); + + if (typeEquals(type.getBoxedType(), getContext().getType(Object.class))) { + builder.string("value"); + } else { + builder.string(singleton.getName()).string(".").startCall(asTypeMethodName(type)).string("value").end(); + } + + builder.end(); // return + + builder.end(); // block + } + + builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); + + return method; + } + + private CodeExecutableElement createGetTopType(TypeSystemData typeSystem) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(Class.class), "getTopType"); + + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn(); + if (typeSystem.getTypes().length > 0) { + builder.typeLiteral(typeSystem.getTypes()[0].getBoxedType()); + } else { + builder.null_(); + } + builder.end(); // return + + return method; + } + + private static String typeName(TypeSystemData typeSystem) { + String name = getSimpleName(typeSystem.getTemplateType()); + return name + "Gen"; + } + + private static String singletonName(TypeMirror type) { + return createConstantName(getSimpleName(type)); + } + + private CodeVariableElement createSingleton(CodeTypeElement clazz) { + CodeVariableElement field = new CodeVariableElement(modifiers(PUBLIC, STATIC, FINAL), clazz.asType(), singletonName(getModel().getTemplateType().asType())); + field.createInitBuilder().startNew(clazz.asType()).end(); + return field; + } + + private CodeExecutableElement createIsTypeMethod(TypeData type) { + if (!type.getTypeChecks().isEmpty()) { + return null; + } + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(boolean.class), + TypeSystemCodeGenerator.isTypeMethodName(type)); + method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); + + CodeTreeBuilder body = method.createBuilder(); + body.startReturn().instanceOf(LOCAL_VALUE, type.getBoxedType()).end(); + + return method; + } + + private CodeExecutableElement createAsTypeMethod(TypeData type) { + if (!type.getTypeCasts().isEmpty()) { + return null; + } + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), + TypeSystemCodeGenerator.asTypeMethodName(type)); + method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); + + CodeTreeBuilder body = method.createBuilder(); + body.startReturn().cast(type.getPrimitiveType(), body.create().string(LOCAL_VALUE).getTree()).end(); + + return method; + } + + private CodeExecutableElement createExpectTypeMethod(TypeData expectedType, TypeData sourceType) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), expectedType.getPrimitiveType(), TypeSystemCodeGenerator.expectTypeMethodName(expectedType)); + method.addParameter(new CodeVariableElement(sourceType.getPrimitiveType(), LOCAL_VALUE)); + method.addThrownType(getContext().getTruffleTypes().getUnexpectedValueException()); + + CodeTreeBuilder body = method.createBuilder(); + body.startIf().startCall(null, TypeSystemCodeGenerator.isTypeMethodName(expectedType)).string(LOCAL_VALUE).end().end().startBlock(); + body.startReturn().startCall(null, TypeSystemCodeGenerator.asTypeMethodName(expectedType)).string(LOCAL_VALUE).end().end(); + body.end(); // if-block + body.startThrow().startNew(getContext().getTruffleTypes().getUnexpectedValueException()).string(LOCAL_VALUE).end().end(); + + return method; + } + } +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.typesystem; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; + +public class TypeSystemData extends Template { + + private final TypeData[] types; + private final TypeMirror[] primitiveTypeMirrors; + private final TypeMirror[] boxedTypeMirrors; + + private final TypeMirror nodeType; + private final TypeMirror genericType; + + private final TypeData voidType; + + private List guards; + + + public TypeSystemData(TypeElement templateType, AnnotationMirror annotation, + TypeData[] types, TypeMirror nodeType, TypeMirror genericType, TypeData voidType) { + super(templateType, annotation); + this.voidType = voidType; + this.types = types; + this.nodeType = nodeType; + this.genericType = genericType; + + this.primitiveTypeMirrors = new TypeMirror[types.length]; + for (int i = 0; i < types.length; i++) { + primitiveTypeMirrors[i] = types[i].getPrimitiveType(); + } + + this.boxedTypeMirrors = new TypeMirror[types.length]; + for (int i = 0; i < types.length; i++) { + boxedTypeMirrors[i] = types[i].getBoxedType(); + } + + for (TypeData type : types) { + type.typeSystem = this; + } + if (voidType != null) { + voidType.typeSystem = this; + } + } + + public TypeData getVoidType() { + return voidType; + } + + void setGuards(List guards) { + this.guards = guards; + } + + public List getGuards() { + return guards; + } + + public TypeData[] getTypes() { + return types; + } + + public TypeMirror[] getPrimitiveTypeMirrors() { + return primitiveTypeMirrors; + } + + public TypeMirror[] getBoxedTypeMirrors() { + return boxedTypeMirrors; + } + + public TypeMirror getNodeType() { + return nodeType; + } + + public TypeMirror getGenericType() { + return genericType; + } + + public TypeData getGenericTypeData() { + TypeData result = types[types.length - 1]; + assert result.getBoxedType() == genericType; + return result; + } + + public TypeData findType(String simpleName) { + for (TypeData type : types) { + if (Utils.getSimpleName(type.getBoxedType()).equals(simpleName)) { + return type; + } + } + return null; + } + + public int findType(TypeMirror type) { + for (int i = 0; i < types.length; i++) { + if (Utils.typeEquals(types[i].getPrimitiveType(), type)) { + return i; + } + } + return -1; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.typesystem; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; + + +abstract class TypeSystemMethodParser extends TemplateMethodParser { + + private final TypeSystemData typeSystem; + + public TypeSystemMethodParser(ProcessorContext context, TypeSystemData typeSystem) { + super(context); + this.typeSystem = typeSystem; + } + + public TypeSystemData getTypeSystem() { + return typeSystem; + } + + protected TypeData findTypeByMethodName(ExecutableElement method, AnnotationMirror annotationMirror, String prefix) { + String methodName = method.getSimpleName().toString(); + if (!methodName.startsWith(prefix)) { + String annotationName = Utils.getSimpleName(annotationMirror.getAnnotationType()); + getContext().getLog().error(method, "Methods annotated with %s must match the pattern '%s'.", + annotationName, String.format("%s${typeName}", prefix)); + return null; + } + String typeName = methodName.substring(prefix.length(), methodName.length()); + TypeData type = typeSystem.findType(typeName); + if (type == null) { + String annotationName = TypeSystem.class.getSimpleName(); + getContext().getLog().error(method, "Type '%s' is not declared in this @%s.", typeName, annotationName); + return null; + } + + return type; + } + +} diff -r a81db08fe930 -r a748e4d44694 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.typesystem; + +import static com.oracle.truffle.codegen.processor.Utils.*; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.operation.*; +import com.oracle.truffle.codegen.processor.template.*; + +public class TypeSystemParser extends TemplateParser { + + public TypeSystemParser(ProcessorContext c) { + super(c); + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return TypeSystem.class; + } + + @Override + protected TypeSystemData parse(Element element, AnnotationMirror mirror) { + TypeElement templateType = (TypeElement) element; + AnnotationMirror templateTypeAnnotation = mirror; + + if (!verifyTemplateType(templateType, templateTypeAnnotation)) { + return null; + } + + TypeData[] types = parseTypes(templateType, templateTypeAnnotation); + if (types == null) { + return null; + } + + TypeMirror nodeType = Utils.getAnnotationValueType(templateTypeAnnotation, "nodeBaseClass"); + TypeMirror genericType = context.getType(Object.class); + + TypeData voidType = null; + if (Utils.getAnnotationValueBoolean(templateTypeAnnotation, "hasVoid")) { + voidType = new TypeData(templateType, templateTypeAnnotation, context.getType(void.class), context.getType(Void.class)); + } + + TypeSystemData typeSystem = new TypeSystemData(templateType, templateTypeAnnotation, types, nodeType, genericType, voidType); + + if (!verifyNodeBaseType(typeSystem)) { + return null; + } + + if (!verifyExclusiveMethodAnnotation(templateType, TypeCast.class, TypeCheck.class, GuardCheck.class)) { + return null; + } + + typeSystem.setExtensionElements(getExtensionParser().parseAll(templateType)); + + List casts = parseMethods(typeSystem, new TypeCastParser(context, typeSystem)); + List checks = parseMethods(typeSystem, new TypeCheckParser(context, typeSystem)); + List guards = parseMethods(typeSystem, new GuardParser(context, typeSystem, typeSystem)); + + if (casts == null || checks == null || guards == null) { + return null; + } + + for (TypeCheckData check : checks) { + check.getCheckedType().addTypeCheck(check); + } + + for (TypeCastData cast : casts) { + cast.getTargetType().addTypeCast(cast); + } + + typeSystem.setGuards(guards); + + if (!verifyGenericTypeChecksAndCasts(types)) { + return null; + } + + if (!verifyMethodSignatures(element, types)) { + return null; + } + + if (!verifyNamesUnique(templateType, templateTypeAnnotation, types)) { + return null; + } + + return typeSystem; + } + + private boolean verifyGenericTypeChecksAndCasts(TypeData[] types) { + boolean valid = true; + for (TypeData type : types) { + if (!type.getTypeChecks().isEmpty()) { + boolean hasGeneric = false; + for (TypeCheckData typeCheck : type.getTypeChecks()) { + if (typeCheck.isGeneric()) { + hasGeneric = true; + break; + } + } + if (!hasGeneric) { + log.error(type.getTypeSystem().getTemplateType(), + "No generic but specific @%s method %s for type %s specified. " + + "Specify a generic @%s method with parameter type %s to resolve this.", + TypeCheck.class.getSimpleName(), TypeSystemCodeGenerator.isTypeMethodName(type), Utils.getSimpleName(type.getBoxedType()), + TypeCheck.class.getSimpleName(), Object.class.getSimpleName()); + valid = false; + } + } + if (!type.getTypeCasts().isEmpty()) { + boolean hasGeneric = false; + for (TypeCastData typeCast : type.getTypeCasts()) { + if (typeCast.isGeneric()) { + hasGeneric = true; + break; + } + } + if (!hasGeneric) { + log.error(type.getTypeSystem().getTemplateType(), + "No generic but specific @%s method %s for type %s specified. " + + "Specify a generic @%s method with parameter type %s to resolve this.", + TypeCast.class.getSimpleName(), TypeSystemCodeGenerator.asTypeMethodName(type), Utils.getSimpleName(type.getBoxedType()), + TypeCast.class.getSimpleName(), Object.class.getSimpleName()); + valid = false; + } + } + } + return valid; + } + + private boolean verifyNodeBaseType(TypeSystemData typeSystem) { + List types = new ArrayList<>(Arrays.asList(typeSystem.getTypes())); + if (typeSystem.getVoidType() != null) { + types.add(typeSystem.getVoidType()); + } + + TypeMirror[] args = new TypeMirror[]{context.getTruffleTypes().getFrame()}; + List missingMethods = new ArrayList<>(); + for (TypeData typeData : types) { + String methodName = OperationCodeGenerator.executeMethodName(typeData); + ExecutableElement declared = Utils.getDeclaredMethodRecursive(Utils.fromTypeMirror(typeSystem.getNodeType()), methodName, args); + if (declared == null || declared.getModifiers().contains(Modifier.FINAL)) { + missingMethods.add(String.format("public %s %s(%s)", + Utils.getSimpleName(typeData.getPrimitiveType()), methodName, + Utils.getSimpleName(context.getTruffleTypes().getFrame()))); + } + } + + if (!missingMethods.isEmpty()) { + log.error(typeSystem.getTemplateType(), typeSystem.getTemplateTypeAnnotation(), + Utils.getAnnotationValue(typeSystem.getTemplateTypeAnnotation(), "nodeBaseClass"), + "The class '%s' does not declare the required non final method(s) %s.", + Utils.getQualifiedName(typeSystem.getNodeType()), missingMethods); + return false; + } + + return true; + } + + private TypeData[] parseTypes(TypeElement templateType, AnnotationMirror templateTypeAnnotation) { + List typeMirrors = Utils.getAnnotationValueList(templateTypeAnnotation, "types"); + if (typeMirrors.size() == 0) { + log.error(templateType, templateTypeAnnotation, "At least one type child must be defined."); + return null; + } + + final AnnotationValue annotationValue = Utils.getAnnotationValue(templateTypeAnnotation, "types"); + final TypeMirror objectType = context.getType(Object.class); + + List types = new ArrayList<>(); + for (TypeMirror primitiveType : typeMirrors) { + + if (isPrimitiveWrapper(primitiveType)) { + log.error(templateType, templateTypeAnnotation, annotationValue, + "Types must not contain primitive wrapper types."); + continue; + } + + TypeMirror boxedType = primitiveType; + if (boxedType.getKind().isPrimitive()) { + boxedType = processingEnv.getTypeUtils().boxedClass((PrimitiveType) boxedType).asType(); + } + + if (Utils.typeEquals(boxedType, objectType)) { + log.error(templateType, templateTypeAnnotation, annotationValue, + "Types must not contain the generic type java.lang.Object."); + continue; + } + + types.add(new TypeData(templateType, templateTypeAnnotation, primitiveType, boxedType)); + } + + verifyTypeOrder(templateType, templateTypeAnnotation, annotationValue, types); + + types.add(new TypeData(templateType, templateTypeAnnotation, objectType, objectType)); + + return types.toArray(new TypeData[types.size()]); + } + + private void verifyTypeOrder(TypeElement templateType, AnnotationMirror templateTypeAnnotation, AnnotationValue annotationValue, List types) { + Map> invalidTypes = new HashMap<>(); + + for (int i = types.size() - 1; i >= 0; i--) { + TypeData typeData = types.get(i); + TypeMirror type = typeData.getBoxedType(); + if (invalidTypes.containsKey(Utils.getQualifiedName(type))) { + log.error(templateType, templateTypeAnnotation, annotationValue, + "Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", + invalidTypes.get(Utils.getQualifiedName(type)), Utils.getQualifiedName(type)); + } + List nextInvalidTypes = Utils.getQualifiedSuperTypeNames(Utils.fromTypeMirror(type)); + nextInvalidTypes.add(getQualifiedName(type)); + + for (String qualifiedName : nextInvalidTypes) { + List inheritedTypes = invalidTypes.get(qualifiedName); + if (inheritedTypes == null) { + inheritedTypes = new ArrayList<>(); + invalidTypes.put(qualifiedName, inheritedTypes); + } + inheritedTypes.add(Utils.getQualifiedName(typeData.getBoxedType())); + } + } + } + + private boolean isPrimitiveWrapper(TypeMirror type) { + Types types = context.getEnvironment().getTypeUtils(); + for (TypeKind kind : TypeKind.values()) { + if (!kind.isPrimitive()) { + continue; + } + if (Utils.typeEquals(type, types.boxedClass(types.getPrimitiveType(kind)).asType())) { + return true; + } + } + return false; + } + + + private boolean verifyMethodSignatures(Element element, TypeData[] types) { + Set generatedIsMethodNames = new HashSet<>(); + Set generatedAsMethodNames = new HashSet<>(); + Set generatedExpectMethodNames = new HashSet<>(); + + for (TypeData typeData : types) { + generatedIsMethodNames.add(TypeSystemCodeGenerator.isTypeMethodName(typeData)); + generatedAsMethodNames.add(TypeSystemCodeGenerator.asTypeMethodName(typeData)); + generatedExpectMethodNames.add(TypeSystemCodeGenerator.expectTypeMethodName(typeData)); + } + + boolean valid = true; + List methods = ElementFilter.methodsIn(element.getEnclosedElements()); + for (ExecutableElement method : methods) { + if (method.getModifiers().contains(Modifier.PRIVATE)) { + // will not conflict overridden methods + continue; + } else if (method.getParameters().size() != 1) { + continue; + } + String methodName = method.getSimpleName().toString(); + if (generatedIsMethodNames.contains(methodName)) { + valid &= verifyIsMethod(method); + } else if (generatedAsMethodNames.contains(methodName)) { + valid &= verifyAsMethod(method); + } else if (generatedExpectMethodNames.contains(methodName)) { + valid &= verifyExpectMethod(method); + } + } + return valid; + } + + private boolean verifyIsMethod(ExecutableElement method) { + AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, TypeCheck.class); + if (mirror == null) { + log.error(method, "Method starting with the pattern is${typeName} must be annotated with @%s.", TypeCheck.class.getSimpleName()); + return false; + } + return true; + } + + private boolean verifyAsMethod(ExecutableElement method) { + AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, TypeCast.class); + if (mirror == null) { + log.error(method, "Method starting with the pattern as${typeName} must be annotated with @%s.", TypeCast.class.getSimpleName()); + return false; + } + return true; + } + + private boolean verifyExpectMethod(ExecutableElement method) { + log.error(method, "Method starting with the pattern expect${typeName} must not be declared manually."); + return false; + } + + private boolean verifyNamesUnique(TypeElement templateType, AnnotationMirror templateTypeAnnotation, TypeData[] types) { + boolean valid = true; + for (int i = 0; i < types.length; i++) { + for (int j = i + 1; j < types.length; j++) { + String name1 = Utils.getSimpleName(types[i].getBoxedType()); + String name2 = Utils.getSimpleName(types[j].getBoxedType()); + if (name1.equalsIgnoreCase(name2)) { + log.error(templateType, templateTypeAnnotation, "Two types result in the same name: %s, %s.", name1, name2); + valid = false; + } + } + } + return valid; + } +} diff -r a81db08fe930 -r a748e4d44694 mx/commands.py --- a/mx/commands.py Fri Dec 21 10:21:24 2012 +0100 +++ b/mx/commands.py Fri Dec 21 10:44:31 2012 -0800 @@ -396,7 +396,14 @@ log = open(logFile, 'w') ret = False while True: - line = stdout.readline().decode(sys.stdout.encoding) + + # encoding may be None on windows plattforms + if sys.stdout.encoding is None: + encoding = 'utf-8' + else: + encoding = sys.stdout.encoding + + line = stdout.readline().decode(encoding) if logFile: log.write(line.encode('utf-8')) line = line.strip() diff -r a81db08fe930 -r a748e4d44694 mx/projects --- a/mx/projects Fri Dec 21 10:21:24 2012 +0100 +++ b/mx/projects Fri Dec 21 10:44:31 2012 -0800 @@ -10,6 +10,9 @@ library@CHECKSTYLE@path=lib/checkstyle-5.5-all.jar library@CHECKSTYLE@urls=jar:http://sourceforge.net/projects/checkstyle/files/checkstyle/5.5/checkstyle-5.5-bin.zip/download!/checkstyle-5.5/checkstyle-5.5-all.jar +library@ANT_JAR_TOOL@path=lib/ant-jar-tool.jar +library@ANT_JAR_TOOL@urls=http://lafo.ssw.uni-linz.ac.at/ant-jar-tool/ant-jar-tool.jar + library@DACAPO@path=lib/dacapo-9.12-bach.jar library@DACAPO@urls=http://softlayer.dl.sourceforge.net/project/dacapobench/9.12-bach/dacapo-9.12-bach.jar @@ -269,3 +272,17 @@ project@com.oracle.truffle.api.test@checkstyle=com.oracle.graal.graph project@com.oracle.truffle.api.test@javaCompliance=1.7 +# truffle.api.codegen +project@com.oracle.truffle.api.codegen@subDir=graal +project@com.oracle.truffle.api.codegen@sourceDirs=src +project@com.oracle.truffle.api.codegen@dependencies=com.oracle.truffle.api +project@com.oracle.truffle.api.codegen@checkstyle=com.oracle.graal.graph +project@com.oracle.truffle.api.codegen@javaCompliance=1.7 + +# truffle.codegen.processor +project@com.oracle.truffle.codegen.processor@subDir=graal +project@com.oracle.truffle.codegen.processor@sourceDirs=src +project@com.oracle.truffle.codegen.processor@dependencies=com.oracle.truffle.api.codegen +project@com.oracle.truffle.codegen.processor@checkstyle=com.oracle.graal.graph +project@com.oracle.truffle.codegen.processor@javaCompliance=1.7 + diff -r a81db08fe930 -r a748e4d44694 mxtool/mx.py --- a/mxtool/mx.py Fri Dec 21 10:21:24 2012 +0100 +++ b/mxtool/mx.py Fri Dec 21 10:44:31 2012 -0800 @@ -188,14 +188,17 @@ if not exists(s): os.mkdir(s) - def all_deps(self, deps, includeLibs, includeSelf=True): + def all_deps(self, deps, includeLibs, includeSelf=True, includeAnnotationProcessors=False): """ Add the transitive set of dependencies for this project, including libraries if 'includeLibs' is true, to the 'deps' list. """ + childDeps = list(self.deps) + if includeAnnotationProcessors and hasattr(self, 'annotationProcessors') and len(self.annotationProcessors) > 0: + childDeps = self.annotationProcessors + childDeps if self in deps: return deps - for name in self.deps: + for name in childDeps: assert name != self.name dep = _libs.get(name, None) if dep is not None: @@ -208,7 +211,7 @@ abort('project named ' + name + ' required by ' + self.name + ' is ignored') abort('dependency named ' + name + ' required by ' + self.name + ' is not found') if not dep in deps: - dep.all_deps(deps, includeLibs) + dep.all_deps(deps, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors) if not self in deps and includeSelf: deps.append(self) return deps @@ -464,7 +467,7 @@ srcDirs = pop_list(attrs, 'sourceDirs') deps = pop_list(attrs, 'dependencies') ap = pop_list(attrs, 'annotationProcessors') - deps += ap + #deps += ap javaCompliance = attrs.pop('javaCompliance', None) subDir = attrs.pop('subDir', None); if subDir is None: @@ -478,9 +481,6 @@ abort('javaCompliance property required for non-native project ' + name) if len(ap) > 0: p.annotationProcessors = ap - apc = pop_list(attrs, 'annotationProcessorClasses') - if len(apc) > 0: - p.annotationProcessorClasses = apc p.__dict__.update(attrs) self.projects.append(p) @@ -729,7 +729,7 @@ entryPath = zi.filename yield zf, entryPath -def sorted_deps(projectNames=None, includeLibs=False): +def sorted_deps(projectNames=None, includeLibs=False, includeAnnotationProcessors=False): """ Gets projects and libraries sorted such that dependencies are before the projects that depend on them. Unless 'includeLibs' is @@ -742,7 +742,7 @@ projects = [project(name) for name in projectNames] for p in projects: - p.all_deps(deps, includeLibs) + p.all_deps(deps, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors) return deps class ArgParser(ArgumentParser): @@ -1296,7 +1296,7 @@ if args.only is not None: sortedProjects = [project(name) for name in args.only.split(',')] else: - sortedProjects = sorted_deps(projects) + sortedProjects = sorted_deps(projects, includeAnnotationProcessors=True) for p in sortedProjects: if p.native: @@ -1380,6 +1380,8 @@ log('could not file .class directive in Jasmin source: ' + src) else: dst = join(outputDir, src[len(sourceDir) + 1:]) + if not exists(dirname(dst)): + os.makedirs(dirname(dst)) if exists(dirname(dst)) and (not exists(dst) or os.path.getmtime(dst) != os.path.getmtime(src)): shutil.copyfile(src, dst) @@ -1410,18 +1412,12 @@ javacArgs += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)] if hasattr(p, 'annotationProcessors') and len(p.annotationProcessors) > 0: - annotationProcessors = [] - for apProject in p.annotationProcessors: - apClasses = project(apProject).annotationProcessorClasses - if len(apClasses) == 0: - abort("Project " + p + " specifies " + apProject + " as an annotation processor but " + apProject + " does not specifiy any annotation processor class") - annotationProcessors += apClasses - + processorPath = classpath(p.annotationProcessors, resolve=True) genDir = p.source_gen_dir(); if exists(genDir): shutil.rmtree(genDir) os.mkdir(genDir) - javacArgs += ['-processor', ",".join(annotationProcessors), "-s", genDir] + javacArgs += ['-processorpath', join(processorPath), '-s', genDir] else: javacArgs += ['-proc:none'] @@ -1467,37 +1463,53 @@ return args return None -def processorjars(args): - hasProcessorJars = [] +def processorjars(): + projects = set([]) for p in sorted_deps(): - if hasattr(p, 'annotationProcessorClasses') and len(p.annotationProcessorClasses) > 0: - hasProcessorJars.append(p) + if _needsEclipseJarBuild(p): + projects.add(p) - if len(hasProcessorJars) <= 0: + if len(projects) <= 0: return - build(['--projects', ",".join(map(lambda p: p.name, hasProcessorJars))]) - - for p in hasProcessorJars: - spDir = join(p.output_dir(), 'META-INF', 'services') - if not exists(spDir): - os.makedirs(spDir) - spFile = join(spDir, 'javax.annotation.processing.Processor') - with open(spFile, 'w') as fp: - fp.writelines(p.annotationProcessorClasses) - created = False - for dep in p.all_deps([], False): - if created: - cmd = 'uf' - else: - cmd = 'cf' - created = True - jarCmd = [java().jar, cmd, join(p.dir, p.name + 'AnnotationProcessor.jar'), '-C', dep.output_dir(), '.'] - subprocess.check_call(jarCmd) - log('added ' + dep.name + ' to ' + p.name + '.jar'); + build(['--projects', ",".join(map(lambda p: p.name, projects))]) + + for p in projects: + targetJar = join(p.dir, p.name + '.jar') + jar(targetJar, [p.output_dir()]) +def jar(destFileName, dirs): + lib = library("ANT_JAR_TOOL", fatalIfMissing=False) + + if lib is None : + log('No library ANT_JAR_TOOL defined. Falling back to JDK Jar tool.'); + _java_jar_tool(destFileName, dirs) + else: + _ant_jar_tool(lib, destFileName, dirs) + +def _java_jar_tool(destFileName, dirs): + created = False + for directory in dirs: + if created: + cmd = 'uf' + else: + cmd = 'cf' + created = True + jarCmd = [java().jar, cmd, destFileName, '-C', directory, '.'] + subprocess.check_call(jarCmd) + +def _ant_jar_tool(lib, destFileName, dirs): + antJar = lib.get_path(True) + + jarCmd = [java().java, '-jar', antJar, destFileName] + for directory in dirs : + jarCmd.append(directory) + + subprocess.check_call(jarCmd) + + def canonicalizeprojects(args): """process all project files to canonicalize the dependencies @@ -1866,7 +1878,7 @@ if suite is None: suite = _mainSuite - processorjars([]) + processorjars() for p in projects(): if p.native: @@ -1884,6 +1896,13 @@ os.mkdir(srcDir) out.element('classpathentry', {'kind' : 'src', 'path' : src}) + if hasattr(p, 'annotationProcessors') and len(p.annotationProcessors) > 0: + genDir = p.source_gen_dir(); + if exists(genDir): + shutil.rmtree(genDir) + os.mkdir(genDir) + out.element('classpathentry', {'kind' : 'src', 'path' : 'src_gen'}) + # Every Java program depends on the JRE out.element('classpathentry', {'kind' : 'con', 'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'}) @@ -1975,6 +1994,23 @@ out.element('name', data=buildCommand) out.element('arguments', data='') out.close('buildCommand') + + if (_needsEclipseJarBuild(p)): + out.open('buildCommand') + out.element('name', data='org.eclipse.ui.externaltools.ExternalToolBuilder') + out.element('triggers', data='auto,full,incremental,') + out.open('arguments') + out.open('dictionary') + out.element('key', data = 'LaunchConfigHandle') + out.element('value', data = _genEclipseJarBuild(p)) + out.close('dictionary') + out.open('dictionary') + out.element('key', data = 'incclean') + out.element('value', data = 'true') + out.close('dictionary') + out.close('arguments') + out.close('buildCommand') + out.close('buildSpec') out.open('natures') out.element('nature', data='org.eclipse.jdt.core.javanature') @@ -2010,7 +2046,7 @@ out.element('factorypathentry', {'kind' : 'PLUGIN', 'id' : 'org.eclipse.jst.ws.annotations.core', 'enabled' : 'true', 'runInBatchMode' : 'false'}) for ap in p.annotationProcessors: apProject = project(ap) - out.element('factorypathentry', {'kind' : 'WKSPJAR', 'id' : '/' + apProject.name + '/' + apProject.name + 'AnnotationProcessor.jar', 'enabled' : 'true', 'runInBatchMode' : 'false'}) + out.element('factorypathentry', {'kind' : 'WKSPJAR', 'id' : '/' + apProject.name + '/' + apProject.name + '.jar', 'enabled' : 'true', 'runInBatchMode' : 'false'}) for dep in apProject.all_deps([], True): if dep.isLibrary(): if not hasattr(dep, 'eclipse.container') and not hasattr(dep, 'eclipse.project'): @@ -2022,11 +2058,79 @@ # safest to simply use absolute paths. path = join(suite.dir, path) out.element('factorypathentry', {'kind' : 'EXTJAR', 'id' : path, 'enabled' : 'true', 'runInBatchMode' : 'false'}) + else: + out.element('factorypathentry', {'kind' : 'WKSPJAR', 'id' : '/' + dep.name + '/' + dep.name + '.jar', 'enabled' : 'true', 'runInBatchMode' : 'false'}) out.close('factorypath') update_file(join(p.dir, '.factorypath'), out.xml(indent='\t', newl='\n')) make_eclipse_attach('localhost', '8000', deps=projects()) + +def _needsEclipseJarBuild(p): + processors = set([]) + + for otherProject in projects(): + if hasattr(otherProject, 'annotationProcessors') and len(otherProject.annotationProcessors) > 0: + for processorName in otherProject.annotationProcessors: + processors.add(project(processorName, fatalIfMissing=True)) + + if p in processors: + return True + + for otherProject in processors: + deps = otherProject.all_deps([], True) + if p in deps: + return True + + return False + +def _genEclipseJarBuild(p): + externalToolDir = '.externalToolBuilders' + relPath = join(externalToolDir, 'Jar.launch') + absPath = join(p.dir, relPath) + + if not exists(join(p.dir, externalToolDir)): + os.makedirs(join(p.dir, externalToolDir)) + + antOut = XMLDoc() + antOut.open('project', {'name' : p.name, 'default' : 'default', 'basedir' : '.'}) + antOut.open('target', {'name' : 'default'}) + antOut.open('jar', {'destfile' : p.name + '.jar'}) + antOut.element('fileset', {'dir' : p.output_dir()}) + antOut.close('jar') + antOut.close('target') + antOut.close('project') + + update_file(join(p.dir, 'eclipse-build.xml'), antOut.xml(indent='\t', newl='\n')) + + launchOut = """ + + + + + + + + + + + + + + + + + + + +""" + update_file(absPath, launchOut) + + return "/.externalToolBuilders/Jar.launch" + + + + def netbeansinit(args, suite=None): """(re)generate NetBeans project configurations""" @@ -2063,9 +2167,10 @@ out.element('explicit-platform', {'explicit-source-supported' : 'true'}) out.open('source-roots') out.element('root', {'id' : 'src.dir'}) + if hasattr(p, 'annotationProcessors') and len(p.annotationProcessors) > 0: + out.element('root', {'id' : 'src.ap-source-output.dir'}) out.close('source-roots') out.open('test-roots') - out.element('root', {'id' : 'test.src.dir'}) out.close('test-roots') out.close('data') @@ -2099,12 +2204,18 @@ out = StringIO.StringIO() jdkPlatform = 'JDK_' + java().version + annotationProcessorEnabled = "false" + annotationProcessorReferences = "" + annotationProcessorSrcFolder = "" + if hasattr(p, 'annotationProcessors') and len(p.annotationProcessors) > 0: + annotationProcessorEnabled = "true" + annotationProcessorSrcFolder = "src.ap-source-output.dir=${build.generated.sources.dir}/ap-source-output" + content = """ -annotation.processing.enabled=false -annotation.processing.enabled.in.editor=false +annotation.processing.enabled=""" + annotationProcessorEnabled + """ +annotation.processing.enabled.in.editor=""" + annotationProcessorEnabled + """ annotation.processing.processors.list= annotation.processing.run.all.processors=true -annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output application.title=""" + p.name + """ application.vendor=mx build.classes.dir=${build.dir} @@ -2134,15 +2245,11 @@ # Space-separated list of extra javac options javac.compilerargs= javac.deprecation=false -javac.processorpath=\\ - ${javac.classpath} javac.source=1.7 javac.target=1.7 javac.test.classpath=\\ ${javac.classpath}:\\ ${build.classes.dir} -javac.test.processorpath=\\ - ${javac.test.classpath} javadoc.additionalparam= javadoc.author=false javadoc.encoding=${source.encoding} @@ -2170,7 +2277,8 @@ run.test.classpath=\\ ${javac.test.classpath}:\\ ${build.test.classes.dir} -test.src.dir= +test.src.dir=./test +""" + annotationProcessorSrcFolder + """ source.encoding=UTF-8""".replace(':', os.pathsep).replace('/', os.sep) print >> out, content @@ -2188,7 +2296,19 @@ print >> out, 'src.' + src + '.dir=${' + ref + '}' javacClasspath = [] - for dep in p.all_deps([], True): + + deps = p.all_deps([], True) + annotationProcessorOnlyDeps = [] + if hasattr(p, 'annotationProcessors') and len(p.annotationProcessors) > 0: + for ap in p.annotationProcessors: + apProject = project(ap) + if not apProject in deps: + deps.append(apProject) + annotationProcessorOnlyDeps.append(apProject) + + annotationProcessorReferences = []; + + for dep in deps: if dep == p: continue; @@ -2208,11 +2328,16 @@ print >> out, 'project.' + n + '=' + relDepPath print >> out, ref + '=${project.' + n + '}/dist/' + dep.name + '.jar' - javacClasspath.append('${' + ref + '}') + if not dep in annotationProcessorOnlyDeps: + javacClasspath.append('${' + ref + '}') + else: + annotationProcessorReferences.append('${' + ref + '}') + annotationProcessorReferences += ":\\\n ${" + ref + "}" print >> out, 'javac.classpath=\\\n ' + (os.pathsep + '\\\n ').join(javacClasspath) - - + print >> out, 'javac.test.processorpath=${javac.test.classpath}\\\n ' + (os.pathsep + '\\\n ').join(annotationProcessorReferences) + print >> out, 'javac.processorpath=${javac.classpath}\\\n ' + (os.pathsep + '\\\n ').join(annotationProcessorReferences) + updated = update_file(join(p.dir, 'nbproject', 'project.properties'), out.getvalue()) or updated out.close() @@ -2223,7 +2348,6 @@ def ideclean(args, suite=None): """remove all Eclipse and NetBeans project configurations""" - def rm(path): if exists(path): os.remove(path) @@ -2233,10 +2357,17 @@ continue shutil.rmtree(join(p.dir, '.settings'), ignore_errors=True) + shutil.rmtree(join(p.dir, '.externalToolBuilders'), ignore_errors=True) shutil.rmtree(join(p.dir, 'nbproject'), ignore_errors=True) rm(join(p.dir, '.classpath')) rm(join(p.dir, '.project')) rm(join(p.dir, 'build.xml')) + rm(join(p.dir, 'eclipse-build.xml')) + try: + rm(join(p.dir, p.name + '.jar')) + except: + log("Error removing {0}".format(p.name + '.jar')) + def ideinit(args, suite=None): """(re)generate Eclipse and NetBeans project configurations"""