Пример #1
0
 public void positionStmtsAfterEnumInitStmts(List<Statement> staticFieldStatements) {
   MethodNode method = getOrAddStaticConstructorNode();
   Statement statement = method.getCode();
   if (statement instanceof BlockStatement) {
     BlockStatement block = (BlockStatement) statement;
     // add given statements for explicitly declared static fields just after enum-special fields
     // are found - the $VALUES binary expression marks the end of such fields.
     List<Statement> blockStatements = block.getStatements();
     ListIterator<Statement> litr = blockStatements.listIterator();
     while (litr.hasNext()) {
       Statement stmt = litr.next();
       if (stmt instanceof ExpressionStatement
           && ((ExpressionStatement) stmt).getExpression() instanceof BinaryExpression) {
         BinaryExpression bExp = (BinaryExpression) ((ExpressionStatement) stmt).getExpression();
         if (bExp.getLeftExpression() instanceof FieldExpression) {
           FieldExpression fExp = (FieldExpression) bExp.getLeftExpression();
           if (fExp.getFieldName().equals("$VALUES")) {
             for (Statement tmpStmt : staticFieldStatements) {
               litr.add(tmpStmt);
             }
           }
         }
       }
     }
   }
 }
Пример #2
0
  public void addStaticInitializerStatements(List<Statement> staticStatements, boolean fieldInit) {
    MethodNode method = getOrAddStaticConstructorNode();
    BlockStatement block = null;
    Statement statement = method.getCode();
    if (statement == null) {
      block = new BlockStatement();
    } else if (statement instanceof BlockStatement) {
      block = (BlockStatement) statement;
    } else {
      block = new BlockStatement();
      block.addStatement(statement);
    }

    // while anything inside a static initializer block is appended
    // we don't want to append in the case we have a initialization
    // expression of a static field. In that case we want to add
    // before the other statements
    if (!fieldInit) {
      block.addStatements(staticStatements);
    } else {
      List<Statement> blockStatements = block.getStatements();
      staticStatements.addAll(blockStatements);
      blockStatements.clear();
      blockStatements.addAll(staticStatements);
    }
  }
Пример #3
0
  public Map<String, MethodNode> getDeclaredMethodsMap() {
    // Start off with the methods from the superclass.
    ClassNode parent = getSuperClass();
    Map<String, MethodNode> result = null;
    if (parent != null) {
      result = parent.getDeclaredMethodsMap();
    } else {
      result = new HashMap<String, MethodNode>();
    }

    // add in unimplemented abstract methods from the interfaces
    for (ClassNode iface : getInterfaces()) {
      Map<String, MethodNode> ifaceMethodsMap = iface.getDeclaredMethodsMap();
      for (String methSig : ifaceMethodsMap.keySet()) {
        if (!result.containsKey(methSig)) {
          MethodNode methNode = ifaceMethodsMap.get(methSig);
          result.put(methSig, methNode);
        }
      }
    }

    // And add in the methods implemented in this class.
    for (MethodNode method : getMethods()) {
      String sig = method.getTypeDescriptor();
      result.put(sig, method);
    }
    return result;
  }
Пример #4
0
 /**
  * Finds a method matching the given name and parameters in this class or any parent class.
  *
  * @return the method matching the given name and parameters or null
  */
 public MethodNode getMethod(String name, Parameter[] parameters) {
   for (MethodNode method : getMethods(name)) {
     if (parametersEqual(method.getParameters(), parameters)) {
       return method;
     }
   }
   return null;
 }
Пример #5
0
 public void addMethod(MethodNode node) {
   node.setDeclaringClass(this);
   ClassNode base = redirect();
   if (base.methodsList.isEmpty()) {
     base.methodsList = new ArrayList<MethodNode>();
   }
   base.methodsList.add(node);
   base.methods.put(node.getName(), node);
 }
 private void memorizeInitialExpressions(final MethodNode node) {
   // add node metadata for default parameters because they are erased by the Verifier
   if (node.getParameters() != null) {
     for (Parameter parameter : node.getParameters()) {
       parameter.putNodeMetaData(
           StaticTypesMarker.INITIAL_EXPRESSION, parameter.getInitialExpression());
     }
   }
 }
  /**
   * This method is used to add "bridge" methods for private methods of an inner/outer class, so
   * that the outer class is capable of calling them. It does basically the same job as access$000
   * like methods in Java.
   *
   * @param node an inner/outer class node for which to generate bridge methods
   */
  @SuppressWarnings("unchecked")
  private void addPrivateBridgeMethods(final ClassNode node) {
    Set<ASTNode> accessedMethods =
        (Set<ASTNode>) node.getNodeMetaData(StaticTypesMarker.PV_METHODS_ACCESS);
    if (accessedMethods == null) return;
    List<MethodNode> methods = new ArrayList<MethodNode>(node.getAllDeclaredMethods());
    Map<MethodNode, MethodNode> privateBridgeMethods =
        (Map<MethodNode, MethodNode>) node.getNodeMetaData(PRIVATE_BRIDGE_METHODS);
    if (privateBridgeMethods != null) {
      // private bridge methods already added
      return;
    }
    privateBridgeMethods = new HashMap<MethodNode, MethodNode>();
    int i = -1;
    final int access = Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC;
    for (MethodNode method : methods) {
      if (accessedMethods.contains(method)) {
        i++;
        Parameter[] methodParameters = method.getParameters();
        Parameter[] newParams = new Parameter[methodParameters.length + 1];
        System.arraycopy(methodParameters, 0, newParams, 1, methodParameters.length);
        newParams[0] = new Parameter(node.getPlainNodeReference(), "$that");
        Expression arguments;
        if (method.getParameters() == null || method.getParameters().length == 0) {
          arguments = ArgumentListExpression.EMPTY_ARGUMENTS;
        } else {
          List<Expression> args = new LinkedList<Expression>();
          for (Parameter parameter : methodParameters) {
            args.add(new VariableExpression(parameter));
          }
          arguments = new ArgumentListExpression(args);
        }
        Expression receiver =
            method.isStatic() ? new ClassExpression(node) : new VariableExpression(newParams[0]);
        MethodCallExpression mce = new MethodCallExpression(receiver, method.getName(), arguments);
        mce.setMethodTarget(method);

        ExpressionStatement returnStatement = new ExpressionStatement(mce);
        MethodNode bridge =
            node.addMethod(
                "access$" + i,
                access,
                method.getReturnType(),
                newParams,
                method.getExceptions(),
                returnStatement);
        privateBridgeMethods.put(method, bridge);
        bridge.addAnnotation(new AnnotationNode(COMPILESTATIC_CLASSNODE));
      }
    }
    if (!privateBridgeMethods.isEmpty()) {
      node.setNodeMetaData(PRIVATE_BRIDGE_METHODS, privateBridgeMethods);
    }
  }
