Add Foreign Functions to asm to wasm
R=bradnelson@chromium.org BUG=https://bugs.chromium.org/p/v8/issues/detail?id=4203 TEST=asm-wasm.js LOG=N Review URL: https://codereview.chromium.org/1667253003 Cr-Commit-Position: refs/heads/master@{#33757}
This commit is contained in:
parent
21c045a2fa
commit
f060922369
@ -51,7 +51,8 @@ class AsmWasmBuilderImpl : public AstVisitor {
|
||||
next_table_index_(0),
|
||||
function_tables_(HashMap::PointersMatch,
|
||||
ZoneHashMap::kDefaultHashMapCapacity,
|
||||
ZoneAllocationPolicy(zone)) {
|
||||
ZoneAllocationPolicy(zone)),
|
||||
imported_function_table_(this) {
|
||||
InitializeAstVisitor(isolate);
|
||||
}
|
||||
|
||||
@ -367,34 +368,26 @@ class AsmWasmBuilderImpl : public AstVisitor {
|
||||
void VisitVariableProxy(VariableProxy* expr) {
|
||||
if (in_function_) {
|
||||
Variable* var = expr->var();
|
||||
if (var->is_function()) {
|
||||
DCHECK(!is_set_op_);
|
||||
std::vector<uint8_t> index =
|
||||
UnsignedLEB128From(LookupOrInsertFunction(var));
|
||||
current_function_builder_->EmitCode(
|
||||
&index[0], static_cast<uint32_t>(index.size()));
|
||||
} else {
|
||||
if (is_set_op_) {
|
||||
if (var->IsContextSlot()) {
|
||||
current_function_builder_->Emit(kExprStoreGlobal);
|
||||
} else {
|
||||
current_function_builder_->Emit(kExprSetLocal);
|
||||
}
|
||||
is_set_op_ = false;
|
||||
} else {
|
||||
if (var->IsContextSlot()) {
|
||||
current_function_builder_->Emit(kExprLoadGlobal);
|
||||
} else {
|
||||
current_function_builder_->Emit(kExprGetLocal);
|
||||
}
|
||||
}
|
||||
LocalType var_type = TypeOf(expr);
|
||||
DCHECK(var_type != kAstStmt);
|
||||
if (is_set_op_) {
|
||||
if (var->IsContextSlot()) {
|
||||
AddLeb128(LookupOrInsertGlobal(var, var_type), false);
|
||||
current_function_builder_->Emit(kExprStoreGlobal);
|
||||
} else {
|
||||
AddLeb128(LookupOrInsertLocal(var, var_type), true);
|
||||
current_function_builder_->Emit(kExprSetLocal);
|
||||
}
|
||||
is_set_op_ = false;
|
||||
} else {
|
||||
if (var->IsContextSlot()) {
|
||||
current_function_builder_->Emit(kExprLoadGlobal);
|
||||
} else {
|
||||
current_function_builder_->Emit(kExprGetLocal);
|
||||
}
|
||||
}
|
||||
LocalType var_type = TypeOf(expr);
|
||||
DCHECK(var_type != kAstStmt);
|
||||
if (var->IsContextSlot()) {
|
||||
AddLeb128(LookupOrInsertGlobal(var, var_type), false);
|
||||
} else {
|
||||
AddLeb128(LookupOrInsertLocal(var, var_type), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -508,11 +501,80 @@ class AsmWasmBuilderImpl : public AstVisitor {
|
||||
return reinterpret_cast<FunctionTableIndices*>(entry->value);
|
||||
}
|
||||
|
||||
class ImportedFunctionTable {
|
||||
private:
|
||||
class ImportedFunctionIndices : public ZoneObject {
|
||||
public:
|
||||
const unsigned char* name_;
|
||||
int name_length_;
|
||||
WasmModuleBuilder::SignatureMap signature_to_index_;
|
||||
|
||||
ImportedFunctionIndices(const unsigned char* name, int name_length,
|
||||
Zone* zone)
|
||||
: name_(name), name_length_(name_length), signature_to_index_(zone) {}
|
||||
};
|
||||
ZoneHashMap table_;
|
||||
AsmWasmBuilderImpl* builder_;
|
||||
|
||||
public:
|
||||
explicit ImportedFunctionTable(AsmWasmBuilderImpl* builder)
|
||||
: table_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity,
|
||||
ZoneAllocationPolicy(builder->zone())),
|
||||
builder_(builder) {}
|
||||
|
||||
void AddImport(Variable* v, const unsigned char* name, int name_length) {
|
||||
ImportedFunctionIndices* indices = new (builder_->zone())
|
||||
ImportedFunctionIndices(name, name_length, builder_->zone());
|
||||
ZoneHashMap::Entry* entry = table_.LookupOrInsert(
|
||||
v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone()));
|
||||
entry->value = indices;
|
||||
}
|
||||
|
||||
uint16_t GetFunctionIndex(Variable* v, FunctionSig* sig) {
|
||||
ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v));
|
||||
DCHECK(entry != nullptr);
|
||||
ImportedFunctionIndices* indices =
|
||||
reinterpret_cast<ImportedFunctionIndices*>(entry->value);
|
||||
WasmModuleBuilder::SignatureMap::iterator pos =
|
||||
indices->signature_to_index_.find(sig);
|
||||
if (pos != indices->signature_to_index_.end()) {
|
||||
return pos->second;
|
||||
} else {
|
||||
uint16_t index = builder_->builder_->AddFunction();
|
||||
indices->signature_to_index_[sig] = index;
|
||||
WasmFunctionBuilder* function = builder_->builder_->FunctionAt(index);
|
||||
function->External(1);
|
||||
function->SetName(indices->name_, indices->name_length_);
|
||||
if (sig->return_count() > 0) {
|
||||
function->ReturnType(sig->GetReturn());
|
||||
}
|
||||
for (size_t i = 0; i < sig->parameter_count(); i++) {
|
||||
function->AddParam(sig->GetParam(i));
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void VisitAssignment(Assignment* expr) {
|
||||
bool in_init = false;
|
||||
if (!in_function_) {
|
||||
// TODO(bradnelson): Get rid of this.
|
||||
if (TypeOf(expr->value()) == kAstStmt) {
|
||||
Property* prop = expr->value()->AsProperty();
|
||||
if (prop != nullptr) {
|
||||
VariableProxy* vp = prop->obj()->AsVariableProxy();
|
||||
if (vp != nullptr && vp->var()->IsParameter() &&
|
||||
vp->var()->index() == 1) {
|
||||
VariableProxy* target = expr->target()->AsVariableProxy();
|
||||
if (target->bounds().lower->Is(Type::Function())) {
|
||||
const AstRawString* name =
|
||||
prop->key()->AsLiteral()->AsRawPropertyName();
|
||||
imported_function_table_.AddImport(
|
||||
target->var(), name->raw_data(), name->length());
|
||||
}
|
||||
}
|
||||
}
|
||||
ArrayLiteral* funcs = expr->value()->AsArrayLiteral();
|
||||
if (funcs != nullptr &&
|
||||
funcs->bounds().lower->AsArray()->Element()->IsFunction()) {
|
||||
@ -620,8 +682,29 @@ class AsmWasmBuilderImpl : public AstVisitor {
|
||||
switch (call_type) {
|
||||
case Call::OTHER_CALL: {
|
||||
DCHECK(in_function_);
|
||||
uint16_t index;
|
||||
VariableProxy* vp = expr->expression()->AsVariableProxy();
|
||||
if (vp != nullptr &&
|
||||
Type::Any()->Is(vp->bounds().lower->AsFunction()->Result())) {
|
||||
LocalType return_type = TypeOf(expr);
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
|
||||
args->length());
|
||||
if (return_type != kAstStmt) {
|
||||
sig.AddReturn(return_type);
|
||||
}
|
||||
for (int i = 0; i < args->length(); i++) {
|
||||
sig.AddParam(TypeOf(args->at(i)));
|
||||
}
|
||||
index =
|
||||
imported_function_table_.GetFunctionIndex(vp->var(), sig.Build());
|
||||
} else {
|
||||
index = LookupOrInsertFunction(vp->var());
|
||||
}
|
||||
current_function_builder_->Emit(kExprCallFunction);
|
||||
RECURSE(Visit(expr->expression()));
|
||||
std::vector<uint8_t> index_arr = UnsignedLEB128From(index);
|
||||
current_function_builder_->EmitCode(
|
||||
&index_arr[0], static_cast<uint32_t>(index_arr.size()));
|
||||
break;
|
||||
}
|
||||
case Call::KEYED_PROPERTY_CALL: {
|
||||
@ -1094,6 +1177,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
|
||||
uint16_t init_function_index_;
|
||||
uint32_t next_table_index_;
|
||||
ZoneHashMap function_tables_;
|
||||
ImportedFunctionTable imported_function_table_;
|
||||
|
||||
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
|
||||
|
||||
|
@ -263,7 +263,7 @@ uint32_t WasmFunctionEncoder::BodySize(void) const {
|
||||
|
||||
|
||||
uint32_t WasmFunctionEncoder::NameSize() const {
|
||||
return exported_ ? static_cast<uint32_t>(name_.size()) : 0;
|
||||
return HasName() ? static_cast<uint32_t>(name_.size()) : 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -47,7 +47,7 @@ class WasmFunctionEncoder : public ZoneObject {
|
||||
local_f64_count_) > 0;
|
||||
}
|
||||
|
||||
bool HasName() const { return exported_ && name_.size() > 0; }
|
||||
bool HasName() const { return (exported_ || external_) && name_.size() > 0; }
|
||||
};
|
||||
|
||||
class WasmFunctionBuilder : public ZoneObject {
|
||||
@ -133,12 +133,12 @@ class WasmModuleBuilder : public ZoneObject {
|
||||
void AddIndirectFunction(uint16_t index);
|
||||
WasmModuleWriter* Build(Zone* zone);
|
||||
|
||||
private:
|
||||
struct CompareFunctionSigs {
|
||||
bool operator()(FunctionSig* a, FunctionSig* b) const;
|
||||
};
|
||||
typedef ZoneMap<FunctionSig*, uint16_t, CompareFunctionSigs> SignatureMap;
|
||||
|
||||
private:
|
||||
Zone* zone_;
|
||||
ZoneVector<FunctionSig*> signatures_;
|
||||
ZoneVector<WasmFunctionBuilder*> functions_;
|
||||
|
@ -995,3 +995,88 @@ assertEquals(9, module.caller(0, 2, 54, 45));
|
||||
assertEquals(99, module.caller(0, 3, 54, 45));
|
||||
assertEquals(23, module.caller(0, 4, 12, 11));
|
||||
assertEquals(31, module.caller(1, 0, 30, 11));
|
||||
|
||||
|
||||
function TestForeignFunctions() {
|
||||
function AsmModule(stdlib, foreign, buffer) {
|
||||
"use asm";
|
||||
|
||||
var setVal = foreign.setVal;
|
||||
var getVal = foreign.getVal;
|
||||
|
||||
function caller(initial_value, new_value) {
|
||||
initial_value = initial_value|0;
|
||||
new_value = new_value|0;
|
||||
if ((getVal()|0) == (initial_value|0)) {
|
||||
setVal(new_value|0);
|
||||
return getVal()|0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return {caller:caller};
|
||||
}
|
||||
|
||||
function ffi(initial_val) {
|
||||
var val = initial_val;
|
||||
|
||||
function getVal() {
|
||||
return val;
|
||||
}
|
||||
|
||||
function setVal(new_val) {
|
||||
val = new_val;
|
||||
}
|
||||
|
||||
return {getVal:getVal, setVal:setVal};
|
||||
}
|
||||
|
||||
var foreign = new ffi(23);
|
||||
|
||||
var module = _WASMEXP_.instantiateModuleFromAsm(AsmModule.toString(),
|
||||
foreign, null);
|
||||
|
||||
module.__init__();
|
||||
assertEquals(103, module.caller(23, 103));
|
||||
}
|
||||
|
||||
TestForeignFunctions();
|
||||
|
||||
function TestForeignFunctionMultipleUse() {
|
||||
function AsmModule(stdlib, foreign, buffer) {
|
||||
"use asm";
|
||||
|
||||
var getVal = foreign.getVal;
|
||||
|
||||
function caller(int_val, double_val) {
|
||||
int_val = int_val|0;
|
||||
double_val = +double_val;
|
||||
if ((getVal()|0) == (int_val|0)) {
|
||||
if ((+getVal()) == (+double_val)) {
|
||||
return 89;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return {caller:caller};
|
||||
}
|
||||
|
||||
function ffi() {
|
||||
function getVal() {
|
||||
return 83.25;
|
||||
}
|
||||
|
||||
return {getVal:getVal};
|
||||
}
|
||||
|
||||
var foreign = new ffi();
|
||||
|
||||
var module = _WASMEXP_.instantiateModuleFromAsm(AsmModule.toString(),
|
||||
foreign, null);
|
||||
|
||||
module.__init__();
|
||||
assertEquals(89, module.caller(83, 83.25));
|
||||
}
|
||||
|
||||
TestForeignFunctionMultipleUse();
|
||||
|
Loading…
Reference in New Issue
Block a user