diff graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/SpecializedNodeFactory.java @ 18752:1acaa69ff61b

Truffle-DSL: refactor generator classes
author Christian Humer <christian.humer@gmail.com>
date Mon, 29 Dec 2014 23:38:16 +0100
parents
children f6b8787dc113
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/SpecializedNodeFactory.java	Mon Dec 29 23:38:16 2014 +0100
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 2014, 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.dsl.processor.generator;
+
+import static com.oracle.truffle.dsl.processor.java.ElementUtils.*;
+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.nodes.*;
+import com.oracle.truffle.dsl.processor.java.*;
+import com.oracle.truffle.dsl.processor.java.model.*;
+import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror;
+import com.oracle.truffle.dsl.processor.model.*;
+import com.oracle.truffle.dsl.processor.parser.*;
+
+class SpecializedNodeFactory extends NodeBaseFactory {
+
+    protected final CodeTypeElement nodeGen;
+
+    public SpecializedNodeFactory(CodeTypeElement nodeGen) {
+        this.nodeGen = nodeGen;
+    }
+
+    @Override
+    public CodeTypeElement create(SpecializationData specialization) {
+        NodeData node = specialization.getNode();
+        TypeMirror baseType = node.getNodeType();
+        if (nodeGen != null) {
+            baseType = nodeGen.asType();
+        }
+        CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false);
+
+        if (specialization.isSpecialized() || specialization.isUninitialized()) {
+            clazz.add(createGetMetadata0(false));
+            clazz.add(createMetadataLiteral());
+        }
+
+        NodeCost cost;
+        if (specialization.isGeneric()) {
+            cost = NodeCost.MEGAMORPHIC;
+        } else if (specialization.isUninitialized()) {
+            cost = NodeCost.UNINITIALIZED;
+        } else if (specialization.isPolymorphic()) {
+            cost = NodeCost.POLYMORPHIC;
+        } else if (specialization.isSpecialized()) {
+            cost = NodeCost.MONOMORPHIC;
+        } else {
+            throw new AssertionError();
+        }
+        clazz.getAnnotationMirrors().add(createNodeInfo(node, cost));
+
+        if (specialization.isUninitialized() && node.getGenericSpecialization().isReachable()) {
+            clazz.add(createUninitializedGetCostOverride());
+        }
+
+        return clazz;
+    }
+
+    private Element createUninitializedGetCostOverride() {
+        TypeMirror returnType = context.getTruffleTypes().getNodeCost();
+        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getCost");
+        CodeTreeBuilder builder = method.createBuilder();
+        builder.startIf().string(CONTAINS_FALLBACK).end().startBlock();
+        builder.startReturn().staticReference(returnType, "MONOMORPHIC").end();
+        builder.end();
+        builder.startReturn().string("super.getCost()").end();
+        return method;
+    }
+
+    private CodeVariableElement createMetadataLiteral() {
+        CodeVariableElement includes = new CodeVariableElement(modifiers(PRIVATE, STATIC, FINAL), context.getTruffleTypes().getDslMetadata(), METADATA_FIELD_NAME);
+
+        CodeTreeBuilder builder = includes.createInitBuilder();
+
+        SpecializationData specialization = getModel();
+        NodeData node = specialization.getNode();
+
+        Set<SpecializationData> contains = specialization.getContains();
+        if (specialization.isUninitialized()) {
+            contains = new HashSet<>();
+
+            SpecializationData polymorphic = node.getPolymorphicSpecialization();
+            if (polymorphic != null) {
+                contains.addAll(polymorphic.getContains());
+            }
+            SpecializationData generic = node.getGenericSpecialization();
+            if (generic != null) {
+                contains.addAll(generic.getContains());
+            }
+        }
+
+        builder.startNew(context.getTruffleTypes().getDslMetadata());
+        builder.startGroup().string(nodeSpecializationClassName(getModel()), ".class").end();
+        builder.tree(createSpecializationListLiteral(builder, contains));
+        builder.tree(createSpecializationListLiteral(builder, getModel().getExcludedBy()));
+        builder.tree(createSpecializationTypeLiteral(builder, SpecializationData.getSignatureTypes(getModel())));
+        builder.string("0").string("0");
+        builder.end();
+        return includes;
+    }
+
+    private CodeTree createSpecializationTypeLiteral(CodeTreeBuilder parent, List<TypeMirror> list) {
+        ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class));
+        CodeTreeBuilder builder = parent.create();
+
+        if (list.isEmpty()) {
+            builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY);
+        } else {
+            builder.startNewArray(classArray, null);
+            for (TypeMirror type : list) {
+                builder.typeLiteral(type);
+            }
+            builder.end();
+        }
+
+        return builder.getRoot();
+    }
+
+    private CodeTree createSpecializationListLiteral(CodeTreeBuilder parent, Set<SpecializationData> list) {
+        ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class));
+        CodeTreeBuilder builder = parent.create();
+
+        if (list.isEmpty()) {
+            builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY);
+        } else {
+            builder.startNewArray(classArray, null);
+            for (SpecializationData specialization : list) {
+                SpecializationData s = specialization;
+                if (s.isGeneric() || s.isPolymorphic()) {
+                    s = getModel().getNode().getUninitializedSpecialization();
+                }
+                builder.startGroup().string(nodeSpecializationClassName(s)).string(".class").end();
+            }
+            builder.end();
+        }
+
+        return builder.getRoot();
+    }
+
+    protected CodeAnnotationMirror createNodeInfo(NodeData node, NodeCost cost) {
+        String shortName = node.getShortName();
+        CodeAnnotationMirror nodeInfoMirror = new CodeAnnotationMirror(getContext().getTruffleTypes().getNodeInfoAnnotation());
+        if (shortName != null) {
+            nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("shortName"), new CodeAnnotationValue(shortName));
+        }
+
+        DeclaredType nodeinfoCost = getContext().getTruffleTypes().getNodeCost();
+        VariableElement varKind = ElementUtils.findVariableElement(nodeinfoCost, cost.name());
+
+        nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("cost"), new CodeAnnotationValue(varKind));
+        return nodeInfoMirror;
+    }
+
+    @Override
+    protected void createChildren(SpecializationData specialization) {
+        CodeTypeElement clazz = getElement();
+        createConstructors(clazz);
+
+        createExecuteMethods(specialization);
+        createCachedExecuteMethods(specialization);
+
+        if (specialization.isUninitialized()) {
+            if (specialization.getNode().isFallbackReachable()) {
+                CodeVariableElement var = new CodeVariableElement(modifiers(Modifier.PRIVATE), context.getType(boolean.class), CONTAINS_FALLBACK);
+                var.addAnnotationMirror(new CodeAnnotationMirror(context.getTruffleTypes().getCompilationFinal()));
+                clazz.add(var);
+            }
+            clazz.add(createExecuteUninitialized());
+        }
+
+        if (!specialization.isUninitialized() && specialization.getNode().needsRewrites(context)) {
+            clazz.add(createCopyConstructorFactoryMethod(nodeGen.asType(), specialization));
+        } else {
+            for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
+                if (constructor.getParameters().size() == 1 && ((CodeVariableElement) constructor.getParameters().get(0)).getType().equals(nodeGen.asType())) {
+                    // skip copy constructor - not used
+                    continue;
+                }
+                clazz.add(createConstructorFactoryMethod(specialization, constructor));
+            }
+        }
+    }
+
+    protected void createConstructors(CodeTypeElement clazz) {
+        TypeElement superTypeElement = ElementUtils.fromTypeMirror(clazz.getSuperclass());
+        SpecializationData specialization = getModel();
+        NodeData node = specialization.getNode();
+        for (ExecutableElement constructor : ElementFilter.constructorsIn(superTypeElement.getEnclosedElements())) {
+            if (specialization.isUninitialized()) {
+                // ignore copy constructors for uninitialized if not polymorphic
+                if (isCopyConstructor(constructor) && !node.isPolymorphic(context)) {
+                    continue;
+                }
+            } else if (node.getUninitializedSpecialization() != null) {
+                // ignore others than copy constructors for specialized nodes
+                if (!isCopyConstructor(constructor)) {
+                    continue;
+                }
+            }
+
+            CodeExecutableElement superConstructor = createSuperConstructor(clazz, constructor);
+            if (superConstructor == null) {
+                continue;
+            }
+            CodeTree body = superConstructor.getBodyTree();
+            CodeTreeBuilder builder = superConstructor.createBuilder();
+            builder.tree(body);
+
+            if (superConstructor != null) {
+                for (Parameter param : getImplicitTypeParameters(getModel())) {
+                    clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), implicitTypeName(param)));
+                    superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param)));
+
+                    builder.startStatement();
+                    builder.string("this.").string(implicitTypeName(param)).string(" = ").string(implicitTypeName(param));
+                    builder.end();
+                }
+
+                clazz.add(superConstructor);
+            }
+        }
+    }
+
+    protected void createExecuteMethods(SpecializationData specialization) {
+        NodeData node = specialization.getNode();
+        CodeTypeElement clazz = getElement();
+
+        List<ExecutableTypeData> primaryExecutes = null;
+        int lastEvaluatedCount = -1;
+
+        for (ExecutableTypeData execType : node.getExecutableTypes()) {
+            if (execType.isFinal()) {
+                continue;
+            }
+            if (execType.getEvaluatedCount() != lastEvaluatedCount) {
+                lastEvaluatedCount = execType.getEvaluatedCount();
+                primaryExecutes = findFunctionalExecutableType(specialization, lastEvaluatedCount);
+            }
+
+            CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, true);
+            clazz.add(executeMethod);
+            CodeTreeBuilder builder = executeMethod.getBuilder();
+            CodeTree result = createExecuteBody(builder, specialization, execType, primaryExecutes);
+            if (result != null) {
+                builder.tree(result);
+            } else {
+                clazz.remove(executeMethod);
+            }
+        }
+    }
+
+    protected void createCachedExecuteMethods(SpecializationData specialization) {
+        NodeData node = specialization.getNode();
+        if (!node.isPolymorphic(context)) {
+            return;
+        }
+
+        CodeTypeElement clazz = getElement();
+
+        final SpecializationData polymorphic = node.getPolymorphicSpecialization();
+        ExecutableElement executeCached = nodeGen.getMethod(EXECUTE_CHAINED);
+        CodeExecutableElement executeMethod = CodeExecutableElement.clone(getContext().getEnvironment(), executeCached);
+        executeMethod.getModifiers().remove(Modifier.ABSTRACT);
+        CodeTreeBuilder builder = executeMethod.createBuilder();
+
+        if (specialization.isPolymorphic()) {
+            builder.startReturn().startCall("this.next0", EXECUTE_CHAINED);
+            addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, false, null);
+            builder.end().end();
+        } else if (specialization.isUninitialized()) {
+            builder.tree(createDeoptimizeUninitialized(node, builder));
+            builder.startReturn().startCall("this", EXECUTE_UNINITIALIZED);
+            addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, false, null);
+            builder.end().end();
+        } else {
+            CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder);
+            elseBuilder.startReturn().startCall("this.next0", EXECUTE_CHAINED);
+            addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, false, null);
+            elseBuilder.end().end();
+
+            builder.tree(createExecuteTree(builder, polymorphic, SpecializationGroup.create(specialization), new CodeBlock<SpecializationData>() {
+
+                public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
+                    return createGenericInvoke(b, polymorphic, current);
+                }
+            }, elseBuilder.getRoot(), false, true, true, false));
+        }
+        clazz.add(executeMethod);
+    }
+
+    private static CodeTree createDeoptimizeUninitialized(NodeData node, CodeTreeBuilder parent) {
+        CodeTreeBuilder builder = parent.create();
+        if (node.getGenericSpecialization().isReachable()) {
+            builder.startIf().string("!containsFallback").end().startBlock();
+            builder.tree(createDeoptimize(builder));
+            builder.end();
+        } else {
+            builder.tree(createDeoptimize(builder));
+        }
+        return builder.getRoot();
+    }
+
+    private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType, List<ExecutableTypeData> primaryExecutes) {
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
+        if (primaryExecutes.contains(execType) || primaryExecutes.isEmpty()) {
+            builder.tree(createFunctionalExecute(builder, specialization, execType));
+        } else if (needsCastingExecuteMethod(execType)) {
+            assert !primaryExecutes.isEmpty();
+            builder.tree(createCastingExecute(builder, specialization, execType, primaryExecutes.get(0)));
+        } else {
+            return null;
+        }
+
+        return builder.getRoot();
+    }
+
+    private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType, boolean evaluated) {
+        CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod());
+
+        method.getAnnotationMirrors().clear();
+        for (VariableElement variable : method.getParameters()) {
+            variable.getAnnotationMirrors().clear();
+        }
+
+        CodeTreeBuilder builder = method.createBuilder();
+        int i = 0;
+        int signatureIndex = -1;
+        for (VariableElement param : method.getParameters()) {
+            CodeVariableElement var = CodeVariableElement.clone(param);
+            Parameter actualParameter = i < execType.getParameters().size() ? execType.getParameters().get(i) : null;
+            String name;
+            if (actualParameter != null) {
+                if (actualParameter.getSpecification().isSignature()) {
+                    signatureIndex++;
+                }
+
+                if (evaluated && actualParameter.getSpecification().isSignature()) {
+                    name = valueNameEvaluated(actualParameter);
+                } else {
+                    name = valueName(actualParameter);
+                }
+
+                int varArgCount = getModel().getSignatureSize() - signatureIndex;
+                if (evaluated && actualParameter.isTypeVarArgs()) {
+                    Parameter baseVarArgs = actualParameter;
+                    name = valueName(baseVarArgs) + "Args";
+
+                    builder.startAssert().string(name).string(" != null").end();
+                    builder.startAssert().string(name).string(".length == ").string(String.valueOf(varArgCount)).end();
+                    if (varArgCount > 0) {
+                        List<Parameter> varArgsParameter = execType.getParameters().subList(i, execType.getParameters().size());
+                        for (Parameter varArg : varArgsParameter) {
+                            if (varArgCount <= 0) {
+                                break;
+                            }
+                            TypeMirror type = baseVarArgs.getType();
+                            if (type.getKind() == TypeKind.ARRAY) {
+                                type = ((ArrayType) type).getComponentType();
+                            }
+                            builder.declaration(type, valueNameEvaluated(varArg), name + "[" + varArg.getTypeVarArgsIndex() + "]");
+                            varArgCount--;
+                        }
+                    }
+                }
+            } else {
+                name = "arg" + i;
+            }
+            var.setName(name);
+            method.getParameters().set(i, var);
+            i++;
+        }
+
+        method.getAnnotationMirrors().clear();
+        method.getModifiers().remove(Modifier.ABSTRACT);
+        return method;
+    }
+
+    private static boolean needsCastingExecuteMethod(ExecutableTypeData execType) {
+        if (execType.isAbstract()) {
+            return true;
+        }
+        if (execType.getType().isGeneric()) {
+            return true;
+        }
+        return false;
+    }
+
+    private List<ExecutableTypeData> findFunctionalExecutableType(SpecializationData specialization, int evaluatedCount) {
+        TypeData primaryType = specialization.getReturnType().getTypeSystemType();
+        List<ExecutableTypeData> otherTypes = specialization.getNode().getExecutableTypes(evaluatedCount);
+
+        List<ExecutableTypeData> filteredTypes = new ArrayList<>();
+        for (ExecutableTypeData compareType : otherTypes) {
+            if (ElementUtils.typeEquals(compareType.getType().getPrimitiveType(), primaryType.getPrimitiveType())) {
+                filteredTypes.add(compareType);
+            }
+        }
+
+        // no direct matches found use generic where the type is Object
+        if (filteredTypes.isEmpty()) {
+            for (ExecutableTypeData compareType : otherTypes) {
+                if (compareType.getType().isGeneric() && !compareType.hasUnexpectedValue(getContext())) {
+                    filteredTypes.add(compareType);
+                }
+            }
+        }
+
+        if (filteredTypes.isEmpty()) {
+            for (ExecutableTypeData compareType : otherTypes) {
+                if (compareType.getType().isGeneric()) {
+                    filteredTypes.add(compareType);
+                }
+            }
+        }
+
+        return filteredTypes;
+    }
+
+    private CodeTree createFunctionalExecute(CodeTreeBuilder parent, final SpecializationData specialization, final ExecutableTypeData executable) {
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
+        if (specialization.isUninitialized()) {
+            builder.tree(createDeoptimizeUninitialized(specialization.getNode(), builder));
+        }
+
+        builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null));
+
+        CodeTree returnSpecialized = null;
+
+        if (specialization.findNextSpecialization() != null) {
+            CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder);
+            returnBuilder.tree(createDeoptimize(builder));
+            returnBuilder.tree(createCallRewriteMonomorphic(builder, executable.hasUnexpectedValue(context), executable.getType(), specialization, null, "One of guards " + specialization.getGuards() +
+                            " failed"));
+            returnSpecialized = returnBuilder.getRoot();
+        }
+
+        builder.tree(createExecuteTree(builder, specialization, SpecializationGroup.create(specialization), new CodeBlock<SpecializationData>() {
+
+            public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
+                return createExecute(b, executable, specialization);
+            }
+        }, returnSpecialized, false, false, false, false));
+
+        return builder.getRoot();
+    }
+
+    private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {
+        NodeData node = specialization.getNode();
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        if (!specialization.getExceptions().isEmpty() || !specialization.getAssumptions().isEmpty()) {
+            builder.startTryBlock();
+        }
+
+        for (String assumption : specialization.getAssumptions()) {
+            builder.startStatement();
+            builder.string("this.").string(assumption).string(".check()");
+            builder.end();
+        }
+
+        CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent);
+        if (specialization.isPolymorphic()) {
+            returnBuilder.startCall("next0", EXECUTE_CHAINED);
+            addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, false, null);
+            returnBuilder.end();
+        } else if (specialization.isUninitialized()) {
+            returnBuilder.startCall(EXECUTE_UNINITIALIZED);
+            addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, false, null);
+            returnBuilder.end();
+        } else if (specialization.getMethod() == null && !node.needsRewrites(context)) {
+            emitEncounteredSynthetic(builder, getModel().getNode(), specialization);
+        } else {
+            returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null));
+        }
+
+        if (!returnBuilder.isEmpty()) {
+            TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType());
+            TypeData sourceType = specialization.getReturnType().getTypeSystemType();
+
+            builder.startReturn();
+            if (targetType == null || sourceType == null) {
+                builder.tree(returnBuilder.getRoot());
+            } else if (sourceType.needsCastTo(targetType)) {
+                String castMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType);
+                if (!executable.hasUnexpectedValue(context)) {
+                    castMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType);
+                }
+                builder.tree(createCallTypeSystemMethod(parent, node, castMethodName, returnBuilder.getRoot()));
+            } else {
+                builder.tree(returnBuilder.getRoot());
+            }
+            builder.end();
+        }
+
+        if (!specialization.getExceptions().isEmpty()) {
+            for (SpecializationThrowsData exception : specialization.getExceptions()) {
+                builder.end().startCatchBlock(exception.getJavaClass(), "ex");
+                builder.tree(createDeoptimize(builder));
+                builder.tree(createCallRewriteMonomorphic(parent, executable.hasUnexpectedValue(context), executable.getType(), specialization, null,
+                                "Thrown " + ElementUtils.getSimpleName(exception.getJavaClass())));
+            }
+            builder.end();
+        }
+        if (!specialization.getAssumptions().isEmpty()) {
+            builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex");
+            builder.tree(createCallRewriteMonomorphic(parent, executable.hasUnexpectedValue(context), executable.getType(), specialization, null, "Assumption failed"));
+            builder.end();
+        }
+
+        return builder.getRoot();
+    }
+
+    private CodeExecutableElement createCopyConstructorFactoryMethod(TypeMirror baseType, SpecializationData specialization) {
+        List<Parameter> implicitTypeParams = getImplicitTypeParameters(specialization);
+        String baseName = "current";
+        CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), NodeFactoryFactory.FACTORY_METHOD_NAME);
+        method.addParameter(new CodeVariableElement(specialization.getNode().getNodeType(), baseName));
+        for (Parameter implicitTypeParam : implicitTypeParams) {
+            method.addParameter(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(implicitTypeParam)));
+        }
+        CodeTreeBuilder builder = method.createBuilder();
+        builder.startReturn();
+        builder.startNew(getElement().asType());
+        builder.startGroup().cast(baseType, CodeTreeBuilder.singleString(baseName)).end();
+        for (Parameter param : implicitTypeParams) {
+            builder.string(implicitTypeName(param));
+        }
+        builder.end().end();
+        return method;
+    }
+
+    private CodeExecutableElement createConstructorFactoryMethod(SpecializationData specialization, ExecutableElement constructor) {
+        List<? extends VariableElement> parameters = constructor.getParameters();
+        CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), NodeFactoryFactory.FACTORY_METHOD_NAME,
+                        parameters.toArray(new CodeVariableElement[parameters.size()]));
+        CodeTreeBuilder builder = method.createBuilder();
+        builder.startReturn();
+        builder.startNew(getElement().asType());
+        for (VariableElement param : parameters) {
+            builder.string(((CodeVariableElement) param).getName());
+        }
+        builder.end().end();
+        return method;
+    }
+}
\ No newline at end of file