Aviator源码:Aviator表达式引擎执行过程源码分析

news2024/10/5 23:26:42

目录

1.if执行脚本示例

2.源码分析

2.1 compile执行过程

2.1.1 CodeGenerator

2.1.2 ExpressionParser

2.1.3 if脚本ASM反编译结果

2.2 compiledExpression.execute执行过程

3.总结概述


由于Aviator支持的脚本语法较多,下面通过项目中使用较多的if语句来对aviator执行过程进行一次源码剖析,以便更清楚的了解aviator具体的解析执行过程,并加深技术储备,方便后续aviator源码相关问题的快速深入分析,同时希望达到“窥一斑而知全貌”的效果;

1.if执行脚本示例

Map<String, Object> env = new HashMap<>();
env.put("a", 2);
env.put("b", 3);
env.put("c", 4);
Object result = AviatorEvaluator.execute("if(a > 1) { return b+2; } else { return c; }", env);

通过执行上述的if脚本,着重分析aviator框架内部的解析逻辑,比如通过asm字节码技术动态生成class、LambdaFunctionBootstrap构造和设计理念以及LambdaFunction函数的构造和设计理念等;

2.源码分析

跟踪AviatorEvaluator.execute方法,内部实现如下:

  /**
   * Execute a text expression with environment
   *
   * @param cacheKey unique key for caching
   * @param expression text expression
   * @param env Binding variable environment
   * @param cached Whether to cache the compiled result,make true to cache it.
   */
  public Object execute(final String cacheKey, final String expression,
      final Map<String, Object> env, final boolean cached) {
    Expression compiledExpression = compile(cacheKey, expression, cached);
    if (compiledExpression != null) {
      return compiledExpression.execute(env);
    } else {
      throw new ExpressionNotFoundException("Null compiled expression for " + expression);
    }
  }

其中主要包含2个部分:

1)compile方法通过asm技术生成ClassExpression的子类:这里将整个表达式脚本编译为ClassExpression子类;

2)执行compiledExpression.execute方法:将外部传入的变量集env实参带入方法中进行执行,返回脚本执行结果;

下面对这2个部分分别进行分析:

2.1 compile执行过程

compile方法体中使用了LRU或HashMap对编译后的字节码进行缓存,编译的字节码是通过方法innerCompile来获取的:

 private Expression compile(final String cacheKey, final String expression,
      final String sourceFile, final boolean cached) {
    if (expression == null || expression.trim().length() == 0) {
      throw new CompileExpressionErrorException("Blank expression");
    }
    if (cacheKey == null || cacheKey.trim().length() == 0) {
      throw new CompileExpressionErrorException("Blank cacheKey");
    }

    if (cached) {
      FutureTask<Expression> existedTask = null;
      if (this.expressionLRUCache != null) {
        boolean runTask = false;
        synchronized (this.expressionLRUCache) {
          existedTask = this.expressionLRUCache.get(cacheKey);
          if (existedTask == null) {
            existedTask = newCompileTask(expression, sourceFile, cached);
            runTask = true;
            this.expressionLRUCache.put(cacheKey, existedTask);
          }
        }
        if (runTask) {
          existedTask.run();
        }
      } else {
        FutureTask<Expression> task = this.expressionCache.get(cacheKey);
        if (task != null) {
          return getCompiledExpression(expression, task);
        }
        task = newCompileTask(expression, sourceFile, cached);
        existedTask = this.expressionCache.putIfAbsent(cacheKey, task);
        if (existedTask == null) {
          existedTask = task;
          existedTask.run();
        }
      }
      return getCompiledExpression(cacheKey, existedTask);

    } else {
      return innerCompile(expression, sourceFile, cached);
    }

  }

innerCompile方法实现如下:

  private Expression innerCompile(final String expression, final String sourceFile,
      final boolean cached) {
    ExpressionLexer lexer = new ExpressionLexer(this, expression);
    CodeGenerator codeGenerator = newCodeGenerator(sourceFile, cached);
    ExpressionParser parser = new ExpressionParser(this, lexer, codeGenerator);
    Expression exp = parser.parse();
    if (getOptionValue(Options.TRACE_EVAL).bool) {
      ((BaseExpression) exp).setExpression(expression);
    }
    return exp;
  }

这里说明几个主要用到的类:

ExpressionLexer:表达式词法分析器,用来对aviator脚本进行词法解析,如将脚本解析为变量、数字、字符串、注释等,并构造Token流进行后续处理;

CodeGenerator:字节码生成器,用于动态生成自定义的字节码;

ExpressionParser:表达式解析器,用于将脚本编译为表达式对象(ClassExpression),支持对多种aviator支持的脚本进行解析,具体解析过程是将ExpressionLexer构造的Token流通过字节码生成器编译为表达式对象ClassExpression

2.1.1 CodeGenerator

这里用到的CodeGenerator主要包括:

CodeGenerator:定义了字节码生成的顶层接口

ASMCodeGenerator:默认的ASM字节码生成器,对CodeGenerator声明的操作进行ASM具体实现

OptimizeCodeGenerator:为加快执行效率而生的字节码生成器(默认的字节码生成器),可以执行一些前置的计算逻辑,然后再委托ASMCodeGenerator进行字节码生成

2.1.2 ExpressionParser

