Bug 1252498 - Baldr: add Wasm object behind pref, default off (r=jorendorff)

MozReview-Commit-ID: BlhrURAX26H

--HG--
extra : rebase_source : e1b540f06c2f3976f91242ac7b0b8ede29fbc5f2
This commit is contained in:
Luke Wagner 2016-03-03 10:20:21 -06:00
parent 1e69d4c08b
commit b5a255ff58
16 changed files with 130 additions and 54 deletions

View File

@ -301,6 +301,7 @@ LoadRuntimeOptions(const char* aPrefName, void* /* aClosure */)
// Runtime options.
JS::RuntimeOptions runtimeOptions;
runtimeOptions.setAsmJS(GetWorkerPref<bool>(NS_LITERAL_CSTRING("asmjs")))
.setWasm(GetWorkerPref<bool>(NS_LITERAL_CSTRING("wasm")))
.setThrowOnAsmJSValidationFailure(GetWorkerPref<bool>(
NS_LITERAL_CSTRING("throw_on_asmjs_validation_failure")))
.setBaseline(GetWorkerPref<bool>(NS_LITERAL_CSTRING("baselinejit")))

View File

@ -1333,3 +1333,80 @@ wasm::Eval(JSContext* cx, Handle<ArrayBufferObject*> code,
return true;
}
static bool
InstantiateModule(JSContext* cx, unsigned argc, Value* vp)
{
MOZ_ASSERT(cx->runtime()->options().wasm());
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.get(0).isObject() || !args.get(0).toObject().is<ArrayBufferObject>()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_BUF_ARG);
return false;
}
RootedObject importObj(cx);
if (!args.get(1).isUndefined()) {
if (!args.get(1).isObject()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMPORT_ARG);
return false;
}
importObj = &args[1].toObject();
}
Rooted<ArrayBufferObject*> code(cx, &args[0].toObject().as<ArrayBufferObject>());
RootedObject exportObj(cx);
if (!Eval(cx, code, importObj, &exportObj))
return false;
args.rval().setObject(*exportObj);
return true;
}
#if JS_HAS_TOSOURCE
static bool
wasm_toSource(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setString(cx->names().Wasm);
return true;
}
#endif
static JSFunctionSpec wasm_static_methods[] = {
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, wasm_toSource, 0, 0),
#endif
JS_FN("instantiateModule", InstantiateModule, 1, 0),
JS_FS_END
};
const Class js::WasmClass = {
js_Wasm_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_Wasm)
};
JSObject*
js::InitWasmClass(JSContext* cx, HandleObject global)
{
MOZ_ASSERT(cx->runtime()->options().wasm());
RootedObject proto(cx, global->as<GlobalObject>().getOrCreateObjectPrototype(cx));
if (!proto)
return nullptr;
RootedObject Wasm(cx, NewObjectWithGivenProto(cx, &WasmClass, proto, SingletonObject));
if (!Wasm)
return nullptr;
if (!JS_DefineProperty(cx, global, js_Wasm_str, Wasm, JSPROP_RESOLVING))
return nullptr;
if (!JS_DefineFunctions(cx, Wasm, wasm_static_methods))
return nullptr;
global->as<GlobalObject>().setConstructor(JSProto_Wasm, ObjectValue(*Wasm));
return Wasm;
}

View File

@ -19,7 +19,10 @@
#ifndef wasm_h
#define wasm_h
#include "NamespaceImports.h"
#include "gc/Rooting.h"
#include "js/Class.h"
namespace js {
@ -31,8 +34,8 @@ namespace wasm {
bool
HasCompilerSupport(ExclusiveContext* cx);
// The WebAssembly spec hard-codes the virtual page size to be 64KiB and limits
// forces the linear memory to always be a multiple of 64KiB.
// The WebAssembly spec hard-codes the virtual page size to be 64KiB and
// requires linear memory to always be a multiple of 64KiB.
static const unsigned PageSize = 64 * 1024;
// When signal handling is used for bounds checking, MappedSize bytes are
@ -46,10 +49,18 @@ static const uint64_t MappedSize = 2 * Uint32Range + PageSize;
// Compiles the given binary wasm module given the ArrayBufferObject
// and links the module's imports with the given import object.
bool
Eval(JSContext* cx, JS::Handle<ArrayBufferObject*> code,
JS::HandleObject importObj, JS::MutableHandleObject exportObj);
Eval(JSContext* cx, Handle<ArrayBufferObject*> code, HandleObject importObj,
MutableHandleObject exportObj);
} // namespace wasm
// Initialization of the Wasm global object and its properties.
extern const Class WasmClass;
JSObject*
InitWasmClass(JSContext* cx, HandleObject global);
} // namespace js
#endif // namespace wasm_h

View File

