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