ExpressionParser完成对多种aviator支持的脚本的解析工作,比如if,for,let等脚本特性,解析逻辑是依赖parse方法完成的,如下:

  public Expression parse(final boolean reportErrorIfNotEOF) {
    StatementType statementType = statements();
    if (this.lookhead != null && reportErrorIfNotEOF) {
      if (statementType == StatementType.Ternary) {
        reportSyntaxError("unexpect token '" + currentTokenLexeme()
            + "', maybe forget to insert ';' to complete last expression ");
      } else {
        reportSyntaxError("unexpect token '" + currentTokenLexeme() + "'");
      }
    }
    return getCodeGeneratorWithTimes().getResult(true);
  }

这里主要分为2个部分:

1)调用statements完成脚本解析工作,产出Token流(以默认的OptimizeCodeGenerator进行分析)

2)调用OptimizeCodeGenerator的getResult方法完成ASM字节码生成,并根据字节码构造完成ClassExpression实例对象

2.1.1.1 statements方法

statements中主要的解析过程如下:

private StatementType statements() {
    if (this.lookhead == null) {
      return StatementType.Empty;
    }

    StatementType stmtType = statement();
    ensureDepthState();
    while (expectChar(';') || stmtType == StatementType.Other || stmtType == StatementType.Return) {

      ensureNoStatementAfterReturn(stmtType);

      if (this.lookhead != null && this.lookhead != Variable.END && !expectChar('}')) {
        getCodeGeneratorWithTimes().onTernaryEnd(this.lookhead);
      }

      if (expectChar(';')) {
        move(true);
      }

      if (this.lookhead == null) {
        break;
      }

      StatementType nextStmtType = statement();
      if (nextStmtType == StatementType.Empty) {
        break;
      }
      stmtType = nextStmtType;
      ensureDepthState();
    }
    ensureNoStatementAfterReturn(stmtType);
    // If the last statement is ternary,it must be ended with END TOKEN such as null token, '}',
    // 'end' keyword, or ';'
    // Otherwise report syntax error.
    if (stmtType == StatementType.Ternary) {
      if (lookhead != null && !expectChar(';') && !expectChar('}') && lookhead != Variable.END) {
        this.back();
        reportSyntaxError("unexpect token '" + currentTokenLexeme()
            + "', maybe forget to insert ';' to complete last expression ");
      }
    }

    return stmtType;
  }

具体的解析过程是在statement方法中,如下:

private StatementType statement() {
    if (this.lookhead == Variable.IF) {
      ensureFeatureEnabled(Feature.If);
      if (ifStatement(false, false)) {
        return StatementType.Return;
      } else {
        return StatementType.Other;
      }
    } else if (this.lookhead == Variable.FOR) {
      ensureFeatureEnabled(Feature.ForLoop);
      forStatement();
      return StatementType.Other;
    } else if (this.lookhead == Variable.RETURN) {
      ensureFeatureEnabled(Feature.Return);
      returnStatement();
      return StatementType.Return;
    } else if (this.lookhead == Variable.BREAK) {
      breakStatement();
      return StatementType.Return;
    } else if (this.lookhead == Variable.CONTINUE) {
      continueStatement();
      return StatementType.Return;
    } else if (this.lookhead == Variable.LET) {
      ensureFeatureEnabled(Feature.Let);
      letStatement();
      return StatementType.Other;
    } else if (this.lookhead == Variable.WHILE) {
      ensureFeatureEnabled(Feature.WhileLoop);
      whileStatement();
      return StatementType.Other;
    } else if (this.lookhead == Variable.FN) {
      ensureFeatureEnabled(Feature.Fn);
      fnStatement();
      return StatementType.Other;
    } else if (this.lookhead == Variable.TRY) {
      ensureFeatureEnabled(Feature.ExceptionHandle);
      tryStatement();
      return StatementType.Other;
    } else if (this.lookhead == Variable.THROW) {
      ensureFeatureEnabled(Feature.ExceptionHandle);
      throwStatement();
      return StatementType.Other;
    } else if (expectChar('{')) {
      ensureFeatureEnabled(Feature.LexicalScope);
      if (scopeStatement()) {
        return StatementType.Return;
      } else {
        return StatementType.Other;
      }
    } else if (this.lookhead == Variable.USE) {
      ensureFeatureEnabled(Feature.Use);
      useStatement();
      return StatementType.Other;
    } else {
      if (ternary()) {
        return StatementType.Ternary;
      } else {
        return StatementType.Empty;
      }
    }
  }

这里可以看到:aviator支持的多种脚本特性,比如if、for、let、return等语法都是在这里解析完成的;

