Commit cfed56c2 authored by bradnelson's avatar bradnelson Committed by Commit bot

[wasm] [asm.js] Track direct function indices and fixup.

Recent changes to the wasm format prevent you from knowing
the function index of a direct call until you know how many
imports you have (the index spaces have been merged).

Asm.js validation can't know this until all callsites have been
visited if you want to avoid materializing the entire AST / parsing twice.
Instead, keep a list of fixups to perform for all direct callsites,
then update these with the imports count added when emitting the module.

BUG=v8:4203
R=aseemgarg@chromium.org,titzer@chromium.org

Review-Url: https://codereview.chromium.org/2384623003
Cr-Commit-Position: refs/heads/master@{#39937}
parent 55478da2
...@@ -108,20 +108,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { ...@@ -108,20 +108,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
return ret; return ret;
} }
void BuildImports() {
for (const AsmTyper::FFIUseSignature& ffi : typer_->FFIUseSignatures()) {
size_t ret_count = ffi.return_type_ == AsmType::Void() ? 0 : 1;
FunctionSig::Builder b(zone_, ret_count, ffi.arg_types_.size());
for (AsmType* arg : ffi.arg_types_) b.AddParam(TypeFrom(arg));
if (ffi.return_type_ != AsmType::Void()) {
b.AddReturn(TypeFrom(ffi.return_type_));
}
imported_function_table_.AddFunction(ffi.var, b.Build());
}
}
void Build() { void Build() {
BuildImports();
InitializeInitFunction(); InitializeInitFunction();
RECURSE(VisitFunctionLiteral(literal_)); RECURSE(VisitFunctionLiteral(literal_));
BuildForeignInitFunction(); BuildForeignInitFunction();
...@@ -733,11 +720,12 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { ...@@ -733,11 +720,12 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
private: private:
class ImportedFunctionIndices : public ZoneObject { class ImportedFunctionIndices : public ZoneObject {
public: public:
bool has_name_; const char* name_;
int name_length_;
WasmModuleBuilder::SignatureMap signature_to_index_; WasmModuleBuilder::SignatureMap signature_to_index_;
explicit ImportedFunctionIndices(Zone* zone) ImportedFunctionIndices(const char* name, int name_length, Zone* zone)
: has_name_(false), signature_to_index_(zone) {} : name_(name), name_length_(name_length), signature_to_index_(zone) {}
}; };
ZoneHashMap table_; ZoneHashMap table_;
AsmWasmBuilderImpl* builder_; AsmWasmBuilderImpl* builder_;
...@@ -748,51 +736,31 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { ...@@ -748,51 +736,31 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
ZoneAllocationPolicy(builder->zone())), ZoneAllocationPolicy(builder->zone())),
builder_(builder) {} builder_(builder) {}
// Set the imported name of a variable. Must happen after all signatures void AddImport(Variable* v, const char* name, int name_length) {
// (and thus import indices) are added for a given variable. ImportedFunctionIndices* indices = new (builder_->zone())
void SetImportName(Variable* v, const char* name, int name_length) { ImportedFunctionIndices(name, name_length, builder_->zone());
auto indices = GetEntry(v); auto* entry = table_.LookupOrInsert(
if (indices) {
for (auto entry : indices->signature_to_index_) {
uint32_t index = entry.second;
builder_->builder_->SetImportName(index, name, name_length);
}
indices->has_name_ = true;
}
}
// Get a function's index. Does not insert new entries.
uint32_t GetFunctionIndex(Variable* v, FunctionSig* sig) {
auto indices = GetEntry(v);
DCHECK_NOT_NULL(indices);
auto pos = indices->signature_to_index_.find(sig);
DCHECK(pos != indices->signature_to_index_.end());
return pos->second;
}
// Add a function and register it as an import with the builder.
void AddFunction(Variable* v, FunctionSig* sig) {
auto entry = table_.LookupOrInsert(
v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone())); v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone()));
if (entry->value == nullptr) { entry->value = indices;
entry->value = }
new (builder_->zone()) ImportedFunctionIndices(builder_->zone());
} // Get a function's index (or allocate if new).
auto indices = reinterpret_cast<ImportedFunctionIndices*>(entry->value); uint32_t LookupOrInsertImport(Variable* v, FunctionSig* sig) {
DCHECK(!indices->has_name_); ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v));
auto pos = indices->signature_to_index_.find(sig); DCHECK_NOT_NULL(entry);
if (pos == indices->signature_to_index_.end()) { ImportedFunctionIndices* indices =
// A new import. Name is not known up front. reinterpret_cast<ImportedFunctionIndices*>(entry->value);
uint32_t index = builder_->builder_->AddImport(nullptr, 0, sig); 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; indices->signature_to_index_[sig] = index;
return index;
} }
} }
ImportedFunctionIndices* GetEntry(Variable* v) {
auto entry = table_.Lookup(v, ComputePointerHash(v));
if (entry == nullptr) return nullptr;
return reinterpret_cast<ImportedFunctionIndices*>(entry->value);
}
}; };
void EmitAssignmentLhs(Expression* target, MachineType* mtype) { void EmitAssignmentLhs(Expression* target, MachineType* mtype) {
...@@ -942,7 +910,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { ...@@ -942,7 +910,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
if (typer_->TypeOf(target)->AsFFIType() != nullptr) { if (typer_->TypeOf(target)->AsFFIType() != nullptr) {
const AstRawString* name = const AstRawString* name =
prop->key()->AsLiteral()->AsRawPropertyName(); prop->key()->AsLiteral()->AsRawPropertyName();
imported_function_table_.SetImportName( imported_function_table_.AddImport(
target->var(), reinterpret_cast<const char*>(name->raw_data()), target->var(), reinterpret_cast<const char*>(name->raw_data()),
name->length()); name->length());
} }
...@@ -1393,8 +1361,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { ...@@ -1393,8 +1361,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
for (int i = 0; i < args->length(); ++i) { for (int i = 0; i < args->length(); ++i) {
sig.AddParam(TypeOf(args->at(i))); sig.AddParam(TypeOf(args->at(i)));
} }
uint32_t index = uint32_t index = imported_function_table_.LookupOrInsertImport(
imported_function_table_.GetFunctionIndex(vp->var(), sig.Build()); vp->var(), sig.Build());
VisitCallArgs(expr); VisitCallArgs(expr);
current_function_builder_->Emit(kExprCallFunction); current_function_builder_->Emit(kExprCallFunction);
current_function_builder_->EmitVarInt(index); current_function_builder_->EmitVarInt(index);
...@@ -1402,7 +1370,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { ...@@ -1402,7 +1370,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
WasmFunctionBuilder* function = LookupOrInsertFunction(vp->var()); WasmFunctionBuilder* function = LookupOrInsertFunction(vp->var());
VisitCallArgs(expr); VisitCallArgs(expr);
current_function_builder_->Emit(kExprCallFunction); current_function_builder_->Emit(kExprCallFunction);
current_function_builder_->EmitVarInt(function->func_index()); current_function_builder_->EmitDirectCallIndex(
function->func_index());
returns_value = function->signature()->return_count() > 0; returns_value = function->signature()->return_count() > 0;
} }
break; break;
......
...@@ -51,14 +51,14 @@ WasmFunctionBuilder::WasmFunctionBuilder(WasmModuleBuilder* builder) ...@@ -51,14 +51,14 @@ WasmFunctionBuilder::WasmFunctionBuilder(WasmModuleBuilder* builder)
locals_(builder->zone()), locals_(builder->zone()),
signature_index_(0), signature_index_(0),
exported_(0), exported_(0),
func_index_(static_cast<uint32_t>(builder->imports_.size() + func_index_(static_cast<uint32_t>(builder->functions_.size())),
builder->functions_.size())),
body_(builder->zone()), body_(builder->zone()),
name_(builder->zone()), name_(builder->zone()),
i32_temps_(builder->zone()), i32_temps_(builder->zone()),
i64_temps_(builder->zone()), i64_temps_(builder->zone()),
f32_temps_(builder->zone()), f32_temps_(builder->zone()),
f64_temps_(builder->zone()) {} f64_temps_(builder->zone()),
direct_calls_(builder->zone()) {}
void WasmFunctionBuilder::EmitVarInt(uint32_t val) { void WasmFunctionBuilder::EmitVarInt(uint32_t val) {
byte buffer[8]; byte buffer[8];
...@@ -130,6 +130,15 @@ void WasmFunctionBuilder::EmitI32Const(int32_t value) { ...@@ -130,6 +130,15 @@ void WasmFunctionBuilder::EmitI32Const(int32_t value) {
} }
} }
void WasmFunctionBuilder::EmitDirectCallIndex(uint32_t index) {
DirectCallIndex call;
call.offset = body_.size();
call.direct_index = index;
direct_calls_.push_back(call);
byte code[] = {U32V_5(0)};
EmitCode(code, sizeof(code));
}
void WasmFunctionBuilder::SetExported() { exported_ = true; } void WasmFunctionBuilder::SetExported() { exported_ = true; }
void WasmFunctionBuilder::SetName(const char* name, int name_length) { void WasmFunctionBuilder::SetName(const char* name, int name_length) {
...@@ -152,7 +161,8 @@ void WasmFunctionBuilder::WriteExport(ZoneBuffer& buffer) const { ...@@ -152,7 +161,8 @@ void WasmFunctionBuilder::WriteExport(ZoneBuffer& buffer) const {
buffer.write(reinterpret_cast<const byte*>(&name_[0]), name_.size()); buffer.write(reinterpret_cast<const byte*>(&name_[0]), name_.size());
} }
buffer.write_u8(kExternalFunction); buffer.write_u8(kExternalFunction);
buffer.write_u32v(func_index_); buffer.write_u32v(func_index_ +
static_cast<uint32_t>(builder_->imports_.size()));
} }
} }
...@@ -164,7 +174,13 @@ void WasmFunctionBuilder::WriteBody(ZoneBuffer& buffer) const { ...@@ -164,7 +174,13 @@ void WasmFunctionBuilder::WriteBody(ZoneBuffer& buffer) const {
locals_.Emit(*ptr); locals_.Emit(*ptr);
(*ptr) += locals_size; // UGLY: manual bump of position pointer (*ptr) += locals_size; // UGLY: manual bump of position pointer
if (body_.size() > 0) { if (body_.size() > 0) {
size_t base = buffer.offset();
buffer.write(&body_[0], body_.size()); buffer.write(&body_[0], body_.size());
for (DirectCallIndex call : direct_calls_) {
buffer.patch_u32v(
base + call.offset,
call.direct_index + static_cast<uint32_t>(builder_->imports_.size()));
}
} }
} }
...@@ -230,7 +246,6 @@ void WasmModuleBuilder::AddIndirectFunction(uint32_t index) { ...@@ -230,7 +246,6 @@ void WasmModuleBuilder::AddIndirectFunction(uint32_t index) {
uint32_t WasmModuleBuilder::AddImport(const char* name, int name_length, uint32_t WasmModuleBuilder::AddImport(const char* name, int name_length,
FunctionSig* sig) { FunctionSig* sig) {
DCHECK_EQ(0, functions_.size()); // imports must be added before functions!
imports_.push_back({AddSignature(sig), name, name_length}); imports_.push_back({AddSignature(sig), name, name_length});
return static_cast<uint32_t>(imports_.size() - 1); return static_cast<uint32_t>(imports_.size() - 1);
} }
...@@ -369,7 +384,8 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const { ...@@ -369,7 +384,8 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
// == emit start function index ============================================== // == emit start function index ==============================================
if (start_function_index_ >= 0) { if (start_function_index_ >= 0) {
size_t start = EmitSection(kStartSectionCode, buffer); size_t start = EmitSection(kStartSectionCode, buffer);
buffer.write_u32v(start_function_index_); buffer.write_u32v(start_function_index_ +
static_cast<uint32_t>(imports_.size()));
FixupSection(buffer, start); FixupSection(buffer, start);
} }
...@@ -384,7 +400,7 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const { ...@@ -384,7 +400,7 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
buffer.write_size(indirect_functions_.size()); // element count buffer.write_size(indirect_functions_.size()); // element count
for (auto index : indirect_functions_) { for (auto index : indirect_functions_) {
buffer.write_u32v(index); buffer.write_u32v(index + static_cast<uint32_t>(imports_.size()));
} }
FixupSection(buffer, start); FixupSection(buffer, start);
......
...@@ -126,6 +126,7 @@ class V8_EXPORT_PRIVATE WasmFunctionBuilder : public ZoneObject { ...@@ -126,6 +126,7 @@ class V8_EXPORT_PRIVATE WasmFunctionBuilder : public ZoneObject {
void EmitWithU8(WasmOpcode opcode, const byte immediate); void EmitWithU8(WasmOpcode opcode, const byte immediate);
void EmitWithU8U8(WasmOpcode opcode, const byte imm1, const byte imm2); void EmitWithU8U8(WasmOpcode opcode, const byte imm1, const byte imm2);
void EmitWithVarInt(WasmOpcode opcode, uint32_t immediate); void EmitWithVarInt(WasmOpcode opcode, uint32_t immediate);
void EmitDirectCallIndex(uint32_t index);
void SetExported(); void SetExported();
void SetName(const char* name, int name_length); void SetName(const char* name, int name_length);
...@@ -141,6 +142,12 @@ class V8_EXPORT_PRIVATE WasmFunctionBuilder : public ZoneObject { ...@@ -141,6 +142,12 @@ class V8_EXPORT_PRIVATE WasmFunctionBuilder : public ZoneObject {
explicit WasmFunctionBuilder(WasmModuleBuilder* builder); explicit WasmFunctionBuilder(WasmModuleBuilder* builder);
friend class WasmModuleBuilder; friend class WasmModuleBuilder;
friend class WasmTemporary; friend class WasmTemporary;
struct DirectCallIndex {
size_t offset;
uint32_t direct_index;
};
WasmModuleBuilder* builder_; WasmModuleBuilder* builder_;
LocalDeclEncoder locals_; LocalDeclEncoder locals_;
uint32_t signature_index_; uint32_t signature_index_;
...@@ -152,6 +159,7 @@ class V8_EXPORT_PRIVATE WasmFunctionBuilder : public ZoneObject { ...@@ -152,6 +159,7 @@ class V8_EXPORT_PRIVATE WasmFunctionBuilder : public ZoneObject {
ZoneVector<uint32_t> i64_temps_; ZoneVector<uint32_t> i64_temps_;
ZoneVector<uint32_t> f32_temps_; ZoneVector<uint32_t> f32_temps_;
ZoneVector<uint32_t> f64_temps_; ZoneVector<uint32_t> f64_temps_;
ZoneVector<DirectCallIndex> direct_calls_;
}; };
class WasmTemporary { class WasmTemporary {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment