|
|
@ -19,6 +19,11 @@ |
|
|
|
|
|
|
|
#include "src/ast/ast.h" |
|
|
|
#include "src/ast/scopes.h" |
|
|
|
#include "src/codegen.h" |
|
|
|
#include "src/compilation-info.h" |
|
|
|
#include "src/compiler.h" |
|
|
|
#include "src/isolate.h" |
|
|
|
#include "src/parsing/parse-info.h" |
|
|
|
|
|
|
|
namespace v8 { |
|
|
|
namespace internal { |
|
|
@ -37,13 +42,14 @@ enum ValueFate { kDrop, kLeaveOnStack }; |
|
|
|
struct ForeignVariable { |
|
|
|
Handle<Name> name; |
|
|
|
Variable* var; |
|
|
|
LocalType type; |
|
|
|
ValueType type; |
|
|
|
}; |
|
|
|
|
|
|
|
class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
public: |
|
|
|
AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal, |
|
|
|
AsmTyper* typer) |
|
|
|
AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, CompilationInfo* info, |
|
|
|
AstValueFactory* ast_value_factory, Handle<Script> script, |
|
|
|
FunctionLiteral* literal, AsmTyper* typer) |
|
|
|
: local_variables_(ZoneHashMap::kDefaultHashMapCapacity, |
|
|
|
ZoneAllocationPolicy(zone)), |
|
|
|
functions_(ZoneHashMap::kDefaultHashMapCapacity, |
|
|
@ -56,15 +62,20 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
literal_(literal), |
|
|
|
isolate_(isolate), |
|
|
|
zone_(zone), |
|
|
|
info_(info), |
|
|
|
ast_value_factory_(ast_value_factory), |
|
|
|
script_(script), |
|
|
|
typer_(typer), |
|
|
|
typer_failed_(false), |
|
|
|
typer_finished_(false), |
|
|
|
breakable_blocks_(zone), |
|
|
|
foreign_variables_(zone), |
|
|
|
init_function_(nullptr), |
|
|
|
foreign_init_function_(nullptr), |
|
|
|
next_table_index_(0), |
|
|
|
function_tables_(ZoneHashMap::kDefaultHashMapCapacity, |
|
|
|
ZoneAllocationPolicy(zone)), |
|
|
|
imported_function_table_(this) { |
|
|
|
imported_function_table_(this), |
|
|
|
parent_binop_(nullptr) { |
|
|
|
InitializeAstVisitor(isolate); |
|
|
|
} |
|
|
|
|
|
|
@ -90,10 +101,11 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
uint32_t index = LookupOrInsertGlobal(fv->var, fv->type); |
|
|
|
foreign_init_function_->EmitWithVarInt(kExprSetGlobal, index); |
|
|
|
} |
|
|
|
foreign_init_function_->Emit(kExprEnd); |
|
|
|
} |
|
|
|
|
|
|
|
i::Handle<i::FixedArray> GetForeignArgs() { |
|
|
|
i::Handle<FixedArray> ret = isolate_->factory()->NewFixedArray( |
|
|
|
Handle<FixedArray> GetForeignArgs() { |
|
|
|
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]; |
|
|
@ -102,10 +114,26 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
void Build() { |
|
|
|
bool Build() { |
|
|
|
InitializeInitFunction(); |
|
|
|
RECURSE(VisitFunctionLiteral(literal_)); |
|
|
|
if (!typer_->ValidateBeforeFunctionsPhase()) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
DCHECK(!HasStackOverflow()); |
|
|
|
VisitFunctionLiteral(literal_); |
|
|
|
if (HasStackOverflow()) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (!typer_finished_ && !typer_failed_) { |
|
|
|
typer_->FailWithMessage("Module missing export section."); |
|
|
|
typer_failed_ = true; |
|
|
|
} |
|
|
|
if (typer_failed_) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
BuildForeignInitFunction(); |
|
|
|
init_function_->Emit(kExprEnd); // finish init function.
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
void VisitVariableDeclaration(VariableDeclaration* decl) {} |
|
|
@ -113,12 +141,65 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
void VisitFunctionDeclaration(FunctionDeclaration* decl) { |
|
|
|
DCHECK_EQ(kModuleScope, scope_); |
|
|
|
DCHECK_NULL(current_function_builder_); |
|
|
|
FunctionLiteral* old_func = decl->fun(); |
|
|
|
Zone zone(isolate_->allocator(), ZONE_NAME); |
|
|
|
DeclarationScope* new_func_scope = nullptr; |
|
|
|
if (decl->fun()->body() == nullptr) { |
|
|
|
// TODO(titzer/bradnelson): Reuse SharedFunctionInfos used here when
|
|
|
|
// compiling the wasm module.
|
|
|
|
Handle<SharedFunctionInfo> shared = |
|
|
|
Compiler::GetSharedFunctionInfo(decl->fun(), script_, info_); |
|
|
|
shared->set_is_toplevel(false); |
|
|
|
ParseInfo info(&zone, script_); |
|
|
|
info.set_shared_info(shared); |
|
|
|
info.set_toplevel(false); |
|
|
|
info.set_language_mode(decl->fun()->scope()->language_mode()); |
|
|
|
info.set_allow_lazy_parsing(false); |
|
|
|
info.set_function_literal_id(shared->function_literal_id()); |
|
|
|
info.set_ast_value_factory(ast_value_factory_); |
|
|
|
info.set_ast_value_factory_owned(false); |
|
|
|
// Create fresh function scope to use to parse the function in.
|
|
|
|
new_func_scope = new (info.zone()) DeclarationScope( |
|
|
|
info.zone(), decl->fun()->scope()->outer_scope(), FUNCTION_SCOPE); |
|
|
|
info.set_asm_function_scope(new_func_scope); |
|
|
|
if (!Compiler::ParseAndAnalyze(&info)) { |
|
|
|
typer_failed_ = true; |
|
|
|
return; |
|
|
|
} |
|
|
|
FunctionLiteral* func = info.literal(); |
|
|
|
DCHECK_NOT_NULL(func); |
|
|
|
decl->set_fun(func); |
|
|
|
} |
|
|
|
if (!typer_->ValidateInnerFunction(decl)) { |
|
|
|
typer_failed_ = true; |
|
|
|
decl->set_fun(old_func); |
|
|
|
if (new_func_scope != nullptr) { |
|
|
|
DCHECK_EQ(new_func_scope, decl->scope()->inner_scope()); |
|
|
|
if (!decl->scope()->RemoveInnerScope(new_func_scope)) { |
|
|
|
UNREACHABLE(); |
|
|
|
} |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
current_function_builder_ = LookupOrInsertFunction(decl->proxy()->var()); |
|
|
|
scope_ = kFuncScope; |
|
|
|
|
|
|
|
// Record start of the function, used as position for the stack check.
|
|
|
|
current_function_builder_->SetAsmFunctionStartPosition( |
|
|
|
decl->fun()->start_position()); |
|
|
|
|
|
|
|
RECURSE(Visit(decl->fun())); |
|
|
|
decl->set_fun(old_func); |
|
|
|
if (new_func_scope != nullptr) { |
|
|
|
DCHECK_EQ(new_func_scope, decl->scope()->inner_scope()); |
|
|
|
if (!decl->scope()->RemoveInnerScope(new_func_scope)) { |
|
|
|
UNREACHABLE(); |
|
|
|
} |
|
|
|
} |
|
|
|
scope_ = kModuleScope; |
|
|
|
current_function_builder_ = nullptr; |
|
|
|
local_variables_.Clear(); |
|
|
|
typer_->ClearFunctionNodeTypes(); |
|
|
|
} |
|
|
|
|
|
|
|
void VisitStatements(ZoneList<Statement*>* stmts) { |
|
|
@ -129,7 +210,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
continue; |
|
|
|
} |
|
|
|
RECURSE(Visit(stmt)); |
|
|
|
if (stmt->IsJump()) break; |
|
|
|
if (typer_failed_) break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -204,6 +285,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
|
|
|
|
void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); } |
|
|
|
|
|
|
|
void VisitGetIterator(GetIterator* expr) { UNREACHABLE(); } |
|
|
|
|
|
|
|
void VisitIfStatement(IfStatement* stmt) { |
|
|
|
DCHECK_EQ(kFuncScope, scope_); |
|
|
|
RECURSE(Visit(stmt->condition())); |
|
|
@ -245,6 +328,16 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
|
|
|
|
void VisitReturnStatement(ReturnStatement* stmt) { |
|
|
|
if (scope_ == kModuleScope) { |
|
|
|
if (typer_finished_) { |
|
|
|
typer_->FailWithMessage("Module has multiple returns."); |
|
|
|
typer_failed_ = true; |
|
|
|
return; |
|
|
|
} |
|
|
|
if (!typer_->ValidateAfterFunctionsPhase()) { |
|
|
|
typer_failed_ = true; |
|
|
|
return; |
|
|
|
} |
|
|
|
typer_finished_ = true; |
|
|
|
scope_ = kExportScope; |
|
|
|
RECURSE(Visit(stmt->expression())); |
|
|
|
scope_ = kModuleScope; |
|
|
@ -440,16 +533,21 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
// Add the parameters for the function.
|
|
|
|
const auto& arguments = func_type->Arguments(); |
|
|
|
for (int i = 0; i < expr->parameter_count(); ++i) { |
|
|
|
LocalType type = TypeFrom(arguments[i]); |
|
|
|
DCHECK_NE(kAstStmt, type); |
|
|
|
ValueType type = TypeFrom(arguments[i]); |
|
|
|
DCHECK_NE(kWasmStmt, type); |
|
|
|
InsertParameter(scope->parameter(i), type, i); |
|
|
|
} |
|
|
|
} else { |
|
|
|
UNREACHABLE(); |
|
|
|
} |
|
|
|
} |
|
|
|
RECURSE(VisitStatements(expr->body())); |
|
|
|
RECURSE(VisitDeclarations(scope->declarations())); |
|
|
|
if (typer_failed_) return; |
|
|
|
RECURSE(VisitStatements(expr->body())); |
|
|
|
if (scope_ == kFuncScope) { |
|
|
|
// Finish the function-body scope block.
|
|
|
|
current_function_builder_->Emit(kExprEnd); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { |
|
|
@ -461,18 +559,18 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
RECURSE(Visit(expr->condition())); |
|
|
|
// WASM ifs come with implicit blocks for both arms.
|
|
|
|
breakable_blocks_.push_back(std::make_pair(nullptr, false)); |
|
|
|
LocalTypeCode type; |
|
|
|
ValueTypeCode type; |
|
|
|
switch (TypeOf(expr)) { |
|
|
|
case kAstI32: |
|
|
|
case kWasmI32: |
|
|
|
type = kLocalI32; |
|
|
|
break; |
|
|
|
case kAstI64: |
|
|
|
case kWasmI64: |
|
|
|
type = kLocalI64; |
|
|
|
break; |
|
|
|
case kAstF32: |
|
|
|
case kWasmF32: |
|
|
|
type = kLocalF32; |
|
|
|
break; |
|
|
|
case kAstF64: |
|
|
|
case kWasmF64: |
|
|
|
type = kLocalF64; |
|
|
|
break; |
|
|
|
default: |
|
|
@ -544,8 +642,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
if (VisitStdlibConstant(var)) { |
|
|
|
return; |
|
|
|
} |
|
|
|
LocalType var_type = TypeOf(expr); |
|
|
|
DCHECK_NE(kAstStmt, var_type); |
|
|
|
ValueType var_type = TypeOf(expr); |
|
|
|
DCHECK_NE(kWasmStmt, var_type); |
|
|
|
if (var->IsContextSlot()) { |
|
|
|
current_function_builder_->EmitWithVarInt( |
|
|
|
kExprGetGlobal, LookupOrInsertGlobal(var, var_type)); |
|
|
@ -638,12 +736,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
Literal* name = prop->key()->AsLiteral(); |
|
|
|
DCHECK_NOT_NULL(name); |
|
|
|
DCHECK(name->IsPropertyName()); |
|
|
|
const AstRawString* raw_name = name->AsRawPropertyName(); |
|
|
|
Handle<String> function_name = name->AsPropertyName(); |
|
|
|
int length; |
|
|
|
std::unique_ptr<char[]> utf8 = function_name->ToCString( |
|
|
|
DISALLOW_NULLS, FAST_STRING_TRAVERSAL, &length); |
|
|
|
if (var->is_function()) { |
|
|
|
WasmFunctionBuilder* function = LookupOrInsertFunction(var); |
|
|
|
function->Export(); |
|
|
|
function->SetName({reinterpret_cast<const char*>(raw_name->raw_data()), |
|
|
|
raw_name->length()}); |
|
|
|
function->ExportAs({utf8.get(), length}); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -660,53 +759,67 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
current_function_builder_ = nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) { |
|
|
|
auto* func_tbl_type = typer_->TypeOf(funcs)->AsFunctionTableType(); |
|
|
|
DCHECK_NOT_NULL(func_tbl_type); |
|
|
|
auto* func_type = func_tbl_type->signature()->AsFunctionType(); |
|
|
|
struct FunctionTableIndices : public ZoneObject { |
|
|
|
uint32_t start_index; |
|
|
|
uint32_t signature_index; |
|
|
|
}; |
|
|
|
|
|
|
|
FunctionTableIndices* LookupOrAddFunctionTable(VariableProxy* table, |
|
|
|
Property* p) { |
|
|
|
FunctionTableIndices* indices = LookupFunctionTable(table->var()); |
|
|
|
if (indices != nullptr) { |
|
|
|
// Already setup.
|
|
|
|
return indices; |
|
|
|
} |
|
|
|
indices = new (zone()) FunctionTableIndices(); |
|
|
|
auto* func_type = typer_->TypeOf(p)->AsFunctionType(); |
|
|
|
auto* func_table_type = typer_->TypeOf(p->obj()->AsVariableProxy()->var()) |
|
|
|
->AsFunctionTableType(); |
|
|
|
const auto& arguments = func_type->Arguments(); |
|
|
|
LocalType return_type = TypeFrom(func_type->ReturnType()); |
|
|
|
FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1, |
|
|
|
ValueType return_type = TypeFrom(func_type->ReturnType()); |
|
|
|
FunctionSig::Builder sig(zone(), return_type == kWasmStmt ? 0 : 1, |
|
|
|
arguments.size()); |
|
|
|
if (return_type != kAstStmt) { |
|
|
|
if (return_type != kWasmStmt) { |
|
|
|
sig.AddReturn(return_type); |
|
|
|
} |
|
|
|
for (auto* arg : arguments) { |
|
|
|
sig.AddParam(TypeFrom(arg)); |
|
|
|
} |
|
|
|
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())->func_index()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
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; |
|
|
|
indices->start_index = builder_->AllocateIndirectFunctions( |
|
|
|
static_cast<uint32_t>(func_table_type->length())); |
|
|
|
indices->signature_index = signature_index; |
|
|
|
ZoneHashMap::Entry* entry = function_tables_.LookupOrInsert( |
|
|
|
v, ComputePointerHash(v), ZoneAllocationPolicy(zone())); |
|
|
|
entry->value = container; |
|
|
|
table->var(), ComputePointerHash(table->var()), |
|
|
|
ZoneAllocationPolicy(zone())); |
|
|
|
entry->value = indices; |
|
|
|
return indices; |
|
|
|
} |
|
|
|
|
|
|
|
FunctionTableIndices* LookupFunctionTable(Variable* v) { |
|
|
|
ZoneHashMap::Entry* entry = |
|
|
|
function_tables_.Lookup(v, ComputePointerHash(v)); |
|
|
|
DCHECK_NOT_NULL(entry); |
|
|
|
if (entry == nullptr) { |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
return reinterpret_cast<FunctionTableIndices*>(entry->value); |
|
|
|
} |
|
|
|
|
|
|
|
void PopulateFunctionTable(VariableProxy* table, ArrayLiteral* funcs) { |
|
|
|
FunctionTableIndices* indices = LookupFunctionTable(table->var()); |
|
|
|
// Ignore unused function tables.
|
|
|
|
if (indices == nullptr) { |
|
|
|
return; |
|
|
|
} |
|
|
|
for (int i = 0; i < funcs->values()->length(); ++i) { |
|
|
|
VariableProxy* func = funcs->values()->at(i)->AsVariableProxy(); |
|
|
|
DCHECK_NOT_NULL(func); |
|
|
|
builder_->SetIndirectFunction( |
|
|
|
indices->start_index + i, |
|
|
|
LookupOrInsertFunction(func->var())->func_index()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
class ImportedFunctionTable { |
|
|
|
private: |
|
|
|
class ImportedFunctionIndices : public ZoneObject { |
|
|
@ -727,20 +840,33 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
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()); |
|
|
|
ImportedFunctionIndices* LookupOrInsertImport(Variable* v) { |
|
|
|
auto* entry = table_.LookupOrInsert( |
|
|
|
v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone())); |
|
|
|
entry->value = indices; |
|
|
|
ImportedFunctionIndices* indices; |
|
|
|
if (entry->value == nullptr) { |
|
|
|
indices = new (builder_->zone()) |
|
|
|
ImportedFunctionIndices(nullptr, 0, builder_->zone()); |
|
|
|
entry->value = indices; |
|
|
|
} else { |
|
|
|
indices = reinterpret_cast<ImportedFunctionIndices*>(entry->value); |
|
|
|
} |
|
|
|
return indices; |
|
|
|
} |
|
|
|
|
|
|
|
void SetImportName(Variable* v, const char* name, int name_length) { |
|
|
|
auto* indices = LookupOrInsertImport(v); |
|
|
|
indices->name_ = name; |
|
|
|
indices->name_length_ = name_length; |
|
|
|
for (auto i : indices->signature_to_index_) { |
|
|
|
builder_->builder_->SetImportName(i.second, indices->name_, |
|
|
|
indices->name_length_); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Get a function's index (or allocate if new).
|
|
|
|
uint32_t LookupOrInsertImport(Variable* v, FunctionSig* sig) { |
|
|
|
ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v)); |
|
|
|
DCHECK_NOT_NULL(entry); |
|
|
|
ImportedFunctionIndices* indices = |
|
|
|
reinterpret_cast<ImportedFunctionIndices*>(entry->value); |
|
|
|
uint32_t LookupOrInsertImportUse(Variable* v, FunctionSig* sig) { |
|
|
|
auto* indices = LookupOrInsertImport(v); |
|
|
|
WasmModuleBuilder::SignatureMap::iterator pos = |
|
|
|
indices->signature_to_index_.find(sig); |
|
|
|
if (pos != indices->signature_to_index_.end()) { |
|
|
@ -819,8 +945,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
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); |
|
|
|
ValueType var_type = TypeOf(expr); |
|
|
|
DCHECK_NE(kWasmStmt, var_type); |
|
|
|
if (var->IsContextSlot()) { |
|
|
|
uint32_t index = LookupOrInsertGlobal(var, var_type); |
|
|
|
current_function_builder_->EmitWithVarInt(kExprSetGlobal, index); |
|
|
@ -841,7 +967,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
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() && |
|
|
|
if (TypeOf(expr->value()) == kWasmF64 && expr->target()->IsProperty() && |
|
|
|
typer_->TypeOf(expr->target()->AsProperty()->obj()) |
|
|
|
->IsA(AsmType::Float32Array())) { |
|
|
|
current_function_builder_->Emit(kExprF32ConvertF64); |
|
|
@ -901,7 +1027,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
if (typer_->TypeOf(target)->AsFFIType() != nullptr) { |
|
|
|
const AstRawString* name = |
|
|
|
prop->key()->AsLiteral()->AsRawPropertyName(); |
|
|
|
imported_function_table_.AddImport( |
|
|
|
imported_function_table_.SetImportName( |
|
|
|
target->var(), reinterpret_cast<const char*>(name->raw_data()), |
|
|
|
name->length()); |
|
|
|
} |
|
|
@ -910,14 +1036,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
return; |
|
|
|
} |
|
|
|
ArrayLiteral* funcs = expr->value()->AsArrayLiteral(); |
|
|
|
if (funcs != nullptr && |
|
|
|
typer_->TypeOf(funcs) |
|
|
|
->AsFunctionTableType() |
|
|
|
->signature() |
|
|
|
->AsFunctionType()) { |
|
|
|
if (funcs != nullptr) { |
|
|
|
VariableProxy* target = expr->target()->AsVariableProxy(); |
|
|
|
DCHECK_NOT_NULL(target); |
|
|
|
AddFunctionTable(target, funcs); |
|
|
|
PopulateFunctionTable(target, funcs); |
|
|
|
// Only add to the function table. No init needed.
|
|
|
|
return; |
|
|
|
} |
|
|
@ -952,8 +1074,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
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; |
|
|
|
Object::ToName(isolate_, key_literal->value()).ToHandleChecked(); |
|
|
|
ValueType type = is_float ? kWasmF64 : kWasmI32; |
|
|
|
foreign_variables_.push_back({name, var, type}); |
|
|
|
} |
|
|
|
} |
|
|
@ -961,7 +1083,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
void VisitPropertyAndEmitIndex(Property* expr, AsmType** atype) { |
|
|
|
Expression* obj = expr->obj(); |
|
|
|
*atype = typer_->TypeOf(obj); |
|
|
|
int size = (*atype)->ElementSizeInBytes(); |
|
|
|
int32_t size = (*atype)->ElementSizeInBytes(); |
|
|
|
if (size == 1) { |
|
|
|
// Allow more general expression in byte arrays than the spec
|
|
|
|
// strictly permits.
|
|
|
@ -974,7 +1096,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
Literal* value = expr->key()->AsLiteral(); |
|
|
|
if (value) { |
|
|
|
DCHECK(value->raw_value()->IsNumber()); |
|
|
|
DCHECK_EQ(kAstI32, TypeOf(value)); |
|
|
|
DCHECK_EQ(kWasmI32, TypeOf(value)); |
|
|
|
int32_t val = static_cast<int32_t>(value->raw_value()->AsNumber()); |
|
|
|
// TODO(titzer): handle overflow here.
|
|
|
|
current_function_builder_->EmitI32Const(val * size); |
|
|
@ -984,14 +1106,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
if (binop) { |
|
|
|
DCHECK_EQ(Token::SAR, binop->op()); |
|
|
|
DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber()); |
|
|
|
DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral())); |
|
|
|
DCHECK(kWasmI32 == 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_->EmitI32Const(~(size - 1)); |
|
|
|
current_function_builder_->Emit(kExprI32And); |
|
|
|
return; |
|
|
|
} |
|
|
@ -1030,7 +1151,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
AsmTyper::StandardMember standard_object = |
|
|
|
typer_->VariableAsStandardMember(var); |
|
|
|
ZoneList<Expression*>* args = call->arguments(); |
|
|
|
LocalType call_type = TypeOf(call); |
|
|
|
ValueType call_type = TypeOf(call); |
|
|
|
|
|
|
|
switch (standard_object) { |
|
|
|
case AsmTyper::kNone: { |
|
|
@ -1038,57 +1159,57 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
} |
|
|
|
case AsmTyper::kMathAcos: { |
|
|
|
VisitCallArgs(call); |
|
|
|
DCHECK_EQ(kAstF64, call_type); |
|
|
|
DCHECK_EQ(kWasmF64, call_type); |
|
|
|
current_function_builder_->Emit(kExprF64Acos); |
|
|
|
break; |
|
|
|
} |
|
|
|
case AsmTyper::kMathAsin: { |
|
|
|
VisitCallArgs(call); |
|
|
|
DCHECK_EQ(kAstF64, call_type); |
|
|
|
DCHECK_EQ(kWasmF64, call_type); |
|
|
|
current_function_builder_->Emit(kExprF64Asin); |
|
|
|
break; |
|
|
|
} |
|
|
|
case AsmTyper::kMathAtan: { |
|
|
|
VisitCallArgs(call); |
|
|
|
DCHECK_EQ(kAstF64, call_type); |
|
|
|
DCHECK_EQ(kWasmF64, call_type); |
|
|
|
current_function_builder_->Emit(kExprF64Atan); |
|
|
|
break; |
|
|
|
} |
|
|
|
case AsmTyper::kMathCos: { |
|
|
|
VisitCallArgs(call); |
|
|
|
DCHECK_EQ(kAstF64, call_type); |
|
|
|
DCHECK_EQ(kWasmF64, call_type); |
|
|
|
current_function_builder_->Emit(kExprF64Cos); |
|
|
|
break; |
|
|
|
} |
|
|
|
case AsmTyper::kMathSin: { |
|
|
|
VisitCallArgs(call); |
|
|
|
DCHECK_EQ(kAstF64, call_type); |
|
|
|
DCHECK_EQ(kWasmF64, call_type); |
|
|
|
current_function_builder_->Emit(kExprF64Sin); |
|
|
|
break; |
|
|
|
} |
|
|
|
case AsmTyper::kMathTan: { |
|
|
|
VisitCallArgs(call); |
|
|
|
DCHECK_EQ(kAstF64, call_type); |
|
|
|
DCHECK_EQ(kWasmF64, call_type); |
|
|
|
current_function_builder_->Emit(kExprF64Tan); |
|
|
|
break; |
|
|
|
} |
|
|
|
case AsmTyper::kMathExp: { |
|
|
|
VisitCallArgs(call); |
|
|
|
DCHECK_EQ(kAstF64, call_type); |
|
|
|
DCHECK_EQ(kWasmF64, call_type); |
|
|
|
current_function_builder_->Emit(kExprF64Exp); |
|
|
|
break; |
|
|
|
} |
|
|
|
case AsmTyper::kMathLog: { |
|
|
|
VisitCallArgs(call); |
|
|
|
DCHECK_EQ(kAstF64, call_type); |
|
|
|
DCHECK_EQ(kWasmF64, call_type); |
|
|
|
current_function_builder_->Emit(kExprF64Log); |
|
|
|
break; |
|
|
|
} |
|
|
|
case AsmTyper::kMathCeil: { |
|
|
|
VisitCallArgs(call); |
|
|
|
if (call_type == kAstF32) { |
|
|
|
if (call_type == kWasmF32) { |
|
|
|
current_function_builder_->Emit(kExprF32Ceil); |
|
|
|
} else if (call_type == kAstF64) { |
|
|
|
} else if (call_type == kWasmF64) { |
|
|
|
current_function_builder_->Emit(kExprF64Ceil); |
|
|
|
} else { |
|
|
|
UNREACHABLE(); |
|
|
@ -1097,9 +1218,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
} |
|
|
|
case AsmTyper::kMathFloor: { |
|
|
|
VisitCallArgs(call); |
|
|
|
if (call_type == kAstF32) { |
|
|
|
if (call_type == kWasmF32) { |
|
|
|
current_function_builder_->Emit(kExprF32Floor); |
|
|
|
} else if (call_type == kAstF64) { |
|
|
|
} else if (call_type == kWasmF64) { |
|
|
|
current_function_builder_->Emit(kExprF64Floor); |
|
|
|
} else { |
|
|
|
UNREACHABLE(); |
|
|
@ -1108,9 +1229,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
} |
|
|
|
case AsmTyper::kMathSqrt: { |
|
|
|
VisitCallArgs(call); |
|
|
|
if (call_type == kAstF32) { |
|
|
|
if (call_type == kWasmF32) { |
|
|
|
current_function_builder_->Emit(kExprF32Sqrt); |
|
|
|
} else if (call_type == kAstF64) { |
|
|
|
} else if (call_type == kWasmF64) { |
|
|
|
current_function_builder_->Emit(kExprF64Sqrt); |
|
|
|
} else { |
|
|
|
UNREACHABLE(); |
|
|
@ -1119,18 +1240,18 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
} |
|
|
|
case AsmTyper::kMathClz32: { |
|
|
|
VisitCallArgs(call); |
|
|
|
DCHECK(call_type == kAstI32); |
|
|
|
DCHECK(call_type == kWasmI32); |
|
|
|
current_function_builder_->Emit(kExprI32Clz); |
|
|
|
break; |
|
|
|
} |
|
|
|
case AsmTyper::kMathAbs: { |
|
|
|
if (call_type == kAstI32) { |
|
|
|
WasmTemporary tmp(current_function_builder_, kAstI32); |
|
|
|
if (call_type == kWasmI32) { |
|
|
|
WasmTemporary tmp(current_function_builder_, kWasmI32); |
|
|
|
|
|
|
|
// if set_local(tmp, x) < 0
|
|
|
|
Visit(call->arguments()->at(0)); |
|
|
|
current_function_builder_->EmitTeeLocal(tmp.index()); |
|
|
|
byte code[] = {WASM_I8(0)}; |
|
|
|
byte code[] = {WASM_ZERO}; |
|
|
|
current_function_builder_->EmitCode(code, sizeof(code)); |
|
|
|
current_function_builder_->Emit(kExprI32LtS); |
|
|
|
current_function_builder_->EmitWithU8(kExprIf, kLocalI32); |
|
|
@ -1146,10 +1267,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
// end
|
|
|
|
current_function_builder_->Emit(kExprEnd); |
|
|
|
|
|
|
|
} else if (call_type == kAstF32) { |
|
|
|
} else if (call_type == kWasmF32) { |
|
|
|
VisitCallArgs(call); |
|
|
|
current_function_builder_->Emit(kExprF32Abs); |
|
|
|
} else if (call_type == kAstF64) { |
|
|
|
} else if (call_type == kWasmF64) { |
|
|
|
VisitCallArgs(call); |
|
|
|
current_function_builder_->Emit(kExprF64Abs); |
|
|
|
} else { |
|
|
@ -1159,9 +1280,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
} |
|
|
|
case AsmTyper::kMathMin: { |
|
|
|
// TODO(bradnelson): Change wasm to match Math.min in asm.js mode.
|
|
|
|
if (call_type == kAstI32) { |
|
|
|
WasmTemporary tmp_x(current_function_builder_, kAstI32); |
|
|
|
WasmTemporary tmp_y(current_function_builder_, kAstI32); |
|
|
|
if (call_type == kWasmI32) { |
|
|
|
WasmTemporary tmp_x(current_function_builder_, kWasmI32); |
|
|
|
WasmTemporary tmp_y(current_function_builder_, kWasmI32); |
|
|
|
|
|
|
|
// if set_local(tmp_x, x) < set_local(tmp_y, y)
|
|
|
|
Visit(call->arguments()->at(0)); |
|
|
@ -1181,10 +1302,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
current_function_builder_->EmitGetLocal(tmp_y.index()); |
|
|
|
current_function_builder_->Emit(kExprEnd); |
|
|
|
|
|
|
|
} else if (call_type == kAstF32) { |
|
|
|
} else if (call_type == kWasmF32) { |
|
|
|
VisitCallArgs(call); |
|
|
|
current_function_builder_->Emit(kExprF32Min); |
|
|
|
} else if (call_type == kAstF64) { |
|
|
|
} else if (call_type == kWasmF64) { |
|
|
|
VisitCallArgs(call); |
|
|
|
current_function_builder_->Emit(kExprF64Min); |
|
|
|
} else { |
|
|
@ -1194,9 +1315,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
} |
|
|
|
case AsmTyper::kMathMax: { |
|
|
|
// TODO(bradnelson): Change wasm to match Math.max in asm.js mode.
|
|
|
|
if (call_type == kAstI32) { |
|
|
|
WasmTemporary tmp_x(current_function_builder_, kAstI32); |
|
|
|
WasmTemporary tmp_y(current_function_builder_, kAstI32); |
|
|
|
if (call_type == kWasmI32) { |
|
|
|
WasmTemporary tmp_x(current_function_builder_, kWasmI32); |
|
|
|
WasmTemporary tmp_y(current_function_builder_, kWasmI32); |
|
|
|
|
|
|
|
// if set_local(tmp_x, x) < set_local(tmp_y, y)
|
|
|
|
Visit(call->arguments()->at(0)); |
|
|
@ -1217,10 +1338,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
current_function_builder_->EmitGetLocal(tmp_x.index()); |
|
|
|
current_function_builder_->Emit(kExprEnd); |
|
|
|
|
|
|
|
} else if (call_type == kAstF32) { |
|
|
|
} else if (call_type == kWasmF32) { |
|
|
|
VisitCallArgs(call); |
|
|
|
current_function_builder_->Emit(kExprF32Max); |
|
|
|
} else if (call_type == kAstF64) { |
|
|
|
} else if (call_type == kWasmF64) { |
|
|
|
VisitCallArgs(call); |
|
|
|
current_function_builder_->Emit(kExprF64Max); |
|
|
|
} else { |
|
|
@ -1230,13 +1351,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
} |
|
|
|
case AsmTyper::kMathAtan2: { |
|
|
|
VisitCallArgs(call); |
|
|
|
DCHECK_EQ(kAstF64, call_type); |
|
|
|
DCHECK_EQ(kWasmF64, call_type); |
|
|
|
current_function_builder_->Emit(kExprF64Atan2); |
|
|
|
break; |
|
|
|
} |
|
|
|
case AsmTyper::kMathPow: { |
|
|
|
VisitCallArgs(call); |
|
|
|
DCHECK_EQ(kAstF64, call_type); |
|
|
|
DCHECK_EQ(kWasmF64, call_type); |
|
|
|
current_function_builder_->Emit(kExprF64Pow); |
|
|
|
break; |
|
|
|
} |
|
|
@ -1298,6 +1419,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
bool VisitCallExpression(Call* expr) { |
|
|
|
Call::CallType call_type = expr->GetCallType(); |
|
|
|
bool returns_value = true; |
|
|
|
|
|
|
|
// Save the parent now, it might be overwritten in VisitCallArgs.
|
|
|
|
BinaryOperation* parent_binop = parent_binop_; |
|
|
|
|
|
|
|
switch (call_type) { |
|
|
|
case Call::OTHER_CALL: { |
|
|
|
VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
|
|
@ -1313,11 +1438,11 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
VariableProxy* vp = expr->expression()->AsVariableProxy(); |
|
|
|
DCHECK_NOT_NULL(vp); |
|
|
|
if (typer_->TypeOf(vp)->AsFFIType() != nullptr) { |
|
|
|
LocalType return_type = TypeOf(expr); |
|
|
|
ValueType return_type = TypeOf(expr); |
|
|
|
ZoneList<Expression*>* args = expr->arguments(); |
|
|
|
FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1, |
|
|
|
FunctionSig::Builder sig(zone(), return_type == kWasmStmt ? 0 : 1, |
|
|
|
args->length()); |
|
|
|
if (return_type != kAstStmt) { |
|
|
|
if (return_type != kWasmStmt) { |
|
|
|
sig.AddReturn(return_type); |
|
|
|
} else { |
|
|
|
returns_value = false; |
|
|
@ -1325,16 +1450,23 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
for (int i = 0; i < args->length(); ++i) { |
|
|
|
sig.AddParam(TypeOf(args->at(i))); |
|
|
|
} |
|
|
|
uint32_t index = imported_function_table_.LookupOrInsertImport( |
|
|
|
uint32_t index = imported_function_table_.LookupOrInsertImportUse( |
|
|
|
vp->var(), sig.Build()); |
|
|
|
VisitCallArgs(expr); |
|
|
|
current_function_builder_->AddAsmWasmOffset(expr->position()); |
|
|
|
// For non-void functions, we must know the parent node.
|
|
|
|
DCHECK_IMPLIES(returns_value, parent_binop != nullptr); |
|
|
|
DCHECK_IMPLIES(returns_value, parent_binop->left() == expr || |
|
|
|
parent_binop->right() == expr); |
|
|
|
int pos = expr->position(); |
|
|
|
int parent_pos = returns_value ? parent_binop->position() : pos; |
|
|
|
current_function_builder_->AddAsmWasmOffset(pos, parent_pos); |
|
|
|
current_function_builder_->Emit(kExprCallFunction); |
|
|
|
current_function_builder_->EmitVarInt(index); |
|
|
|
} else { |
|
|
|
WasmFunctionBuilder* function = LookupOrInsertFunction(vp->var()); |
|
|
|
VisitCallArgs(expr); |
|
|
|
current_function_builder_->AddAsmWasmOffset(expr->position()); |
|
|
|
current_function_builder_->AddAsmWasmOffset(expr->position(), |
|
|
|
expr->position()); |
|
|
|
current_function_builder_->Emit(kExprCallFunction); |
|
|
|
current_function_builder_->EmitDirectCallIndex( |
|
|
|
function->func_index()); |
|
|
@ -1348,19 +1480,20 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
DCHECK_NOT_NULL(p); |
|
|
|
VariableProxy* var = p->obj()->AsVariableProxy(); |
|
|
|
DCHECK_NOT_NULL(var); |
|
|
|
FunctionTableIndices* indices = LookupFunctionTable(var->var()); |
|
|
|
FunctionTableIndices* indices = LookupOrAddFunctionTable(var, p); |
|
|
|
Visit(p->key()); // TODO(titzer): should use RECURSE()
|
|
|
|
|
|
|
|
// We have to use a temporary for the correct order of evaluation.
|
|
|
|
current_function_builder_->EmitI32Const(indices->start_index); |
|
|
|
current_function_builder_->Emit(kExprI32Add); |
|
|
|
WasmTemporary tmp(current_function_builder_, kAstI32); |
|
|
|
WasmTemporary tmp(current_function_builder_, kWasmI32); |
|
|
|
current_function_builder_->EmitSetLocal(tmp.index()); |
|
|
|
|
|
|
|
VisitCallArgs(expr); |
|
|
|
|
|
|
|
current_function_builder_->EmitGetLocal(tmp.index()); |
|
|
|
current_function_builder_->AddAsmWasmOffset(expr->position()); |
|
|
|
current_function_builder_->AddAsmWasmOffset(expr->position(), |
|
|
|
expr->position()); |
|
|
|
current_function_builder_->Emit(kExprCallIndirect); |
|
|
|
current_function_builder_->EmitVarInt(indices->signature_index); |
|
|
|
current_function_builder_->EmitVarInt(0); // table index
|
|
|
@ -1383,7 +1516,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
RECURSE(Visit(expr->expression())); |
|
|
|
switch (expr->op()) { |
|
|
|
case Token::NOT: { |
|
|
|
DCHECK_EQ(kAstI32, TypeOf(expr->expression())); |
|
|
|
DCHECK_EQ(kWasmI32, TypeOf(expr->expression())); |
|
|
|
current_function_builder_->Emit(kExprI32Eqz); |
|
|
|
break; |
|
|
|
} |
|
|
@ -1398,10 +1531,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
int32_t val) { |
|
|
|
DCHECK_NOT_NULL(expr->right()); |
|
|
|
if (expr->op() == op && expr->right()->IsLiteral() && |
|
|
|
TypeOf(expr) == kAstI32) { |
|
|
|
TypeOf(expr) == kWasmI32) { |
|
|
|
Literal* right = expr->right()->AsLiteral(); |
|
|
|
DCHECK(right->raw_value()->IsNumber()); |
|
|
|
if (static_cast<int32_t>(right->raw_value()->AsNumber()) == val) { |
|
|
|
if (right->raw_value()->IsNumber() && |
|
|
|
static_cast<int32_t>(right->raw_value()->AsNumber()) == val) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
@ -1412,7 +1545,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
double val) { |
|
|
|
DCHECK_NOT_NULL(expr->right()); |
|
|
|
if (expr->op() == op && expr->right()->IsLiteral() && |
|
|
|
TypeOf(expr) == kAstF64) { |
|
|
|
TypeOf(expr) == kWasmF64) { |
|
|
|
Literal* right = expr->right()->AsLiteral(); |
|
|
|
DCHECK(right->raw_value()->IsNumber()); |
|
|
|
if (right->raw_value()->AsNumber() == val) { |
|
|
@ -1426,7 +1559,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
|
|
|
|
ConvertOperation MatchOr(BinaryOperation* expr) { |
|
|
|
if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) && |
|
|
|
(TypeOf(expr->left()) == kAstI32)) { |
|
|
|
(TypeOf(expr->left()) == kWasmI32)) { |
|
|
|
return kAsIs; |
|
|
|
} else { |
|
|
|
return kNone; |
|
|
@ -1436,7 +1569,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
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; |
|
|
|
return (TypeOf(expr->left()) == kWasmI32) ? kAsIs : kToInt; |
|
|
|
} else { |
|
|
|
return kNone; |
|
|
|
} |
|
|
@ -1444,13 +1577,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
|
|
|
|
ConvertOperation MatchXor(BinaryOperation* expr) { |
|
|
|
if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) { |
|
|
|
DCHECK_EQ(kAstI32, TypeOf(expr->left())); |
|
|
|
DCHECK_EQ(kAstI32, TypeOf(expr->right())); |
|
|
|
DCHECK_EQ(kWasmI32, TypeOf(expr->left())); |
|
|
|
DCHECK_EQ(kWasmI32, 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) { |
|
|
|
DCHECK_EQ(kWasmI32, TypeOf(op->right())); |
|
|
|
if (TypeOf(op->left()) != kWasmI32) { |
|
|
|
return kToInt; |
|
|
|
} else { |
|
|
|
return kAsIs; |
|
|
@ -1463,8 +1596,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
|
|
|
|
ConvertOperation MatchMul(BinaryOperation* expr) { |
|
|
|
if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) { |
|
|
|
DCHECK_EQ(kAstF64, TypeOf(expr->right())); |
|
|
|
if (TypeOf(expr->left()) != kAstF64) { |
|
|
|
DCHECK_EQ(kWasmF64, TypeOf(expr->right())); |
|
|
|
if (TypeOf(expr->left()) != kWasmF64) { |
|
|
|
return kToDouble; |
|
|
|
} else { |
|
|
|
return kAsIs; |
|
|
@ -1532,6 +1665,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
void VisitBinaryOperation(BinaryOperation* expr) { |
|
|
|
ConvertOperation convertOperation = MatchBinaryOperation(expr); |
|
|
|
static const bool kDontIgnoreSign = false; |
|
|
|
parent_binop_ = expr; |
|
|
|
if (convertOperation == kToDouble) { |
|
|
|
RECURSE(Visit(expr->left())); |
|
|
|
TypeIndex type = TypeIndexOf(expr->left(), kDontIgnoreSign); |
|
|
@ -1694,6 +1828,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
void VisitDeclarations(Declaration::List* decls) { |
|
|
|
for (Declaration* decl : *decls) { |
|
|
|
RECURSE(Visit(decl)); |
|
|
|
if (typer_failed_) { |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -1719,7 +1856,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
uint32_t index; |
|
|
|
}; |
|
|
|
|
|
|
|
uint32_t LookupOrInsertLocal(Variable* v, LocalType type) { |
|
|
|
uint32_t LookupOrInsertLocal(Variable* v, ValueType type) { |
|
|
|
DCHECK_NOT_NULL(current_function_builder_); |
|
|
|
ZoneHashMap::Entry* entry = |
|
|
|
local_variables_.Lookup(v, ComputePointerHash(v)); |
|
|
@ -1736,7 +1873,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
return (reinterpret_cast<IndexContainer*>(entry->value))->index; |
|
|
|
} |
|
|
|
|
|
|
|
void InsertParameter(Variable* v, LocalType type, uint32_t index) { |
|
|
|
void InsertParameter(Variable* v, ValueType type, uint32_t index) { |
|
|
|
DCHECK(v->IsParameter()); |
|
|
|
DCHECK_NOT_NULL(current_function_builder_); |
|
|
|
ZoneHashMap::Entry* entry = |
|
|
@ -1749,7 +1886,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
entry->value = container; |
|
|
|
} |
|
|
|
|
|
|
|
uint32_t LookupOrInsertGlobal(Variable* v, LocalType type) { |
|
|
|
uint32_t LookupOrInsertGlobal(Variable* v, ValueType type) { |
|
|
|
ZoneHashMap::Entry* entry = |
|
|
|
global_variables_.Lookup(v, ComputePointerHash(v)); |
|
|
|
if (entry == nullptr) { |
|
|
@ -1770,14 +1907,14 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
auto* func_type = typer_->TypeOf(v)->AsFunctionType(); |
|
|
|
DCHECK_NOT_NULL(func_type); |
|
|
|
// Build the signature for the function.
|
|
|
|
LocalType return_type = TypeFrom(func_type->ReturnType()); |
|
|
|
ValueType return_type = TypeFrom(func_type->ReturnType()); |
|
|
|
const auto& arguments = func_type->Arguments(); |
|
|
|
FunctionSig::Builder b(zone(), return_type == kAstStmt ? 0 : 1, |
|
|
|
FunctionSig::Builder b(zone(), return_type == kWasmStmt ? 0 : 1, |
|
|
|
arguments.size()); |
|
|
|
if (return_type != kAstStmt) b.AddReturn(return_type); |
|
|
|
if (return_type != kWasmStmt) b.AddReturn(return_type); |
|
|
|
for (int i = 0; i < static_cast<int>(arguments.size()); ++i) { |
|
|
|
LocalType type = TypeFrom(arguments[i]); |
|
|
|
DCHECK_NE(kAstStmt, type); |
|
|
|
ValueType type = TypeFrom(arguments[i]); |
|
|
|
DCHECK_NE(kWasmStmt, type); |
|
|
|
b.AddParam(type); |
|
|
|
} |
|
|
|
|
|
|
@ -1792,22 +1929,22 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
return (reinterpret_cast<WasmFunctionBuilder*>(entry->value)); |
|
|
|
} |
|
|
|
|
|
|
|
LocalType TypeOf(Expression* expr) { return TypeFrom(typer_->TypeOf(expr)); } |
|
|
|
ValueType TypeOf(Expression* expr) { return TypeFrom(typer_->TypeOf(expr)); } |
|
|
|
|
|
|
|
LocalType TypeFrom(AsmType* type) { |
|
|
|
ValueType TypeFrom(AsmType* type) { |
|
|
|
if (type->IsA(AsmType::Intish())) { |
|
|
|
return kAstI32; |
|
|
|
return kWasmI32; |
|
|
|
} |
|
|
|
|
|
|
|
if (type->IsA(AsmType::Floatish())) { |
|
|
|
return kAstF32; |
|
|
|
return kWasmF32; |
|
|
|
} |
|
|
|
|
|
|
|
if (type->IsA(AsmType::DoubleQ())) { |
|
|
|
return kAstF64; |
|
|
|
return kWasmF64; |
|
|
|
} |
|
|
|
|
|
|
|
return kAstStmt; |
|
|
|
return kWasmStmt; |
|
|
|
} |
|
|
|
|
|
|
|
Zone* zone() { return zone_; } |
|
|
@ -1821,7 +1958,12 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
FunctionLiteral* literal_; |
|
|
|
Isolate* isolate_; |
|
|
|
Zone* zone_; |
|
|
|
CompilationInfo* info_; |
|
|
|
AstValueFactory* ast_value_factory_; |
|
|
|
Handle<Script> script_; |
|
|
|
AsmTyper* typer_; |
|
|
|
bool typer_failed_; |
|
|
|
bool typer_finished_; |
|
|
|
ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_; |
|
|
|
ZoneVector<ForeignVariable> foreign_variables_; |
|
|
|
WasmFunctionBuilder* init_function_; |
|
|
@ -1829,6 +1971,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
uint32_t next_table_index_; |
|
|
|
ZoneHashMap function_tables_; |
|
|
|
ImportedFunctionTable imported_function_table_; |
|
|
|
// Remember the parent node for reporting the correct location for ToNumber
|
|
|
|
// conversions after calls.
|
|
|
|
BinaryOperation* parent_binop_; |
|
|
|
|
|
|
|
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); |
|
|
|
|
|
|
@ -1836,22 +1981,24 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
|
|
|
DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl); |
|
|
|
}; |
|
|
|
|
|
|
|
AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone, |
|
|
|
FunctionLiteral* literal, AsmTyper* typer) |
|
|
|
: isolate_(isolate), zone_(zone), literal_(literal), typer_(typer) {} |
|
|
|
AsmWasmBuilder::AsmWasmBuilder(CompilationInfo* info) |
|
|
|
: info_(info), |
|
|
|
typer_(info->isolate(), info->zone(), info->script(), info->literal()) {} |
|
|
|
|
|
|
|
// 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.
|
|
|
|
AsmWasmBuilder::Result AsmWasmBuilder::Run( |
|
|
|
i::Handle<i::FixedArray>* foreign_args) { |
|
|
|
AsmWasmBuilderImpl impl(isolate_, zone_, literal_, typer_); |
|
|
|
impl.Build(); |
|
|
|
AsmWasmBuilder::Result AsmWasmBuilder::Run(Handle<FixedArray>* foreign_args) { |
|
|
|
Zone* zone = info_->zone(); |
|
|
|
AsmWasmBuilderImpl impl(info_->isolate(), zone, info_, |
|
|
|
info_->parse_info()->ast_value_factory(), |
|
|
|
info_->script(), info_->literal(), &typer_); |
|
|
|
bool success = impl.Build(); |
|
|
|
*foreign_args = impl.GetForeignArgs(); |
|
|
|
ZoneBuffer* module_buffer = new (zone_) ZoneBuffer(zone_); |
|
|
|
ZoneBuffer* module_buffer = new (zone) ZoneBuffer(zone); |
|
|
|
impl.builder_->WriteTo(*module_buffer); |
|
|
|
ZoneBuffer* asm_offsets_buffer = new (zone_) ZoneBuffer(zone_); |
|
|
|
ZoneBuffer* asm_offsets_buffer = new (zone) ZoneBuffer(zone); |
|
|
|
impl.builder_->WriteAsmJsOffsetTable(*asm_offsets_buffer); |
|
|
|
return {module_buffer, asm_offsets_buffer}; |
|
|
|
return {module_buffer, asm_offsets_buffer, success}; |
|
|
|
} |
|
|
|
|
|
|
|
const char* AsmWasmBuilder::foreign_init_name = "__foreign_init__"; |
|
|
|