org.apache.royale.abc.semantics.MethodBodyInfo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of compiler Show documentation
Show all versions of compiler Show documentation
The Apache Royale Compiler
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.royale.abc.semantics;
import java.util.Collections;
import java.util.List;
import java.util.Vector;
import org.apache.royale.abc.graph.IBasicBlock;
import org.apache.royale.abc.graph.IFlowgraph;
import org.apache.royale.abc.instructionlist.InstructionList;
import org.apache.royale.abc.visitors.IDiagnosticsVisitor;
import static org.apache.royale.abc.ABCConstants.*;
/**
* A representation of a method's method body information.
*/
public class MethodBodyInfo
{
/**
* Construct a new MethodBodyInfo.
*/
public MethodBodyInfo()
{
}
MethodInfo methodInfo;
public int max_stack;
public int max_scope;
public int initial_scope;
public int max_local;
public int max_slot;
public int code_len;
Integer explicit_max_stack;
Integer explicit_init_scope;
Integer explicit_max_scope;
Integer explicit_max_local;
Integer explicit_max_slot;
Traits traits = new Traits();
/**
* Does this method body contain a newclass instruction? Higher-level code
* needs to know this because the ABC may have its class info structures
* sorted into dependency order, which would invalidate the index in the
* newclass instruction if the method body were serialized to bytecode.
*/
private boolean hasNewclass = false;
private Vector exceptions = new Vector();
/**
* The method's instructions as a simple list.
*/
InstructionList instructions = new InstructionList();
/**
* The method's control flow graph. The ControlFlowGraph is only available
* and valid when the method's instructions are in their deserialized form.
*/
IFlowgraph cfg = null;
/**
* The method's instructions after being converted into ABC bytecode.
*/
byte[] bytecode = null;
public MethodInfo getMethodInfo()
{
return this.methodInfo;
}
public void setMethodInfo(MethodInfo minfo)
{
this.methodInfo = minfo;
}
/**
* @return the method's traits.
*/
public Traits getTraits()
{
return traits;
}
/**
* Set the method's traits.
*
* @param t - the method's traits.
*/
public void setTraits(Traits t)
{
this.traits = t;
}
/**
* Set this method's serialized ABC.
*
* @param bytecode - the method's instructions serialized to ABC bytecode.
* @post the method's InstructionList based bytecode is no longer available.
*/
public void setBytecode(final byte[] bytecode)
{
this.bytecode = bytecode;
this.instructions = null;
this.cfg = null;
}
/**
* Retrieve this method's bytecode.
*
* @return previously serialized bytecode.
* @pre setBytecode() called to store the bytecode.
*/
public byte[] getBytecode()
{
assert this.bytecode != null;
return this.bytecode;
}
/**
* Has this method been serialized to bytecode?
*
* @return true if the method's serialized bytecode is set.
*/
public boolean hasBytecode()
{
return this.bytecode != null;
}
/**
* Get the method's control flow graph, building it as necessary.
*
* @return the method's control flow graph.
* @pre the method must not have been serialized to ABC.
*/
public IFlowgraph getCfg()
{
if (null == this.cfg)
rebuildCfg();
return this.cfg;
}
/**
* Rebuild the control flow graph.
*/
private void rebuildCfg()
{
// Note that it would be possible to deserialize the method and then construct a CFG.
assert instructions != null : "Unable to build control flow graph after serialization to ABC";
this.cfg = new ControlFlowGraph(this);
}
public Instruction insn(int opcode)
{
return this.instructions.addInstruction(opcode);
}
public Instruction insn(int opcode, Object[] operands)
{
Instruction result = InstructionFactory.getInstruction(opcode, operands);
this.instructions.addInstruction(result);
return result;
}
public Instruction insn(int opcode, Object pooledValue)
{
Instruction i = InstructionFactory.getInstruction(opcode, pooledValue);
this.instructions.addInstruction(i);
return i;
}
public Instruction insn(int opcode, int immed)
{
Instruction i = InstructionFactory.getInstruction(opcode, immed);
this.instructions.addInstruction(i);
return i;
}
public void insn(Instruction instruction)
{
this.instructions.addInstruction(instruction);
}
/**
* Compute a functions's max_stack, max_scope, and slot count.
*
* @note noop if all counts were explicitly provided.
*/
public void computeFrameCounts(IDiagnosticsVisitor diagnosticsVisitor)
{
if (this.explicit_max_stack != null && this.explicit_max_scope != null && this.explicit_max_local != null && this.explicit_max_slot != null)
{
// All counts explicitly provided.
return;
}
FrameCountVisitor counts = new FrameCountVisitor(this, diagnosticsVisitor, this.initial_scope);
getCfg().traverseGraph(counts);
// Grrr.. TODO when we tighten up the max_stack,
// max_scope, etc for code we read out of the flex
// framework we seem to break that code.
// For now, never let the max_stack, etc go down.
this.max_stack = Math.max(counts.max_stack, this.max_stack);
this.max_scope = Math.max(counts.max_scope, this.max_scope);
this.max_local = Math.max(counts.max_local, this.max_local);
this.max_slot = Math.max(counts.max_slot, this.max_slot);
this.hasNewclass |= counts.hasNewclassInstruction();
}
public int getMaxStack()
{
if (explicit_max_stack != null)
return explicit_max_stack;
else
return max_stack;
}
public int getLocalCount()
{
if (explicit_max_local != null)
return explicit_max_local;
else if ((this.methodInfo.getFlags() & NEED_REST) != 0)
return max_local + 1;
else
return max_local;
}
public int getMaxSlotCount()
{
if (explicit_max_slot != null)
return explicit_max_slot;
else if (max_slot < traits.getTraitCount())
return traits.getTraitCount();
else
return max_slot;
}
public int getMaxScopeDepth()
{
if (explicit_max_scope != null)
return explicit_max_scope;
else
return max_scope;
}
public int addExceptionInfo(ExceptionInfo ex)
{
this.exceptions.add(ex);
return this.exceptions.size() - 1; // zero-based exception numbers
}
public int getInitScopeDepth()
{
if (this.explicit_init_scope != null)
return explicit_init_scope;
else
return this.initial_scope;
}
/**
* Get the block that the label corresponds to. Will throw an
* IllegalArgumentException if the label does not correspond to any known
* block.
*
* @param target the label you want the block for
* @return the block that the label refers to.
*/
public IBasicBlock getBlock(Label target)
{
return getBlock(target, true);
}
/**
* Get the block that the label corresponds to. Will throw an
* IllegalArgumentException if the label does not correspond to any known
* block, and throwOnError is true.
*
* @param target the label you want the block for
* @param throwOnError false if you do not want this method to throw an
* IllegalArgumentException - in this case the method will return null
* instead.
* @return the block that the label refers to.
*/
public IBasicBlock getBlock(Label target, boolean throwOnError)
{
IBasicBlock result = cfg.getBlock(target);
if (result == null && throwOnError)
throw new IllegalArgumentException("Label " + target.toString() + " was referenced, but never defined.");
return result;
}
/**
* @return exception handlers defined in this method.
*/
public List getExceptions()
{
if (this.exceptions != null)
return exceptions;
else
return Collections.emptyList();
}
/**
* Does the given Label reference a catch target?
* @param l - the Label of interest.
* @return true if the Label references a catch target,
* either by identity or by position.
*/
public boolean isCatchTarget(Label l)
{
for (ExceptionInfo e : exceptions)
{
Label target = e.getTarget();
if ( l.getPosition() == target.getPosition() || l == target )
return true;
}
return false;
}
/**
* Set this method body's InstructionList. Used by code generators that
* build up an InstructionList from smaller parts; not relevant if the
* InstructionList is built by visitInstruction() calls on this object.
*/
public void setInstructionList(InstructionList new_list)
{
this.instructions = new_list;
if (this.cfg != null)
rebuildCfg();
}
/**
* @return this method body's InstructionList.
*/
public InstructionList getInstructionList()
{
assert (this.instructions != null) : "No active InstructionList";
return this.instructions;
}
/**
* Pass through a labelCurrent() request to the resident InstructionList.
*/
public void labelCurrent(Label l)
{
assert (this.instructions != null) : "No active InstructionList";
this.instructions.labelCurrent(l);
}
/**
* Pass through a labelNext() request to the resident InstructionList.
*/
public void labelNext(Label l)
{
assert (this.instructions != null) : "No active InstructionList";
this.instructions.labelNext(l);
}
/**
* Does this method body contain a newclass instruction?
*
* @pre computeFrameCounts() must have been called.
*/
public boolean hasNewclassInstruction()
{
return this.hasNewclass;
}
}