Search in sources :

Example 1 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project hackpad by dropbox.

the class CodeGenerator method generateNestedFunctions.

private void generateNestedFunctions() {
    int functionCount = scriptOrFn.getFunctionCount();
    if (functionCount == 0)
        return;
    InterpreterData[] array = new InterpreterData[functionCount];
    for (int i = 0; i != functionCount; i++) {
        FunctionNode fn = scriptOrFn.getFunctionNode(i);
        CodeGenerator gen = new CodeGenerator();
        gen.compilerEnv = compilerEnv;
        gen.scriptOrFn = fn;
        gen.itsData = new InterpreterData(itsData);
        gen.generateFunctionICode();
        array[i] = gen.itsData;
    }
    itsData.itsNestedFunctions = array;
}
Also used : FunctionNode(org.mozilla.javascript.ast.FunctionNode)

Example 2 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project hackpad by dropbox.

the class Node method toStringTreeHelper.

private static void toStringTreeHelper(ScriptNode treeTop, Node n, ObjToIntMap printIds, int level, StringBuffer sb) {
    if (Token.printTrees) {
        if (printIds == null) {
            printIds = new ObjToIntMap();
            generatePrintIds(treeTop, printIds);
        }
        for (int i = 0; i != level; ++i) {
            sb.append("    ");
        }
        n.toString(printIds, sb);
        sb.append('\n');
        for (Node cursor = n.getFirstChild(); cursor != null; cursor = cursor.getNext()) {
            if (cursor.getType() == Token.FUNCTION) {
                int fnIndex = cursor.getExistingIntProp(Node.FUNCTION_PROP);
                FunctionNode fn = treeTop.getFunctionNode(fnIndex);
                toStringTreeHelper(fn, fn, null, level + 1, sb);
            } else {
                toStringTreeHelper(treeTop, cursor, printIds, level + 1, sb);
            }
        }
    }
}
Also used : ScriptNode(org.mozilla.javascript.ast.ScriptNode) FunctionNode(org.mozilla.javascript.ast.FunctionNode) FunctionNode(org.mozilla.javascript.ast.FunctionNode)

Example 3 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project hackpad by dropbox.

the class ClassCompiler method compileToClassFiles.

/**
     * Compile JavaScript source into one or more Java class files.
     * The first compiled class will have name mainClassName.
     * If the results of {@link #getTargetExtends()} or
     * {@link #getTargetImplements()} are not null, then the first compiled
     * class will extend the specified super class and implement
     * specified interfaces.
     *
     * @return array where elements with even indexes specifies class name
     *         and the following odd index gives class file body as byte[]
     *         array. The initial element of the array always holds
     *         mainClassName and array[1] holds its byte code.
     */
public Object[] compileToClassFiles(String source, String sourceLocation, int lineno, String mainClassName) {
    Parser p = new Parser(compilerEnv);
    AstRoot ast = p.parse(source, sourceLocation, lineno);
    IRFactory irf = new IRFactory(compilerEnv);
    ScriptNode tree = irf.transformTree(ast);
    // release reference to original parse tree & parser
    irf = null;
    ast = null;
    p = null;
    Class<?> superClass = getTargetExtends();
    Class<?>[] interfaces = getTargetImplements();
    String scriptClassName;
    boolean isPrimary = (interfaces == null && superClass == null);
    if (isPrimary) {
        scriptClassName = mainClassName;
    } else {
        scriptClassName = makeAuxiliaryClassName(mainClassName, "1");
    }
    Codegen codegen = new Codegen();
    codegen.setMainMethodClass(mainMethodClassName);
    byte[] scriptClassBytes = codegen.compileToClassFile(compilerEnv, scriptClassName, tree, tree.getEncodedSource(), false);
    if (isPrimary) {
        return new Object[] { scriptClassName, scriptClassBytes };
    }
    int functionCount = tree.getFunctionCount();
    ObjToIntMap functionNames = new ObjToIntMap(functionCount);
    for (int i = 0; i != functionCount; ++i) {
        FunctionNode ofn = tree.getFunctionNode(i);
        String name = ofn.getName();
        if (name != null && name.length() != 0) {
            functionNames.put(name, ofn.getParamCount());
        }
    }
    if (superClass == null) {
        superClass = ScriptRuntime.ObjectClass;
    }
    byte[] mainClassBytes = JavaAdapter.createAdapterCode(functionNames, mainClassName, superClass, interfaces, scriptClassName);
    return new Object[] { mainClassName, mainClassBytes, scriptClassName, scriptClassBytes };
}
Also used : FunctionNode(org.mozilla.javascript.ast.FunctionNode) ScriptNode(org.mozilla.javascript.ast.ScriptNode) AstRoot(org.mozilla.javascript.ast.AstRoot)

