gecko-dev/dom/base/nsJSUtils.h
Nicholas Nethercote 18fae65f38 Bug 1563139 - Remove StaticPrefs.h. r=glandium
This requires replacing inclusions of it with inclusions of more specific prefs
files.

The exception is that StaticPrefsAll.h, which is equivalent to StaticPrefs.h,
and is used in `Codegen.py` because doing something smarter is tricky and
suitable for a follow-up. As a result, any change to StaticPrefList.yaml will
still trigger recompilation of all the generated DOM bindings files, but that's
still a big improvement over trigger recompilation of every file that uses
static prefs.

Most of the changes in this commit are very boring. The only changes that are
not boring are modules/libpref/*, Codegen.py, and ServoBindings.toml.

Differential Revision: https://phabricator.services.mozilla.com/D39138

--HG--
extra : moz-landing-system : lando
2019-07-26 01:10:23 +00:00

319 lines
11 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsJSUtils_h__
#define nsJSUtils_h__
/**
* This is not a generated file. It contains common utility functions
* invoked from the JavaScript code generated from IDL interfaces.
* The goal of the utility functions is to cut down on the size of
* the generated code itself.
*/
#include "mozilla/Assertions.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/Utf8.h" // mozilla::Utf8Unit
#include "GeckoProfiler.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "js/Conversions.h"
#include "js/SourceText.h"
#include "js/StableStringChars.h"
#include "nsString.h"
class nsIScriptContext;
class nsIScriptElement;
class nsIScriptGlobalObject;
class nsXBLPrototypeBinding;
namespace mozilla {
namespace dom {
class AutoJSAPI;
class Element;
} // namespace dom
} // namespace mozilla
class nsJSUtils {
public:
static bool GetCallingLocation(JSContext* aContext, nsACString& aFilename,
uint32_t* aLineno = nullptr,
uint32_t* aColumn = nullptr);
static bool GetCallingLocation(JSContext* aContext, nsAString& aFilename,
uint32_t* aLineno = nullptr,
uint32_t* aColumn = nullptr);
/**
* Retrieve the inner window ID based on the given JSContext.
*
* @param JSContext aContext
* The JSContext from which you want to find the inner window ID.
*
* @returns uint64_t the inner window ID.
*/
static uint64_t GetCurrentlyRunningCodeInnerWindowID(JSContext* aContext);
static nsresult CompileFunction(mozilla::dom::AutoJSAPI& jsapi,
JS::HandleVector<JSObject*> aScopeChain,
JS::CompileOptions& aOptions,
const nsACString& aName, uint32_t aArgCount,
const char** aArgArray,
const nsAString& aBody,
JSObject** aFunctionObject);
// ExecutionContext is used to switch compartment.
class MOZ_STACK_CLASS ExecutionContext {
#ifdef MOZ_GECKO_PROFILER
// Register stack annotations for the Gecko profiler.
mozilla::AutoProfilerLabel mAutoProfilerLabel;
#endif
JSContext* mCx;
// Handles switching to our global's realm.
JSAutoRealm mRealm;
// Set to a valid handle if a return value is expected.
JS::Rooted<JS::Value> mRetValue;
// Scope chain in which the execution takes place.
JS::RootedVector<JSObject*> mScopeChain;
// The compiled script.
JS::Rooted<JSScript*> mScript;
// returned value forwarded when we have to interupt the execution eagerly
// with mSkip.
nsresult mRv;
// Used to skip upcoming phases in case of a failure. In such case the
// result is carried by mRv.
bool mSkip;
// Should the result be serialized before being returned.
bool mCoerceToString;
// Encode the bytecode before it is being executed.
bool mEncodeBytecode;
#ifdef DEBUG
// Should we set the return value.
bool mWantsReturnValue;
bool mExpectScopeChain;
bool mScriptUsed;
#endif
private:
// Compile a script contained in a SourceText.
template <typename Unit>
nsresult InternalCompile(JS::CompileOptions& aCompileOptions,
JS::SourceText<Unit>& aSrcBuf);
public:
// Enter compartment in which the code would be executed. The JSContext
// must come from an AutoEntryScript.
ExecutionContext(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
ExecutionContext(const ExecutionContext&) = delete;
ExecutionContext(ExecutionContext&&) = delete;
~ExecutionContext() {
// This flag is reset when the returned value is extracted.
MOZ_ASSERT_IF(!mSkip, !mWantsReturnValue);
// If encoding was started we expect the script to have been
// used when ending the encoding.
MOZ_ASSERT_IF(mEncodeBytecode && mScript && mRv == NS_OK, mScriptUsed);
}
// The returned value would be converted to a string if the
// |aCoerceToString| is flag set.
ExecutionContext& SetCoerceToString(bool aCoerceToString) {
mCoerceToString = aCoerceToString;
return *this;
}
// When set, this flag records and encodes the bytecode as soon as it is
// being compiled, and before it is being executed. The bytecode can then be
// requested by using |JS::FinishIncrementalEncoding| with the mutable
// handle |aScript| argument of |CompileAndExec| or |JoinAndExec|.
ExecutionContext& SetEncodeBytecode(bool aEncodeBytecode) {
mEncodeBytecode = aEncodeBytecode;
return *this;
}
// Set the scope chain in which the code should be executed.
void SetScopeChain(JS::HandleVector<JSObject*> aScopeChain);
// After getting a notification that an off-thread compilation terminated,
// this function will take the result of the parser and move it to the main
// thread.
MOZ_MUST_USE nsresult JoinCompile(JS::OffThreadToken** aOffThreadToken);
// Compile a script contained in a SourceText.
nsresult Compile(JS::CompileOptions& aCompileOptions,
JS::SourceText<char16_t>& aSrcBuf);
nsresult Compile(JS::CompileOptions& aCompileOptions,
JS::SourceText<mozilla::Utf8Unit>& aSrcBuf);
// Compile a script contained in a string.
nsresult Compile(JS::CompileOptions& aCompileOptions,
const nsAString& aScript);
// Decode a script contained in a buffer.
nsresult Decode(JS::CompileOptions& aCompileOptions,
mozilla::Vector<uint8_t>& aBytecodeBuf,
size_t aBytecodeIndex);
// After getting a notification that an off-thread decoding terminated, this
// function will get the result of the decoder and move it to the main
// thread.
nsresult JoinDecode(JS::OffThreadToken** aOffThreadToken);
nsresult JoinDecodeBinAST(JS::OffThreadToken** aOffThreadToken);
// Decode a BinAST encoded script contained in a buffer.
nsresult DecodeBinAST(JS::CompileOptions& aCompileOptions,
const uint8_t* aBuf, size_t aLength);
// Get a successfully compiled script.
JSScript* GetScript();
// Get the compiled script if present, or nullptr.
JSScript* MaybeGetScript();
// Execute the compiled script and ignore the return value.
MOZ_MUST_USE nsresult ExecScript();
// Execute the compiled script a get the return value.
//
// Copy the returned value into the mutable handle argument. In case of a
// evaluation failure either during the execution or the conversion of the
// result to a string, the nsresult is be set to the corresponding result
// code and the mutable handle argument remains unchanged.
//
// The value returned in the mutable handle argument is part of the
// compartment given as argument to the ExecutionContext constructor. If the
// caller is in a different compartment, then the out-param value should be
// wrapped by calling |JS_WrapValue|.
MOZ_MUST_USE nsresult ExecScript(JS::MutableHandle<JS::Value> aRetValue);
};
static bool BinASTEncodingEnabled() {
#ifdef JS_BUILD_BINAST
return mozilla::StaticPrefs::dom_script_loader_binast_encoding_enabled();
#else
return false;
#endif
}
static nsresult CompileModule(JSContext* aCx,
JS::SourceText<char16_t>& aSrcBuf,
JS::Handle<JSObject*> aEvaluationGlobal,
JS::CompileOptions& aCompileOptions,
JS::MutableHandle<JSObject*> aModule);
static nsresult CompileModule(JSContext* aCx,
JS::SourceText<mozilla::Utf8Unit>& aSrcBuf,
JS::Handle<JSObject*> aEvaluationGlobal,
JS::CompileOptions& aCompileOptions,
JS::MutableHandle<JSObject*> aModule);
static nsresult InitModuleSourceElement(JSContext* aCx,
JS::Handle<JSObject*> aModule,
nsIScriptElement* aElement);
static nsresult ModuleInstantiate(JSContext* aCx,
JS::Handle<JSObject*> aModule);
static nsresult ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule);
// Returns false if an exception got thrown on aCx. Passing a null
// aElement is allowed; that wil produce an empty aScopeChain.
static bool GetScopeChainForElement(
JSContext* aCx, mozilla::dom::Element* aElement,
JS::MutableHandleVector<JSObject*> aScopeChain);
// Returns a scope chain suitable for XBL execution.
//
// This is by default GetScopeChainForElemenet, but will be different if the
// <binding> element had the simpleScopeChain attribute.
//
// This is to prevent footguns like bug 1446342.
static bool GetScopeChainForXBL(
JSContext* aCx, mozilla::dom::Element* aBoundElement,
const nsXBLPrototypeBinding& aProtoBinding,
JS::MutableHandleVector<JSObject*> aScopeChain);
static void ResetTimeZone();
static bool DumpEnabled();
};
template <typename T>
inline bool AssignJSString(JSContext* cx, T& dest, JSString* s) {
size_t len = JS::GetStringLength(s);
static_assert(js::MaxStringLength < (1 << 30),
"Shouldn't overflow here or in SetCapacity");
if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible))) {
JS_ReportOutOfMemory(cx);
return false;
}
return js::CopyStringChars(cx, dest.BeginWriting(), s, len);
}
inline void AssignJSFlatString(nsAString& dest, JSFlatString* s) {
size_t len = js::GetFlatStringLength(s);
static_assert(js::MaxStringLength < (1 << 30),
"Shouldn't overflow here or in SetCapacity");
dest.SetLength(len);
js::CopyFlatStringChars(dest.BeginWriting(), s, len);
}
class nsAutoJSString : public nsAutoString {
public:
/**
* nsAutoJSString should be default constructed, which leaves it empty
* (this->IsEmpty()), and initialized with one of the init() methods below.
*/
nsAutoJSString() {}
bool init(JSContext* aContext, JSString* str) {
return AssignJSString(aContext, *this, str);
}
bool init(JSContext* aContext, const JS::Value& v) {
if (v.isString()) {
return init(aContext, v.toString());
}
// Stringify, making sure not to run script.
JS::Rooted<JSString*> str(aContext);
if (v.isObject()) {
str = JS_NewStringCopyZ(aContext, "[Object]");
} else {
JS::Rooted<JS::Value> rootedVal(aContext, v);
str = JS::ToString(aContext, rootedVal);
}
return str && init(aContext, str);
}
bool init(JSContext* aContext, jsid id) {
JS::Rooted<JS::Value> v(aContext);
return JS_IdToValue(aContext, id, &v) && init(aContext, v);
}
bool init(const JS::Value& v);
~nsAutoJSString() {}
};
#endif /* nsJSUtils_h__ */