/** * Auxiliary method that translates into Kitten bytecode all class members that are referenced * from the given block and the blocks reachable from it. * * @param block the block * @param done the class member signatures already translated * @param blocksDone the blocks that have been already processed */ protected void translateReferenced( Block block, Set<ClassMemberSignature> done, Set<Block> blocksDone) { // if we already processed the block, we return immediately if (!blocksDone.add(block)) return; for (BytecodeList cursor = block.getBytecode(); cursor != null; cursor = cursor.getTail()) { Bytecode h = cursor.getHead(); if (h instanceof GETFIELD) { FieldSignature field = ((GETFIELD) h).getField(); this.process(field.getDefiningClass(), done); done.add(field); } else if (h instanceof PUTFIELD) { FieldSignature field = ((PUTFIELD) h).getField(); this.process(field.getDefiningClass(), done); done.add(field); } else if (h instanceof CALL) for (CodeSignature callee : ((CALL) h).getDynamicTargets()) { this.process(callee.getDefiningClass(), done); callee.getAbstractSyntax().translate(done); } } // we continue with the following blocks for (Block follow : block.getFollows()) translateReferenced(follow, done, blocksDone); }
protected void process(ClassType clazz, Set<ClassMemberSignature> done) { for (CodeSignature cs : clazz.fixturesLookup()) { cs.getAbstractSyntax().translate(done); } for (CodeSignature cs : clazz.getTests()) { cs.getAbstractSyntax().translate(done); } }
/** * Translates this constructor or method into intermediate Kitten code. This amounts to * translating its body with a continuation containing a {@code return} bytecode. This way, if a * method does not have an explicit {@code return} statement, it is automatically put at its end. * * @param done the set of code signatures that have been already translated */ public void translate(Set<ClassMemberSignature> done) { if (done.add(sig)) { this.process(sig.getDefiningClass(), done); // we translate the body of the constructor or // method with a block containing RETURN as continuation. This way, // all methods returning void and // with some missing return command are correctly // terminated anyway. If the method is not void, this // precaution is useless since we know that every execution path // ends with a return command, as guaranteed by // checkForDeadCode() (see typeCheck() in MethodDeclaration.java) sig.setCode(getBody().translate(sig, new Block(new RETURN(VoidType.INSTANCE)))); // we translate all methods and constructors that are referenced // from the code we have generated translateReferenced(sig.getCode(), done, new HashSet<Block>()); } }