Search in sources :

Example 1 with BranchEnd

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

the class AbstractParserGenerator method invokeState.

private void invokeState(final String className, final ClassFile file, final CodeAttribute c, final State currentState, final State initialState, final CodeLocation noStateStart, final CodeLocation prefixStart, final CodeLocation returnIncompleteCode, final CodeLocation returnCompleteCode, final CustomStateMachine stateMachine) {
    currentState.mark(c);
    BranchEnd parseDone = null;
    if (currentState == initialState) {
        //if this is the initial state there is a possibility that we need to deal with a left over character first
        //we need to see if we start with a left over character
        c.aload(PARSE_STATE_VAR);
        c.getfield(parseStateClass, "leftOver", "B");
        c.dup();
        final BranchEnd end = c.ifne();
        c.pop();
        //load 2 copies of the current byte into the stack
        handleReturnIfNoMoreBytes(c, returnIncompleteCode);
        c.aload(BYTE_BUFFER_VAR);
        c.invokevirtual(ByteBuffer.class.getName(), "get", "()B");
        BranchEnd cont = c.gotoInstruction();
        c.branchEnd(end);
        c.aload(PARSE_STATE_VAR);
        c.iconst(0);
        c.putfield(parseStateClass, "leftOver", "B");
        c.branchEnd(cont);
    } else {
        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<AtomicReference<BranchEnd>> tokenEnds = new HashSet<AtomicReference<BranchEnd>>();
    final Map<State, AtomicReference<BranchEnd>> ends = new IdentityHashMap<State, AtomicReference<BranchEnd>>();
    for (State state : currentState.next.values()) {
        c.iconst(state.value);
        ends.put(state, new AtomicReference<BranchEnd>(c.ifIcmpeq()));
        c.dup();
    }
    if (stateMachine.isHeader()) {
        c.iconst(':');
        tokenEnds.add(new AtomicReference<BranchEnd>(c.ifIcmpeq()));
        c.dup();
    }
    c.iconst(' ');
    tokenEnds.add(new AtomicReference<BranchEnd>(c.ifIcmpeq()));
    c.dup();
    c.iconst('\t');
    tokenEnds.add(new AtomicReference<BranchEnd>(c.ifIcmpeq()));
    c.dup();
    c.iconst('\r');
    tokenEnds.add(new AtomicReference<BranchEnd>(c.ifIcmpeq()));
    c.dup();
    c.iconst('\n');
    tokenEnds.add(new AtomicReference<BranchEnd>(c.ifIcmpeq()));
    c.iconst(NO_STATE);
    c.istore(CURRENT_STATE_VAR);
    //create the string builder
    c.aload(STATE_STRING_BUILDER_VAR);
    c.ldc(currentState.soFar);
    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.pop();
    c.gotoInstruction(noStateStart);
    //now we write out tokenEnd
    for (AtomicReference<BranchEnd> tokenEnd : tokenEnds) {
        c.branchEnd(tokenEnd.get());
    }
    if (!currentState.soFar.isEmpty()) {
        c.getstatic(file.getName(), currentState.httpStringFieldName, HTTP_STRING_DESCRIPTOR);
        stateMachine.handleStateMachineMatchedToken(c);
        //TODO: exit if it returns null
        tokenDone(c, returnCompleteCode, stateMachine);
    } else {
        if (stateMachine.initialNewlineMeansRequestDone()) {
            c.iconst('\n');
            parseDone = c.ifIcmpeq();
        } else {
            c.pop();
        }
        setupLocalVariables(c);
        handleReturnIfNoMoreBytes(c, returnIncompleteCode);
        initialState.jumpTo(c);
    }
    for (Map.Entry<State, AtomicReference<BranchEnd>> e : ends.entrySet()) {
        c.branchEnd(e.getValue().get());
        c.pop();
        final State state = e.getKey();
        if (state.stateno < 0) {
            //prefix match
            c.iconst(state.stateno);
            c.istore(CURRENT_STATE_VAR);
            c.getstatic(className, state.httpStringFieldName, HTTP_STRING_DESCRIPTOR);
            c.astore(STATE_CURRENT_VAR);
            c.getstatic(className, state.fieldName, "[B");
            c.astore(STATE_CURRENT_BYTES_VAR);
            c.iconst(state.soFar.length());
            c.istore(STATE_POS_VAR);
            c.gotoInstruction(prefixStart);
        } else {
            c.iconst(state.stateno);
            c.istore(CURRENT_STATE_VAR);
            state.jumpTo(c);
        }
    }
    if (parseDone != null) {
        c.branchEnd(parseDone);
        c.aload(PARSE_STATE_VAR);
        c.invokevirtual(parseStateClass, "parseComplete", "()V");
        c.iconst(0);
        c.returnInstruction();
    }
}
Also used : BranchEnd(org.jboss.classfilewriter.code.BranchEnd) IdentityHashMap(java.util.IdentityHashMap) AtomicReference(java.util.concurrent.atomic.AtomicReference) ByteBuffer(java.nio.ByteBuffer) IdentityHashMap(java.util.IdentityHashMap) HashMap(java.util.HashMap) Map(java.util.Map) HashSet(java.util.HashSet)

Example 2 with BranchEnd

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

the class AbstractParserGenerator method createStateField.

private void createStateField(final State state, final ClassFile file, final CodeAttribute sc) {
    if (state.fieldName != null) {
        file.addField(AccessFlag.STATIC | AccessFlag.FINAL | AccessFlag.PRIVATE, state.fieldName, "[B");
        sc.ldc(state.terminalState);
        sc.ldc("ISO-8859-1");
        sc.invokevirtual(String.class.getName(), "getBytes", "(Ljava/lang/String;)[B");
        sc.putstatic(file.getName(), state.fieldName, "[B");
    }
    if (state.httpStringFieldName != null) {
        file.addField(AccessFlag.STATIC | AccessFlag.FINAL | AccessFlag.PRIVATE, state.httpStringFieldName, HTTP_STRING_DESCRIPTOR);
        //first we try and get the string from the map of known HTTP strings
        //this means that the result we store will be the same object as the
        //constants that are referenced in the handlers
        //if this fails we just create a new http string
        sc.aload(CONSTRUCTOR_HTTP_STRING_MAP_VAR);
        if (state.terminalState != null) {
            sc.ldc(state.terminalState);
        } else {
            sc.ldc(state.soFar);
        }
        sc.invokeinterface(Map.class.getName(), "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
        sc.dup();
        BranchEnd end = sc.ifnull();
        sc.checkcast(HTTP_STRING_CLASS);
        sc.putstatic(file.getName(), state.httpStringFieldName, HTTP_STRING_DESCRIPTOR);
        BranchEnd done = sc.gotoInstruction();
        sc.branchEnd(end);
        sc.pop();
        sc.newInstruction(HTTP_STRING_CLASS);
        sc.dup();
        if (state.terminalState != null) {
            sc.ldc(state.terminalState);
        } else {
            sc.ldc(state.soFar);
        }
        sc.invokespecial(HTTP_STRING_CLASS, "<init>", "(Ljava/lang/String;)V");
        sc.putstatic(file.getName(), state.httpStringFieldName, HTTP_STRING_DESCRIPTOR);
        sc.branchEnd(done);
    }
}
Also used : BranchEnd(org.jboss.classfilewriter.code.BranchEnd) IdentityHashMap(java.util.IdentityHashMap) HashMap(java.util.HashMap) Map(java.util.Map)

Example 3 with BranchEnd

use of org.jboss.classfilewriter.code.BranchEnd 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

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