Search in sources :

Example 6 with ScriptNode

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

the class BodyCodegen method generateCode.

private byte[] generateCode(String encodedSource) {
    boolean hasScript = (scriptOrFnNodes[0].getType() == Token.SCRIPT);
    boolean hasFunctions = (scriptOrFnNodes.length > 1 || !hasScript);
    boolean isStrictMode = scriptOrFnNodes[0].isInStrictMode();
    String sourceFile = null;
    if (compilerEnv.isGenerateDebugInfo()) {
        sourceFile = scriptOrFnNodes[0].getSourceName();
    }
    ClassFileWriter cfw = new ClassFileWriter(mainClassName, SUPER_CLASS_NAME, sourceFile);
    cfw.addField(ID_FIELD_NAME, "I", ACC_PRIVATE);
    if (hasFunctions) {
        generateFunctionConstructor(cfw);
    }
    if (hasScript) {
        cfw.addInterface("org/mozilla/javascript/Script");
        generateScriptCtor(cfw);
        generateMain(cfw);
        generateExecute(cfw);
    }
    generateCallMethod(cfw, isStrictMode);
    generateResumeGenerator(cfw);
    generateNativeFunctionOverrides(cfw, encodedSource);
    int count = scriptOrFnNodes.length;
    for (int i = 0; i != count; ++i) {
        ScriptNode n = scriptOrFnNodes[i];
        BodyCodegen bodygen = new BodyCodegen();
        bodygen.cfw = cfw;
        bodygen.codegen = this;
        bodygen.compilerEnv = compilerEnv;
        bodygen.scriptOrFn = n;
        bodygen.scriptOrFnIndex = i;
        try {
            bodygen.generateBodyCode();
        } catch (ClassFileWriter.ClassFileFormatException e) {
            throw reportClassFileFormatException(n, e.getMessage());
        }
        if (n.getType() == Token.FUNCTION) {
            OptFunctionNode ofn = OptFunctionNode.get(n);
            generateFunctionInit(cfw, ofn);
            if (ofn.isTargetOfDirectCall()) {
                emitDirectConstructor(cfw, ofn);
            }
        }
    }
    emitRegExpInit(cfw);
    emitConstantDudeInitializers(cfw);
    return cfw.toByteArray();
}
Also used : ScriptNode(org.mozilla.javascript.ast.ScriptNode)

Example 7 with ScriptNode

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

the class BodyCodegen method generateCallMethod.

private void generateCallMethod(ClassFileWriter cfw, boolean isStrictMode) {
    cfw.startMethod("call", "(Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "Lorg/mozilla/javascript/Scriptable;" + "[Ljava/lang/Object;)Ljava/lang/Object;", (short) (ACC_PUBLIC | ACC_FINAL));
    // Generate code for:
    // if (!ScriptRuntime.hasTopCall(cx)) {
    // return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args);
    // }
    int nonTopCallLabel = cfw.acquireLabel();
    // cx
    cfw.addALoad(1);
    cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/ScriptRuntime", "hasTopCall", "(Lorg/mozilla/javascript/Context;" + ")Z");
    cfw.add(ByteCode.IFNE, nonTopCallLabel);
    cfw.addALoad(0);
    cfw.addALoad(1);
    cfw.addALoad(2);
    cfw.addALoad(3);
    cfw.addALoad(4);
    cfw.addPush(isStrictMode);
    cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/ScriptRuntime", "doTopCall", "(Lorg/mozilla/javascript/Callable;" + "Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "Lorg/mozilla/javascript/Scriptable;" + "[Ljava/lang/Object;" + "Z" + ")Ljava/lang/Object;");
    cfw.add(ByteCode.ARETURN);
    cfw.markLabel(nonTopCallLabel);
    // Now generate switch to call the real methods
    cfw.addALoad(0);
    cfw.addALoad(1);
    cfw.addALoad(2);
    cfw.addALoad(3);
    cfw.addALoad(4);
    int end = scriptOrFnNodes.length;
    boolean generateSwitch = (2 <= end);
    int switchStart = 0;
    int switchStackTop = 0;
    if (generateSwitch) {
        cfw.addLoadThis();
        cfw.add(ByteCode.GETFIELD, cfw.getClassName(), ID_FIELD_NAME, "I");
        // do switch from (1,  end - 1) mapping 0 to
        // the default case
        switchStart = cfw.addTableSwitch(1, end - 1);
    }
    for (int i = 0; i != end; ++i) {
        ScriptNode n = scriptOrFnNodes[i];
        if (generateSwitch) {
            if (i == 0) {
                cfw.markTableSwitchDefault(switchStart);
                switchStackTop = cfw.getStackTop();
            } else {
                cfw.markTableSwitchCase(switchStart, i - 1, switchStackTop);
            }
        }
        if (n.getType() == Token.FUNCTION) {
            OptFunctionNode ofn = OptFunctionNode.get(n);
            if (ofn.isTargetOfDirectCall()) {
                int pcount = ofn.fnode.getParamCount();
                if (pcount != 0) {
                    // stack top == arguments array from addALoad4()
                    for (int p = 0; p != pcount; ++p) {
                        cfw.add(ByteCode.ARRAYLENGTH);
                        cfw.addPush(p);
                        int undefArg = cfw.acquireLabel();
                        int beyond = cfw.acquireLabel();
                        cfw.add(ByteCode.IF_ICMPLE, undefArg);
                        // get array[p]
                        cfw.addALoad(4);
                        cfw.addPush(p);
                        cfw.add(ByteCode.AALOAD);
                        cfw.add(ByteCode.GOTO, beyond);
                        cfw.markLabel(undefArg);
                        pushUndefined(cfw);
                        cfw.markLabel(beyond);
                        // Only one push
                        cfw.adjustStackTop(-1);
                        cfw.addPush(0.0);
                        // restore invariant
                        cfw.addALoad(4);
                    }
                }
            }
        }
        cfw.addInvoke(ByteCode.INVOKESTATIC, mainClassName, getBodyMethodName(n), getBodyMethodSignature(n));
        cfw.add(ByteCode.ARETURN);
    }
    cfw.stopMethod((short) 5);
// 5: this, cx, scope, js this, args[]
}
Also used : ScriptNode(org.mozilla.javascript.ast.ScriptNode)

Example 8 with ScriptNode

use of org.mozilla.javascript.ast.ScriptNode 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 9 with ScriptNode

use of org.mozilla.javascript.ast.ScriptNode 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)

