/** * create a CAstNode l representing a loop that traverses the prototype chain from receiver * searching for the constant property element. update nodeMap to map root to an expression that * reads the property from the right node. * * @param root * @param receiver * @param element * @param context * @param nodeMap * @return */ private CAstNode makeConstRead( CAstNode root, CAstNode receiver, CAstNode element, RewriteContext context, Map<Pair<CAstNode, ExpanderKey>, CAstNode> nodeMap) { CAstNode get, result; String receiverTemp = TEMP_NAME + (readTempCounter++); String elt = (String) element.getValue(); if (elt.equals("prototype") || elt.equals("__proto__")) { result = Ast.makeNode( CAstNode.BLOCK_EXPR, get = Ast.makeNode(CAstNode.OBJECT_REF, receiver, Ast.makeConstant(elt))); } else { if (context.inAssignment()) { context.setAssign( Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)), Ast.makeConstant(elt)); } result = Ast.makeNode( CAstNode.BLOCK_EXPR, // declare loop variable and initialize to the receiver Ast.makeNode( CAstNode.DECL_STMT, Ast.makeConstant(new InternalCAstSymbol(receiverTemp, false, false)), receiver), Ast.makeNode( CAstNode.LOOP, // while the desired property of the loop variable is not // defined... Ast.makeNode( CAstNode.UNARY_EXPR, CAstOperator.OP_NOT, Ast.makeNode( CAstNode.IS_DEFINED_EXPR, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)), Ast.makeConstant(elt))), // set the loop variable to be its prototype Ast.makeNode( CAstNode.ASSIGN, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)), Ast.makeNode( CAstNode.OBJECT_REF, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)), Ast.makeConstant("__proto__")))), get = Ast.makeNode( CAstNode.OBJECT_REF, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)), Ast.makeConstant(elt))); } nodeMap.put(Pair.make(root, context.key()), result); nodeMap.put(Pair.make(root, ExpanderKey.EXTRA), get); return result; }
private IMethod makeObjectCall(IClass cls, int nargs) { assert nargs == 0; Object key = Pair.make(cls, new Integer(nargs)); if (constructors.containsKey(key)) return constructors.get(key); else return record(key, makeNullaryObjectConstructor(cls)); }
private IMethod makeFunctionObjectConstructor(IClass cls, int nargs) { JSInstructionFactory insts = (JSInstructionFactory) cls.getClassLoader().getInstructionFactory(); Object key = Pair.make(cls, new Integer(nargs)); if (constructors.containsKey(key)) return constructors.get(key); MethodReference ref = JavaScriptMethods.makeCtorReference(cls.getReference()); JavaScriptSummary S = new JavaScriptSummary(ref, nargs + 1); S.addStatement(insts.GetInstruction(nargs + 4, 1, "prototype")); S.getNextProgramCounter(); S.addStatement( insts.NewInstruction( nargs + 5, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object))); S.addStatement(insts.SetPrototype(nargs + 5, nargs + 4)); // S.addStatement(insts.PutInstruction(nargs + 5, nargs + 4, "__proto__")); S.getNextProgramCounter(); CallSiteReference cs = new JSCallSiteReference(S.getNextProgramCounter()); int[] args = new int[nargs + 1]; args[0] = nargs + 5; for (int i = 0; i < nargs; i++) args[i + 1] = i + 2; S.addStatement(insts.Invoke(1, nargs + 7, args, nargs + 8, cs)); S.addStatement(insts.ReturnInstruction(nargs + 7, false)); S.getNextProgramCounter(); S.addStatement(insts.ReturnInstruction(nargs + 5, false)); S.getNextProgramCounter(); // S.addConstant(nargs + 9, new ConstantValue("__proto__")); return record(key, new JavaScriptConstructor(ref, S, cls)); }
/** * builds a call graph, and sets the corresponding heap model for analysis * * @param scope * @param cha * @param options * @return * @throws CancelException * @throws IllegalArgumentException */ private static Pair<CallGraph, PointerAnalysis> buildCallGraph( AnalysisScope scope, ClassHierarchy cha, AnalysisOptions options) throws IllegalArgumentException, CancelException { CallGraph retCG = null; PointerAnalysis retPA = null; final AnalysisCache cache = new AnalysisCache(); CallGraphBuilder builder; if (CHEAP_CG) { builder = Util.makeZeroCFABuilder(options, cache, cha, scope); // we want vanilla 0-1 CFA, which has one abstract loc per allocation heapModel = Util.makeVanillaZeroOneCFABuilder(options, cache, cha, scope); } else { builder = Util.makeZeroOneContainerCFABuilder(options, cache, cha, scope); heapModel = (HeapModel) builder; } ProgressMaster master = ProgressMaster.make(new NullProgressMonitor(), 360000, false); master.beginTask("runSolver", 1); try { retCG = builder.makeCallGraph(options, master); retPA = builder.getPointerAnalysis(); } catch (CallGraphBuilderCancelException e) { System.err.println("TIMED OUT!!"); retCG = e.getPartialCallGraph(); retPA = e.getPartialPointerAnalysis(); } return Pair.make(retCG, retPA); }
private IMethod makeNumberCall(IClass cls, int nargs) { assert nargs == 0 || nargs == 1; Object key = Pair.make(cls, new Integer(nargs)); if (constructors.containsKey(key)) return constructors.get(key); else return record(key, (nargs == 0) ? makeNullaryNumberCall(cls) : makeUnaryNumberCall(cls)); }
List<String> mapExternalVarForProject() { List<String> map = new LinkedList<String>(); PlanNode predecessor = planNode.getPredecessor(wrapper.getPlan()); if (predecessor != null) { String predecessorCTE = wrapper.getPlanNodeCTE(predecessor, false); Set<Variable> predecessorVars = predecessor.getAvailableVariables(); if (predecessorVars != null) { Set<Variable> iriBoundVariables = wrapper.getIRIBoundVariables(); for (Variable v : predecessorVars) { if (projectedInPrimary.contains(v)) continue; projectedInPrimary.add(v); String vPredName = wrapper.getPlanNodeVarMapping(predecessor, v.getName()); map.add(predecessorCTE + "." + vPredName + " AS " + v.getName()); String vType = null; if (!iriBoundVariables.contains(v)) { String vPredType = predecessorCTE + "." + v.getName() + Constants.TYP_COLUMN_SUFFIX_IN_SPARQL_RS; map.add(vPredType + " AS " + v.getName() + Constants.TYP_COLUMN_SUFFIX_IN_SPARQL_RS); vType = vPredType; } varMap.put(v.getName(), Pair.make(predecessorCTE + "." + vPredName, vType)); } } } return map; }
/* * @see com.ibm.wala.ssa.SSAPiNodePolicy#getPi(com.ibm.wala.ssa.SSAConditionalBranchInstruction, com.ibm.wala.ssa.SSAInstruction, * com.ibm.wala.ssa.SSAInstruction, com.ibm.wala.ssa.SymbolTable) */ @Override public Pair<Integer, SSAInstruction> getPi( SSAConditionalBranchInstruction cond, SSAInstruction def1, SSAInstruction def2, SymbolTable symbolTable) { if (def1 instanceof SSAInstanceofInstruction) { if (symbolTable.isBooleanOrZeroOneConstant(cond.getUse(1))) { return Pair.make(def1.getUse(0), def1); } } if (def2 instanceof SSAInstanceofInstruction) { if (symbolTable.isBooleanOrZeroOneConstant(cond.getUse(0))) { return Pair.make(def2.getUse(0), def2); } } return null; }
private IMethod makeArrayConstructor(IClass cls, int nargs) { Object key = Pair.make(cls, new Integer(nargs)); if (constructors.containsKey(key)) return constructors.get(key); else return record( key, (nargs == 1) ? makeArrayLengthConstructor(cls) : makeArrayContentsConstructor(cls, nargs)); }
private List<String> getEntrySQLConstraint() { List<String> entrySQLConstraint = new LinkedList<String>(); QueryTriple qt = planNode.getTriple(); QueryTripleTerm entryTerm = null; AccessMethod am = planNode.getMethod(); boolean hasSqlType = false; if (AccessMethodType.isDirectAccess(am.getType())) { entryTerm = qt.getSubject(); } else { entryTerm = qt.getObject(); hasSqlType = true; } if (entryTerm.isVariable()) { Variable entryVariable = entryTerm.getVariable(); PlanNode predecessor = planNode.getPredecessor(wrapper.getPlan()); boolean typConstraint = false; if (hasSqlType && wrapper.getIRIBoundVariables().contains(entryVariable)) { entrySQLConstraint.add( getTypeConstraintForIRIs(tTableColumnPrefix + Constants.NAME_COLUMN_PREFIX_TYPE)); } else if (hasSqlType && !wrapper.getIRIBoundVariables().contains(entryVariable)) { typConstraint = true; } boolean entryConstraintWithPredecessor = getPredecessorConstraint( entrySQLConstraint, entryVariable, predecessor, tTableColumnPrefix + Constants.NAME_COLUMN_ENTRY, tTableColumnPrefix + Constants.NAME_COLUMN_PREFIX_TYPE, typConstraint); if (!entryConstraintWithPredecessor) { // Check for entry constraint for variable with the same name on different positions if (varMap.containsKey(entryVariable.getName())) { entrySQLConstraint.add( tTableColumnPrefix + Constants.NAME_COLUMN_ENTRY + " = " + varMap.get(entryVariable.getName()).fst); } } String entryType = (typConstraint) ? tTableColumnPrefix + Constants.NAME_COLUMN_PREFIX_TYPE : null; varMap.put( entryVariable.getName(), Pair.make(tTableColumnPrefix + Constants.NAME_COLUMN_ENTRY, entryType)); } else { super.addConstantEntrySQLConstraint( entryTerm, entrySQLConstraint, hasSqlType, tTableColumnPrefix + Constants.NAME_COLUMN_ENTRY); } return entrySQLConstraint; }
List<String> getValueSQLConstraint() { List<String> valueSQLConstraint = new LinkedList<String>(); QueryTriple qt = planNode.getTriple(); QueryTripleTerm valueTerm = null; AccessMethod am = planNode.getMethod(); boolean hasSqlType = false; if (AccessMethodType.isDirectAccess(am.getType())) { valueTerm = qt.getObject(); hasSqlType = true; } else { valueTerm = qt.getSubject(); } if (valueTerm.isVariable()) { Variable valueVariable = valueTerm.getVariable(); PlanNode predecessor = planNode.getPredecessor(wrapper.getPlan()); boolean typConstraint = false; if (hasSqlType && wrapper.getIRIBoundVariables().contains(valueVariable)) { valueSQLConstraint.add( getTypeConstraintForIRIs(hashColumnExpression(Constants.NAME_COLUMN_PREFIX_TYPE))); } if (hasSqlType && !wrapper.getIRIBoundVariables().contains(valueVariable)) { typConstraint = true; } boolean hasValueConstrintWithPredecessor = getPredecessorConstraint( valueSQLConstraint, valueVariable, predecessor, hashColumnExpression(Constants.NAME_COLUMN_PREFIX_VALUE), hashColumnExpression(Constants.NAME_COLUMN_PREFIX_TYPE), typConstraint); if (!hasValueConstrintWithPredecessor) { if (varMap.containsKey(valueVariable.getName())) { // Check for value constraint for variable with the same name on different positions valueSQLConstraint.add( hashColumnExpression(Constants.NAME_COLUMN_PREFIX_VALUE) + " = " + varMap.get(valueVariable.getName()).fst); } } String valueType = (typConstraint) ? hashColumnExpression(Constants.NAME_COLUMN_PREFIX_TYPE) : null; varMap.put( valueVariable.getName(), Pair.make(hashColumnExpression(Constants.NAME_COLUMN_PREFIX_VALUE), valueType)); } else { valueSQLConstraint.add( hashColumnExpression(Constants.NAME_COLUMN_PREFIX_VALUE) + " = '" + valueTerm.toSqlDataString() + "'"); } return valueSQLConstraint; }
/** * similar to makeConstRead(), but desired property is some expression instead of a constant * * @see #makeConstRead(CAstNode, CAstNode, CAstNode, RewriteContext, Map) */ private CAstNode makeVarRead( CAstNode root, CAstNode receiver, CAstNode element, RewriteContext context, Map<Pair<CAstNode, ExpanderKey>, CAstNode> nodeMap) { String receiverTemp = TEMP_NAME + (readTempCounter++); String elementTemp = TEMP_NAME + (readTempCounter++); if (context.inAssignment()) { context.setAssign( Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)), Ast.makeNode(CAstNode.VAR, Ast.makeConstant(elementTemp))); } CAstNode get; CAstNode result = Ast.makeNode( CAstNode.BLOCK_EXPR, Ast.makeNode( CAstNode.DECL_STMT, Ast.makeConstant(new InternalCAstSymbol(receiverTemp, false, false)), receiver), Ast.makeNode( CAstNode.DECL_STMT, Ast.makeConstant(new InternalCAstSymbol(elementTemp, false, false)), element), Ast.makeNode( CAstNode.LOOP, Ast.makeNode( CAstNode.UNARY_EXPR, CAstOperator.OP_NOT, Ast.makeNode( CAstNode.IS_DEFINED_EXPR, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)), Ast.makeNode(CAstNode.VAR, Ast.makeConstant(elementTemp)))), Ast.makeNode( CAstNode.ASSIGN, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)), Ast.makeNode( CAstNode.OBJECT_REF, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)), Ast.makeConstant("__proto__")))), get = Ast.makeNode( CAstNode.OBJECT_REF, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)), Ast.makeNode(CAstNode.VAR, Ast.makeConstant(elementTemp)))); nodeMap.put(Pair.make(root, context.key()), get); return result; }
private IMethod makeObjectConstructor(IClass cls, int nargs) { if (nargs == 0 || nargs == 1) { Object key = Pair.make(cls, new Integer(nargs)); if (constructors.containsKey(key)) return constructors.get(key); else return record( key, (nargs == 0) ? makeNullaryObjectConstructor(cls) : makeUnaryObjectConstructor(cls)); } else { // not a legal call, likely the result of analysis imprecision return null; } }
private IMethod makeValueConstructor(IClass cls, int nargs, Object value) { if (nargs == 0 || nargs == 1) { Object key = Pair.make(cls, new Integer(nargs)); if (constructors.containsKey(key)) return constructors.get(key); else return record( key, (nargs == 0) ? makeNullaryValueConstructor(cls, value) : makeUnaryValueConstructor(cls)); } else { // not a legal call, likely due to dataflow imprecision return null; } }
/** * collect the putstatic instructions in the call graph as {@link PathEdge} seeds for the * analysis */ private Collection<PathEdge<BasicBlockInContext<IExplodedBasicBlock>>> collectInitialSeeds() { Collection<PathEdge<BasicBlockInContext<IExplodedBasicBlock>>> result = HashSetFactory.make(); for (BasicBlockInContext<IExplodedBasicBlock> bb : supergraph) { IExplodedBasicBlock ebb = bb.getDelegate(); SSAInstruction instruction = ebb.getInstruction(); if (instruction instanceof SSAPutInstruction) { SSAPutInstruction putInstr = (SSAPutInstruction) instruction; if (putInstr.isStatic()) { final CGNode cgNode = bb.getNode(); Pair<CGNode, Integer> fact = Pair.make(cgNode, ebb.getFirstInstructionIndex()); int factNum = domain.add(fact); BasicBlockInContext<IExplodedBasicBlock> fakeEntry = getFakeEntry(cgNode); // note that the fact number used for the source of this path edge doesn't really matter result.add(PathEdge.createPathEdge(fakeEntry, factNum, bb, factNum)); } } } return result; }
private IMethod makeFunctionConstructor(IClass receiver, IClass cls) { JSInstructionFactory insts = (JSInstructionFactory) cls.getClassLoader().getInstructionFactory(); Pair<IClass, IClass> tableKey = Pair.make(receiver, cls); if (constructors.containsKey(tableKey)) return constructors.get(tableKey); MethodReference ref = JavaScriptMethods.makeCtorReference(receiver.getReference()); JavaScriptSummary S = new JavaScriptSummary(ref, 1); S.addStatement(insts.GetInstruction(4, 1, "prototype")); S.getNextProgramCounter(); S.addStatement( insts.NewInstruction( 5, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference()))); S.addStatement( insts.NewInstruction( 7, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object))); S.addStatement(insts.SetPrototype(5, 4)); // S.addStatement(insts.PutInstruction(5, 4, "__proto__")); S.getNextProgramCounter(); S.addStatement(insts.PutInstruction(5, 7, "prototype")); S.getNextProgramCounter(); S.addStatement(insts.PutInstruction(7, 5, "constructor")); S.getNextProgramCounter(); // TODO we need to set v7.__proto__ to Object.prototype S.addStatement(insts.ReturnInstruction(5, false)); S.getNextProgramCounter(); // S.addConstant(8, new ConstantValue("__proto__")); if (receiver != cls) return record( tableKey, new JavaScriptConstructor(ref, S, receiver, "(" + cls.getReference().getName() + ")")); else return record(tableKey, new JavaScriptConstructor(ref, S, receiver)); }
private static List<Pair<CGNode, SSACheckCastInstruction>> findFailingCasts( CallGraph cg, DemandRefinementPointsTo dmp) { final IClassHierarchy cha = dmp.getClassHierarchy(); List<Pair<CGNode, SSACheckCastInstruction>> failing = new ArrayList<Pair<CGNode, SSACheckCastInstruction>>(); int numSafe = 0, numMightFail = 0; outer: for (Iterator<? extends CGNode> nodeIter = cg.iterator(); nodeIter.hasNext(); ) { CGNode node = nodeIter.next(); TypeReference declaringClass = node.getMethod().getReference().getDeclaringClass(); // skip library classes if (declaringClass.getClassLoader().equals(ClassLoaderReference.Primordial)) { continue; } IR ir = node.getIR(); if (ir == null) continue; SSAInstruction[] instrs = ir.getInstructions(); for (int i = 0; i < instrs.length; i++) { if (numSafe + numMightFail > MAX_CASTS) break outer; SSAInstruction instruction = instrs[i]; if (instruction instanceof SSACheckCastInstruction) { SSACheckCastInstruction castInstr = (SSACheckCastInstruction) instruction; final TypeReference[] declaredResultTypes = castInstr.getDeclaredResultTypes(); boolean primOnly = true; for (TypeReference t : declaredResultTypes) { if (!t.isPrimitiveType()) { primOnly = false; } } if (primOnly) { continue; } System.err.println("CHECKING " + castInstr + " in " + node.getMethod()); PointerKey castedPk = heapModel.getPointerKeyForLocal(node, castInstr.getUse(0)); Predicate<InstanceKey> castPred = new Predicate<InstanceKey>() { @Override public boolean test(InstanceKey ik) { TypeReference ikTypeRef = ik.getConcreteType().getReference(); for (TypeReference t : declaredResultTypes) { if (cha.isAssignableFrom(cha.lookupClass(t), cha.lookupClass(ikTypeRef))) { return true; } } return false; } }; long startTime = System.currentTimeMillis(); Pair<PointsToResult, Collection<InstanceKey>> queryResult = dmp.getPointsTo(castedPk, castPred); long runningTime = System.currentTimeMillis() - startTime; System.err.println("running time: " + runningTime + "ms"); final FieldRefinePolicy fieldRefinePolicy = dmp.getRefinementPolicy().getFieldRefinePolicy(); switch (queryResult.fst) { case SUCCESS: System.err.println("SAFE: " + castInstr + " in " + node.getMethod()); if (fieldRefinePolicy instanceof ManualFieldPolicy) { ManualFieldPolicy hackedFieldPolicy = (ManualFieldPolicy) fieldRefinePolicy; System.err.println(hackedFieldPolicy.getHistory()); } System.err.println("TRAVERSED " + dmp.getNumNodesTraversed() + " nodes"); numSafe++; break; case NOMOREREFINE: if (queryResult.snd != null) { System.err.println( "MIGHT FAIL: no more refinement possible for " + castInstr + " in " + node.getMethod()); } else { System.err.println( "MIGHT FAIL: exceeded budget for " + castInstr + " in " + node.getMethod()); } failing.add(Pair.make(node, castInstr)); numMightFail++; break; case BUDGETEXCEEDED: System.err.println( "MIGHT FAIL: exceeded budget for " + castInstr + " in " + node.getMethod()); failing.add(Pair.make(node, castInstr)); numMightFail++; break; default: Assertions.UNREACHABLE(); } } } // break outer; } System.err.println("TOTAL SAFE: " + numSafe); System.err.println("TOTAL MIGHT FAIL: " + numMightFail); return failing; }
@Override protected CAstNode copyNodes( CAstNode root, final CAstControlFlowMap cfg, RewriteContext context, Map<Pair<CAstNode, ExpanderKey>, CAstNode> nodeMap) { int kind = root.getKind(); if (kind == CAstNode.OBJECT_REF && context.inRead()) { // if we see a property access (OBJECT_REF) in a read context, transform // to a loop traversing the prototype chain CAstNode readLoop; CAstNode receiver = copyNodes(root.getChild(0), cfg, READ, nodeMap); CAstNode element = copyNodes(root.getChild(1), cfg, READ, nodeMap); if (element.getKind() == CAstNode.CONSTANT && element.getValue() instanceof String) { readLoop = makeConstRead(root, receiver, element, context, nodeMap); } else { readLoop = makeVarRead(root, receiver, element, context, nodeMap); } return readLoop; } else if (kind == CAstNode.ASSIGN_PRE_OP || kind == CAstNode.ASSIGN_POST_OP) { // handle cases like x.f++, represented as ASSIGN_POST_OP(x.f,1,+) AssignPreOrPostOpContext ctxt = new AssignPreOrPostOpContext(); // generate loop for the first child (x.f for example), keeping the loop var and element var // in ctxt CAstNode lval = copyNodes(root.getChild(0), cfg, ctxt, nodeMap); CAstNode rval = copyNodes(root.getChild(1), cfg, READ, nodeMap); CAstNode op = copyNodes(root.getChild(2), cfg, READ, nodeMap); if (ctxt.receiverTemp != null) { // if we found a nested property access String temp1 = TEMP_NAME + (readTempCounter++); String temp2 = TEMP_NAME + (readTempCounter++); CAstNode copy = Ast.makeNode( CAstNode.BLOCK_EXPR, // assign lval to temp1 (where lval is a block that includes the prototype chain // loop) Ast.makeNode( CAstNode.DECL_STMT, Ast.makeConstant(new InternalCAstSymbol(temp1, true, false)), lval), // ? --MS // rval, // assign temp2 the new value to be assigned Ast.makeNode( CAstNode.DECL_STMT, Ast.makeConstant(new InternalCAstSymbol(temp2, true, false)), Ast.makeNode( CAstNode.BINARY_EXPR, op, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(temp1)), rval)), // write temp2 into the property Ast.makeNode( CAstNode.ASSIGN, Ast.makeNode(CAstNode.OBJECT_REF, ctxt.receiverTemp, ctxt.elementTemp), Ast.makeNode(CAstNode.VAR, Ast.makeConstant(temp2))), // final value depends on whether we had a pre op or post op Ast.makeNode( CAstNode.VAR, Ast.makeConstant((kind == CAstNode.ASSIGN_PRE_OP) ? temp2 : temp1))); nodeMap.put(Pair.make(root, context.key()), copy); return copy; } else { CAstNode copy = Ast.makeNode(kind, lval, rval, op); nodeMap.put(Pair.make(root, context.key()), copy); return copy; } } else if (kind == CAstNode.ASSIGN) { // use ASSIGN context for LHS so we don't translate property accesses there CAstNode copy = Ast.makeNode( CAstNode.ASSIGN, copyNodes(root.getChild(0), cfg, ASSIGN, nodeMap), copyNodes(root.getChild(1), cfg, READ, nodeMap)); nodeMap.put(Pair.make(root, context.key()), copy); return copy; } else if (kind == CAstNode.BLOCK_EXPR) { CAstNode children[] = new CAstNode[root.getChildCount()]; int last = (children.length - 1); for (int i = 0; i < last; i++) { children[i] = copyNodes(root.getChild(i), cfg, READ, nodeMap); } children[last] = copyNodes(root.getChild(last), cfg, context, nodeMap); CAstNode copy = Ast.makeNode(CAstNode.BLOCK_EXPR, children); nodeMap.put(Pair.make(root, context.key()), copy); return copy; } else if (root.getKind() == CAstNode.CONSTANT) { CAstNode copy = Ast.makeConstant(root.getValue()); nodeMap.put(Pair.make(root, context.key()), copy); return copy; } else if (root.getKind() == CAstNode.OPERATOR) { nodeMap.put(Pair.make(root, context.key()), root); return root; } else { CAstNode children[] = new CAstNode[root.getChildCount()]; for (int i = 0; i < children.length; i++) { children[i] = copyNodes(root.getChild(i), cfg, READ, nodeMap); } for (Object label : cfg.getTargetLabels(root)) { if (label instanceof CAstNode) { copyNodes((CAstNode) label, cfg, READ, nodeMap); } } CAstNode copy = Ast.makeNode(kind, children); nodeMap.put(Pair.make(root, context.key()), copy); return copy; } }