private void createStubEval(
      final ClassGenerator generator, final InvokerDataProvider data, final Map vars) {
    generator
        .setInterfaces(EvalStub.class, CompiledInvoker.class)
        .addField(ACC_PRIVATE + ACC_VOLATILE, "eval", EvalExpression.class);

    generator
        .addMethod(
            ACC_PUBLIC,
            "createContext",
            generator.methodDescr(Object.class),
            new ClassGenerator.MethodBody() {
              public void body(MethodVisitor mv) {
                mv.visitInsn(ACONST_NULL);
                mv.visitInsn(ARETURN);
              }
            })
        .addMethod(
            ACC_PUBLIC,
            "clone",
            generator.methodDescr(EvalExpression.class),
            new ClassGenerator.MethodBody() {
              public void body(MethodVisitor mv) {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitInsn(ARETURN);
              }
            })
        .addMethod(
            ACC_PUBLIC,
            "replaceDeclaration",
            generator.methodDescr(null, Declaration.class, Declaration.class))
        .addMethod(
            ACC_PUBLIC,
            "evaluate",
            generator.methodDescr(
                Boolean.TYPE, Tuple.class, Declaration[].class, WorkingMemory.class, Object.class),
            new String[] {"java/lang/Exception"},
            new ClassGenerator.MethodBody() {
              public void body(MethodVisitor mv) {
                Label syncStart = new Label();
                Label syncEnd = new Label();
                Label l1 = new Label();
                Label l2 = new Label();
                mv.visitTryCatchBlock(syncStart, l1, l2, null);
                Label l3 = new Label();
                mv.visitTryCatchBlock(l2, l3, l2, null);
                getFieldFromThis("eval", EvalExpression.class);
                mv.visitJumpInsn(IFNONNULL, syncEnd);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitInsn(DUP);
                mv.visitVarInsn(ASTORE, 5);
                // synchronized(this) {
                mv.visitInsn(MONITORENTER);
                mv.visitLabel(syncStart);
                getFieldFromThis("eval", EvalExpression.class);
                // if (eval == null) ...
                Label ifNotInitialized = new Label();
                mv.visitJumpInsn(IFNONNULL, ifNotInitialized);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitVarInsn(ALOAD, 2);
                mv.visitVarInsn(ALOAD, 3);
                // ... EvalGenerator.generate(this, tuple, declarations, workingMemory)
                invokeStatic(
                    EvalGenerator.class,
                    "generate",
                    null,
                    EvalStub.class,
                    Tuple.class,
                    Declaration[].class,
                    WorkingMemory.class);
                mv.visitLabel(ifNotInitialized);
                mv.visitVarInsn(ALOAD, 5);
                mv.visitInsn(MONITOREXIT);
                mv.visitLabel(l1);
                mv.visitJumpInsn(GOTO, syncEnd);
                mv.visitLabel(l2);
                mv.visitVarInsn(ASTORE, 6);
                mv.visitVarInsn(ALOAD, 5);
                mv.visitInsn(MONITOREXIT);
                mv.visitLabel(l3);
                mv.visitVarInsn(ALOAD, 6);
                mv.visitInsn(ATHROW);
                mv.visitLabel(syncEnd);
                // } end of synchronized
                getFieldFromThis("eval", EvalExpression.class);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitVarInsn(ALOAD, 2);
                mv.visitVarInsn(ALOAD, 3);
                mv.visitVarInsn(ALOAD, 4);
                invokeInterface(
                    EvalExpression.class,
                    "evaluate",
                    Boolean.TYPE,
                    Tuple.class,
                    Declaration[].class,
                    WorkingMemory.class,
                    Object.class);
                mv.visitInsn(IRETURN);
              }
            })
        .addMethod(
            ACC_PUBLIC,
            "setEval",
            generator.methodDescr(null, EvalExpression.class),
            new ClassGenerator.MethodBody() {
              public void body(MethodVisitor mv) {
                putFieldInThisFromRegistry("eval", EvalExpression.class, 1);
                mv.visitInsn(RETURN);
              }
            });
  }
 protected byte[] createEvalBytecode(final RuleBuildContext ruleContext, final Map vars) {
   final InvokerDataProvider data = new InvokerContext(vars);
   final ClassGenerator generator = InvokerGenerator.createInvokerStubGenerator(data, ruleContext);
   createStubEval(generator, data, vars);
   return generator.generateBytecode();
 }