/** * push an operand of the given type onto the stack * <p> * If the entry is wide then a corresponding TOP type will be created */ public StackFrame push(String type) { StackState ns = stackState.push(type); return new StackFrame(ns, localVariableState, typeNoLocalChange(ns)); }
private LocalVariableState getLocalVars() { if (currentFrame == null) { throw new RuntimeException("No local variable information available, call setupFrame first"); } return currentFrame.getLocalVariableState(); }
private void invokespecial(String className, String methodName, String descriptor, String returnType, String[] parameterTypes) { // TODO: validate stack int method = constPool.addMethodEntry(className, methodName, descriptor); writeByte(Opcode.INVOKESPECIAL); writeShort(method); currentOffset += 3; int pop = 1 + parameterTypes.length; for (String argument : parameterTypes) { if (argument.equals("D") || argument.equals("J")) { pop++; } } if (methodName.equals("<init>")) { advanceFrame(currentFrame.constructorCall(pop - 1)); } else if (returnType.equals("V")) { advanceFrame(currentFrame.pop(pop)); } else { advanceFrame(currentFrame.pop(pop).push(returnType)); } }
StackState mergeStackState = stackFrame.getStackState(); if (currentStackState.size() != mergeStackState.size()) { throw new InvalidBytecodeException("Cannot merge stack frames, different stack sizes " + currentFrame + " " + stackFrame); throw new InvalidBytecodeException("Could not find common supertype for " + mergeEntry.getDescriptor() + " and " + currentEntry.getDescriptor() + " " + currentFrame + " " + stackFrame); } else if (!superType.equals(currentEntry.getDescriptor())) { stackFrames.put(currentOffset, currentFrame = currentFrame.mergeStack(i, new StackEntry(StackEntryType.OBJECT, DescriptorUtils.makeDescriptor(superType), constPool))); LocalVariableState mergeLocalVariableState = stackFrame.getLocalVariableState(); if (currentLocalVariableState.size() < mergeLocalVariableState.size()) { throw new InvalidBytecodeException( throw new InvalidBytecodeException("Could not find common supertype for " + mergeEntry.getDescriptor() + " and " + currentEntry.getDescriptor() + " " + currentFrame + " " + stackFrame); } else if (!superType.equals(currentEntry.getDescriptor())) { stackFrames.put(currentOffset, currentFrame = currentFrame.mergeLocals(i, new StackEntry(StackEntryType.OBJECT, DescriptorUtils.makeDescriptor(superType), constPool)));
/** * Marks the current code location as the exception handler and adds the handler to the exception handler table; */ public void exceptionHandlerStart(ExceptionHandler handler) { if (handler.getEnd() == 0) { throw new InvalidBytecodeException( "handler end location must be initialised via exceptionHandlerEnd before calling exceptionHandlerAdd"); } handler.setHandler(currentOffset); exceptionTable.add(handler); mergeStackFrames(new StackFrame(new StackState(handler.getExceptionType(), constPool), handler.getFrame() .getLocalVariableState(), StackFrameType.FULL_FRAME)); }
/** * writes a full_frame to the stack map table */ private void writeFullFrame(DataOutputStream dstream, int offset, int position, StackFrame value) throws IOException { dstream.writeByte(FULL_FRAME); dstream.writeShort(offset); List<StackEntry> realLocalVars = new ArrayList<StackEntry>(value.getLocalVariableState().getContents().size()); for (StackEntry i : value.getLocalVariableState().getContents()) { if (i.getType() != StackEntryType.TOP) { realLocalVars.add(i); } } dstream.writeShort(realLocalVars.size()); for (StackEntry i : realLocalVars) { i.write(dstream); } // TODO: this is inefficient, the stack should store the number of TOP values in each frame List<StackEntry> realStack = new ArrayList<StackEntry>(value.getStackState().getContents().size()); for (StackEntry i : value.getStackState().getContents()) { if (i.getType() != StackEntryType.TOP) { realStack.add(i); } } dstream.writeShort(realStack.size()); for (StackEntry i : realStack) { i.write(dstream); } }
public StackFrame mergeLocals(int pos, StackEntry frame) { LocalVariableState locals = localVariableState.updateMerged(pos, frame); return new StackFrame(stackState, locals, StackFrameType.FULL_FRAME); } public StackFrameType getType() {
public void dup2() { writeByte(Opcode.DUP2); currentOffset++; advanceFrame(currentFrame.dup2()); }
public void dupX1() { assertNotWideOnStack("dup_x1 cannot be used if double or long is on top of the stack"); assertNotWideOnStack(1, "dup_x1 cannot be used if double or long is in position 2 on the stack"); writeByte(Opcode.DUP_X1); currentOffset++; advanceFrame(currentFrame.dupX1()); }
public void dup2X2() { assertNotWideOnStack(3, "dup2_x2 cannot be used if double or long is in position 4 on the stack"); writeByte(Opcode.DUP2_X2); currentOffset++; advanceFrame(currentFrame.dup2X2()); }
public void aconstNull() { writeByte(Opcode.ACONST_NULL); currentOffset++; advanceFrame(currentFrame.aconstNull()); }
public void dupX2() { assertNotWideOnStack("dup_x2 acnnot be used if double or long is on top of the stack"); writeByte(Opcode.DUP_X2); currentOffset++; advanceFrame(currentFrame.dupX2()); }
public void dup() { assertNotWideOnStack("dup acnnot be used if double or long is on top of the stack"); writeByte(Opcode.DUP); currentOffset++; advanceFrame(currentFrame.dup()); }
public void dup2X1() { assertNotWideOnStack(2, "dup2_x1 cannot be used if double or long is in position 3 on the stack"); writeByte(Opcode.DUP2_X1); currentOffset++; advanceFrame(currentFrame.dup2X1()); }
private void invokespecial(String className, String methodName, String descriptor, String returnType, String[] parameterTypes) { // TODO: validate stack int method = constPool.addMethodEntry(className, methodName, descriptor); writeByte(Opcode.INVOKESPECIAL); writeShort(method); currentOffset += 3; int pop = 1 + parameterTypes.length; for (String argument : parameterTypes) { if (argument.equals("D") || argument.equals("J")) { pop++; } } if (methodName.equals("<init>")) { advanceFrame(currentFrame.constructorCall(pop - 1)); } else if (returnType.equals("V")) { advanceFrame(currentFrame.pop(pop)); } else { advanceFrame(currentFrame.pop(pop).push(returnType)); } }
StackState mergeStackState = stackFrame.getStackState(); if (currentStackState.size() != mergeStackState.size()) { throw new InvalidBytecodeException("Cannot merge stack frames, different stack sizes " + currentFrame + " " + stackFrame); throw new InvalidBytecodeException("Could not find common supertype for " + mergeEntry.getDescriptor() + " and " + currentEntry.getDescriptor() + " " + currentFrame + " " + stackFrame); } else if (!superType.equals(currentEntry.getDescriptor())) { stackFrames.put(currentOffset, currentFrame = currentFrame.mergeStack(i, new StackEntry(StackEntryType.OBJECT, DescriptorUtils.makeDescriptor(superType), constPool))); LocalVariableState mergeLocalVariableState = stackFrame.getLocalVariableState(); if (currentLocalVariableState.size() < mergeLocalVariableState.size()) { throw new InvalidBytecodeException( throw new InvalidBytecodeException("Could not find common supertype for " + mergeEntry.getDescriptor() + " and " + currentEntry.getDescriptor() + " " + currentFrame + " " + stackFrame); } else if (!superType.equals(currentEntry.getDescriptor())) { stackFrames.put(currentOffset, currentFrame = currentFrame.mergeLocals(i, new StackEntry(StackEntryType.OBJECT, DescriptorUtils.makeDescriptor(superType), constPool)));
/** * Marks the current code location as the exception handler and adds the handler to the exception handler table; */ public void exceptionHandlerStart(ExceptionHandler handler) { if (handler.getEnd() == 0) { throw new InvalidBytecodeException( "handler end location must be initialised via exceptionHandlerEnd before calling exceptionHandlerAdd"); } handler.setHandler(currentOffset); exceptionTable.add(handler); mergeStackFrames(new StackFrame(new StackState(handler.getExceptionType(), constPool), handler.getFrame() .getLocalVariableState(), StackFrameType.FULL_FRAME)); }
/** * writes a full_frame to the stack map table */ private void writeFullFrame(DataOutputStream dstream, int offset, int position, StackFrame value) throws IOException { dstream.writeByte(FULL_FRAME); dstream.writeShort(offset); List<StackEntry> realLocalVars = new ArrayList<StackEntry>(value.getLocalVariableState().getContents().size()); for (StackEntry i : value.getLocalVariableState().getContents()) { if (i.getType() != StackEntryType.TOP) { realLocalVars.add(i); } } dstream.writeShort(realLocalVars.size()); for (StackEntry i : realLocalVars) { i.write(dstream); } // TODO: this is inefficient, the stack should store the number of TOP values in each frame List<StackEntry> realStack = new ArrayList<StackEntry>(value.getStackState().getContents().size()); for (StackEntry i : value.getStackState().getContents()) { if (i.getType() != StackEntryType.TOP) { realStack.add(i); } } dstream.writeShort(realStack.size()); for (StackEntry i : realStack) { i.write(dstream); } }
/** * marks the value in potition initializedValueStackPosition as initialized. This also pops this value and everything above * it */ public StackFrame constructorCall(int initializedValueStackPosition) { StackEntry entry = stackState.getContents().get(stackState.getContents().size() - 1 - initializedValueStackPosition); StackState ns = stackState.constructorCall(initializedValueStackPosition, entry); LocalVariableState locals = localVariableState.constructorCall(entry); return new StackFrame(ns, locals, StackFrameType.FULL_FRAME); }
public void dup2() { writeByte(Opcode.DUP2); currentOffset++; advanceFrame(currentFrame.dup2()); }