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;
}
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);
}
}
}
}
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 };
}
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);
}
}
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 };
}
Aggregations