/** * Copyright (c) 2012-2016 André Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.compiler; import static com.github.anba.es6draft.compiler.ClassPropertyGenerator.ClassPropertyEvaluation; import static com.github.anba.es6draft.compiler.GeneratorComprehensionGenerator.EvaluateGeneratorComprehension; import static com.github.anba.es6draft.semantics.StaticSemantics.IsStrict; import static com.github.anba.es6draft.semantics.StaticSemantics.TemplateStrings; import java.lang.reflect.Modifier; import java.util.AbstractMap.SimpleImmutableEntry; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; import com.github.anba.es6draft.ast.*; import com.github.anba.es6draft.ast.synthetic.ExpressionMethod; import com.github.anba.es6draft.ast.synthetic.MethodDefinitionsMethod; import com.github.anba.es6draft.ast.synthetic.PropertyDefinitionsMethod; import com.github.anba.es6draft.ast.synthetic.SpreadElementMethod; import com.github.anba.es6draft.ast.synthetic.StatementListMethod; import com.github.anba.es6draft.ast.synthetic.SyntheticNode; import com.github.anba.es6draft.compiler.CodeVisitor.GeneratorState; import com.github.anba.es6draft.compiler.CodeVisitor.LabelState; import com.github.anba.es6draft.compiler.DefaultCodeGenerator.ValType; import com.github.anba.es6draft.compiler.StatementGenerator.Completion; import com.github.anba.es6draft.compiler.assembler.Code; import com.github.anba.es6draft.compiler.assembler.Code.MethodCode; import com.github.anba.es6draft.compiler.assembler.MethodName; import com.github.anba.es6draft.compiler.assembler.MethodTypeDescriptor; import com.github.anba.es6draft.compiler.assembler.MutableValue; import com.github.anba.es6draft.compiler.assembler.Type; import com.github.anba.es6draft.compiler.assembler.Variable; import com.github.anba.es6draft.compiler.completion.CompletionValueVisitor; import com.github.anba.es6draft.parser.Parser; import com.github.anba.es6draft.runtime.DeclarativeEnvironmentRecord; import com.github.anba.es6draft.runtime.ExecutionContext; import com.github.anba.es6draft.runtime.LexicalEnvironment; import com.github.anba.es6draft.runtime.internal.CompatibilityOption; import com.github.anba.es6draft.runtime.internal.JVMNames; import com.github.anba.es6draft.runtime.internal.ResumptionPoint; import com.github.anba.es6draft.runtime.internal.SourceCompressor; import com.github.anba.es6draft.runtime.internal.Strings; import com.github.anba.es6draft.runtime.modules.SourceTextModuleRecord; import com.github.anba.es6draft.runtime.types.builtins.ArrayObject; import com.github.anba.es6draft.runtime.types.builtins.OrdinaryConstructorFunction; import com.github.anba.es6draft.runtime.types.builtins.OrdinaryObject; /** * */ final class CodeGenerator { private static final class Methods { // class: CompiledFunction static final MethodName CompiledFunction_Constructor = MethodName.findConstructor(Types.CompiledFunction, Type.methodType(Type.VOID_TYPE, Types.RuntimeInfo$Function)); // class: CompiledModule static final MethodName CompiledModule_Constructor = MethodName.findConstructor(Types.CompiledModule, Type.methodType(Type.VOID_TYPE, Types.RuntimeInfo$ModuleBody)); // class: CompiledScript static final MethodName CompiledScript_Constructor = MethodName.findConstructor(Types.CompiledScript, Type.methodType(Type.VOID_TYPE, Types.RuntimeInfo$ScriptBody)); // class: ScriptRuntime static final MethodName ScriptRuntime_GetTemplateObject = MethodName.findStatic(Types.ScriptRuntime, "GetTemplateObject", Type.methodType(Types.ArrayObject, Type.INT_TYPE, Types.MethodHandle, Types.ExecutionContext)); } private static final class MethodDescriptors { static final MethodTypeDescriptor FunctionConstructor = Type.methodType(Type.VOID_TYPE); static final MethodTypeDescriptor ModuleConstructor = Type.methodType(Type.VOID_TYPE); static final MethodTypeDescriptor ScriptConstructor = Type.methodType(Type.VOID_TYPE); static final MethodTypeDescriptor TemplateLiteral = Type.methodType(Types.String_); static final MethodTypeDescriptor DoExpressionMethod = Type.methodType(Type.INT_TYPE, Types.ExecutionContext, Types.Object_); static final MethodTypeDescriptor DoExpressionMethodWithResume = Type.methodType(Type.INT_TYPE, Types.ExecutionContext, Types.ResumptionPoint_, Types.Object_); static final MethodTypeDescriptor StatementListMethod = Type.methodType(Type.INT_TYPE, Types.ExecutionContext, Types.Object_); static final MethodTypeDescriptor StatementListMethodWithResume = Type.methodType(Type.INT_TYPE, Types.ExecutionContext, Types.ResumptionPoint_, Types.Object_); static final MethodTypeDescriptor SpreadElementMethod = Type.methodType(Type.INT_TYPE, Types.ExecutionContext, Types.ArrayObject, Type.INT_TYPE); static final MethodTypeDescriptor SpreadElementMethodWithResume = Type.methodType(Type.INT_TYPE, Types.ExecutionContext, Types.ResumptionPoint_, Types.Object_, Types.ArrayObject, Type.INT_TYPE); static final MethodTypeDescriptor PropertyDefinitionsMethod = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext, Types.OrdinaryObject, Types.ArrayList); static final MethodTypeDescriptor PropertyDefinitionsMethodWithResume = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext, Types.ResumptionPoint_, Types.Object_, Types.OrdinaryObject, Types.ArrayList); static final MethodTypeDescriptor MethodDefinitionsMethod = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext, Types.OrdinaryConstructorFunction, Types.OrdinaryObject, Types.ArrayList); static final MethodTypeDescriptor MethodDefinitionsMethodWithResume = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext, Types.ResumptionPoint_, Types.Object_, Types.OrdinaryConstructorFunction, Types.OrdinaryObject, Types.ArrayList); static final MethodTypeDescriptor ExpressionMethod = Type.methodType(Types.Object, Types.ExecutionContext); static final MethodTypeDescriptor ExpressionMethodWithResume = Type.methodType(Types.Object, Types.ExecutionContext, Types.ResumptionPoint_, Types.Object_); static final MethodTypeDescriptor BlockDeclarationInit = Type.methodType(Type.VOID_TYPE, Types.LexicalEnvironment, Types.ExecutionContext); static final MethodTypeDescriptor AsyncFunction_Call = Type.methodType(Types.PromiseObject, Types.OrdinaryAsyncFunction, Types.ExecutionContext, Types.Object, Types.Object_); static final MethodTypeDescriptor AsyncFunction_Init = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext, Types.OrdinaryAsyncFunction, Types.Object_); static final MethodTypeDescriptor AsyncFunction_Code = Type.methodType(Types.Object, Types.ExecutionContext, Types.ResumptionPoint); static final MethodTypeDescriptor AsyncGenerator_Call = Type.methodType(Types.AsyncGeneratorObject, Types.OrdinaryAsyncGenerator, Types.ExecutionContext, Types.Object, Types.Object_); static final MethodTypeDescriptor AsyncGenerator_Init = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext, Types.OrdinaryAsyncGenerator, Types.Object_); static final MethodTypeDescriptor AsyncGenerator_Code = Type.methodType(Types.Object, Types.ExecutionContext, Types.ResumptionPoint); static final MethodTypeDescriptor Function_Call = Type.methodType(Types.Object, Types.OrdinaryFunction, Types.ExecutionContext, Types.Object, Types.Object_); static final MethodTypeDescriptor Function_Init = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext, Types.OrdinaryFunction, Types.Object_); static final MethodTypeDescriptor Function_Code = Type.methodType(Types.Object, Types.ExecutionContext); static final MethodTypeDescriptor ConstructorFunction_Call = Type.methodType(Types.Object, Types.OrdinaryConstructorFunction, Types.ExecutionContext, Types.Object, Types.Object_); static final MethodTypeDescriptor ConstructorFunction_Construct = Type.methodType(Types.ScriptObject, Types.OrdinaryConstructorFunction, Types.ExecutionContext, Types.Constructor, Types.Object_); static final MethodTypeDescriptor ConstructorFunction_ConstructTailCall = Type.methodType(Types.Object, Types.OrdinaryConstructorFunction, Types.ExecutionContext, Types.Constructor, Types.Object_); static final MethodTypeDescriptor ConstructorFunction_Init = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext, Types.OrdinaryConstructorFunction, Types.Object_); static final MethodTypeDescriptor ConstructorFunction_Code = Function_Code; static final MethodTypeDescriptor LegacyFunction_Call = Type.methodType(Types.Object, Types.LegacyConstructorFunction, Types.ExecutionContext, Types.Object, Types.Object_); static final MethodTypeDescriptor LegacyFunction_Construct = Type.methodType(Types.ScriptObject, Types.LegacyConstructorFunction, Types.ExecutionContext, Types.Constructor, Types.Object_); static final MethodTypeDescriptor LegacyFunction_Init = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext, Types.LegacyConstructorFunction, Types.Object_); static final MethodTypeDescriptor LegacyFunction_Code = Function_Code; static final MethodTypeDescriptor ConstructorGenerator_Call = Type.methodType(Types.GeneratorObject, Types.OrdinaryConstructorGenerator, Types.ExecutionContext, Types.Object, Types.Object_); static final MethodTypeDescriptor ConstructorGenerator_Construct = Type.methodType(Types.GeneratorObject, Types.OrdinaryConstructorGenerator, Types.ExecutionContext, Types.Constructor, Types.Object_); static final MethodTypeDescriptor ConstructorGenerator_Init = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext, Types.OrdinaryConstructorGenerator, Types.Object_); static final MethodTypeDescriptor ConstructorGenerator_Code = Type.methodType(Types.Object, Types.ExecutionContext, Types.ResumptionPoint); static final MethodTypeDescriptor Generator_Call = Type.methodType(Types.GeneratorObject, Types.OrdinaryGenerator, Types.ExecutionContext, Types.Object, Types.Object_); static final MethodTypeDescriptor Generator_Init = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext, Types.OrdinaryGenerator, Types.Object_); static final MethodTypeDescriptor Generator_Code = Type.methodType(Types.Object, Types.ExecutionContext, Types.ResumptionPoint); static final MethodTypeDescriptor FunctionNode_RTI = Type.methodType(Types.RuntimeInfo$Function); static final MethodTypeDescriptor FunctionNode_DebugInfo = Type.methodType(Types.DebugInfo); static final MethodTypeDescriptor Script_Eval = Type.methodType(Types.Object, Types.ExecutionContext, Types.Script); static final MethodTypeDescriptor Script_Code = Type.methodType(Types.Object, Types.ExecutionContext); static final MethodTypeDescriptor Script_Init = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext); static final MethodTypeDescriptor Script_RTI = Type.methodType(Types.RuntimeInfo$ScriptBody); static final MethodTypeDescriptor Script_DebugInfo = Type.methodType(Types.DebugInfo); static final MethodTypeDescriptor Module_Code = Type.methodType(Types.Object, Types.ExecutionContext); static final MethodTypeDescriptor Module_Init = Type.methodType(Type.VOID_TYPE, Types.ExecutionContext, Types.SourceTextModuleRecord, Types.LexicalEnvironment); static final MethodTypeDescriptor Module_RTI = Type.methodType(Types.RuntimeInfo$ScriptBody); static final MethodTypeDescriptor Module_DebugInfo = Type.methodType(Types.DebugInfo); } private static final boolean INCLUDE_SOURCE = true; private static final Future<String> NO_SOURCE = CompletableFuture.completedFuture(null); private static final int MAX_FNAME_LENGTH = 0x400; private final Code code; private final Program program; private final ExecutorService executor; private final EnumSet<CompatibilityOption> options; private final EnumSet<Parser.Option> parserOptions; private final EnumSet<Compiler.Option> compilerOptions; private final StatementGenerator stmtgen = new StatementGenerator(this); private final ExpressionGenerator exprgen = new ExpressionGenerator(this); private final PropertyGenerator propgen = new PropertyGenerator(this); private final BlockDeclarationInstantiationGenerator blockgen = new BlockDeclarationInstantiationGenerator(this); CodeGenerator(Code code, Program program, ExecutorService executor, EnumSet<Compiler.Option> compilerOptions) { this.code = code; this.program = program; this.executor = executor; this.options = program.getOptions(); this.parserOptions = program.getParserOptions(); this.compilerOptions = compilerOptions; } Program getProgram() { return program; } boolean isEnabled(CompatibilityOption option) { return options.contains(option); } boolean isEnabled(Parser.Option option) { return parserOptions.contains(option); } boolean isEnabled(Compiler.Option option) { return compilerOptions.contains(option); } // template strings private final HashMap<TemplateLiteral, Integer> templateKeys = new HashMap<>(); private int templateKey(TemplateLiteral template) { Integer key = templateKeys.get(template); if (key == null) { templateKeys.put(template, key = templateKeys.size()); } return key; } private final HashMap<DoExpression, LabelState> doExpressionCompletions = new HashMap<>(); private final HashMap<StatementListMethod, LabelState> statementCompletions = new HashMap<>(); /* ----------------------------------------------------------------------------------------- */ enum ScriptName { Eval, Code, Init, RTI, DebugInfo } enum ModuleName { Code, Init, RTI, DebugInfo } enum FunctionName { Call, Construct, ConstructTailCall, Code, Init, RTI, DebugInfo } /** * Map of nodes to base method names */ private final HashMap<Node, String> methodNames = new HashMap<>(32); private final AtomicInteger methodCounter = new AtomicInteger(0); private boolean isCompiled(Node node) { return methodNames.containsKey(node); } private String methodName(Script node, ScriptName name) { switch (name) { case Eval: return "!script"; case Code: return "~script_code"; case Init: return "~script_init"; case RTI: return "!script_rti"; case DebugInfo: return "!script_dbg"; default: throw new AssertionError(); } } private String methodName(Module node, ModuleName name) { switch (name) { case Code: return "~module"; case Init: return "~module_init"; case RTI: return "!module_rti"; case DebugInfo: return "!module_dbg"; default: throw new AssertionError(); } } private String methodName(DoExpression node) { String name = methodNames.get(node); if (name == null) { throw new IllegalStateException("no method-name present for: " + node); } return name; } private String methodName(StatementListMethod node) { String name = methodNames.get(node); if (name == null) { throw new IllegalStateException("no method-name present for: " + node); } return name; } private String baseName(TopLevelNode<?> topLevel) { if (topLevel instanceof FunctionNode) { return methodName((FunctionNode) topLevel, FunctionName.Code); } if (topLevel instanceof Module) { return methodName((Module) topLevel, ModuleName.Code); } assert topLevel instanceof Script; return methodName((Script) topLevel, ScriptName.Code); } private String methodName(TopLevelNode<?> topLevel, DoExpression node) { return addMethodName(node, baseName(topLevel), '\''); } private String methodName(TopLevelNode<?> topLevel, StatementListMethod node) { return addMethodName(node, baseName(topLevel), '\''); } private String methodName(TemplateLiteral node) { return methodName(node, "!template"); } private String methodName(SpreadElementMethod node) { return methodName(node, "!spread"); } private String methodName(PropertyDefinitionsMethod node) { return methodName(node, "!propdef"); } private String methodName(MethodDefinitionsMethod node) { return methodName(node, "!mdef"); } private String methodName(ExpressionMethod node) { return methodName(node, "!expr"); } private String methodName(BlockStatement node) { return methodName(node, "!block"); } private String methodName(SwitchStatement node) { return methodName(node, "!block"); } private String methodName(Node node, String name) { String n = methodNames.get(node); if (n == null) { n = addMethodName(node, name, '~'); } return n; } private String methodName(FunctionNode node, FunctionName name) { String fname = methodNames.get(node); if (fname == null) { fname = addMethodName(node, getMethodName(node), '~'); } switch (name) { case Call: return insertMarker("!", fname, "_call"); case Code: return insertMarker("", fname, ""); case Construct: case ConstructTailCall: return insertMarker("!", fname, "_construct"); case Init: return insertMarker("", fname, "_init"); case RTI: return insertMarker("!", fname, "_rti"); case DebugInfo: return insertMarker("!", fname, "_dbg"); default: throw new AssertionError(); } } private String getMethodName(FunctionNode node) { String name = node.getMethodName(); if (name.isEmpty()) { name = "anonymous"; } else if (name.length() > MAX_FNAME_LENGTH) { name = name.substring(0, MAX_FNAME_LENGTH); } return name; } private String insertMarker(String prefix, String fname, String suffix) { return JVMNames.addPrefixSuffix(fname, prefix, suffix); } private String addMethodName(Node node, String name, char sep) { assert !methodNames.containsKey(node); String n = JVMNames.toBytecodeName(name + sep + methodCounter.incrementAndGet()); methodNames.put(node, n); return n; } private String addMethodNameUnchecked(String name, char sep) { return JVMNames.toBytecodeName(name + sep + methodCounter.incrementAndGet()); } /* ----------------------------------------------------------------------------------------- */ private MethodTypeDescriptor methodDescriptor(TemplateLiteral node) { return MethodDescriptors.TemplateLiteral; } private MethodTypeDescriptor methodDescriptor(DoExpression node) { if (node.hasYieldOrAwait()) { return MethodDescriptors.DoExpressionMethodWithResume; } return MethodDescriptors.DoExpressionMethod; } private MethodTypeDescriptor methodDescriptor(StatementListMethod node) { if (node.hasResumePoint()) { return MethodDescriptors.StatementListMethodWithResume; } return MethodDescriptors.StatementListMethod; } private MethodTypeDescriptor methodDescriptor(SpreadElementMethod node) { if (node.hasResumePoint()) { return MethodDescriptors.SpreadElementMethodWithResume; } return MethodDescriptors.SpreadElementMethod; } private MethodTypeDescriptor methodDescriptor(PropertyDefinitionsMethod node) { if (node.hasResumePoint()) { return MethodDescriptors.PropertyDefinitionsMethodWithResume; } return MethodDescriptors.PropertyDefinitionsMethod; } private MethodTypeDescriptor methodDescriptor(MethodDefinitionsMethod node) { if (node.hasResumePoint()) { return MethodDescriptors.MethodDefinitionsMethodWithResume; } return MethodDescriptors.MethodDefinitionsMethod; } private MethodTypeDescriptor methodDescriptor(ExpressionMethod node) { if (node.hasResumePoint()) { return MethodDescriptors.ExpressionMethodWithResume; } return MethodDescriptors.ExpressionMethod; } private MethodTypeDescriptor methodDescriptor(BlockStatement node) { return MethodDescriptors.BlockDeclarationInit; } private MethodTypeDescriptor methodDescriptor(SwitchStatement node) { return MethodDescriptors.BlockDeclarationInit; } private MethodTypeDescriptor methodDescriptor(FunctionNode node, FunctionName name) { switch (name) { case Call: if (node.isAsync() && node.isGenerator()) { return MethodDescriptors.AsyncGenerator_Call; } if (node.isAsync()) { return MethodDescriptors.AsyncFunction_Call; } if (node.isGenerator()) { if (node.isConstructor()) { return MethodDescriptors.ConstructorGenerator_Call; } return MethodDescriptors.Generator_Call; } if (isLegacy(node)) { return MethodDescriptors.LegacyFunction_Call; } if (node.isConstructor()) { return MethodDescriptors.ConstructorFunction_Call; } assert !isCallConstructor(node); return MethodDescriptors.Function_Call; case ConstructTailCall: assert node.isConstructor() && !isLegacy(node) && !node.isGenerator() && !node.isAsync(); return MethodDescriptors.ConstructorFunction_ConstructTailCall; case Construct: assert node.isConstructor(); if (node.isGenerator()) { return MethodDescriptors.ConstructorGenerator_Construct; } if (isLegacy(node)) { return MethodDescriptors.LegacyFunction_Construct; } return MethodDescriptors.ConstructorFunction_Construct; case Code: if (node.isAsync() && node.isGenerator()) { return MethodDescriptors.AsyncGenerator_Code; } if (node.isAsync()) { return MethodDescriptors.AsyncFunction_Code; } if (node.isGenerator()) { if (node.isConstructor()) { return MethodDescriptors.ConstructorGenerator_Code; } return MethodDescriptors.Generator_Code; } if (isLegacy(node)) { return MethodDescriptors.LegacyFunction_Code; } if (node.isConstructor() || isCallConstructor(node)) { return MethodDescriptors.ConstructorFunction_Code; } return MethodDescriptors.Function_Code; case Init: if (node.isAsync() && node.isGenerator()) { return MethodDescriptors.AsyncGenerator_Init; } if (node.isAsync()) { return MethodDescriptors.AsyncFunction_Init; } if (node.isGenerator()) { if (node.isConstructor()) { return MethodDescriptors.ConstructorGenerator_Init; } return MethodDescriptors.Generator_Init; } if (isLegacy(node)) { return MethodDescriptors.LegacyFunction_Init; } if (node.isConstructor() || isCallConstructor(node)) { return MethodDescriptors.ConstructorFunction_Init; } return MethodDescriptors.Function_Init; case RTI: return MethodDescriptors.FunctionNode_RTI; case DebugInfo: return MethodDescriptors.FunctionNode_DebugInfo; default: throw new AssertionError(); } } private boolean isLegacy(FunctionNode node) { if (IsStrict(node)) { return false; } if (!(node instanceof FunctionDeclaration || node instanceof FunctionExpression)) { return false; } return isEnabled(CompatibilityOption.FunctionArguments) || isEnabled(CompatibilityOption.FunctionCaller); } private boolean isCallConstructor(FunctionNode node) { if (node instanceof MethodDefinition) { return ((MethodDefinition) node).isCallConstructor(); } return false; } private MethodTypeDescriptor methodDescriptor(Script node, ScriptName name) { switch (name) { case Eval: return MethodDescriptors.Script_Eval; case Code: return MethodDescriptors.Script_Code; case Init: return MethodDescriptors.Script_Init; case RTI: return MethodDescriptors.Script_RTI; case DebugInfo: return MethodDescriptors.Script_DebugInfo; default: throw new AssertionError(); } } private MethodTypeDescriptor methodDescriptor(Module node, ModuleName name) { switch (name) { case Code: return MethodDescriptors.Module_Code; case Init: return MethodDescriptors.Module_Init; case RTI: return MethodDescriptors.Module_RTI; case DebugInfo: return MethodDescriptors.Module_DebugInfo; default: throw new AssertionError(); } } /* ----------------------------------------------------------------------------------------- */ /** * Map of concrete method names to class names */ private final HashMap<String, Type> methodClasses = new HashMap<>(32 * 4); private MethodCode publicStaticMethod(String methodName, MethodTypeDescriptor methodDescriptor) { final int access = Modifier.PUBLIC | Modifier.STATIC; MethodCode method = code.newMethod(access, methodName, methodDescriptor); // System.out.printf("add <%s, %s>%n", methodName, method.classCode.className); assert !methodClasses.containsKey(methodName) : String.format("method '%s' already compiled", methodName); methodClasses.put(methodName, method.classCode.classType); return method; } private MethodCode newMethod(TemplateLiteral node) { return publicStaticMethod(methodName(node), methodDescriptor(node)); } private MethodCode newMethod(TopLevelNode<?> topLevel, DoExpression node) { return publicStaticMethod(methodName(topLevel, node), methodDescriptor(node)); } private MethodCode newMethod(TopLevelNode<?> topLevel, StatementListMethod node) { return publicStaticMethod(methodName(topLevel, node), methodDescriptor(node)); } private MethodCode newMethod(SpreadElementMethod node) { return publicStaticMethod(methodName(node), methodDescriptor(node)); } private MethodCode newMethod(PropertyDefinitionsMethod node) { return publicStaticMethod(methodName(node), methodDescriptor(node)); } private MethodCode newMethod(MethodDefinitionsMethod node) { return publicStaticMethod(methodName(node), methodDescriptor(node)); } private MethodCode newMethod(ExpressionMethod node) { return publicStaticMethod(methodName(node), methodDescriptor(node)); } private MethodCode newMethod(BlockStatement node) { return publicStaticMethod(methodName(node), methodDescriptor(node)); } private MethodCode newMethod2(BlockStatement node) { return publicStaticMethod(addMethodNameUnchecked(methodName(node), '\''), methodDescriptor(node)); } private MethodCode newMethod(SwitchStatement node) { return publicStaticMethod(methodName(node), methodDescriptor(node)); } private MethodCode newMethod2(SwitchStatement node) { return publicStaticMethod(addMethodNameUnchecked(methodName(node), '\''), methodDescriptor(node)); } MethodCode newMethod(FunctionNode node, FunctionName name) { return publicStaticMethod(methodName(node, name), methodDescriptor(node, name)); } MethodCode newMethod(Script node, ScriptName name) { return publicStaticMethod(methodName(node, name), methodDescriptor(node, name)); } MethodCode newMethod(Module node, ModuleName name) { return publicStaticMethod(methodName(node, name), methodDescriptor(node, name)); } /* ----------------------------------------------------------------------------------------- */ private Type owner(String methodName) { Type owner = methodClasses.get(methodName); assert owner != null : String.format("method '%s' not yet compiled", methodName); return owner; } private MethodName methodDesc(TemplateLiteral node) { String methodName = methodName(node); return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node)); } private MethodName methodDesc(DoExpression node) { String methodName = methodName(node); return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node)); } private MethodName methodDesc(StatementListMethod node) { String methodName = methodName(node); return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node)); } private MethodName methodDesc(SpreadElementMethod node) { String methodName = methodName(node); return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node)); } private MethodName methodDesc(PropertyDefinitionsMethod node) { String methodName = methodName(node); return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node)); } private MethodName methodDesc(MethodDefinitionsMethod node) { String methodName = methodName(node); return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node)); } private MethodName methodDesc(ExpressionMethod node) { String methodName = methodName(node); return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node)); } private MethodName methodDesc(BlockStatement node) { String methodName = methodName(node); return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node)); } private MethodName methodDesc(BlockStatement node, String methodName) { return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node)); } private MethodName methodDesc(SwitchStatement node) { String methodName = methodName(node); return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node)); } private MethodName methodDesc(SwitchStatement node, String methodName) { return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node)); } MethodName methodDesc(FunctionNode node, FunctionName name) { String methodName = methodName(node, name); return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node, name)); } MethodName methodDesc(Script node, ScriptName name) { String methodName = methodName(node, name); return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node, name)); } MethodName methodDesc(Module node, ModuleName name) { String methodName = methodName(node, name); return MethodName.findStatic(owner(methodName), methodName, methodDescriptor(node, name)); } /* ----------------------------------------------------------------------------------------- */ /** * [12.2.8.2.2] Runtime Semantics: GetTemplateObject * * @param node * the template literal * @param mv * the code visitor */ void GetTemplateObject(TemplateLiteral node, CodeVisitor mv) { assert isCompiled(node); // GetTemplateObject mv.iconst(templateKey(node)); mv.handle(methodDesc(node)); mv.loadExecutionContext(); mv.invoke(Methods.ScriptRuntime_GetTemplateObject); } void compile(TemplateLiteral node) { if (!isCompiled(node)) { MethodCode method = newMethod(node); InstructionVisitor body = new InstructionVisitor(method); body.lineInfo(node); body.begin(); List<TemplateCharacters> strings = TemplateStrings(node); body.anewarray(strings.size() * 2, Types.String); for (int i = 0, size = strings.size(); i < size; ++i) { TemplateCharacters e = strings.get(i); int index = i << 1; body.astore(index, e.getValue()); body.astore(index + 1, e.getRawValue()); } body._return(); body.end(); } } void compile(Script node) { // initialization methods if (!(node.isEvalScript() || node.isScripting())) { new GlobalDeclarationInstantiationGenerator(this).generate(node); } else { new EvalDeclarationInstantiationGenerator(this).generate(node); } // runtime method scriptBody(node); // eval method new ScriptCodeGenerator(this).generate(node); // runtime-info method new RuntimeInfoGenerator(this).runtimeInfo(node); // add default constructor defaultScriptConstructor(node); } private void scriptBody(Script node) { MethodCode method = newMethod(node, ScriptName.Code); ScriptCodeVisitor body = new ScriptCodeVisitor(method, node); body.lineInfo(node); body.begin(); body.loadUndefined(); body.storeCompletionValue(ValType.Undefined); body.enterScope(node); Completion result = statements(node.getStatements(), body); body.exitScope(); if (!result.isAbrupt()) { body.loadCompletionValue(); body._return(); } body.end(); } private void defaultScriptConstructor(Script node) { InstructionVisitor mv = new InstructionVisitor( code.newConstructor(Modifier.PUBLIC, MethodDescriptors.ScriptConstructor)); mv.begin(); mv.loadThis(); mv.invoke(methodDesc(node, ScriptName.RTI)); mv.invoke(Methods.CompiledScript_Constructor); mv._return(); mv.end(); } void compile(Module node, SourceTextModuleRecord moduleRecord) { // initialization methods new ModuleDeclarationInstantiationGenerator(this).generate(node, moduleRecord); // runtime method moduleBody(node); // runtime-info method new RuntimeInfoGenerator(this).runtimeInfo(node); // add default constructor defaultModuleConstructor(node); } private void moduleBody(Module node) { MethodCode method = newMethod(node, ModuleName.Code); ModuleCodeVisitor body = new ModuleCodeVisitor(method, node); body.lineInfo(node); body.begin(); body.enterScope(node); Completion result = statements(node.getStatements(), body); body.exitScope(); if (!result.isAbrupt()) { // Completion values are currently ignored for module code. body.loadUndefined(); body._return(); } body.end(); } private void defaultModuleConstructor(Module node) { InstructionVisitor mv = new InstructionVisitor( code.newConstructor(Modifier.PUBLIC, MethodDescriptors.ModuleConstructor)); mv.begin(); mv.loadThis(); mv.invoke(methodDesc(node, ModuleName.RTI)); mv.invoke(Methods.CompiledModule_Constructor); mv._return(); mv.end(); } void compileFunction(FunctionNode function) { MethodName method = compile(function); // add default constructor defaultFunctionConstructor(function, method); } private void defaultFunctionConstructor(FunctionNode function, MethodName method) { InstructionVisitor mv = new InstructionVisitor( code.newConstructor(Modifier.PUBLIC, MethodDescriptors.FunctionConstructor)); mv.begin(); mv.loadThis(); mv.invoke(method); mv.invoke(Methods.CompiledFunction_Constructor); mv._return(); mv.end(); } MethodName compile(ClassDefinition node) { MethodDefinition constructor = node.getConstructor(); MethodDefinition callConstructor = node.getCallConstructor(); if (!isCompiled(constructor)) { assert callConstructor == null || !isCompiled(callConstructor); Future<String> source = getSource(node); // initialization method new FunctionDeclarationInstantiationGenerator(this).generate(constructor); if (callConstructor != null) { new FunctionDeclarationInstantiationGenerator(this).generate(callConstructor); } // runtime method boolean tailConstruct = functionBody(constructor); boolean tailCall = callConstructor != null ? functionBody(callConstructor) : false; // call method new FunctionCodeGenerator(this).generate(node, tailCall, tailConstruct); // runtime-info method new RuntimeInfoGenerator(this).runtimeInfo(node, tailCall, tailConstruct, result(source)); } return methodDesc(constructor, FunctionName.RTI); } MethodName compile(GeneratorComprehension node) { return compile((FunctionNode) node); } MethodName compile(FunctionDefinition node) { return compile((FunctionNode) node); } MethodName compile(GeneratorDefinition node) { return compile((FunctionNode) node); } MethodName compile(ArrowFunction node) { return compile((FunctionNode) node); } MethodName compile(MethodDefinition node) { assert !(node.isClassConstructor() || node.isCallConstructor()); return compile((FunctionNode) node); } MethodName compile(AsyncArrowFunction node) { return compile((FunctionNode) node); } MethodName compile(AsyncFunctionDefinition node) { return compile((FunctionNode) node); } MethodName compile(AsyncGeneratorDefinition node) { return compile((FunctionNode) node); } private MethodName compile(FunctionNode node) { if (!isCompiled(node)) { Future<String> source = getSource(node); // initialization method new FunctionDeclarationInstantiationGenerator(this).generate(node); // runtime method boolean tailCall; if (node instanceof ArrowFunction && ((ArrowFunction) node).getExpression() != null) { tailCall = conciseFunctionBody((ArrowFunction) node); } else if (node instanceof AsyncArrowFunction && ((AsyncArrowFunction) node).getExpression() != null) { tailCall = conciseAsyncFunctionBody((AsyncArrowFunction) node); } else if (node instanceof GeneratorComprehension) { tailCall = generatorComprehensionBody((GeneratorComprehension) node); } else if (node.isAsync() || node.isGenerator()) { tailCall = generatorBody(node); } else { tailCall = functionBody(node); } // call method new FunctionCodeGenerator(this).generate(node, tailCall); // runtime-info method new RuntimeInfoGenerator(this).runtimeInfo(node, tailCall, result(source)); } return methodDesc(node, FunctionName.RTI); } private Future<String> getSource(ClassDefinition node) { if (INCLUDE_SOURCE && !isEnabled(Parser.Option.NativeFunction)) { StringBuilder sb = new StringBuilder(); appendMethodSource(sb, "constructor", node.getConstructor()); if (node.getCallConstructor() != null) { sb.append('\n'); appendMethodSource(sb, "call constructor", node.getCallConstructor()); } return executor.submit(new CompressSourceTask(sb.toString())); } return NO_SOURCE; } private static void appendMethodSource(StringBuilder sb, String methodName, MethodDefinition method) { // Ignores implicit-strict compatibility option. sb.append(methodName).append(method.getHeaderSource()).append('{').append(method.getBodySource()).append('}'); } private Future<String> getSource(FunctionNode node) { if (INCLUDE_SOURCE && !isEnabled(Parser.Option.NativeFunction)) { String source = Strings.concat(node.getHeaderSource(), node.getBodySource()); return executor.submit(new CompressSourceTask(source)); } return NO_SOURCE; } private static <T> T result(Future<T> future) { try { return future.get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } private static final class CompressSourceTask implements Callable<String> { private final String source; CompressSourceTask(String source) { this.source = source; } @Override public String call() throws Exception { return SourceCompressor.compress(source); } } private boolean conciseFunctionBody(ArrowFunction node) { MethodCode method = newMethod(node, FunctionName.Code); FunctionCodeVisitor body = new FunctionCodeVisitor(method, node); body.lineInfo(node); body.begin(); // call expression in concise function body is always in tail-call position Expression expression = node.getExpression(); body.enterTailCallPosition(expression); body.enterFunction(node); expressionBoxed(expression, body); body.exitFunction(); body._return(); body.end(); return body.hasTailCalls(); } private boolean functionBody(FunctionNode node) { MethodCode method = newMethod(node, FunctionName.Code); FunctionCodeVisitor body = new FunctionCodeVisitor(method, node); body.lineInfo(node); body.begin(); body.enterFunction(node); Completion result = statements(node.getStatements(), body); body.exitFunction(); if (!result.isAbrupt()) { // fall-thru, return undefined from function body.loadUndefined(); body._return(); } body.end(); return body.hasTailCalls(); } private boolean conciseAsyncFunctionBody(AsyncArrowFunction node) { MethodCode method = newMethod(node, FunctionName.Code); GeneratorCodeVisitor body = new GeneratorCodeVisitor(method, node); body.lineInfo(node); body.begin(); GeneratorState generatorState = body.generatorPrologue(); body.enterFunction(node); expressionBoxed(node.getExpression(), body); body.exitFunction(); body._return(); body.generatorEpilogue(generatorState); body.end(); return body.hasTailCalls(); } private boolean generatorBody(FunctionNode node) { MethodCode method = newMethod(node, FunctionName.Code); GeneratorCodeVisitor body = new GeneratorCodeVisitor(method, node); body.lineInfo(node); body.begin(); GeneratorState generatorState = body.generatorPrologue(); body.enterFunction(node); Completion result = statements(node.getStatements(), body); body.exitFunction(); if (!result.isAbrupt()) { // fall-thru, return undefined from function body.loadUndefined(); body._return(); } body.generatorEpilogue(generatorState); body.end(); return body.hasTailCalls(); } private boolean generatorComprehensionBody(GeneratorComprehension node) { MethodCode method = newMethod(node, FunctionName.Code); GeneratorCodeVisitor body = new GeneratorCodeVisitor(method, node); body.lineInfo(node); body.begin(); GeneratorState generatorState = body.generatorPrologue(); body.enterFunction(node); EvaluateGeneratorComprehension(this, node, body); body.exitFunction(); body.loadUndefined(); body._return(); body.generatorEpilogue(generatorState); body.end(); return body.hasTailCalls(); } Entry<MethodName, LabelState> compile(DoExpression node, CodeVisitor mv) { if (!isCompiled(node)) { if (!isEnabled(Compiler.Option.NoCompletion)) { CompletionValueVisitor.performCompletion(node); } MethodCode method = newMethod(mv.getTopLevelNode(), node); DoExpressionCodeVisitor body = new DoExpressionCodeVisitor(node, method, mv); body.lineInfo(node); body.nop(); // force line-number entry body.begin(); GeneratorState generatorState = null; if (node.hasYieldOrAwait()) { generatorState = body.generatorPrologue(); } body.labelPrologue(); Completion result = statement(node.getStatement(), body); if (!result.isAbrupt()) { // fall-thru, return `0`. body.iconst(0); body._return(); } LabelState labelState = body.labelEpilogue(result); if (generatorState != null) { body.generatorEpilogue(generatorState); } body.end(); doExpressionCompletions.put(node, labelState); } return new SimpleImmutableEntry<>(methodDesc(node), doExpressionCompletions.get(node)); } Entry<MethodName, LabelState> compile(StatementListMethod node, CodeVisitor mv) { if (!isCompiled(node)) { MethodCode method = newMethod(mv.getTopLevelNode(), node); StatementListMethodCodeVisitor body = new StatementListMethodCodeVisitor(node, method, mv); body.lineInfo(node); body.nop(); // force line-number entry body.begin(); GeneratorState generatorState = null; if (node.hasResumePoint()) { generatorState = body.generatorPrologue(); } body.labelPrologue(); Completion result = statements(node.getStatements(), body); if (!result.isAbrupt()) { // fall-thru, return `0`. body.iconst(0); body._return(); } LabelState labelState = body.labelEpilogue(result); if (generatorState != null) { body.generatorEpilogue(generatorState); } body.end(); statementCompletions.put(node, labelState); } return new SimpleImmutableEntry<>(methodDesc(node), statementCompletions.get(node)); } MethodName compile(SpreadElementMethod node, CodeVisitor mv) { if (!isCompiled(node)) { MethodCode method = newMethod(node); SpreadElementCodeVisitor body = new SpreadElementCodeVisitor(node, method, mv); body.lineInfo(node); body.begin(); body.loadArrayObject(); body.loadArrayIndex(); expression(node.getExpression(), body); body._return(); body.end(); } return methodDesc(node); } MethodName compile(PropertyDefinitionsMethod node, boolean hasDecorators, CodeVisitor mv) { if (!isCompiled(node)) { MethodCode method = newMethod(node); PropertyDefinitionsCodeVisitor body = new PropertyDefinitionsCodeVisitor(node, method, mv); body.lineInfo(node); body.begin(); Variable<OrdinaryObject> object = body.getObjectParameter(); Variable<ArrayList<Object>> decorators = hasDecorators ? body.getDecoratorsParameter() : null; PropertyGenerator propgen = propertyGenerator(decorators); for (PropertyDefinition property : node.getProperties()) { body.load(object); property.accept(propgen, body); } body._return(); body.end(); } return methodDesc(node); } MethodName compile(MethodDefinitionsMethod node, boolean hasDecorators, CodeVisitor mv) { if (!isCompiled(node)) { MethodCode method = newMethod(node); MethodDefinitionsCodeVisitor body = new MethodDefinitionsCodeVisitor(node, method, mv); body.lineInfo(node); body.begin(); Variable<OrdinaryConstructorFunction> function = body.getFunctionParameter(); Variable<OrdinaryObject> proto = body.getPrototypeParameter(); Variable<ArrayList<Object>> decorators = hasDecorators ? body.getDecoratorsParameter() : null; ClassPropertyEvaluation(this, node.getProperties(), function, proto, decorators, body); body._return(); body.end(); } return methodDesc(node); } MethodName compile(ExpressionMethod node, CodeVisitor mv) { if (!isCompiled(node)) { MethodCode method = newMethod(node); ExpressionMethodVisitor body = new ExpressionMethodVisitor(node, method, mv); body.lineInfo(node); body.begin(); expressionBoxed(node.getExpression(), body); body._return(); body.end(); } return methodDesc(node); } MethodName compile(BlockStatement node, BlockDeclarationInstantiationGenerator generator) { if (!isCompiled(node)) { MethodCode method = newMethod(node); BlockDeclInitVisitor body = new BlockDeclInitVisitor(method); body.lineInfo(node); body.begin(); Variable<ExecutionContext> cx = body.getExecutionContext(); Variable<LexicalEnvironment<DeclarativeEnvironmentRecord>> env = body.getLexicalEnvironment(); generator.generateMethod(node, cx, env, body); body._return(); body.end(); } return methodDesc(node); } MethodName compile(BlockStatement node, List<Declaration> declarations, BlockDeclarationInstantiationGenerator generator) { MethodCode method = newMethod2(node); BlockDeclInitVisitor body = new BlockDeclInitVisitor(method); body.lineInfo(node); body.begin(); Variable<ExecutionContext> cx = body.getExecutionContext(); Variable<LexicalEnvironment<DeclarativeEnvironmentRecord>> env = body.getLexicalEnvironment(); generator.generateMethod(declarations, cx, env, body); body._return(); body.end(); return methodDesc(node, method.methodName); } MethodName compile(SwitchStatement node, BlockDeclarationInstantiationGenerator generator) { if (!isCompiled(node)) { MethodCode method = newMethod(node); BlockDeclInitVisitor body = new BlockDeclInitVisitor(method); body.lineInfo(node); body.begin(); Variable<ExecutionContext> cx = body.getExecutionContext(); Variable<LexicalEnvironment<DeclarativeEnvironmentRecord>> env = body.getLexicalEnvironment(); generator.generateMethod(node, cx, env, body); body._return(); body.end(); } return methodDesc(node); } MethodName compile(SwitchStatement node, List<Declaration> declarations, BlockDeclarationInstantiationGenerator generator) { MethodCode method = newMethod2(node); BlockDeclInitVisitor body = new BlockDeclInitVisitor(method); body.lineInfo(node); body.begin(); Variable<ExecutionContext> cx = body.getExecutionContext(); Variable<LexicalEnvironment<DeclarativeEnvironmentRecord>> env = body.getLexicalEnvironment(); generator.generateMethod(declarations, cx, env, body); body._return(); body.end(); return methodDesc(node, method.methodName); } /* ----------------------------------------------------------------------------------------- */ ValType expression(Expression node, CodeVisitor mv) { return node.accept(exprgen, mv); } ValType expressionBoxed(Expression node, CodeVisitor mv) { ValType type = node.accept(exprgen, mv); if (type.isJavaPrimitive()) { mv.toBoxed(type); return ValType.Any; } return type; } PropertyGenerator propertyGenerator(Variable<ArrayList<Object>> decorators) { if (decorators != null) { return new PropertyGenerator(this, decorators); } return propgen; } void propertyDefinition(PropertyDefinition node, CodeVisitor mv) { node.accept(propgen, mv); } void blockInit(BlockStatement node, CodeVisitor mv) { blockgen.generate(node, mv); } void blockInit(SwitchStatement node, CodeVisitor mv) { blockgen.generate(node, mv); } Completion statement(ModuleItem node, CodeVisitor mv) { return node.accept(stmtgen, mv); } Completion statements(List<? extends ModuleItem> statements, CodeVisitor mv) { // 13.1.13 Runtime Semantics: Evaluation<br> // StatementList : StatementList StatementListItem /* steps 1-6 */ Completion result = Completion.Empty; for (ModuleItem item : statements) { if ((result = result.then(statement(item, mv))).isAbrupt()) { break; } } return result; } /* ----------------------------------------------------------------------------------------- */ private static final class ScriptCodeVisitor extends CodeVisitor { ScriptCodeVisitor(MethodCode method, Script node) { super(method, node); } @Override public void begin() { super.begin(); setParameterName("cx", 0, Types.ExecutionContext); } @Override protected Variable<Object> createCompletionVariable() { return newVariable("completion", Object.class); } @Override protected boolean hasCompletionValue() { return true; } } private static final class ModuleCodeVisitor extends CodeVisitor { ModuleCodeVisitor(MethodCode method, Module node) { super(method, node); } @Override public void begin() { super.begin(); setParameterName("cx", 0, Types.ExecutionContext); } } private static final class FunctionCodeVisitor extends CodeVisitor { FunctionCodeVisitor(MethodCode method, FunctionNode node) { super(method, node); } @Override public void begin() { super.begin(); setParameterName("cx", 0, Types.ExecutionContext); } } private static final class GeneratorCodeVisitor extends CodeVisitor { GeneratorCodeVisitor(MethodCode method, FunctionNode node) { super(method, node); } @Override public void begin() { super.begin(); setParameterName("cx", 0, Types.ExecutionContext); setParameterName("rp", 1, Types.ResumptionPoint); } } private static final class DoExpressionCodeVisitor extends CodeVisitor { private final boolean withResume; DoExpressionCodeVisitor(DoExpression node, MethodCode method, CodeVisitor parent) { super(method, parent); this.withResume = node.hasYieldOrAwait(); } private int parameter(int index) { assert index > 0; return withResume ? index + 1 : index; } private <T> MutableValue<T> arrayElementFromParameter(int index, Class<T[]> arrayType) { @SuppressWarnings("unchecked") Class<T> componentType = (Class<T>) arrayType.getComponentType(); return arrayElement(getParameter(index, arrayType), 0, componentType); } @Override public void begin() { super.begin(); setParameterName("cx", 0, Types.ExecutionContext); if (withResume) { setParameterName("rp", 1, Types.ResumptionPoint_); } setParameterName("completion", parameter(1), Types.Object_); } @Override protected MutableValue<Object> createCompletionVariable() { return arrayElementFromParameter(parameter(1), Object[].class); } @Override protected boolean hasCompletionValue() { return true; } @Override protected MutableValue<ResumptionPoint> resumptionPoint() { assert withResume; return arrayElementFromParameter(1, ResumptionPoint[].class); } @Override protected void returnForSuspend() { store(resumptionPoint()); iconst(-1); _return(); } } private static abstract class OutlinedMethodCodeVisitor extends CodeVisitor { private final boolean withResume; protected OutlinedMethodCodeVisitor(SyntheticNode node, MethodCode method, CodeVisitor parent) { super(method, parent); this.withResume = node.hasResumePoint(); } protected final boolean hasResume() { return withResume; } protected final int parameter(int index) { assert index > 0; return withResume ? index + 2 : index; } protected final <T> MutableValue<T> arrayElementFromParameter(int index, Class<T[]> arrayType) { @SuppressWarnings("unchecked") Class<T> componentType = (Class<T>) arrayType.getComponentType(); return arrayElement(getParameter(index, arrayType), 0, componentType); } @Override public void begin() { super.begin(); setParameterName("cx", 0, Types.ExecutionContext); if (withResume) { setParameterName("rp", 1, Types.ResumptionPoint_); setParameterName("completion", 2, Types.Object_); } } @Override protected final MutableValue<ResumptionPoint> resumptionPoint() { assert withResume; return arrayElementFromParameter(1, ResumptionPoint[].class); } @Override protected final void returnForSuspend() { store(resumptionPoint()); pushDefaultReturn(); _return(); } @Override protected final void returnForCompletion() { if (withResume) { store(arrayElementFromParameter(2, Object[].class)); pushDefaultReturn(); _return(); } else { _return(); } } protected abstract void pushDefaultReturn(); } private static final class StatementListMethodCodeVisitor extends OutlinedMethodCodeVisitor { private final boolean nodeCompletion; StatementListMethodCodeVisitor(StatementListMethod node, MethodCode method, CodeVisitor parent) { super(node, method, parent); this.nodeCompletion = node.hasCompletionValue(); } @Override public void begin() { super.begin(); if (!hasResume()) { setParameterName("completion", 1, Types.Object_); } } @Override protected MutableValue<Object> createCompletionVariable() { return arrayElementFromParameter(hasResume() ? 2 : 1, Object[].class); } @Override protected boolean hasCompletionValue() { return nodeCompletion && getParent().hasCompletionValue(); } @Override protected void pushDefaultReturn() { // Only used for suspend returns, completion returns are stored in Labels#completion. iconst(-1); } } private static final class ExpressionMethodVisitor extends OutlinedMethodCodeVisitor { ExpressionMethodVisitor(ExpressionMethod node, MethodCode method, CodeVisitor parent) { super(node, method, parent); } @Override protected void pushDefaultReturn() { anull(); } } private static final class SpreadElementCodeVisitor extends OutlinedMethodCodeVisitor { SpreadElementCodeVisitor(SpreadElementMethod node, MethodCode method, CodeVisitor parent) { super(node, method, parent); } @Override public void begin() { super.begin(); setParameterName("array", parameter(1), Types.ArrayObject); setParameterName("index", parameter(2), Type.INT_TYPE); } @Override protected void pushDefaultReturn() { iconst(-1); } void loadArrayObject() { loadParameter(parameter(1), ArrayObject.class); } void loadArrayIndex() { loadParameter(parameter(2), int.class); } } private static final class PropertyDefinitionsCodeVisitor extends OutlinedMethodCodeVisitor { PropertyDefinitionsCodeVisitor(PropertyDefinitionsMethod node, MethodCode method, CodeVisitor parent) { super(node, method, parent); } @Override public void begin() { super.begin(); setParameterName("object", parameter(1), Types.OrdinaryObject); setParameterName("decorators", parameter(2), Types.ArrayList); } @Override protected void pushDefaultReturn() { // void return } Variable<OrdinaryObject> getObjectParameter() { return getParameter(parameter(1), OrdinaryObject.class); } Variable<ArrayList<Object>> getDecoratorsParameter() { return getParameter(parameter(2), ArrayList.class).uncheckedCast(); } } private static final class MethodDefinitionsCodeVisitor extends OutlinedMethodCodeVisitor { MethodDefinitionsCodeVisitor(MethodDefinitionsMethod node, MethodCode method, CodeVisitor parent) { super(node, method, parent); } @Override public void begin() { super.begin(); setParameterName("F", parameter(1), Types.OrdinaryConstructorFunction); setParameterName("proto", parameter(2), Types.OrdinaryObject); setParameterName("decorators", parameter(3), Types.ArrayList); } @Override protected void pushDefaultReturn() { // void return } Variable<OrdinaryConstructorFunction> getFunctionParameter() { return getParameter(parameter(1), OrdinaryConstructorFunction.class); } Variable<OrdinaryObject> getPrototypeParameter() { return getParameter(parameter(2), OrdinaryObject.class); } Variable<ArrayList<Object>> getDecoratorsParameter() { return getParameter(parameter(3), ArrayList.class).uncheckedCast(); } } private static final class BlockDeclInitVisitor extends InstructionVisitor { BlockDeclInitVisitor(MethodCode method) { super(method); } @Override public void begin() { super.begin(); setParameterName("env", 0, Types.LexicalEnvironment); setParameterName("cx", 1, Types.ExecutionContext); } Variable<LexicalEnvironment<DeclarativeEnvironmentRecord>> getLexicalEnvironment() { return getParameter(0, LexicalEnvironment.class).uncheckedCast(); } Variable<ExecutionContext> getExecutionContext() { return getParameter(1, ExecutionContext.class); } } }