Пример #8
0
 /** Adds a synthetic method as part of the compilation process */
 public MethodNode addSyntheticMethod(
     String name,
     int modifiers,
     ClassNode returnType,
     Parameter[] parameters,
     ClassNode[] exceptions,
     Statement code) {
   MethodNode answer =
       addMethod(name, modifiers | ACC_SYNTHETIC, returnType, parameters, exceptions, code);
   answer.setSynthetic(true);
   return answer;
 }
 /**
  * Tests whether the ClassNode implements the specified method name
  *
  * @param classNode The ClassNode
  * @param methodName The method name
  * @param argTypes
  * @return True if it implements the method
  */
 private static boolean implementsMethod(
     ClassNode classNode, String methodName, Class[] argTypes) {
   List methods = classNode.getMethods();
   for (Iterator i = methods.iterator(); i.hasNext(); ) {
     MethodNode mn = (MethodNode) i.next();
     final boolean isZeroArg = (argTypes == null || argTypes.length == 0);
     boolean methodMatch = mn.getName().equals(methodName) && isZeroArg;
     if (methodMatch) return true;
     // TODO Implement further parameter analysis
   }
   return false;
 }
Пример #10
0
 public MethodNode getGetterMethod(String getterName) {
   for (MethodNode method : getDeclaredMethods(getterName)) {
     if (getterName.equals(method.getName())
         && ClassHelper.VOID_TYPE != method.getReturnType()
         && method.getParameters().length == 0) {
       return method;
     }
   }
   ClassNode parent = getSuperClass();
   if (parent != null) return parent.getGetterMethod(getterName);
   return null;
 }
Пример #11
0
 public MethodNode getSetterMethod(String setterName, boolean voidOnly) {
   for (MethodNode method : getDeclaredMethods(setterName)) {
     if (setterName.equals(method.getName())
         && (!voidOnly || ClassHelper.VOID_TYPE == method.getReturnType())
         && method.getParameters().length == 1) {
       return method;
     }
   }
   ClassNode parent = getSuperClass();
   if (parent != null) return parent.getSetterMethod(setterName, voidOnly);
   return null;
 }
Пример #12
0
  /**
   * @return the list of abstract methods associated with this ClassNode or null if there are no
   *     such methods
   */
  public List<MethodNode> getAbstractMethods() {
    List<MethodNode> result = new ArrayList<MethodNode>(3);
    for (MethodNode method : getDeclaredMethodsMap().values()) {
      if (method.isAbstract()) {
        result.add(method);
      }
    }

    if (result.isEmpty()) {
      return null;
    } else {
      return result;
    }
  }
Пример #13
0
 public void removeMethod(MethodNode node) {
   ClassNode base = redirect();
   if (!base.methodsList.isEmpty()) {
     base.methodsList.remove(node);
   }
   base.methods.remove(node.getName(), node);
 }
 @Override
 public void visitMethod(final MethodNode node) {
   if (isSkipMode(node)) {
     node.putNodeMetaData(STATIC_COMPILE_NODE, false);
   }
   super.visitMethod(node);
   checkForConstructorWithCSButClassWithout(node);
 }
Пример #15
0
 private MethodNode getOrAddStaticConstructorNode() {
   MethodNode method = null;
   List declaredMethods = getDeclaredMethods("<clinit>");
   if (declaredMethods.isEmpty()) {
     method =
         addMethod(
             "<clinit>",
             ACC_STATIC,
             ClassHelper.VOID_TYPE,
             Parameter.EMPTY_ARRAY,
             ClassNode.EMPTY_ARRAY,
             new BlockStatement());
     method.setSynthetic(true);
   } else {
     method = (MethodNode) declaredMethods.get(0);
   }
   return method;
 }
