Commit 48c2857a authored by bradnelson's avatar bradnelson Committed by Commit bot

Delay asm->wasm foreign globals init until later.

Rather than bake foreign globals into the module
at compile time, add a __foreign_init__ function that can be called
after instantiation with foreign values gathers using keys
in a separately generated FixedArray.

This is an incremental step towards being able to enable asm->wasm
on for general traffic, behind a flag.

BUG= https://bugs.chromium.org/p/v8/issues/detail?id=4203
TEST=asm-wasm
R=titzer@chromium.org,aseemgarg@chromium.org
LOG=N

Review-Url: https://codereview.chromium.org/1999523002
Cr-Commit-Position: refs/heads/master@{#36418}
parent 43547df9
...@@ -33,10 +33,16 @@ namespace wasm { ...@@ -33,10 +33,16 @@ namespace wasm {
enum AsmScope { kModuleScope, kInitScope, kFuncScope, kExportScope }; enum AsmScope { kModuleScope, kInitScope, kFuncScope, kExportScope };
struct ForeignVariable {
Handle<Name> name;
Variable* var;
LocalType type;
};
class AsmWasmBuilderImpl : public AstVisitor { class AsmWasmBuilderImpl : public AstVisitor {
public: public:
AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal, AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal,
Handle<Object> foreign, AsmTyper* typer) AsmTyper* typer)
: local_variables_(HashMap::PointersMatch, : local_variables_(HashMap::PointersMatch,
ZoneHashMap::kDefaultHashMapCapacity, ZoneHashMap::kDefaultHashMapCapacity,
ZoneAllocationPolicy(zone)), ZoneAllocationPolicy(zone)),
...@@ -51,11 +57,12 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -51,11 +57,12 @@ class AsmWasmBuilderImpl : public AstVisitor {
literal_(literal), literal_(literal),
isolate_(isolate), isolate_(isolate),
zone_(zone), zone_(zone),
foreign_(foreign),
typer_(typer), typer_(typer),
cache_(TypeCache::Get()), cache_(TypeCache::Get()),
breakable_blocks_(zone), breakable_blocks_(zone),
foreign_variables_(zone),
init_function_index_(0), init_function_index_(0),
foreign_init_function_index_(0),
next_table_index_(0), next_table_index_(0),
function_tables_(HashMap::PointersMatch, function_tables_(HashMap::PointersMatch,
ZoneHashMap::kDefaultHashMapCapacity, ZoneHashMap::kDefaultHashMapCapacity,
...@@ -74,9 +81,43 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -74,9 +81,43 @@ class AsmWasmBuilderImpl : public AstVisitor {
current_function_builder_ = nullptr; 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_->Exported(1);
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 Compile() { void Compile() {
InitializeInitFunction(); InitializeInitFunction();
RECURSE(VisitFunctionLiteral(literal_)); RECURSE(VisitFunctionLiteral(literal_));
BuildForeignInitFunction();
} }
void VisitVariableDeclaration(VariableDeclaration* decl) {} void VisitVariableDeclaration(VariableDeclaration* decl) {}
...@@ -706,13 +747,17 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -706,13 +747,17 @@ class AsmWasmBuilderImpl : public AstVisitor {
DCHECK(binop->right()->IsLiteral()); DCHECK(binop->right()->IsLiteral());
DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber()); DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot()); DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot());
VisitForeignVariable(true, prop); DCHECK(target->IsVariableProxy());
VisitForeignVariable(true, target->AsVariableProxy()->var(), prop);
*is_nop = true;
return; return;
} else if (binop->op() == Token::BIT_OR) { } else if (binop->op() == Token::BIT_OR) {
DCHECK(binop->right()->IsLiteral()); DCHECK(binop->right()->IsLiteral());
DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber()); DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot()); DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot());
VisitForeignVariable(false, prop); DCHECK(target->IsVariableProxy());
VisitForeignVariable(false, target->AsVariableProxy()->var(), prop);
*is_nop = true;
return; return;
} else { } else {
UNREACHABLE(); UNREACHABLE();
...@@ -835,51 +880,18 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -835,51 +880,18 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitThrow(Throw* expr) { UNREACHABLE(); } void VisitThrow(Throw* expr) { UNREACHABLE(); }
void VisitForeignVariable(bool is_float, Property* expr) { void VisitForeignVariable(bool is_float, Variable* var, Property* expr) {
DCHECK(expr->obj()->AsVariableProxy()); DCHECK(expr->obj()->AsVariableProxy());
DCHECK(VariableLocation::PARAMETER == DCHECK(VariableLocation::PARAMETER ==
expr->obj()->AsVariableProxy()->var()->location()); expr->obj()->AsVariableProxy()->var()->location());
DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index()); DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index());
Literal* key_literal = expr->key()->AsLiteral(); Literal* key_literal = expr->key()->AsLiteral();
DCHECK_NOT_NULL(key_literal); DCHECK_NOT_NULL(key_literal);
if (!key_literal->value().is_null() && !foreign_.is_null() && if (!key_literal->value().is_null()) {
foreign_->IsObject()) {
Handle<Name> name = Handle<Name> name =
i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked(); i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked();
MaybeHandle<Object> maybe_value = i::Object::GetProperty(foreign_, name); LocalType type = is_float ? kAstF64 : kAstI32;
if (!maybe_value.is_null()) { foreign_variables_.push_back({name, var, type});
Handle<Object> value = maybe_value.ToHandleChecked();
if (is_float) {
MaybeHandle<Object> maybe_nvalue = i::Object::ToNumber(value);
if (!maybe_nvalue.is_null()) {
Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
if (nvalue->IsNumber()) {
double val = nvalue->Number();
byte code[] = {WASM_F64(val)};
current_function_builder_->EmitCode(code, sizeof(code));
return;
}
}
} else {
MaybeHandle<Object> maybe_nvalue =
i::Object::ToInt32(isolate_, value);
if (!maybe_nvalue.is_null()) {
Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
if (nvalue->IsNumber()) {
int32_t val = static_cast<int32_t>(nvalue->Number());
current_function_builder_->EmitI32Const(val);
return;
}
}
}
}
}
if (is_float) {
byte code[] = {WASM_F64(std::numeric_limits<double>::quiet_NaN())};
current_function_builder_->EmitCode(code, sizeof(code));
} else {
byte code[] = {WASM_I32V_1(0)};
current_function_builder_->EmitCode(code, sizeof(code));
} }
} }
...@@ -1724,11 +1736,12 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -1724,11 +1736,12 @@ class AsmWasmBuilderImpl : public AstVisitor {
FunctionLiteral* literal_; FunctionLiteral* literal_;
Isolate* isolate_; Isolate* isolate_;
Zone* zone_; Zone* zone_;
Handle<Object> foreign_;
AsmTyper* typer_; AsmTyper* typer_;
TypeCache const& cache_; TypeCache const& cache_;
ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_; ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
ZoneVector<ForeignVariable> foreign_variables_;
uint32_t init_function_index_; uint32_t init_function_index_;
uint32_t foreign_init_function_index_;
uint32_t next_table_index_; uint32_t next_table_index_;
ZoneHashMap function_tables_; ZoneHashMap function_tables_;
ImportedFunctionTable imported_function_table_; ImportedFunctionTable imported_function_table_;
...@@ -1741,19 +1754,15 @@ class AsmWasmBuilderImpl : public AstVisitor { ...@@ -1741,19 +1754,15 @@ class AsmWasmBuilderImpl : public AstVisitor {
}; };
AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone, AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
FunctionLiteral* literal, Handle<Object> foreign, FunctionLiteral* literal, AsmTyper* typer)
AsmTyper* typer) : isolate_(isolate), zone_(zone), literal_(literal), typer_(typer) {}
: isolate_(isolate),
zone_(zone),
literal_(literal),
foreign_(foreign),
typer_(typer) {}
// TODO(aseemgarg): probably should take zone (to write wasm to) as input so // 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. // that zone in constructor may be thrown away once wasm module is written.
WasmModuleIndex* AsmWasmBuilder::Run() { WasmModuleIndex* AsmWasmBuilder::Run(i::Handle<i::FixedArray>* foreign_args) {
AsmWasmBuilderImpl impl(isolate_, zone_, literal_, foreign_, typer_); AsmWasmBuilderImpl impl(isolate_, zone_, literal_, typer_);
impl.Compile(); impl.Compile();
*foreign_args = impl.GetForeignArgs();
WasmModuleWriter* writer = impl.builder_->Build(zone_); WasmModuleWriter* writer = impl.builder_->Build(zone_);
return writer->WriteTo(zone_); return writer->WriteTo(zone_);
} }
......
...@@ -21,14 +21,13 @@ namespace wasm { ...@@ -21,14 +21,13 @@ namespace wasm {
class AsmWasmBuilder { class AsmWasmBuilder {
public: public:
explicit AsmWasmBuilder(Isolate* isolate, Zone* zone, FunctionLiteral* root, explicit AsmWasmBuilder(Isolate* isolate, Zone* zone, FunctionLiteral* root,
Handle<Object> foreign, AsmTyper* typer); AsmTyper* typer);
WasmModuleIndex* Run(); WasmModuleIndex* Run(Handle<FixedArray>* foreign_args);
private: private:
Isolate* isolate_; Isolate* isolate_;
Zone* zone_; Zone* zone_;
FunctionLiteral* literal_; FunctionLiteral* literal_;
Handle<Object> foreign_;
AsmTyper* typer_; AsmTyper* typer_;
}; };
} // namespace wasm } // namespace wasm
......
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "src/api.h"
#include "src/api-natives.h" #include "src/api-natives.h"
#include "src/api.h"
#include "src/assert-scope.h" #include "src/assert-scope.h"
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/ast/scopes.h" #include "src/ast/scopes.h"
#include "src/execution.h"
#include "src/factory.h" #include "src/factory.h"
#include "src/handles.h" #include "src/handles.h"
#include "src/isolate.h" #include "src/isolate.h"
...@@ -121,7 +122,8 @@ void VerifyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -121,7 +122,8 @@ void VerifyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
} }
v8::internal::wasm::WasmModuleIndex* TranslateAsmModule( v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(
i::ParseInfo* info, i::Handle<i::Object> foreign, ErrorThrower* thrower) { i::ParseInfo* info, ErrorThrower* thrower,
i::Handle<i::FixedArray>* foreign_args) {
info->set_global(); info->set_global();
info->set_lazy(false); info->set_lazy(false);
info->set_allow_lazy_parsing(false); info->set_allow_lazy_parsing(false);
...@@ -149,18 +151,18 @@ v8::internal::wasm::WasmModuleIndex* TranslateAsmModule( ...@@ -149,18 +151,18 @@ v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(
return nullptr; return nullptr;
} }
auto module = v8::internal::wasm::AsmWasmBuilder builder(info->isolate(), info->zone(),
v8::internal::wasm::AsmWasmBuilder(info->isolate(), info->zone(), info->literal(), &typer);
info->literal(), foreign, &typer)
.Run(); auto module = builder.Run(foreign_args);
return module; return module;
} }
void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args, i::MaybeHandle<i::JSObject> InstantiateModuleCommon(
const byte* start, const byte* end, const v8::FunctionCallbackInfo<v8::Value>& args, const byte* start,
ErrorThrower* thrower, const byte* end, ErrorThrower* thrower,
internal::wasm::ModuleOrigin origin) { internal::wasm::ModuleOrigin origin) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate()); i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
i::Handle<i::JSArrayBuffer> memory = i::Handle<i::JSArrayBuffer>::null(); i::Handle<i::JSArrayBuffer> memory = i::Handle<i::JSArrayBuffer>::null();
...@@ -176,6 +178,7 @@ void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args, ...@@ -176,6 +178,7 @@ void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args,
internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule( internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule(
isolate, &zone, start, end, false, origin); isolate, &zone, start, end, false, origin);
i::MaybeHandle<i::JSObject> object;
if (result.failed() && origin == internal::wasm::kAsmJsOrigin) { if (result.failed() && origin == internal::wasm::kAsmJsOrigin) {
thrower->Error("Asm.js converted module failed to decode"); thrower->Error("Asm.js converted module failed to decode");
} else if (result.failed()) { } else if (result.failed()) {
...@@ -188,8 +191,7 @@ void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args, ...@@ -188,8 +191,7 @@ void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args,
ffi = i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj)); ffi = i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
} }
i::MaybeHandle<i::JSObject> object = object = result.val->Instantiate(isolate, ffi, memory);
result.val->Instantiate(isolate, ffi, memory);
if (!object.is_null()) { if (!object.is_null()) {
args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked())); args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked()));
...@@ -197,6 +199,7 @@ void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args, ...@@ -197,6 +199,7 @@ void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args,
} }
if (result.val) delete result.val; if (result.val) delete result.val;
return object;
} }
void InstantiateModuleFromAsm(const v8::FunctionCallbackInfo<v8::Value>& args) { void InstantiateModuleFromAsm(const v8::FunctionCallbackInfo<v8::Value>& args) {
...@@ -221,13 +224,54 @@ void InstantiateModuleFromAsm(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -221,13 +224,54 @@ void InstantiateModuleFromAsm(const v8::FunctionCallbackInfo<v8::Value>& args) {
foreign = v8::Utils::OpenHandle(*local_foreign); foreign = v8::Utils::OpenHandle(*local_foreign);
} }
auto module = TranslateAsmModule(&info, foreign, &thrower); i::Handle<i::FixedArray> foreign_args;
auto module = TranslateAsmModule(&info, &thrower, &foreign_args);
if (module == nullptr) { if (module == nullptr) {
return; return;
} }
InstantiateModuleCommon(args, module->Begin(), module->End(), &thrower, i::MaybeHandle<i::Object> maybe_module_object =
internal::wasm::kAsmJsOrigin); InstantiateModuleCommon(args, module->Begin(), module->End(), &thrower,
internal::wasm::kAsmJsOrigin);
if (maybe_module_object.is_null()) {
return;
}
i::Handle<i::Name> name =
factory->NewStringFromStaticChars("__foreign_init__");
i::Handle<i::Object> module_object = maybe_module_object.ToHandleChecked();
i::MaybeHandle<i::Object> maybe_init =
i::Object::GetProperty(module_object, name);
DCHECK(!maybe_init.is_null());
i::Handle<i::Object> init = maybe_init.ToHandleChecked();
i::Handle<i::Object> undefined(isolate->heap()->undefined_value(), isolate);
i::Handle<i::Object>* foreign_args_array =
new i::Handle<i::Object>[foreign_args->length()];
for (int j = 0; j < foreign_args->length(); j++) {
if (!foreign.is_null()) {
i::MaybeHandle<i::Name> name = i::Object::ToName(
isolate, i::Handle<i::Object>(foreign_args->get(j), isolate));
if (!name.is_null()) {
i::MaybeHandle<i::Object> val =
i::Object::GetProperty(foreign, name.ToHandleChecked());
if (!val.is_null()) {
foreign_args_array[j] = val.ToHandleChecked();
continue;
}
}
}
foreign_args_array[j] = undefined;
}
i::MaybeHandle<i::Object> retval = i::Execution::Call(
isolate, init, undefined, foreign_args->length(), foreign_args_array);
delete[] foreign_args_array;
if (retval.is_null()) {
thrower.Error(
"WASM.instantiateModuleFromAsm(): foreign init function failed");
}
} }
void InstantiateModule(const v8::FunctionCallbackInfo<v8::Value>& args) { void InstantiateModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
......
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