newStatements = copyFinally(finallyBody);
+ if (!isTerminal(newStatements)) {
+ newStatements.add(endpoint);
+ }
+ return new ExecuteNode(new Block(source, endpoint.getToken(), finish, newStatements));
+ }
+ return endpoint;
+ }
+ });
+
+ addStatement(newTryNode);
+ for (final Node statement : finallyBody.getStatements()) {
+ addStatement(statement);
}
- /*
- * We have a finally clause.
- *
- * Transform to do finally tail duplication as follows:
- *
- *
- * try {
- * try_body
- * } catch e1 {
- * catchbody_1
- * }
- * ...
- * } catch en {
- * catchbody_n
- * } finally {
- * finally_body
- * }
- *
- * (where e1 ... en are optional)
- *
- * turns into
- *
- * try {
- * try {
- * try_body
- * } catch e1 {
- * catchbody1
- * //nothing inlined explicitly here, return, break other
- * //terminals may inline the finally body
- * ...
- * } catch en {
- * catchbody2
- * //nothing inlined explicitly here, return, break other
- * //terminals may inline the finally body
- * }
- * } catch all ex {
- * finally_body_inlined
- * rethrow ex
- * }
- * finally_body_inlined
- *
- *
- * If tries are catches are terminal, visitors for return, break &
- * continue will handle the tail duplications. Throw needs to be
- * treated specially with the catchall as described in the above
- * ASCII art.
- *
- * If the try isn't terminal we do the finally_body_inlined at the
- * end. If the try is terminated with continue/break/return the
- * existing visitor logic will inline the finally before that
- * operation. if the try is terminated with a throw, the catches e1
- * ... en will have a chance to process the exception. If the
- * appropriate catch e1..en is non terminal we fall through to the
- * last finally_body_inlined. if the catch e1...en IS terminal with
- * continue/break/return existing visitor logic will fix it. If they
- * are terminal with another throw it goes to the catchall and the
- * finally_body_inlined marked (*) will fix it before rethrowing
- * whatever problem there was for identical semantic.
- */
- final Source source = getCurrentFunctionNode().getSource();
-
- // if try node does not contain a catch we can skip creation of a new
- // try node and just append our synthetic catch to the existing try node.
- if (!tryNode.getCatchBlocks().isEmpty()) {
- // insert an intermediate try-catch* node, where we move the body and all catch blocks.
- // the original try node become a try-finally container for the new try-catch* node.
- // because we don't clone (to avoid deep copy), we have to fix the block chain in the end.
- final TryNode innerTryNode;
- innerTryNode = new TryNode(source, token, finish, tryNode.getNext());
- innerTryNode.setBody(tryNode.getBody());
- innerTryNode.setCatchBlocks(tryNode.getCatchBlocks());
-
- // set outer tryNode's body to innerTryNode
- final Block outerBody;
- outerBody = new Block(source, token, finish);
- outerBody.setStatements(new ArrayList(Arrays.asList(innerTryNode)));
- tryNode.setBody(outerBody);
- tryNode.setCatchBlocks(null);
- }
-
- // create a catch-all that inlines finally and rethrows
-
- final Block catchBlock = new Block(source, token, finish);
- //this catch block should get define symbol
-
- final Block catchBody = new Block(source, token, finish);
- final Node catchAllFinally = finallyBody.copy();
-
- catchBody.addStatement(new ExecuteNode(source, finallyBody.getToken(), finallyBody.getFinish(), catchAllFinally));
- setTerminal(catchBody, true);
-
- final CatchNode catchAllNode;
- final IdentNode exception;
-
- exception = new IdentNode(source, token, finish, getCurrentFunctionNode().uniqueName("catch_all"));
- catchAllNode = new CatchNode(source, token, finish, new IdentNode(exception), null, catchBody);
- catchAllNode.setIsSyntheticRethrow();
-
- catchBlock.addStatement(catchAllNode);
-
- // replace all catches of outer tryNode with the catch-all
- tryNode.setCatchBlocks(new ArrayList<>(Arrays.asList(catchBlock)));
-
- /*
- * We leave the finally block for the original try in place for now
- * so that children visitations will work. It is removed and placed
- * afterwards in the else case below, after all children are visited
- */
-
- return tryNode;
+ return newTryNode;
}
@Override
public Node leaveTryNode(final TryNode tryNode) {
- final Block finallyBody = tryNode.getFinallyBody();
+ final Block finallyBody = tryNode.getFinallyBody();
- boolean allTerminal = tryNode.getBody().isTerminal() && (finallyBody == null || finallyBody.isTerminal());
-
- for (final Block catchBlock : tryNode.getCatchBlocks()) {
- allTerminal &= catchBlock.isTerminal();
+ if (finallyBody == null) {
+ return addStatement(tryNode);
}
- tryNode.setIsTerminal(allTerminal);
+ /*
+ * create a new trynode
+ * if we have catches:
+ *
+ * try try
+ * x try
+ * catch x
+ * y catch
+ * finally z y
+ * catchall
+ * rethrow
+ *
+ * otheriwse
+ *
+ * try try
+ * x x
+ * finally catchall
+ * y rethrow
+ *
+ *
+ * now splice in finally code wherever needed
+ *
+ */
+ TryNode newTryNode;
- addStatement(tryNode);
- unnest(tryNode);
+ final Block catchAll = catchAllBlock(tryNode);
- // if finally body is present, place it after the tryNode
- if (finallyBody != null) {
- tryNode.setFinallyBody(null);
- addStatement(finallyBody);
+ final List rethrows = new ArrayList<>();
+ catchAll.accept(new NodeVisitor() {
+ @Override
+ public boolean enterThrowNode(final ThrowNode throwNode) {
+ rethrows.add(throwNode);
+ return true;
+ }
+ });
+ assert rethrows.size() == 1;
+
+ if (tryNode.getCatchBlocks().isEmpty()) {
+ newTryNode = tryNode.setFinallyBody(null);
+ } else {
+ Block outerBody = new Block(tryNode.getSource(), tryNode.getToken(), tryNode.getFinish(), new ArrayList(Arrays.asList(tryNode.setFinallyBody(null))));
+ newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null);
}
- return tryNode;
+ newTryNode = newTryNode.setCatchBlocks(Arrays.asList(catchAll)).setFinallyBody(null);
+
+ /*
+ * Now that the transform is done, we have to go into the try and splice
+ * the finally block in front of any statement that is outside the try
+ */
+ return spliceFinally(newTryNode, rethrows, finallyBody);
}
@Override
public Node leaveVarNode(final VarNode varNode) {
addStatement(varNode);
+ if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && getLexicalContext().getCurrentFunction().isProgram()) {
+ new ExecuteNode(varNode.getSource(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
+ }
return varNode;
}
- @Override
- public Node enterWhileNode(final WhileNode whileNode) {
- return nest(whileNode);
- }
-
@Override
public Node leaveWhileNode(final WhileNode whileNode) {
final Node test = whileNode.getTest();
+ final Block body = whileNode.getBody();
- if (test == null) {
- setHasGoto(whileNode);
+ if (conservativeAlwaysTrue(test)) {
+ //turn it into a for node without a test.
+ final ForNode forNode = (ForNode)new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this);
+ getLexicalContext().replace(whileNode, forNode);
+ return forNode;
}
- final Block body = whileNode.getBody();
- final boolean escapes = controlFlowEscapes(body);
- if (escapes) {
- setTerminal(body, false);
- }
-
- Node node = whileNode;
-
- if (body.isTerminal()) {
- if (whileNode instanceof DoWhileNode) {
- setTerminal(whileNode, true);
- } else if (conservativeAlwaysTrue(test)) {
- node = new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish());
- ((ForNode)node).setBody(body);
- node.accept(this);
- setTerminal(node, !escapes);
- }
- }
-
- // pop the loop from the loop context
- unnest(whileNode);
- addStatement(node);
-
- return node;
+ return addStatement(checkEscape(whileNode));
}
@Override
public Node leaveWithNode(final WithNode withNode) {
- if (withNode.getBody().isTerminal()) {
- setTerminal(withNode, true);
- }
- addStatement(withNode);
-
- return withNode;
+ return addStatement(withNode);
}
@Override
@@ -741,23 +549,25 @@ final class Lower extends NodeOperatorVisitor {
*
* @param callNode call node to check if it's an eval
*/
- private void checkEval(final CallNode callNode) {
+ private CallNode checkEval(final CallNode callNode) {
if (callNode.getFunction() instanceof IdentNode) {
final List args = callNode.getArgs();
final IdentNode callee = (IdentNode)callNode.getFunction();
// 'eval' call with at least one argument
- if (args.size() >= 1 && EVAL.tag().equals(callee.getName())) {
- final CallNode.EvalArgs evalArgs =
+ if (args.size() >= 1 && EVAL.symbolName().equals(callee.getName())) {
+ final FunctionNode currentFunction = getLexicalContext().getCurrentFunction();
+ return callNode.setEvalArgs(
new CallNode.EvalArgs(
- args.get(0).copy().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case"
- getCurrentFunctionNode().getThisNode(),
+ ensureUniqueLabelsIn(args.get(0)).accept(this),
+ compilerConstant(THIS),
evalLocation(callee),
- getCurrentFunctionNode().isStrictMode());
- callNode.setEvalArgs(evalArgs);
+ currentFunction.isStrict()));
}
}
+
+ return callNode;
}
private static boolean conservativeAlwaysTrue(final Node node) {
@@ -773,7 +583,7 @@ final class Lower extends NodeOperatorVisitor {
* @param loopBody the loop body to check
* @return true if control flow may escape the loop
*/
- private boolean controlFlowEscapes(final Node loopBody) {
+ private static boolean controlFlowEscapes(final LexicalContext lex, final Block loopBody) {
final List escapes = new ArrayList<>();
loopBody.accept(new NodeVisitor() {
@@ -786,7 +596,7 @@ final class Lower extends NodeOperatorVisitor {
@Override
public Node leaveContinueNode(final ContinueNode node) {
// all inner loops have been popped.
- if (nesting.contains(node.getTargetNode())) {
+ if (lex.contains(lex.getContinueTo(node.getLabel()))) {
escapes.add(node);
}
return node;
@@ -796,135 +606,23 @@ final class Lower extends NodeOperatorVisitor {
return !escapes.isEmpty();
}
- private void guaranteeReturn(final FunctionNode functionNode) {
- Node resultNode;
-
- if (functionNode.isProgram()) {
- resultNode = functionNode.getResultNode(); // the eval result, symbol assigned in Attr
- } else {
- if (lastStatement != null && lastStatement.isTerminal() || lastStatement instanceof ReturnNode) {
- return; //already in place or not needed, as it should be for a non-undefined returning function
- }
- resultNode = LiteralNode.newInstance(functionNode, ScriptRuntime.UNDEFINED);
+ private LoopNode checkEscape(final LoopNode loopNode) {
+ final LexicalContext lc = getLexicalContext();
+ final boolean escapes = controlFlowEscapes(lc, loopNode.getBody());
+ if (escapes) {
+ return loopNode.
+ setBody(lc, loopNode.getBody().setIsTerminal(lc, false)).
+ setControlFlowEscapes(lc, escapes);
}
-
- //create a return statement
- final Node returnNode = new ReturnNode(functionNode.getSource(), functionNode.getLastToken(), functionNode.getFinish(), resultNode, null);
- returnNode.accept(this);
+ return loopNode;
}
- private Node nest(final Node node) {
- LOG.info("Nesting: " + node);
- LOG.indent();
- nesting.push(node);
- return node;
+ private Node addStatement(final Node statement) {
+ ((BlockLexicalContext)getLexicalContext()).appendStatement(statement);
+ return statement;
}
- private void unnest(final Node node) {
- LOG.unindent();
- assert nesting.getFirst() == node : "inconsistent nesting order : " + nesting.getFirst() + " != " + node;
- LOG.info("Unnesting: " + nesting);
- nesting.pop();
- }
-
- private static void setTerminal(final Node node, final boolean isTerminal) {
- LOG.info("terminal = " + isTerminal + " for " + node);
- node.setIsTerminal(isTerminal);
- }
-
- private static void setHasGoto(final Node node) { //, final boolean hasGoto) {
- LOG.info("hasGoto = true for " + node);
- node.setHasGoto();
- }
-
- private static void copyTerminal(final Node node, final Node sourceNode) {
- LOG.info("copy terminal flags " + sourceNode + " -> " + node);
- node.copyTerminalFlags(sourceNode);
- }
-
- private void addStatement(final Node statement, final boolean storeInLastStatement) {
- LOG.info("add statement = " + statement + " (lastStatement = " + lastStatement + ")");
- statements.add(statement);
- if (storeInLastStatement) {
- lastStatement = statement;
- }
- }
-
- private void addStatement(final Node statement) {
- addStatement(statement, true);
- }
-
- /**
- * Determine if Try block is inside target block.
- *
- * @param tryNode Try node to test.
- * @param target Target block.
- *
- * @return true if try block is inside the target, false otherwise.
- */
- private boolean isNestedTry(final TryNode tryNode, final Block target) {
- for(Iterator blocks = lexicalContext.getBlocks(getCurrentBlock()); blocks.hasNext();) {
- final Block block = blocks.next();
- if(block == target) {
- return false;
- }
- if(tryNode.isChildBlock(block)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Clones the body of the try finallys up to the target block.
- *
- * @param node first try node in the chain.
- * @param targetNode target block of the break/continue statement or null for return
- *
- * @return true if terminates.
- */
- private boolean copyFinally(final TryNode node, final Node targetNode) {
- Block target = null;
-
- if (targetNode instanceof Block) {
- target = (Block)targetNode;
- }
-
- for (TryNode tryNode = node; tryNode != null; tryNode = tryNode.getNext()) {
- if (target != null && !isNestedTry(tryNode, target)) {
- return false;
- }
-
- Block finallyBody = tryNode.getFinallyBody();
- if (finallyBody == null) {
- continue;
- }
-
- finallyBody = (Block)finallyBody.copy();
- final boolean hasTerminalFlags = finallyBody.hasTerminalFlags();
-
- new ExecuteNode(finallyBody.getSource(), finallyBody.getToken(), finallyBody.getFinish(), finallyBody).accept(this);
-
- if (hasTerminalFlags) {
- getCurrentBlock().copyTerminalFlags(finallyBody);
- return true;
- }
- }
-
- return false;
- }
-
- private Node enterBreakOrContinue(final LabeledNode labeledNode) {
- final TryNode tryNode = labeledNode.getTryChain();
- if (tryNode != null && copyFinally(tryNode, labeledNode.getTargetNode())) {
- return null;
- }
- addStatement(labeledNode);
- return null;
- }
-
-
/**
* An internal expression has a symbol that is tagged internal. Check if
* this is such a node
@@ -939,40 +637,21 @@ final class Lower extends NodeOperatorVisitor {
/**
* Is this an assignment to the special variable that hosts scripting eval
- * results?
+ * results, i.e. __return__?
*
* @param expression expression to check whether it is $evalresult = X
* @return true if an assignment to eval result, false otherwise
*/
- private boolean isEvalResultAssignment(final Node expression) {
+ private static boolean isEvalResultAssignment(final Node expression) {
Node e = expression;
- if (e.tokenType() == TokenType.DISCARD) {
- e = ((UnaryNode)expression).rhs();
- }
- final Node resultNode = getCurrentFunctionNode().getResultNode();
- return e instanceof BinaryNode && ((BinaryNode)e).lhs().equals(resultNode);
- }
-
- /**
- * Prepare special function nodes.
- * TODO : only create those that are needed.
- * TODO : make sure slot numbering is not hardcoded in {@link CompilerConstants} - now creation order is significant
- */
- private static void initFunctionNode(final FunctionNode functionNode) {
- final Source source = functionNode.getSource();
- final long token = functionNode.getToken();
- final int finish = functionNode.getFinish();
-
- functionNode.setThisNode(new IdentNode(source, token, finish, THIS.tag()));
- functionNode.setScopeNode(new IdentNode(source, token, finish, SCOPE.tag()));
- functionNode.setResultNode(new IdentNode(source, token, finish, SCRIPT_RETURN.tag()));
- functionNode.setCalleeNode(new IdentNode(source, token, finish, CALLEE.tag()));
- if (functionNode.isVarArg()) {
- functionNode.setVarArgsNode(new IdentNode(source, token, finish, VARARGS.tag()));
- if (functionNode.needsArguments()) {
- functionNode.setArgumentsNode(new IdentNode(source, token, finish, ARGUMENTS.tag()));
+ assert e.tokenType() != TokenType.DISCARD; //there are no discards this early anymore
+ if (e instanceof BinaryNode) {
+ final Node lhs = ((BinaryNode)e).lhs();
+ if (lhs instanceof IdentNode) {
+ return ((IdentNode)lhs).getName().equals(RETURN.symbolName());
}
}
+ return false;
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java
index ae40ed33bee..4fbb57a68cf 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java
@@ -53,9 +53,12 @@ import static jdk.internal.org.objectweb.asm.Opcodes.NEW;
import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
+import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
+import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS_DEBUGGER;
+import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
import static jdk.nashorn.internal.codegen.CompilerConstants.className;
import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
@@ -67,6 +70,7 @@ import java.lang.reflect.Array;
import java.util.ArrayDeque;
import java.util.EnumSet;
import java.util.Iterator;
+import java.util.List;
import jdk.internal.dynalink.support.NameCodec;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor;
@@ -79,14 +83,14 @@ import jdk.nashorn.internal.codegen.types.NumericType;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.RuntimeNode;
-import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.runtime.ArgumentSetter;
+import jdk.nashorn.internal.runtime.Debug;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.JSType;
-import jdk.nashorn.internal.runtime.Scope;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
@@ -116,10 +120,10 @@ public class MethodEmitter implements Emitter {
private final ClassEmitter classEmitter;
/** FunctionNode representing this method, or null if none exists */
- private FunctionNode functionNode;
+ protected FunctionNode functionNode;
- /** SplitNode representing the current split, or null if none exists */
- private SplitNode splitNode;
+ /** Check whether this emitter ever has a function return point */
+ private boolean hasReturn;
/** The script environment */
private final ScriptEnvironment env;
@@ -203,7 +207,7 @@ public class MethodEmitter implements Emitter {
@Override
public String toString() {
- return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + stack;
+ return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this);
}
/**
@@ -476,8 +480,8 @@ public class MethodEmitter implements Emitter {
String name = symbol.getName();
- if (name.equals(THIS.tag())) {
- name = THIS_DEBUGGER.tag();
+ if (name.equals(THIS.symbolName())) {
+ name = THIS_DEBUGGER.symbolName();
}
method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start, end, symbol.getSlot());
@@ -654,7 +658,7 @@ public class MethodEmitter implements Emitter {
* @return this method emitter
*/
MethodEmitter loadConstants() {
- getStatic(classEmitter.getUnitClassName(), CONSTANTS.tag(), CONSTANTS.descriptor());
+ getStatic(classEmitter.getUnitClassName(), CONSTANTS.symbolName(), CONSTANTS.descriptor());
assert peekType().isArray() : peekType();
return this;
}
@@ -669,7 +673,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter loadUndefined(final Type type) {
- debug("load undefined " + type);
+ debug("load undefined ", type);
pushType(type.loadUndefined(method));
return this;
}
@@ -681,7 +685,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter loadEmpty(final Type type) {
- debug("load empty " + type);
+ debug("load empty ", type);
pushType(type.loadEmpty(method));
return this;
}
@@ -814,7 +818,7 @@ public class MethodEmitter implements Emitter {
}
/**
- * Push an local variable to the stack. If the symbol representing
+ * Push a local variable to the stack. If the symbol representing
* the local variable doesn't have a slot, this is a NOP
*
* @param symbol the symbol representing the local variable.
@@ -835,13 +839,13 @@ public class MethodEmitter implements Emitter {
if (functionNode.needsArguments()) {
// ScriptObject.getArgument(int) on arguments
debug("load symbol", symbol.getName(), " arguments index=", index);
- loadArguments();
+ loadCompilerConstant(ARGUMENTS);
load(index);
ScriptObject.GET_ARGUMENT.invoke(this);
} else {
// array load from __varargs__
debug("load symbol", symbol.getName(), " array index=", index);
- loadVarArgs();
+ loadCompilerConstant(VARARGS);
load(symbol.getFieldIndex());
arrayload();
}
@@ -870,47 +874,12 @@ public class MethodEmitter implements Emitter {
if(functionNode == null) {
return slot == CompilerConstants.JAVA_THIS.slot();
}
- final int thisSlot = functionNode.getThisNode().getSymbol().getSlot();
+ final int thisSlot = compilerConstant(THIS).getSlot();
assert !functionNode.needsCallee() || thisSlot == 1; // needsCallee -> thisSlot == 1
assert functionNode.needsCallee() || thisSlot == 0; // !needsCallee -> thisSlot == 0
return slot == thisSlot;
}
- /**
- * Push the this object to the stack.
- *
- * @return the method emitter
- */
- MethodEmitter loadThis() {
- load(functionNode.getThisNode().getSymbol());
- return this;
- }
-
- /**
- * Push the scope object to the stack.
- *
- * @return the method emitter
- */
- MethodEmitter loadScope() {
- if (peekType() == Type.SCOPE) {
- dup();
- return this;
- }
- load(functionNode.getScopeNode().getSymbol());
- return this;
- }
-
- /**
- * Push the return object to the stack.
- *
- * @return the method emitter
- */
- MethodEmitter loadResult() {
- load(functionNode.getResultNode().getSymbol());
- return this;
- }
-
-
/**
* Push a method handle to the stack
*
@@ -927,62 +896,33 @@ public class MethodEmitter implements Emitter {
return this;
}
- /**
- * Push the varargs object to the stack
- *
- * @return the method emitter
- */
- MethodEmitter loadVarArgs() {
- debug("load var args " + functionNode.getVarArgsNode().getSymbol());
- return load(functionNode.getVarArgsNode().getSymbol());
+ private Symbol compilerConstant(final CompilerConstants cc) {
+ return functionNode.getBody().getExistingSymbol(cc.symbolName());
}
/**
- * Push the arguments array to the stack
- *
- * @return the method emitter
+ * True if this method has a slot allocated for the scope variable (meaning, something in the method actually needs
+ * the scope).
+ * @return if this method has a slot allocated for the scope variable.
*/
- MethodEmitter loadArguments() {
- debug("load arguments ", functionNode.getArgumentsNode().getSymbol());
- assert functionNode.getArgumentsNode().getSymbol().getSlot() != 0;
- return load(functionNode.getArgumentsNode().getSymbol());
+ boolean hasScope() {
+ return compilerConstant(SCOPE).hasSlot();
}
- /**
- * Push the callee object to the stack
- *
- * @return the method emitter
- */
- MethodEmitter loadCallee() {
- final Symbol calleeSymbol = functionNode.getCalleeNode().getSymbol();
- debug("load callee ", calleeSymbol);
- assert calleeSymbol.getSlot() == 0 : "callee has wrong slot " + calleeSymbol.getSlot() + " in " + functionNode.getName();
-
- return load(calleeSymbol);
+ MethodEmitter loadCompilerConstant(final CompilerConstants cc) {
+ final Symbol symbol = compilerConstant(cc);
+ if (cc == SCOPE && peekType() == Type.SCOPE) {
+ dup();
+ return this;
+ }
+ debug("load compiler constant ", symbol);
+ return load(symbol);
}
- /**
- * Pop the scope from the stack and store it in its predefined slot
- */
- void storeScope() {
- debug("store scope");
- store(functionNode.getScopeNode().getSymbol());
- }
-
- /**
- * Pop the return from the stack and store it in its predefined slot
- */
- void storeResult() {
- debug("store result");
- store(functionNode.getResultNode().getSymbol());
- }
-
- /**
- * Pop the arguments array from the stack and store it in its predefined slot
- */
- void storeArguments() {
- debug("store arguments");
- store(functionNode.getArgumentsNode().getSymbol());
+ void storeCompilerConstant(final CompilerConstants cc) {
+ final Symbol symbol = compilerConstant(cc);
+ debug("store compiler constant ", symbol);
+ store(symbol);
}
/**
@@ -1030,13 +970,13 @@ public class MethodEmitter implements Emitter {
final int index = symbol.getFieldIndex();
if (functionNode.needsArguments()) {
debug("store symbol", symbol.getName(), " arguments index=", index);
- loadArguments();
+ loadCompilerConstant(ARGUMENTS);
load(index);
ArgumentSetter.SET_ARGUMENT.invoke(this);
} else {
// varargs without arguments object - just do array store to __varargs__
debug("store symbol", symbol.getName(), " array index=", index);
- loadVarArgs();
+ loadCompilerConstant(VARARGS);
load(index);
ArgumentSetter.SET_ARRAY_ELEMENT.invoke(this);
}
@@ -1144,7 +1084,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter newarray(final ArrayType arrayType) {
- debug("newarray ", "arrayType=" + arrayType);
+ debug("newarray ", "arrayType=", arrayType);
popType(Type.INT); //LENGTH
pushType(arrayType.newarray(method));
return this;
@@ -1223,7 +1163,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter invokespecial(final String className, final String methodName, final String methodDescriptor) {
- debug("invokespecial", className + "." + methodName + methodDescriptor);
+ debug("invokespecial", className, ".", methodName, methodDescriptor);
return invoke(INVOKESPECIAL, className, methodName, methodDescriptor, true);
}
@@ -1237,7 +1177,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter invokevirtual(final String className, final String methodName, final String methodDescriptor) {
- debug("invokevirtual", className + "." + methodName + methodDescriptor + " " + stack);
+ debug("invokevirtual", className, ".", methodName, methodDescriptor, " ", stack);
return invoke(INVOKEVIRTUAL, className, methodName, methodDescriptor, true);
}
@@ -1251,7 +1191,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter invokestatic(final String className, final String methodName, final String methodDescriptor) {
- debug("invokestatic", className + "." + methodName + methodDescriptor);
+ debug("invokestatic", className, ".", methodName, methodDescriptor);
invoke(INVOKESTATIC, className, methodName, methodDescriptor, false);
return this;
}
@@ -1284,7 +1224,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter invokeinterface(final String className, final String methodName, final String methodDescriptor) {
- debug("invokeinterface", className + "." + methodName + methodDescriptor);
+ debug("invokeinterface", className, ".", methodName, methodDescriptor);
return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true);
}
@@ -1336,15 +1276,20 @@ public class MethodEmitter implements Emitter {
*/
void conditionalJump(final Condition cond, final boolean isCmpG, final Label trueLabel) {
if (peekType().isCategory2()) {
- debug("[ld]cmp isCmpG=" + isCmpG);
+ debug("[ld]cmp isCmpG=", isCmpG);
pushType(get2n().cmp(method, isCmpG));
jump(Condition.toUnary(cond), trueLabel, 1);
} else {
- debug("if" + cond);
+ debug("if", cond);
jump(Condition.toBinary(cond, peekType().isObject()), trueLabel, 2);
}
}
+ MethodEmitter registerReturn() {
+ this.hasReturn = true;
+ return this;
+ }
+
/**
* Perform a non void return, popping the type from the stack
*
@@ -1385,22 +1330,7 @@ public class MethodEmitter implements Emitter {
*
* @param label destination label
*/
- void splitAwareGoto(final Label label) {
-
- if (splitNode != null) {
- final int index = splitNode.getExternalTargets().indexOf(label);
-
- if (index > -1) {
- loadScope();
- checkcast(Scope.class);
- load(index + 1);
- invoke(Scope.SET_SPLIT_STATE);
- loadUndefined(Type.OBJECT);
- _return(functionNode.getReturnType());
- return;
- }
- }
-
+ void splitAwareGoto(final LexicalContext lc, final Label label) {
_goto(label);
}
@@ -1595,7 +1525,7 @@ public class MethodEmitter implements Emitter {
*/
private void mergeStackTo(final Label label) {
final ArrayDeque labelStack = label.getStack();
- //debug(labelStack == null ? " >> Control flow - first visit " + label : " >> Control flow - JOIN with " + labelStack + " at " + label);
+ //debug(labelStack == null ? " >> Control flow - first visit ", label : " >> Control flow - JOIN with ", labelStack, " at ", label);
if (labelStack == null) {
assert stack != null;
label.setStack(stack.clone());
@@ -1788,7 +1718,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter dynamicNew(final int argCount, final int flags) {
- debug("dynamic_new", "argcount=" + argCount);
+ debug("dynamic_new", "argcount=", argCount);
final String signature = getDynamicSignature(Type.OBJECT, argCount);
method.visitInvokeDynamicInsn("dyn:new", signature, LINKERBOOTSTRAP, flags);
pushType(Type.OBJECT); //TODO fix result type
@@ -1805,7 +1735,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags) {
- debug("dynamic_call", "args=" + argCount, "returnType=" + returnType);
+ debug("dynamic_call", "args=", argCount, "returnType=", returnType);
final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target)
debug(" signature", signature);
method.visitInvokeDynamicInsn("dyn:call", signature, LINKERBOOTSTRAP, flags);
@@ -1824,7 +1754,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter dynamicRuntimeCall(final String name, final Type returnType, final RuntimeNode.Request request) {
- debug("dynamic_runtime_call", name, "args=" + request.getArity(), "returnType=" + returnType);
+ debug("dynamic_runtime_call", name, "args=", request.getArity(), "returnType=", returnType);
final String signature = getDynamicSignature(returnType, request.getArity());
debug(" signature", signature);
method.visitInvokeDynamicInsn(name, signature, RUNTIMEBOOTSTRAP);
@@ -1895,7 +1825,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) {
- debug("dynamic_get_index", peekType(1) + "[" + peekType() + "]");
+ debug("dynamic_get_index", peekType(1), "[", peekType(), "]");
Type resultType = result;
if (result.isBoolean()) {
@@ -1931,7 +1861,7 @@ public class MethodEmitter implements Emitter {
* @param flags call site flags for setter
*/
void dynamicSetIndex(final int flags) {
- debug("dynamic_set_index", peekType(2) + "[" + peekType(1) + "] =", peekType());
+ debug("dynamic_set_index", peekType(2), "[", peekType(1), "] =", peekType());
Type value = peekType();
if (value.isObject() || value.isBoolean()) {
@@ -2031,7 +1961,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter getField(final String className, final String fieldName, final String fieldDescriptor) {
- debug("getfield", "receiver=" + peekType(), className + "." + fieldName + fieldDescriptor);
+ debug("getfield", "receiver=", peekType(), className, ".", fieldName, fieldDescriptor);
final Type receiver = popType();
assert receiver.isObject();
method.visitFieldInsn(GETFIELD, className, fieldName, fieldDescriptor);
@@ -2049,7 +1979,7 @@ public class MethodEmitter implements Emitter {
* @return the method emitter
*/
MethodEmitter getStatic(final String className, final String fieldName, final String fieldDescriptor) {
- debug("getstatic", className + "." + fieldName + "." + fieldDescriptor);
+ debug("getstatic", className, ".", fieldName, ".", fieldDescriptor);
method.visitFieldInsn(GETSTATIC, className, fieldName, fieldDescriptor);
pushType(fieldType(fieldDescriptor));
return this;
@@ -2063,7 +1993,7 @@ public class MethodEmitter implements Emitter {
* @param fieldDescriptor field descriptor
*/
void putField(final String className, final String fieldName, final String fieldDescriptor) {
- debug("putfield", "receiver=" + peekType(1), "value=" + peekType());
+ debug("putfield", "receiver=", peekType(1), "value=", peekType());
popType(fieldType(fieldDescriptor));
popType(Type.OBJECT);
method.visitFieldInsn(PUTFIELD, className, fieldName, fieldDescriptor);
@@ -2077,7 +2007,7 @@ public class MethodEmitter implements Emitter {
* @param fieldDescriptor field descriptor
*/
void putStatic(final String className, final String fieldName, final String fieldDescriptor) {
- debug("putfield", "value=" + peekType());
+ debug("putfield", "value=", peekType());
popType(fieldType(fieldDescriptor));
method.visitFieldInsn(PUTSTATIC, className, fieldName, fieldDescriptor);
}
@@ -2237,7 +2167,7 @@ public class MethodEmitter implements Emitter {
}
if (env != null) { //early bootstrap code doesn't have inited context yet
- LOG.info(sb.toString());
+ LOG.info(sb);
if (DEBUG_TRACE_LINE == linePrefix) {
new Throwable().printStackTrace(LOG.getOutputStream());
}
@@ -2254,21 +2184,12 @@ public class MethodEmitter implements Emitter {
this.functionNode = functionNode;
}
- /**
- * Get the split node for this method emitter, if this is code
- * generation due to splitting large methods
- *
- * @return split node
- */
- SplitNode getSplitNode() {
- return splitNode;
+ boolean hasReturn() {
+ return hasReturn;
}
- /**
- * Set the split node for this method emitter
- * @param splitNode split node
- */
- void setSplitNode(final SplitNode splitNode) {
- this.splitNode = splitNode;
+ List