Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(589)

Unified Diff: src/wasm/asm-wasm-builder.cc

Issue 2057403003: Hooking up asm-wasm conversion. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: fix Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/wasm/asm-wasm-builder.h ('k') | src/wasm/wasm-js.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/wasm/asm-wasm-builder.cc
diff --git a/src/wasm/asm-wasm-builder.cc b/src/wasm/asm-wasm-builder.cc
deleted file mode 100644
index 8764a81dc4206750d21da7f5bdbfcb6dfa4f7aa9..0000000000000000000000000000000000000000
--- a/src/wasm/asm-wasm-builder.cc
+++ /dev/null
@@ -1,1785 +0,0 @@
-// Copyright 2015 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/v8.h"
-
-// Required to get M_E etc. in MSVC.
-#if defined(_WIN32)
-#define _USE_MATH_DEFINES
-#endif
-#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"
-
-#include "src/ast/ast.h"
-#include "src/ast/scopes.h"
-#include "src/codegen.h"
-#include "src/type-cache.h"
-
-namespace v8 {
-namespace internal {
-namespace wasm {
-
-#define RECURSE(call) \
- do { \
- DCHECK(!HasStackOverflow()); \
- call; \
- if (HasStackOverflow()) return; \
- } while (false)
-
-enum AsmScope { kModuleScope, kInitScope, kFuncScope, kExportScope };
-
-struct ForeignVariable {
- Handle<Name> name;
- Variable* var;
- LocalType type;
-};
-
-class AsmWasmBuilderImpl : public AstVisitor {
- public:
- AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal,
- AsmTyper* typer)
- : local_variables_(base::HashMap::PointersMatch,
- ZoneHashMap::kDefaultHashMapCapacity,
- ZoneAllocationPolicy(zone)),
- functions_(base::HashMap::PointersMatch,
- ZoneHashMap::kDefaultHashMapCapacity,
- ZoneAllocationPolicy(zone)),
- global_variables_(base::HashMap::PointersMatch,
- ZoneHashMap::kDefaultHashMapCapacity,
- ZoneAllocationPolicy(zone)),
- scope_(kModuleScope),
- builder_(new (zone) WasmModuleBuilder(zone)),
- current_function_builder_(nullptr),
- literal_(literal),
- isolate_(isolate),
- zone_(zone),
- typer_(typer),
- cache_(TypeCache::Get()),
- breakable_blocks_(zone),
- foreign_variables_(zone),
- init_function_index_(0),
- foreign_init_function_index_(0),
- next_table_index_(0),
- function_tables_(base::HashMap::PointersMatch,
- ZoneHashMap::kDefaultHashMapCapacity,
- ZoneAllocationPolicy(zone)),
- 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_->SetSignature(b.Build());
- builder_->MarkStartFunction(init_function_index_);
- current_function_builder_ = nullptr;
- }
-
- void BuildForeignInitFunction() {
- foreign_init_function_index_ = builder_->AddFunction();
- FunctionSig::Builder b(zone(), 0, foreign_variables_.size());
- for (auto i = foreign_variables_.begin(); i != foreign_variables_.end();
- ++i) {
- b.AddParam(i->type);
- }
- current_function_builder_ =
- builder_->FunctionAt(foreign_init_function_index_);
- current_function_builder_->SetExported();
- std::string raw_name = "__foreign_init__";
- current_function_builder_->SetName(raw_name.data(),
- static_cast<int>(raw_name.size()));
- current_function_builder_->SetSignature(b.Build());
- for (size_t pos = 0; pos < foreign_variables_.size(); ++pos) {
- current_function_builder_->EmitGetLocal(static_cast<uint32_t>(pos));
- ForeignVariable* fv = &foreign_variables_[pos];
- uint32_t index = LookupOrInsertGlobal(fv->var, fv->type);
- current_function_builder_->EmitWithVarInt(kExprStoreGlobal, index);
- }
- current_function_builder_ = nullptr;
- }
-
- i::Handle<i::FixedArray> GetForeignArgs() {
- i::Handle<FixedArray> ret = isolate_->factory()->NewFixedArray(
- static_cast<int>(foreign_variables_.size()));
- for (size_t i = 0; i < foreign_variables_.size(); ++i) {
- ForeignVariable* fv = &foreign_variables_[i];
- ret->set(static_cast<int>(i), *fv->name);
- }
- return ret;
- }
-
- void Build() {
- InitializeInitFunction();
- RECURSE(VisitFunctionLiteral(literal_));
- BuildForeignInitFunction();
- }
-
- void VisitVariableDeclaration(VariableDeclaration* decl) override {}
-
- void VisitFunctionDeclaration(FunctionDeclaration* decl) override {
- DCHECK_EQ(kModuleScope, scope_);
- DCHECK_NULL(current_function_builder_);
- uint32_t index = LookupOrInsertFunction(decl->proxy()->var());
- current_function_builder_ = builder_->FunctionAt(index);
- scope_ = kFuncScope;
- RECURSE(Visit(decl->fun()));
- scope_ = kModuleScope;
- current_function_builder_ = nullptr;
- local_variables_.Clear();
- }
-
- void VisitImportDeclaration(ImportDeclaration* decl) override {}
-
- void VisitStatements(ZoneList<Statement*>* stmts) override {
- 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;
- }
- }
-
- void VisitBlock(Block* stmt) override {
- if (stmt->statements()->length() == 1) {
- ExpressionStatement* expr =
- stmt->statements()->at(0)->AsExpressionStatement();
- if (expr != nullptr) {
- if (expr->expression()->IsAssignment()) {
- RECURSE(VisitExpressionStatement(expr));
- return;
- }
- }
- }
- if (scope_ == kFuncScope) {
- BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
- false);
- RECURSE(VisitStatements(stmt->statements()));
- } else {
- RECURSE(VisitStatements(stmt->statements()));
- }
- }
-
- class BlockVisitor {
- private:
- AsmWasmBuilderImpl* builder_;
-
- public:
- BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
- WasmOpcode opcode, bool is_loop)
- : builder_(builder) {
- builder_->breakable_blocks_.push_back(std::make_pair(stmt, is_loop));
- builder_->current_function_builder_->Emit(opcode);
- }
- ~BlockVisitor() {
- builder_->current_function_builder_->Emit(kExprEnd);
- builder_->breakable_blocks_.pop_back();
- }
- };
-
- void VisitExpressionStatement(ExpressionStatement* stmt) override {
- RECURSE(Visit(stmt->expression()));
- }
-
- void VisitEmptyStatement(EmptyStatement* stmt) override {}
-
- void VisitEmptyParentheses(EmptyParentheses* paren) override {
- UNREACHABLE();
- }
-
- void VisitIfStatement(IfStatement* stmt) override {
- 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()));
- }
- 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) override {
- DCHECK_EQ(kFuncScope, scope_);
- DCHECK_NOT_NULL(stmt->target());
- int i = static_cast<int>(breakable_blocks_.size()) - 1;
- int block_distance = 0;
- for (; i >= 0; i--) {
- auto elem = breakable_blocks_.at(i);
- if (elem.first == stmt->target()) {
- DCHECK(elem.second);
- break;
- } else if (elem.second) {
- block_distance += 2;
- } else {
- block_distance += 1;
- }
- }
- DCHECK(i >= 0);
- current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
- current_function_builder_->EmitVarInt(block_distance);
- }
-
- void VisitBreakStatement(BreakStatement* stmt) override {
- DCHECK_EQ(kFuncScope, scope_);
- DCHECK_NOT_NULL(stmt->target());
- int i = static_cast<int>(breakable_blocks_.size()) - 1;
- int block_distance = 0;
- for (; i >= 0; i--) {
- auto elem = breakable_blocks_.at(i);
- if (elem.first == stmt->target()) {
- if (elem.second) {
- block_distance++;
- }
- break;
- } else if (elem.second) {
- block_distance += 2;
- } else {
- block_distance += 1;
- }
- }
- DCHECK(i >= 0);
- current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
- current_function_builder_->EmitVarInt(block_distance);
- }
-
- void VisitReturnStatement(ReturnStatement* stmt) override {
- 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 {
- UNREACHABLE();
- }
- }
-
- void VisitWithStatement(WithStatement* stmt) override { UNREACHABLE(); }
-
- 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));
- }
-
- while (if_depth-- != prev_if_depth) {
- breakable_blocks_.pop_back();
- current_function_builder_->Emit(kExprEnd);
- }
- }
-
- void VisitSwitchStatement(SwitchStatement* stmt) override {
- VariableProxy* tag = stmt->tag()->AsVariableProxy();
- DCHECK_NOT_NULL(tag);
- ZoneList<CaseClause*>* clauses = stmt->cases();
- 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()) {
- 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 {
- 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) override { UNREACHABLE(); }
-
- void VisitDoWhileStatement(DoWhileStatement* stmt) override {
- DCHECK_EQ(kFuncScope, scope_);
- BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
- RECURSE(Visit(stmt->body()));
- RECURSE(Visit(stmt->cond()));
- current_function_builder_->Emit(kExprIf);
- current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
- current_function_builder_->Emit(kExprEnd);
- }
-
- void VisitWhileStatement(WhileStatement* stmt) override {
- DCHECK_EQ(kFuncScope, scope_);
- BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
- RECURSE(Visit(stmt->cond()));
- 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) override {
- DCHECK_EQ(kFuncScope, scope_);
- if (stmt->init() != nullptr) {
- RECURSE(Visit(stmt->init()));
- }
- BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
- if (stmt->cond() != nullptr) {
- RECURSE(Visit(stmt->cond()));
- 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) {
- RECURSE(Visit(stmt->body()));
- }
- if (stmt->next() != nullptr) {
- RECURSE(Visit(stmt->next()));
- }
- current_function_builder_->Emit(kExprNop);
- current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 0);
- }
-
- void VisitForInStatement(ForInStatement* stmt) override { UNREACHABLE(); }
-
- void VisitForOfStatement(ForOfStatement* stmt) override { UNREACHABLE(); }
-
- void VisitTryCatchStatement(TryCatchStatement* stmt) override {
- UNREACHABLE();
- }
-
- void VisitTryFinallyStatement(TryFinallyStatement* stmt) override {
- UNREACHABLE();
- }
-
- void VisitDebuggerStatement(DebuggerStatement* stmt) override {
- UNREACHABLE();
- }
-
- void VisitFunctionLiteral(FunctionLiteral* expr) override {
- Scope* scope = expr->scope();
- 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());
- 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);
- b.AddParam(type);
- InsertParameter(scope->parameter(i), type, i);
- }
- current_function_builder_->SetSignature(b.Build());
- } else {
- UNREACHABLE();
- }
- }
- RECURSE(VisitStatements(expr->body()));
- RECURSE(VisitDeclarations(scope->declarations()));
- }
-
- void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) override {
- UNREACHABLE();
- }
-
- void VisitConditional(Conditional* expr) override {
- 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) {
- AsmTyper::StandardMember standard_object =
- typer_->VariableAsStandardMember(var);
- double value;
- switch (standard_object) {
- case AsmTyper::kInfinity: {
- value = std::numeric_limits<double>::infinity();
- break;
- }
- case AsmTyper::kNaN: {
- value = std::numeric_limits<double>::quiet_NaN();
- break;
- }
- case AsmTyper::kMathE: {
- value = M_E;
- break;
- }
- case AsmTyper::kMathLN10: {
- value = M_LN10;
- break;
- }
- case AsmTyper::kMathLN2: {
- value = M_LN2;
- break;
- }
- case AsmTyper::kMathLOG10E: {
- value = M_LOG10E;
- break;
- }
- case AsmTyper::kMathLOG2E: {
- value = M_LOG2E;
- break;
- }
- case AsmTyper::kMathPI: {
- value = M_PI;
- break;
- }
- case AsmTyper::kMathSQRT1_2: {
- value = M_SQRT1_2;
- break;
- }
- case AsmTyper::kMathSQRT2: {
- value = M_SQRT2;
- break;
- }
- default: { return false; }
- }
- byte code[] = {WASM_F64(value)};
- current_function_builder_->EmitCode(code, sizeof(code));
- return true;
- }
-
- void VisitVariableProxy(VariableProxy* expr) override {
- if (scope_ == kFuncScope || scope_ == kInitScope) {
- Variable* var = expr->var();
- if (VisitStdlibConstant(var)) {
- return;
- }
- LocalType var_type = TypeOf(expr);
- DCHECK_NE(kAstStmt, var_type);
- if (var->IsContextSlot()) {
- current_function_builder_->EmitWithVarInt(
- kExprLoadGlobal, LookupOrInsertGlobal(var, var_type));
- } else {
- current_function_builder_->EmitGetLocal(
- LookupOrInsertLocal(var, var_type));
- }
- }
- }
-
- void VisitLiteral(Literal* expr) override {
- Handle<Object> value = expr->value();
- if (!value->IsNumber() || (scope_ != kFuncScope && scope_ != kInitScope)) {
- return;
- }
- Type* type = bounds_->get(expr).upper;
- if (type->Is(cache_.kAsmSigned)) {
- int32_t i = 0;
- if (!value->ToInt32(&i)) {
- UNREACHABLE();
- }
- byte code[] = {WASM_I32V(i)};
- current_function_builder_->EmitCode(code, sizeof(code));
- } else if (type->Is(cache_.kAsmUnsigned) || type->Is(cache_.kAsmFixnum)) {
- uint32_t u = 0;
- if (!value->ToUint32(&u)) {
- UNREACHABLE();
- }
- int32_t i = static_cast<int32_t>(u);
- byte code[] = {WASM_I32V(i)};
- current_function_builder_->EmitCode(code, sizeof(code));
- } else if (type->Is(cache_.kAsmDouble)) {
- double val = expr->raw_value()->AsNumber();
- byte code[] = {WASM_F64(val)};
- current_function_builder_->EmitCode(code, sizeof(code));
- } else {
- UNREACHABLE();
- }
- }
-
- void VisitRegExpLiteral(RegExpLiteral* expr) override { UNREACHABLE(); }
-
- void VisitObjectLiteral(ObjectLiteral* expr) override {
- ZoneList<ObjectLiteralProperty*>* props = expr->properties();
- for (int i = 0; i < props->length(); ++i) {
- ObjectLiteralProperty* prop = props->at(i);
- DCHECK_EQ(kExportScope, scope_);
- VariableProxy* expr = prop->value()->AsVariableProxy();
- DCHECK_NOT_NULL(expr);
- Variable* var = expr->var();
- Literal* name = prop->key()->AsLiteral();
- DCHECK_NOT_NULL(name);
- DCHECK(name->IsPropertyName());
- const AstRawString* raw_name = name->AsRawPropertyName();
- if (var->is_function()) {
- uint32_t index = LookupOrInsertFunction(var);
- builder_->FunctionAt(index)->SetExported();
- builder_->FunctionAt(index)->SetName(
- reinterpret_cast<const char*>(raw_name->raw_data()),
- raw_name->length());
- }
- }
- }
-
- void VisitArrayLiteral(ArrayLiteral* expr) override { UNREACHABLE(); }
-
- void LoadInitFunction() {
- current_function_builder_ = builder_->FunctionAt(init_function_index_);
- scope_ = kInitScope;
- }
-
- void UnLoadInitFunction() {
- scope_ = kModuleScope;
- current_function_builder_ = nullptr;
- }
-
- void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) {
- FunctionType* func_type =
- 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());
- if (return_type != kAstStmt) {
- sig.AddReturn(static_cast<LocalType>(return_type));
- }
- for (int i = 0; i < func_type->Arity(); ++i) {
- sig.AddParam(TypeFrom(func_type->Parameter(i)));
- }
- 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) {
- VariableProxy* func = funcs->values()->at(i)->AsVariableProxy();
- DCHECK_NOT_NULL(func);
- builder_->AddIndirectFunction(LookupOrInsertFunction(func->var()));
- }
- }
-
- struct FunctionTableIndices : public ZoneObject {
- uint32_t start_index;
- uint32_t signature_index;
- };
-
- void InsertFunctionTable(Variable* v, uint32_t start_index,
- uint32_t signature_index) {
- FunctionTableIndices* container = new (zone()) FunctionTableIndices();
- container->start_index = start_index;
- container->signature_index = signature_index;
- ZoneHashMap::Entry* entry = function_tables_.LookupOrInsert(
- v, ComputePointerHash(v), ZoneAllocationPolicy(zone()));
- entry->value = container;
- }
-
- FunctionTableIndices* LookupFunctionTable(Variable* v) {
- ZoneHashMap::Entry* entry =
- function_tables_.Lookup(v, ComputePointerHash(v));
- DCHECK_NOT_NULL(entry);
- return reinterpret_cast<FunctionTableIndices*>(entry->value);
- }
-
- class ImportedFunctionTable {
- private:
- class ImportedFunctionIndices : public ZoneObject {
- public:
- const char* name_;
- int name_length_;
- WasmModuleBuilder::SignatureMap signature_to_index_;
-
- ImportedFunctionIndices(const char* name, int name_length, Zone* zone)
- : name_(name), name_length_(name_length), signature_to_index_(zone) {}
- };
- ZoneHashMap table_;
- AsmWasmBuilderImpl* builder_;
-
- public:
- explicit ImportedFunctionTable(AsmWasmBuilderImpl* builder)
- : table_(base::HashMap::PointersMatch,
- ZoneHashMap::kDefaultHashMapCapacity,
- ZoneAllocationPolicy(builder->zone())),
- builder_(builder) {}
-
- 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(
- v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone()));
- entry->value = indices;
- }
-
- uint32_t GetFunctionIndex(Variable* v, FunctionSig* sig) {
- ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v));
- DCHECK_NOT_NULL(entry);
- ImportedFunctionIndices* indices =
- reinterpret_cast<ImportedFunctionIndices*>(entry->value);
- WasmModuleBuilder::SignatureMap::iterator pos =
- indices->signature_to_index_.find(sig);
- if (pos != indices->signature_to_index_.end()) {
- return pos->second;
- } else {
- uint32_t index = builder_->builder_->AddImport(
- indices->name_, indices->name_length_, sig);
- indices->signature_to_index_[sig] = index;
- return index;
- }
- }
- };
-
- 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();
- 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());
- DCHECK(target->IsVariableProxy());
- VisitForeignVariable(true, target->AsVariableProxy()->var(), prop);
- *is_nop = true;
- 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());
- DCHECK(target->IsVariableProxy());
- VisitForeignVariable(false, target->AsVariableProxy()->var(), prop);
- *is_nop = true;
- return;
- } else {
- UNREACHABLE();
- }
- }
- 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) override {
- 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 (bounds_->get(target).lower->Is(Type::Function())) {
- const AstRawString* name =
- prop->key()->AsLiteral()->AsRawPropertyName();
- 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.
- return;
- }
- ArrayLiteral* funcs = expr->value()->AsArrayLiteral();
- if (funcs != nullptr &&
- bounds_->get(funcs).lower->AsArray()->Element()->IsFunction()) {
- VariableProxy* target = expr->target()->AsVariableProxy();
- DCHECK_NOT_NULL(target);
- AddFunctionTable(target, funcs);
- // Only add to the function table. No init needed.
- return;
- }
- if (expr->value()->IsCallNew()) {
- // No init code to emit for CallNew nodes.
- return;
- }
- as_init = true;
- }
-
- 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);
- }
- if (as_init) UnLoadInitFunction();
- }
-
- void VisitYield(Yield* expr) override { UNREACHABLE(); }
-
- void VisitThrow(Throw* expr) override { UNREACHABLE(); }
-
- void VisitForeignVariable(bool is_float, Variable* var, Property* expr) {
- DCHECK(expr->obj()->AsVariableProxy());
- DCHECK(VariableLocation::PARAMETER ==
- expr->obj()->AsVariableProxy()->var()->location());
- DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index());
- Literal* key_literal = expr->key()->AsLiteral();
- DCHECK_NOT_NULL(key_literal);
- if (!key_literal->value().is_null()) {
- Handle<Name> name =
- i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked();
- LocalType type = is_float ? kAstF64 : kAstI32;
- foreign_variables_.push_back({name, var, type});
- }
- }
-
- void VisitPropertyAndEmitIndex(Property* expr, MachineType* mtype) {
- Expression* obj = expr->obj();
- 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();
- size = 1;
- } else if (type->Is(cache_.kInt8Array)) {
- *mtype = MachineType::Int8();
- size = 1;
- } else if (type->Is(cache_.kUint16Array)) {
- *mtype = MachineType::Uint16();
- size = 2;
- } else if (type->Is(cache_.kInt16Array)) {
- *mtype = MachineType::Int16();
- size = 2;
- } else if (type->Is(cache_.kUint32Array)) {
- *mtype = MachineType::Uint32();
- size = 4;
- } else if (type->Is(cache_.kInt32Array)) {
- *mtype = MachineType::Int32();
- size = 4;
- } else if (type->Is(cache_.kUint32Array)) {
- *mtype = MachineType::Uint32();
- size = 4;
- } else if (type->Is(cache_.kFloat32Array)) {
- *mtype = MachineType::Float32();
- size = 4;
- } else if (type->Is(cache_.kFloat64Array)) {
- *mtype = MachineType::Float64();
- size = 8;
- } else {
- UNREACHABLE();
- }
- if (size == 1) {
- // Allow more general expression in byte arrays than the spec
- // strictly permits.
- // Early versions of Emscripten emit HEAP8[HEAP32[..]|0] in
- // places that strictly should be HEAP8[HEAP32[..]>>0].
- RECURSE(Visit(expr->key()));
- 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) override {
- 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) {
- current_function_builder_->Emit(kExprF64Ceil);
- } else {
- UNREACHABLE();
- }
- break;
- }
- case AsmTyper::kMathFloor: {
- VisitCallArgs(call);
- if (call_type == kAstF32) {
- current_function_builder_->Emit(kExprF32Floor);
- } else if (call_type == kAstF64) {
- current_function_builder_->Emit(kExprF64Floor);
- } else {
- UNREACHABLE();
- }
- break;
- }
- case AsmTyper::kMathSqrt: {
- VisitCallArgs(call);
- if (call_type == kAstF32) {
- current_function_builder_->Emit(kExprF32Sqrt);
- } else if (call_type == kAstF64) {
- current_function_builder_->Emit(kExprF64Sqrt);
- } else {
- UNREACHABLE();
- }
- break;
- }
- case AsmTyper::kMathAbs: {
- if (call_type == kAstI32) {
- 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(kExprI32LtS);
- current_function_builder_->Emit(kExprIf);
-
- // then (0 - tmp)
- current_function_builder_->EmitCode(code, sizeof(code));
- 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();
- }
- break;
- }
- case AsmTyper::kMathMin: {
- // TODO(bradnelson): Change wasm to match Math.min in asm.js mode.
- if (call_type == kAstI32) {
- 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_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();
- }
- break;
- }
- case AsmTyper::kMathMax: {
- // TODO(bradnelson): Change wasm to match Math.max in asm.js mode.
- if (call_type == kAstI32) {
- 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();
- }
- 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;
- }
- case AsmTyper::kMathFround: {
- 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)};
- current_function_builder_->EmitCode(code, sizeof(code));
- return true;
- }
- }
- VisitCallArgs(call);
- switch (TypeIndexOf(args->at(0))) {
- case kInt32:
- case kFixnum:
- current_function_builder_->Emit(kExprF32SConvertI32);
- break;
- case kUint32:
- current_function_builder_->Emit(kExprF32UConvertI32);
- break;
- case kFloat32:
- break;
- case kFloat64:
- current_function_builder_->Emit(kExprF32ConvertF64);
- break;
- default:
- UNREACHABLE();
- }
- break;
- }
- default: {
- UNREACHABLE();
- break;
- }
- }
- return true;
- }
-
- void VisitCallArgs(Call* expr) {
- ZoneList<Expression*>* args = expr->arguments();
- for (int i = 0; i < args->length(); ++i) {
- Expression* arg = args->at(i);
- RECURSE(Visit(arg));
- }
- }
-
- void VisitCall(Call* expr) override {
- Call::CallType call_type = expr->GetCallType(isolate_);
- switch (call_type) {
- case Call::OTHER_CALL: {
- DCHECK_EQ(kFuncScope, scope_);
- VariableProxy* proxy = expr->expression()->AsVariableProxy();
- if (proxy != nullptr) {
- if (VisitStdlibFunction(expr, proxy)) {
- return;
- }
- }
- uint32_t index;
- VariableProxy* vp = expr->expression()->AsVariableProxy();
- if (vp != nullptr &&
- 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,
- args->length());
- if (return_type != kAstStmt) {
- sig.AddReturn(return_type);
- }
- for (int i = 0; i < args->length(); ++i) {
- sig.AddParam(TypeOf(args->at(i)));
- }
- 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);
- }
- break;
- }
- case Call::KEYED_PROPERTY_CALL: {
- 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());
- 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();
- }
- }
-
- void VisitCallNew(CallNew* expr) override { UNREACHABLE(); }
-
- void VisitCallRuntime(CallRuntime* expr) override { UNREACHABLE(); }
-
- void VisitUnaryOperation(UnaryOperation* expr) override {
- RECURSE(Visit(expr->expression()));
- switch (expr->op()) {
- case Token::NOT: {
- DCHECK_EQ(kAstI32, TypeOf(expr->expression()));
- current_function_builder_->Emit(kExprI32Eqz);
- break;
- }
- default:
- UNREACHABLE();
- }
- }
-
- void VisitCountOperation(CountOperation* expr) override { UNREACHABLE(); }
-
- bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op,
- int32_t val) {
- DCHECK_NOT_NULL(expr->right());
- if (expr->op() == op && expr->right()->IsLiteral() &&
- TypeOf(expr) == kAstI32) {
- Literal* right = expr->right()->AsLiteral();
- DCHECK(right->raw_value()->IsNumber());
- if (static_cast<int32_t>(right->raw_value()->AsNumber()) == val) {
- return true;
- }
- }
- return false;
- }
-
- bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op,
- double val) {
- DCHECK_NOT_NULL(expr->right());
- if (expr->op() == op && expr->right()->IsLiteral() &&
- TypeOf(expr) == kAstF64) {
- Literal* right = expr->right()->AsLiteral();
- DCHECK(right->raw_value()->IsNumber());
- if (right->raw_value()->AsNumber() == val) {
- return true;
- }
- }
- return false;
- }
-
- enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble };
-
- ConvertOperation MatchOr(BinaryOperation* expr) {
- if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) &&
- (TypeOf(expr->left()) == kAstI32)) {
- return kAsIs;
- } else {
- return kNone;
- }
- }
-
- ConvertOperation MatchShr(BinaryOperation* expr) {
- if (MatchIntBinaryOperation(expr, Token::SHR, 0)) {
- // TODO(titzer): this probably needs to be kToUint
- return (TypeOf(expr->left()) == kAstI32) ? kAsIs : kToInt;
- } else {
- return kNone;
- }
- }
-
- ConvertOperation MatchXor(BinaryOperation* expr) {
- if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) {
- DCHECK_EQ(kAstI32, TypeOf(expr->left()));
- DCHECK_EQ(kAstI32, TypeOf(expr->right()));
- BinaryOperation* op = expr->left()->AsBinaryOperation();
- if (op != nullptr) {
- if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) {
- DCHECK_EQ(kAstI32, TypeOf(op->right()));
- if (TypeOf(op->left()) != kAstI32) {
- return kToInt;
- } else {
- return kAsIs;
- }
- }
- }
- }
- return kNone;
- }
-
- ConvertOperation MatchMul(BinaryOperation* expr) {
- if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) {
- DCHECK_EQ(kAstF64, TypeOf(expr->right()));
- if (TypeOf(expr->left()) != kAstF64) {
- return kToDouble;
- } else {
- return kAsIs;
- }
- } else {
- return kNone;
- }
- }
-
- ConvertOperation MatchBinaryOperation(BinaryOperation* expr) {
- switch (expr->op()) {
- case Token::BIT_OR:
- return MatchOr(expr);
- case Token::SHR:
- return MatchShr(expr);
- case Token::BIT_XOR:
- return MatchXor(expr);
- case Token::MUL:
- return MatchMul(expr);
- default:
- return kNone;
- }
- }
-
-// Work around Mul + Div being defined in PPC assembler.
-#ifdef Mul
-#undef Mul
-#endif
-
-#define NON_SIGNED_BINOP(op) \
- static WasmOpcode opcodes[] = { \
- kExprI32##op, \
- kExprI32##op, \
- kExprF32##op, \
- kExprF64##op \
- }
-
-#define SIGNED_BINOP(op) \
- static WasmOpcode opcodes[] = { \
- kExprI32##op##S, \
- kExprI32##op##U, \
- kExprF32##op, \
- kExprF64##op \
- }
-
-#define NON_SIGNED_INT_BINOP(op) \
- static WasmOpcode opcodes[] = { kExprI32##op, kExprI32##op }
-
-#define BINOP_CASE(token, op, V, ignore_sign) \
- case token: { \
- V(op); \
- int type = TypeIndexOf(expr->left(), expr->right(), ignore_sign); \
- current_function_builder_->Emit(opcodes[type]); \
- break; \
- }
-
- Expression* GetLeft(BinaryOperation* expr) {
- if (expr->op() == Token::BIT_XOR) {
- return expr->left()->AsBinaryOperation()->left();
- } else {
- return expr->left();
- }
- }
-
- void VisitBinaryOperation(BinaryOperation* expr) override {
- 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);
- } else if (type == kUint32) {
- current_function_builder_->Emit(kExprF64UConvertI32);
- } else if (type == kFloat32) {
- current_function_builder_->Emit(kExprF64ConvertF32);
- } else {
- UNREACHABLE();
- }
- } else if (convertOperation == kToInt) {
- RECURSE(Visit(GetLeft(expr)));
- TypeIndex type = TypeIndexOf(GetLeft(expr));
- if (type == kFloat32) {
- current_function_builder_->Emit(kExprI32AsmjsSConvertF32);
- } else if (type == kFloat64) {
- current_function_builder_->Emit(kExprI32AsmjsSConvertF64);
- } else {
- UNREACHABLE();
- }
- } 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::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(kExprI32AsmjsRemS);
- } else if (type == kUint32) {
- current_function_builder_->Emit(kExprI32AsmjsRemU);
- } else if (type == kFloat64) {
- current_function_builder_->Emit(kExprF64Mod);
- return;
- } else {
- UNREACHABLE();
- }
- break;
- }
- case Token::COMMA: {
- break;
- }
- default:
- UNREACHABLE();
- }
- }
- }
-
- void VisitCompareOperation(CompareOperation* expr) override {
- 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);
- BINOP_CASE(Token::LTE, Le, SIGNED_BINOP, false);
- BINOP_CASE(Token::GT, Gt, SIGNED_BINOP, false);
- BINOP_CASE(Token::GTE, Ge, SIGNED_BINOP, false);
- default:
- UNREACHABLE();
- }
- }
-
-#undef BINOP_CASE
-#undef NON_SIGNED_INT_BINOP
-#undef SIGNED_BINOP
-#undef NON_SIGNED_BINOP
-
- enum TypeIndex {
- kInt32 = 0,
- kUint32 = 1,
- kFloat32 = 2,
- kFloat64 = 3,
- kFixnum = 4
- };
-
- TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) {
- TypeIndex left_index = TypeIndexOf(left);
- TypeIndex right_index = TypeIndexOf(right);
- if (left_index == kFixnum) {
- left_index = right_index;
- }
- if (right_index == kFixnum) {
- right_index = left_index;
- }
- if (left_index == kFixnum && right_index == kFixnum) {
- left_index = kInt32;
- right_index = kInt32;
- }
- DCHECK((left_index == right_index) ||
- (ignore_sign && (left_index <= 1) && (right_index <= 1)));
- return left_index;
- }
-
- TypeIndex TypeIndexOf(Expression* expr) {
- 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)) {
- return kInt32;
- } else if (type->Is(cache_.kAsmUnsigned)) {
- return kUint32;
- } else if (type->Is(cache_.kAsmInt)) {
- return kInt32;
- } else if (type->Is(cache_.kAsmFloat)) {
- return kFloat32;
- } else if (type->Is(cache_.kAsmDouble)) {
- return kFloat64;
- } else {
- UNREACHABLE();
- return kInt32;
- }
- }
-
-#undef CASE
-#undef NON_SIGNED_INT
-#undef SIGNED
-#undef NON_SIGNED
-
- void VisitThisFunction(ThisFunction* expr) override { UNREACHABLE(); }
-
- void VisitDeclarations(ZoneList<Declaration*>* decls) override {
- for (int i = 0; i < decls->length(); ++i) {
- Declaration* decl = decls->at(i);
- RECURSE(Visit(decl));
- }
- }
-
- void VisitClassLiteral(ClassLiteral* expr) override { UNREACHABLE(); }
-
- void VisitSpread(Spread* expr) override { UNREACHABLE(); }
-
- void VisitSuperPropertyReference(SuperPropertyReference* expr) override {
- UNREACHABLE();
- }
-
- void VisitSuperCallReference(SuperCallReference* expr) override {
- UNREACHABLE();
- }
-
- void VisitSloppyBlockFunctionStatement(
- SloppyBlockFunctionStatement* expr) override {
- UNREACHABLE();
- }
-
- void VisitDoExpression(DoExpression* expr) override { UNREACHABLE(); }
-
- void VisitRewritableExpression(RewritableExpression* expr) override {
- UNREACHABLE();
- }
-
- struct IndexContainer : public ZoneObject {
- uint32_t index;
- };
-
- 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) {
- 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),
- ZoneAllocationPolicy(zone()));
- entry->value = container;
- }
- return (reinterpret_cast<IndexContainer*>(entry->value))->index;
- }
-
- 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) {
- uint32_t index =
- builder_->AddGlobal(WasmOpcodes::MachineTypeFor(type), 0);
- IndexContainer* container = new (zone()) IndexContainer();
- container->index = index;
- entry = global_variables_.LookupOrInsert(v, ComputePointerHash(v),
- ZoneAllocationPolicy(zone()));
- entry->value = container;
- }
- return (reinterpret_cast<IndexContainer*>(entry->value))->index;
- }
-
- uint32_t LookupOrInsertFunction(Variable* v) {
- DCHECK_NOT_NULL(builder_);
- ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
- if (entry == nullptr) {
- uint32_t index = builder_->AddFunction();
- IndexContainer* container = new (zone()) IndexContainer();
- container->index = index;
- entry = functions_.LookupOrInsert(v, ComputePointerHash(v),
- ZoneAllocationPolicy(zone()));
- entry->value = container;
- }
- return (reinterpret_cast<IndexContainer*>(entry->value))->index;
- }
-
- LocalType TypeOf(Expression* expr) {
- DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper);
- return TypeFrom(bounds_->get(expr).lower);
- }
-
- LocalType TypeFrom(Type* type) {
- if (type->Is(cache_.kAsmInt)) {
- return kAstI32;
- } else if (type->Is(cache_.kAsmFloat)) {
- return kAstF32;
- } else if (type->Is(cache_.kAsmDouble)) {
- return kAstF64;
- } else {
- return kAstStmt;
- }
- }
-
- Zone* zone() { return zone_; }
-
- ZoneHashMap local_variables_;
- ZoneHashMap functions_;
- ZoneHashMap global_variables_;
- AsmScope scope_;
- WasmModuleBuilder* builder_;
- WasmFunctionBuilder* current_function_builder_;
- FunctionLiteral* literal_;
- Isolate* isolate_;
- Zone* zone_;
- AsmTyper* typer_;
- TypeCache const& cache_;
- ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
- ZoneVector<ForeignVariable> foreign_variables_;
- uint32_t init_function_index_;
- uint32_t foreign_init_function_index_;
- uint32_t next_table_index_;
- ZoneHashMap function_tables_;
- ImportedFunctionTable imported_function_table_;
- const AstTypeBounds* bounds_;
-
- DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl);
-};
-
-AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
- FunctionLiteral* literal, AsmTyper* typer)
- : isolate_(isolate), zone_(zone), literal_(literal), typer_(typer) {}
-
-// TODO(aseemgarg): probably should take zone (to write wasm to) as input so
-// that zone in constructor may be thrown away once wasm module is written.
-ZoneBuffer* AsmWasmBuilder::Run(i::Handle<i::FixedArray>* foreign_args) {
- AsmWasmBuilderImpl impl(isolate_, zone_, literal_, typer_);
- impl.Build();
- *foreign_args = impl.GetForeignArgs();
- ZoneBuffer* buffer = new (zone_) ZoneBuffer(zone_);
- impl.builder_->WriteTo(*buffer);
- return buffer;
-}
-} // namespace wasm
-} // namespace internal
-} // namespace v8
« no previous file with comments | « src/wasm/asm-wasm-builder.h ('k') | src/wasm/wasm-js.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698