以if语法举例说明,继续跟踪ifStatement方法,如下:

  /**
   * <pre>
   *  if(test) {
   *     ...if-body...
   *  }else {
   *     ...else-body...
   *  }
   *  ...statements...
   * </pre>
   *
   * ===>
   *
   * <pre>
   *  __if_callcc(test ? (lambda() -> ...if-body... end)() :  (lambda() -> ...else-body... end)(),
   *   lambda()- >
   *       ...statements...
   *  end);
   * </pre>
   */
  private boolean ifStatement(final boolean isWhile, final boolean isElsif) {
    if (!isWhile) {
      move(true);
    }
    boolean ifBodyHasReturn = false;
    boolean elseBodyHasReturn = false;
    boolean newLexicalScope = this.scope.newLexicalScope;
    this.scope.newLexicalScope = true;
    // prepare to call __if_callcc(result, statements)
    getCodeGeneratorWithTimes().onMethodName(Constants.IfReturnFn);

    {
      if (!ternary()) {
        reportSyntaxError("missing test statement for if");
      }

      getCodeGeneratorWithTimes().onTernaryBoolean(this.lookhead);
      if (expectChar('{')) {
        move(true);
        this.scope.enterBrace();
        getCodeGeneratorWithTimes().onLambdaDefineStart(
            getPrevToken().withMeta(Constants.SCOPE_META, this.scope.newLexicalScope));
        getCodeGeneratorWithTimes().onLambdaBodyStart(this.lookhead);
        ifBodyHasReturn = statements() == StatementType.Return;
        getCodeGeneratorWithTimes().onLambdaBodyEnd(this.lookhead);
        getCodeGeneratorWithTimes().onMethodName(anonymousMethodName());
        getCodeGeneratorWithTimes().onMethodInvoke(this.lookhead);
        getCodeGeneratorWithTimes().onTernaryLeft(this.lookhead);
      } else {
        reportSyntaxError("expect '{' for " + getLoopKeyword(isWhile) + " statement");
      }
      if (!expectChar('}')) {
        reportSyntaxError("missing '}' to close " + getLoopKeyword(isWhile) + " body");
      }
      this.scope.leaveBrace();
      move(true);

      elseBodyHasReturn = elseStatement(isWhile, ifBodyHasReturn);
      getCodeGeneratorWithTimes().onMethodParameter(this.lookhead);
    }

    {
      //
      if (isWhile || isElsif) {
        // Load ReducerEmptyVal directly.
        getCodeGenerator().onConstant(Constants.ReducerEmptyVal);
      } else {

        if (expectChar(';')) {
          // the statement is ended.
          getCodeGenerator().onConstant(Constants.ReducerEmptyVal);
        } else {
          // create a lambda function wraps statements after if statement (statements)
          getCodeGeneratorWithTimes().onLambdaDefineStart(
              getPrevToken().withMeta(Constants.SCOPE_META, this.scope.newLexicalScope) //
                  .withMeta(Constants.INHERIT_ENV_META, true));
          getCodeGeneratorWithTimes().onLambdaBodyStart(this.lookhead);
          if (statements() == StatementType.Empty) {
            getCodeGenerator().onConstant(Constants.ReducerEmptyVal);
          } else {
            if (ifBodyHasReturn && elseBodyHasReturn && !isElsif) {
              reportSyntaxError("unreachable code");
            }
          }
          getCodeGeneratorWithTimes().onLambdaBodyEnd(this.lookhead);
        }
      }
      getCodeGenerator().onMethodParameter(this.lookhead);
      // call __if_callcc(result, statements)
      getCodeGenerator().onMethodInvoke(this.lookhead);
      this.scope.newLexicalScope = newLexicalScope;
    }

    return ifBodyHasReturn && elseBodyHasReturn;
  }

if语法的解析过程主要分为以下几个部分:

1)通过ternary方法完成对if条件语句的解析(解析结果放入OptimizeCodeGenerator的Token流中,后续统一生成字节码)

2)if的方法体(ifBody)抽象为一个lambda表达式,并通过委托给lambdaGenerator进行解析,后面着重分析该解析过程;

3)对elseBody进行解析:这里实际的解析过程和ifBody的解析过程类似,也是委托给新构建的lambdaGenerator进行解析;

 private boolean elseStatement(final boolean isWhile, final boolean ifBodyHasReturn) {
    if (isWhile) {
      // Call __reducer_break(nil)
      final CodeGenerator cg = getCodeGeneratorWithTimes();
      cg.onMethodName(Constants.ReducerBreakFn);
      cg.onConstant(Variable.NIL);
      cg.onMethodParameter(this.lookhead);
      cg.onMethodInvoke(this.lookhead);
      cg.onTernaryRight(this.lookhead);
      return false;
    }

    if (expectChar(';')) {
      return withoutElse();
    }

    boolean hasReturn = false;
    boolean hasElsif = this.lookhead == Variable.ELSIF;
    boolean hasElse = this.lookhead == Variable.ELSE;
    if (this.lookhead != null && (hasElse || hasElsif || ifBodyHasReturn)) {
      if (hasElse) {
        move(true);
        if (expectChar('{')) {
          this.scope.enterBrace();
          move(true);
          hasReturn = elseBody(false);
          if (expectChar('}')) {
            this.scope.leaveBrace();
            move(true);
          } else {
            reportSyntaxError("missing '}' to close 'else' body");
          }
        } else {
          reportSyntaxError("expect '{' for else statement");
        }
      } else if (hasElsif) {
        hasReturn = ifStatement(false, true);
        getCodeGenerator().onTernaryRight(this.lookhead);
      } else if (ifBodyHasReturn) {
        hasReturn = elseBody(true);
      } else {
        return withoutElse();
      }
      return hasReturn;
    } else {
      // Missing else statement, always nil.
      return withoutElse();
    }
  }

4)这里对if语句后面的整个脚本抽象为一个lambda表达式,也是通过委托给lambdaGenerator进行解析;

如上的解析过程也可以借助方法注释进行较好的理解:

2.1.1.1.1 lambdaGenerator解析过程分析

对2.1.1.1 节的注释2的代码进一步分析:

1)lambda脚本解析前置环节

onLambdaDefineStart方法构造lambdaGenerator;

onLambdaBodyStart方法将ExpressionParser的codeGenerator替换为新构造的lambdaGenerator,同时维护好lambdaGenerator的父parentCodeGenerator=OptimizeCodeGenerator,lamdba解析完成后再替换回parentCodeGenerator,也即OptimizeCodeGenerator,也及整个脚本的ASM操作是通过OptimizeCodeGenerator和lambdaGenerator(如果包含lambda语法)交替完成的

