[wasm] Remove single function JIT support.

While we might at some point want to explore if this is a win versus
whole modules, for now we have the Tables interface planned.

R=titzer@chromium.org,ahaas@chromium.org,mtrofin@chromium.org,rossberg@chromium.org
BUG=v8:5044

Review-Url: https://codereview.chromium.org/2226053002
Cr-Commit-Position: refs/heads/master@{#38461}
This commit is contained in:
bradnelson 2016-08-08 14:47:42 -07:00 committed by Commit bot
parent b1d53a1549
commit 1c5c526b90
12 changed files with 3 additions and 380 deletions

View File

@ -2058,103 +2058,6 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args,
return BuildWasmCall(sig, args, position);
}
Node* WasmGraphBuilder::JITSingleFunction(Node* const base, Node* const length,
Node* const index,
const uint32_t sig_index,
wasm::FunctionSig* const sig,
wasm::WasmCodePosition position) {
MachineOperatorBuilder* machine = jsgraph()->machine();
// Bounds check the memory access
{
Node* base_negative =
graph()->NewNode(machine->Uint32LessThan(), base, Int32Constant(0));
trap_->AddTrapIfTrue(wasm::kTrapMemOutOfBounds, base_negative, position);
Node* length_negative = graph()->NewNode(machine->Uint32LessThanOrEqual(),
length, Int32Constant(0));
trap_->AddTrapIfTrue(wasm::kTrapFuncInvalid, length_negative, position);
Node* in_bounds = graph()->NewNode(
machine->Uint32LessThanOrEqual(),
graph()->NewNode(machine->Int32Add(), base, length), MemSize(0));
trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, in_bounds, position);
}
// Bounds check the index.
{
// Assume only one table for now.
DCHECK_LE(module_->instance->function_tables.size(), 1u);
uint32_t table_size =
module_->IsValidTable(0) ? module_->GetTable(0)->max_size : 0;
if (table_size > 0) {
// Bounds check against the table size.
Node* size = Uint32Constant(table_size);
Node* in_bounds =
graph()->NewNode(machine->Uint32LessThan(), index, size);
trap_->AddTrapIfFalse(wasm::kTrapInvalidIndex, in_bounds, position);
} else {
// No function table. Generate a trap and return a constant.
trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, Int32Constant(0), position);
return trap_->GetTrapValue(module_->GetSignature(sig_index));
}
}
const size_t runtime_input_params = 7;
const size_t runtime_env_params = 5;
Runtime::FunctionId f = Runtime::kJITSingleFunction;
const Runtime::Function* fun = Runtime::FunctionForId(f);
// CEntryStubConstant nodes have to be created and cached in the main
// thread. At the moment this is only done for CEntryStubConstant(1).
DCHECK_EQ(1, fun->result_size);
const uint32_t return_count = static_cast<uint32_t>(sig->return_count());
const uint32_t parameter_count =
static_cast<uint32_t>(sig->parameter_count());
const uint32_t inputs_size = runtime_input_params + runtime_env_params +
return_count + parameter_count;
Node** inputs = Buffer(inputs_size);
inputs[0] = jsgraph()->CEntryStubConstant(fun->result_size);
inputs[1] = BuildChangeUint32ToSmi(base);
inputs[2] = BuildChangeUint32ToSmi(length);
inputs[3] = BuildChangeUint32ToSmi(index);
inputs[4] = FunctionTable(0);
inputs[5] = Uint32Constant(sig_index);
inputs[6] = BuildChangeUint32ToSmi(Uint32Constant(return_count));
// Pass in parameters and return types in to the runtime function
// to allow it to regenerate signature
for (uint32_t i = 0; i < return_count; ++i) {
inputs[i + runtime_input_params] = BuildChangeUint32ToSmi(
Uint32Constant(static_cast<int>(sig->GetReturn(i))));
}
for (uint32_t i = 0; i < parameter_count; ++i) {
inputs[i + runtime_input_params + return_count] = BuildChangeUint32ToSmi(
Uint32Constant(static_cast<int>(sig->GetParam(i))));
}
const uint32_t args_offset = inputs_size - runtime_env_params;
inputs[args_offset] = jsgraph()->ExternalConstant(
ExternalReference(f, jsgraph()->isolate())); // ref
inputs[args_offset + 1] = jsgraph()->Int32Constant(args_offset - 1); // arity
inputs[args_offset + 2] =
HeapConstant(module_->instance->context); // context
inputs[args_offset + 3] = *effect_;
inputs[args_offset + 4] = *control_;
// Use the module context to call the runtime.
CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
jsgraph()->zone(), f, args_offset - 1, Operator::kNoProperties,
CallDescriptor::kNoFlags);
Node* node =
graph()->NewNode(jsgraph()->common()->Call(desc), inputs_size, inputs);
*control_ = node;
*effect_ = node;
return node;
}
Node* WasmGraphBuilder::BuildI32Rol(Node* left, Node* right) {
// Implement Rol by Ror since TurboFan does not have Rol opcode.
// TODO(weiliang): support Word32Rol opcode in TurboFan.

View File

@ -158,9 +158,6 @@ class WasmGraphBuilder {
wasm::WasmCodePosition position);
Node* CallIndirect(uint32_t index, Node** args,
wasm::WasmCodePosition position);
Node* JITSingleFunction(Node* base, Node* length, Node* index,
uint32_t sig_index, wasm::FunctionSig* sig,
wasm::WasmCodePosition position);
void BuildJSToWasmWrapper(Handle<Code> wasm_code, wasm::FunctionSig* sig);
void BuildWasmToJSWrapper(Handle<JSFunction> function,
wasm::FunctionSig* sig);

View File

@ -524,8 +524,6 @@ DEFINE_STRING(dump_wasm_module_path, NULL, "directory to dump wasm modules to")
DEFINE_INT(typed_array_max_size_in_heap, 64,
"threshold for in-heap typed array")
DEFINE_BOOL(wasm_jit_prototype, false,
"enable experimental wasm runtime dynamic code generation")
DEFINE_BOOL(wasm_simd_prototype, false,
"enable prototype simd opcodes for wasm")

View File

@ -109,82 +109,5 @@ RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
return *isolate->factory()->NewNumberFromInt(old_size /
wasm::WasmModule::kPageSize);
}
RUNTIME_FUNCTION(Runtime_JITSingleFunction) {
const int fixed_args = 6;
HandleScope scope(isolate);
DCHECK_LE(fixed_args, args.length());
CONVERT_SMI_ARG_CHECKED(base, 0);
CONVERT_SMI_ARG_CHECKED(length, 1);
CONVERT_SMI_ARG_CHECKED(index, 2);
CONVERT_ARG_HANDLE_CHECKED(FixedArray, function_table, 3);
CONVERT_UINT32_ARG_CHECKED(sig_index, 4);
CONVERT_SMI_ARG_CHECKED(return_count, 5);
Handle<JSObject> module_object;
{
// Get the module JSObject
DisallowHeapAllocation no_allocation;
const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
Address pc =
Memory::Address_at(entry + StandardFrameConstants::kCallerPCOffset);
Code* code =
isolate->inner_pointer_to_code_cache()->GetCacheEntry(pc)->code;
FixedArray* deopt_data = code->deoptimization_data();
DCHECK(deopt_data->length() == 2);
module_object = Handle<JSObject>::cast(handle(deopt_data->get(0), isolate));
CHECK(!module_object->IsNull(isolate));
}
// Get mem buffer associated with module object
Handle<Object> obj(module_object->GetInternalField(kWasmMemArrayBuffer),
isolate);
if (obj->IsUndefined(isolate)) {
return isolate->heap()->undefined_value();
}
Handle<JSArrayBuffer> mem_buffer = Handle<JSArrayBuffer>::cast(obj);
wasm::WasmModule module(reinterpret_cast<byte*>(mem_buffer->backing_store()));
wasm::ErrorThrower thrower(isolate, "JITSingleFunction");
wasm::ModuleEnv module_env;
module_env.module = &module;
module_env.instance = nullptr;
module_env.origin = wasm::kWasmOrigin;
uint32_t signature_size = args.length() - fixed_args;
wasm::LocalType* sig_types = new wasm::LocalType[signature_size];
for (uint32_t i = 0; i < signature_size; ++i) {
CONVERT_SMI_ARG_CHECKED(sig_type, i + fixed_args);
sig_types[i] = static_cast<wasm::LocalType>(sig_type);
}
wasm::FunctionSig sig(return_count, signature_size - return_count, sig_types);
wasm::WasmFunction func;
func.sig = &sig;
func.func_index = index;
func.sig_index = sig_index;
func.name_offset = 0;
func.name_length = 0;
func.code_start_offset = base;
func.code_end_offset = base + length;
Handle<Code> code = compiler::WasmCompilationUnit::CompileWasmFunction(
&thrower, isolate, &module_env, &func);
delete[] sig_types;
if (thrower.error()) {
return isolate->heap()->undefined_value();
}
function_table->set(index, Smi::FromInt(sig_index));
function_table->set(index + function_table->length() / 2, *code);
return isolate->heap()->undefined_value();
}
} // namespace internal
} // namespace v8

