Search in sources :

Example 1 with OutlinedCall

use of com.github.anba.es6draft.compiler.CodeVisitor.OutlinedCall 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 2 with OutlinedCall

use of com.github.anba.es6draft.compiler.CodeVisitor.OutlinedCall 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 3 with OutlinedCall

use of com.github.anba.es6draft.compiler.CodeVisitor.OutlinedCall in project es6draft by anba.

the class ClassPropertyGenerator method visit.

@Override
public Void visit(MethodDefinitionsMethod node, CodeVisitor mv) {
    // Sync array indices on recompilation.
    if (mv.isCompiled(node)) {
        if (!staticFields.isEmpty()) {
            staticFields.skip(countStaticFields(node.getProperties()));
        }
        if (!instanceFields.isEmpty()) {
            instanceFields.skip(countInstanceFields(node.getProperties()));
        }
        if (!instanceMethods.isEmpty()) {
            instanceMethods.skip(countInstanceMethods(node.getProperties()));
        }
        if (!decorators.isEmpty()) {
            DecoratedMethods(node.getProperties(), method -> decorators.skip(method.getDecorators().size()));
        }
    }
    OutlinedCall call = mv.compile(node, this::methodDefinitions);
    mv.invoke(call, false, constructor, prototype, staticFields, instanceFields, instanceMethods, decorators);
    return null;
}
Also used : OutlinedCall(com.github.anba.es6draft.compiler.CodeVisitor.OutlinedCall)

Example 4 with OutlinedCall

use of com.github.anba.es6draft.compiler.CodeVisitor.OutlinedCall in project es6draft by anba.

the class DefaultCodeGenerator method outlined.

/**
 * Compiles an outlined method.
 *
 * @param mv
 *            the code visitor
 * @param compiler
 *            the compiler function
 * @return the outlined-call object
 */
protected final <VISITOR extends OutlinedCodeVisitor> OutlinedCall outlined(VISITOR mv, Function<VISITOR, Completion> compiler) {
    mv.lineInfo(mv.getNode());
    // force line-number entry
    mv.nop();
    mv.begin();
    GeneratorState generatorState = null;
    if (mv.hasResume()) {
        generatorState = mv.generatorPrologue();
    }
    mv.labelPrologue();
    Completion result = compiler.apply(mv);
    if (!result.isAbrupt()) {
        // fall-thru, return `0`.
        mv.iconst(0);
        mv._return();
    }
    LabelState labelState = mv.labelEpilogue(result, mv.hasResume());
    if (generatorState != null) {
        mv.generatorEpilogue(generatorState);
    }
    mv.end();
    return new OutlinedCall(mv.getMethod().name(), labelState);
}
Also used : OutlinedCall(com.github.anba.es6draft.compiler.CodeVisitor.OutlinedCall) Completion(com.github.anba.es6draft.compiler.StatementGenerator.Completion) LabelState(com.github.anba.es6draft.compiler.CodeVisitor.LabelState) GeneratorState(com.github.anba.es6draft.compiler.CodeVisitor.GeneratorState)

Example 5 with OutlinedCall

use of com.github.anba.es6draft.compiler.CodeVisitor.OutlinedCall in project es6draft by anba.

the class ExpressionGenerator method spreadArray.

/**
 * 12.2.4.1.3 Runtime Semantics: Evaluation<br>
 * 12.2.4.1.2 Runtime Semantics: Array Accumulation
 *
 * @param elements
 *            the array elements
 * @param array
 *            the array object
 * @param nextIndex
 *            the next array index
 * @param mv
 *            the code visitor
 */
private void spreadArray(List<Expression> elements, Variable<ArrayObject> array, Variable<Integer> nextIndex, CodeVisitor mv) {
    int elisionWidth = 0;
    for (Expression element : elements) {
        if (element instanceof Elision) {
            // Elision
            elisionWidth += 1;
            continue;
        }
        if (elisionWidth != 0) {
            iadd(nextIndex, elisionWidth, mv);
            elisionWidth = 0;
        }
        if (element instanceof SpreadElementMethod) {
            SpreadElementMethod spread = (SpreadElementMethod) element;
            OutlinedCall call = mv.compile(spread, this::spreadElement);
            mv.enterVariableScope();
            Variable<int[]> nextIndexRef = mv.newVariable("nextIndexRef", int[].class);
            mv.newarray(1, Type.INT_TYPE);
            mv.store(nextIndexRef);
            mv.invoke(call, false, array, nextIndex, nextIndexRef);
            mv.store(nextIndex, mv.iarrayElement(nextIndexRef, 0));
            mv.exitVariableScope();
        } else if (element instanceof SpreadElement) {
            SpreadElement spread = (SpreadElement) element;
            // stack: [] -> []
            mv.load(array);
            mv.load(nextIndex);
            ArrayAccumulationSpreadElement(spread, mv);
            mv.store(nextIndex);
        } else {
            // stack: [] -> [array, nextIndex, value]
            mv.load(array);
            mv.load(nextIndex);
            ArrayAccumulationElement(element, mv);
            elisionWidth += 1;
        }
    }
    if (elisionWidth != 0) {
        iadd(nextIndex, elisionWidth, mv);
    }
}
Also used : OutlinedCall(com.github.anba.es6draft.compiler.CodeVisitor.OutlinedCall) SpreadElementMethod(com.github.anba.es6draft.ast.synthetic.SpreadElementMethod)

Aggregations

OutlinedCall (com.github.anba.es6draft.compiler.CodeVisitor.OutlinedCall)8 Completion (com.github.anba.es6draft.compiler.StatementGenerator.Completion)3 SwitchClause (com.github.anba.es6draft.ast.SwitchClause)2 SpreadElementMethod (com.github.anba.es6draft.ast.synthetic.SpreadElementMethod)1 GeneratorState (com.github.anba.es6draft.compiler.CodeVisitor.GeneratorState)1 LabelState (com.github.anba.es6draft.compiler.CodeVisitor.LabelState)1 Jump (com.github.anba.es6draft.compiler.assembler.Jump)1 OrdinaryObject (com.github.anba.es6draft.runtime.types.builtins.OrdinaryObject)1