[torque] Allow atomarStatements in otherwise statements

In the process:
- Convert TryLabelStatements into TryLabelExpressions
- Change TryLabelExpressions to support only single label blocks and de-sugar
  try/labels into nested try/label statements. This allows the code in a label
  block to goto subsequent labels in the same try/label statement.
- Make otherwise expressions either take IdentifierExpressions which get
  converted into simple label names OR atomarStatements, which make useful
  non-label operations, like 'break' and 'continue', useful together with
  otherwise. Non-label otherwise statements get de-sugared into try/label
  blocks.

Bug: v8:7793
Change-Id: Ie56ede6306e2a3182f6aa1bb8750ed418bda01db
Reviewed-on: https://chromium-review.googlesource.com/c/1266997
Commit-Queue: Daniel Clifford <danno@chromium.org>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56447}
This commit is contained in:
Daniel Clifford 2018-10-08 15:50:46 +02:00 committed by Commit Bot
parent 3efbaf8eb1
commit 6f5600e256
9 changed files with 230 additions and 114 deletions

View File

@ -968,21 +968,19 @@ macro ToIndex(input: Object, context: Context): Number
} }
macro GetLengthProperty(context: Context, o: Object): Number { macro GetLengthProperty(context: Context, o: Object): Number {
let length: Object;
try { try {
try { return (Cast<JSArray>(o) otherwise CheckArgs).length;
return (Cast<JSArray>(o) otherwise CheckArgs).length; }
} label CheckArgs {
label CheckArgs { const a: JSArgumentsObjectWithLength =
const a: JSArgumentsObjectWithLength = Cast<JSArgumentsObjectWithLength>(context, o) otherwise Slow;
Cast<JSArgumentsObjectWithLength>(context, o) otherwise Slow; const length: Object = a.length;
return Cast<Smi>(length = a.length) otherwise ToLength; return Cast<Smi>(length) otherwise goto ToLength(length);
}
} }
label Slow deferred { label Slow deferred {
return ToLength_Inline(context, GetProperty(context, o, kLengthString)); goto ToLength(GetProperty(context, o, kLengthString));
} }
label ToLength deferred { label ToLength(length: Object) deferred {
return ToLength_Inline(context, length); return ToLength_Inline(context, length);
} }
} }

View File

