Index: src/wasm/asm-wasm-builder.cc |
diff --git a/src/wasm/asm-wasm-builder.cc b/src/wasm/asm-wasm-builder.cc |
index 359035994dd4a01808e5fba5074dc7084779020a..38077afe791339b5cc6b32e70f6b6601bcbdb332 100644 |
--- a/src/wasm/asm-wasm-builder.cc |
+++ b/src/wasm/asm-wasm-builder.cc |
@@ -11,6 +11,7 @@ |
#include <math.h> |
#include "src/wasm/asm-wasm-builder.h" |
+#include "src/wasm/switch-logic.h" |
#include "src/wasm/wasm-macro-gen.h" |
#include "src/wasm/wasm-opcodes.h" |
@@ -99,6 +100,11 @@ class AsmWasmBuilderImpl : public AstVisitor { |
void VisitStatements(ZoneList<Statement*>* stmts) { |
for (int i = 0; i < stmts->length(); ++i) { |
Statement* stmt = stmts->at(i); |
+ ExpressionStatement* e = stmt->AsExpressionStatement(); |
+ if (e != nullptr && e->expression()->IsUndefinedLiteral()) { |
+ block_size_--; |
+ continue; |
+ } |
RECURSE(Visit(stmt)); |
if (stmt->IsJump()) break; |
} |
@@ -235,52 +241,108 @@ class AsmWasmBuilderImpl : public AstVisitor { |
void VisitWithStatement(WithStatement* stmt) { UNREACHABLE(); } |
- void SetLocalTo(uint16_t index, int value) { |
- current_function_builder_->Emit(kExprSetLocal); |
- AddLeb128(index, true); |
- // TODO(bradnelson): variable size |
+ void GenerateCaseComparisonCode(int value, WasmOpcode op, |
+ VariableProxy* tag) { |
+ current_function_builder_->Emit(kExprIfElse); |
+ current_function_builder_->Emit(op); |
+ VisitVariableProxy(tag); |
byte code[] = {WASM_I32V(value)}; |
current_function_builder_->EmitCode(code, sizeof(code)); |
- block_size_++; |
} |
- void CompileCase(CaseClause* clause, uint16_t fall_through, |
- VariableProxy* tag) { |
- Literal* label = clause->label()->AsLiteral(); |
- DCHECK_NOT_NULL(label); |
- block_size_++; |
- current_function_builder_->Emit(kExprIf); |
- current_function_builder_->Emit(kExprI32Ior); |
- current_function_builder_->Emit(kExprI32Eq); |
- VisitVariableProxy(tag); |
- VisitLiteral(label); |
- current_function_builder_->Emit(kExprGetLocal); |
- AddLeb128(fall_through, true); |
- BlockVisitor visitor(this, nullptr, kExprBlock, false, 0); |
- SetLocalTo(fall_through, 1); |
- ZoneList<Statement*>* stmts = clause->statements(); |
- block_size_ += stmts->length(); |
- RECURSE(VisitStatements(stmts)); |
+ void HandleCase(CaseNode* node, |
+ const ZoneMap<int, unsigned int>& case_to_block, |
+ VariableProxy* tag, int default_block) { |
+ if (node->left_ != nullptr) { |
+ GenerateCaseComparisonCode(node->begin_, kExprI32LtS, tag); |
+ HandleCase(node->left_, case_to_block, tag, default_block); |
+ } |
+ if (node->right_ != nullptr) { |
+ GenerateCaseComparisonCode(node->end_, kExprI32GtS, tag); |
+ HandleCase(node->right_, case_to_block, tag, default_block); |
+ } |
+ if (node->begin_ == node->end_) { |
+ current_function_builder_->Emit(kExprIf); |
+ current_function_builder_->Emit(kExprI32Eq); |
+ VisitVariableProxy(tag); |
+ byte code[] = {WASM_I32V(node->begin_)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ DCHECK(case_to_block.find(node->begin_) != case_to_block.end()); |
+ current_function_builder_->EmitWithVarInt(kExprBr, |
+ case_to_block.at(node->begin_)); |
+ current_function_builder_->Emit(kExprNop); |
+ } else { |
+ current_function_builder_->Emit(kExprBrTable); |
+ byte count[] = {U32V_1(node->end_ - node->begin_ + 1)}; |
+ current_function_builder_->EmitCode(count, sizeof(count)); |
+ for (int v = node->begin_; v <= node->end_; v++) { |
+ if (case_to_block.find(v) != case_to_block.end()) { |
+ byte break_code[] = {BR_TARGET(case_to_block.at(v))}; |
+ current_function_builder_->EmitCode(break_code, sizeof(break_code)); |
+ } else { |
+ byte break_code[] = {BR_TARGET(default_block)}; |
+ current_function_builder_->EmitCode(break_code, sizeof(break_code)); |
+ } |
+ } |
+ byte break_code[] = {BR_TARGET(default_block)}; |
+ current_function_builder_->EmitCode(break_code, sizeof(break_code)); |
+ current_function_builder_->Emit(kExprI32Sub); |
+ VisitVariableProxy(tag); |
+ byte code[] = {WASM_I32V(node->begin_)}; |
+ current_function_builder_->EmitCode(code, sizeof(code)); |
+ } |
} |
void VisitSwitchStatement(SwitchStatement* stmt) { |
VariableProxy* tag = stmt->tag()->AsVariableProxy(); |
DCHECK_NOT_NULL(tag); |
BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false, |
- 0); |
- uint16_t fall_through = current_function_builder_->AddLocal(kAstI32); |
- SetLocalTo(fall_through, 0); |
- |
+ 1); |
ZoneList<CaseClause*>* clauses = stmt->cases(); |
- for (int i = 0; i < clauses->length(); ++i) { |
+ int case_count = clauses->length(); |
+ DCHECK(case_count > 0); |
+ ZoneVector<BlockVisitor*> blocks(zone_); |
+ ZoneVector<int32_t> cases(zone_); |
+ ZoneMap<int, unsigned int> case_to_block(zone_); |
+ int default_block = 0; |
+ for (int i = case_count - 1; i >= 0; i--) { |
CaseClause* clause = clauses->at(i); |
+ blocks.push_back(new BlockVisitor(this, nullptr, kExprBlock, false, |
+ clause->statements()->length() + 1)); |
if (!clause->is_default()) { |
- CompileCase(clause, fall_through, tag); |
+ Literal* label = clause->label()->AsLiteral(); |
+ Handle<Object> value = label->value(); |
+ DCHECK(value->IsNumber() && |
+ label->bounds().upper->Is(cache_.kAsmSigned)); |
+ int32_t label_value; |
+ if (!value->ToInt32(&label_value)) { |
+ UNREACHABLE(); |
+ } |
+ case_to_block[label_value] = i; |
+ cases.push_back(label_value); |
} else { |
- ZoneList<Statement*>* stmts = clause->statements(); |
- block_size_ += stmts->length(); |
- RECURSE(VisitStatements(stmts)); |
+ default_block = i; |
+ } |
+ } |
+ if (case_count > 1) { |
+ BlockVisitor switch_logic_block(this, nullptr, kExprBlock, false, 1); |
+ CaseNode* root = OrderCases(&cases, zone_); |
+ HandleCase(root, case_to_block, tag, default_block); |
+ if (root->left_ != nullptr || root->right_ != nullptr || |
+ root->begin_ == root->end_) { |
+ block_size_++; |
+ current_function_builder_->EmitWithVarInt(kExprBr, default_block); |
+ current_function_builder_->Emit(kExprNop); |
} |
+ } else { |
+ block_size_--; |
+ } |
+ for (int i = 0; i < case_count; i++) { |
+ CaseClause* clause = clauses->at(i); |
+ RECURSE(VisitStatements(clause->statements())); |
+ BlockVisitor* v = blocks.at(case_count - i - 1); |
+ blocks.pop_back(); |
+ delete (v); |
} |
} |