Search in sources :

Example 1 with SwitchClause

use of com.github.anba.es6draft.ast.SwitchClause in project es6draft by anba.

the class SwitchStatementGenerator method CaseBlockEvaluation.

/**
     * 13.12.9 Runtime Semantics: CaseBlockEvaluation
     * 
     * @param node
     *            the switch statement
     * @param type
     *            the switch statement type
     * @param lblExit
     *            the exit label
     * @param switchValue
     *            the variable which holds the switch value
     * @param mv
     *            the code visitor
     * @return the completion value
     */
private Completion CaseBlockEvaluation(SwitchStatement node, SwitchType type, Jump lblExit, Variable<?> switchValue, CodeVisitor mv) {
    List<SwitchClause> clauses = node.getClauses();
    Jump lblDefault = null;
    Jump[] labels = new Jump[clauses.size()];
    for (int i = 0, size = clauses.size(); i < size; ++i) {
        labels[i] = new Jump();
        if (clauses.get(i).isDefaultClause()) {
            assert lblDefault == null;
            lblDefault = labels[i];
        }
    }
    if (type == SwitchType.Int) {
        emitIntSwitch(clauses, labels, lblDefault, lblExit, switchValue, mv);
    } else if (type == SwitchType.Char) {
        emitCharSwitch(clauses, labels, lblDefault, lblExit, switchValue, mv);
    } else if (type == SwitchType.String) {
        emitStringSwitch(clauses, labels, lblDefault, lblExit, switchValue, mv);
    } else if (type == SwitchType.Generic) {
        emitGenericSwitch(clauses, labels, lblDefault, lblExit, switchValue, mv);
    } else {
        assert type == SwitchType.Default;
        assert switchValue == null;
    // Directly jump to default clause; since switch clauses before default clause are not
    // emitted, jump instruction can be elided as well, so we directly fall into the default
    // clause.
    }
    Completion result = Completion.Normal, lastResult = Completion.Normal;
    if (type == SwitchType.Default) {
        Iterator<SwitchClause> iter = clauses.iterator();
        // skip leading clauses until default clause found
        while (iter.hasNext()) {
            SwitchClause switchClause = iter.next();
            if (switchClause.isDefaultClause()) {
                lastResult = switchClause.accept(this, mv);
                break;
            }
        }
        // handle clauses following default clause until abrupt completion
        while (iter.hasNext() && !lastResult.isAbrupt()) {
            lastResult = iter.next().accept(this, mv);
        }
        result = lastResult;
    } else {
        int index = 0;
        for (SwitchClause switchClause : clauses) {
            Jump caseLabel = labels[index++];
            if (caseLabel != null) {
                mv.mark(caseLabel);
            } else if (lastResult.isAbrupt()) {
                // Ignore unreachable targets
                continue;
            }
            Completion innerResult = switchClause.accept(this, mv);
            if (innerResult.isAbrupt()) {
                // not fall-thru
                result = result.isAbrupt() ? result.select(innerResult) : innerResult;
            }
            lastResult = innerResult;
        }
    }
    return result.normal(lblDefault == null || !lastResult.isAbrupt());
}
Also used : Completion(com.github.anba.es6draft.compiler.StatementGenerator.Completion) SwitchClause(com.github.anba.es6draft.ast.SwitchClause) Jump(com.github.anba.es6draft.compiler.assembler.Jump)

Example 2 with SwitchClause

use of com.github.anba.es6draft.ast.SwitchClause in project es6draft by anba.

the class SwitchStatementGenerator method DefaultCaseBlockEvaluation.

/**
 * 13.12.9 Runtime Semantics: CaseBlockEvaluation
 *
 * @param node
 *            the switch statement
 * @param mv
 *            the code visitor
 * @return the completion value
 */
private Completion DefaultCaseBlockEvaluation(SwitchStatement node, CodeVisitor mv) {
    // Skip leading clauses until default clause found.
    List<SwitchClause> clauses = node.getClauses();
    for (int i = 0; i < clauses.size(); ++i) {
        if (clauses.get(i).isDefaultClause()) {
            clauses = clauses.subList(i, clauses.size());
            break;
        }
    }
    assert !clauses.isEmpty() && clauses.get(0).isDefaultClause();
    Completion lastResult = Completion.Normal;
    if (clauses.size() > SWITCH_CASE_LIMIT) {
        List<CaseBlock> blocks = computeCaseBlocks(node, list -> {
            return new CaseBlock(list, null, null);
        });
        for (CaseBlock caseBlock : blocks) {
            OutlinedCall call = mv.compile(caseBlock.blockKey(), () -> defaultCaseBlock(caseBlock, mv));
            // Pessimistically assume we need to save the completion value.
            lastResult = mv.invokeCompletion(call, mv.hasCompletion());
            if (lastResult.isAbrupt()) {
                break;
            }
        }
    } else {
        // Handle clauses following default clause until abrupt completion found.
        for (SwitchClause switchClause : clauses) {
            lastResult = switchClause.accept(this, mv);
            if (lastResult.isAbrupt()) {
                break;
            }
        }
    }
    return lastResult;
}
Also used : OutlinedCall(com.github.anba.es6draft.compiler.CodeVisitor.OutlinedCall) Completion(com.github.anba.es6draft.compiler.StatementGenerator.Completion) SwitchClause(com.github.anba.es6draft.ast.SwitchClause)

