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 |