View File

@ -303,7 +303,6 @@ namespace internal {
F(ThrowGeneratorRunning, 0, 1) \
F(ThrowStackOverflow, 0, 1) \
F(ThrowWasmError, 2, 1) \
F(JITSingleFunction, -1 /* >= 7 */, 1) \
F(PromiseRejectEvent, 3, 1) \
F(PromiseRevokeReject, 1, 1) \
F(StackGuard, 0, 1) \

View File

@ -192,23 +192,6 @@ class WasmDecoder : public Decoder {
return false;
}
inline bool Complete(const byte* pc, JITSingleFunctionOperand& operand) {
ModuleEnv* m = module_;
if (m && m->module && operand.sig_index < m->module->signatures.size()) {
operand.sig = m->module->signatures[operand.sig_index];
return true;
}
return false;
}
inline bool Validate(const byte* pc, JITSingleFunctionOperand& operand) {
if (Complete(pc, operand)) {
return true;
}
error(pc, pc + 1, "invalid signature index");
return false;
}
inline bool Validate(const byte* pc, BreakDepthOperand& operand,
ZoneVector<Control>& control) {
if (operand.arity > 1) {
@ -303,8 +286,6 @@ class WasmDecoder : public Decoder {
ReturnArityOperand operand(this, pc);
return operand.arity;
}
case kExprJITSingleFunction:
return 3;
#define DECLARE_OPCODE_CASE(name, opcode, sig) \
case kExpr##name: \
@ -358,10 +339,6 @@ class WasmDecoder : public Decoder {
return 1 + operand.length;
}
case kExprJITSingleFunction: {
JITSingleFunctionOperand operand(this, pc);
return 1 + operand.length;
}
case kExprSetLocal:
case kExprGetLocal: {
LocalIndexOperand operand(this, pc);
@ -1027,21 +1004,6 @@ class WasmFullDecoder : public WasmDecoder {
break;
}
}
case kExprJITSingleFunction: {
if (FLAG_wasm_jit_prototype) {
JITSingleFunctionOperand operand(this, pc_);
if (Validate(pc_, operand)) {
Value index = Pop(2, kAstI32);
Value length = Pop(1, kAstI32);
Value base = Pop(0, kAstI32);
TFNode* call =
BUILD(JITSingleFunction, base.node, length.node, index.node,
operand.sig_index, operand.sig, position());
Push(kAstI32, call);
break;
}
}
}
default:
error("Invalid opcode");
return;
@ -1677,13 +1639,6 @@ bool PrintAst(base::AccountingAllocator* allocator, const FunctionBody& body,
}
break;
}
case kExprJITSingleFunction: {
JITSingleFunctionOperand operand(&i, i.pc());
if (decoder.Complete(i.pc(), operand)) {
os << " // sig #" << operand.sig_index << ": " << *operand.sig;
}
break;
}
case kExprReturn: {
ReturnArityOperand operand(&i, i.pc());
os << " // arity=" << operand.arity;

View File

@ -148,16 +148,6 @@ struct CallImportOperand {
}
};
struct JITSingleFunctionOperand {
uint32_t sig_index;
FunctionSig* sig;
unsigned length;
inline JITSingleFunctionOperand(Decoder* decoder, const byte* pc) {
sig_index = decoder->checked_read_u32v(pc, 1, &length, "signature index");
sig = nullptr;
}
};
struct BranchTableOperand {
uint32_t arity;
uint32_t table_count;

View File

@ -507,10 +507,9 @@ class ModuleDecoder : public Decoder {
void DecodeFunctionTableInModule(WasmModule* module,
WasmIndirectFunctionTable* table) {
table->size = consume_u32v("function table entry count");
table->max_size = FLAG_wasm_jit_prototype ? consume_u32v() : table->size;
table->max_size = table->size;
if ((!FLAG_wasm_jit_prototype && table->max_size != table->size) ||
(FLAG_wasm_jit_prototype && table->max_size < table->size)) {
if (table->max_size != table->size) {
error("invalid table maximum size");
}

View File

@ -391,9 +391,6 @@ const WasmCodePosition kNoCodePosition = -1;
V(S128Xor, 0xe578, s_ss) \
V(S128Not, 0xe579, s_s)
// For enabling JIT functionality
#define FOREACH_JIT_OPCODE(V) V(JITSingleFunction, 0xf0, _)
// All opcodes.
#define FOREACH_OPCODE(V) \
FOREACH_CONTROL_OPCODE(V) \
@ -404,8 +401,7 @@ const WasmCodePosition kNoCodePosition = -1;
FOREACH_LOAD_MEM_OPCODE(V) \
FOREACH_MISC_MEM_OPCODE(V) \
FOREACH_ASMJS_COMPAT_OPCODE(V) \
FOREACH_SIMD_OPCODE(V) \
FOREACH_JIT_OPCODE(V)
FOREACH_SIMD_OPCODE(V)
// All signatures.
#define FOREACH_SIGNATURE(V) \

View File

@ -1,56 +0,0 @@
// Copyright 2015 the V8 project authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-wasm
// Flags: --wasm-jit-prototype
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
var module = (function () {
var builder = new WasmModuleBuilder();
var sig_index = builder.addType(kSig_i_ii);
builder.addPadFunctionTable(512);
builder.addImport("add", sig_index);
builder.addFunction("add", sig_index)
.addBody([
kExprGetLocal, 0, kExprGetLocal, 1, kExprCallImport, kArity2, 0
]);
builder.addFunction("sub", sig_index)
.addBody([
kExprGetLocal, 0, // --
kExprGetLocal, 1, // --
kExprI32Sub, // --
]);
builder.addFunction("main", kSig_i_iii)
.addBody([
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprGetLocal, 2,
kExprCallIndirect, kArity2, sig_index
])
.exportFunc()
builder.appendToTable([0, 1, 2]);
return builder.instantiate({add: function(a, b) { return a + b | 0; }});
})();
// Check the module exists.
assertFalse(module === undefined);
assertFalse(module === null);
assertFalse(module === 0);
assertEquals("object", typeof module.exports);
assertEquals("function", typeof module.exports.main);
assertEquals(5, module.exports.main(1, 12, 7));
assertEquals(19, module.exports.main(0, 12, 7));
assertTraps(kTrapFuncSigMismatch, "module.exports.main(2, 12, 33)");
assertTraps(kTrapFuncSigMismatch, "module.exports.main(4, 12, 33)");
assertTraps(kTrapFuncSigMismatch, "module.exports.main(511, 12, 33)");
assertTraps(kTrapFuncInvalid, "module.exports.main(512, 12, 33)");
assertTraps(kTrapFuncInvalid, "module.exports.main(1025, 12, 33)");
assertTraps(kTrapFuncInvalid, "module.exports.main(-1, 12, 33)");

View File

@ -1,79 +0,0 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-wasm
// Flags: --wasm-jit-prototype
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
var module = (function () {
var builder = new WasmModuleBuilder();
var kSig_i_iiiii =
makeSig([kAstI32, kAstI32, kAstI32, kAstI32, kAstI32], [kAstI32]);
var sig_index2 = builder.addType(kSig_i_ii);
var sig_index5 = builder.addType(kSig_i_iiiii);
builder.addMemory(1, 1, true);
var wasm_bytes_sub = [
0,
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprI32Sub
];
builder.addDataSegment(0, wasm_bytes_sub, false);
var wasm_bytes_mul = [
0,
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprI32Mul
];
builder.addDataSegment(6, wasm_bytes_mul, false);
builder.addPadFunctionTable(10);
builder.addImport("add", sig_index2);
builder.addFunction("add", sig_index2)
.addBody([
kExprGetLocal, 0, kExprGetLocal, 1, kExprCallImport, kArity2, 0
]);
builder.addFunction("main", sig_index5)
.addBody([
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprGetLocal, 2,
kExprJITSingleFunction, sig_index2,
kExprGetLocal, 2,
kExprGetLocal, 3,
kExprGetLocal, 4,
kExprCallIndirect, kArity2, sig_index2
])
.exportFunc()
builder.appendToTable([0, 1]);
return builder.instantiate({add: function(a, b) { return a + b | 0; }});
})();
// Check that the module exists
assertFalse(module === undefined);
assertFalse(module === null);
assertFalse(module === 0);
assertEquals("object", typeof module.exports);
assertEquals("function", typeof module.exports.main);
// Check that the bytes referred to lie in the bounds of the memory buffer
assertTraps(kTrapMemOutOfBounds, "module.exports.main(0, 100000, 3, 55, 99)");
assertTraps(kTrapMemOutOfBounds, "module.exports.main(65536, 1, 3, 55, 99)");
// Check that the index lies in the bounds of the table size
assertTraps(kTrapInvalidIndex, "module.exports.main(0, 6, 10, 55, 99)");
assertTraps(kTrapInvalidIndex, "module.exports.main(0, 6, -1, 55, 99)");
// args: base offset, size of func_bytes, index, param1, param2
assertEquals(-444, module.exports.main(0, 6, 3, 555, 999)); // JIT sub function
assertEquals(13, module.exports.main(0, 6, 9, 45, 32)); // JIT sub function
assertEquals(187, module.exports.main(6, 6, 6, 17, 11)); // JIT mul function
assertEquals(30525, module.exports.main(6, 6, 9, 555, 55)); // JIT mul function

View File

@ -311,8 +311,6 @@ var kExprSimdPrefix = 0xe5;
var kExprI32x4Splat = 0x1b;
var kExprI32x4ExtractLane = 0x1c;
var kExprJITSingleFunction = 0xf0;
var kTrapUnreachable = 0;
var kTrapMemOutOfBounds = 1;
var kTrapDivByZero = 2;