2012-09-04 22:56:05 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* Copyright (c) 2002 - 2006 IBM Corporation.
|
|
|
|
* All rights reserved. This program and the accompanying materials
|
|
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
|
|
* which accompanies this distribution, and is available at
|
|
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
|
|
*
|
|
|
|
* Contributors:
|
|
|
|
* IBM Corporation - initial API and implementation
|
|
|
|
*****************************************************************************/
|
|
|
|
package com.ibm.wala.cast.ir.translator;
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
import java.util.LinkedHashSet;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
import com.ibm.wala.cast.ir.ssa.AssignInstruction;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.AstAssertInstruction;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.AstConstants;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.AstEchoInstruction;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.AstGlobalRead;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.AstGlobalWrite;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.AstIsDefinedInstruction;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.AstLexicalRead;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.AstLexicalWrite;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.EachElementGetInstruction;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.SSAConversion;
|
2013-06-06 23:18:16 +00:00
|
|
|
import com.ibm.wala.cast.loader.AstMethod;
|
2012-09-04 22:56:05 +00:00
|
|
|
import com.ibm.wala.cast.loader.AstMethod.DebuggingInformation;
|
|
|
|
import com.ibm.wala.cast.loader.AstMethod.LexicalInformation;
|
|
|
|
import com.ibm.wala.cast.loader.CAstAbstractLoader;
|
|
|
|
import com.ibm.wala.cast.tree.CAstControlFlowMap;
|
|
|
|
import com.ibm.wala.cast.tree.CAstEntity;
|
|
|
|
import com.ibm.wala.cast.tree.CAstNode;
|
|
|
|
import com.ibm.wala.cast.tree.CAstSourcePositionMap;
|
|
|
|
import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
|
|
|
|
import com.ibm.wala.cast.tree.CAstSymbol;
|
|
|
|
import com.ibm.wala.cast.tree.CAstType;
|
|
|
|
import com.ibm.wala.cast.tree.impl.CAstImpl;
|
|
|
|
import com.ibm.wala.cast.tree.impl.CAstOperator;
|
|
|
|
import com.ibm.wala.cast.tree.impl.CAstSymbolImpl;
|
|
|
|
import com.ibm.wala.cast.tree.impl.CAstSymbolImplBase;
|
2012-10-03 14:53:04 +00:00
|
|
|
import com.ibm.wala.cast.tree.rewrite.CAstCloner;
|
|
|
|
import com.ibm.wala.cast.tree.rewrite.CAstRewriter;
|
2012-09-04 22:56:05 +00:00
|
|
|
import com.ibm.wala.cast.tree.visit.CAstVisitor;
|
|
|
|
import com.ibm.wala.cast.types.AstTypeReference;
|
|
|
|
import com.ibm.wala.cast.util.CAstPrinter;
|
|
|
|
import com.ibm.wala.cfg.AbstractCFG;
|
|
|
|
import com.ibm.wala.cfg.IBasicBlock;
|
2013-06-06 23:18:16 +00:00
|
|
|
import com.ibm.wala.classLoader.CallSiteReference;
|
2012-09-04 22:56:05 +00:00
|
|
|
import com.ibm.wala.classLoader.IClassLoader;
|
|
|
|
import com.ibm.wala.classLoader.IMethod;
|
|
|
|
import com.ibm.wala.classLoader.ModuleEntry;
|
2013-06-06 23:18:16 +00:00
|
|
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
2012-09-04 22:56:05 +00:00
|
|
|
import com.ibm.wala.shrikeBT.BinaryOpInstruction;
|
|
|
|
import com.ibm.wala.shrikeBT.ConditionalBranchInstruction;
|
|
|
|
import com.ibm.wala.shrikeBT.IBinaryOpInstruction;
|
|
|
|
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction;
|
|
|
|
import com.ibm.wala.shrikeBT.IUnaryOpInstruction;
|
|
|
|
import com.ibm.wala.shrikeBT.ShiftInstruction;
|
|
|
|
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
|
2014-07-08 18:44:06 +00:00
|
|
|
import com.ibm.wala.ssa.SSAConditionalBranchInstruction;
|
2012-09-04 22:56:05 +00:00
|
|
|
import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction;
|
2013-07-30 18:04:08 +00:00
|
|
|
import com.ibm.wala.ssa.SSAGotoInstruction;
|
2012-09-04 22:56:05 +00:00
|
|
|
import com.ibm.wala.ssa.SSAInstruction;
|
|
|
|
import com.ibm.wala.ssa.SSAInstructionFactory;
|
|
|
|
import com.ibm.wala.ssa.SSAMonitorInstruction;
|
|
|
|
import com.ibm.wala.ssa.SymbolTable;
|
|
|
|
import com.ibm.wala.types.FieldReference;
|
|
|
|
import com.ibm.wala.types.TypeName;
|
|
|
|
import com.ibm.wala.types.TypeReference;
|
2013-04-09 22:47:22 +00:00
|
|
|
import com.ibm.wala.util.collections.HashMapFactory;
|
2012-09-04 22:56:05 +00:00
|
|
|
import com.ibm.wala.util.collections.HashSetFactory;
|
|
|
|
import com.ibm.wala.util.collections.MapUtil;
|
|
|
|
import com.ibm.wala.util.collections.Pair;
|
|
|
|
import com.ibm.wala.util.debug.Assertions;
|
|
|
|
import com.ibm.wala.util.graph.INodeWithNumber;
|
|
|
|
import com.ibm.wala.util.graph.impl.SparseNumberedGraph;
|
2013-04-09 22:47:22 +00:00
|
|
|
import com.ibm.wala.util.graph.traverse.DFS;
|
2012-09-04 22:56:05 +00:00
|
|
|
import com.ibm.wala.util.intset.IntSet;
|
|
|
|
import com.ibm.wala.util.intset.IntSetUtil;
|
|
|
|
import com.ibm.wala.util.intset.MutableIntSet;
|
|
|
|
import com.ibm.wala.util.strings.Atom;
|
|
|
|
import com.ibm.wala.util.warnings.Warning;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Common code to translate CAst to IR. Must be specialized by each language to
|
|
|
|
* handle semantics appropriately.
|
|
|
|
*/
|
|
|
|
public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContext> implements ArrayOpHandler, TranslatorToIR {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* does the language care about using type-appropriate default values? For
|
|
|
|
* Java, the answer is yes (ints should get a default value of 0, null for
|
|
|
|
* pointers, etc.). For JavaScript, the answer is no, as any variable can hold
|
|
|
|
* the value 'undefined'.
|
|
|
|
*/
|
|
|
|
protected abstract boolean useDefaultInitValues();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* can lexical reads / writes access globals?
|
|
|
|
*/
|
|
|
|
protected abstract boolean treatGlobalsAsLexicallyScoped();
|
|
|
|
|
|
|
|
protected boolean topLevelFunctionsInGlobalScope() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* for a block that catches all exceptions, what is the root exception type
|
|
|
|
* that it can catch? E.g., for Java, java.lang.Throwable
|
|
|
|
*/
|
|
|
|
protected abstract TypeReference defaultCatchType();
|
|
|
|
|
|
|
|
protected abstract TypeReference makeType(CAstType type);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* define a new (presumably nested) type. return true if type was successfully
|
|
|
|
* defined, false otherwise
|
|
|
|
*/
|
|
|
|
protected abstract boolean defineType(CAstEntity type, WalkContext wc);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* declare a new function, represented by N
|
|
|
|
*/
|
|
|
|
protected abstract void declareFunction(CAstEntity N, WalkContext context);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* fully define a function. invoked after all the code of the function has
|
|
|
|
* been processed
|
|
|
|
*/
|
|
|
|
protected abstract void defineFunction(CAstEntity N, WalkContext definingContext, AbstractCFG cfg, SymbolTable symtab,
|
2013-04-11 01:09:10 +00:00
|
|
|
boolean hasCatchBlock, Map<IBasicBlock, TypeReference[]> catchTypes, boolean hasMonitorOp, AstLexicalInformation lexicalInfo,
|
2012-09-04 22:56:05 +00:00
|
|
|
DebuggingInformation debugInfo);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* define a new field fieldEntity within topEntity
|
|
|
|
*/
|
|
|
|
protected abstract void defineField(CAstEntity topEntity, WalkContext context, CAstEntity fieldEntity);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* create the language-appropriate name for f
|
|
|
|
*/
|
|
|
|
protected abstract String composeEntityName(WalkContext parent, CAstEntity f);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate IR for a CAst throw expression, updating context.cfg()
|
|
|
|
*/
|
|
|
|
protected abstract void doThrow(WalkContext context, int exception);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate IR for a CAst array read, updating context.cfg()
|
|
|
|
*/
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public abstract void doArrayRead(WalkContext context, int result, int arrayValue, CAstNode arrayRef, int[] dimValues);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate IR for a CAst array write, updating context.cfg()
|
|
|
|
*/
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public abstract void doArrayWrite(WalkContext context, int arrayValue, CAstNode arrayRef, int[] dimValues, int rval);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate IR for a CAst field read, updating context.cfg()
|
|
|
|
*/
|
|
|
|
protected abstract void doFieldRead(WalkContext context, int result, int receiver, CAstNode elt, CAstNode parent);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate IR for a CAst field write, updating context.cfg()
|
|
|
|
*/
|
|
|
|
protected abstract void doFieldWrite(WalkContext context, int receiver, CAstNode elt, CAstNode parent, int rval);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate IR for a CAst function expression, updating context.cfg()
|
|
|
|
*/
|
|
|
|
protected abstract void doMaterializeFunction(CAstNode node, WalkContext context, int result, int exception, CAstEntity fn);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate IR for a CAst new expression, updating context.cfg()
|
|
|
|
*/
|
|
|
|
protected abstract void doNewObject(WalkContext context, CAstNode newNode, int result, Object type, int[] arguments);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate IR for a CAst method call expression, updating context.cfg()
|
|
|
|
*/
|
|
|
|
protected abstract void doCall(WalkContext context, CAstNode call, int result, int exception, CAstNode name, int receiver,
|
|
|
|
int[] arguments);
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
/**
|
|
|
|
* the most-general type for the language being translated
|
|
|
|
*/
|
|
|
|
protected abstract CAstType topType();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* the most-general exception type for the language being translated
|
|
|
|
*/
|
|
|
|
protected abstract CAstType exceptionType();
|
|
|
|
|
2012-09-04 22:56:05 +00:00
|
|
|
/**
|
|
|
|
* used to generate instructions for array operations; defaults to this
|
|
|
|
*/
|
|
|
|
private ArrayOpHandler arrayOpHandler;
|
|
|
|
|
|
|
|
protected boolean isExceptionLabel(Object label) {
|
|
|
|
if (label == null)
|
|
|
|
return false;
|
|
|
|
if (label instanceof Boolean)
|
|
|
|
return false;
|
|
|
|
if (label instanceof Number)
|
|
|
|
return false;
|
|
|
|
if (label == CAstControlFlowMap.SWITCH_DEFAULT)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If this returns true, new global declarations get created for any attempt
|
|
|
|
* to access a non-existent variable (believe it or not, JavaScript actually
|
|
|
|
* does this!)
|
|
|
|
*/
|
|
|
|
protected boolean hasImplicitGlobals() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If this returns true, then attempts to lookup non-existent names return
|
|
|
|
* `null' rather than tripping an assertion. This can be used when special
|
|
|
|
* handling is needed for built-in names. (PHP does this)
|
|
|
|
*/
|
|
|
|
protected boolean hasSpecialUndeclaredVariables() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* some languages let you omit initialization of certain fields when writing
|
|
|
|
* an object literal (e.g., PHP). This method should be overridden to handle
|
|
|
|
* such cases.
|
|
|
|
*/
|
|
|
|
protected void handleUnspecifiedLiteralKey(WalkContext context, CAstNode objectLiteralNode, int unspecifiedLiteralIndex,
|
|
|
|
CAstVisitor<WalkContext> visitor) {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate prologue code for each function body
|
|
|
|
*/
|
|
|
|
protected void doPrologue(WalkContext context) {
|
2013-06-07 16:58:25 +00:00
|
|
|
// perform a lexical write to copy the value stored in the local
|
|
|
|
// associated with each parameter to the lexical name
|
|
|
|
final CAstEntity entity = context.top();
|
|
|
|
Set<String> exposedNames = entity2ExposedNames.get(entity);
|
|
|
|
if (exposedNames != null) {
|
2014-03-16 22:05:49 +00:00
|
|
|
int i = 0;
|
2013-06-07 16:58:25 +00:00
|
|
|
for (String arg : entity.getArgumentNames()) {
|
|
|
|
if (exposedNames.contains(arg)) {
|
|
|
|
final Scope currentScope = context.currentScope();
|
|
|
|
Symbol symbol = currentScope.lookup(arg);
|
|
|
|
assert symbol.getDefiningScope() == currentScope;
|
|
|
|
int argVN = symbol.valueNumber();
|
2014-03-16 22:05:49 +00:00
|
|
|
CAstType type = (entity.getType() instanceof CAstType.Method)?
|
|
|
|
(CAstType)((CAstType.Method)entity.getType()).getArgumentTypes().get(i):
|
|
|
|
topType();
|
|
|
|
Access A = new Access(arg, context.getEntityName(entity), makeType(type), argVN);
|
2014-04-09 15:33:57 +00:00
|
|
|
context.cfg().addInstruction(new AstLexicalWrite(context.cfg().currentInstruction, A));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate IR for call modeling creation of primitive value, updating
|
|
|
|
* context.cfg()
|
|
|
|
*/
|
|
|
|
protected abstract void doPrimitive(int resultVal, WalkContext context, CAstNode primitiveCall);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get the value number for a name defined locally (i.e., within the current
|
|
|
|
* method) by looking up the name in context.currentScope(). Note that the
|
|
|
|
* caller is responsible for ensuring that name is defined in the local scope.
|
|
|
|
*/
|
2014-03-16 22:05:49 +00:00
|
|
|
protected int doLocalRead(WalkContext context, String name, TypeReference type) {
|
2013-06-07 16:58:25 +00:00
|
|
|
CAstEntity entity = context.top();
|
|
|
|
Set<String> exposed = entity2ExposedNames.get(entity);
|
|
|
|
if (exposed != null && exposed.contains(name)) {
|
2014-03-16 22:05:49 +00:00
|
|
|
return doLexReadHelper(context, name, type);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
return context.currentScope().lookup(name).valueNumber();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* add an {@link AssignInstruction} to context.cfg() that copies rval to the
|
|
|
|
* value number of local nm. Note that the caller is responsible for ensuring
|
|
|
|
* that nm is defined in the local scope.
|
|
|
|
*/
|
2014-03-16 22:05:49 +00:00
|
|
|
protected void doLocalWrite(WalkContext context, String nm, TypeReference type, int rval) {
|
2013-06-07 16:58:25 +00:00
|
|
|
CAstEntity entity = context.top();
|
|
|
|
Set<String> exposed = entity2ExposedNames.get(entity);
|
|
|
|
if (exposed != null && exposed.contains(nm)) {
|
|
|
|
// use a lexical write
|
2014-03-16 22:05:49 +00:00
|
|
|
doLexicallyScopedWrite(context, nm, type, rval);
|
2013-06-07 16:58:25 +00:00
|
|
|
return;
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
int lval = context.currentScope().lookup(nm).valueNumber();
|
|
|
|
if (lval != rval) {
|
2014-04-09 14:59:51 +00:00
|
|
|
context.cfg().addInstruction(new AssignInstruction(context.cfg().currentInstruction, lval, rval));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Note that the caller is responsible for ensuring that name is defined in a
|
|
|
|
* lexical scope.
|
|
|
|
*
|
|
|
|
* @param node
|
|
|
|
* the AST node representing the read
|
|
|
|
* @param context
|
|
|
|
* @param name
|
|
|
|
* @return
|
|
|
|
*/
|
2014-03-16 22:05:49 +00:00
|
|
|
protected int doLexicallyScopedRead(CAstNode node, WalkContext context, final String name, TypeReference type) {
|
|
|
|
return doLexReadHelper(context, name, type);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-10-16 21:37:53 +00:00
|
|
|
/**
|
|
|
|
* @param name A variable name
|
|
|
|
* @return is this name safe to overwrite, i.e. it's synthetic from the translator?
|
|
|
|
*/
|
|
|
|
protected boolean ignoreName(String name) {
|
|
|
|
return false;
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* we only have this method to avoid having to pass a node parameter at other
|
|
|
|
* call sites, as would be required for
|
|
|
|
* {@link #doLexicallyScopedRead(CAstNode, WalkContext, String)}
|
|
|
|
*/
|
2014-03-16 22:05:49 +00:00
|
|
|
private int doLexReadHelper(WalkContext context, final String name, TypeReference type) {
|
2012-09-04 22:56:05 +00:00
|
|
|
Symbol S = context.currentScope().lookup(name);
|
|
|
|
Scope definingScope = S.getDefiningScope();
|
|
|
|
CAstEntity E = definingScope.getEntity();
|
|
|
|
// record in declaring scope that the name is exposed to a nested scope
|
|
|
|
addExposedName(E, E, name, definingScope.lookup(name).valueNumber(), false, context);
|
|
|
|
final String entityName = context.getEntityName(E);
|
2013-06-07 16:58:25 +00:00
|
|
|
int result = context.currentScope().allocateTempValue();
|
2014-03-16 22:05:49 +00:00
|
|
|
Access A = new Access(name, entityName, type, result);
|
2014-04-09 15:33:57 +00:00
|
|
|
context.cfg().addInstruction(new AstLexicalRead(context.cfg().currentInstruction, A));
|
2014-03-16 22:05:49 +00:00
|
|
|
markExposedInEnclosingEntities(context, name, definingScope, type, E, entityName, false);
|
2013-06-07 16:58:25 +00:00
|
|
|
return result;
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* record name as exposed for the current entity and for all enclosing
|
|
|
|
* entities up to that of the defining scope, since if the name is updated via
|
|
|
|
* a call to a nested function, SSA for these entities may need to be updated
|
|
|
|
* with the new definition
|
|
|
|
*
|
|
|
|
* @param context
|
|
|
|
* @param name
|
|
|
|
* @param definingScope
|
|
|
|
* @param E
|
|
|
|
* @param entityName
|
|
|
|
* @param isWrite
|
|
|
|
*/
|
2014-03-16 22:05:49 +00:00
|
|
|
private void markExposedInEnclosingEntities(WalkContext context, final String name, Scope definingScope, TypeReference type, CAstEntity E,
|
2012-09-04 22:56:05 +00:00
|
|
|
final String entityName, boolean isWrite) {
|
|
|
|
Scope curScope = context.currentScope();
|
|
|
|
while (!curScope.equals(definingScope)) {
|
|
|
|
final Symbol curSymbol = curScope.lookup(name);
|
|
|
|
final int vn = curSymbol.valueNumber();
|
2014-03-16 22:05:49 +00:00
|
|
|
final Access A = new Access(name, entityName, type, vn);
|
2012-09-04 22:56:05 +00:00
|
|
|
final CAstEntity entity = curScope.getEntity();
|
|
|
|
if (entity != definingScope.getEntity()) {
|
|
|
|
addExposedName(entity, E, name, vn, isWrite, context);
|
|
|
|
// record the access; later, the Accesses in the instruction
|
|
|
|
// defining vn will be adjusted based on this information; see
|
|
|
|
// patchLexicalAccesses()
|
|
|
|
addAccess(context, entity, A);
|
|
|
|
}
|
|
|
|
curScope = curScope.getParent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Note that the caller is responsible for ensuring that name is defined in a
|
|
|
|
* lexical scope.
|
|
|
|
*
|
|
|
|
*/
|
2014-03-16 22:05:49 +00:00
|
|
|
protected void doLexicallyScopedWrite(WalkContext context, String name, TypeReference type, int rval) {
|
2012-09-04 22:56:05 +00:00
|
|
|
Symbol S = context.currentScope().lookup(name);
|
|
|
|
Scope definingScope = S.getDefiningScope();
|
|
|
|
CAstEntity E = definingScope.getEntity();
|
|
|
|
// record in declaring scope that the name is exposed to a nested scope
|
|
|
|
addExposedName(E, E, name, definingScope.lookup(name).valueNumber(), true, context);
|
|
|
|
|
2013-06-07 16:58:25 +00:00
|
|
|
// lexically-scoped variables must be written in their scope each time
|
2014-03-16 22:05:49 +00:00
|
|
|
Access A = new Access(name, context.getEntityName(E), type, rval);
|
2014-04-09 15:33:57 +00:00
|
|
|
context.cfg().addInstruction(new AstLexicalWrite(context.cfg().currentInstruction, A));
|
2014-03-16 22:05:49 +00:00
|
|
|
markExposedInEnclosingEntities(context, name, definingScope, type, E, context.getEntityName(E), true);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate instructions for a read of a global
|
|
|
|
*/
|
2014-03-16 22:05:49 +00:00
|
|
|
protected int doGlobalRead(CAstNode node, WalkContext context, String name, TypeReference type) {
|
2012-09-04 22:56:05 +00:00
|
|
|
// Global variables can be treated as lexicals defined in the CG root, or
|
|
|
|
if (treatGlobalsAsLexicallyScoped()) {
|
|
|
|
|
2013-06-07 16:58:25 +00:00
|
|
|
int result = context.currentScope().allocateTempValue();
|
2014-03-16 22:05:49 +00:00
|
|
|
Access A = new Access(name, null, type, result);
|
2014-04-09 15:33:57 +00:00
|
|
|
context.cfg().addInstruction(new AstLexicalRead(context.cfg().currentInstruction, A));
|
2013-06-07 16:58:25 +00:00
|
|
|
addAccess(context, context.top(), A);
|
|
|
|
return result;
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
// globals can be treated as a single static location
|
|
|
|
} else {
|
|
|
|
int result = context.currentScope().allocateTempValue();
|
|
|
|
FieldReference global = makeGlobalRef(name);
|
2014-04-09 14:59:51 +00:00
|
|
|
context.cfg().addInstruction(new AstGlobalRead(context.cfg().currentInstruction, result, global));
|
2012-09-04 22:56:05 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate instructions for a write of a global
|
|
|
|
*/
|
2014-03-16 22:05:49 +00:00
|
|
|
protected void doGlobalWrite(WalkContext context, String name, TypeReference type, int rval) {
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
// Global variables can be treated as lexicals defined in the CG root, or
|
|
|
|
if (treatGlobalsAsLexicallyScoped()) {
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
Access A = new Access(name, null, type, rval);
|
2014-04-09 15:33:57 +00:00
|
|
|
context.cfg().addInstruction(new AstLexicalWrite(context.cfg().currentInstruction, A));
|
2013-06-07 16:58:25 +00:00
|
|
|
addAccess(context, context.top(), A);
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
// globals can be treated as a single static location
|
|
|
|
} else {
|
|
|
|
FieldReference global = makeGlobalRef(name);
|
2014-04-09 14:59:51 +00:00
|
|
|
context.cfg().addInstruction(new AstGlobalWrite(context.cfg().currentInstruction, global, rval));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* generate instructions to check if ref has field, storing answer in result
|
|
|
|
*/
|
|
|
|
protected void doIsFieldDefined(WalkContext context, int result, int ref, CAstNode field) {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* creates a reference to a global named globalName. the declaring type and
|
|
|
|
* type of the global are both the root type.
|
|
|
|
*/
|
|
|
|
protected FieldReference makeGlobalRef(String globalName) {
|
|
|
|
TypeReference rootTypeRef = TypeReference.findOrCreate(loader.getReference(), AstTypeReference.rootTypeName);
|
|
|
|
return FieldReference.findOrCreate(rootTypeRef, Atom.findOrCreateUnicodeAtom("global " + globalName), rootTypeRef);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected final IClassLoader loader;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* for handling languages that let you include other source files named
|
|
|
|
* statically (e.g., ABAP)
|
|
|
|
*/
|
|
|
|
protected final Map namedEntityResolver;
|
|
|
|
|
|
|
|
protected final SSAInstructionFactory insts;
|
|
|
|
|
|
|
|
protected AstTranslator(IClassLoader loader, Map namedEntityResolver, ArrayOpHandler arrayOpHandler) {
|
|
|
|
this.loader = loader;
|
|
|
|
this.namedEntityResolver = namedEntityResolver;
|
|
|
|
this.arrayOpHandler = arrayOpHandler!=null? arrayOpHandler: this;
|
|
|
|
this.insts = loader.getInstructionFactory();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected AstTranslator(IClassLoader loader, Map namedEntityResolver) {
|
|
|
|
this(loader, namedEntityResolver, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected AstTranslator(IClassLoader loader) {
|
|
|
|
this(loader, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* for keeping position information for the generated SSAInstructions and SSA
|
|
|
|
* locals
|
|
|
|
*/
|
|
|
|
private static class AstDebuggingInformation implements DebuggingInformation {
|
|
|
|
private Position codeBodyPosition;
|
|
|
|
|
|
|
|
private String[][] valueNumberNames;
|
|
|
|
|
|
|
|
private Position[] instructionPositions;
|
|
|
|
|
|
|
|
AstDebuggingInformation(Position codeBodyPosition, Position[] instructionPositions, String[] names) {
|
|
|
|
this.codeBodyPosition = codeBodyPosition;
|
|
|
|
|
|
|
|
this.instructionPositions = instructionPositions;
|
|
|
|
|
|
|
|
valueNumberNames = new String[names.length][];
|
|
|
|
for (int i = 0; i < names.length; i++) {
|
|
|
|
if (names[i] != null) {
|
|
|
|
valueNumberNames[i] = new String[] { names[i] };
|
|
|
|
} else {
|
|
|
|
valueNumberNames[i] = new String[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Position getCodeBodyPosition() {
|
|
|
|
return codeBodyPosition;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Position getInstructionPosition(int instructionOffset) {
|
|
|
|
return instructionPositions[instructionOffset];
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String[][] getSourceNamesForValues() {
|
|
|
|
return valueNumberNames;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static final boolean DEBUG_ALL = false;
|
|
|
|
|
|
|
|
public static final boolean DEBUG_TOP = DEBUG_ALL || false;
|
|
|
|
|
|
|
|
public static final boolean DEBUG_CFG = DEBUG_ALL || false;
|
|
|
|
|
|
|
|
public static final boolean DEBUG_NAMES = DEBUG_ALL || false;
|
|
|
|
|
|
|
|
public static final boolean DEBUG_LEXICAL = DEBUG_ALL || false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* basic block implementation used in the CFGs constructed during the
|
|
|
|
* IR-generating AST traversal
|
|
|
|
*/
|
|
|
|
protected final static class PreBasicBlock implements INodeWithNumber, IBasicBlock<SSAInstruction> {
|
|
|
|
private static final int NORMAL = 0;
|
|
|
|
|
|
|
|
private static final int HANDLER = 1;
|
|
|
|
|
|
|
|
private static final int ENTRY = 2;
|
|
|
|
|
|
|
|
private static final int EXIT = 3;
|
|
|
|
|
|
|
|
private int kind = NORMAL;
|
|
|
|
|
|
|
|
private int number = -1;
|
|
|
|
|
|
|
|
private int firstIndex = -1;
|
|
|
|
|
|
|
|
private int lastIndex = -2;
|
|
|
|
|
|
|
|
private final List<SSAInstruction> instructions = new ArrayList<SSAInstruction>();
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int getNumber() {
|
|
|
|
return getGraphNodeId();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int getGraphNodeId() {
|
|
|
|
return number;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void setGraphNodeId(int number) {
|
|
|
|
this.number = number;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int getFirstInstructionIndex() {
|
|
|
|
return firstIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setFirstIndex(int firstIndex) {
|
|
|
|
this.firstIndex = firstIndex;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int getLastInstructionIndex() {
|
|
|
|
return lastIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setLastIndex(int lastIndex) {
|
|
|
|
this.lastIndex = lastIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void makeExitBlock() {
|
|
|
|
kind = EXIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void makeEntryBlock() {
|
|
|
|
kind = ENTRY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void makeHandlerBlock() {
|
|
|
|
kind = HANDLER;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isEntryBlock() {
|
|
|
|
return kind == ENTRY;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isExitBlock() {
|
|
|
|
return kind == EXIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isHandlerBlock() {
|
|
|
|
return kind == HANDLER;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String toString() {
|
|
|
|
return "PreBB" + number + ":" + firstIndex + ".." + lastIndex;
|
|
|
|
}
|
|
|
|
|
2013-07-30 18:04:08 +00:00
|
|
|
private List<SSAInstruction> instructions() {
|
2012-09-04 22:56:05 +00:00
|
|
|
return instructions;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isCatchBlock() {
|
|
|
|
return (lastIndex > -1) && (instructions.get(0) instanceof SSAGetCaughtExceptionInstruction);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public IMethod getMethod() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Iterator<SSAInstruction> iterator() {
|
|
|
|
return instructions.iterator();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected final class UnwindState {
|
|
|
|
final CAstNode unwindAst;
|
|
|
|
|
|
|
|
final WalkContext astContext;
|
|
|
|
|
|
|
|
final CAstVisitor<WalkContext> astVisitor;
|
|
|
|
|
|
|
|
UnwindState(CAstNode unwindAst, WalkContext astContext, CAstVisitor<WalkContext> astVisitor) {
|
|
|
|
this.unwindAst = unwindAst;
|
|
|
|
this.astContext = astContext;
|
|
|
|
this.astVisitor = astVisitor;
|
|
|
|
}
|
|
|
|
|
|
|
|
public UnwindState getParent() {
|
|
|
|
return astContext.getUnwindState();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int hashCode() {
|
|
|
|
return astContext.hashCode() * unwindAst.hashCode() * astVisitor.hashCode();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean equals(Object o) {
|
|
|
|
if (o instanceof UnwindState) {
|
|
|
|
if (((UnwindState) o).unwindAst != unwindAst)
|
|
|
|
return false;
|
|
|
|
if (((UnwindState) o).astVisitor != astVisitor)
|
|
|
|
return false;
|
|
|
|
if (getParent() == null) {
|
|
|
|
return ((UnwindState) o).getParent() == null;
|
|
|
|
} else {
|
|
|
|
return getParent().equals(((UnwindState) o).getParent());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean covers(UnwindState other) {
|
|
|
|
if (equals(other))
|
|
|
|
return true;
|
|
|
|
if (getParent() != null)
|
|
|
|
return getParent().covers(other);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* holds the control-flow graph as it is being constructed. When construction
|
|
|
|
* is complete, information is stored in an {@link AstCFG}
|
|
|
|
*/
|
2014-07-08 18:44:06 +00:00
|
|
|
@SuppressWarnings("javadoc")
|
2012-09-04 22:56:05 +00:00
|
|
|
public final class IncipientCFG extends SparseNumberedGraph<PreBasicBlock> {
|
|
|
|
|
|
|
|
protected class Unwind {
|
|
|
|
private final Map<PreBasicBlock, UnwindState> unwindData = new LinkedHashMap<PreBasicBlock, UnwindState>();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* a cache of generated blocks
|
|
|
|
*/
|
|
|
|
private final Map<Pair<UnwindState, Pair<PreBasicBlock, Boolean>>, PreBasicBlock> code = new LinkedHashMap<Pair<UnwindState, Pair<PreBasicBlock, Boolean>>, PreBasicBlock>();
|
|
|
|
|
|
|
|
void setUnwindState(PreBasicBlock block, UnwindState context) {
|
|
|
|
unwindData.put(block, context);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setUnwindState(CAstNode node, UnwindState context) {
|
|
|
|
unwindData.put(nodeToBlock.get(node), context);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* When adding an edge from source to target, it is possible that certain
|
|
|
|
* exception-handling code needs to be executed before the control is
|
|
|
|
* actually transfered to target. This method determines if this is the
|
|
|
|
* case, and if so, it generates the exception handler blocks and adds an
|
|
|
|
* appropriate edge to the target. It returns the basic block that should
|
|
|
|
* be the target of the edge from source (target itself if there is no
|
|
|
|
* exception-handling code, the initial catch block otherwise)
|
|
|
|
*/
|
|
|
|
public PreBasicBlock findOrCreateCode(PreBasicBlock source, PreBasicBlock target, final boolean exception) {
|
|
|
|
UnwindState sourceContext = unwindData.get(source);
|
|
|
|
final CAstNode dummy = exception ? (new CAstImpl()).makeNode(CAstNode.EMPTY) : null;
|
|
|
|
|
|
|
|
// no unwinding is needed, so jump to target block directly
|
|
|
|
if (sourceContext == null)
|
|
|
|
return target;
|
|
|
|
|
|
|
|
WalkContext astContext = sourceContext.astContext;
|
|
|
|
UnwindState targetContext = null;
|
|
|
|
if (target != null)
|
|
|
|
targetContext = unwindData.get(target);
|
|
|
|
|
|
|
|
// in unwind context, but catch in same (or inner) unwind context
|
|
|
|
if (targetContext != null && targetContext.covers(sourceContext))
|
|
|
|
return target;
|
|
|
|
|
|
|
|
Pair<UnwindState, Pair<PreBasicBlock, Boolean>> key = Pair.make(sourceContext, Pair.make(target, exception));
|
|
|
|
|
|
|
|
if (code.containsKey(key)) {
|
|
|
|
return code.get(key);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
int e = -1;
|
|
|
|
PreBasicBlock currentBlock = getCurrentBlock();
|
|
|
|
if (!isDeadBlock(currentBlock)) {
|
2014-07-28 15:09:02 +00:00
|
|
|
addInstruction(insts.GotoInstruction(currentInstruction, -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
newBlock(false);
|
|
|
|
}
|
|
|
|
PreBasicBlock startBlock = getCurrentBlock();
|
|
|
|
if (exception) {
|
|
|
|
setCurrentBlockAsHandler();
|
|
|
|
e = sourceContext.astContext.currentScope().allocateTempValue();
|
2014-04-09 14:59:51 +00:00
|
|
|
addInstruction(insts.GetCaughtExceptionInstruction(currentInstruction, startBlock.getNumber(), e));
|
2013-04-11 01:09:10 +00:00
|
|
|
sourceContext.astContext.setCatchType(startBlock, defaultCatchType());
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
while (sourceContext != null && (targetContext == null || !targetContext.covers(sourceContext))) {
|
|
|
|
final CAstRewriter.Rewrite ast = (new CAstCloner(new CAstImpl()) {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected CAstNode flowOutTo(Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap, CAstNode oldSource, Object label,
|
|
|
|
CAstNode oldTarget, CAstControlFlowMap orig, CAstSourcePositionMap src) {
|
|
|
|
if (exception && !isExceptionLabel(label)) {
|
|
|
|
return dummy;
|
|
|
|
} else {
|
|
|
|
return oldTarget;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}).copy(sourceContext.unwindAst, sourceContext.astContext.getControlFlow(), sourceContext.astContext.getSourceMap(),
|
|
|
|
sourceContext.astContext.top().getNodeTypeMap(), sourceContext.astContext.top().getAllScopedEntities());
|
|
|
|
sourceContext.astVisitor.visit(ast.newRoot(), new DelegatingContext(sourceContext.astContext) {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstSourcePositionMap getSourceMap() {
|
|
|
|
return ast.newPos();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstControlFlowMap getControlFlow() {
|
|
|
|
return ast.newCfg();
|
|
|
|
}
|
|
|
|
}, sourceContext.astVisitor);
|
|
|
|
|
|
|
|
sourceContext = sourceContext.getParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
PreBasicBlock endBlock = getCurrentBlock();
|
|
|
|
if (exception) {
|
|
|
|
addPreNode(dummy);
|
|
|
|
doThrow(astContext, e);
|
|
|
|
} else {
|
2014-07-28 15:09:02 +00:00
|
|
|
addInstruction(insts.GotoInstruction(currentInstruction, -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
newBlock(false);
|
|
|
|
|
|
|
|
addEdge(currentBlock, getCurrentBlock());
|
|
|
|
if (target != null) {
|
|
|
|
addEdge(endBlock, target);
|
|
|
|
|
|
|
|
// `null' target is idiom for branch/throw to exit
|
|
|
|
} else {
|
|
|
|
addDelayedEdge(endBlock, exitMarker, exception);
|
|
|
|
}
|
|
|
|
|
|
|
|
code.put(key, startBlock);
|
|
|
|
return startBlock;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Unwind unwind = null;
|
|
|
|
|
|
|
|
private final List<PreBasicBlock> blocks = new ArrayList<PreBasicBlock>();
|
|
|
|
|
2013-04-09 22:47:22 +00:00
|
|
|
private PreBasicBlock entryBlock;
|
|
|
|
|
2012-09-04 22:56:05 +00:00
|
|
|
private final Map<CAstNode, PreBasicBlock> nodeToBlock = new LinkedHashMap<CAstNode, PreBasicBlock>();
|
|
|
|
|
|
|
|
private final Map<Object, Set<Pair<PreBasicBlock, Boolean>>> delayedEdges = new LinkedHashMap<Object, Set<Pair<PreBasicBlock, Boolean>>>();
|
|
|
|
|
|
|
|
private final Object exitMarker = new Object();
|
|
|
|
|
|
|
|
private final Set<PreBasicBlock> deadBlocks = new LinkedHashSet<PreBasicBlock>();
|
|
|
|
|
|
|
|
private final Set<PreBasicBlock> normalToExit = new LinkedHashSet<PreBasicBlock>();
|
|
|
|
|
|
|
|
private final Set<PreBasicBlock> exceptionalToExit = new LinkedHashSet<PreBasicBlock>();
|
|
|
|
|
|
|
|
private Position[] linePositions = new Position[10];
|
|
|
|
|
|
|
|
private boolean hasCatchBlock = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* does the method have any monitor operations?
|
|
|
|
*/
|
|
|
|
private boolean hasMonitorOp = false;
|
|
|
|
|
|
|
|
private int currentInstruction = 0;
|
|
|
|
|
|
|
|
private PreBasicBlock currentBlock;
|
|
|
|
|
|
|
|
public int getCurrentInstruction() {
|
|
|
|
return currentInstruction;
|
|
|
|
}
|
|
|
|
|
|
|
|
public PreBasicBlock getCurrentBlock() {
|
|
|
|
return currentBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean hasCatchBlock() {
|
|
|
|
return hasCatchBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean hasMonitorOp() {
|
|
|
|
return hasMonitorOp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void noteCatchBlock() {
|
|
|
|
hasCatchBlock = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Position[] getLinePositionMap() {
|
|
|
|
return linePositions;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* create a new basic block, and set it as the current block.
|
|
|
|
*
|
|
|
|
* @param fallThruFromPrior
|
|
|
|
* should a fall-through edge be added from the previous block
|
|
|
|
* (value of currentBlock at entry)? if false, the newly created
|
|
|
|
* block is marked as a dead block, as it has no incoming edges.
|
|
|
|
* @return the new block
|
|
|
|
*/
|
|
|
|
public PreBasicBlock newBlock(boolean fallThruFromPrior) {
|
|
|
|
// optimization: if we have a fall-through from an empty block, just
|
|
|
|
// return the empty block
|
|
|
|
if (fallThruFromPrior && !currentBlock.isEntryBlock() && currentBlock.instructions().size() == 0) {
|
|
|
|
return currentBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
PreBasicBlock previous = currentBlock;
|
|
|
|
currentBlock = new PreBasicBlock();
|
|
|
|
addNode(currentBlock);
|
|
|
|
blocks.add(currentBlock);
|
|
|
|
|
|
|
|
if (DEBUG_CFG)
|
|
|
|
System.err.println(("adding new block (node) " + currentBlock));
|
|
|
|
if (fallThruFromPrior) {
|
|
|
|
if (DEBUG_CFG)
|
|
|
|
System.err.println(("adding fall-thru edge " + previous + " --> " + currentBlock));
|
|
|
|
addEdge(previous, currentBlock);
|
|
|
|
} else {
|
|
|
|
deadBlocks.add(currentBlock);
|
|
|
|
}
|
|
|
|
|
|
|
|
return currentBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* record a delayed edge addition from src to dst. Edge will be added when
|
|
|
|
* appropriate; see {@link #checkForRealizedEdges(CAstNode)} and
|
|
|
|
* {@link #checkForRealizedExitEdges(PreBasicBlock)}
|
|
|
|
*/
|
|
|
|
private void addDelayedEdge(PreBasicBlock src, Object dst, boolean exception) {
|
|
|
|
MapUtil.findOrCreateSet(delayedEdges, dst).add(Pair.make(src, exception));
|
|
|
|
}
|
|
|
|
|
|
|
|
void makeEntryBlock(PreBasicBlock bb) {
|
2013-04-09 22:47:22 +00:00
|
|
|
entryBlock = bb;
|
2012-09-04 22:56:05 +00:00
|
|
|
bb.makeEntryBlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void makeExitBlock(PreBasicBlock bb) {
|
|
|
|
bb.makeExitBlock();
|
|
|
|
|
|
|
|
for (Iterator<? extends PreBasicBlock> ps = getPredNodes(bb); ps.hasNext();)
|
|
|
|
normalToExit.add(ps.next());
|
|
|
|
|
|
|
|
// now that we have created the exit block, add the delayed edges to the
|
|
|
|
// exit
|
|
|
|
checkForRealizedExitEdges(bb);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setCurrentBlockAsHandler() {
|
|
|
|
currentBlock.makeHandlerBlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean hasDelayedEdges(CAstNode n) {
|
|
|
|
return delayedEdges.containsKey(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* given some n which is now mapped by nodeToBlock, add any delayed edges to
|
|
|
|
* n's block
|
|
|
|
*/
|
|
|
|
private void checkForRealizedEdges(CAstNode n) {
|
|
|
|
if (delayedEdges.containsKey(n)) {
|
|
|
|
for (Iterator<Pair<PreBasicBlock, Boolean>> ss = delayedEdges.get(n).iterator(); ss.hasNext();) {
|
|
|
|
Pair<PreBasicBlock, Boolean> s = ss.next();
|
|
|
|
PreBasicBlock src = s.fst;
|
|
|
|
boolean exception = s.snd;
|
|
|
|
if (unwind == null) {
|
|
|
|
addEdge(src, nodeToBlock.get(n));
|
|
|
|
} else {
|
|
|
|
PreBasicBlock target = nodeToBlock.get(n);
|
|
|
|
addEdge(src, unwind.findOrCreateCode(src, target, exception));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delayedEdges.remove(n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* add any delayed edges to the exit block
|
|
|
|
*/
|
|
|
|
private void checkForRealizedExitEdges(PreBasicBlock exitBlock) {
|
|
|
|
if (delayedEdges.containsKey(exitMarker)) {
|
|
|
|
for (Iterator<Pair<PreBasicBlock, Boolean>> ss = delayedEdges.get(exitMarker).iterator(); ss.hasNext();) {
|
|
|
|
Pair<PreBasicBlock, Boolean> s = ss.next();
|
|
|
|
PreBasicBlock src = s.fst;
|
|
|
|
boolean exception = s.snd;
|
|
|
|
addEdge(src, exitBlock);
|
|
|
|
if (exception)
|
|
|
|
exceptionalToExit.add(src);
|
|
|
|
else
|
|
|
|
normalToExit.add(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
delayedEdges.remove(exitMarker);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setUnwindState(CAstNode node, UnwindState context) {
|
|
|
|
if (unwind == null)
|
|
|
|
unwind = new Unwind();
|
|
|
|
unwind.setUnwindState(node, context);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addPreNode(CAstNode n) {
|
|
|
|
addPreNode(n, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* associate n with the current block, and update the current unwind state
|
|
|
|
*/
|
|
|
|
public void addPreNode(CAstNode n, UnwindState context) {
|
|
|
|
if (DEBUG_CFG)
|
|
|
|
System.err.println(("adding pre-node " + n));
|
|
|
|
nodeToBlock.put(n, currentBlock);
|
|
|
|
deadBlocks.remove(currentBlock);
|
|
|
|
if (context != null)
|
|
|
|
setUnwindState(n, context);
|
|
|
|
// now that we've associated n with a block, add associated delayed edges
|
|
|
|
checkForRealizedEdges(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addPreEdge(CAstNode src, CAstNode dst, boolean exception) {
|
|
|
|
assert nodeToBlock.containsKey(src);
|
|
|
|
addPreEdge(nodeToBlock.get(src), dst, exception);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* if dst is associated with a basic block b, add an edge from src to b.
|
|
|
|
* otherwise, record the edge addition as delayed.
|
|
|
|
*/
|
|
|
|
public void addPreEdge(PreBasicBlock src, CAstNode dst, boolean exception) {
|
|
|
|
if (dst == CAstControlFlowMap.EXCEPTION_TO_EXIT) {
|
|
|
|
assert exception;
|
|
|
|
addPreEdgeToExit(src, exception);
|
|
|
|
} else if (nodeToBlock.containsKey(dst)) {
|
|
|
|
PreBasicBlock target = nodeToBlock.get(dst);
|
|
|
|
if (DEBUG_CFG)
|
|
|
|
System.err.println(("adding pre-edge " + src + " --> " + dst));
|
|
|
|
if (unwind == null) {
|
|
|
|
addEdge(src, target);
|
|
|
|
} else {
|
|
|
|
addEdge(src, unwind.findOrCreateCode(src, target, exception));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (DEBUG_CFG)
|
|
|
|
System.err.println(("adding delayed pre-edge " + src + " --> " + dst));
|
|
|
|
addDelayedEdge(src, dst, exception);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addPreEdgeToExit(CAstNode src, boolean exception) {
|
|
|
|
assert nodeToBlock.containsKey(src);
|
|
|
|
addPreEdgeToExit(nodeToBlock.get(src), exception);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addPreEdgeToExit(PreBasicBlock src, boolean exception) {
|
|
|
|
if (unwind != null) {
|
|
|
|
PreBasicBlock handlers = unwind.findOrCreateCode(src, null, exception);
|
|
|
|
if (handlers != null) {
|
|
|
|
addEdge(src, handlers);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
addDelayedEdge(src, exitMarker, exception);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void addEdge(PreBasicBlock src, PreBasicBlock dst) {
|
|
|
|
super.addEdge(src, dst);
|
|
|
|
deadBlocks.remove(dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean isDeadBlock(PreBasicBlock block) {
|
|
|
|
return deadBlocks.contains(block);
|
|
|
|
}
|
|
|
|
|
|
|
|
public PreBasicBlock getBlock(CAstNode n) {
|
|
|
|
return nodeToBlock.get(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* mark the current position as the position for the instruction
|
|
|
|
*/
|
|
|
|
private void noteLinePosition(int instruction) {
|
|
|
|
if (linePositions.length < (instruction + 1)) {
|
|
|
|
Position[] newData = new Position[instruction * 2 + 1];
|
|
|
|
System.arraycopy(linePositions, 0, newData, 0, linePositions.length);
|
|
|
|
linePositions = newData;
|
|
|
|
}
|
|
|
|
|
|
|
|
linePositions[instruction] = getCurrentPosition();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addInstruction(SSAInstruction n) {
|
|
|
|
deadBlocks.remove(currentBlock);
|
|
|
|
|
|
|
|
int inst = currentInstruction++;
|
|
|
|
|
|
|
|
noteLinePosition(inst);
|
|
|
|
|
|
|
|
if (currentBlock.instructions().size() == 0) {
|
|
|
|
currentBlock.setFirstIndex(inst);
|
|
|
|
} else {
|
2013-07-30 18:04:08 +00:00
|
|
|
for(SSAInstruction priorInst : currentBlock.instructions()) {
|
|
|
|
assert ! (priorInst instanceof SSAGotoInstruction);
|
|
|
|
}
|
2012-09-04 22:56:05 +00:00
|
|
|
assert !(n instanceof SSAGetCaughtExceptionInstruction);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DEBUG_CFG) {
|
|
|
|
System.err.println(("adding " + n + " at " + inst + " to " + currentBlock));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n instanceof SSAMonitorInstruction) {
|
|
|
|
hasMonitorOp = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
currentBlock.instructions().add(n);
|
|
|
|
|
|
|
|
currentBlock.setLastIndex(inst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* data structure for the final CFG for a method, based on the information in
|
|
|
|
* an {@link IncipientCFG}
|
|
|
|
*/
|
|
|
|
protected final static class AstCFG extends AbstractCFG<SSAInstruction, PreBasicBlock> {
|
|
|
|
private final SSAInstruction[] instructions;
|
|
|
|
|
|
|
|
private final int[] instructionToBlockMap;
|
|
|
|
|
2013-08-05 18:35:41 +00:00
|
|
|
private final int[] pcMap;
|
|
|
|
|
2012-09-04 22:56:05 +00:00
|
|
|
private final String functionName;
|
|
|
|
|
|
|
|
private final SymbolTable symtab;
|
|
|
|
|
2013-04-09 22:47:22 +00:00
|
|
|
private interface EdgeOperation {
|
|
|
|
void act(PreBasicBlock src, PreBasicBlock dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void transferEdges(Set<PreBasicBlock> blocks,
|
|
|
|
IncipientCFG icfg,
|
|
|
|
EdgeOperation normal,
|
|
|
|
EdgeOperation except) {
|
|
|
|
for (PreBasicBlock src : blocks) {
|
|
|
|
for (Iterator j = icfg.getSuccNodes(src); j.hasNext();) {
|
|
|
|
PreBasicBlock dst = (PreBasicBlock) j.next();
|
|
|
|
if (isCatchBlock(dst.getNumber()) || (dst.isExitBlock() && icfg.exceptionalToExit.contains(src))) {
|
|
|
|
except.act(src, dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dst.isExitBlock() ? icfg.normalToExit.contains(src) : !isCatchBlock(dst.getNumber())) {
|
|
|
|
normal.act(src, dst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-30 18:04:08 +00:00
|
|
|
private boolean checkBlockBoundaries(IncipientCFG icfg) {
|
|
|
|
MutableIntSet boundaries = IntSetUtil.make();
|
|
|
|
for(PreBasicBlock b : icfg) {
|
|
|
|
if (b.getFirstInstructionIndex() >= 0) {
|
|
|
|
if (boundaries.contains(b.getFirstInstructionIndex())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
boundaries.add(b.getFirstInstructionIndex());
|
|
|
|
}
|
|
|
|
if (b.getLastInstructionIndex() >= 0 && b.getLastInstructionIndex() != b.getFirstInstructionIndex()) {
|
|
|
|
if (boundaries.contains(b.getLastInstructionIndex())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
boundaries.add(b.getLastInstructionIndex());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
AstCFG(CAstEntity n, IncipientCFG icfg, SymbolTable symtab, SSAInstructionFactory insts) {
|
2012-09-04 22:56:05 +00:00
|
|
|
super(null);
|
2013-04-09 22:47:22 +00:00
|
|
|
|
|
|
|
Set<PreBasicBlock> liveBlocks = DFS.getReachableNodes(icfg, Collections.singleton(icfg.entryBlock));
|
2012-09-04 22:56:05 +00:00
|
|
|
List<PreBasicBlock> blocks = icfg.blocks;
|
2013-04-09 22:47:22 +00:00
|
|
|
boolean hasDeadBlocks = blocks.size() > liveBlocks.size();
|
|
|
|
|
2013-07-30 18:04:08 +00:00
|
|
|
assert checkBlockBoundaries(icfg);
|
|
|
|
|
2012-09-04 22:56:05 +00:00
|
|
|
this.symtab = symtab;
|
|
|
|
functionName = n.getName();
|
2013-04-09 22:47:22 +00:00
|
|
|
instructionToBlockMap = new int[liveBlocks.size()];
|
2013-08-05 18:35:41 +00:00
|
|
|
pcMap = hasDeadBlocks? new int[ icfg.currentInstruction ]: null;
|
|
|
|
|
2013-04-09 22:47:22 +00:00
|
|
|
final Map<PreBasicBlock, Collection<PreBasicBlock>> normalEdges =
|
|
|
|
hasDeadBlocks? HashMapFactory.<PreBasicBlock,Collection<PreBasicBlock>>make() : null;
|
|
|
|
final Map<PreBasicBlock, Collection<PreBasicBlock>> exceptionalEdges =
|
|
|
|
hasDeadBlocks? HashMapFactory.<PreBasicBlock,Collection<PreBasicBlock>>make() : null;
|
|
|
|
if (hasDeadBlocks) {
|
|
|
|
transferEdges(liveBlocks, icfg, new EdgeOperation() {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2013-04-09 22:47:22 +00:00
|
|
|
public void act(PreBasicBlock src, PreBasicBlock dst) {
|
|
|
|
if (! normalEdges.containsKey(src)) {
|
|
|
|
normalEdges.put(src, HashSetFactory.<PreBasicBlock>make());
|
|
|
|
}
|
|
|
|
normalEdges.get(src).add(dst);
|
|
|
|
}
|
|
|
|
}, new EdgeOperation() {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2013-04-09 22:47:22 +00:00
|
|
|
public void act(PreBasicBlock src, PreBasicBlock dst) {
|
|
|
|
if (! exceptionalEdges.containsKey(src)) {
|
|
|
|
exceptionalEdges.put(src, HashSetFactory.<PreBasicBlock>make());
|
|
|
|
}
|
|
|
|
exceptionalEdges.get(src).add(dst);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-07-30 18:04:08 +00:00
|
|
|
int instruction = 0;
|
2013-04-09 22:47:22 +00:00
|
|
|
for (int i = 0, blockNumber = 0; i < blocks.size(); i++) {
|
2013-04-11 01:09:10 +00:00
|
|
|
PreBasicBlock block = blocks.get(i);
|
|
|
|
block.setGraphNodeId(-1);
|
2013-07-30 18:04:08 +00:00
|
|
|
if (liveBlocks.contains(block)) {
|
2013-08-05 18:35:41 +00:00
|
|
|
if (hasDeadBlocks) {
|
|
|
|
int offset = 0;
|
|
|
|
for(int oldPC = block.getFirstInstructionIndex();
|
|
|
|
offset < block.instructions().size();
|
|
|
|
oldPC++, offset++) {
|
|
|
|
pcMap[instruction + offset] = oldPC;
|
|
|
|
}
|
|
|
|
}
|
2013-07-30 18:04:08 +00:00
|
|
|
if (block.getFirstInstructionIndex() >= 0) {
|
|
|
|
block.setFirstIndex(instruction);
|
|
|
|
block.setLastIndex((instruction += block.instructions().size()) - 1);
|
|
|
|
}
|
2013-04-11 01:09:10 +00:00
|
|
|
instructionToBlockMap[blockNumber] = block.getLastInstructionIndex();
|
2012-09-04 22:56:05 +00:00
|
|
|
|
2013-04-09 22:47:22 +00:00
|
|
|
this.addNode(block);
|
|
|
|
if (block.isCatchBlock()) {
|
|
|
|
setCatchBlock(blockNumber);
|
|
|
|
}
|
2012-09-04 22:56:05 +00:00
|
|
|
|
2013-04-09 22:47:22 +00:00
|
|
|
if (DEBUG_CFG) {
|
|
|
|
System.err.println(("added " + blocks.get(i) + " to final CFG as " + getNumber(blocks.get(i))));
|
|
|
|
}
|
|
|
|
|
|
|
|
blockNumber++;
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (DEBUG_CFG)
|
|
|
|
System.err.println((getMaxNumber() + " blocks total"));
|
|
|
|
|
|
|
|
init();
|
|
|
|
|
2013-04-09 22:47:22 +00:00
|
|
|
if (hasDeadBlocks) {
|
|
|
|
for (int i = 0; i < blocks.size(); i++) {
|
|
|
|
PreBasicBlock src = blocks.get(i);
|
|
|
|
if (liveBlocks.contains(src)) {
|
|
|
|
if (normalEdges.containsKey(src)) {
|
|
|
|
for(PreBasicBlock succ : normalEdges.get(src)) {
|
|
|
|
addNormalEdge(src, succ);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (exceptionalEdges.containsKey(src)) {
|
|
|
|
for(PreBasicBlock succ : exceptionalEdges.get(src)) {
|
|
|
|
addExceptionalEdge(src, succ);
|
|
|
|
}
|
|
|
|
}
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
2013-04-09 22:47:22 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
transferEdges(liveBlocks, icfg, new EdgeOperation() {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2013-04-09 22:47:22 +00:00
|
|
|
public void act(PreBasicBlock src, PreBasicBlock dst) {
|
2012-09-04 22:56:05 +00:00
|
|
|
addNormalEdge(src, dst);
|
|
|
|
}
|
2013-04-09 22:47:22 +00:00
|
|
|
}, new EdgeOperation() {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2013-04-09 22:47:22 +00:00
|
|
|
public void act(PreBasicBlock src, PreBasicBlock dst) {
|
|
|
|
addExceptionalEdge(src, dst);
|
|
|
|
}
|
|
|
|
});
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
2013-04-09 22:47:22 +00:00
|
|
|
|
2012-09-04 22:56:05 +00:00
|
|
|
int x = 0;
|
|
|
|
instructions = new SSAInstruction[icfg.currentInstruction];
|
|
|
|
for (int i = 0; i < blocks.size(); i++) {
|
2013-04-09 22:47:22 +00:00
|
|
|
if (liveBlocks.contains(blocks.get(i))) {
|
|
|
|
List<SSAInstruction> bi = blocks.get(i).instructions();
|
|
|
|
for (int j = 0; j < bi.size(); j++) {
|
2013-07-30 18:04:08 +00:00
|
|
|
SSAInstruction inst = bi.get(j);
|
|
|
|
if (inst instanceof SSAGetCaughtExceptionInstruction) {
|
|
|
|
SSAGetCaughtExceptionInstruction ci = (SSAGetCaughtExceptionInstruction) inst;
|
|
|
|
if (ci.getBasicBlockNumber() != blocks.get(i).getNumber()) {
|
2014-05-20 15:59:16 +00:00
|
|
|
inst = insts.GetCaughtExceptionInstruction(x, blocks.get(i).getNumber(), ci.getException());
|
2013-07-30 18:04:08 +00:00
|
|
|
}
|
2014-07-08 18:44:06 +00:00
|
|
|
} else if (inst instanceof SSAGotoInstruction) {
|
|
|
|
Iterator<PreBasicBlock> succs = this.getNormalSuccessors(blocks.get(i)).iterator();
|
|
|
|
if (succs.hasNext()) {
|
|
|
|
PreBasicBlock target = succs.next();
|
|
|
|
assert !succs.hasNext() : "unexpected successors for block " + blocks.get(i) + ": " + target + " and " + succs.next();
|
2014-07-28 15:09:02 +00:00
|
|
|
inst = insts.GotoInstruction(x, target.firstIndex);
|
2014-07-08 18:44:06 +00:00
|
|
|
} else {
|
|
|
|
// goto to the end of the method, so the instruction is unnecessary
|
|
|
|
inst = null;
|
|
|
|
}
|
|
|
|
} else if (inst instanceof SSAConditionalBranchInstruction) {
|
|
|
|
Iterator<PreBasicBlock> succs = this.getNormalSuccessors(blocks.get(i)).iterator();
|
|
|
|
assert succs.hasNext();
|
|
|
|
int target;
|
|
|
|
int t1 = succs.next().firstIndex;
|
|
|
|
if (succs.hasNext()) {
|
|
|
|
int t2 = succs.next().firstIndex;
|
|
|
|
if (t1 == x+1) {
|
|
|
|
target = t2;
|
|
|
|
} else {
|
|
|
|
target = t1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
target = t1;
|
|
|
|
}
|
|
|
|
SSAConditionalBranchInstruction branch = (SSAConditionalBranchInstruction) inst;
|
2014-07-28 15:09:02 +00:00
|
|
|
inst = insts.ConditionalBranchInstruction(x, branch.getOperator(), branch.getType(), branch.getUse(0), branch.getUse(1), target);
|
2013-07-30 18:04:08 +00:00
|
|
|
}
|
2014-07-30 13:05:15 +00:00
|
|
|
|
2013-07-30 18:04:08 +00:00
|
|
|
instructions[x++] = inst;
|
2013-04-09 22:47:22 +00:00
|
|
|
}
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int hashCode() {
|
|
|
|
return functionName.hashCode();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean equals(Object o) {
|
|
|
|
return (o instanceof AstCFG) && functionName.equals(((AstCFG) o).functionName);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public PreBasicBlock getBlockForInstruction(int index) {
|
|
|
|
for (int i = 1; i < getNumberOfNodes() - 1; i++)
|
|
|
|
if (index <= instructionToBlockMap[i])
|
|
|
|
return getNode(i);
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public SSAInstruction[] getInstructions() {
|
|
|
|
return instructions;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int getProgramCounter(int index) {
|
2013-08-05 18:35:41 +00:00
|
|
|
return pcMap == null? index: pcMap[index];
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String toString() {
|
2013-08-05 18:35:41 +00:00
|
|
|
SSAInstruction[] insts = getInstructions();
|
2012-09-04 22:56:05 +00:00
|
|
|
StringBuffer s = new StringBuffer("CAst CFG of " + functionName);
|
|
|
|
int params[] = symtab.getParameterValueNumbers();
|
|
|
|
for (int i = 0; i < params.length; i++)
|
|
|
|
s.append(" ").append(params[i]);
|
|
|
|
s.append("\n");
|
|
|
|
|
|
|
|
for (int i = 0; i < getNumberOfNodes(); i++) {
|
2013-08-05 18:35:41 +00:00
|
|
|
PreBasicBlock bb = getNode(i);
|
2012-09-04 22:56:05 +00:00
|
|
|
s.append(bb).append("\n");
|
|
|
|
|
|
|
|
for (Iterator ss = getSuccNodes(bb); ss.hasNext();)
|
|
|
|
s.append(" -->" + ss.next() + "\n");
|
|
|
|
|
|
|
|
for (int j = bb.getFirstInstructionIndex(); j <= bb.getLastInstructionIndex(); j++)
|
|
|
|
if (insts[j] != null)
|
|
|
|
s.append(" " + insts[j].toString(symtab) + "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
s.append("-- END --");
|
|
|
|
return s.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static enum ScopeType {
|
|
|
|
LOCAL, GLOBAL, SCRIPT, FUNCTION, TYPE
|
|
|
|
};
|
|
|
|
|
|
|
|
private static final boolean DEBUG = false;
|
|
|
|
|
|
|
|
protected class FinalCAstSymbol implements CAstSymbol {
|
|
|
|
private final String _name;
|
2014-03-16 22:05:49 +00:00
|
|
|
private final CAstType type;
|
|
|
|
|
|
|
|
private FinalCAstSymbol(String _name, CAstType type) {
|
2012-09-04 22:56:05 +00:00
|
|
|
this._name = _name;
|
2014-03-16 22:05:49 +00:00
|
|
|
this.type = type;
|
|
|
|
assert _name != null;
|
|
|
|
assert type != null;
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
@Override
|
|
|
|
public CAstType type() {
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String name() {
|
|
|
|
return _name;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isFinal() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isCaseInsensitive() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isInternalName() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Object defaultInitValue() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class InternalCAstSymbol extends CAstSymbolImplBase {
|
2014-03-16 22:05:49 +00:00
|
|
|
public InternalCAstSymbol(String _name, CAstType type) {
|
|
|
|
super(_name, type, false, false, null);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
public InternalCAstSymbol(String _name, CAstType type, boolean _isFinal) {
|
|
|
|
super(_name, type, _isFinal, false, null);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
public InternalCAstSymbol(String _name, CAstType type, boolean _isFinal, boolean _isCaseInsensitive) {
|
|
|
|
super(_name, type, _isFinal, _isCaseInsensitive, null);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
public InternalCAstSymbol(String _name, CAstType type, boolean _isFinal, boolean _isCaseInsensitive, Object _defaultInitValue) {
|
|
|
|
super(_name, type, _isFinal, _isCaseInsensitive, _defaultInitValue);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isInternalName() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* interface for name information stored in a symbol table.
|
|
|
|
*
|
|
|
|
* @see Scope
|
|
|
|
*/
|
|
|
|
protected interface Symbol {
|
|
|
|
int valueNumber();
|
|
|
|
|
|
|
|
Scope getDefiningScope();
|
|
|
|
|
|
|
|
boolean isParameter();
|
|
|
|
|
|
|
|
Object constant();
|
|
|
|
|
|
|
|
void setConstant(Object s);
|
|
|
|
|
|
|
|
boolean isFinal();
|
|
|
|
|
|
|
|
boolean isInternalName();
|
|
|
|
|
|
|
|
Object defaultInitValue();
|
2014-03-16 22:05:49 +00:00
|
|
|
|
|
|
|
CAstType type();
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* a scope in the symbol table built during AST traversal
|
|
|
|
*/
|
|
|
|
public interface Scope {
|
|
|
|
|
|
|
|
ScopeType type();
|
|
|
|
|
|
|
|
int allocateTempValue();
|
|
|
|
|
|
|
|
int getConstantValue(Object c);
|
|
|
|
|
|
|
|
boolean isConstant(int valueNumber);
|
|
|
|
|
|
|
|
Object getConstantObject(int valueNumber);
|
|
|
|
|
|
|
|
void declare(CAstSymbol s);
|
|
|
|
|
|
|
|
void declare(CAstSymbol s, int valueNumber);
|
|
|
|
|
|
|
|
boolean isCaseInsensitive(String name);
|
|
|
|
|
|
|
|
boolean contains(String name);
|
|
|
|
|
|
|
|
Symbol lookup(String name);
|
|
|
|
|
|
|
|
Iterator<String> getAllNames();
|
|
|
|
|
|
|
|
int size();
|
|
|
|
|
|
|
|
boolean isGlobal(Symbol s);
|
|
|
|
|
|
|
|
boolean isLexicallyScoped(Symbol s);
|
|
|
|
|
|
|
|
CAstEntity getEntity();
|
|
|
|
|
|
|
|
Scope getParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static abstract class AbstractSymbol implements Symbol {
|
|
|
|
private Object constantValue;
|
|
|
|
|
|
|
|
private boolean isFinalValue;
|
|
|
|
|
|
|
|
private final Scope definingScope;
|
|
|
|
|
|
|
|
private Object defaultValue;
|
|
|
|
|
|
|
|
AbstractSymbol(Scope definingScope, boolean isFinalValue, Object defaultValue) {
|
|
|
|
this.definingScope = definingScope;
|
|
|
|
this.isFinalValue = isFinalValue;
|
|
|
|
this.defaultValue = defaultValue;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isFinal() {
|
|
|
|
return isFinalValue;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Object defaultInitValue() {
|
|
|
|
return defaultValue;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Object constant() {
|
|
|
|
return constantValue;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void setConstant(Object cv) {
|
|
|
|
constantValue = cv;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Scope getDefiningScope() {
|
|
|
|
return definingScope;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
private abstract class AbstractScope implements Scope {
|
|
|
|
private final Scope parent;
|
|
|
|
|
|
|
|
private final Map<String, Symbol> values = new LinkedHashMap<String, Symbol>();
|
|
|
|
|
|
|
|
private final Map<String, String> caseInsensitiveNames = new LinkedHashMap<String, String>();
|
|
|
|
|
|
|
|
protected abstract SymbolTable getUnderlyingSymtab();
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Scope getParent() {
|
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int size() {
|
|
|
|
return getUnderlyingSymtab().getMaxValueNumber() + 1;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Iterator<String> getAllNames() {
|
|
|
|
return values.keySet().iterator();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int allocateTempValue() {
|
|
|
|
return getUnderlyingSymtab().newSymbol();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int getConstantValue(Object o) {
|
|
|
|
if (o instanceof Integer) {
|
|
|
|
return getUnderlyingSymtab().getConstant(((Integer) o).intValue());
|
|
|
|
} else if (o instanceof Float) {
|
|
|
|
return getUnderlyingSymtab().getConstant(((Float) o).floatValue());
|
|
|
|
} else if (o instanceof Double) {
|
|
|
|
return getUnderlyingSymtab().getConstant(((Double) o).doubleValue());
|
|
|
|
} else if (o instanceof Long) {
|
|
|
|
return getUnderlyingSymtab().getConstant(((Long) o).longValue());
|
|
|
|
} else if (o instanceof String) {
|
|
|
|
return getUnderlyingSymtab().getConstant((String) o);
|
|
|
|
} else if (o instanceof Boolean) {
|
|
|
|
return getUnderlyingSymtab().getConstant((Boolean) o);
|
|
|
|
} else if (o instanceof Character) {
|
|
|
|
return getUnderlyingSymtab().getConstant(((Character) o).charValue());
|
|
|
|
} else if (o instanceof Byte) {
|
|
|
|
return getUnderlyingSymtab().getConstant(((Byte) o).byteValue());
|
|
|
|
} else if (o instanceof Short) {
|
|
|
|
return getUnderlyingSymtab().getConstant(((Short) o).shortValue());
|
|
|
|
} else if (o == null) {
|
|
|
|
return getUnderlyingSymtab().getNullConstant();
|
|
|
|
} else if (o == CAstControlFlowMap.SWITCH_DEFAULT) {
|
|
|
|
return getUnderlyingSymtab().getConstant("__default label");
|
|
|
|
} else {
|
|
|
|
System.err.println(("cannot handle constant " + o));
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isConstant(int valueNumber) {
|
|
|
|
return getUnderlyingSymtab().isConstant(valueNumber);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Object getConstantObject(int valueNumber) {
|
|
|
|
return getUnderlyingSymtab().getConstantValue(valueNumber);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void declare(CAstSymbol s, int vn) {
|
|
|
|
String nm = s.name();
|
|
|
|
assert !contains(nm) : nm;
|
|
|
|
if (s.isCaseInsensitive())
|
|
|
|
caseInsensitiveNames.put(nm.toLowerCase(), nm);
|
|
|
|
values.put(nm, makeSymbol(s, vn));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void declare(CAstSymbol s) {
|
|
|
|
String nm = s.name();
|
|
|
|
if (!contains(nm) || lookup(nm).getDefiningScope() != this) {
|
|
|
|
if (s.isCaseInsensitive())
|
|
|
|
caseInsensitiveNames.put(nm.toLowerCase(), nm);
|
|
|
|
values.put(nm, makeSymbol(s));
|
|
|
|
} else {
|
|
|
|
assert !s.isFinal() : "trying to redeclare " + nm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AbstractScope(Scope parent) {
|
|
|
|
this.parent = parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
private final String mapName(String nm) {
|
|
|
|
String mappedName = caseInsensitiveNames.get(nm.toLowerCase());
|
|
|
|
return (mappedName == null) ? nm : mappedName;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected Symbol makeSymbol(CAstSymbol s) {
|
2014-03-16 22:05:49 +00:00
|
|
|
return makeSymbol(s.name(), s.type(), s.isFinal(), s.isInternalName(), s.defaultInitValue(), -1, this);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
protected Symbol makeSymbol(CAstSymbol s, int vn) {
|
2014-03-16 22:05:49 +00:00
|
|
|
return makeSymbol(s.name(), s.type(), s.isFinal(), s.isInternalName(), s.defaultInitValue(), vn, this);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
abstract protected Symbol makeSymbol(String nm, CAstType type, boolean isFinal, boolean isInternalName, Object defaultInitValue, int vn,
|
2012-09-04 22:56:05 +00:00
|
|
|
Scope parent);
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isCaseInsensitive(String nm) {
|
|
|
|
return caseInsensitiveNames.containsKey(nm.toLowerCase());
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Symbol lookup(String nm) {
|
|
|
|
if (contains(nm)) {
|
|
|
|
return values.get(mapName(nm));
|
|
|
|
} else {
|
|
|
|
Symbol scoped = parent.lookup(nm);
|
|
|
|
if (scoped != null && getEntityScope() == this && (isGlobal(scoped) || isLexicallyScoped(scoped))) {
|
|
|
|
values.put(nm,
|
2014-03-16 22:05:49 +00:00
|
|
|
makeSymbol(nm, scoped.type(), scoped.isFinal(), scoped.isInternalName(), scoped.defaultInitValue(), -1, scoped.getDefiningScope()));
|
2012-09-04 22:56:05 +00:00
|
|
|
if (scoped.getDefiningScope().isCaseInsensitive(nm)) {
|
|
|
|
caseInsensitiveNames.put(nm.toLowerCase(), nm);
|
|
|
|
}
|
|
|
|
return values.get(nm);
|
|
|
|
} else {
|
|
|
|
return scoped;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean contains(String nm) {
|
|
|
|
String mappedName = caseInsensitiveNames.get(nm.toLowerCase());
|
|
|
|
return values.containsKey(mappedName == null ? nm : mappedName);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isGlobal(Symbol s) {
|
|
|
|
return s.getDefiningScope().type() == ScopeType.GLOBAL;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public abstract boolean isLexicallyScoped(Symbol s);
|
|
|
|
|
|
|
|
protected abstract AbstractScope getEntityScope();
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public abstract CAstEntity getEntity();
|
|
|
|
};
|
|
|
|
|
|
|
|
private AbstractScope makeScriptScope(final CAstEntity s, Scope parent) {
|
|
|
|
return new AbstractScope(parent) {
|
|
|
|
SymbolTable scriptGlobalSymtab = new SymbolTable(s.getArgumentCount());
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public SymbolTable getUnderlyingSymtab() {
|
|
|
|
return scriptGlobalSymtab;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected AbstractScope getEntityScope() {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isLexicallyScoped(Symbol s) {
|
|
|
|
if (isGlobal(s))
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return ((AbstractScope) s.getDefiningScope()).getEntity() != getEntity();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstEntity getEntity() {
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public ScopeType type() {
|
|
|
|
return ScopeType.SCRIPT;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2014-03-16 22:05:49 +00:00
|
|
|
protected Symbol makeSymbol(final String nm, final CAstType type, final boolean isFinal, final boolean isInternalName,
|
2012-09-04 22:56:05 +00:00
|
|
|
final Object defaultInitValue, int vn, Scope definer) {
|
2014-03-16 22:05:49 +00:00
|
|
|
assert nm != null;
|
|
|
|
assert type != null;
|
2012-09-04 22:56:05 +00:00
|
|
|
final int v = vn == -1 ? getUnderlyingSymtab().newSymbol() : vn;
|
|
|
|
if (useDefaultInitValues() && defaultInitValue != null) {
|
|
|
|
if (getUnderlyingSymtab().getValue(v) == null) {
|
|
|
|
setDefaultValue(getUnderlyingSymtab(), v, defaultInitValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new AbstractSymbol(definer, isFinal, defaultInitValue) {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String toString() {
|
|
|
|
return nm + ":" + System.identityHashCode(this);
|
|
|
|
}
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
@Override
|
|
|
|
public CAstType type() {
|
|
|
|
return type;
|
|
|
|
}
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int valueNumber() {
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isInternalName() {
|
|
|
|
return isInternalName;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isParameter() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
protected int getArgumentCount(CAstEntity f) {
|
|
|
|
return f.getArgumentCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected String[] getArgumentNames(CAstEntity f) {
|
|
|
|
return f.getArgumentNames();
|
|
|
|
}
|
|
|
|
|
|
|
|
private AbstractScope makeFunctionScope(final CAstEntity f, Scope parent) {
|
|
|
|
return new AbstractScope(parent) {
|
|
|
|
private final String[] params = getArgumentNames(f);
|
|
|
|
|
|
|
|
private final SymbolTable functionSymtab = new SymbolTable(getArgumentCount(f));
|
|
|
|
|
2014-06-26 14:57:48 +00:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "scope for " + f.getName();
|
|
|
|
}
|
|
|
|
|
2012-09-04 22:56:05 +00:00
|
|
|
// ctor for scope object
|
|
|
|
{
|
|
|
|
for (int i = 0; i < getArgumentCount(f); i++) {
|
|
|
|
final int yuck = i;
|
|
|
|
declare(new CAstSymbol() {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String name() {
|
|
|
|
return params[yuck];
|
|
|
|
}
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
@Override
|
|
|
|
public CAstType type() {
|
|
|
|
if (f.getType() instanceof CAstType.Method) {
|
|
|
|
if (yuck == 0) {
|
|
|
|
return ((CAstType.Method)f.getType()).getDeclaringType();
|
|
|
|
} else {
|
|
|
|
return (CAstType) ((CAstType.Method)f.getType()).getArgumentTypes().get(yuck-1);
|
|
|
|
}
|
|
|
|
} else if (f.getType() instanceof CAstType.Function) {
|
|
|
|
return (CAstType) ((CAstType.Function)f.getType()).getArgumentTypes().get(yuck);
|
|
|
|
} else {
|
|
|
|
return topType();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isFinal() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isCaseInsensitive() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isInternalName() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Object defaultInitValue() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public SymbolTable getUnderlyingSymtab() {
|
|
|
|
return functionSymtab;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected AbstractScope getEntityScope() {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isLexicallyScoped(Symbol s) {
|
|
|
|
if (isGlobal(s))
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return ((AbstractScope) s.getDefiningScope()).getEntity() != getEntity();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstEntity getEntity() {
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public ScopeType type() {
|
|
|
|
return ScopeType.FUNCTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
private int find(String n) {
|
|
|
|
for (int i = 0; i < params.length; i++) {
|
|
|
|
if (n.equals(params[i])) {
|
|
|
|
return i + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2014-03-16 22:05:49 +00:00
|
|
|
protected Symbol makeSymbol(final String nm, final CAstType type, final boolean isFinal, final boolean isInternalName,
|
2012-09-04 22:56:05 +00:00
|
|
|
final Object defaultInitValue, final int valueNumber, Scope definer) {
|
2014-03-16 22:05:49 +00:00
|
|
|
assert nm != null;
|
|
|
|
assert type != null;
|
2012-09-04 22:56:05 +00:00
|
|
|
return new AbstractSymbol(definer, isFinal, defaultInitValue) {
|
|
|
|
final int vn;
|
|
|
|
|
|
|
|
{
|
|
|
|
int x = find(nm);
|
|
|
|
if (x != -1) {
|
|
|
|
assert valueNumber == -1;
|
|
|
|
vn = x;
|
|
|
|
} else if (valueNumber != -1) {
|
|
|
|
vn = valueNumber;
|
|
|
|
} else {
|
|
|
|
vn = getUnderlyingSymtab().newSymbol();
|
|
|
|
}
|
|
|
|
if (useDefaultInitValues() && defaultInitValue != null) {
|
|
|
|
if (getUnderlyingSymtab().getValue(vn) == null) {
|
|
|
|
setDefaultValue(getUnderlyingSymtab(), vn, defaultInitValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
@Override
|
|
|
|
public CAstType type() {
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String toString() {
|
|
|
|
return nm + ":" + System.identityHashCode(this);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int valueNumber() {
|
|
|
|
return vn;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isInternalName() {
|
|
|
|
return isInternalName;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isParameter() {
|
|
|
|
return vn <= params.length;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
private Scope makeLocalScope(CAstNode s, final Scope parent) {
|
|
|
|
return new AbstractScope(parent) {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public ScopeType type() {
|
|
|
|
return ScopeType.LOCAL;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public SymbolTable getUnderlyingSymtab() {
|
|
|
|
return ((AbstractScope) parent).getUnderlyingSymtab();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected AbstractScope getEntityScope() {
|
|
|
|
return ((AbstractScope) parent).getEntityScope();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isLexicallyScoped(Symbol s) {
|
2013-08-05 18:35:41 +00:00
|
|
|
return getEntityScope().isLexicallyScoped(s);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstEntity getEntity() {
|
2013-08-05 18:35:41 +00:00
|
|
|
return getEntityScope().getEntity();
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2014-03-16 22:05:49 +00:00
|
|
|
protected Symbol makeSymbol(final String nm, final CAstType type, boolean isFinal, final boolean isInternalName, final Object defaultInitValue,
|
2012-09-04 22:56:05 +00:00
|
|
|
int vn, Scope definer) {
|
|
|
|
final int v = vn == -1 ? getUnderlyingSymtab().newSymbol() : vn;
|
|
|
|
if (useDefaultInitValues() && defaultInitValue != null) {
|
|
|
|
if (getUnderlyingSymtab().getValue(v) == null) {
|
|
|
|
setDefaultValue(getUnderlyingSymtab(), v, defaultInitValue);
|
|
|
|
}
|
|
|
|
}
|
2014-03-16 22:05:49 +00:00
|
|
|
assert nm != null;
|
|
|
|
assert type != null;
|
2012-09-04 22:56:05 +00:00
|
|
|
return new AbstractSymbol(definer, isFinal, defaultInitValue) {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String toString() {
|
|
|
|
return nm + ":" + System.identityHashCode(this);
|
|
|
|
}
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
@Override
|
|
|
|
public CAstType type() {
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int valueNumber() {
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isInternalName() {
|
|
|
|
return isInternalName;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isParameter() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
private Scope makeGlobalScope() {
|
|
|
|
final Map<String, AbstractSymbol> globalSymbols = new LinkedHashMap<String, AbstractSymbol>();
|
|
|
|
final Map<String, String> caseInsensitiveNames = new LinkedHashMap<String, String>();
|
|
|
|
return new Scope() {
|
2014-06-26 14:57:48 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "global scope";
|
|
|
|
}
|
|
|
|
|
2012-09-04 22:56:05 +00:00
|
|
|
private final String mapName(String nm) {
|
|
|
|
String mappedName = caseInsensitiveNames.get(nm.toLowerCase());
|
|
|
|
return (mappedName == null) ? nm : mappedName;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Scope getParent() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isGlobal(Symbol s) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isLexicallyScoped(Symbol s) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstEntity getEntity() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int size() {
|
|
|
|
return globalSymbols.size();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Iterator<String> getAllNames() {
|
|
|
|
return globalSymbols.keySet().iterator();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int allocateTempValue() {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int getConstantValue(Object c) {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isConstant(int valueNumber) {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Object getConstantObject(int valueNumber) {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public ScopeType type() {
|
|
|
|
return ScopeType.GLOBAL;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean contains(String name) {
|
|
|
|
return hasImplicitGlobals() || globalSymbols.containsKey(mapName(name));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isCaseInsensitive(String name) {
|
|
|
|
return caseInsensitiveNames.containsKey(name.toLowerCase());
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Symbol lookup(final String name) {
|
|
|
|
if (!globalSymbols.containsKey(mapName(name))) {
|
|
|
|
if (hasImplicitGlobals()) {
|
|
|
|
declare(new CAstSymbol() {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String name() {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isFinal() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isCaseInsensitive() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isInternalName() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Object defaultInitValue() {
|
|
|
|
return null;
|
|
|
|
}
|
2014-03-16 22:05:49 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public CAstType type() {
|
|
|
|
return topType();
|
|
|
|
}
|
2012-09-04 22:56:05 +00:00
|
|
|
});
|
|
|
|
} else if (hasSpecialUndeclaredVariables()) {
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
throw new Error("cannot find " + name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return globalSymbols.get(mapName(name));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void declare(CAstSymbol s, int vn) {
|
|
|
|
assert vn == -1;
|
|
|
|
declare(s);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void declare(final CAstSymbol s) {
|
|
|
|
final String name = s.name();
|
|
|
|
if (s.isCaseInsensitive()) {
|
|
|
|
caseInsensitiveNames.put(name.toLowerCase(), name);
|
|
|
|
}
|
|
|
|
globalSymbols.put(name, new AbstractSymbol(this, s.isFinal(), s.defaultInitValue()) {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String toString() {
|
|
|
|
return name + ":" + System.identityHashCode(this);
|
|
|
|
}
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
@Override
|
|
|
|
public CAstType type() {
|
|
|
|
return s.type();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isParameter() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isInternalName() {
|
|
|
|
return s.isInternalName();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int valueNumber() {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
protected Scope makeTypeScope(final CAstEntity type, final Scope parent) {
|
|
|
|
final Map<String, AbstractSymbol> typeSymbols = new LinkedHashMap<String, AbstractSymbol>();
|
|
|
|
final Map<String, String> caseInsensitiveNames = new LinkedHashMap<String, String>();
|
|
|
|
return new Scope() {
|
|
|
|
private final String mapName(String nm) {
|
|
|
|
String mappedName = caseInsensitiveNames.get(nm.toLowerCase());
|
|
|
|
return (mappedName == null) ? nm : mappedName;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Scope getParent() {
|
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isGlobal(Symbol s) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isLexicallyScoped(Symbol s) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstEntity getEntity() {
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int size() {
|
|
|
|
return typeSymbols.size();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Iterator<String> getAllNames() {
|
|
|
|
return typeSymbols.keySet().iterator();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int allocateTempValue() {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int getConstantValue(Object c) {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isConstant(int valueNumber) {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Object getConstantObject(int valueNumber) {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public ScopeType type() {
|
|
|
|
return ScopeType.TYPE;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean contains(String name) {
|
|
|
|
return typeSymbols.containsKey(mapName(name));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isCaseInsensitive(String name) {
|
|
|
|
return caseInsensitiveNames.containsKey(name.toLowerCase());
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Symbol lookup(String nm) {
|
|
|
|
if (typeSymbols.containsKey(mapName(nm)))
|
|
|
|
return typeSymbols.get(mapName(nm));
|
|
|
|
else {
|
|
|
|
return parent.lookup(nm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void declare(CAstSymbol s, int vn) {
|
|
|
|
assert vn == -1;
|
|
|
|
declare(s);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void declare(final CAstSymbol s) {
|
|
|
|
final String name = s.name();
|
|
|
|
assert !s.isFinal();
|
|
|
|
if (s.isCaseInsensitive())
|
|
|
|
caseInsensitiveNames.put(name.toLowerCase(), name);
|
|
|
|
typeSymbols.put(name, new AbstractSymbol(this, s.isFinal(), s.defaultInitValue()) {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String toString() {
|
|
|
|
return name + ":" + System.identityHashCode(this);
|
|
|
|
}
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
@Override
|
|
|
|
public CAstType type() {
|
|
|
|
return s.type();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isParameter() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isInternalName() {
|
|
|
|
return s.isInternalName();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int valueNumber() {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
public interface WalkContext extends CAstVisitor.Context {
|
|
|
|
|
|
|
|
ModuleEntry getModule();
|
|
|
|
|
|
|
|
String getName();
|
|
|
|
|
|
|
|
String file();
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
CAstSourcePositionMap getSourceMap();
|
|
|
|
|
|
|
|
CAstControlFlowMap getControlFlow();
|
|
|
|
|
|
|
|
Scope currentScope();
|
|
|
|
|
|
|
|
Set<Scope> entityScopes();
|
|
|
|
|
|
|
|
IncipientCFG cfg();
|
|
|
|
|
|
|
|
UnwindState getUnwindState();
|
|
|
|
|
2013-04-11 01:09:10 +00:00
|
|
|
void setCatchType(IBasicBlock bb, TypeReference catchType);
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
void setCatchType(CAstNode catchNode, TypeReference catchType);
|
|
|
|
|
2013-04-11 01:09:10 +00:00
|
|
|
Map<IBasicBlock,TypeReference[]> getCatchTypes();
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
void addEntityName(CAstEntity e, String name);
|
|
|
|
|
|
|
|
String getEntityName(CAstEntity e);
|
|
|
|
|
|
|
|
boolean hasValue(CAstNode n);
|
|
|
|
|
|
|
|
int setValue(CAstNode n, int v);
|
|
|
|
|
|
|
|
int getValue(CAstNode n);
|
|
|
|
|
|
|
|
Set<Pair<Pair<String, String>, Integer>> exposeNameSet(CAstEntity entity, boolean writeSet);
|
|
|
|
|
|
|
|
Set<Access> getAccesses(CAstEntity e);
|
|
|
|
|
|
|
|
Scope getGlobalScope();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private abstract class DelegatingContext implements WalkContext {
|
|
|
|
private final WalkContext parent;
|
|
|
|
|
|
|
|
DelegatingContext(WalkContext parent) {
|
|
|
|
this.parent = parent;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Set<Access> getAccesses(CAstEntity e) {
|
|
|
|
return parent.getAccesses(e);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public ModuleEntry getModule() {
|
|
|
|
return parent.getModule();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String getName() {
|
|
|
|
return parent.getName();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String file() {
|
|
|
|
return parent.file();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstEntity top() {
|
|
|
|
return parent.top();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstSourcePositionMap getSourceMap() {
|
|
|
|
return parent.getSourceMap();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstControlFlowMap getControlFlow() {
|
|
|
|
return parent.getControlFlow();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Scope currentScope() {
|
|
|
|
return parent.currentScope();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Set<Scope> entityScopes() {
|
|
|
|
return parent.entityScopes();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public IncipientCFG cfg() {
|
|
|
|
return parent.cfg();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public UnwindState getUnwindState() {
|
|
|
|
return parent.getUnwindState();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2013-04-11 01:09:10 +00:00
|
|
|
public void setCatchType(IBasicBlock bb, TypeReference catchType) {
|
|
|
|
parent.setCatchType(bb, catchType);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void setCatchType(CAstNode catchNode, TypeReference catchType) {
|
|
|
|
parent.setCatchType(catchNode, catchType);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2013-04-11 01:09:10 +00:00
|
|
|
public Map<IBasicBlock, TypeReference[]> getCatchTypes() {
|
2012-09-04 22:56:05 +00:00
|
|
|
return parent.getCatchTypes();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void addEntityName(CAstEntity e, String name) {
|
|
|
|
parent.addEntityName(e, name);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String getEntityName(CAstEntity e) {
|
|
|
|
return parent.getEntityName(e);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean hasValue(CAstNode n) {
|
|
|
|
return parent.hasValue(n);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int setValue(CAstNode n, int v) {
|
|
|
|
return parent.setValue(n, v);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int getValue(CAstNode n) {
|
|
|
|
return parent.getValue(n);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Set<Pair<Pair<String, String>, Integer>> exposeNameSet(CAstEntity entity, boolean writeSet) {
|
|
|
|
return parent.exposeNameSet(entity, writeSet);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Scope getGlobalScope() {
|
|
|
|
return parent.getGlobalScope();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private class FileContext extends DelegatingContext {
|
|
|
|
private final String fUnitName;
|
|
|
|
|
|
|
|
public FileContext(WalkContext parent, String unitName) {
|
|
|
|
super(parent);
|
|
|
|
fUnitName = unitName;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String getName() {
|
|
|
|
return fUnitName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class UnwindContext extends DelegatingContext {
|
|
|
|
private final UnwindState state;
|
|
|
|
|
|
|
|
UnwindContext(CAstNode unwindNode, WalkContext parent, CAstVisitor<WalkContext> visitor) {
|
|
|
|
super(parent);
|
|
|
|
this.state = new UnwindState(unwindNode, parent, visitor);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public UnwindState getUnwindState() {
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private abstract class EntityContext extends DelegatingContext {
|
|
|
|
protected final CAstEntity topNode;
|
|
|
|
|
|
|
|
protected final String name;
|
|
|
|
|
|
|
|
EntityContext(WalkContext parent, CAstEntity s) {
|
|
|
|
super(parent);
|
|
|
|
this.topNode = s;
|
|
|
|
this.name = composeEntityName(parent, s);
|
|
|
|
addEntityName(s, this.name);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String getName() {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstEntity top() {
|
|
|
|
return topNode;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstSourcePositionMap getSourceMap() {
|
|
|
|
return top().getSourceMap();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private class CodeEntityContext extends EntityContext {
|
|
|
|
private final Scope topEntityScope;
|
|
|
|
|
|
|
|
private final Set<Scope> allEntityScopes;
|
|
|
|
|
|
|
|
private final IncipientCFG cfg;
|
|
|
|
|
2013-04-11 01:09:10 +00:00
|
|
|
private final Map<IBasicBlock,TypeReference[]> catchTypes = HashMapFactory.make();
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
Set<Pair<Pair<String, String>, Integer>> exposedReads;
|
|
|
|
Set<Pair<Pair<String, String>, Integer>> exposedWrites;
|
|
|
|
|
|
|
|
Set<Access> accesses;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* maps nodes in the current function to the value number holding their value
|
|
|
|
* or, for constants, to their constant value.
|
|
|
|
*/
|
|
|
|
private final Map<CAstNode, Integer> results = new LinkedHashMap<CAstNode, Integer>();
|
|
|
|
|
|
|
|
CodeEntityContext(WalkContext parent, Scope entityScope, CAstEntity s) {
|
|
|
|
super(parent, s);
|
|
|
|
|
|
|
|
this.topEntityScope = entityScope;
|
|
|
|
|
|
|
|
this.allEntityScopes = HashSetFactory.make();
|
|
|
|
this.allEntityScopes.add(entityScope);
|
|
|
|
|
|
|
|
cfg = new IncipientCFG();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Set<Access> getAccesses(CAstEntity e) {
|
|
|
|
if (e == topNode) {
|
|
|
|
if (accesses == null) {
|
|
|
|
accesses = HashSetFactory.make();
|
|
|
|
}
|
|
|
|
return accesses;
|
|
|
|
} else {
|
|
|
|
return super.getAccesses(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Set<Pair<Pair<String, String>, Integer>> exposeNameSet(CAstEntity entity, boolean writeSet) {
|
|
|
|
if (entity == topNode) {
|
|
|
|
if (writeSet) {
|
|
|
|
if (exposedWrites == null) {
|
|
|
|
exposedWrites = HashSetFactory.make();
|
|
|
|
}
|
|
|
|
return exposedWrites;
|
|
|
|
} else {
|
|
|
|
if (exposedReads == null) {
|
|
|
|
exposedReads = HashSetFactory.make();
|
|
|
|
}
|
|
|
|
return exposedReads;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return super.exposeNameSet(entity, writeSet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstControlFlowMap getControlFlow() {
|
|
|
|
return top().getControlFlow();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public IncipientCFG cfg() {
|
|
|
|
return cfg;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Scope currentScope() {
|
|
|
|
return topEntityScope;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Set<Scope> entityScopes() {
|
|
|
|
return allEntityScopes;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public UnwindState getUnwindState() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void setCatchType(CAstNode catchNode, TypeReference catchType) {
|
2013-04-11 01:09:10 +00:00
|
|
|
setCatchType(cfg.getBlock(catchNode), catchType);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2013-04-11 01:09:10 +00:00
|
|
|
public void setCatchType(IBasicBlock bb, TypeReference catchType) {
|
|
|
|
if (! catchTypes.containsKey(bb)) {
|
|
|
|
catchTypes.put(bb, new TypeReference[] { catchType });
|
2012-09-04 22:56:05 +00:00
|
|
|
} else {
|
2013-04-11 01:09:10 +00:00
|
|
|
TypeReference[] data = catchTypes.get(bb);
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < data.length; i++) {
|
|
|
|
if (data[i] == catchType) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeReference[] newData = new TypeReference[data.length + 1];
|
|
|
|
System.arraycopy(data, 0, newData, 0, data.length);
|
|
|
|
newData[data.length] = catchType;
|
|
|
|
|
2013-04-11 01:09:10 +00:00
|
|
|
catchTypes.put(bb, newData);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2013-04-11 01:09:10 +00:00
|
|
|
public Map<IBasicBlock,TypeReference[]> getCatchTypes() {
|
2012-09-04 22:56:05 +00:00
|
|
|
return catchTypes;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean hasValue(CAstNode n) {
|
|
|
|
return results.containsKey(n);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public final int setValue(CAstNode n, int v) {
|
|
|
|
results.put(n, new Integer(v));
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public final int getValue(CAstNode n) {
|
|
|
|
if (results.containsKey(n))
|
|
|
|
return results.get(n).intValue();
|
|
|
|
else {
|
|
|
|
if (DEBUG) {
|
|
|
|
System.err.println(("no value for " + n.getKind()));
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private final class TypeContext extends EntityContext {
|
|
|
|
|
|
|
|
private TypeContext(WalkContext parent, CAstEntity n) {
|
|
|
|
super(parent, n);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstControlFlowMap getControlFlow() {
|
|
|
|
Assertions.UNREACHABLE("TypeContext.getControlFlow()");
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public IncipientCFG cfg() {
|
|
|
|
Assertions.UNREACHABLE("TypeContext.cfg()");
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public UnwindState getUnwindState() {
|
|
|
|
Assertions.UNREACHABLE("TypeContext.getUnwindState()");
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class LocalContext extends DelegatingContext {
|
|
|
|
private final Scope localScope;
|
|
|
|
|
|
|
|
LocalContext(WalkContext parent, Scope localScope) {
|
|
|
|
super(parent);
|
|
|
|
this.localScope = localScope;
|
|
|
|
parent.entityScopes().add(localScope);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Scope currentScope() {
|
|
|
|
return localScope;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* lexical access information for some entity scope. used during call graph
|
|
|
|
* construction to handle lexical accesses.
|
|
|
|
*/
|
|
|
|
public static class AstLexicalInformation implements LexicalInformation {
|
|
|
|
/**
|
|
|
|
* the name of this function, as it appears in the definer portion of a
|
|
|
|
* lexical name
|
|
|
|
*/
|
|
|
|
private final String functionLexicalName;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* names possibly accessed in a nested lexical scope, represented as pairs
|
|
|
|
* (name,nameOfDefiningEntity)
|
|
|
|
*/
|
|
|
|
private final Pair<String, String>[] exposedNames;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* map from instruction index and exposed name (via its index in
|
|
|
|
* {@link #exposedNames}) to the value number for the name at that
|
|
|
|
* instruction index. This can vary at different instructions due to SSA
|
|
|
|
* (and this information is updated during {@link SSAConversion}).
|
|
|
|
*/
|
|
|
|
private final int[][] instructionLexicalUses;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* maps each exposed name (via its index in {@link #exposedNames}) to its
|
|
|
|
* value number at method exit.
|
|
|
|
*/
|
|
|
|
private final int[] exitLexicalUses;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* the names of the enclosing methods declaring names that are lexically
|
|
|
|
* accessed by the entity
|
|
|
|
*/
|
|
|
|
private final String[] scopingParents;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* all value numbers appearing as entries in {@link #instructionLexicalUses}
|
|
|
|
* and {@link #exitLexicalUses}, computed lazily
|
|
|
|
*/
|
|
|
|
private MutableIntSet allExposedUses = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* names of exposed variables of this method that cannot be written outside
|
|
|
|
*/
|
|
|
|
private final Set<String> readOnlyNames;
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
public AstLexicalInformation(AstLexicalInformation original) {
|
|
|
|
this.functionLexicalName = original.functionLexicalName;
|
|
|
|
|
|
|
|
if (original.exposedNames != null) {
|
|
|
|
exposedNames = new Pair[original.exposedNames.length];
|
|
|
|
for (int i = 0; i < exposedNames.length; i++) {
|
|
|
|
exposedNames[i] = Pair.make(original.exposedNames[i].fst, original.exposedNames[i].snd);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
exposedNames = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
instructionLexicalUses = new int[original.instructionLexicalUses.length][];
|
|
|
|
for (int i = 0; i < instructionLexicalUses.length; i++) {
|
|
|
|
int[] x = original.instructionLexicalUses[i];
|
|
|
|
if (x != null) {
|
|
|
|
instructionLexicalUses[i] = new int[x.length];
|
|
|
|
for (int j = 0; j < x.length; j++) {
|
|
|
|
instructionLexicalUses[i][j] = x[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (original.exitLexicalUses != null) {
|
|
|
|
exitLexicalUses = new int[original.exitLexicalUses.length];
|
|
|
|
for (int i = 0; i < exitLexicalUses.length; i++) {
|
|
|
|
exitLexicalUses[i] = original.exitLexicalUses[i];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
exitLexicalUses = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (original.scopingParents != null) {
|
|
|
|
scopingParents = new String[original.scopingParents.length];
|
|
|
|
for (int i = 0; i < scopingParents.length; i++) {
|
|
|
|
scopingParents[i] = original.scopingParents[i];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
scopingParents = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
readOnlyNames = original.readOnlyNames;
|
|
|
|
}
|
|
|
|
|
|
|
|
private int[] buildLexicalUseArray(Pair<Pair<String, String>, Integer>[] exposedNames, String entityName) {
|
|
|
|
if (exposedNames != null) {
|
|
|
|
int[] lexicalUses = new int[exposedNames.length];
|
|
|
|
for (int j = 0; j < exposedNames.length; j++) {
|
|
|
|
if (entityName == null || entityName.equals(exposedNames[j].fst.snd)) {
|
|
|
|
lexicalUses[j] = exposedNames[j].snd;
|
|
|
|
} else {
|
|
|
|
lexicalUses[j] = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return lexicalUses;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Pair<String, String>[] buildLexicalNamesArray(Pair<Pair<String, String>, Integer>[] exposedNames) {
|
|
|
|
if (exposedNames != null) {
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
Pair<String, String>[] lexicalNames = new Pair[exposedNames.length];
|
|
|
|
for (int j = 0; j < exposedNames.length; j++) {
|
|
|
|
lexicalNames[j] = exposedNames[j].fst;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lexicalNames;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
AstLexicalInformation(String entityName, Scope scope, SSAInstruction[] instrs,
|
|
|
|
Set<Pair<Pair<String, String>, Integer>> exposedNamesForReadSet,
|
|
|
|
Set<Pair<Pair<String, String>, Integer>> exposedNamesForWriteSet, Set<Access> accesses) {
|
|
|
|
this.functionLexicalName = entityName;
|
|
|
|
|
|
|
|
Pair<Pair<String, String>, Integer>[] EN = null;
|
|
|
|
if (exposedNamesForReadSet != null || exposedNamesForWriteSet != null) {
|
|
|
|
Set<Pair<Pair<String, String>, Integer>> exposedNamesSet = new HashSet<Pair<Pair<String, String>, Integer>>();
|
|
|
|
if (exposedNamesForReadSet != null) {
|
|
|
|
exposedNamesSet.addAll(exposedNamesForReadSet);
|
|
|
|
}
|
|
|
|
if (exposedNamesForWriteSet != null) {
|
|
|
|
exposedNamesSet.addAll(exposedNamesForWriteSet);
|
|
|
|
}
|
|
|
|
EN = exposedNamesSet.toArray(new Pair[exposedNamesSet.size()]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (exposedNamesForReadSet != null) {
|
|
|
|
Set<String> readOnlyNames = new HashSet<String>();
|
|
|
|
for (Pair<Pair<String, String>, Integer> v : exposedNamesForReadSet) {
|
|
|
|
if (entityName != null && entityName.equals(v.fst.snd)) {
|
|
|
|
readOnlyNames.add(v.fst.fst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (exposedNamesForWriteSet != null) {
|
|
|
|
for (Pair<Pair<String, String>, Integer> v : exposedNamesForWriteSet) {
|
|
|
|
if (entityName != null && entityName.equals(v.fst.snd)) {
|
|
|
|
readOnlyNames.remove(v.fst.fst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.readOnlyNames = readOnlyNames;
|
|
|
|
} else {
|
|
|
|
this.readOnlyNames = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.exposedNames = buildLexicalNamesArray(EN);
|
|
|
|
|
|
|
|
// the value numbers stored in exitLexicalUses and instructionLexicalUses
|
|
|
|
// are identical at first; they will be updated
|
|
|
|
// as needed during the final SSA conversion
|
|
|
|
this.exitLexicalUses = buildLexicalUseArray(EN, entityName);
|
|
|
|
|
|
|
|
this.instructionLexicalUses = new int[instrs.length][];
|
|
|
|
for (int i = 0; i < instrs.length; i++) {
|
|
|
|
if (instrs[i] instanceof SSAAbstractInvokeInstruction) {
|
|
|
|
this.instructionLexicalUses[i] = buildLexicalUseArray(EN, null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (accesses != null) {
|
|
|
|
Set<String> parents = new LinkedHashSet<String>();
|
|
|
|
for (Iterator<Access> ACS = accesses.iterator(); ACS.hasNext();) {
|
|
|
|
Access AC = ACS.next();
|
|
|
|
if (AC.variableDefiner != null) {
|
|
|
|
parents.add(AC.variableDefiner);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
scopingParents = parents.toArray(new String[parents.size()]);
|
|
|
|
|
|
|
|
if (DEBUG_LEXICAL) {
|
|
|
|
System.err.println(("scoping parents of " + scope.getEntity()));
|
|
|
|
System.err.println(parents.toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
scopingParents = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DEBUG_NAMES) {
|
|
|
|
System.err.println(("lexical uses of " + scope.getEntity()));
|
|
|
|
for (int i = 0; i < instructionLexicalUses.length; i++) {
|
|
|
|
if (instructionLexicalUses[i] != null) {
|
|
|
|
System.err.println((" lexical uses of " + instrs[i]));
|
|
|
|
for (int j = 0; j < instructionLexicalUses[i].length; j++) {
|
|
|
|
System.err.println((" " + this.exposedNames[j].fst + ": " + instructionLexicalUses[i][j]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int[] getExitExposedUses() {
|
|
|
|
return exitLexicalUses;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static final int[] NONE = new int[0];
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int[] getExposedUses(int instructionOffset) {
|
|
|
|
return instructionLexicalUses[instructionOffset] == null ? NONE : instructionLexicalUses[instructionOffset];
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public IntSet getAllExposedUses() {
|
|
|
|
if (allExposedUses == null) {
|
|
|
|
allExposedUses = IntSetUtil.make();
|
|
|
|
if (exitLexicalUses != null) {
|
|
|
|
for (int i = 0; i < exitLexicalUses.length; i++) {
|
|
|
|
if (exitLexicalUses[i] > 0) {
|
|
|
|
allExposedUses.add(exitLexicalUses[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (instructionLexicalUses != null) {
|
|
|
|
for (int i = 0; i < instructionLexicalUses.length; i++) {
|
|
|
|
if (instructionLexicalUses[i] != null) {
|
|
|
|
for (int j = 0; j < instructionLexicalUses[i].length; j++) {
|
|
|
|
if (instructionLexicalUses[i][j] > 0) {
|
|
|
|
allExposedUses.add(instructionLexicalUses[i][j]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return allExposedUses;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Pair<String, String>[] getExposedNames() {
|
|
|
|
return exposedNames;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String[] getScopingParents() {
|
|
|
|
return scopingParents;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean isReadOnly(String name) {
|
|
|
|
return readOnlyNames != null && readOnlyNames.contains(name);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String getScopingName() {
|
|
|
|
return functionLexicalName;
|
|
|
|
}
|
2013-06-06 23:18:16 +00:00
|
|
|
|
|
|
|
public static boolean hasExposedUses(CGNode caller, CallSiteReference site) {
|
|
|
|
int uses[] = ((AstMethod) caller.getMethod()).lexicalInfo().getExposedUses(site.getProgramCounter());
|
|
|
|
if (uses != null && uses.length > 0) {
|
|
|
|
for (int use : uses) {
|
|
|
|
if (use > 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2012-09-04 22:56:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* record that in entity e, the access is performed.
|
|
|
|
*
|
|
|
|
* If {@link #useLocalValuesForLexicalVars()} is true, the access is performed
|
|
|
|
* using a local variable. in
|
|
|
|
* {@link #patchLexicalAccesses(SSAInstruction[], Set)}, this information is
|
|
|
|
* used to update an instruction that performs all the accesses at the
|
|
|
|
* beginning of the method and defines the locals.
|
|
|
|
*/
|
|
|
|
private void addAccess(WalkContext context, CAstEntity e, Access access) {
|
|
|
|
context.getAccesses(e).add(access);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Record that a name assigned a value number in the scope of entity may be
|
|
|
|
* accessed by a lexically nested scope, i.e., the name may be
|
|
|
|
* <em>exposed</em> to lexically nested scopes. This information is needed
|
|
|
|
* during call graph construction to properly model the data flow due to the
|
|
|
|
* access in the nested scope.
|
|
|
|
*
|
|
|
|
* @param entity
|
|
|
|
* an entity in whose scope name is assigned a value number
|
|
|
|
* @param declaration
|
|
|
|
* the declaring entity for name (possibly an enclosing scope of
|
|
|
|
* entity, in the case where entity
|
|
|
|
* {@link #useLocalValuesForLexicalVars() accesses the name via a
|
|
|
|
* local})
|
|
|
|
* @param name
|
|
|
|
* the accessed name
|
|
|
|
* @param valueNumber
|
|
|
|
* the name's value number in the scope of entity
|
|
|
|
*/
|
|
|
|
private void addExposedName(CAstEntity entity, CAstEntity declaration, String name, int valueNumber, boolean isWrite, WalkContext context) {
|
|
|
|
Pair<Pair<String, String>, Integer> newVal = Pair.make(Pair.make(name, context.getEntityName(declaration)), valueNumber);
|
|
|
|
context.exposeNameSet(entity, isWrite).add(newVal);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setDefaultValue(SymbolTable symtab, int vn, Object value) {
|
|
|
|
if (value == CAstSymbol.NULL_DEFAULT_VALUE) {
|
|
|
|
symtab.setDefaultValue(vn, null);
|
|
|
|
} else {
|
|
|
|
symtab.setDefaultValue(vn, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected IUnaryOpInstruction.IOperator translateUnaryOpcode(CAstNode op) {
|
|
|
|
if (op == CAstOperator.OP_BITNOT)
|
|
|
|
return AstConstants.UnaryOp.BITNOT;
|
|
|
|
else if (op == CAstOperator.OP_NOT)
|
|
|
|
return IUnaryOpInstruction.Operator.NEG;
|
|
|
|
else if (op == CAstOperator.OP_SUB)
|
|
|
|
return AstConstants.UnaryOp.MINUS;
|
|
|
|
else if (op == CAstOperator.OP_ADD)
|
|
|
|
return AstConstants.UnaryOp.PLUS;
|
|
|
|
else
|
|
|
|
Assertions.UNREACHABLE("cannot translate " + CAstPrinter.print(op));
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
protected IBinaryOpInstruction.IOperator translateBinaryOpcode(CAstNode op) {
|
|
|
|
if (op == CAstOperator.OP_ADD)
|
|
|
|
return BinaryOpInstruction.Operator.ADD;
|
|
|
|
else if (op == CAstOperator.OP_DIV)
|
|
|
|
return BinaryOpInstruction.Operator.DIV;
|
|
|
|
else if (op == CAstOperator.OP_LSH)
|
|
|
|
return ShiftInstruction.Operator.SHL;
|
|
|
|
else if (op == CAstOperator.OP_MOD)
|
|
|
|
return BinaryOpInstruction.Operator.REM;
|
|
|
|
else if (op == CAstOperator.OP_MUL)
|
|
|
|
return BinaryOpInstruction.Operator.MUL;
|
|
|
|
else if (op == CAstOperator.OP_RSH)
|
|
|
|
return ShiftInstruction.Operator.SHR;
|
|
|
|
else if (op == CAstOperator.OP_SUB)
|
|
|
|
return BinaryOpInstruction.Operator.SUB;
|
|
|
|
else if (op == CAstOperator.OP_URSH)
|
|
|
|
return ShiftInstruction.Operator.USHR;
|
|
|
|
else if (op == CAstOperator.OP_BIT_AND)
|
|
|
|
return BinaryOpInstruction.Operator.AND;
|
|
|
|
else if (op == CAstOperator.OP_BIT_OR)
|
|
|
|
return BinaryOpInstruction.Operator.OR;
|
|
|
|
else if (op == CAstOperator.OP_BIT_XOR)
|
|
|
|
return BinaryOpInstruction.Operator.XOR;
|
|
|
|
else if (op == CAstOperator.OP_CONCAT)
|
|
|
|
return AstConstants.BinaryOp.CONCAT;
|
|
|
|
else if (op == CAstOperator.OP_EQ)
|
|
|
|
return AstConstants.BinaryOp.EQ;
|
|
|
|
else if (op == CAstOperator.OP_STRICT_EQ)
|
|
|
|
return AstConstants.BinaryOp.STRICT_EQ;
|
|
|
|
else if (op == CAstOperator.OP_GE)
|
|
|
|
return AstConstants.BinaryOp.GE;
|
|
|
|
else if (op == CAstOperator.OP_GT)
|
|
|
|
return AstConstants.BinaryOp.GT;
|
|
|
|
else if (op == CAstOperator.OP_LE)
|
|
|
|
return AstConstants.BinaryOp.LE;
|
|
|
|
else if (op == CAstOperator.OP_LT)
|
|
|
|
return AstConstants.BinaryOp.LT;
|
|
|
|
else if (op == CAstOperator.OP_NE)
|
|
|
|
return AstConstants.BinaryOp.NE;
|
|
|
|
else if (op == CAstOperator.OP_STRICT_NE)
|
|
|
|
return AstConstants.BinaryOp.STRICT_NE;
|
|
|
|
else {
|
|
|
|
Assertions.UNREACHABLE("cannot translate " + CAstPrinter.print(op));
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected IConditionalBranchInstruction.IOperator translateConditionOpcode(CAstNode op) {
|
|
|
|
if (op == CAstOperator.OP_EQ)
|
|
|
|
return ConditionalBranchInstruction.Operator.EQ;
|
|
|
|
else if (op == CAstOperator.OP_GE)
|
|
|
|
return ConditionalBranchInstruction.Operator.GE;
|
|
|
|
else if (op == CAstOperator.OP_GT)
|
|
|
|
return ConditionalBranchInstruction.Operator.GT;
|
|
|
|
else if (op == CAstOperator.OP_LE)
|
|
|
|
return ConditionalBranchInstruction.Operator.LE;
|
|
|
|
else if (op == CAstOperator.OP_LT)
|
|
|
|
return ConditionalBranchInstruction.Operator.LT;
|
|
|
|
else if (op == CAstOperator.OP_NE)
|
|
|
|
return ConditionalBranchInstruction.Operator.NE;
|
|
|
|
|
|
|
|
else {
|
|
|
|
Assertions.UNREACHABLE("cannot translate " + CAstPrinter.print(op));
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-09 02:32:51 +00:00
|
|
|
protected String[] makeNameMap(CAstEntity n, Set<Scope> scopes, SSAInstruction[] insts) {
|
2012-09-04 22:56:05 +00:00
|
|
|
// all scopes share the same underlying symtab, which is what
|
|
|
|
// size really refers to.
|
|
|
|
String[] map = new String[scopes.iterator().next().size() + 1];
|
|
|
|
|
|
|
|
if (DEBUG_NAMES) {
|
|
|
|
System.err.println(("names array of size " + map.length));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Iterator<Scope> S = scopes.iterator(); S.hasNext();) {
|
|
|
|
Scope scope = S.next();
|
|
|
|
for (Iterator<String> I = scope.getAllNames(); I.hasNext();) {
|
|
|
|
String nm = I.next();
|
2013-10-16 21:37:53 +00:00
|
|
|
|
|
|
|
if (ignoreName(nm)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Symbol v = scope.lookup(nm);
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
if (v.isInternalName()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// constants can flow to multiple variables
|
|
|
|
if (scope.isConstant(v.valueNumber()))
|
|
|
|
continue;
|
|
|
|
|
2013-10-16 21:37:53 +00:00
|
|
|
assert map[v.valueNumber()] == null || map[v.valueNumber()].equals(nm) || ignoreName(map[v.valueNumber()]) : "value number " + v.valueNumber()
|
2012-09-04 22:56:05 +00:00
|
|
|
+ " mapped to multiple names in " + n.getName() + ": " + nm + " and " + map[v.valueNumber()];
|
|
|
|
|
|
|
|
map[v.valueNumber()] = nm;
|
|
|
|
|
|
|
|
if (DEBUG_NAMES) {
|
|
|
|
System.err.println(("mapping name " + nm + " to " + v.valueNumber()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return map;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected final CAstType getTypeForNode(WalkContext context, CAstNode node) {
|
|
|
|
if (context.top().getNodeTypeMap() != null) {
|
|
|
|
return context.top().getNodeTypeMap().getNodeType(node);
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Position getPosition(CAstSourcePositionMap map, CAstNode n) {
|
|
|
|
if (map.getPosition(n) != null) {
|
|
|
|
return map.getPosition(n);
|
|
|
|
} else {
|
|
|
|
for (int i = 0; i < n.getChildCount(); i++) {
|
|
|
|
Position p = getPosition(map, n.getChild(i));
|
|
|
|
if (p != null) {
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected WalkContext makeFileContext(WalkContext c, CAstEntity n) {
|
2013-10-16 21:37:53 +00:00
|
|
|
return new FileContext(c, n.getName());
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected WalkContext makeTypeContext(WalkContext c, CAstEntity n) {
|
2013-10-16 21:37:53 +00:00
|
|
|
return new TypeContext(c, n);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2013-10-16 21:37:53 +00:00
|
|
|
protected WalkContext makeCodeContext(WalkContext context, CAstEntity n) {
|
2012-09-04 22:56:05 +00:00
|
|
|
AbstractScope scope;
|
|
|
|
if (n.getKind() == CAstEntity.SCRIPT_ENTITY)
|
|
|
|
scope = makeScriptScope(n, context.currentScope());
|
|
|
|
else
|
|
|
|
scope = makeFunctionScope(n, context.currentScope());
|
|
|
|
return new CodeEntityContext(context, scope, n);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean enterEntity(final CAstEntity n, WalkContext context, CAstVisitor<WalkContext> visitor) {
|
|
|
|
if (DEBUG_TOP)
|
|
|
|
System.err.println(("translating " + n.getName()));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitFileEntity(CAstEntity n, WalkContext context, WalkContext fileContext, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveFileEntity(CAstEntity n, WalkContext context, WalkContext fileContext, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitFieldEntity(CAstEntity n, WalkContext context, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveFieldEntity(CAstEntity n, WalkContext context, CAstVisitor<WalkContext> visitor) {
|
|
|
|
// Define a new field in the enclosing type, if the language we're
|
|
|
|
// processing allows such.
|
|
|
|
CAstEntity topEntity = context.top(); // better be a type
|
|
|
|
assert topEntity.getKind() == CAstEntity.TYPE_ENTITY : "Parent of field entity is not a type???";
|
2013-10-16 21:37:53 +00:00
|
|
|
defineField(topEntity, context, n);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitGlobalEntity(CAstEntity n, WalkContext context, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveGlobalEntity(CAstEntity n, WalkContext context, CAstVisitor<WalkContext> visitor) {
|
|
|
|
// Define a new field in the enclosing type, if the language we're
|
|
|
|
// processing allows such.
|
2014-03-16 22:05:49 +00:00
|
|
|
context.getGlobalScope().declare(new CAstSymbolImpl(n.getName(), n.getType()));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitTypeEntity(CAstEntity n, WalkContext context, WalkContext typeContext, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
return !defineType(n, context);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveTypeEntity(CAstEntity n, WalkContext context, WalkContext typeContext, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitFunctionEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor<WalkContext> visitor) {
|
|
|
|
if (n.getAST() == null) // presumably abstract
|
2013-10-16 21:37:53 +00:00
|
|
|
declareFunction(n, context);
|
2012-09-04 22:56:05 +00:00
|
|
|
else
|
2013-10-16 21:37:53 +00:00
|
|
|
initFunctionEntity(n, context, codeContext);
|
2012-09-04 22:56:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveFunctionEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor<WalkContext> visitor) {
|
|
|
|
if (n.getAST() != null) // non-abstract
|
2013-10-16 21:37:53 +00:00
|
|
|
closeFunctionEntity(n, context, codeContext);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitMacroEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor<WalkContext> visitor) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitScriptEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
declareFunction(n, codeContext);
|
|
|
|
initFunctionEntity(n, context, codeContext);
|
2012-09-04 22:56:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveScriptEntity(CAstEntity n, WalkContext context, WalkContext codeContext, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
closeFunctionEntity(n, context, codeContext);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void initFunctionEntity(final CAstEntity n, WalkContext parentContext, WalkContext functionContext) {
|
|
|
|
// entry block
|
|
|
|
functionContext.cfg().makeEntryBlock(functionContext.cfg().newBlock(false));
|
|
|
|
// first real block
|
|
|
|
functionContext.cfg().newBlock(true);
|
|
|
|
// prologue code, if any
|
|
|
|
doPrologue(functionContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void closeFunctionEntity(final CAstEntity n, WalkContext parentContext, WalkContext functionContext) {
|
|
|
|
// exit block
|
|
|
|
functionContext.cfg().makeExitBlock(functionContext.cfg().newBlock(true));
|
|
|
|
|
|
|
|
// create code entry stuff for this entity
|
|
|
|
SymbolTable symtab = ((AbstractScope) functionContext.currentScope()).getUnderlyingSymtab();
|
2013-04-11 01:09:10 +00:00
|
|
|
Map<IBasicBlock,TypeReference[]> catchTypes = functionContext.getCatchTypes();
|
2013-07-30 18:04:08 +00:00
|
|
|
AstCFG cfg = new AstCFG(n, functionContext.cfg(), symtab, insts);
|
2012-09-04 22:56:05 +00:00
|
|
|
Position[] line = functionContext.cfg().getLinePositionMap();
|
|
|
|
boolean katch = functionContext.cfg().hasCatchBlock();
|
|
|
|
boolean monitor = functionContext.cfg().hasMonitorOp();
|
2014-02-09 02:32:51 +00:00
|
|
|
String[] nms = makeNameMap(n, functionContext.entityScopes(), cfg.getInstructions());
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set reachableBlocks = DFS.getReachableNodes(cfg,
|
|
|
|
* Collections.singleton(cfg.entry()));
|
|
|
|
* Assertions._assert(reachableBlocks.size() == cfg.getNumberOfNodes(),
|
|
|
|
* cfg.toString());
|
|
|
|
*/
|
|
|
|
|
|
|
|
// (put here to allow subclasses to handle stuff in scoped entities)
|
|
|
|
// assemble lexical information
|
2013-10-16 21:37:53 +00:00
|
|
|
AstLexicalInformation LI = new AstLexicalInformation(functionContext.getEntityName(n), functionContext.currentScope(), cfg.getInstructions(),
|
2012-09-04 22:56:05 +00:00
|
|
|
functionContext.exposeNameSet(n, false),
|
|
|
|
functionContext.exposeNameSet(n, true),
|
|
|
|
functionContext.getAccesses(n));
|
|
|
|
|
|
|
|
DebuggingInformation DBG = new AstDebuggingInformation(n.getPosition(), line, nms);
|
|
|
|
|
|
|
|
// actually make code body
|
|
|
|
defineFunction(n, parentContext, cfg, symtab, katch, catchTypes, monitor, LI, DBG);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected WalkContext makeLocalContext(WalkContext context, CAstNode n) {
|
2013-10-16 21:37:53 +00:00
|
|
|
return new LocalContext(context, makeLocalScope(n, context.currentScope()));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2014-06-26 14:57:48 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
protected WalkContext makeSpecialParentContext(final WalkContext context, CAstNode n) {
|
|
|
|
final String specialName = (String) n.getChild(0).getValue();
|
|
|
|
|
|
|
|
return new LocalContext(context, new AbstractScope(context.currentScope()) {
|
|
|
|
private Scope parent = null;
|
|
|
|
|
|
|
|
private Scope parent() {
|
|
|
|
if (parent == null) {
|
|
|
|
parent = ((AbstractScope)context.currentScope()).getEntityScope().getParent();
|
|
|
|
}
|
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ScopeType type() {
|
|
|
|
return ScopeType.LOCAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Scope scopeFor(String name) {
|
|
|
|
if (name.equals(specialName)) {
|
|
|
|
return parent();
|
|
|
|
} else {
|
|
|
|
return context.currentScope();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean contains(String name) {
|
|
|
|
return scopeFor(name).contains(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Symbol lookup(String name) {
|
|
|
|
return scopeFor(name).lookup(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected SymbolTable getUnderlyingSymtab() {
|
|
|
|
return ((AbstractScope)context.currentScope()).getUnderlyingSymtab();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected Symbol makeSymbol(String nm, CAstType type, boolean isFinal, boolean isInternalName, Object defaultInitValue,
|
|
|
|
int vn, Scope parent) {
|
|
|
|
return ((AbstractScope)context.currentScope()).makeSymbol(nm, type, isFinal, isInternalName, defaultInitValue, vn, parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected AbstractScope getEntityScope() {
|
|
|
|
return ((AbstractScope)context.currentScope()).getEntityScope();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isLexicallyScoped(Symbol s) {
|
|
|
|
return context.currentScope().isLexicallyScoped(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public CAstEntity getEntity() {
|
|
|
|
return context.top();
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected WalkContext makeUnwindContext(WalkContext context, CAstNode n, CAstVisitor<WalkContext> visitor) {
|
|
|
|
// here, n represents the "finally" block of the unwind
|
2013-10-16 21:37:53 +00:00
|
|
|
return new UnwindContext(n, context, visitor);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private Map<CAstEntity, Set<String>> entity2ExposedNames;
|
|
|
|
protected int processFunctionExpr(CAstNode n, WalkContext context) {
|
|
|
|
CAstEntity fn = (CAstEntity) n.getChild(0).getValue();
|
|
|
|
declareFunction(fn, context);
|
|
|
|
int result = context.currentScope().allocateTempValue();
|
|
|
|
int ex = context.currentScope().allocateTempValue();
|
|
|
|
doMaterializeFunction(n, context, result, ex, fn);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitFunctionExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveFunctionExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
int result = processFunctionExpr(n, c);
|
|
|
|
c.setValue(n, result);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitFunctionStmt(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveFunctionStmt(CAstNode n, WalkContext context, CAstVisitor<WalkContext> visitor) {
|
|
|
|
int result = processFunctionExpr(n, context);
|
|
|
|
CAstEntity fn = (CAstEntity) n.getChild(0).getValue();
|
|
|
|
// FIXME: handle redefinitions of functions
|
|
|
|
Scope cs = context.currentScope();
|
|
|
|
if (cs.contains(fn.getName()) && !cs.isLexicallyScoped(cs.lookup(fn.getName())) && !cs.isGlobal(cs.lookup(fn.getName()))) {
|
|
|
|
// if we already have a local with the function's name, write the function
|
|
|
|
// value to that local
|
|
|
|
assignValue(n, context, cs.lookup(fn.getName()), fn.getName(), result);
|
|
|
|
} else if (topLevelFunctionsInGlobalScope() && context.top().getKind() == CAstEntity.SCRIPT_ENTITY) {
|
2014-03-16 22:05:49 +00:00
|
|
|
context.getGlobalScope().declare(new FinalCAstSymbol(fn.getName(), fn.getType()));
|
2012-09-04 22:56:05 +00:00
|
|
|
assignValue(n, context, cs.lookup(fn.getName()), fn.getName(), result);
|
|
|
|
} else {
|
2014-03-16 22:05:49 +00:00
|
|
|
context.currentScope().declare(new FinalCAstSymbol(fn.getName(), fn.getType()), result);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitLocalScope(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-06-26 14:57:48 +00:00
|
|
|
@Override
|
|
|
|
protected boolean visitSpecialParentScope(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveLocalScope(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
c.setValue(n, c.getValue(n.getChild(0)));
|
|
|
|
}
|
|
|
|
|
2014-06-26 14:57:48 +00:00
|
|
|
@Override
|
|
|
|
protected void leaveSpecialParentScope(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
c.setValue(n, c.getValue(n.getChild(1)));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitBlockExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveBlockExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
c.setValue(n, c.getValue(n.getChild(n.getChildCount() - 1)));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitBlockStmt(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveBlockStmt(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitLoop(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
// loop test block
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
PreBasicBlock headerB = context.cfg().getCurrentBlock();
|
|
|
|
visitor.visit(n.getChild(0), context, visitor);
|
|
|
|
|
|
|
|
assert c.getValue(n.getChild(0)) != -1 : "error in loop test " + CAstPrinter.print(n.getChild(0), context.top().getSourceMap())
|
|
|
|
+ " of loop " + CAstPrinter.print(n, context.top().getSourceMap());
|
|
|
|
context.cfg().addInstruction(
|
2014-04-09 14:59:51 +00:00
|
|
|
insts.ConditionalBranchInstruction(context.cfg().currentInstruction, translateConditionOpcode(CAstOperator.OP_EQ), null, c.getValue(n.getChild(0)), context
|
2014-07-08 18:44:06 +00:00
|
|
|
.currentScope().getConstantValue(new Integer(0)), -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
PreBasicBlock branchB = context.cfg().getCurrentBlock();
|
|
|
|
|
|
|
|
// loop body
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
visitor.visit(n.getChild(1), context, visitor);
|
|
|
|
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
|
2014-07-28 15:09:02 +00:00
|
|
|
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction, -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
PreBasicBlock bodyB = context.cfg().getCurrentBlock();
|
|
|
|
context.cfg().addEdge(bodyB, headerB);
|
|
|
|
|
|
|
|
// next block
|
|
|
|
context.cfg().newBlock(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
PreBasicBlock nextB = context.cfg().getCurrentBlock();
|
|
|
|
|
|
|
|
// control flow mapping;
|
|
|
|
context.cfg().addEdge(branchB, nextB);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make final to prevent overriding
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected final void leaveLoopHeader(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected final void leaveLoop(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitGetCaughtException(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveGetCaughtException(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
String nm = (String) n.getChild(0).getValue();
|
2014-03-16 22:05:49 +00:00
|
|
|
context.currentScope().declare(new FinalCAstSymbol(nm, exceptionType()));
|
2012-09-04 22:56:05 +00:00
|
|
|
context.cfg().addInstruction(
|
2014-04-09 15:33:57 +00:00
|
|
|
insts.GetCaughtExceptionInstruction(context.cfg().currentInstruction, context.cfg().getCurrentBlock().getNumber(), context.currentScope().lookup(nm)
|
2012-09-04 22:56:05 +00:00
|
|
|
.valueNumber()));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitThis(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveThis(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
c.setValue(n, 1);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitSuper(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveSuper(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
c.setValue(n, 1);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitCall(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int result = context.currentScope().allocateTempValue();
|
|
|
|
c.setValue(n, result);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveCall(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int result = c.getValue(n);
|
|
|
|
int exp = context.currentScope().allocateTempValue();
|
|
|
|
int fun = c.getValue(n.getChild(0));
|
|
|
|
CAstNode functionName = n.getChild(1);
|
|
|
|
int[] args = new int[n.getChildCount() - 2];
|
|
|
|
for (int i = 0; i < args.length; i++) {
|
|
|
|
args[i] = c.getValue(n.getChild(i + 2));
|
|
|
|
}
|
|
|
|
doCall(context, n, result, exp, functionName, fun, args);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitVar(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveVar(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
String nm = (String) n.getChild(0).getValue();
|
|
|
|
assert nm != null : "cannot find var for " + CAstPrinter.print(n, context.getSourceMap());
|
|
|
|
Symbol s = context.currentScope().lookup(nm);
|
|
|
|
assert s != null : "cannot find symbol for " + nm + " at " + CAstPrinter.print(n, context.getSourceMap());
|
2014-03-16 22:05:49 +00:00
|
|
|
assert s.type() != null : "no type for " + nm + " at " + CAstPrinter.print(n, context.getSourceMap());
|
|
|
|
TypeReference type = makeType(s.type());
|
2012-09-04 22:56:05 +00:00
|
|
|
if (context.currentScope().isGlobal(s)) {
|
2014-03-16 22:05:49 +00:00
|
|
|
c.setValue(n, doGlobalRead(n, context, nm, type));
|
2012-09-04 22:56:05 +00:00
|
|
|
} else if (context.currentScope().isLexicallyScoped(s)) {
|
2014-03-16 22:05:49 +00:00
|
|
|
c.setValue(n, doLexicallyScopedRead(n, context, nm, type));
|
2012-09-04 22:56:05 +00:00
|
|
|
} else {
|
2014-03-16 22:05:49 +00:00
|
|
|
c.setValue(n, doLocalRead(context, nm, type));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitConstant(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveConstant(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
c.setValue(n, context.currentScope().getConstantValue(n.getValue()));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitBinaryExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int result = context.currentScope().allocateTempValue();
|
|
|
|
c.setValue(n, result);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean handleBinaryOpThrow(CAstNode n, CAstNode op, WalkContext context) {
|
|
|
|
// currently, only integer / and % throw exceptions
|
|
|
|
boolean mayBeInteger = false;
|
|
|
|
Collection labels = context.getControlFlow().getTargetLabels(n);
|
|
|
|
if (!labels.isEmpty()) {
|
|
|
|
context.cfg().addPreNode(n, context.getUnwindState());
|
|
|
|
|
|
|
|
mayBeInteger = true;
|
|
|
|
assert op == CAstOperator.OP_DIV || op == CAstOperator.OP_MOD : CAstPrinter.print(n);
|
|
|
|
for (Iterator iter = labels.iterator(); iter.hasNext();) {
|
|
|
|
Object label = iter.next();
|
|
|
|
CAstNode target = context.getControlFlow().getTarget(n, label);
|
|
|
|
if (target == CAstControlFlowMap.EXCEPTION_TO_EXIT)
|
|
|
|
context.cfg().addPreEdgeToExit(n, true);
|
|
|
|
else
|
|
|
|
context.cfg().addPreEdge(n, target, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return mayBeInteger;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveBinaryExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int result = c.getValue(n);
|
|
|
|
CAstNode l = n.getChild(1);
|
|
|
|
CAstNode r = n.getChild(2);
|
|
|
|
assert c.getValue(r) != -1 : CAstPrinter.print(n);
|
|
|
|
assert c.getValue(l) != -1 : CAstPrinter.print(n);
|
|
|
|
|
|
|
|
boolean mayBeInteger = handleBinaryOpThrow(n, n.getChild(0), context);
|
|
|
|
|
|
|
|
context.cfg().addInstruction(
|
2014-04-09 14:59:51 +00:00
|
|
|
insts.BinaryOpInstruction(context.cfg().currentInstruction, translateBinaryOpcode(n.getChild(0)), false, false, result, c.getValue(l), c.getValue(r),
|
2012-09-04 22:56:05 +00:00
|
|
|
mayBeInteger));
|
|
|
|
|
|
|
|
if (mayBeInteger) {
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitUnaryExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int result = context.currentScope().allocateTempValue();
|
|
|
|
c.setValue(n, result);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveUnaryExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int result = c.getValue(n);
|
|
|
|
CAstNode v = n.getChild(1);
|
2014-04-09 14:59:51 +00:00
|
|
|
context.cfg().addInstruction(insts.UnaryOpInstruction(context.cfg().currentInstruction, translateUnaryOpcode(n.getChild(0)), result, c.getValue(v)));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitArrayLength(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int result = context.currentScope().allocateTempValue();
|
|
|
|
c.setValue(n, result);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveArrayLength(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int result = c.getValue(n);
|
|
|
|
int arrayValue = c.getValue(n.getChild(0));
|
2014-04-09 14:59:51 +00:00
|
|
|
context.cfg().addInstruction(insts.ArrayLengthInstruction(context.cfg().currentInstruction, result, arrayValue));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitArrayRef(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveArrayRef(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int arrayValue = c.getValue(n.getChild(0));
|
|
|
|
int result = context.currentScope().allocateTempValue();
|
|
|
|
c.setValue(n, result);
|
|
|
|
arrayOpHandler.doArrayRead(context, result, arrayValue, n, gatherArrayDims(c, n));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitDeclStmt(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: should we handle exploded declaration nodes here instead?
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveDeclStmt(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
CAstSymbol s = (CAstSymbol) n.getChild(0).getValue();
|
|
|
|
String nm = s.name();
|
2014-03-16 22:05:49 +00:00
|
|
|
CAstType t = s.type();
|
2012-09-04 22:56:05 +00:00
|
|
|
Scope scope = c.currentScope();
|
|
|
|
if (n.getChildCount() == 2) {
|
|
|
|
CAstNode v = n.getChild(1);
|
|
|
|
if (scope.contains(nm) && scope.lookup(nm).getDefiningScope() == scope) {
|
|
|
|
assert !s.isFinal();
|
2014-03-16 22:05:49 +00:00
|
|
|
doLocalWrite(c, nm, makeType(t), c.getValue(v));
|
2012-09-04 22:56:05 +00:00
|
|
|
} else if (v.getKind() != CAstNode.CONSTANT && v.getKind() != CAstNode.VAR && v.getKind() != CAstNode.THIS) {
|
|
|
|
scope.declare(s, c.getValue(v));
|
|
|
|
} else {
|
|
|
|
scope.declare(s);
|
2014-03-16 22:05:49 +00:00
|
|
|
doLocalWrite(c, nm, makeType(t), c.getValue(v));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
c.currentScope().declare(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitReturn(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveReturn(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
if (n.getChildCount() > 0) {
|
2014-04-09 15:33:57 +00:00
|
|
|
context.cfg().addInstruction(insts.ReturnInstruction(context.cfg().currentInstruction, c.getValue(n.getChild(0)), false));
|
2012-09-04 22:56:05 +00:00
|
|
|
} else {
|
2014-04-09 14:59:51 +00:00
|
|
|
context.cfg().addInstruction(insts.ReturnInstruction(context.cfg().currentInstruction));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
context.cfg().addPreNode(n, context.getUnwindState());
|
|
|
|
context.cfg().newBlock(false);
|
|
|
|
context.cfg().addPreEdgeToExit(n, false);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitIfgoto(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveIfgoto(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
if (n.getChildCount() == 1) {
|
|
|
|
context.cfg().addInstruction(
|
2014-04-09 15:33:57 +00:00
|
|
|
insts.ConditionalBranchInstruction(context.cfg().currentInstruction, translateConditionOpcode(CAstOperator.OP_NE), null, c.getValue(n.getChild(0)), context
|
2014-07-08 18:44:06 +00:00
|
|
|
.currentScope().getConstantValue(new Integer(0)), -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
} else if (n.getChildCount() == 3) {
|
|
|
|
context.cfg().addInstruction(
|
2014-04-09 15:33:57 +00:00
|
|
|
insts.ConditionalBranchInstruction(context.cfg().currentInstruction, translateConditionOpcode(n.getChild(0)), null, c.getValue(n.getChild(1)),
|
2014-07-08 18:44:06 +00:00
|
|
|
c.getValue(n.getChild(2)), -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
} else {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
context.cfg().addPreNode(n, context.getUnwindState());
|
|
|
|
context.cfg().addPreEdge(n, context.getControlFlow().getTarget(n, Boolean.TRUE), false);
|
2015-02-26 14:34:03 +00:00
|
|
|
|
|
|
|
context.cfg().newBlock(true);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitGoto(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveGoto(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
|
|
|
|
context.cfg().addPreNode(n, context.getUnwindState());
|
2013-07-30 18:04:08 +00:00
|
|
|
context.cfg().addPreEdge(n, context.getControlFlow().getTarget(n, null), false);
|
2014-07-28 15:09:02 +00:00
|
|
|
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction, -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
if (context.getControlFlow().getTarget(n, null) == null) {
|
|
|
|
assert context.getControlFlow().getTarget(n, null) != null : context.getControlFlow() + " does not map " + n + " ("
|
|
|
|
+ context.getSourceMap().getPosition(n) + ")";
|
|
|
|
}
|
2013-07-30 18:04:08 +00:00
|
|
|
context.cfg().newBlock(false);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitLabelStmt(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
if (!context.getControlFlow().getSourceNodes(n).isEmpty()) {
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
context.cfg().addPreNode(n, context.getUnwindState());
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveLabelStmt(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void processIf(CAstNode n, boolean isExpr, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
PreBasicBlock trueB = null, falseB = null;
|
|
|
|
// conditional
|
|
|
|
CAstNode l = n.getChild(0);
|
|
|
|
visitor.visit(l, context, visitor);
|
|
|
|
context.cfg().addInstruction(
|
2014-04-09 15:33:57 +00:00
|
|
|
insts.ConditionalBranchInstruction(context.cfg().currentInstruction, translateConditionOpcode(CAstOperator.OP_EQ), null, c.getValue(l), context.currentScope()
|
2014-07-08 18:44:06 +00:00
|
|
|
.getConstantValue(new Integer(0)), -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
PreBasicBlock srcB = context.cfg().getCurrentBlock();
|
|
|
|
// true clause
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
CAstNode r = n.getChild(1);
|
|
|
|
visitor.visit(r, context, visitor);
|
|
|
|
if (isExpr)
|
2014-04-09 15:33:57 +00:00
|
|
|
context.cfg().addInstruction(new AssignInstruction(context.cfg().currentInstruction, c.getValue(n), c.getValue(r)));
|
2012-09-04 22:56:05 +00:00
|
|
|
if (n.getChildCount() == 3) {
|
|
|
|
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
|
2014-07-28 15:09:02 +00:00
|
|
|
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction, -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
trueB = context.cfg().getCurrentBlock();
|
|
|
|
|
|
|
|
// false clause
|
|
|
|
context.cfg().newBlock(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
falseB = context.cfg().getCurrentBlock();
|
|
|
|
CAstNode f = n.getChild(2);
|
|
|
|
visitor.visit(f, context, visitor);
|
|
|
|
if (isExpr)
|
2014-04-09 14:59:51 +00:00
|
|
|
context.cfg().addInstruction(new AssignInstruction(context.cfg().currentInstruction, c.getValue(n), c.getValue(f)));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// end
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
if (n.getChildCount() == 3) {
|
|
|
|
if (trueB != null)
|
|
|
|
context.cfg().addEdge(trueB, context.cfg().getCurrentBlock());
|
|
|
|
context.cfg().addEdge(srcB, falseB);
|
|
|
|
} else {
|
|
|
|
context.cfg().addEdge(srcB, context.cfg().getCurrentBlock());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make final to prevent overriding
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected final void leaveIfStmtCondition(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected final void leaveIfStmtTrueClause(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected final void leaveIfStmt(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected final void leaveIfExprCondition(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected final void leaveIfExprTrueClause(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected final void leaveIfExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitIfStmt(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
processIf(n, false, c, visitor);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitIfExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int result = context.currentScope().allocateTempValue();
|
|
|
|
c.setValue(n, result);
|
|
|
|
processIf(n, true, c, visitor);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitNew(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveNew(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
int result = context.currentScope().allocateTempValue();
|
|
|
|
c.setValue(n, result);
|
|
|
|
|
|
|
|
int[] arguments;
|
|
|
|
if (n.getChildCount() <= 1) {
|
|
|
|
arguments = null;
|
|
|
|
} else {
|
|
|
|
arguments = new int[n.getChildCount() - 1];
|
|
|
|
for (int i = 1; i < n.getChildCount(); i++) {
|
|
|
|
arguments[i - 1] = c.getValue(n.getChild(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
doNewObject(context, n, result, n.getChild(0).getValue(), arguments);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitObjectLiteral(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveObjectLiteralFieldInit(CAstNode n, int i, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
if (n.getChild(i).getKind() == CAstNode.EMPTY) {
|
|
|
|
handleUnspecifiedLiteralKey(context, n, i, visitor);
|
|
|
|
}
|
|
|
|
doFieldWrite(context, c.getValue(n.getChild(0)), n.getChild(i), n, c.getValue(n.getChild(i + 1)));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveObjectLiteral(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
c.setValue(n, c.getValue(n.getChild(0)));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitArrayLiteral(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveArrayLiteralObject(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
c.setValue(n, c.getValue(n.getChild(0)));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveArrayLiteralInitElement(CAstNode n, int i, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
arrayOpHandler.doArrayWrite(context, c.getValue(n.getChild(0)), n,
|
|
|
|
new int[] { context.currentScope().getConstantValue(new Integer(i - 1)) }, c.getValue(n.getChild(i)));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveArrayLiteral(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitObjectRef(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int result = context.currentScope().allocateTempValue();
|
|
|
|
c.setValue(n, result);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveObjectRef(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int result = c.getValue(n);
|
|
|
|
CAstNode elt = n.getChild(1);
|
|
|
|
doFieldRead(context, result, c.getValue(n.getChild(0)), elt, n);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean visitAssign(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void leaveAssign(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
if (n.getKind() == CAstNode.ASSIGN) {
|
|
|
|
c.setValue(n, c.getValue(n.getChild(1)));
|
|
|
|
} else {
|
|
|
|
c.setValue(n, c.getValue(n.getChild(0)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private int[] gatherArrayDims(WalkContext c, CAstNode n) {
|
|
|
|
int numDims = n.getChildCount() - 2;
|
|
|
|
int[] dims = new int[numDims];
|
|
|
|
for (int i = 0; i < numDims; i++)
|
|
|
|
dims[i] = c.getValue(n.getChild(i + 2));
|
|
|
|
return dims;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prereq: a.getKind() == ASSIGN_PRE_OP || a.getKind() == ASSIGN_POST_OP */
|
|
|
|
protected int processAssignOp(CAstNode n, CAstNode v, CAstNode a, int temp, boolean post, WalkContext c) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int rval = c.getValue(v);
|
|
|
|
CAstNode op = a.getChild(2);
|
|
|
|
int temp2 = context.currentScope().allocateTempValue();
|
|
|
|
|
|
|
|
boolean mayBeInteger = handleBinaryOpThrow(a, op, context);
|
|
|
|
|
|
|
|
context.cfg().addInstruction(
|
2014-04-09 14:59:51 +00:00
|
|
|
insts.BinaryOpInstruction(context.cfg().currentInstruction, translateBinaryOpcode(op), false, false, temp2, temp, rval, mayBeInteger));
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
if (mayBeInteger) {
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return temp2;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitArrayRefAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveArrayRefAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int rval = c.getValue(v);
|
|
|
|
c.setValue(n, rval);
|
|
|
|
arrayOpHandler.doArrayWrite(context, c.getValue(n.getChild(0)), n, gatherArrayDims(c, n), rval);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitArrayRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveArrayRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int temp = context.currentScope().allocateTempValue();
|
|
|
|
int[] dims = gatherArrayDims(c, n);
|
|
|
|
arrayOpHandler.doArrayRead(context, temp, c.getValue(n.getChild(0)), n, dims);
|
|
|
|
int rval = processAssignOp(n, v, a, temp, !pre, c);
|
|
|
|
c.setValue(n, pre ? rval : temp);
|
|
|
|
arrayOpHandler.doArrayWrite(context, c.getValue(n.getChild(0)), n, dims, rval);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitObjectRefAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveObjectRefAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int rval = c.getValue(v);
|
|
|
|
c.setValue(n, rval);
|
|
|
|
doFieldWrite(context, c.getValue(n.getChild(0)), n.getChild(1), n, rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void processObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, WalkContext c) {
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int temp = context.currentScope().allocateTempValue();
|
|
|
|
doFieldRead(context, temp, c.getValue(n.getChild(0)), n.getChild(1), n);
|
|
|
|
int rval = processAssignOp(n, v, a, temp, !pre, c);
|
|
|
|
c.setValue(n, pre ? rval : temp);
|
|
|
|
doFieldWrite(context, c.getValue(n.getChild(0)), n.getChild(1), n, rval);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitBlockExprAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveBlockExprAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
c.setValue(n, c.getValue(n.getChild(n.getChildCount() - 1)));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitBlockExprAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveBlockExprAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
c.setValue(n, c.getValue(n.getChild(n.getChildCount() - 1)));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitVarAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* assign rval to nm as appropriate, depending on the scope of ls
|
|
|
|
*/
|
|
|
|
protected void assignValue(CAstNode n, WalkContext context, Symbol ls, String nm, int rval) {
|
|
|
|
if (context.currentScope().isGlobal(ls))
|
2014-03-16 22:05:49 +00:00
|
|
|
doGlobalWrite(context, nm, makeType(ls.type()), rval);
|
2012-09-04 22:56:05 +00:00
|
|
|
else if (context.currentScope().isLexicallyScoped(ls)) {
|
2014-03-16 22:05:49 +00:00
|
|
|
doLexicallyScopedWrite(context, nm, makeType(ls.type()), rval);
|
2012-09-04 22:56:05 +00:00
|
|
|
} else {
|
|
|
|
assert rval != -1 : CAstPrinter.print(n, context.top().getSourceMap());
|
2014-03-16 22:05:49 +00:00
|
|
|
doLocalWrite(context, nm, makeType(ls.type()), rval);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveVarAssign(CAstNode n, CAstNode v, CAstNode a, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int rval = c.getValue(v);
|
|
|
|
String nm = (String) n.getChild(0).getValue();
|
|
|
|
Symbol ls = context.currentScope().lookup(nm);
|
|
|
|
c.setValue(n, rval);
|
|
|
|
assignValue(n, context, ls, nm, rval);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitVarAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveVarAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
String nm = (String) n.getChild(0).getValue();
|
|
|
|
Symbol ls = context.currentScope().lookup(nm);
|
2014-03-16 22:05:49 +00:00
|
|
|
TypeReference type = makeType(ls.type());
|
2012-09-04 22:56:05 +00:00
|
|
|
int temp;
|
|
|
|
|
|
|
|
if (context.currentScope().isGlobal(ls))
|
2014-03-16 22:05:49 +00:00
|
|
|
temp = doGlobalRead(n, context, nm, type);
|
2012-09-04 22:56:05 +00:00
|
|
|
else if (context.currentScope().isLexicallyScoped(ls)) {
|
2014-03-16 22:05:49 +00:00
|
|
|
temp = doLexicallyScopedRead(n, context, nm, type);
|
2012-09-04 22:56:05 +00:00
|
|
|
} else {
|
2014-03-16 22:05:49 +00:00
|
|
|
temp = doLocalRead(context, nm, type);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!pre) {
|
|
|
|
int ret = context.currentScope().allocateTempValue();
|
2014-04-09 15:33:57 +00:00
|
|
|
context.cfg().addInstruction(new AssignInstruction(context.cfg().currentInstruction, ret, temp));
|
2012-09-04 22:56:05 +00:00
|
|
|
c.setValue(n, ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
int rval = processAssignOp(n, v, a, temp, !pre, c);
|
|
|
|
|
|
|
|
if (pre) {
|
|
|
|
c.setValue(n, rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context.currentScope().isGlobal(ls)) {
|
2014-03-16 22:05:49 +00:00
|
|
|
doGlobalWrite(context, nm, type, rval);
|
2012-09-04 22:56:05 +00:00
|
|
|
} else if (context.currentScope().isLexicallyScoped(ls)) {
|
2014-03-16 22:05:49 +00:00
|
|
|
doLexicallyScopedWrite(context, nm, type, rval);
|
2012-09-04 22:56:05 +00:00
|
|
|
} else {
|
2014-03-16 22:05:49 +00:00
|
|
|
doLocalWrite(context, nm, type, rval);
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean isSimpleSwitch(CAstNode n, WalkContext context, CAstVisitor<WalkContext> visitor) {
|
|
|
|
CAstControlFlowMap ctrl = context.getControlFlow();
|
|
|
|
Collection caseLabels = ctrl.getTargetLabels(n);
|
|
|
|
for (Iterator kases = caseLabels.iterator(); kases.hasNext();) {
|
|
|
|
Object x = kases.next();
|
|
|
|
|
|
|
|
if (x == CAstControlFlowMap.SWITCH_DEFAULT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
CAstNode xn = (CAstNode) x;
|
|
|
|
if (xn.getKind() == CAstNode.CONSTANT) {
|
|
|
|
visitor.visit(xn, context, visitor);
|
|
|
|
if (context.getValue(xn) != -1) {
|
|
|
|
if (context.currentScope().isConstant(context.getValue(xn))) {
|
|
|
|
Object val = context.currentScope().getConstantObject(context.getValue(xn));
|
|
|
|
if (val instanceof Number) {
|
|
|
|
Number num = (Number) val;
|
2013-10-16 21:37:53 +00:00
|
|
|
if (num.intValue() == num.doubleValue()) {
|
2012-09-04 22:56:05 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void doSimpleSwitch(CAstNode n, WalkContext context, CAstVisitor<WalkContext> visitor) {
|
|
|
|
PreBasicBlock defaultHackBlock = null;
|
|
|
|
CAstControlFlowMap ctrl = context.getControlFlow();
|
|
|
|
|
|
|
|
CAstNode switchValue = n.getChild(0);
|
|
|
|
visitor.visit(switchValue, context, visitor);
|
|
|
|
int v = context.getValue(switchValue);
|
|
|
|
|
|
|
|
boolean hasExplicitDefault = ctrl.getTarget(n, CAstControlFlowMap.SWITCH_DEFAULT) != null;
|
|
|
|
|
|
|
|
Collection caseLabels = ctrl.getTargetLabels(n);
|
|
|
|
int cases = caseLabels.size();
|
|
|
|
if (hasExplicitDefault)
|
|
|
|
cases--;
|
|
|
|
int[] casesAndLabels = new int[cases * 2];
|
|
|
|
|
|
|
|
int defaultBlock = context.cfg().getCurrentBlock().getGraphNodeId() + 1;
|
|
|
|
|
2014-04-09 14:59:51 +00:00
|
|
|
context.cfg().addInstruction(insts.SwitchInstruction(context.cfg().currentInstruction, v, defaultBlock, casesAndLabels));
|
2012-09-04 22:56:05 +00:00
|
|
|
context.cfg().addPreNode(n, context.getUnwindState());
|
|
|
|
// PreBasicBlock switchB = context.cfg().getCurrentBlock();
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
|
2014-07-28 15:09:02 +00:00
|
|
|
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction, -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
defaultHackBlock = context.cfg().getCurrentBlock();
|
|
|
|
context.cfg().newBlock(false);
|
|
|
|
|
|
|
|
CAstNode switchBody = n.getChild(1);
|
|
|
|
visitor.visit(switchBody, context, visitor);
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
|
|
|
|
if (!hasExplicitDefault) {
|
|
|
|
context.cfg().addEdge(defaultHackBlock, context.cfg().getCurrentBlock());
|
|
|
|
}
|
|
|
|
|
|
|
|
int cn = 0;
|
|
|
|
for (Iterator kases = caseLabels.iterator(); kases.hasNext();) {
|
|
|
|
Object x = kases.next();
|
|
|
|
CAstNode target = ctrl.getTarget(n, x);
|
|
|
|
if (x == CAstControlFlowMap.SWITCH_DEFAULT) {
|
|
|
|
context.cfg().addEdge(defaultHackBlock, context.cfg().getBlock(target));
|
|
|
|
} else {
|
|
|
|
Number caseLabel = (Number) context.currentScope().getConstantObject(context.getValue((CAstNode) x));
|
|
|
|
casesAndLabels[2 * cn] = caseLabel.intValue();
|
|
|
|
casesAndLabels[2 * cn + 1] = context.cfg().getBlock(target).getGraphNodeId();
|
|
|
|
cn++;
|
|
|
|
|
|
|
|
context.cfg().addPreEdge(n, target, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void doIfConvertSwitch(CAstNode n, WalkContext context, CAstVisitor<WalkContext> visitor) {
|
|
|
|
CAstControlFlowMap ctrl = context.getControlFlow();
|
|
|
|
context.cfg().addPreNode(n, context.getUnwindState());
|
|
|
|
|
|
|
|
CAstNode switchValue = n.getChild(0);
|
|
|
|
visitor.visit(switchValue, context, visitor);
|
|
|
|
int v = context.getValue(switchValue);
|
|
|
|
|
|
|
|
Collection<Object> caseLabels = ctrl.getTargetLabels(n);
|
|
|
|
Map<Object, PreBasicBlock> labelToBlock = new LinkedHashMap<Object, PreBasicBlock>();
|
|
|
|
for (Iterator kases = caseLabels.iterator(); kases.hasNext();) {
|
|
|
|
Object x = kases.next();
|
|
|
|
if (x != CAstControlFlowMap.SWITCH_DEFAULT) {
|
|
|
|
visitor.visit((CAstNode) x, context, visitor);
|
|
|
|
context.cfg().addInstruction(
|
2014-07-28 15:09:02 +00:00
|
|
|
insts.ConditionalBranchInstruction(context.cfg().currentInstruction, translateConditionOpcode(CAstOperator.OP_EQ), null, v, context.getValue((CAstNode) x), -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
labelToBlock.put(x, context.cfg().getCurrentBlock());
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PreBasicBlock defaultGotoBlock = context.cfg().getCurrentBlock();
|
2014-07-28 15:09:02 +00:00
|
|
|
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction, -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
context.cfg().newBlock(false);
|
|
|
|
|
|
|
|
CAstNode switchBody = n.getChild(1);
|
|
|
|
visitor.visit(switchBody, context, visitor);
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
|
|
|
|
for (Iterator kases = caseLabels.iterator(); kases.hasNext();) {
|
|
|
|
Object x = kases.next();
|
|
|
|
if (x != CAstControlFlowMap.SWITCH_DEFAULT) {
|
|
|
|
CAstNode target = ctrl.getTarget(n, x);
|
|
|
|
context.cfg().addEdge(labelToBlock.get(x), context.cfg().getBlock(target));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctrl.getTarget(n, CAstControlFlowMap.SWITCH_DEFAULT) == null) {
|
|
|
|
context.cfg().addEdge(defaultGotoBlock, context.cfg().getCurrentBlock());
|
|
|
|
} else {
|
|
|
|
CAstNode target = ctrl.getTarget(n, CAstControlFlowMap.SWITCH_DEFAULT);
|
|
|
|
context.cfg().addEdge(defaultGotoBlock, context.cfg().getBlock(target));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitSwitch(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
if (isSimpleSwitch(n, context, visitor)) {
|
|
|
|
doSimpleSwitch(n, context, visitor);
|
|
|
|
} else {
|
|
|
|
doIfConvertSwitch(n, context, visitor);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make final to prevent overriding
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected final void leaveSwitchValue(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected final void leaveSwitch(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitThrow(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveThrow(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
doThrow(context, c.getValue(n.getChild(0)));
|
|
|
|
|
|
|
|
context.cfg().addPreNode(n, context.getUnwindState());
|
|
|
|
context.cfg().newBlock(false);
|
|
|
|
|
|
|
|
Collection labels = context.getControlFlow().getTargetLabels(n);
|
|
|
|
for (Iterator iter = labels.iterator(); iter.hasNext();) {
|
|
|
|
Object label = iter.next();
|
|
|
|
CAstNode target = context.getControlFlow().getTarget(n, label);
|
|
|
|
if (target == CAstControlFlowMap.EXCEPTION_TO_EXIT)
|
|
|
|
context.cfg().addPreEdgeToExit(n, true);
|
|
|
|
else
|
|
|
|
context.cfg().addPreEdge(n, target, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitCatch(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
// unreachable catch block
|
|
|
|
if (context.getControlFlow().getSourceNodes(n).isEmpty()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
String id = (String) n.getChild(0).getValue();
|
|
|
|
context.cfg().setCurrentBlockAsHandler();
|
|
|
|
if (!context.currentScope().contains(id)) {
|
2014-03-16 22:05:49 +00:00
|
|
|
context.currentScope().declare(new FinalCAstSymbol(id, exceptionType()));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
context.cfg().addInstruction(
|
2014-04-09 15:33:57 +00:00
|
|
|
insts.GetCaughtExceptionInstruction(context.cfg().currentInstruction, context.cfg().getCurrentBlock().getNumber(), context.currentScope().lookup(id)
|
2012-09-04 22:56:05 +00:00
|
|
|
.valueNumber()));
|
|
|
|
|
|
|
|
context.cfg().addPreNode(n, context.getUnwindState());
|
|
|
|
|
|
|
|
CAstType caughtType = getTypeForNode(context, n);
|
|
|
|
if (caughtType != null) {
|
|
|
|
TypeReference caughtRef = makeType(caughtType);
|
|
|
|
context.setCatchType(n, caughtRef);
|
|
|
|
} else {
|
|
|
|
context.setCatchType(n, defaultCatchType());
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveCatch(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitUnwind(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveUnwind(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean hasIncomingEdges(CAstNode n, WalkContext context) {
|
|
|
|
if (context.cfg().hasDelayedEdges(n)) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
for (int i = 0; i < n.getChildCount(); i++) {
|
|
|
|
if (hasIncomingEdges(n.getChild(i), context)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitTry(final CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
final WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
boolean addSkipCatchGoto = false;
|
|
|
|
visitor.visit(n.getChild(0), context, visitor);
|
|
|
|
PreBasicBlock endOfTry = context.cfg().getCurrentBlock();
|
|
|
|
|
|
|
|
if (!hasIncomingEdges(n.getChild(1), context)) {
|
|
|
|
if (loader instanceof CAstAbstractLoader) {
|
|
|
|
((CAstAbstractLoader) loader).addMessage(context.getModule(), new Warning(Warning.MILD) {
|
|
|
|
@Override
|
|
|
|
public String getMsg() {
|
|
|
|
return "Dead catch block at " + getPosition(context.getSourceMap(), n.getChild(1));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
|
|
|
|
addSkipCatchGoto = true;
|
2014-07-28 15:09:02 +00:00
|
|
|
context.cfg().addInstruction(insts.GotoInstruction(context.cfg().currentInstruction, -1));
|
2012-09-04 22:56:05 +00:00
|
|
|
context.cfg().newBlock(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
context.cfg().noteCatchBlock();
|
|
|
|
visitor.visit(n.getChild(1), context, visitor);
|
|
|
|
|
|
|
|
if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) {
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addSkipCatchGoto) {
|
|
|
|
PreBasicBlock afterBlock = context.cfg().getCurrentBlock();
|
|
|
|
context.cfg().addEdge(endOfTry, afterBlock);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make final to prevent overriding
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected final void leaveTryBlock(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected final void leaveTry(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitEmpty(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveEmpty(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
c.setValue(n, context.currentScope().getConstantValue(null));
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitPrimitive(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leavePrimitive(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int result = context.currentScope().allocateTempValue();
|
|
|
|
c.setValue(n, result);
|
|
|
|
|
|
|
|
doPrimitive(result, context, n);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitVoid(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveVoid(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
c.setValue(n, -1);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitAssert(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) { /* empty */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveAssert(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext context = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
boolean fromSpec = true;
|
|
|
|
int result = c.getValue(n.getChild(0));
|
|
|
|
if (n.getChildCount() == 2) {
|
|
|
|
assert n.getChild(1).getKind() == CAstNode.CONSTANT;
|
|
|
|
assert n.getChild(1).getValue() instanceof Boolean;
|
|
|
|
fromSpec = n.getChild(1).getValue().equals(Boolean.TRUE);
|
|
|
|
}
|
2014-04-09 14:59:51 +00:00
|
|
|
context.cfg().addInstruction(new AstAssertInstruction(context.cfg().currentInstruction, result, fromSpec));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitEachElementGet(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveEachElementGet(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
int result = c.currentScope().allocateTempValue();
|
2012-09-04 22:56:05 +00:00
|
|
|
c.setValue(n, result);
|
2014-05-20 15:59:16 +00:00
|
|
|
c.cfg().addInstruction(new EachElementGetInstruction(c.cfg().currentInstruction, result, c.getValue(n.getChild(0))));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitEachElementHasNext(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void leaveEachElementHasNext(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
int result = c.currentScope().allocateTempValue();
|
2012-09-04 22:56:05 +00:00
|
|
|
c.setValue(n, result);
|
2014-05-20 15:59:16 +00:00
|
|
|
c.cfg().addInstruction(new EachElementHasNextInstruction(c.cfg().currentInstruction, result, c.getValue(n.getChild(0))));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitTypeLiteralExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveTypeLiteralExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext wc = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
assert n.getChild(0).getKind() == CAstNode.CONSTANT;
|
|
|
|
String typeNameStr = (String) n.getChild(0).getValue();
|
|
|
|
TypeName typeName = TypeName.string2TypeName(typeNameStr);
|
|
|
|
TypeReference typeRef = TypeReference.findOrCreate(loader.getReference(), typeName);
|
|
|
|
|
|
|
|
int result = wc.currentScope().allocateTempValue();
|
|
|
|
c.setValue(n, result);
|
|
|
|
|
2014-04-09 14:59:51 +00:00
|
|
|
wc.cfg().addInstruction(insts.LoadMetadataInstruction(wc.cfg().currentInstruction, result, loader.getLanguage().getConstantType(typeRef), typeRef));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitIsDefinedExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveIsDefinedExpr(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext wc = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
int ref = c.getValue(n.getChild(0));
|
|
|
|
int result = wc.currentScope().allocateTempValue();
|
|
|
|
c.setValue(n, result);
|
|
|
|
if (n.getChildCount() == 1) {
|
2014-04-09 14:59:51 +00:00
|
|
|
wc.cfg().addInstruction(new AstIsDefinedInstruction(wc.cfg().currentInstruction, result, ref));
|
2012-09-04 22:56:05 +00:00
|
|
|
} else {
|
|
|
|
doIsFieldDefined(wc, result, ref, n.getChild(1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected boolean visitEcho(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveEcho(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext wc = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
int rvals[] = new int[n.getChildCount()];
|
|
|
|
for (int i = 0; i < n.getChildCount(); i++) {
|
|
|
|
rvals[i] = c.getValue(n.getChild(i));
|
|
|
|
}
|
|
|
|
|
2014-04-09 14:59:51 +00:00
|
|
|
wc.cfg().addInstruction(new AstEchoInstruction(wc.cfg().currentInstruction, rvals));
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public CAstEntity getIncludedEntity(CAstNode n) {
|
|
|
|
if (n.getChild(0).getKind() == CAstNode.NAMED_ENTITY_REF) {
|
|
|
|
assert namedEntityResolver != null;
|
|
|
|
return (CAstEntity) namedEntityResolver.get(n.getChild(0).getChild(0).getValue());
|
|
|
|
} else {
|
|
|
|
return (CAstEntity) n.getChild(0).getValue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected void leaveInclude(final CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2013-10-16 21:37:53 +00:00
|
|
|
WalkContext wc = c;
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
CAstEntity included = getIncludedEntity(n);
|
|
|
|
|
|
|
|
if (included == null) {
|
|
|
|
System.err.println(("cannot find include for " + CAstPrinter.print(n)));
|
|
|
|
System.err.println(("from:\n" + namedEntityResolver));
|
|
|
|
} else {
|
|
|
|
final boolean isMacroExpansion = (included.getKind() == CAstEntity.MACRO_ENTITY);
|
|
|
|
|
|
|
|
System.err.println("found " + included.getName() + " for " + CAstPrinter.print(n));
|
|
|
|
|
|
|
|
final CAstEntity copy = (new CAstCloner(new CAstImpl(), true) {
|
|
|
|
|
|
|
|
private CAstNode copyIncludeExpr(CAstNode expr) {
|
|
|
|
if (expr.getValue() != null) {
|
|
|
|
return Ast.makeConstant(expr.getValue());
|
|
|
|
} else if (expr instanceof CAstOperator) {
|
|
|
|
return expr;
|
|
|
|
} else {
|
|
|
|
CAstNode nc[] = new CAstNode[expr.getChildCount()];
|
|
|
|
|
|
|
|
for (int i = 0; i < expr.getChildCount(); i++) {
|
|
|
|
nc[i] = copyIncludeExpr(expr.getChild(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
return Ast.makeNode(expr.getKind(), nc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
protected CAstNode copyNodes(CAstNode root, final CAstControlFlowMap cfg, NonCopyingContext c, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
|
|
|
|
if (isMacroExpansion && root.getKind() == CAstNode.MACRO_VAR) {
|
|
|
|
int arg = ((Number) root.getChild(0).getValue()).intValue();
|
|
|
|
CAstNode expr = copyIncludeExpr(n.getChild(arg));
|
|
|
|
nodeMap.put(Pair.make(root, c.key()), expr);
|
|
|
|
return expr;
|
|
|
|
} else {
|
|
|
|
return super.copyNodesHackForEclipse(root, cfg, c, nodeMap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}).rewrite(included);
|
|
|
|
|
|
|
|
if (copy.getAST() == null) {
|
|
|
|
System.err.println((copy.getName() + " has no AST"));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
visit(copy.getAST(), new DelegatingContext(wc) {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstSourcePositionMap getSourceMap() {
|
|
|
|
return copy.getSourceMap();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstControlFlowMap getControlFlow() {
|
|
|
|
return copy.getControlFlow();
|
|
|
|
}
|
|
|
|
}, visitor);
|
|
|
|
|
|
|
|
visitor.visitScopedEntities(copy, copy.getAllScopedEntities(), wc, visitor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected final void walkEntities(CAstEntity N, WalkContext c) {
|
|
|
|
visitEntities(N, c, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
public final class RootContext implements WalkContext {
|
|
|
|
private final Scope globalScope;
|
|
|
|
|
|
|
|
private final CAstEntity N;
|
|
|
|
|
|
|
|
private final ModuleEntry module;
|
|
|
|
|
|
|
|
private final Map<CAstEntity, String> entityNames = new LinkedHashMap<CAstEntity, String>();
|
|
|
|
|
|
|
|
public RootContext(CAstEntity N, ModuleEntry module) {
|
|
|
|
this.N = N;
|
|
|
|
this.module = module;
|
|
|
|
this.globalScope = makeGlobalScope();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public ModuleEntry getModule() {
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String file() {
|
|
|
|
return module.getName();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstEntity top() {
|
|
|
|
return N;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Scope currentScope() {
|
|
|
|
return globalScope;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Set<Scope> entityScopes() {
|
|
|
|
return Collections.singleton(globalScope);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstSourcePositionMap getSourceMap() {
|
|
|
|
return N.getSourceMap();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public CAstControlFlowMap getControlFlow() {
|
|
|
|
return N.getControlFlow();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public IncipientCFG cfg() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public UnwindState getUnwindState() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String getName() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2013-04-11 01:09:10 +00:00
|
|
|
public void setCatchType(IBasicBlock bb, TypeReference catchType) {
|
2012-09-04 22:56:05 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void setCatchType(CAstNode castNode, TypeReference catchType) {
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2013-04-11 01:09:10 +00:00
|
|
|
public Map<IBasicBlock, TypeReference[]> getCatchTypes() {
|
2012-09-04 22:56:05 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void addEntityName(CAstEntity e, String name) {
|
|
|
|
entityNames.put(e, name);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public String getEntityName(CAstEntity e) {
|
|
|
|
if (e == null) {
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
assert entityNames.containsKey(e);
|
|
|
|
return "L" + entityNames.get(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean hasValue(CAstNode n) {
|
|
|
|
assert false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int setValue(CAstNode n, int v) {
|
|
|
|
assert false;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public int getValue(CAstNode n) {
|
|
|
|
assert false;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Set<Pair<Pair<String, String>, Integer>> exposeNameSet(CAstEntity entity, boolean writeSet) {
|
|
|
|
assert false;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Set<Access> getAccesses(CAstEntity e) {
|
|
|
|
assert false;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public Scope getGlobalScope(){
|
|
|
|
return globalScope;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* translate module, represented by {@link CAstEntity} N
|
|
|
|
*/
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public void translate(final CAstEntity N, final ModuleEntry module) {
|
|
|
|
if (DEBUG_TOP)
|
|
|
|
System.err.println(("translating " + module.getName()));
|
|
|
|
// this.inlinedSourceMap = inlinedSourceMap;
|
|
|
|
final ExposedNamesCollector exposedNamesCollector = new ExposedNamesCollector();
|
|
|
|
exposedNamesCollector.run(N);
|
|
|
|
entity2ExposedNames = exposedNamesCollector.getEntity2ExposedNames();
|
|
|
|
// CAstEntity rewrite = (new ExposedParamRenamer(new CAstImpl(),
|
|
|
|
// entity2ExposedNames)).rewrite(N);
|
|
|
|
walkEntities(N, new RootContext(N, module));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void translate(final CAstEntity N, final WalkContext context) {
|
|
|
|
final ExposedNamesCollector exposedNamesCollector = new ExposedNamesCollector();
|
|
|
|
exposedNamesCollector.run(N);
|
|
|
|
entity2ExposedNames = exposedNamesCollector.getEntity2ExposedNames();
|
|
|
|
walkEntities(N, context);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|