Commit 8344687c authored by titzer's avatar titzer Committed by Commit bot

[wasm] Properly plumb the origin of the WASM module from asm.js translation.

R=bradnelson@chromium.org,aseemgarg@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1742073002

Cr-Commit-Position: refs/heads/master@{#34345}
parent fb59ea33
......@@ -1153,6 +1153,13 @@ Node* WasmGraphBuilder::BuildF64Max(Node* left, Node* right) {
Node* WasmGraphBuilder::BuildI32SConvertF32(Node* input) {
MachineOperatorBuilder* m = jsgraph()->machine();
if (module_ && module_->asm_js()) {
// asm.js must use the wacky JS semantics.
input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
return graph()->NewNode(
m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
}
// Truncation of the input value is needed for the overflow check later.
Node* trunc = Unop(wasm::kExprF32Trunc, input);
Node* result = graph()->NewNode(m->TruncateFloat32ToInt32(), trunc);
......@@ -1169,7 +1176,8 @@ Node* WasmGraphBuilder::BuildI32SConvertF32(Node* input) {
Node* WasmGraphBuilder::BuildI32SConvertF64(Node* input) {
MachineOperatorBuilder* m = jsgraph()->machine();
if (module_ && module_->asm_js) {
if (module_ && module_->asm_js()) {
// asm.js must use the wacky JS semantics.
return graph()->NewNode(
m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
}
......@@ -1189,6 +1197,13 @@ Node* WasmGraphBuilder::BuildI32SConvertF64(Node* input) {
Node* WasmGraphBuilder::BuildI32UConvertF32(Node* input) {
MachineOperatorBuilder* m = jsgraph()->machine();
if (module_ && module_->asm_js()) {
// asm.js must use the wacky JS semantics.
input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
return graph()->NewNode(
m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
}
// Truncation of the input value is needed for the overflow check later.
Node* trunc = Unop(wasm::kExprF32Trunc, input);
Node* result = graph()->NewNode(m->TruncateFloat32ToUint32(), trunc);
......@@ -1205,7 +1220,8 @@ Node* WasmGraphBuilder::BuildI32UConvertF32(Node* input) {
Node* WasmGraphBuilder::BuildI32UConvertF64(Node* input) {
MachineOperatorBuilder* m = jsgraph()->machine();
if (module_ && module_->asm_js) {
if (module_ && module_->asm_js()) {
// asm.js must use the wacky JS semantics.
return graph()->NewNode(
m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
}
......@@ -1889,7 +1905,7 @@ Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype,
Node* index, uint32_t offset) {
Node* load;
if (module_ && module_->asm_js) {
if (module_ && module_->asm_js()) {
// asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
DCHECK_EQ(0, offset);
const Operator* op = jsgraph()->machine()->CheckedLoad(memtype);
......@@ -1924,7 +1940,7 @@ Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype,
Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
uint32_t offset, Node* val) {
Node* store;
if (module_ && module_->asm_js) {
if (module_ && module_->asm_js()) {
// asm.js semantics use CheckedStore (i.e. ignore OOB writes).
DCHECK_EQ(0, offset);
const Operator* op =
......
......@@ -27,8 +27,8 @@ namespace wasm {
class ModuleDecoder : public Decoder {
public:
ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end,
bool asm_js)
: Decoder(module_start, module_end), module_zone(zone), asm_js_(asm_js) {
ModuleOrigin origin)
: Decoder(module_start, module_end), module_zone(zone), origin_(origin) {
result_.start = start_;
if (limit_ < start_) {
error(start_, "end is less than start");
......@@ -49,6 +49,7 @@ class ModuleDecoder : public Decoder {
module->max_mem_size_log2 = 0;
module->mem_export = false;
module->mem_external = false;
module->origin = origin_;
module->globals = new std::vector<WasmGlobal>();
module->signatures = new std::vector<FunctionSig*>();
module->functions = new std::vector<WasmFunction>();
......@@ -105,7 +106,7 @@ class ModuleDecoder : public Decoder {
ModuleEnv menv;
menv.module = module;
menv.instance = nullptr;
menv.asm_js = asm_js_;
menv.origin = origin_;
// Decode functions.
for (uint32_t i = 0; i < functions_count; i++) {
if (failed()) break;
......@@ -360,7 +361,7 @@ class ModuleDecoder : public Decoder {
private:
Zone* module_zone;
ModuleResult result_;
bool asm_js_;
ModuleOrigin origin_;
uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); }
......@@ -608,22 +609,21 @@ class FunctionError : public FunctionResult {
}
};
ModuleResult DecodeWasmModule(Isolate* isolate, Zone* zone,
const byte* module_start, const byte* module_end,
bool verify_functions, bool asm_js) {
bool verify_functions, ModuleOrigin origin) {
size_t size = module_end - module_start;
if (module_start > module_end) return ModuleError("start > end");
if (size >= kMaxModuleSize) return ModuleError("size > maximum module size");
WasmModule* module = new WasmModule();
ModuleDecoder decoder(zone, module_start, module_end, asm_js);
ModuleDecoder decoder(zone, module_start, module_end, origin);
return decoder.DecodeModule(module, verify_functions);
}
FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start,
const byte* end) {
ModuleDecoder decoder(zone, start, end, false);
ModuleDecoder decoder(zone, start, end, kWasmOrigin);
return decoder.DecodeFunctionSignature(start);
}
......@@ -637,7 +637,7 @@ FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone,
if (size > kMaxFunctionSize)
return FunctionError("size > maximum function size");
WasmFunction* function = new WasmFunction();
ModuleDecoder decoder(zone, function_start, function_end, false);
ModuleDecoder decoder(zone, function_start, function_end, kWasmOrigin);
return decoder.DecodeSingleFunction(module_env, function);
}
} // namespace wasm
......
......@@ -14,7 +14,7 @@ namespace wasm {
// Decodes the bytes of a WASM module between {module_start} and {module_end}.
ModuleResult DecodeWasmModule(Isolate* isolate, Zone* zone,
const byte* module_start, const byte* module_end,
bool verify_functions, bool asm_js);
bool verify_functions, ModuleOrigin origin);
// Exposed for testing. Decodes a single function signature, allocating it
// in the given zone. Returns {nullptr} upon failure.
......
......@@ -64,8 +64,9 @@ void VerifyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (thrower.error()) return;
i::Zone zone;
internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule(
isolate, &zone, buffer.start, buffer.end, true, false);
internal::wasm::ModuleResult result =
internal::wasm::DecodeWasmModule(isolate, &zone, buffer.start, buffer.end,
true, internal::wasm::kWasmOrigin);
if (result.failed()) {
thrower.Failed("", result);
......@@ -139,10 +140,10 @@ v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(
return module;
}
void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args,
const byte* start, const byte* end,
ErrorThrower* thrower, bool must_decode) {
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();
......@@ -156,9 +157,9 @@ void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args,
// Verification will happen during compilation.
i::Zone zone;
internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule(
isolate, &zone, start, end, false, false);
isolate, &zone, start, end, false, origin);
if (result.failed() && must_decode) {
if (result.failed() && origin == internal::wasm::kAsmJsOrigin) {
thrower->Error("Asm.js converted module failed to decode");
} else if (result.failed()) {
thrower->Failed("", result);
......@@ -209,7 +210,8 @@ void InstantiateModuleFromAsm(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
InstantiateModuleCommon(args, module->Begin(), module->End(), &thrower, true);
InstantiateModuleCommon(args, module->Begin(), module->End(), &thrower,
internal::wasm::kAsmJsOrigin);
}
......@@ -221,7 +223,8 @@ void InstantiateModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
RawBuffer buffer = GetRawBufferArgument(thrower, args);
if (buffer.start == nullptr) return;
InstantiateModuleCommon(args, buffer.start, buffer.end, &thrower, false);
InstantiateModuleCommon(args, buffer.start, buffer.end, &thrower,
internal::wasm::kWasmOrigin);
}
} // namespace
......
......@@ -278,6 +278,7 @@ WasmModule::WasmModule()
mem_export(false),
mem_external(false),
start_function_index(-1),
origin(kWasmOrigin),
globals(nullptr),
signatures(nullptr),
functions(nullptr),
......@@ -389,7 +390,7 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
module_env.module = this;
module_env.instance = &instance;
module_env.linker = &linker;
module_env.asm_js = false;
module_env.origin = origin;
if (import_table->size() > 0) {
instance.import_code = &import_code;
......@@ -538,8 +539,8 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
Zone zone;
// Decode the module, but don't verify function bodies, since we'll
// be compiling them anyway.
ModuleResult result =
DecodeWasmModule(isolate, &zone, module_start, module_end, false, false);
ModuleResult result = DecodeWasmModule(isolate, &zone, module_start,
module_end, false, kWasmOrigin);
if (result.failed()) {
// Module verification failed. throw.
std::ostringstream str;
......@@ -579,7 +580,7 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
module_env.module = module;
module_env.instance = &instance;
module_env.linker = &linker;
module_env.asm_js = false;
module_env.origin = module->origin;
// Compile all functions.
Handle<Code> main_code = Handle<Code>::null(); // record last code.
......
......@@ -97,6 +97,8 @@ struct WasmDataSegment {
bool init; // true if loaded upon instantiation.
};
enum ModuleOrigin { kWasmOrigin, kAsmJsOrigin };
// Static representation of a module.
struct WasmModule {
static const uint8_t kMinMemSize = 12; // Minimum memory size = 4kb
......@@ -110,6 +112,7 @@ struct WasmModule {
bool mem_export; // true if the memory is exported.
bool mem_external; // true if the memory is external.
int start_function_index; // start function, if any.
ModuleOrigin origin; // origin of the module
std::vector<WasmGlobal>* globals; // globals in this module.
std::vector<FunctionSig*>* signatures; // signatures in this module.
......@@ -176,7 +179,7 @@ struct ModuleEnv {
WasmModule* module;
WasmModuleInstance* instance;
WasmLinker* linker;
bool asm_js; // true if the module originated from asm.js.
ModuleOrigin origin;
bool IsValidGlobal(uint32_t index) {
return module && index < module->globals->size();
......@@ -211,6 +214,8 @@ struct ModuleEnv {
: 0;
}
bool asm_js() { return origin == kAsmJsOrigin; }
Handle<Code> GetFunctionCode(uint32_t index);
Handle<Code> GetImportCode(uint32_t index);
Handle<FixedArray> GetFunctionTable();
......
......@@ -1510,7 +1510,7 @@ TEST(Run_Wasm_LoadMemI32_oob) {
TEST(Run_Wasm_LoadMemI32_oob_asm) {
TestingModule module;
module.asm_js = true;
module.origin = kAsmJsOrigin;
int32_t* memory = module.AddMemoryElems<int32_t>(8);
WasmRunner<int32_t> r(&module, MachineType::Uint32());
module.RandomizeMemory(1112);
......
......@@ -91,7 +91,7 @@ class TestingModule : public ModuleEnv {
instance->mem_size = 0;
instance->function_code = nullptr;
linker = nullptr;
asm_js = false;
origin = kWasmOrigin;
memset(global_data, 0, sizeof(global_data));
}
......
......@@ -1540,3 +1540,18 @@ TestForeignVariables();
var m = _WASMEXP_.instantiateModuleFromAsm(Module.toString());
assertEquals(0, m.func());
})();
(function TestOutOfBoundsConversion() {
function asmModule($a,$b,$c){'use asm';
function aaa() {
var f = 0.0;
var a = 0;
f = 5616315000.000001;
a = ~~f >>>0;
return a | 0;
}
return { main : aaa };
}
var wasm = _WASMEXP_.instantiateModuleFromAsm(asmModule.toString());
assertEquals(1321347704, wasm.main());
})();
......@@ -30,7 +30,7 @@ class WasmModuleVerifyTest : public TestWithZone {
public:
ModuleResult DecodeModule(const byte* module_start, const byte* module_end) {
return DecodeWasmModule(nullptr, zone(), module_start, module_end, false,
false);
kWasmOrigin);
}
};
......
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