2)lambda脚本解析完成后

lambda脚本解析完成后,这里会调用getLmabdaBootstrap构造LambdaFunctionBootstrap实例对象,并将LambdaFunctionBootstrap缓存到OptimizeCodeGenerator的

Map<String, LambdaFunctionBootstrap> lambdaBootstraps成员变量中;

进一步展开getLmabdaBootstrap函数:

可以看到这里也是通过getResult方法通过ASM字节码技术动态构造Expression子类实例(具体分析过程见2.1.1.2),构造的结果放到了LambdaFunctionBootstrap实例对象中,也即lambda表达式的解析结果即为LambdaFunctionBootstrap;

2.1.1.2 OptimizeCodeGenerator.getResult()过程分析

aviator脚本解析完成之后,解析结果Token流会存放到OptimizeCodeGenerator的成员变量List<Token<?>> tokenList中,getResult方法就是根据tokenList生成字节码的过程;

getResult方法具体实现如下:

  @Override
  public Expression getResult(final boolean unboxObject) {
    // execute literal expression
    while (execute() > 0) {
      ;
    }

    Map<String, VariableMeta/* metadata */> variables = new LinkedHashMap<String, VariableMeta>();
    Map<String, Integer/* counter */> methods = new HashMap<String, Integer>();
    Set<Token<?>> constants = new HashSet<>();
    for (Token<?> token : this.tokenList) {
      if (ExpressionParser.isConstant(token, this.instance)) {
        constants.add(token);
      }
      switch (token.getType()) {
        case Variable:
          if (SymbolTable.isReservedKeyword((Variable) token)) {
            continue;
          }

          String varName = token.getLexeme();
          VariableMeta meta = variables.get(varName);
          if (meta == null) {
            meta = new VariableMeta((CompileTypes) token.getMeta(Constants.TYPE_META), varName,
                token.getMeta(Constants.INIT_META, false), token.getStartIndex());
            variables.put(varName, meta);
          } else {
            meta.add(token);
          }

          break;
        case Delegate:
          DelegateToken delegateToken = (DelegateToken) token;
          if (delegateToken.getDelegateTokenType() == DelegateTokenType.Method_Name) {
            Token<?> realToken = delegateToken.getToken();
            if (realToken == null) {
              continue;
            }
            if (realToken.getType() == TokenType.Variable) {
              String methodName = token.getLexeme();
              if (!methods.containsKey(methodName)) {
                methods.put(methodName, 1);
              } else {
                methods.put(methodName, methods.get(methodName) + 1);
              }
            }
          } else if (delegateToken.getDelegateTokenType() == DelegateTokenType.Array) {
            Token<?> realToken = delegateToken.getToken();
            if (realToken.getType() == TokenType.Variable) {
              varName = token.getLexeme();
              VariableMeta varMeta = variables.get(varName);
              if (varMeta == null) {
                varMeta =
                    new VariableMeta((CompileTypes) realToken.getMeta(Constants.TYPE_META), varName,
                        realToken.getMeta(Constants.INIT_META, false), realToken.getStartIndex());
                variables.put(varName, varMeta);
              } else {
                varMeta.add(realToken);
              }
            }
          }
          break;
      }
    }

    Expression exp = null;

    // Last token is a literal token,then return a LiteralExpression
    if (this.tokenList.size() <= 1) {
      if (this.tokenList.isEmpty()) {
        exp = new LiteralExpression(this.instance, null, new ArrayList<>(variables.values()));
      } else {
        final Token<?> lastToken = this.tokenList.get(0);
        if (ExpressionParser.isLiteralToken(lastToken, this.instance)) {
          exp = new LiteralExpression(this.instance,
              getAviatorObjectFromToken(lastToken).getValue(getCompileEnv()),
              new ArrayList<>(variables.values()));
        }
      }
    }

    if (exp == null) {
      // call asm to generate byte codes
      callASM(variables, methods, constants);
      // get result from asm
      exp = this.codeGen.getResult(unboxObject);
    }


    if (exp instanceof BaseExpression) {
      ((BaseExpression) exp).setCompileEnv(getCompileEnv());
      ((BaseExpression) exp).setSourceFile(this.sourceFile);
    }
    return exp;
  }

这里主要包含以下几部分:

1)可以前置执行的逻辑提前执行,比如文本表达式(1+2)等,先行计算出执行结果,优化执行效率;

2)初始化常量集、变量集、aviator函数实例集合,为后续ASM生成类成员变量和类构造函数使用;

