@Inject public ExpressionCompiler(Metadata metadata, PageFunctionCompiler pageFunctionCompiler) { requireNonNull(metadata, "metadata is null"); this.pageFunctionCompiler = requireNonNull(pageFunctionCompiler, "pageFunctionCompiler is null"); this.cursorProcessors = CacheBuilder.newBuilder() .recordStats() .maximumSize(1000) .build(CacheLoader.from(key -> compile(key.getFilter(), key.getProjections(), new CursorProcessorCompiler(metadata), CursorProcessor.class))); this.cacheStatsMBean = new CacheStatsMBean(cursorProcessors); }
@Override public void generateMethods(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, RowExpression filter, List<RowExpression> projections) { CachedInstanceBinder cachedInstanceBinder = new CachedInstanceBinder(classDefinition, callSiteBinder); generateProcessMethod(classDefinition, projections.size()); Map<LambdaDefinitionExpression, CompiledLambda> filterCompiledLambdaMap = generateMethodsForLambda(classDefinition, callSiteBinder, cachedInstanceBinder, filter, "filter"); generateFilterMethod(classDefinition, callSiteBinder, cachedInstanceBinder, filterCompiledLambdaMap, filter); for (int i = 0; i < projections.size(); i++) { String methodName = "project_" + i; Map<LambdaDefinitionExpression, CompiledLambda> projectCompiledLambdaMap = generateMethodsForLambda(classDefinition, callSiteBinder, cachedInstanceBinder, projections.get(i), methodName); generateProjectMethod(classDefinition, callSiteBinder, cachedInstanceBinder, projectCompiledLambdaMap, methodName, projections.get(i)); } MethodDefinition constructorDefinition = classDefinition.declareConstructor(a(PUBLIC)); BytecodeBlock constructorBody = constructorDefinition.getBody(); Variable thisVariable = constructorDefinition.getThis(); constructorBody.comment("super();") .append(thisVariable) .invokeConstructor(Object.class); cachedInstanceBinder.generateInitializations(thisVariable, constructorBody); constructorBody.ret(); }
@Override public void generateMethods(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, RowExpression filter, List<RowExpression> projections) { CachedInstanceBinder cachedInstanceBinder = new CachedInstanceBinder(classDefinition, callSiteBinder); generateProcessMethod(classDefinition, projections.size()); generateFilterMethod(classDefinition, callSiteBinder, cachedInstanceBinder, filter); for (int i = 0; i < projections.size(); i++) { generateProjectMethod(classDefinition, callSiteBinder, cachedInstanceBinder, "project_" + i, projections.get(i)); } MethodDefinition constructorDefinition = classDefinition.declareConstructor(a(PUBLIC)); BytecodeBlock constructorBody = constructorDefinition.getBody(); Variable thisVariable = constructorDefinition.getThis(); constructorBody.comment("super();") .append(thisVariable) .invokeConstructor(Object.class); cachedInstanceBinder.generateInitializations(thisVariable, constructorBody); constructorBody.ret(); }
private void generateProjectMethod(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, CachedInstanceBinder cachedInstanceBinder, String methodName, RowExpression projection) { Map<CallExpression, MethodDefinition> tryMethodMap = generateTryMethods(classDefinition, callSiteBinder, cachedInstanceBinder, projection, methodName); Parameter session = arg("session", ConnectorSession.class); Parameter cursor = arg("cursor", RecordCursor.class); Parameter output = arg("output", BlockBuilder.class); MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), methodName, type(void.class), session, cursor, output); method.comment("Projection: %s", projection.toString()); Scope scope = method.getScope(); Variable wasNullVariable = scope.declareVariable(type(boolean.class), "wasNull"); BytecodeBlock body = method.getBody() .comment("boolean wasNull = false;") .putVariable(wasNullVariable, false); BytecodeExpressionVisitor visitor = new BytecodeExpressionVisitor( callSiteBinder, cachedInstanceBinder, fieldReferenceCompiler(cursor, wasNullVariable), metadata.getFunctionRegistry(), ImmutableList.of(session, cursor, wasNullVariable), tryMethodMap); body.getVariable(output) .comment("evaluate projection: " + projection.toString()) .append(projection.accept(visitor, scope)) .append(generateWrite(callSiteBinder, scope, wasNullVariable, projection.getType())) .ret(); }
private void generateProjectMethod( ClassDefinition classDefinition, CallSiteBinder callSiteBinder, CachedInstanceBinder cachedInstanceBinder, Map<LambdaDefinitionExpression, CompiledLambda> compiledLambdaMap, String methodName, RowExpression projection) { Parameter session = arg("session", ConnectorSession.class); Parameter cursor = arg("cursor", RecordCursor.class); Parameter output = arg("output", BlockBuilder.class); MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), methodName, type(void.class), session, cursor, output); method.comment("Projection: %s", projection.toString()); Scope scope = method.getScope(); Variable wasNullVariable = scope.declareVariable(type(boolean.class), "wasNull"); RowExpressionCompiler compiler = new RowExpressionCompiler( callSiteBinder, cachedInstanceBinder, fieldReferenceCompiler(cursor), metadata.getFunctionRegistry(), compiledLambdaMap); method.getBody() .comment("boolean wasNull = false;") .putVariable(wasNullVariable, false) .comment("evaluate projection: " + projection.toString()) .append(compiler.compile(projection, scope, Optional.of(output))) .ret(); }
.gotoLabel(done))) .comment("do the projection") .append(createProjectIfStatement(classDefinition, method, session, cursor, pageBuilder, projections)) .comment("completedPositions++;") .incrementVariable(completedPositionsVariable, (byte) 1));
private void generateFilterMethod(ClassDefinition classDefinition, CallSiteBinder callSiteBinder, CachedInstanceBinder cachedInstanceBinder, RowExpression filter) { Map<CallExpression, MethodDefinition> tryMethodMap = generateTryMethods(classDefinition, callSiteBinder, cachedInstanceBinder, filter, "filter"); Parameter session = arg("session", ConnectorSession.class); Parameter cursor = arg("cursor", RecordCursor.class); MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), "filter", type(boolean.class), session, cursor); method.comment("Filter: %s", filter); Scope scope = method.getScope(); Variable wasNullVariable = scope.declareVariable(type(boolean.class), "wasNull"); BytecodeExpressionVisitor visitor = new BytecodeExpressionVisitor( callSiteBinder, cachedInstanceBinder, fieldReferenceCompiler(cursor, wasNullVariable), metadata.getFunctionRegistry(), ImmutableList.of(session, cursor, wasNullVariable), tryMethodMap); LabelNode end = new LabelNode("end"); method.getBody() .comment("boolean wasNull = false;") .putVariable(wasNullVariable, false) .comment("evaluate filter: " + filter) .append(filter.accept(visitor, scope)) .comment("if (wasNull) return false;") .getVariable(wasNullVariable) .ifFalseGoto(end) .pop(boolean.class) .push(false) .visitLabel(end) .retBoolean(); }
callSiteBinder, cachedInstanceBinder, fieldReferenceCompiler(cursor), metadata.getFunctionRegistry(), compiledLambdaMap);
private Filter compileRowExpression(RowExpression filter) { ParameterizedType className = CompilerUtils.makeClassName(Filter.class.getSimpleName()); ParameterizedType[] interfaces = {ParameterizedType.type(Filter.class)}; ParameterizedType type = ParameterizedType.type(Object.class); EnumSet<Access> accessList = a(new Access[]{PUBLIC, FINAL}); ClassDefinition classDefinition = new ClassDefinition(accessList, className, type, interfaces); classDefinition.declareDefaultConstructor(a(PUBLIC)); CallSiteBinder callSiteBinder = new CallSiteBinder(); CursorProcessorCompiler cursorProcessorCompiler = new CursorProcessorCompiler(metadata); Method method; try { method = cursorProcessorCompiler.getClass().getDeclaredMethod("generateFilterMethod", ClassDefinition.class, CallSiteBinder.class, CachedInstanceBinder.class, RowExpression.class); method.setAccessible(true); } catch (NoSuchMethodException e) { throw Throwables.propagate(e); } try { method.invoke(cursorProcessorCompiler, classDefinition, callSiteBinder, new CachedInstanceBinder(classDefinition, callSiteBinder), filter); } catch (IllegalAccessException | InvocationTargetException e) { throw Throwables.propagate(e); } Class<? extends Filter> aClass = defineClass(classDefinition, Filter.class, callSiteBinder.getBindings(), getClass().getClassLoader()); try { return aClass.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException("Couldn't compile expression", e); } }
callSiteBinder, cachedInstanceBinder, fieldReferenceCompiler(cursor, wasNull), metadata.getFunctionRegistry(), inputParameters,
@Override public Class<? extends CursorProcessor> load(CacheKey key) throws Exception { return compile(key.getFilter(), key.getProjections(), new CursorProcessorCompiler(metadata), CursorProcessor.class); } });