Пример #16
0
  /**
   * Returns true if the given method has a possibly matching instance method with the given name
   * and arguments.
   *
   * @param name the name of the method of interest
   * @param arguments the arguments to match against
   * @return true if a matching method was found
   */
  public boolean hasPossibleMethod(String name, Expression arguments) {
    int count = 0;

    if (arguments instanceof TupleExpression) {
      TupleExpression tuple = (TupleExpression) arguments;
      // TODO this won't strictly be true when using list expansion in argument calls
      count = tuple.getExpressions().size();
    }
    ClassNode node = this;
    do {
      for (MethodNode method : getMethods(name)) {
        if (method.getParameters().length == count && !method.isStatic()) {
          return true;
        }
      }
      node = node.getSuperClass();
    } while (node != null);
    return false;
  }
  private void replaceObfuscatedMethodNames(AsmagicDiffVisitor dv) {
    for (MethodNode mn : dv.newMethods) {
      if (mn.visibleAnnotations != null) {
        for (Object oan : mn.visibleAnnotations) {
          AnnotationNode an = (AnnotationNode) oan;
          if (an.desc.contains("AsmagicMethodReplace")) {
            List<Object> vals = an.values;

            String alias = null;
            if (vals != null || vals.size() > 1) {
              alias = (String) vals.get(1);
              dv.methodsToReplace.put(alias, 1);
              mn.name = alias;
            }
          }
        }
      }
    }
  }
Пример #18
0
  public InlineResult doInline(
      @NotNull MethodVisitor adapter,
      @NotNull LocalVarRemapper remapper,
      boolean remapReturn,
      @NotNull LabelOwner labelOwner) {
    // analyze body
    MethodNode transformedNode = markPlacesForInlineAndRemoveInlinable(node);

    // substitute returns with "goto end" instruction to keep non local returns in lambdas
    Label end = new Label();
    transformedNode = doInline(transformedNode);
    removeClosureAssertions(transformedNode);
    InsnList instructions = transformedNode.instructions;
    instructions.resetLabels();

    MethodNode resultNode =
        new MethodNode(
            InlineCodegenUtil.API,
            transformedNode.access,
            transformedNode.name,
            transformedNode.desc,
            transformedNode.signature,
            ArrayUtil.toStringArray(transformedNode.exceptions));
    RemapVisitor visitor = new RemapVisitor(resultNode, remapper, nodeRemapper);
    try {
      transformedNode.accept(visitor);
    } catch (Exception e) {
      throw wrapException(e, transformedNode, "couldn't inline method call");
    }

    resultNode.visitLabel(end);

    if (inliningContext.isRoot()) {
      InternalFinallyBlockInliner.processInlineFunFinallyBlocks(resultNode, lambdasFinallyBlocks);
    }

    processReturns(resultNode, labelOwner, remapReturn, end);
    // flush transformed node to output
    resultNode.accept(new InliningInstructionAdapter(adapter));

    return result;
  }
 @SuppressWarnings("unchecked")
 private boolean makeGetPrivateFieldWithBridgeMethod(
     final Expression receiver,
     final ClassNode receiverType,
     final String fieldName,
     final boolean safe,
     final boolean implicitThis) {
   FieldNode field = receiverType.getField(fieldName);
   ClassNode classNode = controller.getClassNode();
   if (field != null
       && Modifier.isPrivate(field.getModifiers())
       && (StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(receiverType, classNode)
           || StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(classNode, receiverType))
       && !receiverType.equals(classNode)) {
     Map<String, MethodNode> accessors =
         (Map<String, MethodNode>)
             receiverType
                 .redirect()
                 .getNodeMetaData(StaticCompilationMetadataKeys.PRIVATE_FIELDS_ACCESSORS);
     if (accessors != null) {
       MethodNode methodNode = accessors.get(fieldName);
       if (methodNode != null) {
         MethodCallExpression mce =
             new MethodCallExpression(
                 receiver,
                 methodNode.getName(),
                 new ArgumentListExpression(
                     field.isStatic() ? new ConstantExpression(null) : receiver));
         mce.setMethodTarget(methodNode);
         mce.setSafe(safe);
         mce.setImplicitThis(implicitThis);
         mce.visit(controller.getAcg());
         return true;
       }
     }
   }
   return false;
 }
Пример #20
0
  private static void showDocument(Document doc) {
    StringBuffer content = new StringBuffer();
    Node node = doc.getChildNodes().item(0);
    ApplicationNode appNode = new ApplicationNode(node);

    content.append("Application \n");

    List<ClassNode> classes = appNode.getClasses();

    for (int i = 0; i < classes.size(); i++) {
      ClassNode classNode = classes.get(i);
      content.append(SPACE + "Class: " + classNode.getName() + " \n");

      List<MethodNode> methods = classNode.getMethods();

      for (int j = 0; j < methods.size(); j++) {
        MethodNode methodNode = methods.get(j);
        content.append(SPACE + SPACE + "Method: " + methodNode.getName() + " \n");
      }
    }

    System.out.println(content.toString());
  }
Пример #21
0
  /**
   * Returns true if the given method has a possibly matching static method with the given name and
   * arguments.
   *
   * @param name the name of the method of interest
   * @param arguments the arguments to match against
   * @return true if a matching method was found
   */
  public boolean hasPossibleStaticMethod(String name, Expression arguments) {
    int count = 0;

    if (arguments instanceof TupleExpression) {
      TupleExpression tuple = (TupleExpression) arguments;
      // TODO this won't strictly be true when using list expansion in argument calls
      count = tuple.getExpressions().size();
    } else if (arguments instanceof MapExpression) {
      count = 1;
    }

    for (MethodNode method : getMethods(name)) {
      if (method.isStatic()) {
        Parameter[] parameters = method.getParameters();
        if (parameters.length == count) return true;

        // handle varargs case
        if (parameters.length > 0 && parameters[parameters.length - 1].getType().isArray()) {
          if (count >= parameters.length - 1) return true;
        }

        // handle parameters with default values
        int nonDefaultParameters = 0;
        for (Parameter parameter : parameters) {
          if (!parameter.hasInitialExpression()) {
            nonDefaultParameters++;
          }
        }

        if (count < parameters.length && nonDefaultParameters <= count) {
          return true;
        }
      }
    }
    return false;
  }
  /**
   * If we are in a constructor, that is static compiled, but in a class, that is not, it may happen
   * that init code from object initializers, fields or properties is added into the constructor
   * code. The backend assumes a purely static contructor, so it may fail if it encounters dynamic
   * code here. Thus we make this kind of code fail
   */
  private void checkForConstructorWithCSButClassWithout(MethodNode node) {
    if (!(node instanceof ConstructorNode)) return;
    Object meta = node.getNodeMetaData(STATIC_COMPILE_NODE);
    if (!Boolean.TRUE.equals(meta)) return;
    ClassNode clz = typeCheckingContext.getEnclosingClassNode();
    meta = clz.getNodeMetaData(STATIC_COMPILE_NODE);
    if (Boolean.TRUE.equals(meta)) return;
    if (clz.getObjectInitializerStatements().isEmpty()
        && clz.getFields().isEmpty()
        && clz.getProperties().isEmpty()) {
      return;
    }

    addStaticTypeError(
        "Cannot statically compile constructor implicitly including non static elements from object initializers, properties or fields.",
        node);
  }
Пример #23
0
  public MethodNode tryFindPossibleMethod(String name, Expression arguments) {
    int count = 0;

    if (arguments instanceof TupleExpression) {
      TupleExpression tuple = (TupleExpression) arguments;
      // TODO this won't strictly be true when using list expansion in argument calls
      count = tuple.getExpressions().size();
    } else return null;

    MethodNode res = null;
    ClassNode node = this;
    TupleExpression args = (TupleExpression) arguments;
    do {
      for (MethodNode method : node.getMethods(name)) {
        if (method.getParameters().length == count) {
          boolean match = true;
          for (int i = 0; i != count; ++i)
            if (!args.getType().isDerivedFrom(method.getParameters()[i].getType())) {
              match = false;
              break;
            }

          if (match) {
            if (res == null) res = method;
            else {
              if (res.getParameters().length != count) return null;
              if (node.equals(this)) return null;

              match = true;
              for (int i = 0; i != count; ++i)
                if (!res.getParameters()[i].getType().equals(method.getParameters()[i].getType())) {
                  match = false;
                  break;
                }
              if (!match) return null;
            }
          }
        }
      }
      node = node.getSuperClass();
    } while (node != null);

    return res;
  }
  protected Expression transformPropertyExpression(PropertyExpression pe) {
    if (currentMethod != null
        && currentMethod.isStatic()
        && pe.getObjectExpression() instanceof VariableExpression
        && ((VariableExpression) pe.getObjectExpression()).isSuperExpression()) {
      PropertyExpression pexp =
          new PropertyExpression(
              new ClassExpression(currentClass.getSuperClass()), transform(pe.getProperty()));
      pexp.setSourcePosition(pe);
      return pexp;
    }
    boolean oldInPropertyExpression = inPropertyExpression;
    Expression oldFoundArgs = foundArgs;
    Expression oldFoundConstant = foundConstant;
    inPropertyExpression = true;
    foundArgs = null;
    foundConstant = null;
    Expression objectExpression = transform(pe.getObjectExpression());
    boolean candidate = false;
    if (objectExpression instanceof MethodCallExpression) {
      candidate = ((MethodCallExpression) objectExpression).isImplicitThis();
    }

    if (foundArgs != null && foundConstant != null && candidate) {
      Expression result = findStaticMethodImportFromModule(foundConstant, foundArgs);
      if (result != null) {
        objectExpression = result;
        objectExpression.setSourcePosition(pe);
      }
    }
    inPropertyExpression = oldInPropertyExpression;
    foundArgs = oldFoundArgs;
    foundConstant = oldFoundConstant;
    pe.setObjectExpression(objectExpression);
    return pe;
  }
