compilestack.java
来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 653 行 · 第 1/2 页
JAVA
653 行
scope = null;
mv=null;
resetVariableIndex(false);
superBlockNamedLabels.clear();
currentBlockNamedLabels.clear();
namedLoopBreakLabel.clear();
namedLoopContinueLabel.clear();
continueLabel=null;
breakLabel=null;
helper = null;
thisStartLabel=null;
thisEndLabel=null;
}
/**
* initializes this class for a MethodNode. This method will
* automatically define varibales for the method parameters
* and will create references if needed. the created variables
* can be get by getVariable
*
*/
protected void init(VariableScope el, Parameter[] parameters, MethodVisitor mv, ClassNode cn) {
if (!clear) throw new GroovyBugError("CompileStack#init called without calling clear before");
clear=false;
pushVariableScope(el);
this.mv = mv;
this.helper = new BytecodeHelper(mv);
defineMethodVariables(parameters,el.isInStaticContext());
this.className = BytecodeHelper.getTypeDescription(cn);
currentClassIndex = -1; currentMetaClassIndex = -1;
}
/**
* Causes the statestack to add an element and sets
* the given scope as new current variable scope. Creates
* a element for the state stack so pop has to be called later
*/
protected void pushVariableScope(VariableScope el) {
pushState();
scope = el;
superBlockNamedLabels = new HashMap(superBlockNamedLabels);
superBlockNamedLabels.putAll(currentBlockNamedLabels);
currentBlockNamedLabels = new HashMap();
}
/**
* Should be called when decending into a loop that defines
* also a scope. Calls pushVariableScope and prepares labels
* for a loop structure. Creates a element for the state stack
* so pop has to be called later
*/
protected void pushLoop(VariableScope el, String labelName) {
pushVariableScope(el);
initLoopLabels(labelName);
}
private void initLoopLabels(String labelName) {
continueLabel = new Label();
breakLabel = new Label();
if (labelName!=null) {
namedLoopBreakLabel.put(labelName,breakLabel);
namedLoopContinueLabel.put(labelName,continueLabel);
}
}
/**
* Should be called when decending into a loop that does
* not define a scope. Creates a element for the state stack
* so pop has to be called later
*/
protected void pushLoop(String labelName) {
pushState();
initLoopLabels(labelName);
}
/**
* Used for <code>break foo</code> inside a loop to end the
* execution of the marked loop. This method will return the
* break label of the loop if there is one found for the name.
* If not, the current break label is returned.
*/
protected Label getNamedBreakLabel(String name) {
Label label = getBreakLabel();
Label endLabel = null;
if (name!=null) endLabel = (Label) namedLoopBreakLabel.get(name);
if (endLabel!=null) label = endLabel;
return label;
}
/**
* Used for <code>continue foo</code> inside a loop to continue
* the execution of the marked loop. This method will return
* the break label of the loop if there is one found for the
* name. If not, getLabel is used.
*/
protected Label getNamedContinueLabel(String name) {
Label label = getLabel(name);
Label endLabel = null;
if (name!=null) endLabel = (Label) namedLoopContinueLabel.get(name);
if (endLabel!=null) label = endLabel;
return label;
}
/**
* Creates a new break label and a element for the state stack
* so pop has to be called later
*/
protected Label pushSwitch(){
pushState();
breakLabel = new Label();
return breakLabel;
}
/**
* because a boolean Expression may not be evaluated completly
* it is important to keep the registers clean
*/
protected void pushBooleanExpression(){
pushState();
}
private Variable defineVar(String name, ClassNode type, boolean methodParameterUsedInClosure) {
makeNextVariableID(type);
int index = currentVariableIndex;
if (methodParameterUsedInClosure) {
index = localVariableOffset++;
}
Variable answer = new Variable(index, type, name);
usedVariables.add(answer);
answer.setHolder(methodParameterUsedInClosure);
return answer;
}
private void makeLocalVariablesOffset(Parameter[] paras,boolean isInStaticContext) {
resetVariableIndex(isInStaticContext);
for (int i = 0; i < paras.length; i++) {
makeNextVariableID(paras[i].getType());
}
localVariableOffset = nextVariableIndex;
resetVariableIndex(isInStaticContext);
}
private void defineMethodVariables(Parameter[] paras,boolean isInStaticContext) {
Label startLabel = new Label();
thisStartLabel = startLabel;
mv.visitLabel(startLabel);
makeLocalVariablesOffset(paras,isInStaticContext);
boolean hasHolder = false;
for (int i = 0; i < paras.length; i++) {
String name = paras[i].getName();
Variable answer;
if (paras[i].isClosureSharedVariable()) {
answer = defineVar(name, ClassHelper.getWrapper(paras[i].getType()), true);
ClassNode type = paras[i].getType();
helper.load(type,currentVariableIndex);
helper.box(type);
createReference(answer);
hasHolder = true;
} else {
answer = defineVar(name,paras[i].getType(),false);
}
answer.setStartLabel(startLabel);
stackVariables.put(name, answer);
}
if (hasHolder) {
nextVariableIndex = localVariableOffset;
}
}
private void createReference(Variable reference) {
mv.visitTypeInsn(NEW, "groovy/lang/Reference");
mv.visitInsn(DUP_X1);
mv.visitInsn(SWAP);
mv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "(Ljava/lang/Object;)V");
mv.visitVarInsn(ASTORE, reference.getIndex());
}
/**
* Defines a new Variable using an AST variable.
* @param initFromStack if true the last element of the
* stack will be used to initilize
* the new variable. If false null
* will be used.
*/
public Variable defineVariable(org.codehaus.groovy.ast.Variable v, boolean initFromStack) {
String name = v.getName();
Variable answer = defineVar(name,v.getType(),false);
if (v.isClosureSharedVariable()) answer.setHolder(true);
stackVariables.put(name, answer);
Label startLabel = new Label();
answer.setStartLabel(startLabel);
if (answer.isHolder()) {
if (!initFromStack) mv.visitInsn(ACONST_NULL);
createReference(answer);
} else {
if (!initFromStack) mv.visitInsn(ACONST_NULL);
mv.visitVarInsn(ASTORE, currentVariableIndex);
}
mv.visitLabel(startLabel);
return answer;
}
/**
* Returns true if a varibale is already defined
*/
public boolean containsVariable(String name) {
return stackVariables.containsKey(name);
}
/**
* Calculates the index of the next free register stores ir
* and sets the current variable index to the old value
*/
private void makeNextVariableID(ClassNode type) {
currentVariableIndex = nextVariableIndex;
if (type==ClassHelper.long_TYPE || type==ClassHelper.double_TYPE) {
nextVariableIndex++;
}
nextVariableIndex++;
}
/**
* Returns the label for the given name
*/
public Label getLabel(String name) {
if (name==null) return null;
Label l = (Label) superBlockNamedLabels.get(name);
if (l==null) l = createLocalLabel(name);
return l;
}
/**
* creates a new named label
*/
public Label createLocalLabel(String name) {
Label l = (Label) currentBlockNamedLabels.get(name);
if (l==null) {
l = new Label();
currentBlockNamedLabels.put(name,l);
}
return l;
}
public int getCurrentClassIndex(){
return currentClassIndex;
}
public void setCurrentClassIndex(int index){
currentClassIndex=index;
}
public int getCurrentMetaClassIndex(){
return currentMetaClassIndex;
}
public void setCurrentMetaClassIndex(int index){
currentMetaClassIndex=index;
}
public void applyFinallyBlocks(Label label, boolean isBreakLabel) {
// first find the state defining the label. That is the state
// directly after the state not knowing this label. If no state
// in the list knows that label, then the defining state is the
// current state.
StateStackElement result = null;
for (ListIterator iter = stateStack.listIterator(stateStack.size()); iter.hasPrevious();) {
StateStackElement element = (StateStackElement) iter.previous();
if (!element._currentBlockNamedLabels.values().contains(label)) {
if (isBreakLabel && element._breakLabel != label) {
result = element;
break;
}
if (!isBreakLabel && element._continueLabel != label) {
result = element;
break;
}
}
}
List blocksToRemove;
if (result==null) {
// all Blocks do know the label, so use all finally blocks
blocksToRemove = Collections.EMPTY_LIST;
} else {
blocksToRemove = result._finallyBlocks;
}
ArrayList blocks = new ArrayList(finallyBlocks);
blocks.removeAll(blocksToRemove);
applyFinallyBlocks(blocks);
}
private void applyFinallyBlocks(List blocks) {
for (Iterator iter = blocks.iterator(); iter.hasNext();) {
Runnable block = (Runnable) iter.next();
if (visitedBlocks.contains(block)) continue;
visitedBlocks.add(block);
block.run();
}
}
public void applyFinallyBlocks() {
applyFinallyBlocks(finallyBlocks);
}
public boolean hasFinallyBlocks() {
return !finallyBlocks.isEmpty();
}
public void pushFinallyBlock(Runnable block) {
finallyBlocks.addFirst(block);
pushState();
}
public void popFinallyBlock() {
popState();
finallyBlocks.removeFirst();
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?