Merge V8 5.2.361.47 DO NOT MERGE
https://chromium.googlesource.com/v8/v8/+/5.2.361.47
FPIIM-449
Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/src/wasm/asm-wasm-builder.cc b/src/wasm/asm-wasm-builder.cc
index d16d3a8..325058c 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"
@@ -30,6 +31,7 @@
if (HasStackOverflow()) return; \
} while (false)
+enum AsmScope { kModuleScope, kInitScope, kFuncScope, kExportScope };
class AsmWasmBuilderImpl : public AstVisitor {
public:
@@ -43,9 +45,7 @@
global_variables_(HashMap::PointersMatch,
ZoneHashMap::kDefaultHashMapCapacity,
ZoneAllocationPolicy(zone)),
- in_function_(false),
- is_set_op_(false),
- marking_exported(false),
+ scope_(kModuleScope),
builder_(new (zone) WasmModuleBuilder(zone)),
current_function_builder_(nullptr),
literal_(literal),
@@ -55,20 +55,21 @@
typer_(typer),
cache_(TypeCache::Get()),
breakable_blocks_(zone),
- block_size_(0),
init_function_index_(0),
next_table_index_(0),
function_tables_(HashMap::PointersMatch,
ZoneHashMap::kDefaultHashMapCapacity,
ZoneAllocationPolicy(zone)),
- imported_function_table_(this) {
+ imported_function_table_(this),
+ bounds_(typer->bounds()) {
InitializeAstVisitor(isolate);
}
void InitializeInitFunction() {
init_function_index_ = builder_->AddFunction();
+ FunctionSig::Builder b(zone(), 0, 0);
current_function_builder_ = builder_->FunctionAt(init_function_index_);
- current_function_builder_->ReturnType(kAstStmt);
+ current_function_builder_->SetSignature(b.Build());
builder_->MarkStartFunction(init_function_index_);
current_function_builder_ = nullptr;
}
@@ -81,13 +82,13 @@
void VisitVariableDeclaration(VariableDeclaration* decl) {}
void VisitFunctionDeclaration(FunctionDeclaration* decl) {
- DCHECK(!in_function_);
+ DCHECK_EQ(kModuleScope, scope_);
DCHECK_NULL(current_function_builder_);
- uint16_t index = LookupOrInsertFunction(decl->proxy()->var());
+ uint32_t index = LookupOrInsertFunction(decl->proxy()->var());
current_function_builder_ = builder_->FunctionAt(index);
- in_function_ = true;
+ scope_ = kFuncScope;
RECURSE(Visit(decl->fun()));
- in_function_ = false;
+ scope_ = kModuleScope;
current_function_builder_ = nullptr;
local_variables_.Clear();
}
@@ -99,6 +100,10 @@
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()) {
+ continue;
+ }
RECURSE(Visit(stmt));
if (stmt->IsJump()) break;
}
@@ -115,12 +120,10 @@
}
}
}
- if (in_function_) {
+ if (scope_ == kFuncScope) {
BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
- false,
- static_cast<byte>(stmt->statements()->length()));
+ false);
RECURSE(VisitStatements(stmt->statements()));
- DCHECK(block_size_ >= 0);
} else {
RECURSE(VisitStatements(stmt->statements()));
}
@@ -128,25 +131,17 @@
class BlockVisitor {
private:
- int prev_block_size_;
- uint32_t index_;
AsmWasmBuilderImpl* builder_;
public:
BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
- WasmOpcode opcode, bool is_loop, int initial_block_size)
+ WasmOpcode opcode, bool is_loop)
: builder_(builder) {
builder_->breakable_blocks_.push_back(std::make_pair(stmt, is_loop));
builder_->current_function_builder_->Emit(opcode);
- index_ =
- builder_->current_function_builder_->EmitEditableVarIntImmediate();
- prev_block_size_ = builder_->block_size_;
- builder_->block_size_ = initial_block_size;
}
~BlockVisitor() {
- builder_->current_function_builder_->EditVarIntImmediate(
- index_, builder_->block_size_);
- builder_->block_size_ = prev_block_size_;
+ builder_->current_function_builder_->Emit(kExprEnd);
builder_->breakable_blocks_.pop_back();
}
};
@@ -160,25 +155,24 @@
void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); }
void VisitIfStatement(IfStatement* stmt) {
- DCHECK(in_function_);
- if (stmt->HasElseStatement()) {
- current_function_builder_->Emit(kExprIfElse);
- } else {
- current_function_builder_->Emit(kExprIf);
- }
+ DCHECK_EQ(kFuncScope, scope_);
RECURSE(Visit(stmt->condition()));
+ current_function_builder_->Emit(kExprIf);
+ // WASM ifs come with implement blocks for both arms.
+ breakable_blocks_.push_back(std::make_pair(nullptr, false));
if (stmt->HasThenStatement()) {
RECURSE(Visit(stmt->then_statement()));
- } else {
- current_function_builder_->Emit(kExprNop);
}
if (stmt->HasElseStatement()) {
+ current_function_builder_->Emit(kExprElse);
RECURSE(Visit(stmt->else_statement()));
}
+ current_function_builder_->Emit(kExprEnd);
+ breakable_blocks_.pop_back();
}
void VisitContinueStatement(ContinueStatement* stmt) {
- DCHECK(in_function_);
+ DCHECK_EQ(kFuncScope, scope_);
DCHECK_NOT_NULL(stmt->target());
int i = static_cast<int>(breakable_blocks_.size()) - 1;
int block_distance = 0;
@@ -194,12 +188,12 @@
}
}
DCHECK(i >= 0);
- current_function_builder_->EmitWithVarInt(kExprBr, block_distance);
- current_function_builder_->Emit(kExprNop);
+ current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
+ current_function_builder_->EmitVarInt(block_distance);
}
void VisitBreakStatement(BreakStatement* stmt) {
- DCHECK(in_function_);
+ DCHECK_EQ(kFuncScope, scope_);
DCHECK_NOT_NULL(stmt->target());
int i = static_cast<int>(breakable_blocks_.size()) - 1;
int block_distance = 0;
@@ -217,123 +211,191 @@
}
}
DCHECK(i >= 0);
- current_function_builder_->EmitWithVarInt(kExprBr, block_distance);
- current_function_builder_->Emit(kExprNop);
+ current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
+ current_function_builder_->EmitVarInt(block_distance);
}
void VisitReturnStatement(ReturnStatement* stmt) {
- if (in_function_) {
- current_function_builder_->Emit(kExprReturn);
+ if (scope_ == kModuleScope) {
+ scope_ = kExportScope;
+ RECURSE(Visit(stmt->expression()));
+ scope_ = kModuleScope;
+ } else if (scope_ == kFuncScope) {
+ RECURSE(Visit(stmt->expression()));
+ uint8_t arity =
+ TypeOf(stmt->expression()) == kAstStmt ? ARITY_0 : ARITY_1;
+ current_function_builder_->EmitWithU8(kExprReturn, arity);
} else {
- marking_exported = true;
- }
- RECURSE(Visit(stmt->expression()));
- if (!in_function_) {
- marking_exported = false;
+ UNREACHABLE();
}
}
void VisitWithStatement(WithStatement* stmt) { UNREACHABLE(); }
- void SetLocalTo(uint16_t index, int value) {
- current_function_builder_->Emit(kExprSetLocal);
- AddLeb128(index, true);
- // TODO(bradnelson): variable size
- byte code[] = {WASM_I32V(value)};
- current_function_builder_->EmitCode(code, sizeof(code));
- block_size_++;
- }
+ void HandleCase(CaseNode* node,
+ const ZoneMap<int, unsigned int>& case_to_block,
+ VariableProxy* tag, int default_block, int if_depth) {
+ int prev_if_depth = if_depth;
+ if (node->left != nullptr) {
+ VisitVariableProxy(tag);
+ current_function_builder_->EmitI32Const(node->begin);
+ current_function_builder_->Emit(kExprI32LtS);
+ current_function_builder_->Emit(kExprIf);
+ if_depth++;
+ breakable_blocks_.push_back(std::make_pair(nullptr, false));
+ HandleCase(node->left, case_to_block, tag, default_block, if_depth);
+ current_function_builder_->Emit(kExprElse);
+ }
+ if (node->right != nullptr) {
+ VisitVariableProxy(tag);
+ current_function_builder_->EmitI32Const(node->end);
+ current_function_builder_->Emit(kExprI32GtS);
+ current_function_builder_->Emit(kExprIf);
+ if_depth++;
+ breakable_blocks_.push_back(std::make_pair(nullptr, false));
+ HandleCase(node->right, case_to_block, tag, default_block, if_depth);
+ current_function_builder_->Emit(kExprElse);
+ }
+ if (node->begin == node->end) {
+ VisitVariableProxy(tag);
+ current_function_builder_->EmitI32Const(node->begin);
+ current_function_builder_->Emit(kExprI32Eq);
+ current_function_builder_->Emit(kExprIf);
+ DCHECK(case_to_block.find(node->begin) != case_to_block.end());
+ current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
+ current_function_builder_->EmitVarInt(1 + if_depth +
+ case_to_block.at(node->begin));
+ current_function_builder_->Emit(kExprEnd);
+ } else {
+ if (node->begin != 0) {
+ VisitVariableProxy(tag);
+ current_function_builder_->EmitI32Const(node->begin);
+ current_function_builder_->Emit(kExprI32Sub);
+ } else {
+ VisitVariableProxy(tag);
+ }
+ current_function_builder_->EmitWithU8(kExprBrTable, ARITY_0);
+ current_function_builder_->EmitVarInt(node->end - node->begin + 1);
+ for (int v = node->begin; v <= node->end; v++) {
+ if (case_to_block.find(v) != case_to_block.end()) {
+ byte break_code[] = {BR_TARGET(if_depth + case_to_block.at(v))};
+ current_function_builder_->EmitCode(break_code, sizeof(break_code));
+ } else {
+ byte break_code[] = {BR_TARGET(if_depth + default_block)};
+ current_function_builder_->EmitCode(break_code, sizeof(break_code));
+ }
+ if (v == kMaxInt) {
+ break;
+ }
+ }
+ byte break_code[] = {BR_TARGET(if_depth + default_block)};
+ current_function_builder_->EmitCode(break_code, sizeof(break_code));
+ }
- 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));
+ while (if_depth-- != prev_if_depth) {
+ breakable_blocks_.pop_back();
+ current_function_builder_->Emit(kExprEnd);
+ }
}
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) {
+ return;
+ }
+ BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false);
+ 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));
if (!clause->is_default()) {
- CompileCase(clause, fall_through, tag);
+ Literal* label = clause->label()->AsLiteral();
+ Handle<Object> value = label->value();
+ DCHECK(value->IsNumber() &&
+ bounds_->get(label).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);
+ CaseNode* root = OrderCases(&cases, zone_);
+ HandleCase(root, case_to_block, tag, default_block, 0);
+ if (root->left != nullptr || root->right != nullptr ||
+ root->begin == root->end) {
+ current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
+ current_function_builder_->EmitVarInt(default_block);
+ }
+ }
+ 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(); }
void VisitDoWhileStatement(DoWhileStatement* stmt) {
- DCHECK(in_function_);
- BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
- 2);
+ DCHECK_EQ(kFuncScope, scope_);
+ BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
RECURSE(Visit(stmt->body()));
- current_function_builder_->Emit(kExprIf);
RECURSE(Visit(stmt->cond()));
- current_function_builder_->EmitWithVarInt(kExprBr, 0);
- current_function_builder_->Emit(kExprNop);
+ current_function_builder_->Emit(kExprIf);
+ current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
+ current_function_builder_->Emit(kExprEnd);
}
void VisitWhileStatement(WhileStatement* stmt) {
- DCHECK(in_function_);
- BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
- 1);
- current_function_builder_->Emit(kExprIf);
+ DCHECK_EQ(kFuncScope, scope_);
+ BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
RECURSE(Visit(stmt->cond()));
- current_function_builder_->EmitWithVarInt(kExprBr, 0);
+ breakable_blocks_.push_back(std::make_pair(nullptr, false));
+ current_function_builder_->Emit(kExprIf);
RECURSE(Visit(stmt->body()));
+ current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
+ current_function_builder_->Emit(kExprEnd);
+ breakable_blocks_.pop_back();
}
void VisitForStatement(ForStatement* stmt) {
- DCHECK(in_function_);
+ DCHECK_EQ(kFuncScope, scope_);
if (stmt->init() != nullptr) {
- block_size_++;
RECURSE(Visit(stmt->init()));
}
- BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
- 0);
+ BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
if (stmt->cond() != nullptr) {
- block_size_++;
- current_function_builder_->Emit(kExprIf);
- current_function_builder_->Emit(kExprI32Eqz);
RECURSE(Visit(stmt->cond()));
- current_function_builder_->EmitWithVarInt(kExprBr, 1);
+ current_function_builder_->Emit(kExprI32Eqz);
+ current_function_builder_->Emit(kExprIf);
current_function_builder_->Emit(kExprNop);
+ current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 2);
+ current_function_builder_->Emit(kExprEnd);
}
if (stmt->body() != nullptr) {
- block_size_++;
RECURSE(Visit(stmt->body()));
}
if (stmt->next() != nullptr) {
- block_size_++;
RECURSE(Visit(stmt->next()));
}
- block_size_++;
- current_function_builder_->EmitWithVarInt(kExprBr, 0);
current_function_builder_->Emit(kExprNop);
+ current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 0);
}
void VisitForInStatement(ForInStatement* stmt) { UNREACHABLE(); }
@@ -348,16 +410,21 @@
void VisitFunctionLiteral(FunctionLiteral* expr) {
Scope* scope = expr->scope();
- if (in_function_) {
- if (expr->bounds().lower->IsFunction()) {
- FunctionType* func_type = expr->bounds().lower->AsFunction();
+ if (scope_ == kFuncScope) {
+ if (bounds_->get(expr).lower->IsFunction()) {
+ // Build the signature for the function.
+ FunctionType* func_type = bounds_->get(expr).lower->AsFunction();
LocalType return_type = TypeFrom(func_type->Result());
- current_function_builder_->ReturnType(return_type);
+ FunctionSig::Builder b(zone(), return_type == kAstStmt ? 0 : 1,
+ func_type->Arity());
+ if (return_type != kAstStmt) b.AddReturn(return_type);
for (int i = 0; i < expr->parameter_count(); i++) {
LocalType type = TypeFrom(func_type->Parameter(i));
DCHECK_NE(kAstStmt, type);
- LookupOrInsertLocal(scope->parameter(i), type);
+ b.AddParam(type);
+ InsertParameter(scope->parameter(i), type, i);
}
+ current_function_builder_->SetSignature(b.Build());
} else {
UNREACHABLE();
}
@@ -371,11 +438,16 @@
}
void VisitConditional(Conditional* expr) {
- DCHECK(in_function_);
- current_function_builder_->Emit(kExprIfElse);
+ DCHECK_EQ(kFuncScope, scope_);
RECURSE(Visit(expr->condition()));
+ // WASM ifs come with implicit blocks for both arms.
+ breakable_blocks_.push_back(std::make_pair(nullptr, false));
+ current_function_builder_->Emit(kExprIf);
RECURSE(Visit(expr->then_expression()));
+ current_function_builder_->Emit(kExprElse);
RECURSE(Visit(expr->else_expression()));
+ current_function_builder_->Emit(kExprEnd);
+ breakable_blocks_.pop_back();
}
bool VisitStdlibConstant(Variable* var) {
@@ -431,41 +503,29 @@
}
void VisitVariableProxy(VariableProxy* expr) {
- if (in_function_) {
+ if (scope_ == kFuncScope || scope_ == kInitScope) {
Variable* var = expr->var();
- if (is_set_op_) {
- if (var->IsContextSlot()) {
- current_function_builder_->Emit(kExprStoreGlobal);
- } else {
- current_function_builder_->Emit(kExprSetLocal);
- }
- is_set_op_ = false;
- } else {
- if (VisitStdlibConstant(var)) {
- return;
- }
- if (var->IsContextSlot()) {
- current_function_builder_->Emit(kExprLoadGlobal);
- } else {
- current_function_builder_->Emit(kExprGetLocal);
- }
+ if (VisitStdlibConstant(var)) {
+ return;
}
LocalType var_type = TypeOf(expr);
DCHECK_NE(kAstStmt, var_type);
if (var->IsContextSlot()) {
- AddLeb128(LookupOrInsertGlobal(var, var_type), false);
+ current_function_builder_->EmitWithVarInt(
+ kExprLoadGlobal, LookupOrInsertGlobal(var, var_type));
} else {
- AddLeb128(LookupOrInsertLocal(var, var_type), true);
+ current_function_builder_->EmitGetLocal(
+ LookupOrInsertLocal(var, var_type));
}
}
}
void VisitLiteral(Literal* expr) {
Handle<Object> value = expr->value();
- if (!in_function_ || !value->IsNumber()) {
+ if (!value->IsNumber() || (scope_ != kFuncScope && scope_ != kInitScope)) {
return;
}
- Type* type = expr->bounds().upper;
+ Type* type = bounds_->get(expr).upper;
if (type->Is(cache_.kAsmSigned)) {
int32_t i = 0;
if (!value->ToInt32(&i)) {
@@ -496,7 +556,7 @@
ZoneList<ObjectLiteralProperty*>* props = expr->properties();
for (int i = 0; i < props->length(); ++i) {
ObjectLiteralProperty* prop = props->at(i);
- DCHECK(marking_exported);
+ DCHECK_EQ(kExportScope, scope_);
VariableProxy* expr = prop->value()->AsVariableProxy();
DCHECK_NOT_NULL(expr);
Variable* var = expr->var();
@@ -505,10 +565,11 @@
DCHECK(name->IsPropertyName());
const AstRawString* raw_name = name->AsRawPropertyName();
if (var->is_function()) {
- uint16_t index = LookupOrInsertFunction(var);
+ uint32_t index = LookupOrInsertFunction(var);
builder_->FunctionAt(index)->Exported(1);
- builder_->FunctionAt(index)
- ->SetName(raw_name->raw_data(), raw_name->length());
+ builder_->FunctionAt(index)->SetName(
+ reinterpret_cast<const char*>(raw_name->raw_data()),
+ raw_name->length());
}
}
}
@@ -517,17 +578,17 @@
void LoadInitFunction() {
current_function_builder_ = builder_->FunctionAt(init_function_index_);
- in_function_ = true;
+ scope_ = kInitScope;
}
void UnLoadInitFunction() {
- in_function_ = false;
+ scope_ = kModuleScope;
current_function_builder_ = nullptr;
}
void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) {
FunctionType* func_type =
- funcs->bounds().lower->AsArray()->Element()->AsFunction();
+ bounds_->get(funcs).lower->AsArray()->Element()->AsFunction();
LocalType return_type = TypeFrom(func_type->Result());
FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
func_type->Arity());
@@ -537,7 +598,7 @@
for (int i = 0; i < func_type->Arity(); i++) {
sig.AddParam(TypeFrom(func_type->Parameter(i)));
}
- uint16_t signature_index = builder_->AddSignature(sig.Build());
+ uint32_t signature_index = builder_->AddSignature(sig.Build());
InsertFunctionTable(table->var(), next_table_index_, signature_index);
next_table_index_ += funcs->values()->length();
for (int i = 0; i < funcs->values()->length(); i++) {
@@ -549,11 +610,11 @@
struct FunctionTableIndices : public ZoneObject {
uint32_t start_index;
- uint16_t signature_index;
+ uint32_t signature_index;
};
void InsertFunctionTable(Variable* v, uint32_t start_index,
- uint16_t signature_index) {
+ uint32_t signature_index) {
FunctionTableIndices* container = new (zone()) FunctionTableIndices();
container->start_index = start_index;
container->signature_index = signature_index;
@@ -573,12 +634,11 @@
private:
class ImportedFunctionIndices : public ZoneObject {
public:
- const unsigned char* name_;
+ const char* name_;
int name_length_;
WasmModuleBuilder::SignatureMap signature_to_index_;
- ImportedFunctionIndices(const unsigned char* name, int name_length,
- Zone* zone)
+ ImportedFunctionIndices(const char* name, int name_length, Zone* zone)
: name_(name), name_length_(name_length), signature_to_index_(zone) {}
};
ZoneHashMap table_;
@@ -590,7 +650,7 @@
ZoneAllocationPolicy(builder->zone())),
builder_(builder) {}
- void AddImport(Variable* v, const unsigned char* name, int name_length) {
+ void AddImport(Variable* v, const char* name, int name_length) {
ImportedFunctionIndices* indices = new (builder_->zone())
ImportedFunctionIndices(name, name_length, builder_->zone());
ZoneHashMap::Entry* entry = table_.LookupOrInsert(
@@ -598,7 +658,7 @@
entry->value = indices;
}
- uint16_t GetFunctionIndex(Variable* v, FunctionSig* sig) {
+ uint32_t GetFunctionIndex(Variable* v, FunctionSig* sig) {
ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v));
DCHECK_NOT_NULL(entry);
ImportedFunctionIndices* indices =
@@ -608,60 +668,137 @@
if (pos != indices->signature_to_index_.end()) {
return pos->second;
} else {
- uint16_t index = builder_->builder_->AddFunction();
+ uint32_t index = builder_->builder_->AddImport(
+ indices->name_, indices->name_length_, sig);
indices->signature_to_index_[sig] = index;
- WasmFunctionBuilder* function = builder_->builder_->FunctionAt(index);
- function->External(1);
- function->SetName(indices->name_, indices->name_length_);
- if (sig->return_count() > 0) {
- function->ReturnType(sig->GetReturn());
- }
- for (size_t i = 0; i < sig->parameter_count(); i++) {
- function->AddParam(sig->GetParam(i));
- }
return index;
}
}
};
- void VisitAssignment(Assignment* expr) {
- bool in_init = false;
- if (!in_function_) {
- BinaryOperation* binop = expr->value()->AsBinaryOperation();
- if (binop != nullptr) {
+ void EmitAssignmentLhs(Expression* target, MachineType* mtype) {
+ // Match the left hand side of the assignment.
+ VariableProxy* target_var = target->AsVariableProxy();
+ if (target_var != nullptr) {
+ // Left hand side is a local or a global variable, no code on LHS.
+ return;
+ }
+
+ Property* target_prop = target->AsProperty();
+ if (target_prop != nullptr) {
+ // Left hand side is a property access, i.e. the asm.js heap.
+ VisitPropertyAndEmitIndex(target_prop, mtype);
+ return;
+ }
+
+ if (target_var == nullptr && target_prop == nullptr) {
+ UNREACHABLE(); // invalid assignment.
+ }
+ }
+
+ void EmitAssignmentRhs(Expression* target, Expression* value, bool* is_nop) {
+ BinaryOperation* binop = value->AsBinaryOperation();
+ if (binop != nullptr) {
+ if (scope_ == kInitScope) {
+ // Handle foreign variables in the initialization scope.
Property* prop = binop->left()->AsProperty();
- DCHECK_NOT_NULL(prop);
- LoadInitFunction();
- is_set_op_ = true;
- RECURSE(Visit(expr->target()));
- DCHECK(!is_set_op_);
if (binop->op() == Token::MUL) {
DCHECK(binop->right()->IsLiteral());
DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot());
VisitForeignVariable(true, prop);
+ return;
} else if (binop->op() == Token::BIT_OR) {
DCHECK(binop->right()->IsLiteral());
DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot());
VisitForeignVariable(false, prop);
+ return;
} else {
UNREACHABLE();
}
- UnLoadInitFunction();
- return;
}
+ if (MatchBinaryOperation(binop) == kAsIs) {
+ VariableProxy* target_var = target->AsVariableProxy();
+ VariableProxy* effective_value_var = GetLeft(binop)->AsVariableProxy();
+ if (target_var != nullptr && effective_value_var != nullptr &&
+ target_var->var() == effective_value_var->var()) {
+ *is_nop = true;
+ return;
+ }
+ }
+ }
+ RECURSE(Visit(value));
+ }
+
+ void EmitAssignment(Assignment* expr, MachineType type) {
+ // Match the left hand side of the assignment.
+ VariableProxy* target_var = expr->target()->AsVariableProxy();
+ if (target_var != nullptr) {
+ // Left hand side is a local or a global variable.
+ Variable* var = target_var->var();
+ LocalType var_type = TypeOf(expr);
+ DCHECK_NE(kAstStmt, var_type);
+ if (var->IsContextSlot()) {
+ current_function_builder_->EmitWithVarInt(
+ kExprStoreGlobal, LookupOrInsertGlobal(var, var_type));
+ } else {
+ current_function_builder_->EmitSetLocal(
+ LookupOrInsertLocal(var, var_type));
+ }
+ }
+
+ Property* target_prop = expr->target()->AsProperty();
+ if (target_prop != nullptr) {
+ // Left hand side is a property access, i.e. the asm.js heap.
+ if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() &&
+ bounds_->get(expr->target()->AsProperty()->obj())
+ .lower->Is(cache_.kFloat32Array)) {
+ current_function_builder_->Emit(kExprF32ConvertF64);
+ }
+ WasmOpcode opcode;
+ if (type == MachineType::Int8()) {
+ opcode = kExprI32AsmjsStoreMem8;
+ } else if (type == MachineType::Uint8()) {
+ opcode = kExprI32AsmjsStoreMem8;
+ } else if (type == MachineType::Int16()) {
+ opcode = kExprI32AsmjsStoreMem16;
+ } else if (type == MachineType::Uint16()) {
+ opcode = kExprI32AsmjsStoreMem16;
+ } else if (type == MachineType::Int32()) {
+ opcode = kExprI32AsmjsStoreMem;
+ } else if (type == MachineType::Uint32()) {
+ opcode = kExprI32AsmjsStoreMem;
+ } else if (type == MachineType::Float32()) {
+ opcode = kExprF32AsmjsStoreMem;
+ } else if (type == MachineType::Float64()) {
+ opcode = kExprF64AsmjsStoreMem;
+ } else {
+ UNREACHABLE();
+ }
+ current_function_builder_->Emit(opcode);
+ }
+
+ if (target_var == nullptr && target_prop == nullptr) {
+ UNREACHABLE(); // invalid assignment.
+ }
+ }
+
+ void VisitAssignment(Assignment* expr) {
+ bool as_init = false;
+ if (scope_ == kModuleScope) {
Property* prop = expr->value()->AsProperty();
if (prop != nullptr) {
VariableProxy* vp = prop->obj()->AsVariableProxy();
if (vp != nullptr && vp->var()->IsParameter() &&
vp->var()->index() == 1) {
VariableProxy* target = expr->target()->AsVariableProxy();
- if (target->bounds().lower->Is(Type::Function())) {
+ if (bounds_->get(target).lower->Is(Type::Function())) {
const AstRawString* name =
prop->key()->AsLiteral()->AsRawPropertyName();
- imported_function_table_.AddImport(target->var(), name->raw_data(),
- name->length());
+ imported_function_table_.AddImport(
+ target->var(), reinterpret_cast<const char*>(name->raw_data()),
+ name->length());
}
}
// Property values in module scope don't emit code, so return.
@@ -669,7 +806,7 @@
}
ArrayLiteral* funcs = expr->value()->AsArrayLiteral();
if (funcs != nullptr &&
- funcs->bounds().lower->AsArray()->Element()->IsFunction()) {
+ bounds_->get(funcs).lower->AsArray()->Element()->IsFunction()) {
VariableProxy* target = expr->target()->AsVariableProxy();
DCHECK_NOT_NULL(target);
AddFunctionTable(target, funcs);
@@ -680,32 +817,18 @@
// No init code to emit for CallNew nodes.
return;
}
- in_init = true;
- LoadInitFunction();
+ as_init = true;
}
- BinaryOperation* value_op = expr->value()->AsBinaryOperation();
- if (value_op != nullptr && MatchBinaryOperation(value_op) == kAsIs) {
- VariableProxy* target_var = expr->target()->AsVariableProxy();
- VariableProxy* effective_value_var = GetLeft(value_op)->AsVariableProxy();
- if (target_var != nullptr && effective_value_var != nullptr &&
- target_var->var() == effective_value_var->var()) {
- block_size_--;
- return;
- }
+
+ if (as_init) LoadInitFunction();
+ MachineType mtype;
+ bool is_nop = false;
+ EmitAssignmentLhs(expr->target(), &mtype);
+ EmitAssignmentRhs(expr->target(), expr->value(), &is_nop);
+ if (!is_nop) {
+ EmitAssignment(expr, mtype);
}
- is_set_op_ = true;
- RECURSE(Visit(expr->target()));
- DCHECK(!is_set_op_);
- // Assignment to heapf32 from float64 converts.
- if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() &&
- expr->target()->AsProperty()->obj()->bounds().lower->Is(
- cache_.kFloat32Array)) {
- current_function_builder_->Emit(kExprF32ConvertF64);
- }
- RECURSE(Visit(expr->value()));
- if (in_init) {
- UnLoadInitFunction();
- }
+ if (as_init) UnLoadInitFunction();
}
void VisitYield(Yield* expr) { UNREACHABLE(); }
@@ -744,9 +867,7 @@
Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
if (nvalue->IsNumber()) {
int32_t val = static_cast<int32_t>(nvalue->Number());
- // TODO(bradnelson): variable size
- byte code[] = {WASM_I32V(val)};
- current_function_builder_->EmitCode(code, sizeof(code));
+ current_function_builder_->EmitI32Const(val);
return;
}
}
@@ -762,46 +883,41 @@
}
}
- void VisitProperty(Property* expr) {
+ void VisitPropertyAndEmitIndex(Property* expr, MachineType* mtype) {
Expression* obj = expr->obj();
- DCHECK_EQ(obj->bounds().lower, obj->bounds().upper);
- Type* type = obj->bounds().lower;
- MachineType mtype;
+ DCHECK_EQ(bounds_->get(obj).lower, bounds_->get(obj).upper);
+ Type* type = bounds_->get(obj).lower;
int size;
if (type->Is(cache_.kUint8Array)) {
- mtype = MachineType::Uint8();
+ *mtype = MachineType::Uint8();
size = 1;
} else if (type->Is(cache_.kInt8Array)) {
- mtype = MachineType::Int8();
+ *mtype = MachineType::Int8();
size = 1;
} else if (type->Is(cache_.kUint16Array)) {
- mtype = MachineType::Uint16();
+ *mtype = MachineType::Uint16();
size = 2;
} else if (type->Is(cache_.kInt16Array)) {
- mtype = MachineType::Int16();
+ *mtype = MachineType::Int16();
size = 2;
} else if (type->Is(cache_.kUint32Array)) {
- mtype = MachineType::Uint32();
+ *mtype = MachineType::Uint32();
size = 4;
} else if (type->Is(cache_.kInt32Array)) {
- mtype = MachineType::Int32();
+ *mtype = MachineType::Int32();
size = 4;
} else if (type->Is(cache_.kUint32Array)) {
- mtype = MachineType::Uint32();
+ *mtype = MachineType::Uint32();
size = 4;
} else if (type->Is(cache_.kFloat32Array)) {
- mtype = MachineType::Float32();
+ *mtype = MachineType::Float32();
size = 4;
} else if (type->Is(cache_.kFloat64Array)) {
- mtype = MachineType::Float64();
+ *mtype = MachineType::Float64();
size = 8;
} else {
UNREACHABLE();
}
- // TODO(titzer): use special asm-compatibility opcodes?
- current_function_builder_->EmitWithU8U8(
- WasmOpcodes::LoadStoreOpcodeOf(mtype, is_set_op_), 0, 0);
- is_set_op_ = false;
if (size == 1) {
// Allow more general expression in byte arrays than the spec
// strictly permits.
@@ -809,87 +925,123 @@
// places that strictly should be HEAP8[HEAP32[..]>>0].
RECURSE(Visit(expr->key()));
return;
- } else {
- Literal* value = expr->key()->AsLiteral();
- if (value) {
- DCHECK(value->raw_value()->IsNumber());
- DCHECK_EQ(kAstI32, TypeOf(value));
- int val = static_cast<int>(value->raw_value()->AsNumber());
- // TODO(bradnelson): variable size
- byte code[] = {WASM_I32V(val * size)};
- current_function_builder_->EmitCode(code, sizeof(code));
- return;
- }
- BinaryOperation* binop = expr->key()->AsBinaryOperation();
- if (binop) {
- DCHECK_EQ(Token::SAR, binop->op());
- DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
- DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
- DCHECK_EQ(size,
- 1 << static_cast<int>(
- binop->right()->AsLiteral()->raw_value()->AsNumber()));
- // Mask bottom bits to match asm.js behavior.
- current_function_builder_->Emit(kExprI32And);
- byte code[] = {WASM_I8(~(size - 1))};
- current_function_builder_->EmitCode(code, sizeof(code));
- RECURSE(Visit(binop->left()));
- return;
- }
+ }
+
+ Literal* value = expr->key()->AsLiteral();
+ if (value) {
+ DCHECK(value->raw_value()->IsNumber());
+ DCHECK_EQ(kAstI32, TypeOf(value));
+ int32_t val = static_cast<int32_t>(value->raw_value()->AsNumber());
+ // TODO(titzer): handle overflow here.
+ current_function_builder_->EmitI32Const(val * size);
+ return;
+ }
+ BinaryOperation* binop = expr->key()->AsBinaryOperation();
+ if (binop) {
+ DCHECK_EQ(Token::SAR, binop->op());
+ DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
+ DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
+ DCHECK_EQ(size,
+ 1 << static_cast<int>(
+ binop->right()->AsLiteral()->raw_value()->AsNumber()));
+ // Mask bottom bits to match asm.js behavior.
+ byte mask = static_cast<byte>(~(size - 1));
+ RECURSE(Visit(binop->left()));
+ current_function_builder_->EmitWithU8(kExprI8Const, mask);
+ current_function_builder_->Emit(kExprI32And);
+ return;
}
UNREACHABLE();
}
+ void VisitProperty(Property* expr) {
+ MachineType type;
+ VisitPropertyAndEmitIndex(expr, &type);
+ WasmOpcode opcode;
+ if (type == MachineType::Int8()) {
+ opcode = kExprI32AsmjsLoadMem8S;
+ } else if (type == MachineType::Uint8()) {
+ opcode = kExprI32AsmjsLoadMem8U;
+ } else if (type == MachineType::Int16()) {
+ opcode = kExprI32AsmjsLoadMem16S;
+ } else if (type == MachineType::Uint16()) {
+ opcode = kExprI32AsmjsLoadMem16U;
+ } else if (type == MachineType::Int32()) {
+ opcode = kExprI32AsmjsLoadMem;
+ } else if (type == MachineType::Uint32()) {
+ opcode = kExprI32AsmjsLoadMem;
+ } else if (type == MachineType::Float32()) {
+ opcode = kExprF32AsmjsLoadMem;
+ } else if (type == MachineType::Float64()) {
+ opcode = kExprF64AsmjsLoadMem;
+ } else {
+ UNREACHABLE();
+ }
+
+ current_function_builder_->Emit(opcode);
+ }
+
bool VisitStdlibFunction(Call* call, VariableProxy* expr) {
Variable* var = expr->var();
AsmTyper::StandardMember standard_object =
typer_->VariableAsStandardMember(var);
ZoneList<Expression*>* args = call->arguments();
LocalType call_type = TypeOf(call);
+
switch (standard_object) {
case AsmTyper::kNone: {
return false;
}
case AsmTyper::kMathAcos: {
+ VisitCallArgs(call);
DCHECK_EQ(kAstF64, call_type);
current_function_builder_->Emit(kExprF64Acos);
break;
}
case AsmTyper::kMathAsin: {
+ VisitCallArgs(call);
DCHECK_EQ(kAstF64, call_type);
current_function_builder_->Emit(kExprF64Asin);
break;
}
case AsmTyper::kMathAtan: {
+ VisitCallArgs(call);
DCHECK_EQ(kAstF64, call_type);
current_function_builder_->Emit(kExprF64Atan);
break;
}
case AsmTyper::kMathCos: {
+ VisitCallArgs(call);
DCHECK_EQ(kAstF64, call_type);
current_function_builder_->Emit(kExprF64Cos);
break;
}
case AsmTyper::kMathSin: {
+ VisitCallArgs(call);
DCHECK_EQ(kAstF64, call_type);
current_function_builder_->Emit(kExprF64Sin);
break;
}
case AsmTyper::kMathTan: {
+ VisitCallArgs(call);
DCHECK_EQ(kAstF64, call_type);
current_function_builder_->Emit(kExprF64Tan);
break;
}
case AsmTyper::kMathExp: {
+ VisitCallArgs(call);
DCHECK_EQ(kAstF64, call_type);
current_function_builder_->Emit(kExprF64Exp);
break;
}
case AsmTyper::kMathLog: {
+ VisitCallArgs(call);
DCHECK_EQ(kAstF64, call_type);
current_function_builder_->Emit(kExprF64Log);
break;
}
case AsmTyper::kMathCeil: {
+ VisitCallArgs(call);
if (call_type == kAstF32) {
current_function_builder_->Emit(kExprF32Ceil);
} else if (call_type == kAstF64) {
@@ -900,6 +1052,7 @@
break;
}
case AsmTyper::kMathFloor: {
+ VisitCallArgs(call);
if (call_type == kAstF32) {
current_function_builder_->Emit(kExprF32Floor);
} else if (call_type == kAstF64) {
@@ -910,6 +1063,7 @@
break;
}
case AsmTyper::kMathSqrt: {
+ VisitCallArgs(call);
if (call_type == kAstF32) {
current_function_builder_->Emit(kExprF32Sqrt);
} else if (call_type == kAstF64) {
@@ -920,19 +1074,33 @@
break;
}
case AsmTyper::kMathAbs: {
- // TODO(bradnelson): Should this be cast to float?
if (call_type == kAstI32) {
- current_function_builder_->Emit(kExprIfElse);
- current_function_builder_->Emit(kExprI32LtS);
- Visit(args->at(0));
+ uint32_t tmp = current_function_builder_->AddLocal(kAstI32);
+
+ // if set_local(tmp, x) < 0
+ Visit(call->arguments()->at(0));
+ current_function_builder_->EmitSetLocal(tmp);
byte code[] = {WASM_I8(0)};
current_function_builder_->EmitCode(code, sizeof(code));
- current_function_builder_->Emit(kExprI32Sub);
+ current_function_builder_->Emit(kExprI32LtS);
+ current_function_builder_->Emit(kExprIf);
+
+ // then (0 - tmp)
current_function_builder_->EmitCode(code, sizeof(code));
- Visit(args->at(0));
+ current_function_builder_->EmitGetLocal(tmp);
+ current_function_builder_->Emit(kExprI32Sub);
+
+ // else tmp
+ current_function_builder_->Emit(kExprElse);
+ current_function_builder_->EmitGetLocal(tmp);
+ // end
+ current_function_builder_->Emit(kExprEnd);
+
} else if (call_type == kAstF32) {
+ VisitCallArgs(call);
current_function_builder_->Emit(kExprF32Abs);
} else if (call_type == kAstF64) {
+ VisitCallArgs(call);
current_function_builder_->Emit(kExprF64Abs);
} else {
UNREACHABLE();
@@ -942,13 +1110,32 @@
case AsmTyper::kMathMin: {
// TODO(bradnelson): Change wasm to match Math.min in asm.js mode.
if (call_type == kAstI32) {
- current_function_builder_->Emit(kExprIfElse);
+ uint32_t tmp_x = current_function_builder_->AddLocal(kAstI32);
+ uint32_t tmp_y = current_function_builder_->AddLocal(kAstI32);
+
+ // if set_local(tmp_x, x) < set_local(tmp_y, y)
+ Visit(call->arguments()->at(0));
+ current_function_builder_->EmitSetLocal(tmp_x);
+
+ Visit(call->arguments()->at(1));
+ current_function_builder_->EmitSetLocal(tmp_y);
+
current_function_builder_->Emit(kExprI32LeS);
- Visit(args->at(0));
- Visit(args->at(1));
+ current_function_builder_->Emit(kExprIf);
+
+ // then tmp_x
+ current_function_builder_->EmitGetLocal(tmp_x);
+
+ // else tmp_y
+ current_function_builder_->Emit(kExprElse);
+ current_function_builder_->EmitGetLocal(tmp_y);
+ current_function_builder_->Emit(kExprEnd);
+
} else if (call_type == kAstF32) {
+ VisitCallArgs(call);
current_function_builder_->Emit(kExprF32Min);
} else if (call_type == kAstF64) {
+ VisitCallArgs(call);
current_function_builder_->Emit(kExprF64Min);
} else {
UNREACHABLE();
@@ -958,13 +1145,33 @@
case AsmTyper::kMathMax: {
// TODO(bradnelson): Change wasm to match Math.max in asm.js mode.
if (call_type == kAstI32) {
- current_function_builder_->Emit(kExprIfElse);
- current_function_builder_->Emit(kExprI32GtS);
- Visit(args->at(0));
- Visit(args->at(1));
+ uint32_t tmp_x = current_function_builder_->AddLocal(kAstI32);
+ uint32_t tmp_y = current_function_builder_->AddLocal(kAstI32);
+
+ // if set_local(tmp_x, x) < set_local(tmp_y, y)
+ Visit(call->arguments()->at(0));
+
+ current_function_builder_->EmitSetLocal(tmp_x);
+
+ Visit(call->arguments()->at(1));
+ current_function_builder_->EmitSetLocal(tmp_y);
+
+ current_function_builder_->Emit(kExprI32LeS);
+ current_function_builder_->Emit(kExprIf);
+
+ // then tmp_y
+ current_function_builder_->EmitGetLocal(tmp_y);
+
+ // else tmp_x
+ current_function_builder_->Emit(kExprElse);
+ current_function_builder_->EmitGetLocal(tmp_x);
+ current_function_builder_->Emit(kExprEnd);
+
} else if (call_type == kAstF32) {
+ VisitCallArgs(call);
current_function_builder_->Emit(kExprF32Max);
} else if (call_type == kAstF64) {
+ VisitCallArgs(call);
current_function_builder_->Emit(kExprF64Max);
} else {
UNREACHABLE();
@@ -972,16 +1179,19 @@
break;
}
case AsmTyper::kMathAtan2: {
+ VisitCallArgs(call);
DCHECK_EQ(kAstF64, call_type);
current_function_builder_->Emit(kExprF64Atan2);
break;
}
case AsmTyper::kMathPow: {
+ VisitCallArgs(call);
DCHECK_EQ(kAstF64, call_type);
current_function_builder_->Emit(kExprF64Pow);
break;
}
case AsmTyper::kMathImul: {
+ VisitCallArgs(call);
current_function_builder_->Emit(kExprI32Mul);
break;
}
@@ -989,6 +1199,7 @@
DCHECK(args->length() == 1);
Literal* literal = args->at(0)->AsLiteral();
if (literal != nullptr) {
+ // constant fold Math.fround(#const);
if (literal->raw_value()->IsNumber()) {
float val = static_cast<float>(literal->raw_value()->AsNumber());
byte code[] = {WASM_F32(val)};
@@ -996,6 +1207,7 @@
return true;
}
}
+ VisitCallArgs(call);
switch (TypeIndexOf(args->at(0))) {
case kInt32:
case kFixnum:
@@ -1019,7 +1231,6 @@
break;
}
}
- VisitCallArgs(call);
return true;
}
@@ -1035,17 +1246,17 @@
Call::CallType call_type = expr->GetCallType(isolate_);
switch (call_type) {
case Call::OTHER_CALL: {
- DCHECK(in_function_);
+ DCHECK_EQ(kFuncScope, scope_);
VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (proxy != nullptr) {
if (VisitStdlibFunction(expr, proxy)) {
return;
}
}
- uint16_t index;
+ uint32_t index;
VariableProxy* vp = expr->expression()->AsVariableProxy();
if (vp != nullptr &&
- Type::Any()->Is(vp->bounds().lower->AsFunction()->Result())) {
+ Type::Any()->Is(bounds_->get(vp).lower->AsFunction()->Result())) {
LocalType return_type = TypeOf(expr);
ZoneList<Expression*>* args = expr->arguments();
FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
@@ -1058,35 +1269,38 @@
}
index =
imported_function_table_.GetFunctionIndex(vp->var(), sig.Build());
+ VisitCallArgs(expr);
+ current_function_builder_->Emit(kExprCallImport);
+ current_function_builder_->EmitVarInt(expr->arguments()->length());
+ current_function_builder_->EmitVarInt(index);
} else {
index = LookupOrInsertFunction(vp->var());
+ VisitCallArgs(expr);
+ current_function_builder_->Emit(kExprCallFunction);
+ current_function_builder_->EmitVarInt(expr->arguments()->length());
+ current_function_builder_->EmitVarInt(index);
}
- current_function_builder_->Emit(kExprCallFunction);
- std::vector<uint8_t> index_arr = UnsignedLEB128From(index);
- current_function_builder_->EmitCode(
- &index_arr[0], static_cast<uint32_t>(index_arr.size()));
break;
}
case Call::KEYED_PROPERTY_CALL: {
- DCHECK(in_function_);
+ DCHECK_EQ(kFuncScope, scope_);
Property* p = expr->expression()->AsProperty();
DCHECK_NOT_NULL(p);
VariableProxy* var = p->obj()->AsVariableProxy();
DCHECK_NOT_NULL(var);
FunctionTableIndices* indices = LookupFunctionTable(var->var());
- current_function_builder_->EmitWithVarInt(kExprCallIndirect,
- indices->signature_index);
- current_function_builder_->Emit(kExprI32Add);
- // TODO(bradnelson): variable size
- byte code[] = {WASM_I32V(indices->start_index)};
- current_function_builder_->EmitCode(code, sizeof(code));
RECURSE(Visit(p->key()));
+ current_function_builder_->EmitI32Const(indices->start_index);
+ current_function_builder_->Emit(kExprI32Add);
+ VisitCallArgs(expr);
+ current_function_builder_->Emit(kExprCallIndirect);
+ current_function_builder_->EmitVarInt(expr->arguments()->length());
+ current_function_builder_->EmitVarInt(indices->signature_index);
break;
}
default:
UNREACHABLE();
}
- VisitCallArgs(expr);
}
void VisitCallNew(CallNew* expr) { UNREACHABLE(); }
@@ -1094,6 +1308,7 @@
void VisitCallRuntime(CallRuntime* expr) { UNREACHABLE(); }
void VisitUnaryOperation(UnaryOperation* expr) {
+ RECURSE(Visit(expr->expression()));
switch (expr->op()) {
case Token::NOT: {
DCHECK_EQ(kAstI32, TypeOf(expr->expression()));
@@ -1103,7 +1318,6 @@
default:
UNREACHABLE();
}
- RECURSE(Visit(expr->expression()));
}
void VisitCountOperation(CountOperation* expr) { UNREACHABLE(); }
@@ -1207,9 +1421,6 @@
#ifdef Mul
#undef Mul
#endif
-#ifdef Div
-#undef Div
-#endif
#define NON_SIGNED_BINOP(op) \
static WasmOpcode opcodes[] = { \
@@ -1249,6 +1460,7 @@
void VisitBinaryOperation(BinaryOperation* expr) {
ConvertOperation convertOperation = MatchBinaryOperation(expr);
if (convertOperation == kToDouble) {
+ RECURSE(Visit(expr->left()));
TypeIndex type = TypeIndexOf(expr->left());
if (type == kInt32 || type == kFixnum) {
current_function_builder_->Emit(kExprF64SConvertI32);
@@ -1259,37 +1471,53 @@
} else {
UNREACHABLE();
}
- RECURSE(Visit(expr->left()));
} else if (convertOperation == kToInt) {
+ RECURSE(Visit(GetLeft(expr)));
TypeIndex type = TypeIndexOf(GetLeft(expr));
if (type == kFloat32) {
- current_function_builder_->Emit(kExprI32SConvertF32);
+ current_function_builder_->Emit(kExprI32AsmjsSConvertF32);
} else if (type == kFloat64) {
- current_function_builder_->Emit(kExprI32SConvertF64);
+ current_function_builder_->Emit(kExprI32AsmjsSConvertF64);
} else {
UNREACHABLE();
}
- RECURSE(Visit(GetLeft(expr)));
} else if (convertOperation == kAsIs) {
RECURSE(Visit(GetLeft(expr)));
} else {
+ if (expr->op() == Token::COMMA) {
+ current_function_builder_->Emit(kExprBlock);
+ }
+
+ RECURSE(Visit(expr->left()));
+ RECURSE(Visit(expr->right()));
+
+ if (expr->op() == Token::COMMA) {
+ current_function_builder_->Emit(kExprEnd);
+ }
+
switch (expr->op()) {
BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true);
BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true);
BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
- BINOP_CASE(Token::DIV, Div, SIGNED_BINOP, false);
BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true);
BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true);
+ case Token::DIV: {
+ static WasmOpcode opcodes[] = {kExprI32AsmjsDivS, kExprI32AsmjsDivU,
+ kExprF32Div, kExprF64Div};
+ int type = TypeIndexOf(expr->left(), expr->right(), false);
+ current_function_builder_->Emit(opcodes[type]);
+ break;
+ }
case Token::MOD: {
TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false);
if (type == kInt32) {
- current_function_builder_->Emit(kExprI32RemS);
+ current_function_builder_->Emit(kExprI32AsmjsRemS);
} else if (type == kUint32) {
- current_function_builder_->Emit(kExprI32RemU);
+ current_function_builder_->Emit(kExprI32AsmjsRemU);
} else if (type == kFloat64) {
current_function_builder_->Emit(kExprF64Mod);
return;
@@ -1299,31 +1527,17 @@
break;
}
case Token::COMMA: {
- current_function_builder_->EmitWithVarInt(kExprBlock, 2);
break;
}
default:
UNREACHABLE();
}
- RECURSE(Visit(expr->left()));
- RECURSE(Visit(expr->right()));
- }
- }
-
- void AddLeb128(uint32_t index, bool is_local) {
- std::vector<uint8_t> index_vec = UnsignedLEB128From(index);
- if (is_local) {
- uint32_t pos_of_index[1] = {0};
- current_function_builder_->EmitCode(
- &index_vec[0], static_cast<uint32_t>(index_vec.size()), pos_of_index,
- 1);
- } else {
- current_function_builder_->EmitCode(
- &index_vec[0], static_cast<uint32_t>(index_vec.size()));
}
}
void VisitCompareOperation(CompareOperation* expr) {
+ RECURSE(Visit(expr->left()));
+ RECURSE(Visit(expr->right()));
switch (expr->op()) {
BINOP_CASE(Token::EQ, Eq, NON_SIGNED_BINOP, false);
BINOP_CASE(Token::LT, Lt, SIGNED_BINOP, false);
@@ -1333,8 +1547,6 @@
default:
UNREACHABLE();
}
- RECURSE(Visit(expr->left()));
- RECURSE(Visit(expr->right()));
}
#undef BINOP_CASE
@@ -1369,8 +1581,8 @@
}
TypeIndex TypeIndexOf(Expression* expr) {
- DCHECK_EQ(expr->bounds().lower, expr->bounds().upper);
- Type* type = expr->bounds().lower;
+ DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper);
+ Type* type = bounds_->get(expr).lower;
if (type->Is(cache_.kAsmFixnum)) {
return kFixnum;
} else if (type->Is(cache_.kAsmSigned)) {
@@ -1422,20 +1634,17 @@
void VisitRewritableExpression(RewritableExpression* expr) { UNREACHABLE(); }
struct IndexContainer : public ZoneObject {
- uint16_t index;
+ uint32_t index;
};
- uint16_t LookupOrInsertLocal(Variable* v, LocalType type) {
+ uint32_t LookupOrInsertLocal(Variable* v, LocalType type) {
DCHECK_NOT_NULL(current_function_builder_);
ZoneHashMap::Entry* entry =
local_variables_.Lookup(v, ComputePointerHash(v));
if (entry == nullptr) {
- uint16_t index;
- if (v->IsParameter()) {
- index = current_function_builder_->AddParam(type);
- } else {
- index = current_function_builder_->AddLocal(type);
- }
+ uint32_t index;
+ DCHECK(!v->IsParameter());
+ index = current_function_builder_->AddLocal(type);
IndexContainer* container = new (zone()) IndexContainer();
container->index = index;
entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
@@ -1445,11 +1654,24 @@
return (reinterpret_cast<IndexContainer*>(entry->value))->index;
}
- uint16_t LookupOrInsertGlobal(Variable* v, LocalType type) {
+ void InsertParameter(Variable* v, LocalType type, uint32_t index) {
+ DCHECK(v->IsParameter());
+ DCHECK_NOT_NULL(current_function_builder_);
+ ZoneHashMap::Entry* entry =
+ local_variables_.Lookup(v, ComputePointerHash(v));
+ DCHECK_NULL(entry);
+ IndexContainer* container = new (zone()) IndexContainer();
+ container->index = index;
+ entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
+ ZoneAllocationPolicy(zone()));
+ entry->value = container;
+ }
+
+ uint32_t LookupOrInsertGlobal(Variable* v, LocalType type) {
ZoneHashMap::Entry* entry =
global_variables_.Lookup(v, ComputePointerHash(v));
if (entry == nullptr) {
- uint16_t index =
+ uint32_t index =
builder_->AddGlobal(WasmOpcodes::MachineTypeFor(type), 0);
IndexContainer* container = new (zone()) IndexContainer();
container->index = index;
@@ -1460,11 +1682,11 @@
return (reinterpret_cast<IndexContainer*>(entry->value))->index;
}
- uint16_t LookupOrInsertFunction(Variable* v) {
+ uint32_t LookupOrInsertFunction(Variable* v) {
DCHECK_NOT_NULL(builder_);
ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
if (entry == nullptr) {
- uint16_t index = builder_->AddFunction();
+ uint32_t index = builder_->AddFunction();
IndexContainer* container = new (zone()) IndexContainer();
container->index = index;
entry = functions_.LookupOrInsert(v, ComputePointerHash(v),
@@ -1475,8 +1697,8 @@
}
LocalType TypeOf(Expression* expr) {
- DCHECK_EQ(expr->bounds().lower, expr->bounds().upper);
- return TypeFrom(expr->bounds().lower);
+ DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper);
+ return TypeFrom(bounds_->get(expr).lower);
}
LocalType TypeFrom(Type* type) {
@@ -1496,9 +1718,7 @@
ZoneHashMap local_variables_;
ZoneHashMap functions_;
ZoneHashMap global_variables_;
- bool in_function_;
- bool is_set_op_;
- bool marking_exported;
+ AsmScope scope_;
WasmModuleBuilder* builder_;
WasmFunctionBuilder* current_function_builder_;
FunctionLiteral* literal_;
@@ -1508,11 +1728,11 @@
AsmTyper* typer_;
TypeCache const& cache_;
ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
- int block_size_;
- uint16_t init_function_index_;
+ uint32_t init_function_index_;
uint32_t next_table_index_;
ZoneHashMap function_tables_;
ImportedFunctionTable imported_function_table_;
+ const AstTypeBounds* bounds_;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();