3)调用callASM方法生成字节码,根据不同的token类型进行不同的asm操作;

 private void callASM(final Map<String, VariableMeta/* metadata */> variables,
      final Map<String, Integer/* counter */> methods, final Set<Token<?>> constants) {
    this.codeGen.initConstants(constants);
    this.codeGen.initVariables(variables);
    this.codeGen.initMethods(methods);
    this.codeGen.setLambdaBootstraps(this.lambdaBootstraps);
    this.codeGen.start();

    for (int i = 0; i < this.tokenList.size(); i++) {
      Token<?> token = this.tokenList.get(i);
      switch (token.getType()) {
        case Operator:
          OperatorToken op = (OperatorToken) token;

          switch (op.getOperatorType()) {
            case ADD:
              this.codeGen.onAdd(token);
              break;
            case SUB:
              this.codeGen.onSub(token);
              break;
            case MULT:
              this.codeGen.onMult(token);
              break;
            case Exponent:
              this.codeGen.onExponent(token);
              break;
            case DIV:
              this.codeGen.onDiv(token);
              break;
            case MOD:
              this.codeGen.onMod(token);
              break;
            case EQ:
              this.codeGen.onEq(token);
              break;
            case NEQ:
              this.codeGen.onNeq(token);
              break;
            case LT:
              this.codeGen.onLt(token);
              break;
            case LE:
              this.codeGen.onLe(token);
              break;
            case GT:
              this.codeGen.onGt(token);
              break;
            case GE:
              this.codeGen.onGe(token);
              break;
            case NOT:
              this.codeGen.onNot(token);
              break;
            case NEG:
              this.codeGen.onNeg(token);
              break;
            case AND:
              this.codeGen.onAndRight(token);
              break;
            case OR:
              this.codeGen.onJoinRight(token);
              break;
            case FUNC:
              this.codeGen.onMethodInvoke(token);
              break;
            case INDEX:
              this.codeGen.onArrayIndexEnd(token);
              break;
            case MATCH:
              this.codeGen.onMatch(token);
              break;
            case TERNARY:
              this.codeGen.onTernaryRight(token);
              break;
            case BIT_AND:
              this.codeGen.onBitAnd(token);
              break;
            case BIT_OR:
              this.codeGen.onBitOr(token);
              break;
            case BIT_XOR:
              this.codeGen.onBitXor(token);
              break;
            case BIT_NOT:
              this.codeGen.onBitNot(token);
              break;
            case SHIFT_LEFT:
              this.codeGen.onShiftLeft(token);
              break;
            case SHIFT_RIGHT:
              this.codeGen.onShiftRight(token);
              break;
            case DEFINE:
              this.codeGen.onAssignment(token.withMeta(Constants.DEFINE_META, true));
              break;
            case ASSIGNMENT:
              this.codeGen.onAssignment(token);
              break;
            case U_SHIFT_RIGHT:
              this.codeGen.onUnsignedShiftRight(token);
              break;
          }
          break;
        case Delegate:
          DelegateToken delegateToken = (DelegateToken) token;
          final Token<?> realToken = delegateToken.getToken();
          switch (delegateToken.getDelegateTokenType()) {
            case And_Left:
              this.codeGen.onAndLeft(realToken);
              break;
            case Join_Left:
              this.codeGen.onJoinLeft(realToken);
              break;
            case Array:
              this.codeGen.onArray(realToken);
              break;
            case Index_Start:
              this.codeGen.onArrayIndexStart(realToken);
              break;
            case Ternary_Boolean:
              this.codeGen.onTernaryBoolean(realToken);
              break;
            case Ternary_Left:
              this.codeGen.onTernaryLeft(realToken);
              break;
            case Method_Name:
              this.codeGen.onMethodName(realToken);
              break;
            case Method_Param:
              this.codeGen.onMethodParameter(realToken);
              break;
            case Lambda_New:
              this.codeGen.genNewLambdaCode(delegateToken.getLambdaFunctionBootstrap());
              break;
            case Ternay_End:
              this.codeGen.onTernaryEnd(realToken);
              break;
          }
          break;

        default:
          this.codeGen.onConstant(token);
          break;
      }

    }
  }

4)调用getResult方法根据生成的字节码构造Expression子类实例(ClassExpression)

  @Override
  public Expression getResult(final boolean unboxObject) {
    end(unboxObject);

    byte[] bytes = this.classWriter.toByteArray();
    try {
      Class<?> defineClass =
          ClassDefiner.defineClass(this.className, Expression.class, bytes, this.classLoader);
      Constructor<?> constructor =
          defineClass.getConstructor(AviatorEvaluatorInstance.class, List.class, SymbolTable.class);
      BaseExpression exp = (BaseExpression) constructor.newInstance(this.instance,
          new ArrayList<VariableMeta>(this.variables.values()), this.symbolTable);
      exp.setLambdaBootstraps(this.lambdaBootstraps);
      exp.setFuncsArgs(this.funcsArgs);
      exp.setSourceFile(this.sourceFile);
      return exp;
    } catch (ExpressionRuntimeException e) {
      throw e;
    } catch (Throwable e) {
      if (e.getCause() instanceof ExpressionRuntimeException) {
        throw (ExpressionRuntimeException) e.getCause();
      }
      throw new CompileExpressionErrorException("define class error", e);
    }
  }

2.1.3 if脚本ASM反编译结果

if脚本的asm的解析过程已分析完成,结合上面的if具体脚本示例和源码中asm字节码生成过程,可以得到上述的if脚本示例动态生成的类如下:

1)ifBody生成的lassLambda_1684208818128_57)

public super class Script_11313134242424_59 extends ClassExpression {
	
	private final AviatorObject f0=null;
	private final AviatorJavaType f1=null;
	private final AviatorFunction f2=null;

	public void <init> (final AviatorEvaluatorInstance instance, final List<VariableMeta> vars,
      final SymbolTable symbolTable){
		super(instance,vars,symbolTable);
		f0=AviatorLong.valueOf(2);
		f1=new AviatorJavaType("b", symbolTable);
		f2=instance.getFunction("__reducer_return",symbolTable);
	}

	public final Object execute0(Env env){
		return RuntimeUtils.assertNotNull(f2.call(env,f1.add(f0, env))).deref(env);
	}
}

