| 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
|
|
|