diff graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java @ 20938:18c0f02fa4d2

Truffle-DSL: make type systems optional.
author Christian Humer <christian.humer@gmail.com>
date Tue, 14 Apr 2015 15:12:48 +0200
parents 1671d9111c47
children 476374f3fe9a
line wrap: on
line diff
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Tue Apr 14 22:12:03 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Tue Apr 14 15:12:48 2015 +0200
@@ -61,16 +61,19 @@
     private final ProcessorContext context;
     private final NodeData node;
     private final TypeSystemData typeSystem;
-    private final TypeData genericType;
+    private final TypeMirror genericType;
+    private final TypeMirror voidType;
     private final DSLOptions options;
     private final boolean singleSpecializable;
     private final int varArgsThreshold;
+    private final Set<TypeMirror> expectedTypes = new HashSet<>();
 
     public NodeGenFactory(ProcessorContext context, NodeData node) {
         this.context = context;
         this.node = node;
         this.typeSystem = node.getTypeSystem();
-        this.genericType = typeSystem.getGenericTypeData();
+        this.genericType = context.getType(Object.class);
+        this.voidType = context.getType(void.class);
         this.options = typeSystem.getOptions();
         this.singleSpecializable = isSingleSpecializableImpl();
         this.varArgsThreshold = calculateVarArgsThreshold();
@@ -139,8 +142,8 @@
         return "exclude" + specialization.getId() + NAME_SUFFIX;
     }
 
-    private static String executeChildMethodName(NodeExecutionData execution, TypeData type) {
-        return "execute" + ElementUtils.firstLetterUpperCase(execution.getName()) + (type.isGeneric() ? "" : getTypeId(type.getBoxedType())) + NAME_SUFFIX;
+    private static String executeChildMethodName(NodeExecutionData execution, TypeMirror type) {
+        return "execute" + ElementUtils.firstLetterUpperCase(execution.getName()) + (ElementUtils.isObject(type) ? "" : getTypeId(type)) + NAME_SUFFIX;
     }
 
     private CodeTree accessParent(String name) {
@@ -186,7 +189,9 @@
         }
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
-            clazz.add(createNodeField(PRIVATE, execution.getNodeType(), nodeFieldName(execution), Child.class));
+            if (execution.getChild() != null) {
+                clazz.add(createNodeField(PRIVATE, execution.getNodeType(), nodeFieldName(execution), Child.class));
+            }
         }
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
@@ -201,7 +206,7 @@
             }
         }
 
-        Collection<TypeData> specializedTypes = node.findSpecializedReturnTypes();
+        Collection<TypeMirror> specializedTypes = node.findSpecializedReturnTypes();
         List<ExecutableTypeData> implementedExecutables = new ArrayList<>();
         for (ExecutableTypeData execType : node.getExecutableTypes()) {
             if (shouldImplementExecutableType(specializedTypes, execType)) {
@@ -235,6 +240,12 @@
             }
         }
 
+        for (TypeMirror type : ElementUtils.uniqueSortedTypes(expectedTypes)) {
+            if (!typeSystem.hasType(type)) {
+                clazz.addOptional(TypeSystemCodeGenerator.createExpectMethod(PRIVATE, typeSystem, context.getType(Object.class), type));
+            }
+        }
+
         return clazz;
     }
 
@@ -295,7 +306,7 @@
                     CodeTree nameTree = CodeTreeBuilder.singleString(name);
                     CodeTreeBuilder callBuilder = builder.create();
                     callBuilder.string(name).string(" != null ? ");
-                    callBuilder.tree(callTemplateMethod(null, createCast, nameTree));
+                    callBuilder.tree(callMethod(null, createCast.getMethod(), nameTree));
                     callBuilder.string(" : null");
                     name += "_";
                     builder.declaration(child.getNodeType(), name, callBuilder.build());
@@ -305,6 +316,9 @@
         }
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
+            if (execution.getChild() == null) {
+                continue;
+            }
             CreateCastData createCast = node.findCast(execution.getChild().getName());
 
             builder.startStatement();
@@ -315,18 +329,18 @@
             accessorBuilder.string(name);
 
             if (execution.isIndexed()) {
-                accessorBuilder.string("[").string(String.valueOf(execution.getIndex())).string("]");
+                accessorBuilder.string("[").string(String.valueOf(execution.getChildIndex())).string("]");
             }
 
             CodeTree accessor = accessorBuilder.build();
 
             if (createCast != null && execution.getChild().getCardinality().isOne()) {
-                accessor = callTemplateMethod(null, createCast, accessor);
+                accessor = callMethod(null, createCast.getMethod(), accessor);
             }
 
             if (execution.isIndexed()) {
                 CodeTreeBuilder nullCheck = builder.create();
-                nullCheck.string(name).string(" != null && ").string(String.valueOf(execution.getIndex())).string(" < ").string(name).string(".length").string(" ? ");
+                nullCheck.string(name).string(" != null && ").string(String.valueOf(execution.getChildIndex())).string(" < ").string(name).string(".length").string(" ? ");
                 nullCheck.tree(accessor);
                 nullCheck.string(" : null");
                 accessor = nullCheck.build();
@@ -378,8 +392,8 @@
 
         SpecializationData specialization = reachableSpecializations.get(0);
         for (Parameter parameter : specialization.getSignatureParameters()) {
-            TypeData type = parameter.getTypeSystemType();
-            if (type != null && type.hasImplicitSourceTypes()) {
+            TypeMirror type = parameter.getType();
+            if (type != null && typeSystem.hasImplicitSourceTypes(type)) {
                 return true;
             }
         }
@@ -410,9 +424,9 @@
         }
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
-            Collection<TypeData> specializedTypes = node.findSpecializedTypes(execution);
+            Collection<TypeMirror> specializedTypes = node.findSpecializedTypes(execution);
             specializedTypes.add(genericType);
-            for (TypeData specializedType : specializedTypes) {
+            for (TypeMirror specializedType : specializedTypes) {
                 if (isExecuteChildShared(execution, specializedType)) {
                     clazz.add(createExecuteChildMethod(execution, specializedType));
                 }
@@ -428,10 +442,10 @@
         CodeExecutableElement constructor = clazz.addOptional(createSpecializationConstructor(clazz, specialization, null));
 
         for (Parameter p : specialization.getSignatureParameters()) {
-            TypeData targetType = p.getTypeSystemType();
-            if (targetType.hasImplicitSourceTypes()) {
+            TypeMirror targetType = p.getType();
+            if (typeSystem.hasImplicitSourceTypes(targetType)) {
                 NodeExecutionData execution = p.getSpecification().getExecution();
-                CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getTypeSystemType());
+                CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getType());
                 if (implicitProfile != null) {
                     implicitProfile.getModifiers().add(PRIVATE);
                     implicitProfile.getModifiers().add(FINAL);
@@ -449,21 +463,21 @@
         clazz.addOptional(createIsSameMethod(specialization));
         clazz.addOptional(createIsIdenticalMethod(specialization));
 
-        TypeData returnType = specialization.getReturnType().getTypeSystemType();
+        TypeMirror returnType = specialization.getReturnType().getType();
         int signatureSize = specialization.getSignatureSize();
 
         clazz.add(createFastPathExecuteMethod(specialization, null, signatureSize));
 
         if (isTypeBoxingEliminated(specialization)) {
-            clazz.add(createFastPathExecuteMethod(specialization, returnType, 0));
-
-            if (signatureSize > 0 && !returnType.isGeneric()) {
-                clazz.add(createFastPathWrapExecuteMethod(genericType, returnType));
-            }
-
-            ExecutableTypeData voidExecutableType = node.findExecutableType(typeSystem.getVoidType(), 0);
-            if (voidExecutableType != null && isTypeBoxingOptimized(options.voidBoxingOptimization(), returnType)) {
-                clazz.add(createFastPathWrapVoidMethod(returnType));
+            if (node.getMinimalEvaluatedParameters() == 0 || signatureSize == 0) {
+                clazz.add(createFastPathExecuteMethod(specialization, returnType, 0));
+                if (signatureSize > 0 && !isObject(returnType)) {
+                    clazz.add(createFastPathWrapExecuteMethod(genericType, returnType));
+                }
+                ExecutableTypeData voidExecutableType = node.findExecutableType(voidType, 0);
+                if (voidExecutableType != null && isTypeBoxingOptimized(options.voidBoxingOptimization(), returnType)) {
+                    clazz.add(createFastPathWrapVoidMethod(returnType));
+                }
             }
         }
 
@@ -517,7 +531,7 @@
             }
         };
 
-        builder.tree(createGuardAndCast(group, typeSystem.getGenericTypeData(), currentLocals, executionFactory));
+        builder.tree(createGuardAndCast(group, genericType, currentLocals, executionFactory));
         builder.returnFalse();
         return method;
     }
@@ -533,7 +547,7 @@
             if (execution == null) {
                 continue;
             }
-            CodeVariableElement var = createImplicitProfileParameter(execution, parameter.getTypeSystemType());
+            CodeVariableElement var = createImplicitProfileParameter(execution, parameter.getType());
             if (var != null) {
                 profiles.add(var);
             }
@@ -605,8 +619,9 @@
         return executable;
     }
 
-    private Element createFastPathWrapVoidMethod(TypeData wrap) {
-        CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), typeSystem.getVoidType().getPrimitiveType(), TypeSystemNodeFactory.executeName(typeSystem.getVoidType()));
+    private Element createFastPathWrapVoidMethod(TypeMirror wrap) {
+
+        CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), voidType, TypeSystemNodeFactory.executeName(voidType));
         executable.addParameter(new CodeVariableElement(getType(Frame.class), FRAME_VALUE));
         executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
         CodeTreeBuilder builder = executable.createBuilder();
