blob: c2840c5ec1366c55e7a0258385089f99af2b1cc4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tajo.engine.codegen;
import com.google.common.collect.Maps;
import org.apache.tajo.catalog.Schema;
import org.apache.tajo.common.TajoDataTypes;
import org.apache.tajo.datum.Datum;
import org.apache.tajo.datum.IntervalDatum;
import org.apache.tajo.org.objectweb.asm.ClassWriter;
import org.apache.tajo.org.objectweb.asm.MethodVisitor;
import org.apache.tajo.org.objectweb.asm.Opcodes;
import org.apache.tajo.org.objectweb.asm.commons.GeneratorAdapter;
import org.apache.tajo.plan.expr.*;
import org.apache.tajo.storage.Tuple;
import java.util.Map;
import java.util.Stack;
public class EvalCodeGenContext extends TajoGeneratorAdapter {
final String owner;
final Schema schema;
final ClassWriter classWriter;
final EvalNode evalNode;
final Map<EvalNode, String> symbols;
int seqId = 0;
public EvalCodeGenContext(String className, Schema schema, ClassWriter classWriter, EvalNode evalNode) {
this.owner = className;
this.classWriter = classWriter;
this.schema = schema;
this.evalNode = evalNode;
this.symbols = Maps.newHashMap();
emitClassDefinition();
emitMemberFields();
classWriter.visitEnd();
emitConstructor();
String methodName = "eval";
String methodDesc = TajoGeneratorAdapter.getMethodDescription(Datum.class, new Class[]{Tuple.class});
MethodVisitor evalMethod = classWriter.visitMethod(Opcodes.ACC_PUBLIC, methodName, methodDesc, null, null);
evalMethod.visitCode();
this.methodvisitor = evalMethod;
generatorAdapter = new GeneratorAdapter(this.methodvisitor, access, methodDesc, methodDesc);
}
public void emitClassDefinition() {
classWriter.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, this.owner, null,
TajoGeneratorAdapter.getInternalName(EvalNode.class), null);
}
public void emitMemberFields() {
classWriter.visitField(Opcodes.ACC_PRIVATE, "schema",
"L" + TajoGeneratorAdapter.getInternalName(Schema.class) + ";", null, null);
VariablesPreBuilder builder = new VariablesPreBuilder();
builder.visit(this, evalNode, new Stack<>());
}
public static void emitCreateSchema(TajoGeneratorAdapter adapter, MethodVisitor mv, Schema schema) {
mv.visitLdcInsn(schema.toJson());
adapter.invokeStatic(EvalCodeGenerator.class, "createSchema", Schema.class, new Class[] {String.class});
}
public static void emitCreateEval(TajoGeneratorAdapter adapter, MethodVisitor mv, EvalNode evalNode) {
mv.visitLdcInsn(evalNode.toJson());
adapter.invokeStatic(EvalCodeGenerator.class, "createEval", EvalNode.class, new Class[] {String.class});
}
public static void emitConstEval(TajoGeneratorAdapter adapter, MethodVisitor mv, ConstEval evalNode) {
mv.visitLdcInsn(evalNode.toJson());
adapter.invokeStatic(EvalCodeGenerator.class, "createConstEval", ConstEval.class, new Class[] {String.class});
}
public static void emitRowConstantEval(TajoGeneratorAdapter adapter, MethodVisitor mv, RowConstantEval evalNode) {
mv.visitLdcInsn(evalNode.toJson());
adapter.invokeStatic(EvalCodeGenerator.class, "createRowConstantEval", RowConstantEval.class,
new Class[] {String.class});
}
public void emitConstructor() {
// constructor method
MethodVisitor initMethod = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
initMethod.visitCode();
initMethod.visitVarInsn(Opcodes.ALOAD, 0);
initMethod.visitMethodInsn(Opcodes.INVOKESPECIAL, TajoGeneratorAdapter.getInternalName(EvalNode.class), "<init>",
"()V");
TajoGeneratorAdapter consAdapter = new TajoGeneratorAdapter(Opcodes.ACC_PUBLIC, initMethod, "<init>", "()V");
// == this.schema = schema;
if (schema != null) {
consAdapter.aload(0);
emitCreateSchema(consAdapter, initMethod, schema);
initMethod.visitFieldInsn(Opcodes.PUTFIELD, this.owner, "schema", getDescription(Schema.class));
}
for (Map.Entry<EvalNode, String> entry : symbols.entrySet()) {
if (entry.getKey().getType() == EvalType.CONST) {
ConstEval constEval = (ConstEval) entry.getKey();
if (constEval.getValueType().kind() == TajoDataTypes.Type.INTERVAL) {
IntervalDatum datum = (IntervalDatum) constEval.getValue();
final String internalName = TajoGeneratorAdapter.getInternalName(IntervalDatum.class);
initMethod.visitTypeInsn(Opcodes.NEW, internalName);
consAdapter.dup();
initMethod.visitLdcInsn(datum.getMonths());
initMethod.visitLdcInsn(datum.getMilliSeconds());
initMethod.visitMethodInsn(Opcodes.INVOKESPECIAL, internalName, "<init>", "(IJ)V");
int INTERVAL_DATUM = consAdapter.astore();
consAdapter.aload(0);
consAdapter.aload(INTERVAL_DATUM);
initMethod.visitFieldInsn(Opcodes.PUTFIELD, this.owner, entry.getValue(),
"L" + TajoGeneratorAdapter.getInternalName(IntervalDatum.class) + ";");
}
} else if (entry.getKey().getType() == EvalType.IN) {
InEval inEval = (InEval) entry.getKey();
final String internalName = getInternalName(InEval.class);
initMethod.visitTypeInsn(Opcodes.NEW, internalName);
consAdapter.dup();
emitCreateEval(consAdapter, initMethod, inEval.getLeftExpr());
emitRowConstantEval(consAdapter, initMethod, inEval.getRightExpr());
consAdapter.push(inEval.isNot());
consAdapter.invokeSpecial(InEval.class, "<init>", void.class,
new Class [] {EvalNode.class, RowConstantEval.class, boolean.class});
int IN_PREDICATE_EVAL = consAdapter.astore();
consAdapter.aload(0);
consAdapter.aload(IN_PREDICATE_EVAL);
initMethod.visitFieldInsn(Opcodes.PUTFIELD, this.owner, entry.getValue(), getDescription(InEval.class));
} else if (EvalType.isStringPatternMatchOperator(entry.getKey().getType())) {
PatternMatchPredicateEval patternPredicate = (PatternMatchPredicateEval) entry.getKey();
Class clazz = EvalCodeGenerator.getStringPatternEvalClass(entry.getKey().getType());
final String internalName = TajoGeneratorAdapter.getInternalName(clazz);
initMethod.visitTypeInsn(Opcodes.NEW, internalName);
consAdapter.dup();
consAdapter.push(patternPredicate.isNot());
emitCreateEval(consAdapter, initMethod, patternPredicate.getLeftExpr());
emitConstEval(consAdapter, initMethod, (ConstEval) patternPredicate.getRightExpr());
consAdapter.push(patternPredicate.isCaseInsensitive());
consAdapter.invokeSpecial(clazz, "<init>", void.class,
new Class [] {boolean.class, EvalNode.class, ConstEval.class, boolean.class});
int PatternEval = consAdapter.astore();
consAdapter.aload(0);
consAdapter.aload(PatternEval);
initMethod.visitFieldInsn(Opcodes.PUTFIELD, this.owner, entry.getValue(), getDescription(clazz));
} else if (entry.getKey().getType() == EvalType.FUNCTION) {
GeneralFunctionEval function = (GeneralFunctionEval) entry.getKey();
final String internalName = TajoGeneratorAdapter.getInternalName(function.getFuncDesc().getLegacyFuncClass());
// new and initialization of function
initMethod.visitTypeInsn(Opcodes.NEW, internalName);
consAdapter.dup();
initMethod.visitMethodInsn(Opcodes.INVOKESPECIAL, internalName, "<init>", "()V");
int FUNCTION = consAdapter.astore();
// commParam
int paramNum = function.getArgs().length;
initMethod.visitLdcInsn(paramNum);
consAdapter.newArray(FunctionEval.ParamType.class);
final int PARAM_TYPE_ARRAY = consAdapter.astore();
FunctionEval.ParamType[] paramTypes = EvalCodeGenerator.getParamTypes(function.getArgs());
for (int paramIdx = 0; paramIdx < paramTypes.length; paramIdx++) {
consAdapter.aload(PARAM_TYPE_ARRAY);
consAdapter.methodvisitor.visitLdcInsn(paramIdx);
consAdapter.methodvisitor.visitFieldInsn(Opcodes.GETSTATIC, TajoGeneratorAdapter.getInternalName(FunctionEval.ParamType.class),
paramTypes[paramIdx].name(), TajoGeneratorAdapter.getDescription(FunctionEval.ParamType.class));
consAdapter.methodvisitor.visitInsn(Opcodes.AASTORE);
}
initMethod.visitVarInsn(Opcodes.ALOAD, FUNCTION);
consAdapter.aload(PARAM_TYPE_ARRAY);
consAdapter.invokeVirtual(function.getFuncDesc().getLegacyFuncClass(), "init", void.class, new Class[] {FunctionEval.ParamType[].class});
initMethod.visitVarInsn(Opcodes.ALOAD, 0);
initMethod.visitVarInsn(Opcodes.ALOAD, FUNCTION);
initMethod.visitFieldInsn(Opcodes.PUTFIELD, this.owner, entry.getValue(),
"L" + TajoGeneratorAdapter.getInternalName(function.getFuncDesc().getLegacyFuncClass()) + ";");
}
}
initMethod.visitInsn(Opcodes.RETURN);
initMethod.visitMaxs(1, 1);
initMethod.visitEnd();
}
public void emitReturn() {
convertToDatum(evalNode.getValueType(), true);
methodvisitor.visitInsn(Opcodes.ARETURN);
methodvisitor.visitMaxs(0, 0);
methodvisitor.visitEnd();
classWriter.visitEnd();
}
}