Search in sources :

Example 1 with CodeLocation

use of org.jboss.classfilewriter.code.CodeLocation in project undertow by undertow-io.

the class AbstractParserGenerator method writeStateMachine.

private void writeStateMachine(final String className, final ClassFile file, final CodeAttribute c, final State initial, final List<State> allStates, int noStates, final CustomStateMachine stateMachine, final ClassMethod sctor) {
    //initial hasRemaining check
    c.aload(BYTE_BUFFER_VAR);
    c.invokevirtual(ByteBuffer.class.getName(), "hasRemaining", "()Z");
    final BranchEnd nonZero = c.ifne();
    //we have run out of bytes, return 0
    c.iconst(0);
    c.returnInstruction();
    c.branchEnd(nonZero);
    final List<State> states = new ArrayList<State>();
    states.add(initial);
    states.addAll(allStates);
    Collections.sort(states);
    //store the current state in a local variable
    c.aload(PARSE_STATE_VAR);
    c.dup();
    c.getfield(parseStateClass, "stringBuilder", DescriptorUtils.makeDescriptor(StringBuilder.class));
    c.astore(STATE_STRING_BUILDER_VAR);
    c.dup();
    c.getfield(parseStateClass, "parseState", "I");
    c.dup();
    c.istore(CURRENT_STATE_VAR);
    //if this is state 0 there is a lot of stuff can ignore
    BranchEnd optimizationEnd = c.ifeq();
    c.dup();
    c.getfield(parseStateClass, "pos", "I");
    c.istore(STATE_POS_VAR);
    c.dup();
    c.getfield(parseStateClass, "current", HTTP_STRING_DESCRIPTOR);
    c.astore(STATE_CURRENT_VAR);
    c.getfield(parseStateClass, "currentBytes", "[B");
    c.astore(STATE_CURRENT_BYTES_VAR);
    //load the current state
    c.iload(CURRENT_STATE_VAR);
    //switch on the current state
    TableSwitchBuilder builder = new TableSwitchBuilder(-2, noStates);
    final IdentityHashMap<State, AtomicReference<BranchEnd>> ends = new IdentityHashMap<State, AtomicReference<BranchEnd>>();
    final AtomicReference<BranchEnd> prefixMatch = builder.add();
    final AtomicReference<BranchEnd> noState = builder.add();
    ends.put(initial, builder.add());
    for (final State s : states) {
        if (s.stateno > 0) {
            ends.put(s, builder.add());
        }
    }
    c.tableswitch(builder);
    stateNotFound(c, builder);
    //return code
    //code that synchronizes the state object and returns
    setupLocalVariables(c);
    final CodeLocation returnIncompleteCode = c.mark();
    c.aload(PARSE_STATE_VAR);
    c.dup();
    c.dup();
    c.dup();
    c.dup();
    c.iload(STATE_POS_VAR);
    c.putfield(parseStateClass, "pos", "I");
    c.aload(STATE_CURRENT_VAR);
    c.putfield(parseStateClass, "current", HTTP_STRING_DESCRIPTOR);
    c.aload(STATE_CURRENT_BYTES_VAR);
    c.putfield(parseStateClass, "currentBytes", "[B");
    c.iload(CURRENT_STATE_VAR);
    c.putfield(parseStateClass, "parseState", "I");
    c.returnInstruction();
    setupLocalVariables(c);
    final CodeLocation returnCompleteCode = c.mark();
    c.aload(PARSE_STATE_VAR);
    c.dup();
    c.dup();
    c.dup();
    c.dup();
    c.iconst(0);
    c.putfield(parseStateClass, "pos", "I");
    c.aconstNull();
    c.putfield(parseStateClass, "current", HTTP_STRING_DESCRIPTOR);
    c.aconstNull();
    c.putfield(parseStateClass, "currentBytes", "[B");
    c.aload(STATE_STRING_BUILDER_VAR);
    c.iconst(0);
    c.invokevirtual(StringBuilder.class.getName(), "setLength", "(I)V");
    c.iconst(0);
    c.putfield(parseStateClass, "parseState", "I");
    c.returnInstruction();
    //prefix
    c.branchEnd(prefixMatch.get());
    //loop for when we are prefix matching
    final CodeLocation prefixLoop = c.mark();
    handleReturnIfNoMoreBytes(c, returnIncompleteCode);
    //load 3 copies of the current byte into the stack
    c.aload(BYTE_BUFFER_VAR);
    c.invokevirtual(ByteBuffer.class.getName(), "get", "()B");
    c.dup();
    c.dup();
    final Set<BranchEnd> prefixHandleSpace = new HashSet<BranchEnd>();
    if (stateMachine.isHeader()) {
        c.iconst(':');
        prefixHandleSpace.add(c.ifIcmpeq());
        c.dup();
    }
    c.iconst(' ');
    prefixHandleSpace.add(c.ifIcmpeq());
    c.dup();
    c.iconst('\t');
    prefixHandleSpace.add(c.ifIcmpeq());
    c.dup();
    c.iconst('\r');
    prefixHandleSpace.add(c.ifIcmpeq());
    c.dup();
    c.iconst('\n');
    prefixHandleSpace.add(c.ifIcmpeq());
    //check if we have overrun
    c.aload(STATE_CURRENT_BYTES_VAR);
    c.arraylength();
    c.iload(STATE_POS_VAR);
    BranchEnd overrun = c.ifIcmpeq();
    //so we have not overrun
    //now check if the character matches
    c.dup();
    c.aload(STATE_CURRENT_BYTES_VAR);
    c.iload(STATE_POS_VAR);
    c.baload();
    c.isub();
    BranchEnd noMatch = c.ifne();
    //so they match
    //pop our extra bytes off the stack, we do not need it
    c.pop2();
    c.iinc(STATE_POS_VAR, 1);
    handleReturnIfNoMoreBytes(c, returnIncompleteCode);
    c.gotoInstruction(prefixLoop);
    //overrun and not match use the same code path
    c.branchEnd(overrun);
    //the current character did not match
    c.branchEnd(noMatch);
    c.iconst(NO_STATE);
    c.istore(CURRENT_STATE_VAR);
    //create the string builder
    c.aload(STATE_STRING_BUILDER_VAR);
    c.aload(STATE_CURRENT_VAR);
    c.invokevirtual(HTTP_STRING_CLASS, "toString", "()Ljava/lang/String;");
    c.iconst(0);
    c.iload(STATE_POS_VAR);
    c.invokevirtual(String.class.getName(), "substring", "(II)Ljava/lang/String;");
    c.invokevirtual(StringBuilder.class.getName(), "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
    c.swap();
    c.invokevirtual(StringBuilder.class.getName(), "append", "(C)Ljava/lang/StringBuilder;");
    c.pop2();
    BranchEnd prefixToNoState = c.gotoInstruction();
    //handle the space case
    for (BranchEnd b : prefixHandleSpace) {
        c.branchEnd(b);
    }
    //new state will be 0
    c.iconst(0);
    c.istore(CURRENT_STATE_VAR);
    c.aload(STATE_CURRENT_BYTES_VAR);
    c.arraylength();
    c.iload(STATE_POS_VAR);
    BranchEnd correctLength = c.ifIcmpeq();
    c.newInstruction(HTTP_STRING_CLASS);
    c.dup();
    c.aload(STATE_CURRENT_BYTES_VAR);
    c.iconst(0);
    c.iload(STATE_POS_VAR);
    c.invokespecial(HTTP_STRING_CLASS, "<init>", "([BII)V");
    stateMachine.handleOtherToken(c);
    //TODO: exit if it returns null
    //decrease the available bytes
    c.pop();
    tokenDone(c, returnCompleteCode, stateMachine);
    c.branchEnd(correctLength);
    c.aload(STATE_CURRENT_VAR);
    stateMachine.handleStateMachineMatchedToken(c);
    //TODO: exit if it returns null
    c.pop();
    tokenDone(c, returnCompleteCode, stateMachine);
    //nostate
    c.branchEnd(noState.get());
    c.branchEnd(prefixToNoState);
    CodeLocation noStateLoop = c.mark();
    handleReturnIfNoMoreBytes(c, returnIncompleteCode);
    //load 2 copies of the current byte into the stack
    c.aload(BYTE_BUFFER_VAR);
    c.invokevirtual(ByteBuffer.class.getName(), "get", "()B");
    c.dup();
    final Set<BranchEnd> nostateHandleSpace = new HashSet<BranchEnd>();
    if (stateMachine.isHeader()) {
        c.iconst(':');
        nostateHandleSpace.add(c.ifIcmpeq());
        c.dup();
    }
    c.iconst(' ');
    nostateHandleSpace.add(c.ifIcmpeq());
    c.dup();
    c.iconst('\t');
    nostateHandleSpace.add(c.ifIcmpeq());
    c.dup();
    c.iconst('\r');
    nostateHandleSpace.add(c.ifIcmpeq());
    c.dup();
    c.iconst('\n');
    nostateHandleSpace.add(c.ifIcmpeq());
    c.aload(STATE_STRING_BUILDER_VAR);
    c.swap();
    c.invokevirtual(StringBuilder.class.getName(), "append", "(C)Ljava/lang/StringBuilder;");
    c.pop();
    c.aload(BYTE_BUFFER_VAR);
    c.invokevirtual(ByteBuffer.class.getName(), "hasRemaining", "()Z");
    //go back to the start if we have not run out of bytes
    c.ifne(noStateLoop);
    //we have run out of bytes, so we need to write back the current state
    c.aload(PARSE_STATE_VAR);
    c.iload(CURRENT_STATE_VAR);
    c.putfield(parseStateClass, "parseState", "I");
    c.iconst(0);
    c.returnInstruction();
    for (BranchEnd b : nostateHandleSpace) {
        c.branchEnd(b);
    }
    c.aload(STATE_STRING_BUILDER_VAR);
    c.invokevirtual(StringBuilder.class.getName(), "toString", "()Ljava/lang/String;");
    c.newInstruction(HTTP_STRING_CLASS);
    c.dupX1();
    c.swap();
    c.invokespecial(HTTP_STRING_CLASS, "<init>", "(Ljava/lang/String;)V");
    stateMachine.handleOtherToken(c);
    //TODO: exit if it returns null
    tokenDone(c, returnCompleteCode, stateMachine);
    c.branchEnd(optimizationEnd);
    c.pop();
    c.iconst(0);
    c.istore(STATE_POS_VAR);
    c.aconstNull();
    c.astore(STATE_CURRENT_VAR);
    c.aconstNull();
    c.astore(STATE_CURRENT_BYTES_VAR);
    c.branchEnd(ends.get(initial).get());
    invokeState(className, file, c, initial, initial, noStateLoop, prefixLoop, returnIncompleteCode, returnCompleteCode, stateMachine);
    for (final State s : allStates) {
        if (s.stateno >= 0) {
            c.branchEnd(ends.get(s).get());
            invokeState(className, file, c, s, initial, noStateLoop, prefixLoop, returnIncompleteCode, returnCompleteCode, stateMachine);
        }
    }
}
Also used : CodeLocation(org.jboss.classfilewriter.code.CodeLocation) BranchEnd(org.jboss.classfilewriter.code.BranchEnd) IdentityHashMap(java.util.IdentityHashMap) ArrayList(java.util.ArrayList) AtomicReference(java.util.concurrent.atomic.AtomicReference) ByteBuffer(java.nio.ByteBuffer) TableSwitchBuilder(org.jboss.classfilewriter.code.TableSwitchBuilder) HashSet(java.util.HashSet)

Aggregations

ByteBuffer (java.nio.ByteBuffer)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 IdentityHashMap (java.util.IdentityHashMap)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 BranchEnd (org.jboss.classfilewriter.code.BranchEnd)1 CodeLocation (org.jboss.classfilewriter.code.CodeLocation)1 TableSwitchBuilder (org.jboss.classfilewriter.code.TableSwitchBuilder)1