Example 10 with ScriptNode

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

the class Context method compileImpl.

private Object compileImpl(Scriptable scope, Reader sourceReader, String sourceString, String sourceName, int lineno, Object securityDomain, boolean returnFunction, Evaluator compiler, ErrorReporter compilationErrorReporter) throws IOException {
    if (sourceName == null) {
        sourceName = "未命名 代码";
    }
    if (securityDomain != null && getSecurityController() == null) {
        throw new IllegalArgumentException("securityDomain should be null if setSecurityController() was never called");
    }
    // One of sourceReader or sourceString has to be null
    if (!(sourceReader == null ^ sourceString == null))
        Kit.codeBug();
    // scope should be given if and only if compiling function
    if (!(scope == null ^ returnFunction))
        Kit.codeBug();
    CompilerEnvirons compilerEnv = new CompilerEnvirons();
    compilerEnv.initFromContext(this);
    if (compilationErrorReporter == null) {
        compilationErrorReporter = compilerEnv.getErrorReporter();
    }
    if (debugger != null) {
        if (sourceReader != null) {
            sourceString = Kit.readReader(sourceReader);
            sourceReader = null;
        }
    }
    Parser p = new Parser(compilerEnv, compilationErrorReporter);
    if (returnFunction) {
        p.calledByCompileFunction = true;
    }
    if (isStrictMode()) {
        p.setDefaultUseStrictDirective(true);
    }
    AstRoot ast;
    if (sourceString != null) {
        ast = p.parse(sourceString, sourceName, lineno);
    } else {
        ast = p.parse(sourceReader, sourceName, lineno);
    }
    if (returnFunction) {
        // parser no longer adds function to script node
        if (!(ast.getFirstChild() != null && ast.getFirstChild().getType() == Token.FUNCTION)) {
            // with sources like function() {};;;
            throw new IllegalArgumentException("compileFunction only accepts source with single JS function: " + sourceString);
        }
    }
    IRFactory irf = new IRFactory(compilerEnv, compilationErrorReporter);
    ScriptNode tree = irf.transformTree(ast);
    // discard everything but the IR tree
    p = null;
    ast = null;
    irf = null;
    if (compiler == null) {
        compiler = createCompiler();
    }
    Object bytecode = compiler.compile(compilerEnv, tree, tree.getEncodedSource(), returnFunction);
    if (debugger != null) {
        if (sourceString == null)
            Kit.codeBug();
        if (bytecode instanceof DebuggableScript) {
            DebuggableScript dscript = (DebuggableScript) bytecode;
            notifyDebugger_r(this, dscript, sourceString);
        } else {
            throw new RuntimeException("NOT SUPPORTED");
        }
    }
    Object result;
    if (returnFunction) {
        result = compiler.createFunctionObject(this, scope, bytecode, securityDomain);
    } else {
        result = compiler.createScriptObject(bytecode, securityDomain);
    }
    return result;
}
Also used : DebuggableScript(org.mozilla.javascript.debug.DebuggableScript) ScriptNode(org.mozilla.javascript.ast.ScriptNode) AstRoot(org.mozilla.javascript.ast.AstRoot)

Aggregations

ScriptNode (org.mozilla.javascript.ast.ScriptNode)28 FunctionNode (org.mozilla.javascript.ast.FunctionNode)11 AstRoot (org.mozilla.javascript.ast.AstRoot)4 Jump (org.mozilla.javascript.ast.Jump)4 Scope (org.mozilla.javascript.ast.Scope)4 Date (java.util.Date)2 Iterator (java.util.Iterator)2 Point (org.eclipse.swt.graphics.Point)2 MessageBox (org.eclipse.swt.widgets.MessageBox)2 TableItem (org.eclipse.swt.widgets.TableItem)2 CompilerEnvirons (org.mozilla.javascript.CompilerEnvirons)2 Context (org.mozilla.javascript.Context)2 ErrorReporter (org.mozilla.javascript.ErrorReporter)2 EvaluatorException (org.mozilla.javascript.EvaluatorException)2 JavaScriptException (org.mozilla.javascript.JavaScriptException)2 NodeTransformer (org.mozilla.javascript.NodeTransformer)2 Parser (org.mozilla.javascript.Parser)2 Script (org.mozilla.javascript.Script)2 Scriptable (org.mozilla.javascript.Scriptable)2 ScriptableObject (org.mozilla.javascript.ScriptableObject)2