@ -30,7 +30,9 @@ namespace torque {
V(ElementAccessExpression) \ V(ElementAccessExpression) \
V(AssignmentExpression) \ V(AssignmentExpression) \
V(IncrementDecrementExpression) \ V(IncrementDecrementExpression) \
V(AssumeTypeImpossibleExpression) V(AssumeTypeImpossibleExpression) \
V(StatementExpression) \
V(TryLabelExpression)
#define AST_TYPE_EXPRESSION_NODE_KIND_LIST(V) \ #define AST_TYPE_EXPRESSION_NODE_KIND_LIST(V) \
V(BasicTypeExpression) \ V(BasicTypeExpression) \
@ -52,7 +54,6 @@ namespace torque {
V(TailCallStatement) \ V(TailCallStatement) \
V(VarDeclarationStatement) \ V(VarDeclarationStatement) \
V(GotoStatement) \ V(GotoStatement) \
V(TryLabelStatement)
#define AST_DECLARATION_NODE_KIND_LIST(V) \ #define AST_DECLARATION_NODE_KIND_LIST(V) \
V(TypeDeclaration) \ V(TypeDeclaration) \
@ -553,15 +554,22 @@ struct LabelBlock : AstNode {
Statement* body; Statement* body;
}; };
struct TryLabelStatement : Statement { struct StatementExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(TryLabelStatement) DEFINE_AST_NODE_LEAF_BOILERPLATE(StatementExpression)
TryLabelStatement(SourcePosition pos, Statement* try_block, StatementExpression(SourcePosition pos, Statement* statement)
std::vector<LabelBlock*> label_blocks) : Expression(kKind, pos), statement(statement) {}
: Statement(kKind, pos), Statement* statement;
try_block(try_block), };
label_blocks(std::move(label_blocks)) {}
Statement* try_block; struct TryLabelExpression : Expression {
std::vector<LabelBlock*> label_blocks; DEFINE_AST_NODE_LEAF_BOILERPLATE(TryLabelExpression)
TryLabelExpression(SourcePosition pos, Expression* try_expression,
LabelBlock* label_block)
: Expression(kKind, pos),
try_expression(try_expression),
label_block(label_block) {}
Expression* try_expression;
LabelBlock* label_block;
}; };
struct BlockStatement : Statement { struct BlockStatement : Statement {

View File

@ -402,14 +402,15 @@ void DeclarationVisitor::Visit(ForLoopStatement* stmt) {
if (stmt->action) Visit(*stmt->action); if (stmt->action) Visit(*stmt->action);
} }
void DeclarationVisitor::Visit(TryLabelStatement* stmt) { void DeclarationVisitor::Visit(TryLabelExpression* stmt) {
// Activate a new scope to declare handler labels, they should not be // Activate a new scope to declare the handler's label parameters, they should
// visible outside the label block. // not be visible outside the label block.
{ {
Declarations::NodeScopeActivator scope(declarations(), stmt); Declarations::NodeScopeActivator scope(declarations(), stmt);
// Declare labels // Declare label
for (LabelBlock* block : stmt->label_blocks) { {
LabelBlock* block = stmt->label_block;
CurrentSourcePosition::Scope scope(block->pos); CurrentSourcePosition::Scope scope(block->pos);
Label* shared_label = Label* shared_label =
declarations()->DeclareLabel(block->label, block->body); declarations()->DeclareLabel(block->label, block->body);
@ -432,18 +433,16 @@ void DeclarationVisitor::Visit(TryLabelStatement* stmt) {
shared_label->AddVariable(DeclareVariable(p, type, false)); shared_label->AddVariable(DeclareVariable(p, type, false));
++i; ++i;
} }
} if (global_context_.verbose()) {
if (global_context_.verbose()) { std::cout << " declaring label " << block->label << "\n";
std::cout << " declaring label " << block->label << "\n"; }
} }
} }
Visit(stmt->try_block); Visit(stmt->try_expression);
} }
for (LabelBlock* block : stmt->label_blocks) { Visit(stmt->label_block->body);
Visit(block->body);
}
} }
void DeclarationVisitor::GenerateHeader(std::string& file_name) { void DeclarationVisitor::GenerateHeader(std::string& file_name) {
@ -516,6 +515,10 @@ void DeclarationVisitor::Visit(IdentifierExpression* expr) {
} }
} }
void DeclarationVisitor::Visit(StatementExpression* expr) {
Visit(expr->statement);
}
void DeclarationVisitor::Visit(CallExpression* expr) { void DeclarationVisitor::Visit(CallExpression* expr) {
Visit(&expr->callee); Visit(&expr->callee);
for (Expression* arg : expr->arguments) Visit(arg); for (Expression* arg : expr->arguments) Visit(arg);

View File

@ -139,7 +139,8 @@ class DeclarationVisitor : public FileVisitor {
void Visit(AssumeTypeImpossibleExpression* expr) { Visit(expr->expression); } void Visit(AssumeTypeImpossibleExpression* expr) { Visit(expr->expression); }
void Visit(TryLabelStatement* stmt); void Visit(TryLabelExpression* stmt);
void Visit(StatementExpression* stmt);
void GenerateHeader(std::string& file_name); void GenerateHeader(std::string& file_name);
private: private:

View File

@ -80,6 +80,7 @@ void ImplementationVisitor::BeginModuleFile(Module* module) {
DashifyString(module->name()) + "-gen.h\""; DashifyString(module->name()) + "-gen.h\"";
} }
source << "\n"; source << "\n";
source << "#include \"src/objects/arguments.h\"\n";
source << "#include \"src/builtins/builtins-utils-gen.h\"\n"; source << "#include \"src/builtins/builtins-utils-gen.h\"\n";
source << "#include \"src/builtins/builtins.h\"\n"; source << "#include \"src/builtins/builtins.h\"\n";
source << "#include \"src/code-factory.h\"\n"; source << "#include \"src/code-factory.h\"\n";
@ -1081,19 +1082,19 @@ const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
return TypeOracle::GetVoidType(); return TypeOracle::GetVoidType();
} }
const Type* ImplementationVisitor::Visit(TryLabelStatement* stmt) { VisitResult ImplementationVisitor::Visit(TryLabelExpression* expr) {
Block* done_block = assembler().NewBlock(); Block* done_block = assembler().NewBlock();
const Type* try_result = TypeOracle::GetNeverType(); VisitResult try_result;
std::vector<Label*> labels; Label* label = nullptr;
// Output labels for the goto handlers and for the merge after the try. // Output labels for the goto handlers and for the merge after the try.
{ {
// Activate a new scope to see handler labels // Activate a new scope to see handler labels
Declarations::NodeScopeActivator scope(declarations(), stmt); Declarations::NodeScopeActivator scope(declarations(), expr);
for (LabelBlock* block : stmt->label_blocks) { {
LabelBlock* block = expr->label_block;
CurrentSourcePosition::Scope source_position(block->pos); CurrentSourcePosition::Scope source_position(block->pos);
Label* label = declarations()->LookupLabel(block->label); label = declarations()->LookupLabel(block->label);
labels.push_back(label);
Declarations::NodeScopeActivator scope(declarations(), block->body); Declarations::NodeScopeActivator scope(declarations(), block->body);
Stack<const Type*> label_input_stack = assembler().CurrentStack(); Stack<const Type*> label_input_stack = assembler().CurrentStack();
@ -1108,42 +1109,48 @@ const Type* ImplementationVisitor::Visit(TryLabelStatement* stmt) {
// Visit try // Visit try
{ {
StackScope stack_scope(this); StackScope stack_scope(this);
try_result = Visit(stmt->try_block); try_result = Visit(expr->try_expression);
if (try_result.type() != TypeOracle::GetNeverType()) {
try_result = stack_scope.Yield(try_result);
assembler().Goto(done_block);
}
} }
if (try_result != TypeOracle::GetNeverType()) { }
if (label->IsUsed()) {
// Visit and output the code for the label block. If the label block falls
// through, then the try must not return a value. Also, if the try doesn't
// fall through, but the label does, then overall the try-label block
// returns type void.
GenerateLabelBind(label);
const Type* label_result;
{
StackScope stack_scope(this);
label_result = Visit(expr->label_block->body);
}
if (!try_result.type()->IsVoidOrNever() && label_result->IsVoid()) {
ReportError(
"otherwise clauses cannot fall through in a non-void expression");
}
if (label_result != TypeOracle::GetNeverType()) {
assembler().Goto(done_block); assembler().Goto(done_block);
} }
} if (label_result->IsVoid() && try_result.type()->IsNever()) {
try_result =
// Make sure that each label clause is actually used. It's not just a friendly VisitResult(TypeOracle::GetVoidType(), try_result.stack_range());
// thing to do, it will cause problems downstream in the compiler if there are
// bound labels that are never jumped to.
auto label_iterator = stmt->label_blocks.begin();
for (auto label : labels) {
CurrentSourcePosition::Scope scope((*label_iterator)->pos);
if (!label->IsUsed()) {
std::stringstream s;
s << "label ";
s << (*label_iterator)->label;
s << " has a handler block but is never referred to in try block";
ReportError(s.str());
} }
label_iterator++;
} }
// Visit and output the code for each label block, one-by-one. if (!try_result.type()->IsNever()) {
std::vector<Statement*> bodies;
for (LabelBlock* block : stmt->label_blocks) bodies.push_back(block->body);
if (GenerateLabeledStatementBlocks(bodies, labels, done_block)) {
try_result = TypeOracle::GetVoidType();
}
if (!try_result->IsNever()) {
assembler().Bind(done_block); assembler().Bind(done_block);
} }
return try_result; return try_result;
} }
VisitResult ImplementationVisitor::Visit(StatementExpression* expr) {
return VisitResult{Visit(expr->statement), assembler().TopRange(0)};
}
const Type* ImplementationVisitor::Visit(BreakStatement* stmt) { const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
Block* break_block = global_context_.GetCurrentBreak(); Block* break_block = global_context_.GetCurrentBreak();
if (break_block == nullptr) { if (break_block == nullptr) {

View File

@ -177,8 +177,9 @@ class ImplementationVisitor : public FileVisitor {
VisitResult Visit(StringLiteralExpression* expr); VisitResult Visit(StringLiteralExpression* expr);
VisitResult Visit(NumberLiteralExpression* expr); VisitResult Visit(NumberLiteralExpression* expr);
VisitResult Visit(AssumeTypeImpossibleExpression* expr); VisitResult Visit(AssumeTypeImpossibleExpression* expr);
VisitResult Visit(TryLabelExpression* expr);
VisitResult Visit(StatementExpression* expr);
const Type* Visit(TryLabelStatement* stmt);
const Type* Visit(ReturnStatement* stmt); const Type* Visit(ReturnStatement* stmt);
const Type* Visit(GotoStatement* stmt); const Type* Visit(GotoStatement* stmt);
const Type* Visit(IfStatement* stmt); const Type* Visit(IfStatement* stmt);

View File

@ -201,14 +201,50 @@ void CheckNotDeferredStatement(Statement* statement) {
} }
} }
Expression* MakeCall(const std::string& callee, bool is_operator,
const std::vector<TypeExpression*>& generic_arguments,
const std::vector<Expression*>& arguments,
const std::vector<Statement*>& otherwise) {
std::vector<std::string> labels;
// All IdentifierExpressions are treated as label names and can be directly
// used as labels identifiers. All other statements in a call's otherwise
// must create intermediate Labels for the otherwise's statement code.
size_t label_id = 0;
std::vector<LabelBlock*> temp_labels;
for (auto* statement : otherwise) {
if (auto* e = ExpressionStatement::DynamicCast(statement)) {
if (auto* id = IdentifierExpression::DynamicCast(e->expression)) {
if (id->generic_arguments.size() != 0) {
ReportError("An otherwise label cannot have generic parameters");
}
labels.push_back(id->name);
continue;
}
}
auto label_name = std::string("_label") + std::to_string(label_id++);
labels.push_back(label_name);
auto* label_block =
MakeNode<LabelBlock>(label_name, ParameterList::Empty(), statement);
temp_labels.push_back(label_block);
}
// Create nested try-label expression for all of the temporary Labels that
// were created.
Expression* result = MakeNode<CallExpression>(
callee, false, generic_arguments, arguments, labels);
for (auto* label : temp_labels) {
result = MakeNode<TryLabelExpression>(result, label);
}
return result;
}
base::Optional<ParseResult> MakeCall(ParseResultIterator* child_results) { base::Optional<ParseResult> MakeCall(ParseResultIterator* child_results) {
auto callee = child_results->NextAs<std::string>(); auto callee = child_results->NextAs<std::string>();
auto generic_args = child_results->NextAs<TypeList>(); auto generic_args = child_results->NextAs<TypeList>();
auto args = child_results->NextAs<std::vector<Expression*>>(); auto args = child_results->NextAs<std::vector<Expression*>>();
auto labels = child_results->NextAs<std::vector<std::string>>(); auto otherwise = child_results->NextAs<std::vector<Statement*>>();
Expression* result = return ParseResult{MakeCall(callee, false, generic_args, args, otherwise)};
MakeNode<CallExpression>(callee, false, generic_args, args, labels);
return ParseResult{result};
} }
base::Optional<ParseResult> MakeBinaryOperator( base::Optional<ParseResult> MakeBinaryOperator(
@ -216,20 +252,17 @@ base::Optional<ParseResult> MakeBinaryOperator(
auto left = child_results->NextAs<Expression*>(); auto left = child_results->NextAs<Expression*>();
auto op = child_results->NextAs<std::string>(); auto op = child_results->NextAs<std::string>();
auto right = child_results->NextAs<Expression*>(); auto right = child_results->NextAs<Expression*>();
Expression* result = MakeNode<CallExpression>( return ParseResult{MakeCall(op, true, TypeList{},
op, true, TypeList{}, std::vector<Expression*>{left, right}, std::vector<Expression*>{left, right},
std::vector<std::string>{}); std::vector<Statement*>{})};
return ParseResult{result};
} }
base::Optional<ParseResult> MakeUnaryOperator( base::Optional<ParseResult> MakeUnaryOperator(
ParseResultIterator* child_results) { ParseResultIterator* child_results) {
auto op = child_results->NextAs<std::string>(); auto op = child_results->NextAs<std::string>();
auto e = child_results->NextAs<Expression*>(); auto e = child_results->NextAs<Expression*>();
Expression* result = MakeNode<CallExpression>(op, true, TypeList{}, return ParseResult{MakeCall(op, true, TypeList{}, std::vector<Expression*>{e},
std::vector<Expression*>{e}, std::vector<Statement*>{})};
std::vector<std::string>{});
return ParseResult{result};
} }
template <bool has_varargs> template <bool has_varargs>
@ -584,10 +617,11 @@ base::Optional<ParseResult> MakeTypeswitchStatement(
} }
BlockStatement* case_block; BlockStatement* case_block;
if (i < cases.size() - 1) { if (i < cases.size() - 1) {
value = MakeNode<CallExpression>( value =
"Cast", false, std::vector<TypeExpression*>{cases[i].type}, MakeCall("Cast", false, std::vector<TypeExpression*>{cases[i].type},
std::vector<Expression*>{value}, std::vector<Expression*>{value},
std::vector<std::string>{"_NextCase"}); std::vector<Statement*>{MakeNode<ExpressionStatement>(
MakeNode<IdentifierExpression>("_NextCase"))});
case_block = MakeNode<BlockStatement>(); case_block = MakeNode<BlockStatement>();
} else { } else {
case_block = current_block; case_block = current_block;
@ -599,9 +633,11 @@ base::Optional<ParseResult> MakeTypeswitchStatement(
case_block->statements.push_back(cases[i].block); case_block->statements.push_back(cases[i].block);
if (i < cases.size() - 1) { if (i < cases.size() - 1) {
BlockStatement* next_block = MakeNode<BlockStatement>(); BlockStatement* next_block = MakeNode<BlockStatement>();
current_block->statements.push_back(MakeNode<TryLabelStatement>( current_block->statements.push_back(
case_block, std::vector<LabelBlock*>{MakeNode<LabelBlock>( MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>(
"_NextCase", ParameterList::Empty(), next_block)})); MakeNode<StatementExpression>(case_block),
MakeNode<LabelBlock>("_NextCase", ParameterList::Empty(),
next_block))));
current_block = next_block; current_block = next_block;
} }
accumulated_types = accumulated_types =
@ -692,13 +728,16 @@ base::Optional<ParseResult> MakeBlockStatement(
return ParseResult{result}; return ParseResult{result};
} }
base::Optional<ParseResult> MakeTryLabelStatement( base::Optional<ParseResult> MakeTryLabelExpression(
ParseResultIterator* child_results) { ParseResultIterator* child_results) {
auto try_block = child_results->NextAs<Statement*>(); auto try_block = child_results->NextAs<Statement*>();
CheckNotDeferredStatement(try_block); CheckNotDeferredStatement(try_block);
Statement* result = try_block;
auto label_blocks = child_results->NextAs<std::vector<LabelBlock*>>(); auto label_blocks = child_results->NextAs<std::vector<LabelBlock*>>();
Statement* result = for (auto block : label_blocks) {
MakeNode<TryLabelStatement>(try_block, std::move(label_blocks)); result = MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>(
MakeNode<StatementExpression>(result), block));
}
return ParseResult{result}; return ParseResult{result};
} }
@ -1028,10 +1067,10 @@ struct TorqueGrammar : Grammar {
Sequence({Token("labels"), Sequence({Token("labels"),
NonemptyList<LabelAndTypes>(&labelParameter, Token(","))}))}; NonemptyList<LabelAndTypes>(&labelParameter, Token(","))}))};
// Result: std::vector<std::string> // Result: std::vector<Statement*>
Symbol* optionalOtherwise{TryOrDefault<std::vector<std::string>>( Symbol* optionalOtherwise{TryOrDefault<std::vector<Statement*>>(
Sequence({Token("otherwise"), Sequence({Token("otherwise"),
NonemptyList<std::string>(&identifier, Token(","))}))}; NonemptyList<Statement*>(&atomarStatement, Token(","))}))};
// Result: NameAndTypeExpression // Result: NameAndTypeExpression
Symbol nameAndType = { Symbol nameAndType = {
@ -1212,28 +1251,27 @@ struct TorqueGrammar : Grammar {
expression}, expression},
MakeVarDeclarationStatement)}; MakeVarDeclarationStatement)};
// Disallow ambiguous dangling else by only allowing an {atomarStatement} as // Result: Statement*
// a then-clause. Result: Statement*
Symbol atomarStatement = { Symbol atomarStatement = {
Rule({&block}), Rule({expression}, MakeExpressionStatement),
Rule({expression, Token(";")}, MakeExpressionStatement), Rule({Token("return"), Optional<Expression*>(expression)},
Rule({Token("return"), Optional<Expression*>(expression), Token(";")},
MakeReturnStatement), MakeReturnStatement),
Rule({Token("tail"), &callExpression, Token(";")}, MakeTailCallStatement), Rule({Token("tail"), &callExpression}, MakeTailCallStatement),
Rule({Token("break"), Token(";")}, MakeBreakStatement), Rule({Token("break")}, MakeBreakStatement),
Rule({Token("continue"), Token(";")}, MakeContinueStatement), Rule({Token("continue")}, MakeContinueStatement),
Rule({Token("goto"), &identifier, Rule({Token("goto"), &identifier,
TryOrDefault<std::vector<Expression*>>(&argumentList), Token(";")}, TryOrDefault<std::vector<Expression*>>(&argumentList)},
MakeGotoStatement), MakeGotoStatement),
Rule({OneOf({"debug", "unreachable"}), Token(";")}, MakeDebugStatement)}; Rule({OneOf({"debug", "unreachable"})}, MakeDebugStatement)};
// Result: Statement* // Result: Statement*
Symbol statement = { Symbol statement = {
Rule({&atomarStatement}), Rule({&block}),
Rule({&atomarStatement, Token(";")}),
Rule({&varDeclaration, Token(";")}), Rule({&varDeclaration, Token(";")}),
Rule({&varDeclarationWithInitialization, Token(";")}), Rule({&varDeclarationWithInitialization, Token(";")}),
Rule({Token("if"), CheckIf(Token("constexpr")), Token("("), expression, Rule({Token("if"), CheckIf(Token("constexpr")), Token("("), expression,
Token(")"), &atomarStatement, Token(")"), &statement,
Optional<Statement*>(Sequence({Token("else"), &statement}))}, Optional<Statement*>(Sequence({Token("else"), &statement}))},
MakeIfStatement), MakeIfStatement),
Rule( Rule(
@ -1244,21 +1282,19 @@ struct TorqueGrammar : Grammar {
}, },
MakeTypeswitchStatement), MakeTypeswitchStatement),
Rule({Token("try"), &block, NonemptyList<LabelBlock*>(&labelBlock)}, Rule({Token("try"), &block, NonemptyList<LabelBlock*>(&labelBlock)},
MakeTryLabelStatement), MakeTryLabelExpression),
Rule({OneOf({"assert", "check"}), Token("("), &expressionWithSource, Rule({OneOf({"assert", "check"}), Token("("), &expressionWithSource,
Token(")"), Token(";")}, Token(")"), Token(";")},
MakeAssertStatement), MakeAssertStatement),
Rule({Token("while"), Token("("), expression, Token(")"), Rule({Token("while"), Token("("), expression, Token(")"), &statement},
&atomarStatement},
MakeWhileStatement), MakeWhileStatement),
Rule({Token("for"), Token("("), &varDeclaration, Token("of"), expression, Rule({Token("for"), Token("("), &varDeclaration, Token("of"), expression,
Optional<RangeExpression>(&rangeSpecifier), Token(")"), Optional<RangeExpression>(&rangeSpecifier), Token(")"), &statement},
&atomarStatement},
MakeForOfLoopStatement), MakeForOfLoopStatement),
Rule({Token("for"), Token("("), Rule({Token("for"), Token("("),
Optional<Statement*>(&varDeclarationWithInitialization), Token(";"), Optional<Statement*>(&varDeclarationWithInitialization), Token(";"),
Optional<Expression*>(expression), Token(";"), Optional<Expression*>(expression), Token(";"),
Optional<Expression*>(expression), Token(")"), &atomarStatement}, Optional<Expression*>(expression), Token(")"), &statement},
MakeForLoopStatement)}; MakeForLoopStatement)};
// Result: TypeswitchCase // Result: TypeswitchCase