2)elseBody生成的classambda_1684208818128_58)

public super class Script_11313134242424_60 extends ClassExpression {
	
	private final AviatorJavaType f0=null;
	private final AviatorFunction f1=null;

	public void <init> (final AviatorEvaluatorInstance instance, final List<VariableMeta> vars,
      final SymbolTable symbolTable){
		super(instance,vars,symbolTable);
		f0=new AviatorJavaType("c", symbolTable);
	  f1=instance.getFunction("__reducer_return",symbolTable);
	}

	public final Object execute0(Env env){
		return RuntimeUtils.assertNotNull(f1.call(env,f0)).deref(env);
	}
}

 3)if语句后面的语句生成的classambda_1684208818128_59)

public super class Script_11313134242424_61 extends ClassExpression {
		
	private final AviatorJavaType f0=null;

	public void <init> (final AviatorEvaluatorInstance instance, final List<VariableMeta> vars,
      final SymbolTable symbolTable){
		super(instance,vars,symbolTable);
		f0=new AviatorJavaType("_reducer_empty", symbolTable);
	}

	public final Object execute0(Env env){
		return f0.deref(env); // return null;
	}
}

4)整个if脚本生成的class

public super class Script_11313134242424_58 extends ClassExpression {

	private final AviatorObject f0=null;
	private final AviatorJavaType f1=null;
	private final AviatorFunction f2=null;

	public void <init> (final AviatorEvaluatorInstance instance, final List<VariableMeta> vars,
      final SymbolTable symbolTable){
		super(instance,vars,symbolTable);
		f0=AviatorLong.valueOf(1);
		f1=new AviatorJavaType("a", symbolTable);
	  f2=AviatorEvaluatorInstance.getFunction("__if_callcc",symbolTable);
	}

	public final Object execute0(Env env){

		RuntimeUtils.assertNotNull(f2.call(env, 
		if(f1.compare(f0, env).booleanValue(env)){
			RuntimeUtils.assertNotNull(RuntimeUtils.getFunction(this.newLambda(env, "Lambda_1684208818128_57"), env).call(env));
		}else{
			RuntimeUtils.assertNotNull(RuntimeUtils.getFunction(this.newLambda(env, "Lambda_1684208818128_58"), env).call(env));
		},
		this.newLambda(env, "Lambda_1684208818128_59")
		)).getValue(env);
	}
}

2.2 compiledExpression.execute执行过程

上述根据if脚本通过asm字节码最终生成ClassExpression类后,下面即传出变量集env实参进行执行,execute方法如下:

  @Override
  public Object execute(Map<String, Object> map) {
    if (map == null) {
      map = Collections.emptyMap();
    }
    Env env = genTopEnv(map);
    EnvProcessor envProcessor = this.instance.getEnvProcessor();
    if (envProcessor != null) {
      envProcessor.beforeExecute(env, this);
    }
    try {
      return executeDirectly(env);
    } finally {
      if (envProcessor != null) {
        envProcessor.afterExecute(env, this);
      }
    }
  }

这里包含了EnvProcessor前置拦截和后置拦截器,下面主要分析下executeDirectly方法具体执行过程:

  @Override
  public Object executeDirectly(final Map<String, Object> env) {
    try {
      Object result = execute0((Env) env);
      if (RuntimeUtils.isTracedEval(env)) {
        RuntimeUtils.printlnTrace(env, "Result : " + result);
      }
      return result;
    } catch (ExpressionRuntimeException e) {
      throw e;
    } catch (Throwable t) {
      throw Reflector.sneakyThrow(t);
    }
  }

ClassExpression的方法executeDirectly中又调用了execute0进行执行,产出结果,这里的execute0即为上面asm字节码生成部分通过asm生成的成员方法,

针对上述的if脚本示例,生成的ClassExpression子类和实现的execute0方法如下:

public super class Script_11313134242424_58 extends ClassExpression {

	private final AviatorObject f0=null;
	private final AviatorJavaType f1=null;
	private final AviatorFunction f2=null;

	public void <init> (final AviatorEvaluatorInstance instance, final List<VariableMeta> vars,
      final SymbolTable symbolTable){
		super(instance,vars,symbolTable);
		f0=AviatorLong.valueOf(1);
		f1=new AviatorJavaType("a", symbolTable);
	  f2=AviatorEvaluatorInstance.getFunction("__if_callcc",symbolTable);
	}

	public final Object execute0(Env env){

		RuntimeUtils.assertNotNull(f2.call(env, 
		if(f1.compare(f0, env).booleanValue(env)){
			RuntimeUtils.assertNotNull(RuntimeUtils.getFunction(this.newLambda(env, "Lambda_1684208818128_57"), env).call(env));
		}else{
			RuntimeUtils.assertNotNull(RuntimeUtils.getFunction(this.newLambda(env, "Lambda_1684208818128_58"), env).call(env));
		},
		this.newLambda(env, "Lambda_1684208818128_59")
		)).getValue(env);
	}
}

这样,execute0通过传入env实参,执行的方法体即完整实现了if示例脚本的内容,最终产出if脚本计算结果;

其中在执行到某个具体if分支时,会调用newLambda函数:

  public LambdaFunction newLambda(final Env env, final String name) {
    LambdaFunctionBootstrap bootstrap = this.lambdaBootstraps.get(name);
    if (bootstrap == null) {
      throw new ExpressionNotFoundException("Lambda " + name + " not found");
    }
    return bootstrap.newInstance(env);
  }