@ -501,42 +501,7 @@ static bool
WasmIsSupported(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::HasCompilerSupport(cx));
return true;
}
static bool
WasmEval(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject callee(cx, &args.callee());
if (args.length() < 1 || args.length() > 2) {
ReportUsageError(cx, callee, "Wrong number of arguments");
return false;
}
if (!args[0].isObject() || !args[0].toObject().is<ArrayBufferObject>()) {
ReportUsageError(cx, callee, "First argument must be an ArrayBuffer");
return false;
}
RootedObject importObj(cx);
if (!args.get(1).isUndefined()) {
if (!args.get(1).isObject()) {
ReportUsageError(cx, callee, "Second argument, if present, must be an Object");
return false;
}
importObj = &args[1].toObject();
}
Rooted<ArrayBufferObject*> code(cx, &args[0].toObject().as<ArrayBufferObject>());
RootedObject exportObj(cx);
if (!wasm::Eval(cx, code, importObj, &exportObj))
return false;
args.rval().setObject(*exportObj);
args.rval().setBoolean(wasm::HasCompilerSupport(cx) && cx->runtime()->options().wasm());
return true;
}
@ -3711,11 +3676,6 @@ gc::ZealModeHelpText),
"wasmIsSupported()",
" Returns a boolean indicating whether WebAssembly is supported on the current device."),
JS_FN_HELP("wasmEval", WasmEval, 2, 0,
"wasmEval(buffer, imports)",
" Compiles the given binary wasm module given by 'buffer' (which must be an ArrayBuffer)\n"
" and links the module's imports with the given 'imports' object."),
JS_FN_HELP("wasmTextToBinary", WasmTextToBinary, 1, 0,
"wasmTextToBinary(str)",
" Translates the given text wasm module into its binary encoding."),

View File

@ -4,7 +4,7 @@ if (!wasmIsSupported())
load(libdir + "asserts.js");
function wasmEvalText(str, imports) {
return wasmEval(wasmTextToBinary(str), imports);
return Wasm.instantiateModule(wasmTextToBinary(str), imports);
}
function mismatchError(actual, expect) {

View File

@ -96,8 +96,8 @@ if (!hasI64) {
// ----------------------------------------------------------------------------
// imports
assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', 1), Error, /Second argument, if present, must be an Object/);
assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', null), Error, /Second argument, if present, must be an Object/);
assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', 1), Error, /second argument, if present, must be an object/);
assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', null), Error, /second argument, if present, must be an object/);
const noImportObj = /no import object given/;
const notObject = /import object field is not an Object/;

View File

@ -53,6 +53,8 @@ function moduleHeaderThen(...rest) {
return [magic0, magic1, magic2, magic3, ver0, ver1, ver2, ver3, ...rest];
}
const wasmEval = Wasm.instantiateModule;
assertErrorMessage(() => wasmEval(toBuf([])), TypeError, magicError);
assertErrorMessage(() => wasmEval(toBuf([42])), TypeError, magicError);
assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2])), TypeError, magicError);

View File

@ -366,6 +366,8 @@ MSG_DEF(JSMSG_WASM_FAIL, 1, JSEXN_TYPEERR, "wasm error: {0}")
MSG_DEF(JSMSG_WASM_DECODE_FAIL, 2, JSEXN_TYPEERR, "wasm validation error at offset {0}: {1}")
MSG_DEF(JSMSG_WASM_TEXT_FAIL, 1, JSEXN_SYNTAXERR, "wasm text error: {0}")
MSG_DEF(JSMSG_WASM_BAD_IND_CALL, 0, JSEXN_ERR, "wasm indirect call signature mismatch")
MSG_DEF(JSMSG_WASM_BAD_BUF_ARG, 0, JSEXN_TYPEERR, "first argument must be an ArrayBuffer")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument, if present, must be an object")
// Proxy
MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value")

View File