View File

@ -271,6 +271,21 @@ TEST(TestLogicalOperators) {
ft.Call(); ft.Call();
} }
TEST(TestOtherwiseAndLabels) {
Isolate* isolate(CcTest::InitIsolateOnce());
CodeAssemblerTester asm_tester(isolate, 0);
TestBuiltinsFromDSLAssembler m(asm_tester.state());
{
m.TestOtherwiseWithCode1();
m.TestOtherwiseWithCode2();
m.TestOtherwiseWithCode3();
m.TestForwardLabel();
m.Return(m.UndefinedConstant());
}
FunctionTester ft(asm_tester.GenerateCode(), 0);
ft.Call();
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8

View File

@ -154,9 +154,9 @@ module test {
check(GenericMacroTest<Object>(Null) == Null); check(GenericMacroTest<Object>(Null) == Null);
check(GenericMacroTest<Object>(False) == False); check(GenericMacroTest<Object>(False) == False);
check(GenericMacroTest<Object>(True) == True); check(GenericMacroTest<Object>(True) == True);
check(GenericMacroTestWithLabels<Smi>(0) otherwise Fail == Undefined); check((GenericMacroTestWithLabels<Smi>(0) otherwise Fail) == Undefined);
check(GenericMacroTestWithLabels<Smi>(0) otherwise Fail == Undefined); check((GenericMacroTestWithLabels<Smi>(0) otherwise Fail) == Undefined);
check(GenericMacroTestWithLabels<Object>(smi0) otherwise Fail == smi0); check((GenericMacroTestWithLabels<Object>(smi0) otherwise Fail) == smi0);
try { try {
GenericMacroTestWithLabels<Object>(False) otherwise Expected; GenericMacroTestWithLabels<Object>(False) otherwise Expected;
} }
@ -541,4 +541,51 @@ module test {
check(!TestOrAnd2(false, false, false)); check(!TestOrAnd2(false, false, false));
check(!TestOrAnd3(false, false, false)); check(!TestOrAnd3(false, false, false));
} }
macro TestCall(i: Smi): Smi
labels A {
if (i < 5) return i;
goto A;
}
macro TestOtherwiseWithCode1() {
let v: Smi = 0;
let s: Smi = 1;
try {
TestCall(10) otherwise goto B(++s);
}
label B(v1: Smi) {
v = v1;
}
assert(v == 2);
}
macro TestOtherwiseWithCode2() {
let s: Smi = 0;
for (let i: Smi = 0; i < 10; ++i) {
TestCall(i) otherwise break;
++s;
}
assert(s == 5);
}
macro TestOtherwiseWithCode3() {
let s: Smi = 0;
for (let i: Smi = 0; i < 10; ++i) {
s += TestCall(i) otherwise break;
}
assert(s == 10);
}
macro TestForwardLabel() {
try {
goto A;
}
label A {
goto B(5);
}
label B(b: Smi) {
assert(b == 5);
}
}
} }