newLambda函数中会调用缓存的lambdaBootstraps,获取对应的LambdaFunctionBootstrap,然后通过newInstance方法创建对应的LambdaFunction,如下:

  /**
   * Create a lambda function.
   *
   * @param env
   * @return
   */
  public LambdaFunction newInstance(final Env env) {
    Reference<LambdaFunction> ref = null;
    if (this.inheritEnv && (ref = this.fnLocal.get()) != null) {
      LambdaFunction fn = ref.get();
      if (fn != null) {
        fn.setContext(env);
        return fn;
      } else {
        this.fnLocal.remove();
      }
    }

    LambdaFunction fn = new LambdaFunction(this.name, this.params, this.expression, env);
    fn.setInheritEnv(this.inheritEnv);
    if (this.inheritEnv) {
      this.fnLocal.set(new SoftReference<>(fn));
    }
    return fn;
  }

后面继续调用LambdaFunction的call函数:

  @Override
  public AviatorObject call(final Map<String, Object> env) {
    try {
      if (this.isVariadic && !this.installed) {
        return variadicCall(env, true);
      }
      return AviatorRuntimeJavaType.valueOf(this.expression.executeDirectly(newEnv(env)));
    } finally {
      if (this.inheritEnv) {
        this.context = null;
      }
    }
  }

call方法体中,又进一步调用了lambda脚本通过asm生成的expression,进而执行了对应分支的逻辑,至此,最终产出计算结果;

3.总结概述

1)LambdaFunctionBootstrap代表的含义

LambdaFunctionBootstrap是对if语法中ifBody,elseBody,elsifBody以及if语句之后的语句构造的模型(也包括其他的while、for、lambda语法等),是对lambda类型脚本通过asm字节码技术编译后的抽象,包含了lambda类型脚本编译后的Expression

2)LRU缓存中缓存的内容

LRU缓存的key为执行脚本本身,String类型

LRU缓存的value为Expression对象,对于ClassExpression子类对象,内部包含了解析的多个LambdaFunctionBootstrap实例,对于上述if脚本示例,即包含3个LambdaFunctionBootstrap实例

3)LambdaFunction代表的含义

在if脚本示例编译后的ClassExpression子类实例中,方法execute0中调用了newLambda方法,在传入参数env后的执行过程中,通过这里的newLambda会创建LambdaFunction对象,LambdaFunction是对lambda类型脚本在执行过程中的抽象,包含了lambda类型脚本编译后的Expression;

在LambdaFunctionBootstrap中实现了对于LambdaFunction(非线程安全)的ThreadLocal线程本地缓存,提交执行效率;

附,LambdaFunction函数作为线程本地缓存,aviator低版本(version<5.3.3)存在内存泄漏问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/649372.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

tinyWebServer 学习笔记——六、注册登录

文章目录 一、基础知识二、代码解析1. 载入数据库表2. 提取用户名和密码3. 同步线程登录注册4. 页面跳转 参考文献 一、基础知识 流程图 [1] 二、代码解析 1. 载入数据库表 // 用户名和密码 map<string, string> users;// 初始化数据库 void http_conn::initmysql_resu…

关于 Spring 中事务的嵌套,你了解多少?

Spring事务的的详细理解&#xff0c;事务嵌套解析&#xff0c;以及事务失效的场景解惑 想要了解Spring的事务嵌套&#xff0c;我们先了解一下Spring的七种事务传播属性各自表示的意思 propagation_requierd&#xff1a;如果当前没有事务&#xff0c;就新建一个事务&#xff0c…

简单的TCP网络程序·单进程(后端服务器)

目录 文件1&#xff1a;tcpServer.cc 文件2&#xff1a;tcpServer.hpp 1.提出日志概念 -- 在后续完善 日志格式 -- 暂定简单的打印功能 2.创建套接字 SOCK_STREAM -- socket参数 3.bind自己的套接字 4.设置socket 为监听状态 * 新接口1&#xff1a;listen 函数1&…

Spring Boot进阶(46):集成Jackson之快速入门 | 超级详细,建议收藏

1. 前言&#x1f525; 在上一期《SpringBoot之Jackson配置全局时间日期格式》文中提到Jackson&#xff0c;了解到有很多小伙伴对它很感兴趣&#xff1b;顾这一期&#xff0c;我就重点带着大家以最基础的教学方式领大家入门&#xff0c;废话不多说&#xff0c;咱们这就开始。 这…

(字符串) 925. 长按键入 ——【Leetcode每日一题】

❓925. 长按键入 难度&#xff1a;简单 你的朋友正在使用键盘输入他的名字 name。偶尔&#xff0c;在键入字符 c 时&#xff0c;按键可能会被长按&#xff0c;而字符可能被输入 1 次或多次。 你将会检查键盘输入的字符 typed。如果它对应的可能是你的朋友的名字&#xff08;…

【大学物理实验】表面张力

文章目录 选择题选择题 液体表面张力只存在与液体的: A. 内部 B. 底部 C. 表面 D. 表面和内部 正确答案: C 本实验中,下面哪一件测量仪器(工具)是不需要的: A. 力敏传感器 B. 数字电压表 C. 游标卡尺 D. 物理天平 正确答案: D 关于吊环从液体中拉脱力(即最大表面张力)…

距离和相似性度量

