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 {
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,
Handle<Object> foreign, AsmTyper* typer)
AsmTyper* typer)
: local_variables_(HashMap::PointersMatch,
ZoneHashMap::kDefaultHashMapCapacity,
ZoneAllocationPolicy(zone)),
......@@ -51,11 +57,12 @@ class AsmWasmBuilderImpl : public AstVisitor {
literal_(literal),
isolate_(isolate),
zone_(zone),
foreign_(foreign),
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_(HashMap::PointersMatch,
ZoneHashMap::kDefaultHashMapCapacity,
......@@ -74,9 +81,43 @@ class AsmWasmBuilderImpl : public AstVisitor {
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() {
InitializeInitFunction();
RECURSE(VisitFunctionLiteral(literal_));
BuildForeignInitFunction();
}
void VisitVariableDeclaration(VariableDeclaration* decl) {}
......@@ -706,13 +747,17 @@ class AsmWasmBuilderImpl : public AstVisitor {
DCHECK(binop->right()->IsLiteral());
DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot());
VisitForeignVariable(true, prop);
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());
VisitForeignVariable(false, prop);
DCHECK(target->IsVariableProxy());
VisitForeignVariable(false, target->AsVariableProxy()->var(), prop);
*is_nop = true;
return;
} else {
UNREACHABLE();
......@@ -835,51 +880,18 @@ class AsmWasmBuilderImpl : public AstVisitor {
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(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() && !foreign_.is_null() &&
foreign_->IsObject()) {
if (!key_literal->value().is_null()) {
Handle<Name> name =
i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked();
MaybeHandle<Object> maybe_value = i::Object::GetProperty(foreign_, name);
if (!maybe_value.is_null()) {
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));
LocalType type = is_float ? kAstF64 : kAstI32;
foreign_variables_.push_back({name, var, type});
}
}
......@@ -1724,11 +1736,12 @@ class AsmWasmBuilderImpl : public AstVisitor {
FunctionLiteral* literal_;
Isolate* isolate_;
Zone* zone_;
Handle<Object> foreign_;
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_;
......@@ -1741,19 +1754,15 @@ class AsmWasmBuilderImpl : public AstVisitor {
};
AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
FunctionLiteral* literal, Handle<Object> foreign,
AsmTyper* typer)
: isolate_(isolate),
zone_(zone),
literal_(literal),
foreign_(foreign),
typer_(typer) {}
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.
WasmModuleIndex* AsmWasmBuilder::Run() {
AsmWasmBuilderImpl impl(isolate_, zone_, literal_, foreign_, typer_);
WasmModuleIndex* AsmWasmBuilder::Run(i::Handle<i::FixedArray>* foreign_args) {
AsmWasmBuilderImpl impl(isolate_, zone_, literal_, typer_);
impl.Compile();
*foreign_args = impl.GetForeignArgs();
WasmModuleWriter* writer = impl.builder_->Build(zone_);
return writer->WriteTo(zone_);
}
......
......@@ -21,14 +21,13 @@ namespace wasm {
class AsmWasmBuilder {
public:
explicit AsmWasmBuilder(Isolate* isolate, Zone* zone, FunctionLiteral* root,
Handle<Object> foreign, AsmTyper* typer);
WasmModuleIndex* Run();
AsmTyper* typer);
WasmModuleIndex* Run(Handle<FixedArray>* foreign_args);
private:
Isolate* isolate_;
Zone* zone_;
FunctionLiteral* literal_;
Handle<Object> foreign_;
AsmTyper* typer_;
};
} // namespace wasm
......
......@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/api.h"
#include "src/api-natives.h"
#include "src/api.h"
#include "src/assert-scope.h"
#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/execution.h"
#include "src/factory.h"
#include "src/handles.h"
#include "src/isolate.h"
......@@ -121,7 +122,8 @@ void VerifyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
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_lazy(false);
info->set_allow_lazy_parsing(false);
......@@ -149,18 +151,18 @@ v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(
return nullptr;
}
auto module =
v8::internal::wasm::AsmWasmBuilder(info->isolate(), info->zone(),
info->literal(), foreign, &typer)
.Run();
v8::internal::wasm::AsmWasmBuilder builder(info->isolate(), info->zone(),
info->literal(), &typer);
auto module = builder.Run(foreign_args);
return module;
}
void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args,
const byte* start, const byte* end,
ErrorThrower* thrower,
internal::wasm::ModuleOrigin origin) {
i::MaybeHandle<i::JSObject> InstantiateModuleCommon(
const v8::FunctionCallbackInfo<v8::Value>& args, const byte* start,
const byte* end, ErrorThrower* thrower,
internal::wasm::ModuleOrigin origin) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
i::Handle<i::JSArrayBuffer> memory = i::Handle<i::JSArrayBuffer>::null();
......@@ -176,6 +178,7 @@ void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args,
internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule(
isolate, &zone, start, end, false, origin);
i::MaybeHandle<i::JSObject> object;
if (result.failed() && origin == internal::wasm::kAsmJsOrigin) {
thrower->Error("Asm.js converted module failed to decode");
} else if (result.failed()) {
......@@ -188,8 +191,7 @@ void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args,
ffi = i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
}
i::MaybeHandle<i::JSObject> object =
result.val->Instantiate(isolate, ffi, memory);
object = result.val->Instantiate(isolate, ffi, memory);
if (!object.is_null()) {
args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked()));
......@@ -197,6 +199,7 @@ void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args,
}
if (result.val) delete result.val;
return object;
}
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);
}
auto module = TranslateAsmModule(&info, foreign, &thrower);
i::Handle<i::FixedArray> foreign_args;
auto module = TranslateAsmModule(&info, &thrower, &foreign_args);
if (module == nullptr) {
return;
}
InstantiateModuleCommon(args, module->Begin(), module->End(), &thrower,
internal::wasm::kAsmJsOrigin);
i::MaybeHandle<i::Object> maybe_module_object =
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) {
......
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