Commit 224ca74a authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[asm.js] Propagate language mode to exported functions.

This makes sure the language mode of the module is correctly propagated
through the WebAssembly module, so that exported functions are allocated
with the correct language mode. It extends the existing {ModuleOrigin}
enum to consist of three values now.

R=clemensh@chromium.org
TEST=mjsunit/regress/wasm/regress-985154
BUG=chromium:985154

Change-Id: Id7b566738b1e710cc5001b894022bcd0f2c01bc3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1708484
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarMichael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62826}
parent d251ec41
......@@ -287,7 +287,7 @@ UnoptimizedCompilationJob::Status AsmJsCompilationJob::FinalizeJobImpl(
isolate, &thrower,
wasm::ModuleWireBytes(module_->begin(), module_->end()),
Vector<const byte>(asm_offsets_->begin(), asm_offsets_->size()),
uses_bitset)
uses_bitset, shared_info->language_mode())
.ToHandleChecked();
DCHECK(!thrower.error());
compile_time_ = compile_timer.Elapsed().InMillisecondsF();
......
......@@ -2625,7 +2625,7 @@ void Pipeline::GenerateCodeForWasmFunction(
pipeline.RunPrintAndVerify("V8.WasmMachineCode", true);
data.BeginPhaseKind("V8.WasmOptimization");
const bool is_asm_js = module->origin == wasm::kAsmJsOrigin;
const bool is_asm_js = is_asmjs_module(module);
if (FLAG_turbo_splitting && !is_asm_js) {
data.info()->MarkAsSplittingEnabled();
}
......
......@@ -2386,8 +2386,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break;
default: {
// Deal with special asmjs opcodes.
if (this->module_ != nullptr &&
this->module_->origin == kAsmJsOrigin) {
if (this->module_ != nullptr && is_asmjs_module(this->module_)) {
FunctionSig* sig = WasmOpcodes::AsmjsSignature(opcode);
if (sig) {
BuildSimpleOperator(opcode, sig);
......
......@@ -112,7 +112,7 @@ ExecutionTier WasmCompilationUnit::GetDefaultExecutionTier(
const WasmModule* module) {
// Liftoff does not support the special asm.js opcodes, thus always compile
// asm.js modules with TurboFan.
if (module->origin == kAsmJsOrigin) return ExecutionTier::kTurbofan;
if (is_asmjs_module(module)) return ExecutionTier::kTurbofan;
if (FLAG_wasm_interpret_all) return ExecutionTier::kInterpreter;
return FLAG_liftoff ? ExecutionTier::kLiftoff : ExecutionTier::kTurbofan;
}
......@@ -147,7 +147,7 @@ WasmCompilationResult WasmCompilationUnit::ExecuteImportWrapperCompilation(
// Assume the wrapper is going to be a JS function with matching arity at
// instantiation time.
auto kind = compiler::kDefaultImportCallKind;
bool source_positions = env->module->origin == kAsmJsOrigin;
bool source_positions = is_asmjs_module(env->module);
WasmCompilationResult result = compiler::CompileWasmImportCallWrapper(
engine, env, kind, sig, source_positions);
return result;
......
......@@ -824,7 +824,7 @@ void ValidateSequentially(
bool IsLazyModule(const WasmModule* module) {
return FLAG_wasm_lazy_compilation ||
(FLAG_asm_wasm_lazy_compilation && module->origin == kAsmJsOrigin);
(FLAG_asm_wasm_lazy_compilation && is_asmjs_module(module));
}
} // namespace
......@@ -2502,7 +2502,7 @@ WasmCode* CompileImportWrapper(
// yet.
WasmImportWrapperCache::CacheKey key(kind, sig);
DCHECK_NULL((*cache_scope)[key]);
bool source_positions = native_module->module()->origin == kAsmJsOrigin;
bool source_positions = is_asmjs_module(native_module->module());
// Keep the {WasmCode} alive until we explicitly call {IncRef}.
WasmCodeRefScope code_ref_scope;
CompilationEnv env = native_module->CreateCompilationEnv();
......
......@@ -259,13 +259,13 @@ class ModuleDecoderImpl : public Decoder {
explicit ModuleDecoderImpl(const WasmFeatures& enabled, ModuleOrigin origin)
: Decoder(nullptr, nullptr),
enabled_features_(enabled),
origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {}
origin_(FLAG_assume_asmjs_origin ? kAsmJsSloppyOrigin : origin) {}
ModuleDecoderImpl(const WasmFeatures& enabled, const byte* module_start,
const byte* module_end, ModuleOrigin origin)
: Decoder(module_start, module_end),
enabled_features_(enabled),
origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {
origin_(FLAG_assume_asmjs_origin ? kAsmJsSloppyOrigin : origin) {
if (end_ < start_) {
error(start_, "end is less than start");
end_ = start_;
......@@ -746,7 +746,7 @@ class ModuleDecoderImpl : public Decoder {
}
}
// Check for duplicate exports (except for asm.js).
if (ok() && origin_ != kAsmJsOrigin && module_->export_table.size() > 1) {
if (ok() && origin_ == kWasmOrigin && module_->export_table.size() > 1) {
std::vector<WasmExport> sorted_exports(module_->export_table);
auto cmp_less = [this](const WasmExport& a, const WasmExport& b) {
......
......@@ -312,8 +312,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
memory->set_is_detachable(false);
DCHECK_IMPLIES(native_module->use_trap_handler(),
module_->origin == kAsmJsOrigin ||
memory->is_wasm_memory() ||
is_asmjs_module(module_) || memory->is_wasm_memory() ||
memory->backing_store() == nullptr);
} else if (initial_pages > 0 || native_module->use_trap_handler()) {
// We need to unconditionally create a guard region if using trap handlers,
......@@ -795,7 +794,7 @@ void InstanceBuilder::SanitizeImports() {
int int_index = static_cast<int>(index);
MaybeHandle<Object> result =
module_->origin == kAsmJsOrigin
is_asmjs_module(module_)
? LookupImportAsm(int_index, import_name)
: LookupImport(int_index, module_name, import_name);
if (thrower_->error()) {
......@@ -1131,7 +1130,7 @@ bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
module_name, import_name);
return false;
}
if (module_->origin == kAsmJsOrigin) {
if (is_asmjs_module(module_)) {
// Accepting {JSFunction} on top of just primitive values here is a
// workaround to support legacy asm.js code with broken binding. Note
// that using {NaN} (or Smi::kZero) here is what using the observable
......@@ -1469,7 +1468,8 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
exports_object = isolate_->factory()->NewJSObjectWithNullProto();
break;
}
case kAsmJsOrigin: {
case kAsmJsSloppyOrigin:
case kAsmJsStrictOrigin: {
Handle<JSFunction> object_function = Handle<JSFunction>(
isolate_->native_context()->object_function(), isolate_);
exports_object = isolate_->factory()->NewJSObject(object_function);
......
......@@ -238,10 +238,13 @@ bool WasmEngine::SyncValidate(Isolate* isolate, const WasmFeatures& enabled,
MaybeHandle<AsmWasmData> WasmEngine::SyncCompileTranslatedAsmJs(
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes,
Vector<const byte> asm_js_offset_table_bytes,
Handle<HeapNumber> uses_bitset) {
Handle<HeapNumber> uses_bitset, LanguageMode language_mode) {
ModuleOrigin origin = language_mode == LanguageMode::kSloppy
? kAsmJsSloppyOrigin
: kAsmJsStrictOrigin;
ModuleResult result =
DecodeWasmModule(kAsmjsWasmFeatures, bytes.start(), bytes.end(), false,
kAsmJsOrigin, isolate->counters(), allocator());
origin, isolate->counters(), allocator());
if (result.failed()) {
// This happens once in a while when we have missed some limit check
// in the asm parser. Output an error message to help diagnose, but crash.
......
......@@ -62,7 +62,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
MaybeHandle<AsmWasmData> SyncCompileTranslatedAsmJs(
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes,
Vector<const byte> asm_js_offset_table_bytes,
Handle<HeapNumber> uses_bitset);
Handle<HeapNumber> uses_bitset, LanguageMode language_mode);
Handle<WasmModuleObject> FinalizeTranslatedAsmJs(
Isolate* isolate, Handle<AsmWasmData> asm_wasm_data,
Handle<Script> script);
......
......@@ -164,7 +164,11 @@ struct WasmCompilationHint {
WasmCompilationHintTier top_tier;
};
enum ModuleOrigin : uint8_t { kWasmOrigin, kAsmJsOrigin };
enum ModuleOrigin : uint8_t {
kWasmOrigin,
kAsmJsSloppyOrigin,
kAsmJsStrictOrigin
};
#define SELECT_WASM_COUNTER(counters, origin, prefix, suffix) \
((origin) == kWasmOrigin ? (counters)->prefix##_wasm_##suffix() \
......@@ -221,6 +225,10 @@ struct V8_EXPORT_PRIVATE WasmModule {
void AddFunctionNameForTesting(int function_index, WireBytesRef name);
};
inline bool is_asmjs_module(const WasmModule* module) {
return module->origin != kWasmOrigin;
}
size_t EstimateStoredSize(const WasmModule* module);
// Returns the number of possible export wrappers for a given module.
......
......@@ -111,7 +111,7 @@ void WasmModuleObject::reset_breakpoint_infos() {
GetReadOnlyRoots().undefined_value());
}
bool WasmModuleObject::is_asm_js() {
bool asm_js = module()->origin == wasm::kAsmJsOrigin;
bool asm_js = is_asmjs_module(module());
DCHECK_EQ(asm_js, script().IsUserJavaScript());
DCHECK_EQ(asm_js, has_asm_js_offset_table());
return asm_js;
......
......@@ -511,7 +511,7 @@ int WasmModuleObject::GetSourcePosition(Handle<WasmModuleObject> module_object,
Isolate* isolate = module_object->GetIsolate();
const WasmModule* module = module_object->module();
if (module->origin != wasm::kAsmJsOrigin) {
if (module->origin == wasm::kWasmOrigin) {
// for non-asm.js modules, we just add the function's start offset
// to make a module-relative position.
return byte_offset + module_object->GetFunctionOffset(func_index);
......@@ -2237,7 +2237,8 @@ Handle<WasmExportedFunction> WasmExportedFunction::New(
function_data->set_packed_args_size(0);
MaybeHandle<String> maybe_name;
if (instance->module()->origin == wasm::kAsmJsOrigin) {
bool is_asm_js_module = instance->module_object().is_asm_js();
if (is_asm_js_module) {
// We can use the function name only for asm.js. For WebAssembly, the
// function name is specified as the function_index.toString().
maybe_name = WasmModuleObject::GetFunctionNameOrNull(
......@@ -2252,10 +2253,18 @@ Handle<WasmExportedFunction> WasmExportedFunction::New(
Vector<uint8_t>::cast(buffer.SubVector(0, length)))
.ToHandleChecked();
}
bool is_asm_js_module = instance->module_object().is_asm_js();
Handle<Map> function_map = is_asm_js_module
? isolate->sloppy_function_map()
: isolate->wasm_exported_function_map();
Handle<Map> function_map;
switch (instance->module()->origin) {
case wasm::kWasmOrigin:
function_map = isolate->wasm_exported_function_map();
break;
case wasm::kAsmJsSloppyOrigin:
function_map = isolate->sloppy_function_map();
break;
case wasm::kAsmJsStrictOrigin:
function_map = isolate->strict_function_map();
break;
}
NewFunctionArgs args =
NewFunctionArgs::ForWasm(name, function_data, function_map);
Handle<JSFunction> js_function = isolate->factory()->NewFunction(args);
......
......@@ -90,7 +90,7 @@ class TestingModuleBuilder {
TestingModuleBuilder(Zone*, ManuallyImportedJSFunction*, ExecutionTier,
RuntimeExceptionSupport, LowerSimd);
void ChangeOriginToAsmjs() { test_module_->origin = kAsmJsOrigin; }
void ChangeOriginToAsmjs() { test_module_->origin = kAsmJsSloppyOrigin; }
byte* AddMemory(uint32_t size, SharedFlag shared = SharedFlag::kNotShared);
......
......@@ -162,7 +162,7 @@ int32_t CompileAndRunAsmWasmModule(Isolate* isolate, const byte* module_start,
MaybeHandle<AsmWasmData> data =
isolate->wasm_engine()->SyncCompileTranslatedAsmJs(
isolate, &thrower, ModuleWireBytes(module_start, module_end),
Vector<const byte>(), Handle<HeapNumber>());
Vector<const byte>(), Handle<HeapNumber>(), LanguageMode::kSloppy);
DCHECK_EQ(thrower.error(), data.is_null());
if (data.is_null()) return -1;
......
// Copyright 2019 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.
(function TestSloppynessPropagates() {
let f = (function() {
function Module() {
"use asm";
function f() {}
return {f: f}
}
return Module;
})()().f;
let p = Object.getOwnPropertyNames(f);
assertArrayEquals(["length", "name", "arguments", "caller", "prototype"], p);
assertEquals(null, f.arguments);
assertEquals(null, f.caller);
})();
(function TestStrictnessPropagates() {
let f = (function() {
"use strict";
function Module() {
"use asm";
function f() {}
return {f: f}
}
return Module;
})()().f;
let p = Object.getOwnPropertyNames(f);
assertArrayEquals(["length", "name", "prototype"], p);
assertThrows(() => f.arguments, TypeError);
assertThrows(() => f.caller, TypeError);
})();
......@@ -2159,7 +2159,7 @@ TEST_F(FunctionBodyDecoderTest, WasmMemoryGrow) {
}
TEST_F(FunctionBodyDecoderTest, AsmJsMemoryGrow) {
TestModuleBuilder builder(kAsmJsOrigin);
TestModuleBuilder builder(kAsmJsSloppyOrigin);
module = builder.module();
builder.InitializeMemory();
......@@ -2191,7 +2191,7 @@ TEST_F(FunctionBodyDecoderTest, AsmJsBinOpsCheckOrigin) {
};
{
TestModuleBuilder builder(kAsmJsOrigin);
TestModuleBuilder builder(kAsmJsSloppyOrigin);
module = builder.module();
builder.InitializeMemory();
for (size_t i = 0; i < arraysize(AsmJsBinOps); i++) {
......@@ -2239,7 +2239,7 @@ TEST_F(FunctionBodyDecoderTest, AsmJsUnOpsCheckOrigin) {
{kExprI32AsmjsSConvertF64, sigs.i_d()},
{kExprI32AsmjsUConvertF64, sigs.i_d()}};
{
TestModuleBuilder builder(kAsmJsOrigin);
TestModuleBuilder builder(kAsmJsSloppyOrigin);
module = builder.module();
builder.InitializeMemory();
for (size_t i = 0; i < arraysize(AsmJsUnOps); i++) {
......
......@@ -19,3 +19,14 @@ print("https://crbug.com/935800");
}
print(Object.getOwnPropertyNames(foo().bar));
})();
print("https://crbug.com/985154");
(function () {
"use strict";
function foo() {
"use asm";
function baz() {}
return {bar: baz};
}
print(Object.getOwnPropertyNames(foo().bar));
})();
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