Example 3 with SwitchClause

use of com.github.anba.es6draft.ast.SwitchClause in project es6draft by anba.

the class SwitchStatementGenerator method caseSelect.

/**
 * Generates a case-select method.
 *
 * @param caseBlock
 *            the case-block
 * @param switchVarType
 *            the switch-var type
 * @param mv
 *            the code visitor
 * @return the outlined-call object
 */
private OutlinedCall caseSelect(SwitchStatementGenerator.CaseBlock caseBlock, Type switchVarType, CodeVisitor mv) {
    SwitchClause firstClause = caseBlock.clauses.get(0);
    MethodTypeDescriptor methodDescriptor = SwitchSelectCodeVisitor.methodDescriptor(switchVarType, mv);
    MethodCode method = codegen.method(mv, "select", methodDescriptor);
    return outlined(new SwitchSelectCodeVisitor(firstClause, method, mv), body -> {
        Variable<?> switchValue = body.getSwitchValueParameter();
        MutableValue<Integer> switchTarget = body.iarrayElement(body.getSwitchTargetParameter(), 0);
        List<SwitchClause> clauses = caseBlock.clauses;
        int[] switchTargets = caseBlock.switchTargets;
        int numTargets = caseBlock.numTargets();
        Jump[] targetLabels = new Jump[numTargets];
        for (int i = 0; i < targetLabels.length; ++i) {
            targetLabels[i] = new Jump();
        }
        Jump lblExit = new Jump();
        Jump[] labels = new Jump[clauses.size()];
        for (int i = 0; i < clauses.size(); ++i) {
            labels[i] = targetLabels[switchTargets[i] - 1];
        }
        caseSelector(SwitchType.of(clauses)).select(clauses, switchValue, labels, lblExit, body);
        Jump setSwitchTarget = new Jump();
        for (int i = 0; i < targetLabels.length; ++i) {
            // targetLabels[i] is not reachable if only used by the default clause.
            if (targetLabels[i].isTarget()) {
                body.mark(targetLabels[i]);
                body.iconst(i + 1);
                body.goTo(setSwitchTarget);
            }
        }
        if (setSwitchTarget.isTarget()) {
            // stack: [newSwitchTarget] -> []
            body.mark(setSwitchTarget);
            body.store(switchTarget);
        }
        body.mark(lblExit);
        return Completion.Normal;
    });
}
Also used : SwitchClause(com.github.anba.es6draft.ast.SwitchClause) MethodCode(com.github.anba.es6draft.compiler.assembler.Code.MethodCode) Jump(com.github.anba.es6draft.compiler.assembler.Jump) MethodTypeDescriptor(com.github.anba.es6draft.compiler.assembler.MethodTypeDescriptor)

Example 4 with SwitchClause

use of com.github.anba.es6draft.ast.SwitchClause in project es6draft by anba.

the class SwitchStatementGenerator method CaseBlockEvaluation.

/**
 * 13.12.9 Runtime Semantics: CaseBlockEvaluation
 *
 * @param node
 *            the switch statement
 * @param type
 *            the switch statement type
 * @param lblExit
 *            the exit label
 * @param switchValue
 *            the variable which holds the switch value
 * @param mv
 *            the code visitor
 * @return the completion value
 */
