com.yahoo.yqlplus.engine.internal.compiler.TaskGenerator.java Source code

Java tutorial

Introduction

Here is the source code for com.yahoo.yqlplus.engine.internal.compiler.TaskGenerator.java

Source

/*
 * Copyright (c) 2016 Yahoo Inc.
 * Licensed under the terms of the Apache version 2.0 license.
 * See LICENSE file for terms.
 */

package com.yahoo.yqlplus.engine.internal.compiler;

import com.google.common.collect.Lists;
import com.yahoo.yqlplus.api.types.YQLCoreType;
import com.yahoo.yqlplus.api.types.YQLType;
import com.yahoo.yqlplus.engine.internal.bytecode.ReturnCode;
import com.yahoo.yqlplus.engine.internal.bytecode.types.gambit.GambitCreator;
import com.yahoo.yqlplus.engine.internal.bytecode.types.gambit.GambitScope;
import com.yahoo.yqlplus.engine.internal.bytecode.types.gambit.InvocableBuilder;
import com.yahoo.yqlplus.engine.internal.bytecode.types.gambit.ObjectBuilder;
import com.yahoo.yqlplus.engine.internal.bytecode.types.gambit.PhysicalExprOperatorCompiler;
import com.yahoo.yqlplus.engine.internal.bytecode.types.gambit.ScopedBuilder;
import com.yahoo.yqlplus.engine.internal.generate.CompiledResultSetInfo;
import com.yahoo.yqlplus.engine.internal.generate.ProgramGenerator;
import com.yahoo.yqlplus.engine.internal.generate.ProgramInvocation;
import com.yahoo.yqlplus.engine.internal.plan.ast.OperatorStep;
import com.yahoo.yqlplus.engine.internal.plan.ast.OperatorValue;
import com.yahoo.yqlplus.engine.internal.plan.ast.PhysicalExprOperator;
import com.yahoo.yqlplus.engine.internal.plan.ast.PhysicalOperator;
import com.yahoo.yqlplus.engine.internal.plan.types.BytecodeExpression;
import com.yahoo.yqlplus.engine.internal.plan.types.BytecodeSequence;
import com.yahoo.yqlplus.engine.internal.plan.types.base.AnyTypeWidget;
import com.yahoo.yqlplus.engine.internal.plan.types.base.BaseTypeAdapter;
import com.yahoo.yqlplus.language.operator.OperatorNode;
import com.yahoo.yqlplus.language.parser.Location;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import java.util.List;

public class TaskGenerator {
    private final ProgramGenerator programGenerator;
    private final ObjectBuilder builder;
    private final ObjectBuilder.MethodBuilder run;
    private final ScopedBuilder runBody;
    List<String> argumentNames = Lists.newArrayList();

