| Index: src/wasm/asm-wasm-builder.cc
|
| diff --git a/src/wasm/asm-wasm-builder.cc b/src/wasm/asm-wasm-builder.cc
|
| index d16d3a8bdd308e6aef95cb5c99cece7e34b73132..f7b7998e54c77636bab9cd6c049d4ba8e2fd850c 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,53 +241,124 @@ 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);
|
| + std::vector<uint8_t> count =
|
| + UnsignedLEB128From(node->end - node->begin + 1);
|
| + current_function_builder_->EmitCode(&count[0],
|
| + static_cast<uint32_t>(count.size()));
|
| + 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));
|
| + }
|
| + if (v == kMaxInt) {
|
| + break;
|
| + }
|
| + }
|
| + byte break_code[] = {BR_TARGET(default_block)};
|
| + current_function_builder_->EmitCode(break_code, sizeof(break_code));
|
| + // TODO(aseemgarg): remove the if once sub 0 is fixed
|
| + if (node->begin != 0) {
|
| + current_function_builder_->Emit(kExprI32Sub);
|
| + VisitVariableProxy(tag);
|
| + byte code[] = {WASM_I32V(node->begin)};
|
| + current_function_builder_->EmitCode(code, sizeof(code));
|
| + } else {
|
| + VisitVariableProxy(tag);
|
| + }
|
| + }
|
| }
|
|
|
| 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);
|
| -
|
| ZoneList<CaseClause*>* clauses = stmt->cases();
|
| - for (int i = 0; i < clauses->length(); ++i) {
|
| + int case_count = clauses->length();
|
| + if (case_count == 0) {
|
| + block_size_--;
|
| + return;
|
| + }
|
| + BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false,
|
| + 1);
|
| + ZoneVector<BlockVisitor*> blocks(zone_);
|
| + ZoneVector<int32_t> cases(zone_);
|
| + ZoneMap<int, unsigned int> case_to_block(zone_);
|
| + bool has_default = false;
|
| + 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));
|
| + DCHECK_EQ(i, case_count - 1);
|
| + has_default = true;
|
| }
|
| }
|
| + if (!has_default || case_count > 1) {
|
| + int default_block = has_default ? case_count - 1 : case_count;
|
| + 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_ = clauses->at(0)->statements()->length();
|
| + }
|
| + 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;
|
| + }
|
| }
|
|
|
| void VisitCaseClause(CaseClause* clause) { UNREACHABLE(); }
|
|
|