Example 4 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project HL4A by HL4A.

the class BodyCodegen method generateNativeFunctionOverrides.

private void generateNativeFunctionOverrides(ClassFileWriter cfw, String encodedSource) {
    // Override NativeFunction.getLanguageVersion() with
    // public int getLanguageVersion() { return <version-constant>; }
    cfw.startMethod("getLanguageVersion", "()I", ACC_PUBLIC);
    cfw.addPush(compilerEnv.getLanguageVersion());
    cfw.add(ByteCode.IRETURN);
    // 1: this and no argument or locals
    cfw.stopMethod((short) 1);
    // The rest of NativeFunction overrides require specific code for each
    // script/function id
    final int Do_getFunctionName = 0;
    final int Do_getParamCount = 1;
    final int Do_getParamAndVarCount = 2;
    final int Do_getParamOrVarName = 3;
    final int Do_getEncodedSource = 4;
    final int Do_getParamOrVarConst = 5;
    final int SWITCH_COUNT = 6;
    for (int methodIndex = 0; methodIndex != SWITCH_COUNT; ++methodIndex) {
        if (methodIndex == Do_getEncodedSource && encodedSource == null) {
            continue;
        }
        // Generate:
        // prologue;
        // switch over function id to implement function-specific action
        // epilogue
        short methodLocals;
        switch(methodIndex) {
            case Do_getFunctionName:
                // Only this
                methodLocals = 1;
                cfw.startMethod("getFunctionName", "()Ljava/lang/String;", ACC_PUBLIC);
                break;
            case Do_getParamCount:
                // Only this
                methodLocals = 1;
                cfw.startMethod("getParamCount", "()I", ACC_PUBLIC);
                break;
            case Do_getParamAndVarCount:
                // Only this
                methodLocals = 1;
                cfw.startMethod("getParamAndVarCount", "()I", ACC_PUBLIC);
                break;
            case Do_getParamOrVarName:
                // this + paramOrVarIndex
                methodLocals = 1 + 1;
                cfw.startMethod("getParamOrVarName", "(I)Ljava/lang/String;", ACC_PUBLIC);
                break;
            case Do_getParamOrVarConst:
                // this + paramOrVarName
                methodLocals = 1 + 1 + 1;
                cfw.startMethod("getParamOrVarConst", "(I)Z", ACC_PUBLIC);
                break;
            case Do_getEncodedSource:
                // Only this
                methodLocals = 1;
                cfw.startMethod("getEncodedSource", "()Ljava/lang/String;", ACC_PUBLIC);
                cfw.addPush(encodedSource);
                break;
            default:
                throw Kit.codeBug();
        }
        int count = scriptOrFnNodes.length;
        int switchStart = 0;
        int switchStackTop = 0;
        if (count > 1) {
            // Generate switch but only if there is more then one
            // script/function
            cfw.addLoadThis();
            cfw.add(ByteCode.GETFIELD, cfw.getClassName(), ID_FIELD_NAME, "I");
            // do switch from 1 .. count - 1 mapping 0 to the default case
            switchStart = cfw.addTableSwitch(1, count - 1);
        }
        for (int i = 0; i != count; ++i) {
            ScriptNode n = scriptOrFnNodes[i];
            if (i == 0) {
                if (count > 1) {
                    cfw.markTableSwitchDefault(switchStart);
                    switchStackTop = cfw.getStackTop();
                }
            } else {
                cfw.markTableSwitchCase(switchStart, i - 1, switchStackTop);
            }
            // Impelemnet method-specific switch code
            switch(methodIndex) {
                case Do_getFunctionName:
                    // Push function name
                    if (n.getType() == Token.SCRIPT) {
                        cfw.addPush("");
                    } else {
                        String name = ((FunctionNode) n).getName();
                        cfw.addPush(name);
                    }
                    cfw.add(ByteCode.ARETURN);
                    break;
                case Do_getParamCount:
                    // Push number of defined parameters
                    cfw.addPush(n.getParamCount());
                    cfw.add(ByteCode.IRETURN);
                    break;
                case Do_getParamAndVarCount:
                    // Push number of defined parameters and declared variables
                    cfw.addPush(n.getParamAndVarCount());
                    cfw.add(ByteCode.IRETURN);
                    break;
                case Do_getParamOrVarName:
                    // Push name of parameter using another switch
                    // over paramAndVarCount
                    int paramAndVarCount = n.getParamAndVarCount();
                    if (paramAndVarCount == 0) {
                        // The runtime should never call the method in this
                        // case but to make bytecode verifier happy return null
                        // as throwing execption takes more code
                        cfw.add(ByteCode.ACONST_NULL);
                        cfw.add(ByteCode.ARETURN);
                    } else if (paramAndVarCount == 1) {
                        // As above do not check for valid index but always
                        // return the name of the first param
                        cfw.addPush(n.getParamOrVarName(0));
                        cfw.add(ByteCode.ARETURN);
                    } else {
                        // Do switch over getParamOrVarName
                        // param or var index
                        cfw.addILoad(1);
                        // do switch from 1 .. paramAndVarCount - 1 mapping 0
                        // to the default case
                        int paramSwitchStart = cfw.addTableSwitch(1, paramAndVarCount - 1);
                        for (int j = 0; j != paramAndVarCount; ++j) {
                            if (cfw.getStackTop() != 0)
                                Kit.codeBug();
                            String s = n.getParamOrVarName(j);
                            if (j == 0) {
                                cfw.markTableSwitchDefault(paramSwitchStart);
                            } else {
                                cfw.markTableSwitchCase(paramSwitchStart, j - 1, 0);
                            }
                            cfw.addPush(s);
                            cfw.add(ByteCode.ARETURN);
                        }
                    }
                    break;
                case Do_getParamOrVarConst:
                    // Push name of parameter using another switch
                    // over paramAndVarCount
                    paramAndVarCount = n.getParamAndVarCount();
                    boolean[] constness = n.getParamAndVarConst();
                    if (paramAndVarCount == 0) {
                        // The runtime should never call the method in this
                        // case but to make bytecode verifier happy return null
                        // as throwing execption takes more code
                        cfw.add(ByteCode.ICONST_0);
                        cfw.add(ByteCode.IRETURN);
                    } else if (paramAndVarCount == 1) {
                        // As above do not check for valid index but always
                        // return the name of the first param
                        cfw.addPush(constness[0]);
                        cfw.add(ByteCode.IRETURN);
                    } else {
                        // Do switch over getParamOrVarName
                        // param or var index
                        cfw.addILoad(1);
                        // do switch from 1 .. paramAndVarCount - 1 mapping 0
                        // to the default case
                        int paramSwitchStart = cfw.addTableSwitch(1, paramAndVarCount - 1);
                        for (int j = 0; j != paramAndVarCount; ++j) {
                            if (cfw.getStackTop() != 0)
                                Kit.codeBug();
                            if (j == 0) {
                                cfw.markTableSwitchDefault(paramSwitchStart);
                            } else {
                                cfw.markTableSwitchCase(paramSwitchStart, j - 1, 0);
                            }
                            cfw.addPush(constness[j]);
                            cfw.add(ByteCode.IRETURN);
                        }
                    }
                    break;
                case Do_getEncodedSource:
                    // Push number encoded source start and end
                    // to prepare for encodedSource.substring(start, end)
                    cfw.addPush(n.getEncodedSourceStart());
                    cfw.addPush(n.getEncodedSourceEnd());
                    cfw.addInvoke(ByteCode.INVOKEVIRTUAL, "java/lang/String", "substring", "(II)Ljava/lang/String;");
                    cfw.add(ByteCode.ARETURN);
                    break;
                default:
                    throw Kit.codeBug();
            }
        }
        cfw.stopMethod(methodLocals);
    }
}
Also used : FunctionNode(org.mozilla.javascript.ast.FunctionNode) ScriptNode(org.mozilla.javascript.ast.ScriptNode)