Пример #25
0
  @NotNull
  public MethodNode prepareNode(@NotNull MethodNode node) {
    final int capturedParamsSize = parameters.getCaptured().size();
    final int realParametersSize = parameters.getReal().size();
    Type[] types = Type.getArgumentTypes(node.desc);
    Type returnType = Type.getReturnType(node.desc);

    ArrayList<Type> capturedTypes = parameters.getCapturedTypes();
    Type[] allTypes =
        ArrayUtil.mergeArrays(types, capturedTypes.toArray(new Type[capturedTypes.size()]));

    node.instructions.resetLabels();
    MethodNode transformedNode =
        new MethodNode(
            InlineCodegenUtil.API,
            node.access,
            node.name,
            Type.getMethodDescriptor(returnType, allTypes),
            node.signature,
            null) {

          private final boolean isInliningLambda = nodeRemapper.isInsideInliningLambda();

          private int getNewIndex(int var) {
            return var + (var < realParametersSize ? 0 : capturedParamsSize);
          }

          @Override
          public void visitVarInsn(int opcode, int var) {
            super.visitVarInsn(opcode, getNewIndex(var));
          }

          @Override
          public void visitIincInsn(int var, int increment) {
            super.visitIincInsn(getNewIndex(var), increment);
          }

          @Override
          public void visitMaxs(int maxStack, int maxLocals) {
            super.visitMaxs(maxStack, maxLocals + capturedParamsSize);
          }

          @Override
          public void visitLineNumber(int line, @NotNull Label start) {
            if (isInliningLambda) {
              super.visitLineNumber(line, start);
            }
          }

          @Override
          public void visitLocalVariable(
              @NotNull String name,
              @NotNull String desc,
              String signature,
              @NotNull Label start,
              @NotNull Label end,
              int index) {
            if (isInliningLambda) {
              super.visitLocalVariable(name, desc, signature, start, end, getNewIndex(index));
            }
          }
        };

    node.accept(transformedNode);

    transformCaptured(transformedNode);

    return transformedNode;
  }
