public void visitLocalVariableInfo( Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { // Let the visitor visit the class referenced in the local variable. localVariableInfo.referencedClassAccept(classVisitor); }
/** * Does the extraction. * * @return {@code non-null;} the extracted information */ private LocalVariableInfo doit() { // FIXME why is this needed here? if (method.getRegCount() > 0) { for (int bi = method.getEntryBlockIndex(); bi >= 0; bi = workSet.nextSetBit(0)) { workSet.clear(bi); processBlock(bi); } } resultInfo.setImmutable(); return resultInfo; }
/** * Processes a single block. * * @param blockIndex {@code >= 0;} block index of the block to process */ private void processBlock(int blockIndex) { RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(blockIndex); SsaBasicBlock block = blocks.get(blockIndex); List<SsaInsn> insns = block.getInsns(); int insnSz = insns.size(); // The exit block has no insns and no successors if (blockIndex == method.getExitBlockIndex()) { return; } /* * We may have to treat the last instruction specially: If it * can (but doesn't always) throw, and the exception can be * caught within the same method, then we need to use the * state *before* executing it to be what is merged into * exception targets. */ SsaInsn lastInsn = insns.get(insnSz - 1); boolean hasExceptionHandlers = lastInsn.getOriginalRopInsn().getCatches().size() != 0; boolean canThrowDuringLastInsn = hasExceptionHandlers && (lastInsn.getResult() != null); int freezeSecondaryStateAt = insnSz - 1; RegisterSpecSet secondaryState = primaryState; /* * Iterate over the instructions, adding information for each place * that the active variable set changes. */ for (int i = 0; i < insnSz; i++) { if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) { // Until this point, primaryState == secondaryState. primaryState.setImmutable(); primaryState = primaryState.mutableCopy(); } SsaInsn insn = insns.get(i); RegisterSpec result; result = insn.getLocalAssignment(); if (result == null) { // We may be nuking an existing local result = insn.getResult(); if (result != null && primaryState.get(result.getReg()) != null) { primaryState.remove(primaryState.get(result.getReg())); } continue; } result = result.withSimpleType(); RegisterSpec already = primaryState.get(result); /* * The equals() check ensures we only add new info if * the instruction causes a change to the set of * active variables. */ if (!result.equals(already)) { /* * If this insn represents a local moving from one register * to another, remove the association between the old register * and the local. */ RegisterSpec previous = primaryState.localItemToSpec(result.getLocalItem()); if (previous != null && (previous.getReg() != result.getReg())) { primaryState.remove(previous); } resultInfo.addAssignment(insn, result); primaryState.put(result); } } primaryState.setImmutable(); /* * Merge this state into the start state for each successor, * and update the work set where required (that is, in cases * where the start state for a block changes). */ IntList successors = block.getSuccessorList(); int succSz = successors.size(); int primarySuccessor = block.getPrimarySuccessorIndex(); for (int i = 0; i < succSz; i++) { int succ = successors.get(i); RegisterSpecSet state = (succ == primarySuccessor) ? primaryState : secondaryState; if (resultInfo.mergeStarts(succ, state)) { workSet.set(succ); } } }
public void writeInstruction(Instruction _instruction) throws CodeGenException { if (_instruction instanceof CompositeIfElseInstruction) { write("("); final Instruction lhs = writeConditional(((CompositeInstruction) _instruction).getBranchSet()); write(")?"); writeInstruction(lhs); write(":"); writeInstruction(lhs.getNextExpr().getNextExpr()); } else if (_instruction instanceof CompositeInstruction) { writeComposite((CompositeInstruction) _instruction); } else if (_instruction instanceof AssignToLocalVariable) { final AssignToLocalVariable assignToLocalVariable = (AssignToLocalVariable) _instruction; final LocalVariableInfo localVariableInfo = assignToLocalVariable.getLocalVariableInfo(); if (assignToLocalVariable.isDeclaration()) { final String descriptor = localVariableInfo.getVariableDescriptor(); // Arrays always map to __global arrays if (descriptor.startsWith("[")) { write(" __global "); } write(convertType(descriptor, true)); } if (localVariableInfo == null) { throw new CodeGenException("outOfScope" + _instruction.getThisPC() + " = "); } else { write(localVariableInfo.getVariableName() + " = "); } for (Instruction operand = _instruction.getFirstChild(); operand != null; operand = operand.getNextExpr()) { writeInstruction(operand); } } else if (_instruction instanceof AssignToArrayElement) { final AssignToArrayElement arrayAssignmentInstruction = (AssignToArrayElement) _instruction; writeInstruction(arrayAssignmentInstruction.getArrayRef()); write("["); writeInstruction(arrayAssignmentInstruction.getArrayIndex()); write("]"); write(" "); write(" = "); writeInstruction(arrayAssignmentInstruction.getValue()); } else if (_instruction instanceof AccessArrayElement) { // we're getting an element from an array // if the array is a primitive then we just return the value // so the generated code looks like // arrayName[arrayIndex]; // but if the array is an object, or multidimensional array, then we want to return // a pointer to our index our position in the array. The code will look like // &(arrayName[arrayIndex * this->arrayNameLen_dimension] // final AccessArrayElement arrayLoadInstruction = (AccessArrayElement) _instruction; // object array, get address if (arrayLoadInstruction instanceof I_AALOAD) { write("(&"); } writeInstruction(arrayLoadInstruction.getArrayRef()); write("["); writeInstruction(arrayLoadInstruction.getArrayIndex()); // object array, find the size of each object in the array // for 2D arrays, this size is the size of a row. if (arrayLoadInstruction instanceof I_AALOAD) { int dim = 0; Instruction load = arrayLoadInstruction.getArrayRef(); while (load instanceof I_AALOAD) { load = load.getFirstChild(); dim++; } String arrayName = ((AccessInstanceField) load) .getConstantPoolFieldEntry() .getNameAndTypeEntry() .getNameUTF8Entry() .getUTF8(); write(" * this->" + arrayName + arrayDimMangleSuffix + dim); } write("]"); // object array, close parentheses if (arrayLoadInstruction instanceof I_AALOAD) { write(")"); } } else if (_instruction instanceof AccessField) { final AccessField accessField = (AccessField) _instruction; if (accessField instanceof AccessInstanceField) { Instruction accessInstanceField = ((AccessInstanceField) accessField).getInstance(); if (accessInstanceField instanceof CloneInstruction) { accessInstanceField = ((CloneInstruction) accessInstanceField).getReal(); } if (!(accessInstanceField instanceof I_ALOAD_0)) { writeInstruction(accessInstanceField); write("."); } else { writeThisRef(); } } write( accessField .getConstantPoolFieldEntry() .getNameAndTypeEntry() .getNameUTF8Entry() .getUTF8()); } else if (_instruction instanceof I_ARRAYLENGTH) { // getting the length of an array. // if this is a primitive array, then this is trivial // if we're getting an object array, then we need to find what dimension // we're looking at int dim = 0; Instruction load = _instruction.getFirstChild(); while (load instanceof I_AALOAD) { load = load.getFirstChild(); dim++; } final AccessInstanceField child = (AccessInstanceField) load; final String arrayName = child.getConstantPoolFieldEntry().getNameAndTypeEntry().getNameUTF8Entry().getUTF8(); write("this->" + arrayName + arrayLengthMangleSuffix + dim); } else if (_instruction instanceof AssignToField) { final AssignToField assignedField = (AssignToField) _instruction; if (assignedField instanceof AssignToInstanceField) { final Instruction accessInstanceField = ((AssignToInstanceField) assignedField).getInstance().getReal(); if (!(accessInstanceField instanceof I_ALOAD_0)) { writeInstruction(accessInstanceField); write("."); } else { writeThisRef(); } } write( assignedField .getConstantPoolFieldEntry() .getNameAndTypeEntry() .getNameUTF8Entry() .getUTF8()); write("="); writeInstruction(assignedField.getValueToAssign()); } else if (_instruction instanceof Constant<?>) { final Constant<?> constantInstruction = (Constant<?>) _instruction; final Object value = constantInstruction.getValue(); if (value instanceof Float) { final Float f = (Float) value; if (f.isNaN()) { write("NAN"); } else if (f.isInfinite()) { if (f < 0) { write("-"); } write("INFINITY"); } else { write(value.toString()); write("f"); } } else if (value instanceof Double) { final Double d = (Double) value; if (d.isNaN()) { write("NAN"); } else if (d.isInfinite()) { if (d < 0) { write("-"); } write("INFINITY"); } else { write(value.toString()); } } else { write(value.toString()); if (value instanceof Long) { write("L"); } } } else if (_instruction instanceof AccessLocalVariable) { final AccessLocalVariable localVariableLoadInstruction = (AccessLocalVariable) _instruction; final LocalVariableInfo localVariable = localVariableLoadInstruction.getLocalVariableInfo(); write(localVariable.getVariableName()); } else if (_instruction instanceof I_IINC) { final I_IINC location = (I_IINC) _instruction; final LocalVariableInfo localVariable = location.getLocalVariableInfo(); final int adjust = location.getAdjust(); write(localVariable.getVariableName()); if (adjust == 1) { write("++"); } else if (adjust == -1) { write("--"); } else if (adjust > 1) { write("+=" + adjust); } else if (adjust < -1) { write("-=" + (-adjust)); } } else if (_instruction instanceof BinaryOperator) { final BinaryOperator binaryInstruction = (BinaryOperator) _instruction; final Instruction parent = binaryInstruction.getParentExpr(); boolean needsParenthesis = true; if (parent instanceof AssignToLocalVariable) { needsParenthesis = false; } else if (parent instanceof AssignToField) { needsParenthesis = false; } else if (parent instanceof AssignToArrayElement) { needsParenthesis = false; } else { /** * if (parent instanceof BinaryOperator) { BinaryOperator parentBinaryOperator = * (BinaryOperator) parent; if (parentBinaryOperator.getOperator().ordinal() > * binaryInstruction.getOperator().ordinal()) { needsParenthesis = false; } } */ } if (needsParenthesis) { write("("); } writeInstruction(binaryInstruction.getLhs()); write(" " + binaryInstruction.getOperator().getText() + " "); writeInstruction(binaryInstruction.getRhs()); if (needsParenthesis) { write(")"); } } else if (_instruction instanceof CastOperator) { final CastOperator castInstruction = (CastOperator) _instruction; // write("("); write(convertCast(castInstruction.getOperator().getText())); writeInstruction(castInstruction.getUnary()); // write(")"); } else if (_instruction instanceof UnaryOperator) { final UnaryOperator unaryInstruction = (UnaryOperator) _instruction; // write("("); write(unaryInstruction.getOperator().getText()); writeInstruction(unaryInstruction.getUnary()); // write(")"); } else if (_instruction instanceof Return) { final Return ret = (Return) _instruction; write("return"); if (ret.getStackConsumeCount() > 0) { write("("); writeInstruction(ret.getFirstChild()); write(")"); } } else if (_instruction instanceof MethodCall) { final MethodCall methodCall = (MethodCall) _instruction; final MethodEntry methodEntry = methodCall.getConstantPoolMethodEntry(); writeMethod(methodCall, methodEntry); } else if (_instruction.getByteCode().equals(ByteCode.CLONE)) { final CloneInstruction cloneInstruction = (CloneInstruction) _instruction; writeInstruction(cloneInstruction.getReal()); } else if (_instruction.getByteCode().equals(ByteCode.INCREMENT)) { final IncrementInstruction incrementInstruction = (IncrementInstruction) _instruction; if (incrementInstruction.isPre()) { if (incrementInstruction.isInc()) { write("++"); } else { write("--"); } } writeInstruction(incrementInstruction.getFieldOrVariableReference()); if (!incrementInstruction.isPre()) { if (incrementInstruction.isInc()) { write("++"); } else { write("--"); } } } else if (_instruction.getByteCode().equals(ByteCode.MULTI_ASSIGN)) { final MultiAssignInstruction multiAssignInstruction = (MultiAssignInstruction) _instruction; AssignToLocalVariable from = (AssignToLocalVariable) multiAssignInstruction.getFrom(); final AssignToLocalVariable last = (AssignToLocalVariable) multiAssignInstruction.getTo(); final Instruction common = multiAssignInstruction.getCommon(); final Stack<AssignToLocalVariable> stack = new Stack<AssignToLocalVariable>(); while (from != last) { stack.push(from); from = (AssignToLocalVariable) ((Instruction) from).getNextExpr(); } for (AssignToLocalVariable alv = stack.pop(); alv != null; alv = stack.size() > 0 ? stack.pop() : null) { final LocalVariableInfo localVariableInfo = alv.getLocalVariableInfo(); if (alv.isDeclaration()) { write(convertType(localVariableInfo.getVariableDescriptor(), true)); } if (localVariableInfo == null) { throw new CodeGenException("outOfScope" + _instruction.getThisPC() + " = "); } else { write(localVariableInfo.getVariableName() + " = "); } } writeInstruction(common); } else if (_instruction.getByteCode().equals(ByteCode.INLINE_ASSIGN)) { final InlineAssignInstruction inlineAssignInstruction = (InlineAssignInstruction) _instruction; final AssignToLocalVariable assignToLocalVariable = inlineAssignInstruction.getAssignToLocalVariable(); final LocalVariableInfo localVariableInfo = assignToLocalVariable.getLocalVariableInfo(); if (assignToLocalVariable.isDeclaration()) { // this is bad! we need a general way to hoist up a required declaration throw new CodeGenException( "/* we can't declare this " + convertType(localVariableInfo.getVariableDescriptor(), true) + " here */"); } write(localVariableInfo.getVariableName()); write("="); writeInstruction(inlineAssignInstruction.getRhs()); } else if (_instruction.getByteCode().equals(ByteCode.FIELD_ARRAY_ELEMENT_ASSIGN)) { final FieldArrayElementAssign inlineAssignInstruction = (FieldArrayElementAssign) _instruction; final AssignToArrayElement arrayAssignmentInstruction = inlineAssignInstruction.getAssignToArrayElement(); writeInstruction(arrayAssignmentInstruction.getArrayRef()); write("["); writeInstruction(arrayAssignmentInstruction.getArrayIndex()); write("]"); write(" "); write(" = "); writeInstruction(inlineAssignInstruction.getRhs()); } else if (_instruction.getByteCode().equals(ByteCode.FIELD_ARRAY_ELEMENT_INCREMENT)) { final FieldArrayElementIncrement fieldArrayElementIncrement = (FieldArrayElementIncrement) _instruction; final AssignToArrayElement arrayAssignmentInstruction = fieldArrayElementIncrement.getAssignToArrayElement(); if (fieldArrayElementIncrement.isPre()) { if (fieldArrayElementIncrement.isInc()) { write("++"); } else { write("--"); } } writeInstruction(arrayAssignmentInstruction.getArrayRef()); write("["); writeInstruction(arrayAssignmentInstruction.getArrayIndex()); write("]"); if (!fieldArrayElementIncrement.isPre()) { if (fieldArrayElementIncrement.isInc()) { write("++"); } else { write("--"); } } } else if (_instruction.getByteCode().equals(ByteCode.NONE)) { // we are done } else if (_instruction instanceof Branch) { throw new CodeGenException( String.format( "%s -> %04d", _instruction.getByteCode().toString().toLowerCase(), ((Branch) _instruction).getTarget().getThisPC())); } else if (_instruction instanceof I_POP) { // POP discarded void call return? writeInstruction(_instruction.getFirstChild()); } else { throw new CodeGenException( String.format("%s", _instruction.getByteCode().toString().toLowerCase())); } }