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:
aseemgarg 2016-02-04 18:07:23 -08:00 committed by Commit bot
parent 21c045a2fa
commit f060922369
4 changed files with 199 additions and 30 deletions

View File

@ -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();

View File

@ -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;
}

View File

@ -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_;

View File

@ -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();