@@ -619,8 +634,8 @@
         return executable;
     }
 
-    private Element createFastPathWrapExecuteMethod(TypeData override, TypeData wrap) {
-        CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), override.getPrimitiveType(), TypeSystemNodeFactory.executeName(override));
+    private Element createFastPathWrapExecuteMethod(TypeMirror override, TypeMirror wrap) {
+        CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), override, TypeSystemNodeFactory.executeName(override));
         executable.addParameter(new CodeVariableElement(getType(Frame.class), FRAME_VALUE));
         executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
         CodeTreeBuilder builder = executable.createBuilder();
@@ -758,11 +773,11 @@
         }
 
         TypeBoxingOptimization optimization = options.monomorphicTypeBoxingOptimization();
-        if (isTypeBoxingOptimized(optimization, specialization.getReturnType().getTypeSystemType())) {
+        if (isTypeBoxingOptimized(optimization, specialization.getReturnType().getType())) {
             return true;
         }
         for (Parameter p : specialization.getSignatureParameters()) {
-            if (isTypeBoxingOptimized(optimization, p.getTypeSystemType())) {
+            if (isTypeBoxingOptimized(optimization, p.getType())) {
                 return true;
             }
         }
@@ -772,7 +787,7 @@
 
     private Set<Integer> getEvaluatedCounts() {
         Set<Integer> evaluatedCount = new TreeSet<>();
-        Collection<TypeData> returnSpecializedTypes = node.findSpecializedReturnTypes();
+        Collection<TypeMirror> returnSpecializedTypes = node.findSpecializedReturnTypes();
         for (ExecutableTypeData execType : node.getExecutableTypes()) {
             if (shouldImplementExecutableType(returnSpecializedTypes, execType)) {
                 evaluatedCount.add(execType.getEvaluatedCount());
@@ -788,7 +803,7 @@
         }
         LocalContext locals = LocalContext.load(this);
 
-        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType.getPrimitiveType(), "unsupported", FRAME_VALUE);
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType, "unsupported", FRAME_VALUE);
         method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
 
         CodeTreeBuilder builder = method.createBuilder();
@@ -808,8 +823,8 @@
         SpecializationData specialization = reachableSpecializations.get(0);
 
         for (Parameter parameter : specialization.getSignatureParameters()) {
-            TypeData type = parameter.getTypeSystemType();
-            if (type != null && type.hasImplicitSourceTypes()) {
+            TypeMirror type = parameter.getType();
+            if (type != null && typeSystem.hasImplicitSourceTypes(type)) {
                 return false;
             }
         }
@@ -853,22 +868,23 @@
 
     private CodeExecutableElement createExecutableTypeOverride(List<ExecutableTypeData> implementedExecutables, ExecutableTypeData execType) {
         final String varArgsName = "args";
-        final TypeData returnType = execType.getType();
-        final TypeData executedType = execType.getEvaluatedCount() > 0 ? null : returnType;
-
-        CodeExecutableElement method = cloneExecutableTypeOverride(execType, varArgsName);
-        LocalContext locals = LocalContext.load(this, execType.getSignatureSize(), Integer.MAX_VALUE);
+        final TypeMirror returnType = execType.getReturnType();
+        final TypeMirror executedType = execType.getEvaluatedCount() > 0 ? null : returnType;
+
+        LocalContext locals = LocalContext.load(this, execType.getEvaluatedCount(), Integer.MAX_VALUE);
+        CodeExecutableElement method = cloneExecutableTypeOverride(locals, execType, varArgsName);
 
         // rename varargs parameter
         int signatureIndex = 0;
-        for (Parameter parameter : execType.getSignatureParameters()) {
-            LocalVariable var = locals.get(parameter, signatureIndex);
+        for (TypeMirror parameter : execType.getEvaluatedParameters()) {
+            LocalVariable var = locals.getValue(signatureIndex);
             if (var != null) {
-                if (parameter.isTypeVarArgs()) {
-                    var = var.accessWith(CodeTreeBuilder.singleString(varArgsName + "[" + parameter.getTypeVarArgsIndex() + "]"));
+                int varArgsIndex = execType.getVarArgsIndex(execType.getParameterIndex(signatureIndex));
+                if (varArgsIndex >= 0) {
+                    var = var.accessWith(CodeTreeBuilder.singleString(varArgsName + "[" + varArgsIndex + "]"));
                 }
-                if (!parameter.getTypeSystemType().isGeneric()) {
-                    var = var.newType(parameter.getTypeSystemType());
+                if (!isObject(parameter)) {
+                    var = var.newType(parameter);
                 }
                 locals.setValue(node.getChildExecutions().get(signatureIndex), var);
             }
@@ -876,12 +892,12 @@
             signatureIndex++;
         }
 
-        Parameter frame = execType.getFrame();
+        TypeMirror frame = execType.getFrameParameter();
         CodeTreeBuilder builder = method.createBuilder();
         if (singleSpecializable) {
             LocalVariable frameVar = null;
             if (frame != null) {
-                frameVar = locals.get(FRAME_VALUE).newType(frame.getType());
+                frameVar = locals.get(FRAME_VALUE).newType(frame);
             }
             method.getThrownTypes().clear();
             locals.set(FRAME_VALUE, frameVar);
@@ -889,9 +905,9 @@
             SpecializationData specialization = getReachableSpecializations().iterator().next();
             ExecutableTypeData wrappedExecutableType = findWrappedExecutable(specialization, implementedExecutables, execType);
             if (wrappedExecutableType != null) {
-                builder.startReturn().tree(callTemplateMethod(null, wrappedExecutableType, locals)).end();
+                builder.startReturn().tree(callExecuteMethod(null, wrappedExecutableType, locals)).end();
             } else {
-                builder.tree(createFastPath(builder, specialization, execType.getType(), locals));
+                builder.tree(createFastPath(builder, specialization, execType.getReturnType(), locals));
             }
         } else {
             // create acceptAndExecute
@@ -900,23 +916,23 @@
             if (frame == null) {
                 executeBuilder.nullLiteral();
             } else {
-                executeBuilder.string(frame.getLocalName());
+                executeBuilder.string(locals.get(FRAME_VALUE).getName());
             }
             locals.addReferencesTo(executeBuilder);
             executeBuilder.end();
 
-            boolean hasExecutedUnexpected = executedType != null && !executedType.isGeneric() && !executedType.isVoid();
+            boolean hasExecutedUnexpected = executedType != null && !isObject(executedType) && !isVoid(executedType);
 
             CodeTreeBuilder contentBuilder = builder.create();
             contentBuilder.startReturn();
             if (!hasExecutedUnexpected && !execType.hasUnexpectedValue(context)) {
-                if (executedType == null || executedType.needsCastTo(returnType)) {
-                    contentBuilder.cast(returnType.getPrimitiveType(), executeBuilder.build());
+                if (executedType == null || needsCastTo(executedType, returnType)) {
+                    contentBuilder.cast(returnType, executeBuilder.build());
                 } else {
                     contentBuilder.tree(executeBuilder.build());
                 }
             } else {
-                contentBuilder.tree(TypeSystemCodeGenerator.expect(executedType, returnType, executeBuilder.build()));
+                contentBuilder.tree(expect(executedType, returnType, executeBuilder.build()));
             }
             contentBuilder.end();
             // try catch assert if unexpected value is not expected
@@ -940,12 +956,12 @@
     }
 
     private static ExecutableTypeData findWrappedExecutable(SpecializationData specialization, List<ExecutableTypeData> implementedExecutables, ExecutableTypeData executedType) {
-        if (specialization.getReturnType().getTypeSystemType() == executedType.getType()) {
+        if (specialization.getReturnType().getType() == executedType.getReturnType()) {
             return null;
         }
         for (ExecutableTypeData otherType : implementedExecutables) {
             if (otherType != executedType && //
-                            otherType.getType() == specialization.getReturnType().getTypeSystemType() && //
+                            otherType.getReturnType() == specialization.getReturnType().getType() && //
                             otherType.getEvaluatedCount() == executedType.getEvaluatedCount()) {
                 return otherType;
             }
@@ -953,43 +969,50 @@
         return null;
     }
 
-    private CodeExecutableElement cloneExecutableTypeOverride(ExecutableTypeData execType, final String varArgsName) throws AssertionError {
+    private CodeExecutableElement cloneExecutableTypeOverride(LocalContext locals, ExecutableTypeData execType, final String varArgsName) throws AssertionError {
         CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), execType.getMethod());
 
         method.getAnnotationMirrors().clear();
         method.getModifiers().remove(Modifier.ABSTRACT);
 
-        if (!execType.getMethod().isVarArgs() && execType.getParameters().size() != method.getParameters().size()) {
-            throw new AssertionError("Should be verified in the parser");
+        // align argument names
+        int parameterIndex = 0;
+        if (execType.getFrameParameter() != null) {
+            CodeVariableElement frameParameter = (CodeVariableElement) method.getParameters().get(0);
+            frameParameter.setName(FRAME_VALUE);
+            frameParameter.getAnnotationMirrors().clear();
+            parameterIndex++;
         }
 
-        // align argument names
-        int index = 0;
-        for (Parameter parameter : execType.getParameters()) {
-            CodeVariableElement var = (CodeVariableElement) method.getParameters().get(index);
-            if (parameter.isTypeVarArgs()) {
+        for (int signatureIndex = 0; signatureIndex < execType.getEvaluatedCount(); signatureIndex++) {
+            CodeVariableElement var = (CodeVariableElement) method.getParameters().get(parameterIndex);
+            if (signatureIndex < node.getSignatureSize()) {
+                if (execType.getVarArgsIndex(parameterIndex) >= 0) {
+                    var.getAnnotationMirrors().clear();
+                    var.setName(varArgsName);
+                    break;
+                }
+                var.setName(locals.getValue(signatureIndex).getName());
                 var.getAnnotationMirrors().clear();
-                var.setName(varArgsName);
-                break;
+            } else {
+                var.setName("other" + signatureIndex);
             }
-            var.setName(LocalVariable.fromParameter(parameter).createParameter().getName());
-            var.getAnnotationMirrors().clear();
-            index++;
+            parameterIndex++;
         }
         return method;
     }
 
-    private boolean shouldImplementExecutableType(Collection<TypeData> specializedTypes, ExecutableTypeData execType) {
-        TypeData type = execType.getType();
+    private boolean shouldImplementExecutableType(Collection<TypeMirror> specializedTypes, ExecutableTypeData execType) {
+        TypeMirror type = execType.getReturnType();
         Set<Modifier> modifiers = execType.getMethod().getModifiers();
         if (modifiers.contains(FINAL) || modifiers.contains(STATIC) || modifiers.contains(PRIVATE)) {
             return false;
         } else if (execType.isAbstract()) {
             return true;
-        } else if (type.isGeneric()) {
+        } else if (ElementUtils.isObject(type)) {
             return true;
-        } else if (type.isVoid()) {
-            for (TypeData specializedType : specializedTypes) {
+        } else if (ElementUtils.isVoid(type)) {
+            for (TypeMirror specializedType : specializedTypes) {
                 if (isTypeBoxingOptimized(options.voidBoxingOptimization(), specializedType)) {
                     return true;
                 }
@@ -1021,7 +1044,7 @@
         return childField;
     }
 
-    private static List<ExecutableTypeData> resolveSpecializedExecutables(NodeExecutionData execution, Collection<TypeData> types, TypeBoxingOptimization optimization) {
+    private static List<ExecutableTypeData> resolveSpecializedExecutables(NodeExecutionData execution, Collection<TypeMirror> types, TypeBoxingOptimization optimization) {
         if (optimization == TypeBoxingOptimization.NONE) {
             return Collections.emptyList();
         } else if (types.isEmpty()) {
@@ -1029,10 +1052,13 @@
         }
 
         List<ExecutableTypeData> executables = new ArrayList<>();
-        for (TypeData type : types) {
+        for (TypeMirror type : types) {
             if (!isTypeBoxingOptimized(optimization, type)) {
                 continue;
             }
+            if (execution.getChild() == null) {
+                continue;
+            }
             ExecutableTypeData foundType = execution.getChild().getNodeData().findExecutableType(type, execution.getChild().getExecuteWith().size());
             if (foundType != null) {
                 executables.add(foundType);
@@ -1041,15 +1067,15 @@
         return executables;
     }
 
-    private static CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, CodeTree... boundValues) {
+    private static CodeTree callMethod(CodeTree receiver, ExecutableElement method, CodeTree... boundValues) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        if (method.getMethod().getModifiers().contains(STATIC)) {
-            builder.startStaticCall(method.getMethod().getEnclosingElement().asType(), method.getMethodName());
+        if (method.getModifiers().contains(STATIC)) {
+            builder.startStaticCall(method.getEnclosingElement().asType(), method.getSimpleName().toString());
         } else {
-            builder.startCall(receiver, method.getMethodName());
+            builder.startCall(receiver, method.getSimpleName().toString());
         }
         int index = -1;
-        for (Parameter parameter : method.getParameters()) {
+        for (VariableElement parameter : method.getParameters()) {
             index++;
             if (index < boundValues.length) {
                 CodeTree tree = boundValues[index];
@@ -1059,13 +1085,39 @@
                 }
             }
 
-            builder.defaultValue(parameter.getType());
+            builder.defaultValue(parameter.asType());
         }
         builder.end();
         return builder.build();
     }
 
-    private static CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, LocalContext currentValues) {
+    private CodeTree callExecuteMethod(NodeExecutionData execution, ExecutableTypeData method, LocalContext currentValues) {
+        CodeTree receiver = execution != null ? accessParent(nodeFieldName(execution)) : null;
+        List<NodeExecutionData> executeWith = execution != null ? execution.getChild().getExecuteWith() : null;
+
+        List<CodeTree> values = new ArrayList<>();
+        if (method.getFrameParameter() != null) {
+            LocalVariable frameLocal = currentValues.get(FRAME_VALUE);
+            if (frameLocal == null) {
+                values.add(CodeTreeBuilder.singleString("null"));
+            } else {
+                values.add(createTypeSafeReference(frameLocal, method.getFrameParameter()));
+            }
+        }
+        for (int parameterIndex = 0; parameterIndex < method.getEvaluatedCount(); parameterIndex++) {
+            TypeMirror targetParameter = method.getEvaluatedParameters().get(parameterIndex);
+            LocalVariable variable;
+            if (executeWith != null && parameterIndex < executeWith.size()) {
+                variable = currentValues.getValue(executeWith.get(parameterIndex));
+            } else {
+                variable = currentValues.getValue(parameterIndex);
+            }
+            values.add(createTypeSafeReference(variable, targetParameter));
+        }
+        return callMethod(receiver, method.getMethod(), values.toArray(new CodeTree[values.size()]));
+    }
+
+    private CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, LocalContext currentValues) {
         CodeTree[] bindings = new CodeTree[method.getParameters().size()];
 
         int signatureIndex = 0;
@@ -1078,20 +1130,28 @@
             }
 
             if (var != null) {
-                CodeTree valueReference = var.createReference();
-                if (parameter.getTypeSystemType() != null && var.getType() != null && var.getType().needsCastTo(parameter.getTypeSystemType())) {
-                    valueReference = TypeSystemCodeGenerator.cast(parameter.getTypeSystemType(), valueReference);
-                } else if (ElementUtils.needsCastTo(var.getTypeMirror(), parameter.getType())) {
-                    valueReference = CodeTreeBuilder.createBuilder().cast(parameter.getType(), valueReference).build();
-                }
-                bindings[i] = valueReference;
+                bindings[i] = createTypeSafeReference(var, parameter.getType());
             }
 
             if (parameter.getSpecification().isSignature()) {
                 signatureIndex++;
             }
         }
-        return callTemplateMethod(receiver, method, bindings);
+        return callMethod(receiver, method.getMethod(), bindings);
+    }
+
+    private CodeTree createTypeSafeReference(LocalVariable var, TypeMirror targetType) {
+        CodeTree valueReference = var.createReference();
+        TypeMirror sourceType = var.getTypeMirror();
+        if (targetType == null || sourceType == null) {
+            return valueReference;
+        }
+        if (needsCastTo(sourceType, targetType)) {
+            valueReference = TypeSystemCodeGenerator.cast(typeSystem, targetType, valueReference);
+        } else if (ElementUtils.needsCastTo(sourceType, targetType)) {
+            valueReference = CodeTreeBuilder.createBuilder().cast(targetType, valueReference).build();
+        }
+        return valueReference;
     }
 
     private SpecializationGroup createSpecializationGroups() {
@@ -1125,7 +1185,7 @@
                 String varName = name + specialization.getIndex();
                 TypeMirror type = assumption.getExpression().getResolvedType();
                 builder.declaration(type, varName, assumptions);
-                currentValues.set(name, new LocalVariable(null, type, varName, null, null));
+                currentValues.set(name, new LocalVariable(type, varName, null, null));
             }
 
             builder.startIf();
@@ -1189,14 +1249,14 @@
         return builder.build();
     }
 
-    private boolean hasFallthrough(SpecializationGroup group, TypeData forType, LocalContext currentValues, boolean fastPath, List<GuardExpression> ignoreGuards) {
+    private boolean hasFallthrough(SpecializationGroup group, TypeMirror forType, LocalContext currentValues, boolean fastPath, List<GuardExpression> ignoreGuards) {
         for (TypeGuard guard : group.getTypeGuards()) {
             if (currentValues.getValue(guard.getSignatureIndex()) == null) {
                 // not evaluated
                 return true;
             }
             LocalVariable value = currentValues.getValue(guard.getSignatureIndex());
-            if (value.getType().needsCastTo(guard.getType())) {
+            if (needsCastTo(value.getTypeMirror(), guard.getType())) {
                 return true;
             }
         }
@@ -1265,7 +1325,11 @@
             if (execution.isShortCircuit()) {
                 builder.nullLiteral();
             }
-            builder.tree(accessParent(nodeFieldName(execution)));
+            if (execution.getChild() == null) {
+                builder.nullLiteral();
+            } else {
+                builder.tree(accessParent(nodeFieldName(execution)));
+            }
         }
         builder.end();
         return builder.build();
@@ -1289,7 +1353,7 @@
         }
         if (currentValues != null) {
             for (Parameter p : specialization.getSignatureParameters()) {
-                CodeVariableElement var = createImplicitProfileParameter(p.getSpecification().getExecution(), p.getTypeSystemType());
+                CodeVariableElement var = createImplicitProfileParameter(p.getSpecification().getExecution(), p.getType());
                 if (var != null) {
                     LocalVariable variable = currentValues.get(p.getLocalName());
                     if (variable == null) {
@@ -1370,19 +1434,19 @@
             for (Parameter p : specialization.getSignatureParameters()) {
                 NodeExecutionData execution = p.getSpecification().getExecution();
 
-                CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getTypeSystemType());
+                CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getType());
                 if (implicitProfile != null) {
-                    LocalVariable var = LocalVariable.fromParameter(p).makeGeneric();
+                    LocalVariable var = LocalVariable.fromParameter(p).makeGeneric(context);
 
                     String implicitFieldName = implicitProfile.getName();
                     if (options.implicitCastOptimization().isDuplicateTail()) {
                         constructor.addParameter(var.createParameter());
-                        CodeTree implicitType = TypeSystemCodeGenerator.implicitType(p.getTypeSystemType(), var.createReference());
+                        CodeTree implicitType = TypeSystemCodeGenerator.implicitType(typeSystem, p.getType(), var.createReference());
                         builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(implicitType).end();
                     } else if (options.implicitCastOptimization().isMergeCasts()) {
                         // use node that supports polymorphism
                         constructor.addParameter(var.createParameter());
-                        builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(ImplicitCastNodeFactory.create(p.getTypeSystemType(), var.createReference())).end();
+                        builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(ImplicitCastNodeFactory.create(typeSystem, p.getType(), var.createReference())).end();
                     } else {
                         throw new AssertionError();
                     }
@@ -1443,7 +1507,7 @@
         return builder.build();
     }
 
-    private CodeTree createCallNext(TypeData forType, LocalContext currentValues) {
+    private CodeTree createCallNext(TypeMirror forType, LocalContext currentValues) {
         if (singleSpecializable) {
             return createThrowUnsupported(currentValues);
         }
@@ -1451,10 +1515,10 @@
         callBuilder.startCall("next", TypeSystemNodeFactory.executeName(null));
         currentValues.addReferencesTo(callBuilder, FRAME_VALUE);
         callBuilder.end();
-        return CodeTreeBuilder.createBuilder().startReturn().tree(TypeSystemCodeGenerator.expect(genericType, forType, callBuilder.build())).end().build();
+        return CodeTreeBuilder.createBuilder().startReturn().tree(expect(genericType, forType, callBuilder.build())).end().build();
     }
 
-    private CodeTree createCallRemove(String reason, TypeData forType, LocalContext currentValues) {
+    private CodeTree createCallRemove(String reason, TypeMirror forType, LocalContext currentValues) {
         if (singleSpecializable) {
             return createThrowUnsupported(currentValues);
         }
@@ -1467,12 +1531,12 @@
 
         builder = builder.create();
         builder.startReturn();
-        builder.tree(TypeSystemCodeGenerator.expect(genericType, forType, call));
+        builder.tree(expect(genericType, forType, call));
         builder.end();
         return builder.build();
     }
 
-    private static CodeTree createCallDelegate(String methodName, String reason, TypeData forType, LocalContext currentValues) {
+    private CodeTree createCallDelegate(String methodName, String reason, TypeMirror forType, LocalContext currentValues) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         builder.startCall(methodName);
         if (reason != null) {
@@ -1481,21 +1545,28 @@
         currentValues.addReferencesTo(builder, FRAME_VALUE);
         builder.end();
 
-        TypeData executedType = forType.getTypeSystem().getGenericTypeData();
-        return TypeSystemCodeGenerator.expect(executedType, forType, builder.build());
+        return expect(genericType, forType, builder.build());
     }
 
-    private Set<ExecutableTypeData> findSpecializedExecutableTypes(NodeExecutionData execution, TypeData type) {
+    private CodeTree expect(TypeMirror sourceType, TypeMirror forType, CodeTree tree) {
+        expectedTypes.add(forType);
+        return TypeSystemCodeGenerator.expect(typeSystem, sourceType, forType, tree);
+    }
+
+    private Set<ExecutableTypeData> findSpecializedExecutableTypes(NodeExecutionData execution, TypeMirror type) {
+        if (execution.getChild() == null) {
+            return Collections.emptySet();
+        }
         ExecutableTypeData executableType = resolveExecutableType(execution.getChild(), type);
         Set<ExecutableTypeData> executedTypes = new HashSet<>();
         executedTypes.add(executableType);
-        if (type.hasImplicitSourceTypes()) {
-            executedTypes.addAll(resolveSpecializedExecutables(execution, type.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()));
+        if (typeSystem.hasImplicitSourceTypes(type)) {
+            executedTypes.addAll(resolveSpecializedExecutables(execution, typeSystem.lookupSourceTypes(type), options.implicitTypeBoxingOptimization()));
         }
         return executedTypes;
     }
 
-    private ExecutableTypeData resolveExecutableType(NodeChildData child, TypeData type) {
+    private ExecutableTypeData resolveExecutableType(NodeChildData child, TypeMirror type) {
         int executeWithCount = child.getExecuteWith().size();
         ExecutableTypeData executableType = child.getNodeData().findExecutableType(type, executeWithCount);
         if (executableType == null) {
@@ -1504,27 +1575,27 @@
         return executableType;
     }
 
-    private boolean hasUnexpectedResult(NodeExecutionData execution, TypeData type) {
+    private boolean hasUnexpectedResult(NodeExecutionData execution, TypeMirror type) {
         for (ExecutableTypeData executableType : findSpecializedExecutableTypes(execution, type)) {
-            if (executableType != null && (executableType.hasUnexpectedValue(context) || executableType.getType().needsCastTo(type))) {
+            if (executableType != null && (executableType.hasUnexpectedValue(context) || needsCastTo(executableType.getReturnType(), type))) {
                 return true;
             }
         }
         return false;
     }
 
-    private Element createFastPathExecuteMethod(SpecializationData specialization, final TypeData forType, int evaluatedArguments) {
-        TypeData type = forType == null ? genericType : forType;
+    private Element createFastPathExecuteMethod(SpecializationData specialization, final TypeMirror forType, int evaluatedArguments) {
+        TypeMirror type = forType == null ? genericType : forType;
         LocalContext currentLocals = LocalContext.load(this, evaluatedArguments, varArgsThreshold);
 
         if (specialization != null) {
             currentLocals.loadFastPathState(specialization);
         }
 
-        CodeExecutableElement executable = currentLocals.createMethod(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemNodeFactory.executeName(forType), FRAME_VALUE);
+        CodeExecutableElement executable = currentLocals.createMethod(modifiers(PUBLIC), type, TypeSystemNodeFactory.executeName(forType), FRAME_VALUE);
         executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
 
-        if (!type.isGeneric()) {
+        if (!isObject(type)) {
             executable.getThrownTypes().add(getType(UnexpectedResultException.class));
         }
 
@@ -1534,17 +1605,17 @@
         return executable;
     }
 
-    private CodeTree createFastPath(CodeTreeBuilder parent, SpecializationData specialization, TypeData type, LocalContext currentLocals) {
+    private CodeTree createFastPath(CodeTreeBuilder parent, SpecializationData specialization, TypeMirror type, LocalContext currentLocals) {
         final CodeTreeBuilder builder = parent.create();
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
             LocalVariable var = currentLocals.getValue(execution);
             if (var == null) {
-                TypeData targetType;
+                TypeMirror targetType;
                 if (specialization == null) {
                     targetType = genericType;
                 } else {
-                    targetType = specialization.findParameterOrDie(execution).getTypeSystemType();
+                    targetType = specialization.findParameterOrDie(execution).getType();
                 }
                 LocalVariable shortCircuit = resolveShortCircuit(specialization, execution, currentLocals);
                 LocalVariable value = currentLocals.createValue(execution, targetType).nextName();
@@ -1561,7 +1632,7 @@
         } else if (specialization.isUninitialized()) {
             builder.startReturn().tree(createCallDelegate("uninitialized", null, type, currentLocals)).end();
         } else {
-            final TypeData finalType = type;
+            final TypeMirror finalType = type;
             SpecializationGroup group = SpecializationGroup.create(specialization);
             SpecializationBody executionFactory = new SpecializationBody(true, true) {
                 @Override
@@ -1605,7 +1676,7 @@
         return shortCircuitIndex;
     }
 
-    private CodeTree createFastPathExecute(CodeTreeBuilder parent, final TypeData forType, SpecializationData specialization, LocalContext currentValues) {
+    private CodeTree createFastPathExecute(CodeTreeBuilder parent, final TypeMirror forType, SpecializationData specialization, LocalContext currentValues) {
         CodeTreeBuilder builder = parent.create();
         int ifCount = 0;
         if (specialization.isFallback()) {
@@ -1642,21 +1713,37 @@
             builder.end();
         }
 
-        execute.startReturn();
         if (specialization.getMethod() == null) {
+            execute.startReturn();
             execute.startCall("unsupported");
             currentValues.addReferencesTo(execute, FRAME_VALUE);
             execute.end();
+            execute.end();
         } else {
+            boolean doReturn = !isVoid(specialization.getMethod().getReturnType());
+            if (doReturn) {
+                execute.startReturn();
+            } else {
+                execute.startStatement();
+            }
             execute.tree(callTemplateMethod(accessParent(null), specialization, currentValues));
+            execute.end();
+            if (!doReturn) {
+                if (isVoid(forType)) {
+                    execute.returnStatement();
+                } else {
+                    execute.startReturn();
+                    execute.defaultValue(forType);
+                    execute.end();
+                }
+            }
         }
-        execute.end();
         builder.tree(createFastPathTryCatchRewriteException(specialization, forType, currentValues, execute.build()));
         builder.end(ifCount);
         return builder.build();
     }
 
-    private CodeTree createGuardAndCast(SpecializationGroup group, TypeData forType, LocalContext currentValues, SpecializationBody execution) {
+    private CodeTree createGuardAndCast(SpecializationGroup group, TypeMirror forType, LocalContext currentValues, SpecializationBody execution) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
 
         Set<TypeGuard> castGuards;
@@ -1780,10 +1867,10 @@
         return false;
     }
 
-    private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeData targetType) {
+    private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeMirror targetType) {
         LocalContext locals = LocalContext.load(this, 0, varArgsThreshold);
 
-        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType.getPrimitiveType(), executeChildMethodName(execution, targetType), FRAME_VALUE);
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType, executeChildMethodName(execution, targetType), FRAME_VALUE);
         if (hasUnexpectedResult(execution, targetType)) {
             method.getThrownTypes().add(getType(UnexpectedResultException.class));
         }
@@ -1810,30 +1897,30 @@
         return method;
     }
 
-    private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeData targetType) {
-        if (targetType.hasImplicitSourceTypes()) {
+    private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeMirror targetType) {
+        if (typeSystem.hasImplicitSourceTypes(targetType)) {
             switch (options.implicitCastOptimization()) {
                 case NONE:
                     return null;
                 case DUPLICATE_TAIL:
                     return new CodeVariableElement(getType(Class.class), implicitClassFieldName(execution));
                 case MERGE_CASTS:
-                    return new CodeVariableElement(ImplicitCastNodeFactory.type(targetType), implicitNodeFieldName(execution));
+                    return new CodeVariableElement(ImplicitCastNodeFactory.type(typeSystem, targetType), implicitNodeFieldName(execution));
             }
         }
         return null;
     }
 
-    private boolean isExecuteChildShared(NodeExecutionData execution, TypeData targetType) {
-        if (targetType.isVoid()) {
+    private boolean isExecuteChildShared(NodeExecutionData execution, TypeMirror targetType) {
+        if (isVoid(targetType)) {
             return false;
-        } else if (targetType.isGeneric()) {
+        } else if (isObject(targetType)) {
             return resolvePolymorphicExecutables(execution).size() >= 1;
         } else {
             if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), targetType)) {
                 return false;
             }
-            if (!targetType.hasImplicitSourceTypes()) {
+            if (!typeSystem.hasImplicitSourceTypes(targetType)) {
                 return false;
             }
 
@@ -1841,25 +1928,25 @@
             for (SpecializationData specialization : node.getSpecializations()) {
                 List<Parameter> parameters = specialization.findByExecutionData(execution);
                 for (Parameter parameter : parameters) {
-                    if (targetType.equals(parameter.getTypeSystemType())) {
+                    if (targetType.equals(parameter.getType())) {
                         uses++;
                     }
                 }
             }
             if (uses > 1) {
-                return resolveSpecializedExecutables(execution, targetType.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()).size() > 1;
+                return resolveSpecializedExecutables(execution, typeSystem.lookupSourceTypes(targetType), options.implicitTypeBoxingOptimization()).size() > 1;
             } else {
                 return false;
             }
         }
     }
 
-    private CodeTree createAssignExecuteChild(NodeExecutionData execution, TypeData returnType, LocalVariable targetValue, LocalVariable shortCircuit, LocalContext currentValues) {
+    private CodeTree createAssignExecuteChild(NodeExecutionData execution, TypeMirror returnType, LocalVariable targetValue, LocalVariable shortCircuit, LocalContext currentValues) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        boolean hasUnexpected = hasUnexpectedResult(execution, targetValue.getType());
+        boolean hasUnexpected = hasUnexpectedResult(execution, targetValue.getTypeMirror());
 
         CodeTree executeChild;
-        if (isExecuteChildShared(execution, targetValue.getType())) {
+        if (isExecuteChildShared(execution, targetValue.getTypeMirror())) {
             executeChild = createCallSharedExecuteChild(execution, targetValue, currentValues);
         } else {
             executeChild = createExecuteChild(execution, targetValue, currentValues, false);
@@ -1876,7 +1963,7 @@
             builder.startCatchBlock(getType(UnexpectedResultException.class), "ex");
             LocalContext slowPathValues = currentValues.copy();
 
-            slowPathValues.setValue(execution, targetValue.makeGeneric().accessWith(CodeTreeBuilder.singleString("ex.getResult()")));
+            slowPathValues.setValue(execution, targetValue.makeGeneric(context).accessWith(CodeTreeBuilder.singleString("ex.getResult()")));
             boolean found = false;
             for (NodeExecutionData otherExecution : node.getChildExecutions()) {
                 if (found) {
@@ -1945,16 +2032,16 @@
     }
 
     private CodeTree createCallSharedExecuteChild(NodeExecutionData execution, LocalVariable targetValue, LocalContext currentValues) {
-        if (!isExecuteChildShared(execution, targetValue.getType())) {
+        if (!isExecuteChildShared(execution, targetValue.getTypeMirror())) {
             throw new AssertionError("Execute child not shared with method but called.");
         }
 
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         builder.tree(targetValue.createReference()).string(" = ");
-        builder.startCall(executeChildMethodName(execution, targetValue.getType()));
+        builder.startCall(executeChildMethodName(execution, targetValue.getTypeMirror()));
         builder.string(FRAME_VALUE);
 
-        CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetValue.getType());
+        CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetValue.getTypeMirror());
         if (implicitProfile != null) {
             builder.string(implicitProfile.getName());
         }
@@ -1970,12 +2057,12 @@
 
         CodeTree assignment = createAssignmentStart(target, shared);
 
-        final Set<ExecutableTypeData> executableTypes = findSpecializedExecutableTypes(execution, target.getType());
+        final Set<ExecutableTypeData> executableTypes = findSpecializedExecutableTypes(execution, target.getTypeMirror());
         if (executableTypes.isEmpty()) {
             throw new AssertionError(); // cannot execute child
-        } else if (executableTypes.size() == 1 && !target.getType().hasImplicitSourceTypes()) {
+        } else if (executableTypes.size() == 1 && !typeSystem.hasImplicitSourceTypes(target.getTypeMirror())) {
             ExecutableTypeData executableType = executableTypes.iterator().next();
-            if (target.getType().isGeneric() && executableType.getEvaluatedCount() == 0) {
+            if (isObject(target.getTypeMirror()) && executableType.getEvaluatedCount() == 0) {
                 return createPolymorphicExecuteChild(execution, target, currentValues, shared);
             } else {
                 builder.tree(assignment);
@@ -1997,9 +2084,8 @@
     }
 
     private CodeTree createSingleExecute(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, ExecutableTypeData executableType) {
-        CodeTree accessChild = accessParent(nodeFieldName(execution));
-        CodeTree execute = callTemplateMethod(accessChild, executableType, currentValues);
-        return TypeSystemCodeGenerator.expect(executableType.getType(), target.getType(), execute);
+        CodeTree execute = callExecuteMethod(execution, executableType, currentValues);
+        return expect(executableType.getReturnType(), target.getTypeMirror(), execute);
     }
 
     private CodeTree createPolymorphicExecuteChild(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, boolean shared) throws AssertionError {
@@ -2011,7 +2097,7 @@
         List<ExecutableTypeData> specializedExecutables = resolvePolymorphicExecutables(execution);
         Collections.sort(specializedExecutables, new Comparator<ExecutableTypeData>() {
             public int compare(ExecutableTypeData o1, ExecutableTypeData o2) {
-                return o1.getType().compareTo(o2.getType());
+                return compareType(o1.getReturnType(), o2.getReturnType());
             }
         });
 
@@ -2034,7 +2120,7 @@
             for (ExecutableTypeData executableType : specializedExecutables) {
                 hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes);
                 polyChainBuilder.string(profileField);
-                polyChainBuilder.string(" == ").typeLiteral(executableType.getType().getPrimitiveType());
+                polyChainBuilder.string(" == ").typeLiteral(executableType.getReturnType());
                 polyChainBuilder.end();
                 polyChainBuilder.startBlock();
                 polyChainBuilder.startStatement();
@@ -2048,20 +2134,20 @@
             polyChainBuilder.startElseIf().string(profileField).string(" == null").end();
             polyChainBuilder.startBlock();
             polyChainBuilder.tree(createTransferToInterpreterAndInvalidate());
-            polyChainBuilder.declaration(genericExecutableType.getType().getPrimitiveType(), valueFieldName, executeGeneric);
+            polyChainBuilder.declaration(genericExecutableType.getReturnType(), valueFieldName, executeGeneric);
 
             hasSpecializedTypes = false;
             for (ExecutableTypeData executableType : specializedExecutables) {
                 hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes);
-                polyChainBuilder.tree(TypeSystemCodeGenerator.check(executableType.getType(), CodeTreeBuilder.singleString(valueFieldName)));
+                polyChainBuilder.tree(TypeSystemCodeGenerator.check(typeSystem, executableType.getReturnType(), CodeTreeBuilder.singleString(valueFieldName)));
                 polyChainBuilder.end();
                 polyChainBuilder.startBlock();
-                polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(executableType.getType().getPrimitiveType()).end();
+                polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(executableType.getReturnType()).end();
                 polyChainBuilder.end();
             }
 
             polyChainBuilder.startElseBlock();
-            polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType.getPrimitiveType()).end();
+            polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType).end();
             polyChainBuilder.end();
             polyChainBuilder.startReturn().string(valueFieldName).end();
             polyChainBuilder.end();
@@ -2077,7 +2163,7 @@
                 builder.tree(executePolymorphic);
                 builder.end();
                 builder.startCatchBlock(getType(UnexpectedResultException.class), "ex");
-                builder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType.getPrimitiveType()).end();
+                builder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType).end();
                 builder.startReturn().string("ex.getResult()").end();
                 builder.end();
             } else {
@@ -2091,9 +2177,9 @@
         if (singleSpecializable) {
             return Collections.emptyList();
         }
-        Set<TypeData> specializedTypes = new HashSet<>();
-        for (TypeData type : node.findSpecializedTypes(execution)) {
-            specializedTypes.addAll(type.getImplicitSourceTypes());
+        Set<TypeMirror> specializedTypes = new HashSet<>();
+        for (TypeMirror type : node.findSpecializedTypes(execution)) {
+            specializedTypes.addAll(typeSystem.lookupSourceTypes(type));
         }
         return resolveSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination());
     }
@@ -2110,23 +2196,22 @@
 
     private CodeTree createExecuteChildDuplicateTail(CodeTreeBuilder parent, NodeExecutionData execution, CodeTree assignment, LocalVariable target, LocalContext currentValues) {
         CodeTreeBuilder builder = parent.create();
-        List<TypeData> sourceTypes = target.getType().getImplicitSourceTypes();
+        List<TypeMirror> sourceTypes = typeSystem.lookupSourceTypes(target.getTypeMirror());
         String implicitClassFieldName = implicitClassFieldName(execution);
-        String nodeFieldName = nodeFieldName(execution);
         List<ExecutableTypeData> executableTypes = resolveSpecializedExecutables(execution, sourceTypes, options.implicitTypeBoxingOptimization());
 
         boolean elseIf = false;
         for (ExecutableTypeData executableType : executableTypes) {
             elseIf = builder.startIf(elseIf);
-            builder.string(implicitClassFieldName).string(" == ").typeLiteral(executableType.getType().getPrimitiveType());
+            builder.string(implicitClassFieldName).string(" == ").typeLiteral(executableType.getReturnType());
             builder.end();
             builder.startBlock();
             builder.startStatement().tree(assignment);
 
-            CodeTree execute = callTemplateMethod(accessParent(nodeFieldName), executableType, currentValues);
-            ImplicitCastData cast = typeSystem.lookupCast(executableType.getType(), target.getType());
+            CodeTree execute = callExecuteMethod(execution, executableType, currentValues);
+            ImplicitCastData cast = typeSystem.lookupCast(executableType.getReturnType(), target.getTypeMirror());
             if (cast != null) {
-                execute = callTemplateMethod(null, cast, execute);
+                execute = callMethod(null, cast.getMethod(), execute);
             }
             builder.tree(execute);
             builder.end();
@@ -2137,13 +2222,13 @@
             builder.startElseBlock();
         }
 
-        LocalVariable genericValue = target.makeGeneric().nextName();
-        builder.tree(createAssignExecuteChild(execution, genericValue.getType(), genericValue, null, currentValues));
+        LocalVariable genericValue = target.makeGeneric(context).nextName();
+        builder.tree(createAssignExecuteChild(execution, genericValue.getTypeMirror(), genericValue, null, currentValues));
         if (executableTypes.size() == sourceTypes.size()) {
             builder.startThrow().startNew(getType(UnexpectedResultException.class)).tree(genericValue.createReference()).end().end();
         } else {
             builder.startStatement().tree(assignment);
-            builder.tree(TypeSystemCodeGenerator.implicitExpect(target.getType(), genericValue.createReference(), implicitClassFieldName));
+            builder.tree(TypeSystemCodeGenerator.implicitExpect(typeSystem, target.getTypeMirror(), genericValue.createReference(), implicitClassFieldName));
             builder.end();
         }
 
@@ -2153,7 +2238,7 @@
         return builder.build();
     }
 
-    private CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, TypeData forType, LocalContext currentValues, CodeTree execution) {
+    private CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, TypeMirror forType, LocalContext currentValues, CodeTree execution) {
         if (specialization.getExceptions().isEmpty()) {
             return execution;
         }
@@ -2248,8 +2333,8 @@
         for (TypeGuard typeGuard : typeGuards) {
             int signatureIndex = typeGuard.getSignatureIndex();
             LocalVariable value = currentValues.getValue(signatureIndex);
-            TypeData targetType = typeGuard.getType();
-            if (!value.getType().needsCastTo(targetType)) {
+            TypeMirror targetType = typeGuard.getType();
+            if (!ElementUtils.needsCastTo(value.getTypeMirror(), targetType)) {
                 continue;
             }
             NodeExecutionData execution = node.getChildExecutions().get(signatureIndex);
@@ -2264,7 +2349,7 @@
             if (shortCircuit != null) {
                 checkBuilder.string("(");
                 CodeTreeBuilder referenceBuilder = checkBuilder.create();
-                if (!shortCircuit.getType().isPrimitive()) {
+                if (!ElementUtils.isPrimitive(shortCircuit.getTypeMirror())) {
                     referenceBuilder.string("(boolean) ");
                 }
                 referenceBuilder.tree(shortCircuit.createReference());
@@ -2276,15 +2361,15 @@
             List<ImplicitCastData> sourceTypes = typeSystem.lookupByTargetType(targetType);
             CodeTree valueReference = value.createReference();
             if (sourceTypes.isEmpty()) {
-                checkBuilder.tree(TypeSystemCodeGenerator.check(targetType, value.createReference()));
-                castBuilder.tree(TypeSystemCodeGenerator.cast(targetType, valueReference));
+                checkBuilder.tree(TypeSystemCodeGenerator.check(typeSystem, targetType, value.createReference()));
+                castBuilder.tree(TypeSystemCodeGenerator.cast(typeSystem, targetType, valueReference));
             } else {
                 ImplicitCastOptimization opt = options.implicitCastOptimization();
                 if (specializationExecution.isFastPath() && !opt.isNone()) {
                     if (opt.isDuplicateTail()) {
                         String typeHintField = implicitClassFieldName(execution);
-                        checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(targetType, valueReference, typeHintField));
-                        castBuilder.tree(TypeSystemCodeGenerator.implicitCast(targetType, valueReference, typeHintField));
+                        checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(typeSystem, targetType, valueReference, typeHintField));
+                        castBuilder.tree(TypeSystemCodeGenerator.implicitCast(typeSystem, targetType, valueReference, typeHintField));
                     } else if (opt.isMergeCasts()) {
                         checkBuilder.tree(ImplicitCastNodeFactory.check(implicitNodeFieldName(execution), valueReference));
                         castBuilder.tree(ImplicitCastNodeFactory.cast(implicitNodeFieldName(execution), valueReference));
@@ -2292,14 +2377,14 @@
                         throw new AssertionError("implicit cast opt");
                     }
                 } else {
-                    checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(targetType, valueReference, null));
-                    castBuilder.tree(TypeSystemCodeGenerator.implicitCast(targetType, valueReference, null));
+                    checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(typeSystem, targetType, valueReference, null));
+                    castBuilder.tree(TypeSystemCodeGenerator.implicitCast(typeSystem, targetType, valueReference, null));
                 }
             }
 
             if (shortCircuit != null) {
                 checkBuilder.string(")");
-                castBuilder.string(" : ").defaultValue(targetType.getPrimitiveType());
+                castBuilder.string(" : ").defaultValue(targetType);
             }
 
             if (castGuards == null || castGuards.contains(typeGuard)) {
@@ -2329,7 +2414,7 @@
         String varName = name + specialization.getIndex();
         TypeMirror type = cache.getParameter().getType();
         builder.declaration(type, varName, initializer);
-        currentValues.set(name, new LocalVariable(null, type, varName, null, null));
+        currentValues.set(name, new LocalVariable(type, varName, null, null));
     }
 
     public static final class LocalContext {
@@ -2345,13 +2430,13 @@
             for (CacheExpression cache : specialization.getCaches()) {
                 Parameter cacheParameter = cache.getParameter();
                 String name = cacheParameter.getVariableElement().getSimpleName().toString();
-                set(cacheParameter.getLocalName(), new LocalVariable(cacheParameter.getTypeSystemType(), cacheParameter.getType(), name, CodeTreeBuilder.singleString("this." + name), null));
+                set(cacheParameter.getLocalName(), new LocalVariable(cacheParameter.getType(), name, CodeTreeBuilder.singleString("this." + name), null));
             }
 
             for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
                 String name = assumptionName(assumption);
                 TypeMirror type = assumption.getExpression().getResolvedType();
-                set(name, new LocalVariable(null, type, name, CodeTreeBuilder.singleString("this." + name), null));
+                set(name, new LocalVariable(type, name, CodeTreeBuilder.singleString("this." + name), null));
             }
         }
 
@@ -2382,12 +2467,12 @@
         }
 
         @SuppressWarnings("static-method")
-        public LocalVariable createValue(NodeExecutionData execution, TypeData type) {
-            return new LocalVariable(type, type.getPrimitiveType(), valueName(execution), null, null);
+        public LocalVariable createValue(NodeExecutionData execution, TypeMirror type) {
+            return new LocalVariable(type, valueName(execution), null, null);
         }
 
         public LocalVariable createShortCircuitValue(NodeExecutionData execution) {
-            return new LocalVariable(factory.typeSystem.getBooleanType(), factory.getType(boolean.class), shortCircuitName(execution), null, null);
+            return new LocalVariable(factory.getType(boolean.class), shortCircuitName(execution), null, null);
         }
 
         private static String valueName(NodeExecutionData execution) {
@@ -2424,7 +2509,12 @@
         }
 
         public LocalVariable getValue(int signatureIndex) {
-            return getValue(factory.node.getChildExecutions().get(signatureIndex));
+            List<NodeExecutionData> childExecutions = factory.node.getChildExecutions();
+            if (signatureIndex < childExecutions.size()) {
+                return getValue(childExecutions.get(signatureIndex));
+            } else {
+                return null;
+            }
         }
 
         public void removeValue(String id) {
@@ -2458,11 +2548,11 @@
         }
 
         private void loadValues(int evaluatedArguments, int varargsThreshold) {
-            values.put(FRAME_VALUE, new LocalVariable(null, factory.getType(Frame.class), FRAME_VALUE, null, null));
+            values.put(FRAME_VALUE, new LocalVariable(factory.getType(Frame.class), FRAME_VALUE, null, null));
 
             for (NodeFieldData field : factory.node.getFields()) {
                 String fieldName = fieldValueName(field);
-                values.put(fieldName, new LocalVariable(null, field.getType(), fieldName, factory.accessParent(field.getName()), null));
+                values.put(fieldName, new LocalVariable(field.getType(), fieldName, factory.accessParent(field.getName()), null));
             }
 
             boolean varargs = needsVarargs(false, varargsThreshold);
@@ -2473,7 +2563,7 @@
                 }
                 NodeExecutionData execution = childExecutions.get(i);
                 if (execution.isShortCircuit()) {
-                    LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric();
+                    LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric(factory.context);
                     if (varargs) {
                         shortCircuit = shortCircuit.accessWith(createReadVarargs(i));
                     }
@@ -2562,7 +2652,6 @@
 
     public static final class LocalVariable {
 
-        private final TypeData type;
         private final TypeMirror typeMirror;
         private final CodeTree accessorTree;
         private final String name;
@@ -2576,22 +2665,17 @@
             } else {
                 name = createName(execution);
             }
-            return new LocalVariable(parameter.getTypeSystemType(), parameter.getType(), name, null, null);
+            return new LocalVariable(parameter.getType(), name, null, null);
         }
 
-        private LocalVariable(TypeData type, TypeMirror typeMirror, String name, CodeTree accessorTree, LocalVariable previous) {
+        private LocalVariable(TypeMirror typeMirror, String name, CodeTree accessorTree, LocalVariable previous) {
             Objects.requireNonNull(typeMirror);
             this.typeMirror = typeMirror;
             this.accessorTree = accessorTree;
-            this.type = type;
             this.name = name;
             this.previous = previous;
         }
 
-        public TypeData getType() {
-            return type;
-        }
-
         public String getShortCircuitName() {
             return "has" + ElementUtils.firstLetterUpperCase(getName());
         }
@@ -2631,24 +2715,20 @@
             }
         }
 
-        public LocalVariable newType(TypeData newType) {
-            return new LocalVariable(newType, newType.getPrimitiveType(), name, accessorTree, this);
-        }
-
         public LocalVariable newType(TypeMirror newType) {
-            return new LocalVariable(type, newType, name, accessorTree, this);
+            return new LocalVariable(newType, name, accessorTree, this);
         }
 
         public LocalVariable accessWith(CodeTree tree) {
-            return new LocalVariable(type, typeMirror, name, tree, this);
+            return new LocalVariable(typeMirror, name, tree, this);
         }
 
         public LocalVariable nextName() {
-            return new LocalVariable(type, typeMirror, createNextName(name), accessorTree, this);
+            return new LocalVariable(typeMirror, createNextName(name), accessorTree, this);
         }
 
         public LocalVariable makeOriginal() {
-            return new LocalVariable(type, typeMirror, name, accessorTree, null);
+            return new LocalVariable(typeMirror, name, accessorTree, null);
         }
 
         public LocalVariable original() {
@@ -2659,8 +2739,8 @@
             return variable;
         }
 
-        public LocalVariable makeGeneric() {
-            return newType(type.getTypeSystem().getGenericTypeData());
+        public LocalVariable makeGeneric(ProcessorContext context) {
+            return newType(context.getType(Object.class));
         }
 
         @Override