private Completion CaseBlockEvaluation(SwitchStatement node, SwitchType type, boolean defaultClausePresent, Jump lblExit, Variable<?> switchValue, CodeVisitor mv) {
    List<SwitchClause> clauses = node.getClauses();
    Completion lastResult = Completion.Normal;
    if (clauses.size() > SWITCH_CASE_LIMIT) {
        List<CaseBlock> blocks = computeCaseBlocks(node, list -> {
            // 0 is reserved
            int targetCounter = 1;
            int[] switchTargets = new int[list.size()];
            for (int i = 0; i < list.size(); ++i) {
                if (list.get(i).getStatements().isEmpty()) {
                    switchTargets[i] = targetCounter;
                } else {
                    switchTargets[i] = targetCounter++;
                }
            }
            return new CaseBlock(list, switchTargets, new Jump());
        });
        mv.enterVariableScope();
        Variable<int[]> switchTargetRef = mv.newVariable("switchTarget", int[].class);
        mv.newarray(1, Type.INT_TYPE);
        mv.store(switchTargetRef);
        MutableValue<Integer> switchTarget = mv.iarrayElement(switchTargetRef, 0);
        for (CaseBlock caseBlock : blocks) {
            OutlinedCall call = mv.compile(caseBlock.selectKey(), () -> caseSelect(caseBlock, switchValue.getType(), mv));
            mv.invokeCompletion(call, false, switchValue, switchTargetRef);
            mv.load(switchTarget);
            mv.ifne(caseBlock.entry);
        }
        if (!defaultClausePresent) {
            mv.goTo(lblExit);
        } else {
            for (CaseBlock caseBlock : blocks) {
                int index = indexOf(caseBlock.clauses, SwitchClause::isDefaultClause);
                if (index >= 0) {
                    mv.store(switchTarget, mv.vconst(caseBlock.switchTargets[index]));
                    mv.goTo(caseBlock.entry);
                    break;
                }
            }
        }
        for (CaseBlock caseBlock : blocks) {
            OutlinedCall call = mv.compile(caseBlock.blockKey(), () -> caseBlock(caseBlock, mv));
            // Pessimistically assume we need to save the completion value.
            mv.mark(caseBlock.entry);
            lastResult = mv.invokeCompletion(call, mv.hasCompletion(), switchTarget);
            if (!lastResult.isAbrupt()) {
                // Clear switchTarget on fall-thru.
                mv.store(switchTarget, mv.vconst(0));
            }
        }
        mv.exitVariableScope();
    } else {
        Jump lblDefault = null;
        Jump[] labels = new Jump[clauses.size()];
        for (int i = 0, size = clauses.size(); i < size; ++i) {
            labels[i] = new Jump();
            if (clauses.get(i).isDefaultClause()) {
                assert lblDefault == null;
                lblDefault = labels[i];
            }
        }
        assert defaultClausePresent == (lblDefault != null);
        caseSelector(type).select(clauses, switchValue, labels, defaultClausePresent ? lblDefault : lblExit, mv);
        int index = 0;
        for (SwitchClause switchClause : clauses) {
            Jump caseLabel = labels[index++];
            if (caseLabel.isTarget()) {
                mv.mark(caseLabel);
            } else if (lastResult.isAbrupt()) {
                // Ignore unreachable targets.
                continue;
            }
            lastResult = switchClause.accept(this, mv);
        }
    }
    return lastResult;
}
Also used : OutlinedCall(com.github.anba.es6draft.compiler.CodeVisitor.OutlinedCall) Jump(com.github.anba.es6draft.compiler.assembler.Jump) Completion(com.github.anba.es6draft.compiler.StatementGenerator.Completion) SwitchClause(com.github.anba.es6draft.ast.SwitchClause)

Example 5 with SwitchClause

use of com.github.anba.es6draft.ast.SwitchClause in project es6draft by anba.

the class SwitchStatementGenerator method defaultCaseBlock.

/**
 * Generates a case-block method.
 *
 * @param caseBlock
 *            the case-block
 * @param mv
 *            the code visitor
 * @return the outlined-call object
 */
private OutlinedCall defaultCaseBlock(SwitchStatementGenerator.CaseBlock caseBlock, CodeVisitor mv) {
    SwitchClause firstClause = caseBlock.clauses.get(0);
    MethodTypeDescriptor methodDescriptor = DefaultSwitchBlockCodeVisitor.methodDescriptor(mv);
    MethodCode method = codegen.method(mv, "case", methodDescriptor);
    return outlined(new DefaultSwitchBlockCodeVisitor(firstClause, method, mv), body -> {
        Completion lastResult = Completion.Normal;
        for (SwitchClause clause : caseBlock.clauses) {
            lastResult = clause.accept(this, body);
            if (lastResult.isAbrupt()) {
                break;
            }
        }
        return lastResult;
    });
}
Also used : Completion(com.github.anba.es6draft.compiler.StatementGenerator.Completion) SwitchClause(com.github.anba.es6draft.ast.SwitchClause) MethodCode(com.github.anba.es6draft.compiler.assembler.Code.MethodCode) MethodTypeDescriptor(com.github.anba.es6draft.compiler.assembler.MethodTypeDescriptor)

Aggregations

SwitchClause (com.github.anba.es6draft.ast.SwitchClause)8 Completion (com.github.anba.es6draft.compiler.StatementGenerator.Completion)5 Jump (com.github.anba.es6draft.compiler.assembler.Jump)5 MethodCode (com.github.anba.es6draft.compiler.assembler.Code.MethodCode)3 MethodTypeDescriptor (com.github.anba.es6draft.compiler.assembler.MethodTypeDescriptor)3 OutlinedCall (com.github.anba.es6draft.compiler.CodeVisitor.OutlinedCall)2