@ -1109,6 +1109,7 @@ class JS_PUBLIC_API(RuntimeOptions) {
: baseline_(true),
ion_(true),
asmJS_(true),
wasm_(false),
throwOnAsmJSValidationFailure_(false),
nativeRegExp_(true),
unboxedArrays_(false),
@ -1156,6 +1157,16 @@ class JS_PUBLIC_API(RuntimeOptions) {
return *this;
}
bool wasm() const { return wasm_; }
RuntimeOptions& setWasm(bool flag) {
wasm_ = flag;
return *this;
}
RuntimeOptions& toggleWasm() {
wasm_ = !wasm_;
return *this;
}
bool throwOnAsmJSValidationFailure() const { return throwOnAsmJSValidationFailure_; }
RuntimeOptions& setThrowOnAsmJSValidationFailure(bool flag) {
throwOnAsmJSValidationFailure_ = flag;
@ -1236,6 +1247,7 @@ class JS_PUBLIC_API(RuntimeOptions) {
bool baseline_ : 1;
bool ion_ : 1;
bool asmJS_ : 1;
bool wasm_ : 1;
bool throwOnAsmJSValidationFailure_ : 1;
bool nativeRegExp_ : 1;
bool unboxedArrays_ : 1;

View File

@ -106,9 +106,10 @@ IF_BDATA(real,imaginary)(TypedObject, 40, InitTypedObjectModuleObj
real(Reflect, 41, InitReflect, nullptr) \
IF_SIMD(real,imaginary)(SIMD, 42, InitSimdClass, OCLASP(Simd)) \
real(WeakSet, 43, InitWeakSetClass, OCLASP(WeakSet)) \
real(TypedArray, 44, InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \
IF_SAB(real,imaginary)(Atomics, 45, InitAtomicsClass, OCLASP(Atomics)) \
real(SavedFrame, 46, InitViaClassSpec, &js::SavedFrame::class_) \
real(TypedArray, 44, InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \
IF_SAB(real,imaginary)(Atomics, 45, InitAtomicsClass, OCLASP(Atomics)) \
real(SavedFrame, 46, InitViaClassSpec, &js::SavedFrame::class_) \
real(Wasm, 47, InitWasmClass, CLASP(Wasm)) \
#define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro)

View File

@ -6586,6 +6586,7 @@ SetRuntimeOptions(JSRuntime* rt, const OptionParser& op)
JS::RuntimeOptionsRef(rt).setBaseline(enableBaseline)
.setIon(enableIon)
.setAsmJS(enableAsmJS)
.setWasm(true)
.setNativeRegExp(enableNativeRegExp)
.setUnboxedArrays(enableUnboxedArrays);
@ -6843,6 +6844,7 @@ SetWorkerRuntimeOptions(JSRuntime* rt)
JS::RuntimeOptionsRef(rt).setBaseline(enableBaseline)
.setIon(enableIon)
.setAsmJS(enableAsmJS)
.setWasm(true)
.setNativeRegExp(enableNativeRegExp)
.setUnboxedArrays(enableUnboxedArrays);
rt->setOffthreadIonCompilationEnabled(offthreadCompilation);

View File

@ -15,6 +15,7 @@
#include "jsprototypes.h"
#include "jsweakmap.h"
#include "asmjs/Wasm.h"
#include "builtin/AtomicsObject.h"
#include "builtin/Eval.h"
#if EXPOSE_INTL_API
@ -94,6 +95,9 @@ js::GlobalObject::getTypedObjectModule() const {
/* static */ bool
GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key)
{
if (key == JSProto_Wasm)
return !cx->runtime()->options().wasm();
#ifdef ENABLE_SHARED_ARRAY_BUFFER
// Return true if the given constructor has been disabled at run-time.
switch (key) {

View File

@ -31,11 +31,11 @@ namespace js {
*
* (If you're wondering, 0xb973c0de is used because it looks like "bytecode".)
*/
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 348;
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 349;
static const uint32_t XDR_BYTECODE_VERSION =
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
static_assert(JSErr_Limit == 445,
static_assert(JSErr_Limit == 447,
"GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
"removed MSG_DEFs from js.msg, you should increment "
"XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "

View File

@ -1542,6 +1542,7 @@ ReloadPrefsCallback(const char* pref, void* data)
bool useBaseline = Preferences::GetBool(JS_OPTIONS_DOT_STR "baselinejit") && !safeMode;
bool useIon = Preferences::GetBool(JS_OPTIONS_DOT_STR "ion") && !safeMode;
bool useAsmJS = Preferences::GetBool(JS_OPTIONS_DOT_STR "asmjs") && !safeMode;
bool useWasm = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm") && !safeMode;
bool throwOnAsmJSValidationFailure = Preferences::GetBool(JS_OPTIONS_DOT_STR
"throw_on_asmjs_validation_failure");
bool useNativeRegExp = Preferences::GetBool(JS_OPTIONS_DOT_STR "native_regexp") && !safeMode;
@ -1576,6 +1577,7 @@ ReloadPrefsCallback(const char* pref, void* data)
JS::RuntimeOptionsRef(rt).setBaseline(useBaseline)
.setIon(useIon)
.setAsmJS(useAsmJS)
.setWasm(useWasm)
.setThrowOnAsmJSValidationFailure(throwOnAsmJSValidationFailure)
.setNativeRegExp(useNativeRegExp)
.setAsyncStack(useAsyncStack)

View File

@ -984,7 +984,8 @@ ProcessArgsForCompartment(JSContext* cx, char** argv, int argc)
break;
case 'I':
RuntimeOptionsRef(cx).toggleIon()
.toggleAsmJS();
.toggleAsmJS()
.toggleWasm();
break;
}
}

View File

@ -1143,6 +1143,7 @@ pref("javascript.options.strict.debug", false);
pref("javascript.options.baselinejit", true);
pref("javascript.options.ion", true);
pref("javascript.options.asmjs", true);
pref("javascript.options.wasm", false);
pref("javascript.options.native_regexp", true);
pref("javascript.options.parallel_parsing", true);
#if !defined(RELEASE_BUILD) && !defined(ANDROID) && !defined(MOZ_B2G) && !defined(XP_IOS)