Example 5 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project HL4A by HL4A.

the class ClassCompiler method compileToClassFiles.

/**
 * Compile JavaScript source into one or more Java class files.
 * The first compiled class will have name mainClassName.
 * If the results of {@link #getTargetExtends()} or
 * {@link #getTargetImplements()} are not null, then the first compiled
 * class will extend the specified super class and implement
 * specified interfaces.
 *
 * @return array where elements with even indexes specifies class name
 *         and the following odd index gives class file body as byte[]
 *         array. The initial element of the array always holds
 *         mainClassName and array[1] holds its byte code.
 */
public Object[] compileToClassFiles(String source, String sourceLocation, int lineno, String mainClassName) {
    Parser p = new Parser(compilerEnv);
    AstRoot ast = p.parse(source, sourceLocation, lineno);
    IRFactory irf = new IRFactory(compilerEnv);
    ScriptNode tree = irf.transformTree(ast);
    // release reference to original parse tree & parser
    irf = null;
    ast = null;
    p = null;
    Class<?> superClass = getTargetExtends();
    Class<?>[] interfaces = getTargetImplements();
    String scriptClassName;
    boolean isPrimary = (interfaces == null && superClass == null);
    if (isPrimary) {
        scriptClassName = mainClassName;
    } else {
        scriptClassName = makeAuxiliaryClassName(mainClassName, "1");
    }
    Codegen codegen = new Codegen();
    codegen.setMainMethodClass(mainMethodClassName);
    byte[] scriptClassBytes = codegen.compileToClassFile(compilerEnv, scriptClassName, tree, tree.getEncodedSource(), false);
    if (isPrimary) {
        return new Object[] { scriptClassName, scriptClassBytes };
    }
    int functionCount = tree.getFunctionCount();
    ObjToIntMap functionNames = new ObjToIntMap(functionCount);
    for (int i = 0; i != functionCount; ++i) {
        FunctionNode ofn = tree.getFunctionNode(i);
        String name = ofn.getName();
        if (name != null && name.length() != 0) {
            functionNames.put(name, ofn.getParamCount());
        }
    }
    if (superClass == null) {
        superClass = ScriptRuntime.ObjectClass;
    }
    byte[] mainClassBytes = JavaAdapter.createAdapterCode(functionNames, mainClassName, superClass, interfaces, scriptClassName);
    return new Object[] { mainClassName, mainClassBytes, scriptClassName, scriptClassBytes };
}
Also used : FunctionNode(org.mozilla.javascript.ast.FunctionNode) ScriptNode(org.mozilla.javascript.ast.ScriptNode) AstRoot(org.mozilla.javascript.ast.AstRoot)

Aggregations

FunctionNode (org.mozilla.javascript.ast.FunctionNode)32 ScriptNode (org.mozilla.javascript.ast.ScriptNode)20 AstNode (org.mozilla.javascript.ast.AstNode)8 Name (org.mozilla.javascript.ast.Name)7 LetNode (org.mozilla.javascript.ast.LetNode)6 Jump (org.mozilla.javascript.ast.Jump)4 Scope (org.mozilla.javascript.ast.Scope)4 XmlString (org.mozilla.javascript.ast.XmlString)3 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 Iterator (java.util.Iterator)2 Map (java.util.Map)2 AstRoot (org.mozilla.javascript.ast.AstRoot)2 ErrorNode (org.mozilla.javascript.ast.ErrorNode)2 Block (org.mozilla.javascript.ast.Block)1 Comment (org.mozilla.javascript.ast.Comment)1 EmptyExpression (org.mozilla.javascript.ast.EmptyExpression)1 ExpressionStatement (org.mozilla.javascript.ast.ExpressionStatement)1 ObjectProperty (org.mozilla.javascript.ast.ObjectProperty)1 ParenthesizedExpression (org.mozilla.javascript.ast.ParenthesizedExpression)1