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;
}
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;
}
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;
}
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);
}
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);
}
}
Aggregations