    public TaskGenerator(ProgramGenerator program, GambitScope scope) {
        builder = scope.createObject();
        builder.implement(Runnable.class);
        builder.addParameter("$program", program.getType());
        programGenerator = program;
        this.run = builder.method("run");
        GambitCreator.CatchBuilder catcher = run.tryCatchFinally();
        ScopedBuilder body = catcher.body();
        runBody = body.block();
        body.exec(new ReturnCode());
        ScopedBuilder handler = catcher.on("$e", Throwable.class);
        handler.exec(new BytecodeSequence() {
            @Override
            public void generate(CodeEmitter code) {
                code.exec(code.getLocal("$program"));
                code.exec(code.getLocal("$e"));
                code.getMethodVisitor().visitMethodInsn(Opcodes.INVOKEVIRTUAL,
                        Type.getInternalName(ProgramInvocation.class), "fail",
                        Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Throwable.class)), false);
                code.getMethodVisitor().visitInsn(Opcodes.RETURN);
            }
        });
        run.exec(catcher.build());
    }

    public void addArgument(OperatorValue arg) {
        builder.addParameter(arg.getName(), programGenerator.getValue(arg));
        argumentNames.add(arg.getName());
    }

    public void executeStep(OperatorStep step) {
        PhysicalExprOperatorCompiler compiler = new PhysicalExprOperatorCompiler(runBody);
        OperatorNode<PhysicalOperator> op = (OperatorNode<PhysicalOperator>) step.getCompute();
        OperatorValue output = step.getOutput();
        BytecodeExpression rootContext = runBody.propertyValue(op.getLocation(), runBody.local("$program"),
                "rootContext");
        switch (op.getOperator()) {
        case REQUIRED_ARGUMENT: {
            String nm = op.getArgument(0);
            YQLType ty = op.getArgument(1);
            BytecodeExpression expr = programGenerator.addProgramArgument(nm, ty);
            programGenerator.register(output, expr.getType());
            runBody.evaluateInto(output.getName(), expr);
            break;
        }
        case OPTIONAL_ARGUMENT: {
            String nm = op.getArgument(0);
            YQLType ty = op.getArgument(1);
            Object defaultValue = op.getArgument(2);
            BytecodeExpression expr = programGenerator.addProgramArgument(nm, ty, defaultValue);
            programGenerator.register(output, expr.getType());
            runBody.evaluateInto(output.getName(), expr);
            break;
        }
        case OUTPUT: {
            String nm = op.getArgument(0);
            OperatorNode<PhysicalExprOperator> value = op.getArgument(1);
            final BytecodeExpression nameExpr = runBody.constant(nm);
            GambitCreator.CatchBuilder catchBuilder = runBody.tryCatchFinally();
            ScopedBuilder body = catchBuilder.body();
            body.exec(body.invokeExact(op.getLocation(), "succeed", ProgramInvocation.class, BaseTypeAdapter.VOID,
                    body.local("$program"), nameExpr, body.cast(op.getLocation(), AnyTypeWidget.getInstance(),
                            compiler.evaluateExpression(body.local("$program"), rootContext, value))));
            ScopedBuilder fail = catchBuilder.on("$e", Throwable.class);
            fail.exec(body.invokeExact(op.getLocation(), "fail", ProgramInvocation.class, BaseTypeAdapter.VOID,
                    body.local("$program"), nameExpr,
                    body.cast(op.getLocation(), AnyTypeWidget.getInstance(), fail.local("$e"))));
            runBody.exec(catchBuilder.build());
            CompiledResultSetInfo info = new CompiledResultSetInfo(nm, Object.class);
            programGenerator.getResultSetInfos().add(info);
            break;
        }
        case END: {
            runBody.exec(runBody.invokeExact(op.getLocation(), "end", ProgramInvocation.class, BaseTypeAdapter.VOID,
                    runBody.local("$program")));
            break;
        }
        case EVALUATE_GUARD:
        case EXECUTE:
        case EVALUATE: {
            OperatorNode<PhysicalExprOperator> contextExpr = op.getArgument(0);
            OperatorNode<PhysicalExprOperator> exprTree = op.getArgument(1);
            if (op.getOperator() == PhysicalOperator.EVALUATE_GUARD
                    && exprTree.getOperator() != PhysicalExprOperator.ENFORCE_TIMEOUT) {
                exprTree = OperatorNode.create(PhysicalExprOperator.ENFORCE_TIMEOUT, exprTree);
            }
            BytecodeExpression ctxExpr = compiler.evaluateExpression(runBody.local("$program"), rootContext,
                    contextExpr);
            BytecodeExpression program = runBody.local("$program");
            InvocableBuilder stepInvocable = runBody.createInvocable();
            BytecodeExpression pgm = stepInvocable.addArgument("$program", program.getType());
            BytecodeExpression ctx = stepInvocable.addArgument("$context", ctxExpr.getType());
            PhysicalExprOperatorCompiler stepCompiler = new PhysicalExprOperatorCompiler(stepInvocable.block());
            BytecodeExpression outputExpression = stepCompiler.evaluateExpression(pgm, ctx, exprTree);
            if (op.getOperator() == PhysicalOperator.EXECUTE) {
                GambitCreator.Invocable inc = stepInvocable.complete(outputExpression);
                BytecodeExpression evaluatedExpr = runBody.invoke(exprTree.getLocation(), inc, program, ctxExpr);
                runBody.exec(evaluatedExpr);
            } else if (outputExpression.getType().getValueCoreType() != YQLCoreType.VOID) {
                BytecodeExpression expr = stepInvocable.evaluateTryCatch(op.getLocation(), outputExpression);
                GambitCreator.Invocable inc = stepInvocable.complete(expr);

                ObjectBuilder.FieldBuilder field = programGenerator.registerValue(output, expr.getType());
                BytecodeExpression evaluatedExpr = runBody.invoke(exprTree.getLocation(), inc, program, ctxExpr);
                runBody.set(Location.NONE, field.get(runBody.local("$program")),
                        runBody.evaluateInto(output.getName(), evaluatedExpr));
            } else {
                GambitCreator.Invocable inc = stepInvocable.complete(outputExpression);
                BytecodeExpression evaluatedExpr = runBody.invoke(exprTree.getLocation(), inc, program, ctxExpr);
                runBody.exec(evaluatedExpr);
            }
            break;
        }
        default:
            throw new UnsupportedOperationException("Unimplemented operator: " + op);
        }
    }

    public BytecodeExpression createRunnable(ScopedBuilder body, BytecodeExpression program,
            List<OperatorValue> args) {
        List<BytecodeExpression> exprs = Lists.newArrayList();
        exprs.add(program);
        for (OperatorValue arg : args) {
            exprs.add(body.local(arg.getName()));
        }
        return body.invoke(Location.NONE, builder.getConstructor().invoker(), exprs);
    }

    public ScopedBuilder getBody() {
        return runBody;
    }
}