📄 asmclassgenerator.java
字号:
leftHandExpression = wasLeft; return; } private void throwException(String s) { throw new RuntimeParserException(s, currentASTNode); } public void visitPrefixExpression(PrefixExpression expression) { switch (expression.getOperation().getType()) { case Types.PLUS_PLUS : evaluatePrefixMethod("next", expression.getExpression()); break; case Types.MINUS_MINUS : evaluatePrefixMethod("previous", expression.getExpression()); break; } } public void visitClosureExpression(ClosureExpression expression) { ClassNode innerClass = createClosureClass(expression); addInnerClass(innerClass); String innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass); passingClosureParams = true; List constructors = innerClass.getDeclaredConstructors(); ConstructorNode node = (ConstructorNode) constructors.get(0); Parameter[] localVariableParams = node.getParameters(); cv.visitTypeInsn(NEW, innerClassinternalName); cv.visitInsn(DUP); if (isStaticMethod() || classNode.isStaticClass()) { visitClassExpression(new ClassExpression(classNode)); } else { cv.visitVarInsn(ALOAD, 0); } // now lets load the various parameters we're passing // we start at index 1 because the first variable we pass // is the owner instance and at this point it is already // on the stack for (int i = 1; i < localVariableParams.length; i++) { Parameter param = localVariableParams[i]; String name = param.getName(); if (compileStack.getScope().isReferencedClassVariable(name)) { visitFieldExpression(new FieldExpression(classNode.getField(name))); } else { Variable v = compileStack.getVariable(name,classNode.getSuperClass()!=ClassHelper.CLOSURE_TYPE); if (v==null) { // variable is not on stack because we are // inside a nested Closure and this variable // was not used before // then load it from the Closure field FieldNode field = classNode.getField(name); cv.visitVarInsn(ALOAD, 0); cv.visitFieldInsn(GETFIELD, internalClassName, name, BytecodeHelper.getTypeDescription(field.getType())); // and define it // Note: // we can simply define it here and don't have to // be afraid about name problems because a second // variable with that name is not allowed inside the closure param.setClosureSharedVariable(false); v = compileStack.defineVariable(param,true); param.setClosureSharedVariable(true); v.setHolder(true); } cv.visitVarInsn(ALOAD, v.getIndex()); } } passingClosureParams = false; // we may need to pass in some other constructors //cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", prototype + ")V"); cv.visitMethodInsn( INVOKESPECIAL, innerClassinternalName, "<init>", BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, localVariableParams)); } /** * Loads either this object or if we're inside a closure then load the top level owner */ protected void loadThisOrOwner() { if (isInnerClass()) { visitFieldExpression(new FieldExpression(classNode.getField("owner"))); } else { cv.visitVarInsn(ALOAD, 0); } } public void visitRegexExpression(RegexExpression expression) { expression.getRegex().visit(this); regexPattern.call(cv); } /** * Generate byte code for constants * @see <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#14152">Class field types</a> */ public void visitConstantExpression(ConstantExpression expression) { Object value = expression.getValue(); helper.loadConstant(value); } public void visitSpreadExpression(SpreadExpression expression) { Expression subExpression = expression.getExpression(); subExpression.visit(this); spreadList.call(cv); } public void visitSpreadMapExpression(SpreadMapExpression expression) { Expression subExpression = expression.getExpression(); subExpression.visit(this); spreadMap.call(cv); } public void visitMethodPointerExpression(MethodPointerExpression expression) { Expression subExpression = expression.getExpression(); subExpression.visit(this); helper.loadConstant(expression.getMethodName()); getMethodPointer.call(cv); } public void visitNegationExpression(NegationExpression expression) { Expression subExpression = expression.getExpression(); subExpression.visit(this); negation.call(cv); } public void visitBitwiseNegExpression(BitwiseNegExpression expression) { Expression subExpression = expression.getExpression(); subExpression.visit(this); bitNegation.call(cv); } public void visitCastExpression(CastExpression expression) { ClassNode type = expression.getType(); visitAndAutoboxBoolean(expression.getExpression()); doConvertAndCast(type, expression.getExpression(), expression.isIgnoringAutoboxing(),false); } public void visitNotExpression(NotExpression expression) { Expression subExpression = expression.getExpression(); subExpression.visit(this); // This is not the best way to do this. Javac does it by reversing the // underlying expressions but that proved // fairly complicated for not much gain. Instead we'll just use a // utility function for now. if (isComparisonExpression(expression.getExpression())) { notBoolean.call(cv); } else { notObject.call(cv); } } /** * return a primitive boolean value of the BooleanExpresion. * @param expression */ public void visitBooleanExpression(BooleanExpression expression) { compileStack.pushBooleanExpression(); expression.getExpression().visit(this); if (!isComparisonExpression(expression.getExpression())) {// comment out for optimization when boolean values are not autoboxed for eg. function calls.// Class typeClass = expression.getExpression().getTypeClass();// if (typeClass != null && typeClass != boolean.class) { asBool.call(cv); // to return a primitive boolean// } } compileStack.pop(); } private void prepareMethodcallObjectAndName(Expression objectExpression, boolean objectExpressionIsMethodName, String method) { if (objectExpressionIsMethodName) { VariableExpression.THIS_EXPRESSION.visit(this); objectExpression.visit(this); } else { objectExpression.visit(this); cv.visitLdcInsn(method); } } public void visitMethodCallExpression(MethodCallExpression call) { onLineNumber(call, "visitMethodCallExpression: \"" + call.getMethod() + "\":"); this.leftHandExpression = false; Expression arguments = call.getArguments(); /* * if (arguments instanceof TupleExpression) { TupleExpression * tupleExpression = (TupleExpression) arguments; int size = * tupleExpression.getExpressions().size(); if (size == 0) { arguments = * ConstantExpression.EMPTY_ARRAY; } } */ boolean superMethodCall = MethodCallExpression.isSuperMethodCall(call); String method = call.getMethod(); // are we a local variable if (isThisExpression(call.getObjectExpression()) && isFieldOrVariable(method) && ! classNode.hasPossibleMethod(method, arguments)) { /* * if (arguments instanceof TupleExpression) { TupleExpression * tupleExpression = (TupleExpression) arguments; int size = * tupleExpression.getExpressions().size(); if (size == 1) { * arguments = (Expression) * tupleExpression.getExpressions().get(0); } } */ // lets invoke the closure method visitVariableExpression(new VariableExpression(method)); arguments.visit(this); invokeClosureMethod.call(cv); } else { if (superMethodCall) { MethodNode superMethodNode = findSuperMethod(call); cv.visitVarInsn(ALOAD, 0); loadArguments(superMethodNode.getParameters(), arguments); String descriptor = BytecodeHelper.getMethodDescriptor(superMethodNode.getReturnType(), superMethodNode.getParameters()); cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(superMethodNode.getDeclaringClass()), method, descriptor); // as long as we want to work with objects where possible, we may have to // box the value here. This can be removed when we know the return type // and save it in the MethodCallExpression. By default it returns Object // so boxing is always save. helper.box(superMethodNode.getReturnType()); } else { Expression objectExpression = call.getObjectExpression(); boolean objectExpressionIsMethodName = false; if (method.equals("call")) { if (objectExpression instanceof GStringExpression) { objectExpressionIsMethodName=true; objectExpression = new CastExpression(ClassHelper.STRING_TYPE, objectExpression); } else if (objectExpression instanceof ConstantExpression) { Object value = ((ConstantExpression) objectExpression).getValue(); if ( value != null && value instanceof String) objectExpressionIsMethodName=true; } } if (emptyArguments(arguments) && !call.isSafe() && !call.isSpreadSafe()) { prepareMethodcallObjectAndName(objectExpression, objectExpressionIsMethodName,method); invokeNoArgumentsMethod.call(cv); } else { if (argumentsUseStack(arguments)) { arguments.visit(this); int paramIdx = compileStack.defineTemporaryVariable(method + "_arg",true); prepareMethodcallObjectAndName(objectExpression, objectExpressionIsMethodName,method); cv.visitVarInsn(ALOAD, paramIdx); compileStack.removeVar(paramIdx); } else { prepareMethodcallObjectAndName(objectExpression, objectExpressionIsMethodName,method); arguments.visit(this); } if (call.isSpreadSafe()) { invokeMethodSpreadSafeMethod.call(cv); } else if (call.isSafe()) { invokeMethodSafeMethod.call(cv); } else { invokeMethodMethod.call(cv); } } } } } /** * Loads and coerces the argument values for the given method call */ protected void loadArguments(Parameter[] parameters, Expression expression) { TupleExpression argListExp = (TupleExpression) expression; List arguments = argListExp.getExpressions(); for (int i = 0, size = arguments.size(); i < size; i++) { Expression argExp = argListExp.getExpression(i); Parameter param = parameters[i]; visitAndAutoboxBoolean(argExp); ClassNode type = param.getType(); ClassNode expType = getExpressionType(argExp); if (!type.equals(expType)) { doConvertAndCast(type); } } } /** * Attempts to find the method of the given name in a super class */ protected MethodNode findSuperMethod(MethodCallExpression call) { String methodName = call.getMethod(); TupleExpression argExpr = (TupleExpression) call.getArguments(); int argCount = argExpr.getExpressions().size(); ClassNode superClassNode = classNode.getSuperClass(); if (superClassNode != null) { List methods = superClassNode.getMethods(methodName); for (Iterator iter = methods.iterator(); iter.hasNext(); ) { MethodNode method = (MethodNode) iter.next(); if (method.getParameters().length == argCount) { return method; } } } throwException("No such method: " + methodName + " for class: " + classNode.getName()); return null; // should not come her
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -