Index: src/asmjs/asm-wasm-builder.cc |
diff --git a/src/asmjs/asm-wasm-builder.cc b/src/asmjs/asm-wasm-builder.cc |
index cac6fbd8b372c43cea8d43edec72199a2195ca42..bb9f14dea33b7e12950287d17482a1485bbf71c2 100644 |
--- a/src/asmjs/asm-wasm-builder.cc |
+++ b/src/asmjs/asm-wasm-builder.cc |
@@ -19,6 +19,10 @@ |
#include "src/ast/ast.h" |
#include "src/ast/scopes.h" |
+#include "src/codegen.h" |
+#include "src/compiler.h" |
+#include "src/isolate.h" |
+#include "src/parsing/parse-info.h" |
namespace v8 { |
namespace internal { |
@@ -42,8 +46,9 @@ struct ForeignVariable { |
class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
public: |
- AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal, |
- AsmTyper* typer) |
+ AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, |
+ AstValueFactory* ast_value_factory, Script* script, |
+ FunctionLiteral* literal, AsmTyper* typer) |
: local_variables_(ZoneHashMap::kDefaultHashMapCapacity, |
ZoneAllocationPolicy(zone)), |
functions_(ZoneHashMap::kDefaultHashMapCapacity, |
@@ -56,12 +61,14 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
literal_(literal), |
isolate_(isolate), |
zone_(zone), |
+ ast_value_factory_(ast_value_factory), |
+ script_(script), |
typer_(typer), |
+ typer_failed_(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) { |
@@ -92,8 +99,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
} |
} |
- 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 +109,21 @@ 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_failed_) { |
+ return false; |
+ } |
BuildForeignInitFunction(); |
+ return true; |
} |
void VisitVariableDeclaration(VariableDeclaration* decl) {} |
@@ -113,12 +131,62 @@ 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(bradnelson): Refactor parser so we don't need a |
+ // SharedFunctionInfo to parse a single function, |
+ // or squirrel away the SharedFunctionInfo to use later. |
+ Handle<SharedFunctionInfo> shared = |
+ isolate_->factory()->NewSharedFunctionInfoForLiteral( |
+ decl->fun(), handle(script_, isolate_)); |
+ shared->set_is_toplevel(false); |
+ ParseInfo info(&zone, handle(script_, isolate_)); |
+ 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; |
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,6 +197,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
continue; |
} |
RECURSE(Visit(stmt)); |
+ if (typer_failed_) break; |
if (stmt->IsJump()) break; |
} |
} |
@@ -245,6 +314,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
void VisitReturnStatement(ReturnStatement* stmt) { |
if (scope_ == kModuleScope) { |
+ if (!typer_->ValidateAfterFunctionsPhase()) { |
+ typer_failed_ = true; |
+ return; |
+ } |
scope_ = kExportScope; |
RECURSE(Visit(stmt->expression())); |
scope_ = kModuleScope; |
@@ -448,8 +521,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
UNREACHABLE(); |
} |
} |
- RECURSE(VisitStatements(expr->body())); |
RECURSE(VisitDeclarations(scope->declarations())); |
+ if (typer_failed_) return; |
+ RECURSE(VisitStatements(expr->body())); |
} |
void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { |
@@ -660,10 +734,22 @@ 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, |
@@ -675,38 +761,37 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
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()); |
+ DCHECK_NOT_NULL(indices); |
+ 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 +812,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()) { |
@@ -901,7 +999,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 +1008,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,7 +1046,7 @@ 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(); |
+ Object::ToName(isolate_, key_literal->value()).ToHandleChecked(); |
LocalType type = is_float ? kAstF64 : kAstI32; |
foreign_variables_.push_back({name, var, type}); |
} |
@@ -1325,7 +1419,7 @@ 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()); |
@@ -1348,7 +1442,7 @@ 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. |
@@ -1694,6 +1788,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
void VisitDeclarations(Declaration::List* decls) { |
for (Declaration* decl : *decls) { |
RECURSE(Visit(decl)); |
+ if (typer_failed_) { |
+ return; |
+ } |
} |
} |
@@ -1821,7 +1918,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
FunctionLiteral* literal_; |
Isolate* isolate_; |
Zone* zone_; |
+ AstValueFactory* ast_value_factory_; |
+ Script* script_; |
AsmTyper* typer_; |
+ bool typer_failed_; |
ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_; |
ZoneVector<ForeignVariable> foreign_variables_; |
WasmFunctionBuilder* init_function_; |
@@ -1837,21 +1937,27 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
}; |
AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone, |
- FunctionLiteral* literal, AsmTyper* typer) |
- : isolate_(isolate), zone_(zone), literal_(literal), typer_(typer) {} |
+ AstValueFactory* ast_value_factory, |
+ Script* script, FunctionLiteral* literal) |
+ : isolate_(isolate), |
+ zone_(zone), |
+ ast_value_factory_(ast_value_factory), |
+ script_(script), |
+ literal_(literal), |
+ typer_(isolate, zone, script, 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) { |
+ AsmWasmBuilderImpl impl(isolate_, zone_, ast_value_factory_, script_, |
+ literal_, &typer_); |
+ bool success = impl.Build(); |
*foreign_args = impl.GetForeignArgs(); |
ZoneBuffer* module_buffer = new (zone_) ZoneBuffer(zone_); |
impl.builder_->WriteTo(*module_buffer); |
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__"; |