文章目录 1. 距离度量1.1 欧几里得距离(Euclidean Distance)1.2 明可夫斯基距离(Minkowski Distance)1.3 曼哈顿距离(Manhattan Distance)1.4 切比雪夫距离(Chebyshev Distance)1.5 马哈拉诺比斯距离(Mahalanobis Distance) 2. 相似性度量2.1 向量空间余弦相似度(Cosine Simila…

盘点五种最常用加密算法!

大家好&#xff0c;我是老三&#xff0c;大家都知道我是一个臭做支付的&#xff0c;支付常常要和一些加签、验签&#xff0c;加密、解密打交道&#xff0c;今天&#xff0c;就给大家来盘点一下最常见的5种加密算法。 前言 大家平时的工作中&#xff0c;可能也在很多地方用到了…

封神榜科技成果 - 国产训练大模型

封神榜科技成果 Fengshenbang 1.0: 封神榜开源计划1.0中英双语总论文&#xff0c;旨在成为中文认知智能的基础设施。 BioBART: 由清华大学和IDEA研究院一起提供的生物医疗领域的生成语言模型。(BioNLP 2022) UniMC: 针对zero-shot场景下基于标签数据集的统一模型。(EMNLP 2022)…

STM32单片机(六)TIM定时器 -> 第三节:TIM输出比较

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

『2023北京智源大会』视觉与多模态大模型

『2023北京智源大会』视觉与多模态大模型 文章目录 一. Drag Your GAN: Interactive Point-based Manipulation on the Generative Image Manifold | 潘新钢 | 南洋理工大学1. Image Manipulation(图像编辑)背景2. Drag Your GAN 二. Machine Learning for 3D Content Creatio…

实验篇(7.2) 14. 站对站安全隧道 - 多条隧道负载均衡(上)(FortiGate-IPsec) ❀ 远程访问

【简介】IPsec VPN虽然价廉物美&#xff0c;但是由运营商原因&#xff0c;经常会出访问慢、不稳定甚至断开的情况&#xff0c;好在现在大多数企业都有二条甚至更多条宽带&#xff0c;我们可以创建多条IPsec VPN&#xff0c;来保证正常访问。 实验要求与环境 OldMei集团深圳总部…

友盟分享之新浪微博站(签名apk下载)

适用环境&#xff1a; 1 单独集成新浪微博分享 2 友盟分享新浪微博 集成步骤&#xff1a; 1 注册新浪微博开发者账号 新浪微博开放平台-首页 2 选择要接入的应用类型 根据官网提示输入对应资料&#xff0c;进行申请 4 创建应用的时候&#xff0c;Android需要输入签名&#x…

NFC无源电子墨水屏

NFC电子纸造就无源可视 电子墨水标签 NFCE-paper For NFC Batteryless E-ink Tag 产品参数 产品型号 PN29_S 尺寸(mm) 95*46.4*5.4mm 显示技术 电子墨水屏 显示区域(mm) 29(H) * 66.9(V) 分辨率(像素) 296*128 像素尺寸(mm) 0.227*0.226 显示颜色 黑/白 视…

摩尔定律放缓后,AMD应如何引领自适应的风潮?

编者按&#xff1a;自适应计算如何为核心市场带来动力&#xff1f;近日&#xff0c;在AMD“自适应和嵌入式产品技术日”活动日上&#xff0c;AMD 全球副总裁唐晓蕾表示&#xff0c;创新是驱动发展的引擎&#xff0c;百行百业的数字化与智能化转型离不开创新输送的源源不断的强劲…

【监控】Zabbix:企业级开源监控解决方案

文章目录 一、zabbix的基本概述二、zabbix的构成三、zabbix的监控对象四、zabbix的常用术语五、zabbix的工作流程六、zabbix进程详解七、zabbix的监控框架7.1 三种架构模式的架构图如下&#xff1a;7.2 每个模块的工作职责&#xff1a; 八、zabbix源码安装及部署一、服务端安装…

电子工程师,一起来聊聊PCB板上的Mark点吧

在PCB设计中&#xff0c;电子工程师需要注意很多方面&#xff0c;新手工程师经常会忽略Mark点&#xff0c;但资深工程师们却对Mark点又爱又恨&#xff0c;甚至不得不花时间耗费在Mark点上&#xff0c;为什么Mark点如此重要&#xff1f;该如何设计Mark点&#xff1f; 一、Mark点…

Linux基础IO - 文件系统 | 软硬链接

之前的文章中我们与文件有关的内容谈论的都是被打开的文件&#xff0c;那么如果文件没有被打开呢&#xff1f;这样文件就一定不再内存中&#xff0c;只能在磁盘外设中存储&#xff0c;本文中我们就来讲述磁盘中文件的相关知识。 磁盘的物理存储结构 一个磁盘由多个盘片叠加而…

如何撰写高效且实用的Prompt

很多人说GPT并没有什么让人惊艳的地方&#xff0c;但实际上&#xff0c;他们并没有发挥好它的潜能。在很多情况下&#xff0c;他们往往没有使用恰当的prompt。一个恰到好处的prompt就如同魔法师在施展魔法时所需要吟唱的咒语&#xff0c;只有那些正确无误的咒语&#xff0c;才能…

Zstack实习-基础知识总结归纳-持续更新

什么是虚拟化&#xff1f; 虚拟化技术是一种将物理计算资源&#xff0c;如服务器、存储和网络等&#xff0c;转化成虚拟的逻辑资源的技术。通过虚拟化技术&#xff0c;可以将多个独立的操作系统运行在同一台物理计算机上&#xff0c;实现资源的共享&#xff0c;提高硬件的利用率…