use of com.github.anba.es6draft.compiler.assembler.Jump in project es6draft by anba.
the class AbstractIterationGenerator method generate.
/**
* Emit code for the wrapped iteration.
*
* @param node
* the ast node
* @param iterator
* the iterator variable
* @param target
* the target label
* @param mv
* the code visitor
* @return the completion value
*/
public final Completion generate(NODE node, Variable<ITERATOR> iterator, Jump target, CodeVisitor mv) {
TryCatchLabel startIteration = new TryCatchLabel(), endIteration = new TryCatchLabel();
TryCatchLabel handlerCatch = new TryCatchLabel();
TryCatchLabel handlerCatchStackOverflow = null;
if (codegen.isEnabled(Compiler.Option.IterationCatchStackOverflow)) {
handlerCatchStackOverflow = new TryCatchLabel();
}
boolean hasTarget = target != null;
if (!hasTarget) {
target = new Jump();
}
mv.enterVariableScope();
MutableValue<Object> completion = enterIteration(node, mv);
// Emit loop body
mv.mark(startIteration);
Completion loopBodyResult = iterationBody(node, iterator, mv);
if (!loopBodyResult.isAbrupt()) {
mv.goTo(target);
}
mv.mark(endIteration);
// Restore temporary abrupt targets
List<TempLabel> tempLabels = exitIteration(node, mv);
// Emit throw handler
Completion throwResult = emitThrowHandler(node, iterator, handlerCatch, handlerCatchStackOverflow, mv);
// Emit return handler
Completion returnResult = emitReturnHandler(node, iterator, completion, tempLabels, mv);
mv.exitVariableScope();
mv.tryCatch(startIteration, endIteration, handlerCatch, Types.ScriptException);
if (handlerCatchStackOverflow != null) {
mv.tryCatch(startIteration, endIteration, handlerCatchStackOverflow, Types.Error);
}
if (!hasTarget) {
mv.mark(target);
epilogue(node, iterator, mv);
}
if (tempLabels.isEmpty()) {
// No Return handler installed
return throwResult.select(loopBodyResult);
}
return returnResult.select(throwResult.select(loopBodyResult));
}
use of com.github.anba.es6draft.compiler.assembler.Jump in project es6draft by anba.
the class ExpressionGenerator method PerformEval.
/**
* [18.2.1.1] Direct Call to Eval
*
* @param call
* the function call expression
* @param arguments
* the list of function call arguments
* @param hasThisValue
* {@code true} if the thisValue is on the stack
* @param afterCall
* the label after the call instruction
* @param mv
* the code visitor
*/
private void PerformEval(Expression call, List<Expression> arguments, boolean hasThisValue, Jump afterCall, CodeVisitor mv) {
int evalFlags = EvalFlags.Direct.getValue();
if (mv.isStrict()) {
evalFlags |= EvalFlags.Strict.getValue();
}
if (mv.isGlobalCode()) {
evalFlags |= EvalFlags.GlobalCode.getValue();
}
if (isGlobalScope(mv.getScope())) {
evalFlags |= EvalFlags.GlobalScope.getValue();
}
if (isGlobalThis(mv.getScope())) {
evalFlags |= EvalFlags.GlobalThis.getValue();
}
if (isEnclosedByWithStatement(mv.getScope())) {
evalFlags |= EvalFlags.EnclosedByWithStatement.getValue();
}
if (!mv.isStrict() && isEnclosedByLexicalDeclaration(mv.getScope())) {
evalFlags |= EvalFlags.EnclosedByLexicalDeclaration.getValue();
}
// stack: [thisValue?, args?, func(Callable)] -> [thisValue?, args?]
mv.pop();
// stack: [thisValue?, args?] -> [args?]
boolean constantArguments = hasConstantArguments(arguments);
if (hasThisValue) {
if (constantArguments) {
// stack: [thisValue] -> []
mv.pop();
} else {
// stack: [thisValue, args] -> [args]
mv.swap();
mv.pop();
}
}
if (codegen.isEnabled(CompatibilityOption.Realm)) {
if (constantArguments) {
// stack: [] -> [args]
ArgumentListEvaluation(call, arguments, mv);
}
// stack: [args] -> [result]
mv.loadExecutionContext();
mv.iconst(evalFlags);
mv.invoke(Methods.Eval_directEvalWithTranslate);
mv.goTo(afterCall);
} else {
if (arguments.isEmpty()) {
assert constantArguments : "empty arguments list is constant";
// stack: [] -> [result]
mv.loadUndefined();
mv.goTo(afterCall);
} else if (hasArguments(arguments)) {
if (constantArguments) {
// stack: [] -> [arg_0]
ValType type = arguments.get(0).accept(this, mv);
mv.toBoxed(type);
} else {
// stack: [args] -> [arg_0]
mv.iconst(0);
mv.aaload();
}
mv.loadExecutionContext();
mv.iconst(evalFlags);
mv.invoke(Methods.Eval_directEval);
mv.goTo(afterCall);
} else {
assert !constantArguments : "spread arguments list is not constant";
Jump emptyArguments = new Jump();
mv.dup();
mv.arraylength();
mv.ifeq(emptyArguments);
{
mv.iconst(0);
mv.aaload();
mv.loadExecutionContext();
mv.iconst(evalFlags);
mv.invoke(Methods.Eval_directEval);
mv.goTo(afterCall);
}
mv.mark(emptyArguments);
mv.pop();
mv.loadUndefined();
mv.goTo(afterCall);
}
}
}
use of com.github.anba.es6draft.compiler.assembler.Jump in project es6draft by anba.
the class ExpressionGenerator method visit.
/**
* 12.13 Conditional Operator ( ? : )
* <p>
* 12.13.3 Runtime Semantics: Evaluation
*/
@Override
public ValType visit(ConditionalExpression node, CodeVisitor mv) {
Jump l0 = new Jump(), l1 = new Jump();
/* steps 1-2 */
ValType typeTest = node.getTest().accept(this, mv);
/* step 2 */
ToBoolean(typeTest, mv);
/* step 3 */
mv.ifeq(l0);
ValType typeThen = node.getThen().accept(this, mv);
if (typeThen.isJavaPrimitive()) {
// Try to avoid boxing if then-and-otherwise are both compatible primitive types.
ValType expected = expressionType(node.getOtherwise());
boolean sameType = typeThen == expected;
if (sameType || (typeThen.isNumeric() && expected.isNumeric())) {
if (!sameType) {
ToNumber(typeThen, mv);
}
mv.goTo(l1);
mv.mark(l0);
ValType typeOtherwise = node.getOtherwise().accept(this, mv);
assert expected == typeOtherwise : String.format("expected=%s, got=%s", expected, typeOtherwise);
if (!sameType) {
ToNumber(typeOtherwise, mv);
}
mv.mark(l1);
return sameType ? typeThen : ValType.Number;
}
}
mv.toBoxed(typeThen);
mv.goTo(l1);
/* step 4 */
mv.mark(l0);
ValType typeOtherwise = node.getOtherwise().accept(this, mv);
mv.toBoxed(typeOtherwise);
mv.mark(l1);
return typeThen == typeOtherwise ? typeThen : ValType.Any;
}
use of com.github.anba.es6draft.compiler.assembler.Jump in project es6draft by anba.
the class StatementGenerator method visit.
/**
* 14.1.20 Runtime Semantics: Evaluation
*/
@Override
public Completion visit(FunctionDeclaration node, CodeVisitor mv) {
/* B.3.3 Block-Level Function Declarations Web Legacy Compatibility Semantics */
if (node.isLegacyBlockScoped()) {
Name name = node.getIdentifier().getName();
TopLevelScope top = mv.getScope().getTop();
if (mv.isFunction()) {
assert top instanceof FunctionScope;
Name varName = ((FunctionScope) top).variableScope().resolveName(name, false);
assert varName != null && name != varName;
/* step 1.a.ii.3.1 */
Value<DeclarativeEnvironmentRecord> fenv = getVariableEnvironmentRecord(Types.DeclarativeEnvironmentRecord, mv);
/* steps 1.a.ii.3.5-6 */
BindingOp.of(fenv, varName).setMutableBinding(fenv, varName, asm -> {
Value<DeclarativeEnvironmentRecord> benv = getLexicalEnvironmentRecord(Types.DeclarativeEnvironmentRecord, mv);
BindingOp.of(benv, name).getBindingValue(benv, name, false, mv);
}, false, mv);
} else {
assert top instanceof ScriptScope;
Name varName = name;
int functionId = node.getLegacyBlockScopeId();
Jump isLegacyScoped = null;
if (functionId > 0) {
isLegacyScoped = new Jump();
mv.loadExecutionContext();
mv.iconst(functionId);
mv.invoke(Methods.ScriptRuntime_isLegacyBlockFunction);
mv.ifeq(isLegacyScoped);
}
// The variable environment record is either:
// 1. The global environment record for global (eval) scripts.
// 2. Or a (function) declarative environment record for eval in functions.
// 3. Or a script-context environment record for eval in JSR-223 scripting.
Value<EnvironmentRecord> genv = getVariableEnvironmentRecord(Types.EnvironmentRecord, mv);
BindingOp.of(genv, varName).setMutableBinding(genv, varName, asm -> {
Value<DeclarativeEnvironmentRecord> benv = getLexicalEnvironmentRecord(Types.DeclarativeEnvironmentRecord, mv);
BindingOp.of(benv, name).getBindingValue(benv, name, false, mv);
}, false, mv);
if (isLegacyScoped != null) {
mv.mark(isLegacyScoped);
}
}
}
/* step 1 */
return Completion.Empty;
}
use of com.github.anba.es6draft.compiler.assembler.Jump in project es6draft by anba.
the class StatementGenerator method AsyncForInOfBodyEvaluation.
/**
* 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation (lhs, stmt, iterator, lhsKind, labelSet)
* <p>
* stack: [Iterator] {@literal ->} []
*
* @param <FORSTATEMENT>
* the for-statement node type
* @param node
* the for-statement node
* @param mv
* the code visitor
* @return the completion value
*/
private <FORSTATEMENT extends IterationStatement & ForIterationNode> Completion AsyncForInOfBodyEvaluation(FORSTATEMENT node, CodeVisitor mv) {
assert mv.getStackSize() == 1;
ContinueLabel lblContinue = new ContinueLabel();
BreakLabel lblBreak = new BreakLabel();
Jump enter = new Jump(), test = new Jump();
mv.enterVariableScope();
Variable<ScriptObject> iterator = mv.newVariable("iter", ScriptObject.class);
// stack: [Iterator] -> []
mv.store(iterator);
Variable<ScriptObject> nextResult = mv.newVariable("nextResult", ScriptObject.class);
mv.anull();
mv.store(nextResult);
Variable<Object> nextValue = mv.newVariable("nextValue", Object.class);
mv.anull();
mv.store(nextValue);
Variable<LexicalEnvironment<?>> savedEnv = saveEnvironment(node, mv);
/* step 2 */
if (node.hasCompletionValue()) {
mv.storeUndefinedAsCompletionValue();
}
/* steps 3-4 (not applicable) */
/* step 5 (repeat loop) */
mv.nonDestructiveGoTo(test);
/* steps 5.d-e */
mv.mark(enter);
IteratorValue(node, nextResult, mv);
await(node, mv);
mv.store(nextValue);
/* steps 5.f-l */
{
mv.enterIteration(node, lblBreak, lblContinue);
mv.enterWrapped();
new AbstractIterationGenerator<FORSTATEMENT, ScriptObject>(codegen) {
@Override
protected Completion iterationBody(FORSTATEMENT node, Variable<ScriptObject> iterator, CodeVisitor mv) {
return ForInOfBodyEvaluationInner(node, nextValue, mv);
}
@Override
protected MutableValue<Object> enterIteration(FORSTATEMENT node, CodeVisitor mv) {
return mv.enterIterationBody(node);
}
@Override
protected List<TempLabel> exitIteration(FORSTATEMENT node, CodeVisitor mv) {
return mv.exitIterationBody(node);
}
@Override
protected void IteratorClose(FORSTATEMENT node, Variable<ScriptObject> iterator, Variable<? extends Throwable> throwable, CodeVisitor mv) {
asyncIteratorClose(node, iterator, throwable, mv);
}
@Override
protected void IteratorClose(FORSTATEMENT node, Variable<ScriptObject> iterator, CodeVisitor mv) {
asyncIteratorClose(node, iterator, mv);
}
}.generate(node, iterator, test, mv);
mv.exitWrapped();
mv.exitIteration(node);
}
/* steps 5.m-n */
if (lblContinue.isTarget()) {
mv.mark(lblContinue);
restoreEnvironment(savedEnv, mv);
}
/* steps 5.a-c */
mv.mark(test);
IteratorNext(node, iterator, mv);
await(node, mv);
// FIXME: spec bug - missing type check after await
requireObjectResult(node, "next", mv);
mv.store(nextResult);
IteratorComplete(node, nextResult, mv);
mv.ifeq(enter);
/* steps 5.m-n */
if (lblBreak.isTarget()) {
mv.mark(lblBreak);
restoreEnvironment(savedEnv, mv);
}
mv.exitVariableScope();
return Completion.Normal;
}
Aggregations