Пример #26
0
  private MethodNode doInline(MethodNode node) {

    final Deque<InvokeCall> currentInvokes = new LinkedList<InvokeCall>(invokeCalls);

    final MethodNode resultNode =
        new MethodNode(node.access, node.name, node.desc, node.signature, null);

    final Iterator<AnonymousObjectGeneration> iterator = anonymousObjectGenerations.iterator();

    RemappingMethodAdapter remappingMethodAdapter =
        new RemappingMethodAdapter(
            resultNode.access, resultNode.desc, resultNode, new TypeRemapper(currentTypeMapping));

    InlineAdapter lambdaInliner =
        new InlineAdapter(remappingMethodAdapter, parameters.totalSize()) {

          private AnonymousObjectGeneration anonymousObjectGen;

          private void handleAnonymousObjectGeneration() {
            anonymousObjectGen = iterator.next();

            if (anonymousObjectGen.shouldRegenerate()) {
              // TODO: need poping of type but what to do with local funs???
              Type newLambdaType =
                  Type.getObjectType(inliningContext.nameGenerator.genLambdaClassName());
              currentTypeMapping.put(
                  anonymousObjectGen.getOwnerInternalName(), newLambdaType.getInternalName());
              AnonymousObjectTransformer transformer =
                  new AnonymousObjectTransformer(
                      anonymousObjectGen.getOwnerInternalName(),
                      inliningContext.subInlineWithClassRegeneration(
                          inliningContext.nameGenerator, currentTypeMapping, anonymousObjectGen),
                      isSameModule,
                      newLambdaType);

              InlineResult transformResult =
                  transformer.doTransform(anonymousObjectGen, nodeRemapper);
              result.addAllClassesToRemove(transformResult);

              if (inliningContext.isInliningLambda && !anonymousObjectGen.isStaticOrigin()) {
                // this class is transformed and original not used so we should remove original one
                // after inlining
                // Note: It is unsafe to remove anonymous class that is referenced by GETSTATIC
                // within lambda
                // because it can be local function from outer scope
                result.addClassToRemove(anonymousObjectGen.getOwnerInternalName());
              }

              if (transformResult.getReifiedTypeParametersUsages().wereUsedReifiedParameters()) {
                ReifiedTypeInliner.putNeedClassReificationMarker(mv);
                result
                    .getReifiedTypeParametersUsages()
                    .mergeAll(transformResult.getReifiedTypeParametersUsages());
              }
            }
          }

          @Override
          public void anew(@NotNull Type type) {
            if (isAnonymousConstructorCall(type.getInternalName(), "<init>")) {
              handleAnonymousObjectGeneration();
            }

            // in case of regenerated anonymousObjectGen type would be remapped to new one via
            // remappingMethodAdapter
            super.anew(type);
          }

          @Override
          public void visitMethodInsn(
              int opcode, String owner, String name, String desc, boolean itf) {
            if (
            /*INLINE_RUNTIME.equals(owner) &&*/ isInvokeOnLambda(owner, name)) { // TODO add method
              assert !currentInvokes.isEmpty();
              InvokeCall invokeCall = currentInvokes.remove();
              LambdaInfo info = invokeCall.lambdaInfo;

              if (info == null) {
                // noninlinable lambda
                super.visitMethodInsn(opcode, owner, name, desc, itf);
                return;
              }

              int valueParamShift = getNextLocalIndex(); // NB: don't inline cause it changes
              putStackValuesIntoLocals(
                  info.getInvokeParamsWithoutCaptured(), valueParamShift, this, desc);

              addInlineMarker(this, true);
              Parameters lambdaParameters = info.addAllParameters(nodeRemapper);

              InlinedLambdaRemapper newCapturedRemapper =
                  new InlinedLambdaRemapper(
                      info.getLambdaClassType().getInternalName(), nodeRemapper, lambdaParameters);

              setLambdaInlining(true);
              MethodInliner inliner =
                  new MethodInliner(
                      info.getNode(),
                      lambdaParameters,
                      inliningContext.subInlineLambda(info),
                      newCapturedRemapper,
                      true /*cause all calls in same module as lambda*/,
                      "Lambda inlining " + info.getLambdaClassType().getInternalName());

              LocalVarRemapper remapper = new LocalVarRemapper(lambdaParameters, valueParamShift);
              InlineResult lambdaResult =
                  inliner.doInline(
                      this.mv, remapper, true, info); // TODO add skipped this and receiver
              result.addAllClassesToRemove(lambdaResult);

              // return value boxing/unboxing
              Method bridge =
                  typeMapper
                      .mapSignature(
                          ClosureCodegen.getErasedInvokeFunction(info.getFunctionDescriptor()))
                      .getAsmMethod();
              Method delegate =
                  typeMapper.mapSignature(info.getFunctionDescriptor()).getAsmMethod();
              StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this);
              setLambdaInlining(false);
              addInlineMarker(this, false);
            } else if (isAnonymousConstructorCall(owner, name)) { // TODO add method
              assert anonymousObjectGen != null
                  : "<init> call not corresponds to new call" + owner + " " + name;
              if (anonymousObjectGen.shouldRegenerate()) {
                // put additional captured parameters on stack
                for (CapturedParamDesc capturedParamDesc :
                    anonymousObjectGen.getAllRecapturedParameters()) {
                  visitFieldInsn(
                      Opcodes.GETSTATIC,
                      capturedParamDesc.getContainingLambdaName(),
                      "$$$" + capturedParamDesc.getFieldName(),
                      capturedParamDesc.getType().getDescriptor());
                }
                super.visitMethodInsn(
                    opcode,
                    anonymousObjectGen.getNewLambdaType().getInternalName(),
                    name,
                    anonymousObjectGen.getNewConstructorDescriptor(),
                    itf);
                anonymousObjectGen = null;
              } else {
                super.visitMethodInsn(
                    opcode, changeOwnerForExternalPackage(owner, opcode), name, desc, itf);
              }
            } else if (ReifiedTypeInliner.isNeedClassReificationMarker(
                new MethodInsnNode(opcode, owner, name, desc, false))) {
              // we will put it if needed in anew processing
            } else {
              super.visitMethodInsn(
                  opcode, changeOwnerForExternalPackage(owner, opcode), name, desc, itf);
            }
          }

          @Override
          public void visitFieldInsn(
              int opcode, @NotNull String owner, @NotNull String name, @NotNull String desc) {
            if (opcode == Opcodes.GETSTATIC && isAnonymousSingletonLoad(owner, name)) {
              handleAnonymousObjectGeneration();
            }
            super.visitFieldInsn(opcode, owner, name, desc);
          }

          @Override
          public void visitMaxs(int stack, int locals) {
            lambdasFinallyBlocks = resultNode.tryCatchBlocks.size();
            super.visitMaxs(stack, locals);
          }
        };

    node.accept(lambdaInliner);

    return resultNode;
  }
  @Override
  public void makeGetPropertySite(
      Expression receiver,
      final String methodName,
      final boolean safe,
      final boolean implicitThis) {
    Object dynamic =
        receiver.getNodeMetaData(StaticCompilationMetadataKeys.RECEIVER_OF_DYNAMIC_PROPERTY);
    if (dynamic != null) {
      MethodNode target =
          safe ? INVOKERHELPER_GETPROPERTYSAFE_METHOD : INVOKERHELPER_GETPROPERTY_METHOD;
      MethodCallExpression mce =
          new MethodCallExpression(
              new ClassExpression(INVOKERHELPER_TYPE),
              target.getName(),
              new ArgumentListExpression(receiver, new ConstantExpression(methodName)));
      mce.setSafe(false);
      mce.setImplicitThis(false);
      mce.setMethodTarget(target);
      mce.visit(controller.getAcg());
      return;
    }
    TypeChooser typeChooser = controller.getTypeChooser();
    ClassNode classNode = controller.getClassNode();
    ClassNode receiverType =
        (ClassNode) receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
    if (receiverType == null) {
      receiverType = typeChooser.resolveType(receiver, classNode);
    }
    Object type = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
    if (type == null && receiver instanceof VariableExpression) {
      Variable variable = ((VariableExpression) receiver).getAccessedVariable();
      if (variable instanceof Expression) {
        type = ((Expression) variable).getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
      }
    }
    if (type != null) {
      // in case a "flow type" is found, it is preferred to use it instead of
      // the declaration type
      receiverType = (ClassNode) type;
    }
    boolean isClassReceiver = false;
    if (isClassClassNodeWrappingConcreteType(receiverType)) {
      isClassReceiver = true;
      receiverType = receiverType.getGenericsTypes()[0].getType();
    }
    MethodVisitor mv = controller.getMethodVisitor();

    if (receiverType.isArray() && methodName.equals("length")) {
      receiver.visit(controller.getAcg());
      ClassNode arrayGetReturnType = typeChooser.resolveType(receiver, classNode);
      controller.getOperandStack().doGroovyCast(arrayGetReturnType);
      mv.visitInsn(ARRAYLENGTH);
      controller.getOperandStack().replace(int_TYPE);
      return;
    } else if ((receiverType.implementsInterface(COLLECTION_TYPE)
            || COLLECTION_TYPE.equals(receiverType))
        && ("size".equals(methodName) || "length".equals(methodName))) {
      MethodCallExpression expr =
          new MethodCallExpression(receiver, "size", ArgumentListExpression.EMPTY_ARGUMENTS);
      expr.setMethodTarget(COLLECTION_SIZE_METHOD);
      expr.setImplicitThis(implicitThis);
      expr.setSafe(safe);
      expr.visit(controller.getAcg());
      return;
    }
    if (makeGetPropertyWithGetter(receiver, receiverType, methodName, safe, implicitThis)) return;
    if (makeGetField(
        receiver,
        receiverType,
        methodName,
        implicitThis,
        samePackages(receiverType.getPackageName(), classNode.getPackageName()))) return;
    if (receiverType.isEnum()) {
      mv.visitFieldInsn(
          GETSTATIC,
          BytecodeHelper.getClassInternalName(receiverType),
          methodName,
          BytecodeHelper.getTypeDescription(receiverType));
      controller.getOperandStack().push(receiverType);
      return;
    }
    if (receiver instanceof ClassExpression) {
      if (makeGetField(
          receiver,
          receiver.getType(),
          methodName,
          implicitThis,
          samePackages(receiver.getType().getPackageName(), classNode.getPackageName()))) return;
      if (makeGetPropertyWithGetter(receiver, receiver.getType(), methodName, safe, implicitThis))
        return;
      if (makeGetPrivateFieldWithBridgeMethod(
          receiver, receiver.getType(), methodName, safe, implicitThis)) return;
    }
    if (isClassReceiver) {
      // we are probably looking for a property of the class
      if (makeGetPropertyWithGetter(receiver, CLASS_Type, methodName, safe, implicitThis)) return;
      if (makeGetField(receiver, CLASS_Type, methodName, false, true)) return;
    }
    if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, methodName, safe, implicitThis))
      return;

    // GROOVY-5580, it is still possible that we're calling a superinterface property
    String getterName = "get" + MetaClassHelper.capitalize(methodName);
    if (receiverType.isInterface()) {
      Set<ClassNode> allInterfaces = receiverType.getAllInterfaces();
      MethodNode getterMethod = null;
      for (ClassNode anInterface : allInterfaces) {
        getterMethod = anInterface.getGetterMethod(getterName);
        if (getterMethod != null) break;
      }
      // GROOVY-5585
      if (getterMethod == null) {
        getterMethod = OBJECT_TYPE.getGetterMethod(getterName);
      }

      if (getterMethod != null) {
        MethodCallExpression call =
            new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
        call.setMethodTarget(getterMethod);
        call.setImplicitThis(false);
        call.setSourcePosition(receiver);
        call.visit(controller.getAcg());
        return;
      }
    }

    // GROOVY-5568, we would be facing a DGM call, but instead of foo.getText(), have foo.text
    List<MethodNode> methods =
        findDGMMethodsByNameAndArguments(
            controller.getSourceUnit().getClassLoader(),
            receiverType,
            getterName,
            ClassNode.EMPTY_ARRAY);
    if (!methods.isEmpty()) {
      List<MethodNode> methodNodes = chooseBestMethod(receiverType, methods, ClassNode.EMPTY_ARRAY);
      if (methodNodes.size() == 1) {
        MethodNode getter = methodNodes.get(0);
        MethodCallExpression call =
            new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
        call.setMethodTarget(getter);
        call.setImplicitThis(false);
        call.setSourcePosition(receiver);
        call.visit(controller.getAcg());
        return;
      }
    }

    boolean isStaticProperty =
        receiver instanceof ClassExpression
            && (receiverType.isDerivedFrom(receiver.getType())
                || receiverType.implementsInterface(receiver.getType()));

    if (!isStaticProperty) {
      if (receiverType.implementsInterface(MAP_TYPE) || MAP_TYPE.equals(receiverType)) {
        // for maps, replace map.foo with map.get('foo')
        writeMapDotProperty(receiver, methodName, mv, safe);
        return;
      }
      if (receiverType.implementsInterface(LIST_TYPE) || LIST_TYPE.equals(receiverType)) {
        writeListDotProperty(receiver, methodName, mv, safe);
        return;
      }
    }

    controller
        .getSourceUnit()
        .addError(
            new SyntaxException(
                "Access to "
                    + (receiver instanceof ClassExpression ? receiver.getType() : receiverType)
                        .toString(false)
                    + "#"
                    + methodName
                    + " is forbidden",
                receiver.getLineNumber(),
                receiver.getColumnNumber(),
                receiver.getLastLineNumber(),
                receiver.getLastColumnNumber()));
    controller.getMethodVisitor().visitInsn(ACONST_NULL);
    controller.getOperandStack().push(OBJECT_TYPE);
  }
  private boolean makeGetPropertyWithGetter(
      final Expression receiver,
      final ClassNode receiverType,
      final String methodName,
      final boolean safe,
      final boolean implicitThis) {
    // does a getter exists ?
    String getterName = "get" + MetaClassHelper.capitalize(methodName);
    MethodNode getterNode = receiverType.getGetterMethod(getterName);
    if (getterNode == null) {
      getterName = "is" + MetaClassHelper.capitalize(methodName);
      getterNode = receiverType.getGetterMethod(getterName);
    }
    if (getterNode != null
        && receiver instanceof ClassExpression
        && !CLASS_Type.equals(receiverType)
        && !getterNode.isStatic()) {
      return false;
    }

    // GROOVY-5561: if two files are compiled in the same source unit
    // and that one references the other, the getters for properties have not been
    // generated by the compiler yet (generated by the Verifier)
    PropertyNode propertyNode = receiverType.getProperty(methodName);
    if (propertyNode != null) {
      // it is possible to use a getter
      String prefix = "get";
      if (boolean_TYPE.equals(propertyNode.getOriginType())) {
        prefix = "is";
      }
      getterName = prefix + MetaClassHelper.capitalize(methodName);
      getterNode =
          new MethodNode(
              getterName,
              ACC_PUBLIC,
              propertyNode.getOriginType(),
              Parameter.EMPTY_ARRAY,
              ClassNode.EMPTY_ARRAY,
              EmptyStatement.INSTANCE);
      getterNode.setDeclaringClass(receiverType);
      if (propertyNode.isStatic()) getterNode.setModifiers(ACC_PUBLIC + ACC_STATIC);
    }
    if (getterNode != null) {
      MethodCallExpression call =
          new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
      call.setSourcePosition(receiver);
      call.setMethodTarget(getterNode);
      call.setImplicitThis(implicitThis);
      call.setSafe(safe);
      call.visit(controller.getAcg());
      return true;
    }

    if (receiverType instanceof InnerClassNode && !receiverType.isStaticClass()) {
      if (makeGetPropertyWithGetter(
          receiver, receiverType.getOuterClass(), methodName, safe, implicitThis)) {
        return true;
      }
    }

    // go upper level
    ClassNode superClass = receiverType.getSuperClass();
    if (superClass != null) {
      return makeGetPropertyWithGetter(receiver, superClass, methodName, safe, implicitThis);
    }
    return false;
  }
 static {
   ARRAYLIST_CONSTRUCTOR =
       new ConstructorNode(
           ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
   ARRAYLIST_CONSTRUCTOR.setDeclaringClass(StaticCompilationVisitor.ARRAYLIST_CLASSNODE);
 }
  protected Expression transformMethodCallExpression(MethodCallExpression mce) {
    Expression args = transform(mce.getArguments());
    Expression method = transform(mce.getMethod());
    Expression object = transform(mce.getObjectExpression());
    boolean isExplicitThisOrSuper = false;
    boolean isExplicitSuper = false;
    if (object instanceof VariableExpression) {
      VariableExpression ve = (VariableExpression) object;
      isExplicitThisOrSuper =
          !mce.isImplicitThis() && (ve.isThisExpression() || ve.isSuperExpression());
      isExplicitSuper = ve.isSuperExpression();
    }

    if (mce.isImplicitThis() || isExplicitThisOrSuper) {
      if (mce.isImplicitThis()) {
        Expression ret = findStaticMethodImportFromModule(method, args);
        if (ret != null) {
          setSourcePosition(ret, mce);
          return ret;
        }
        if (method instanceof ConstantExpression && !inLeftExpression) {
          // could be a closure field
          String methodName = (String) ((ConstantExpression) method).getValue();
          ret = findStaticFieldOrPropAccessorImportFromModule(methodName);
          if (ret != null) {
            ret = new MethodCallExpression(ret, "call", args);
            setSourcePosition(ret, mce);
            return ret;
          }
        }
      } else if (currentMethod != null && currentMethod.isStatic() && isExplicitSuper) {
        MethodCallExpression ret =
            new MethodCallExpression(
                new ClassExpression(currentClass.getSuperClass()), method, args);
        setSourcePosition(ret, mce);
        return ret;
      }

      if (method instanceof ConstantExpression) {
        ConstantExpression ce = (ConstantExpression) method;
        Object value = ce.getValue();
        if (value instanceof String) {
          String methodName = (String) value;
          boolean lookForPossibleStaticMethod = !methodName.equals("call");
          if (currentMethod != null && !currentMethod.isStatic()) {
            if (currentClass.hasPossibleMethod(methodName, args)) {
              lookForPossibleStaticMethod = false;
            }
          }
          if (!inClosure
              && (inSpecialConstructorCall
                  || (lookForPossibleStaticMethod
                      && currentClass.hasPossibleStaticMethod(methodName, args)))) {
            StaticMethodCallExpression smce =
                new StaticMethodCallExpression(currentClass, methodName, args);
            setSourcePosition(smce, mce);
            return smce;
          }
        }
      }
    }

    MethodCallExpression result = new MethodCallExpression(object, method, args);
    result.setSafe(mce.isSafe());
    result.setImplicitThis(mce.isImplicitThis());
    result.setSpreadSafe(mce.isSpreadSafe());
    result.setMethodTarget(mce.getMethodTarget());
    // GROOVY-6757
    result.setGenericsTypes(mce.getGenericsTypes());
    setSourcePosition(result, mce);
    return result;
  }