Bug 1590907 - Stop configure macros from masking function prototypes in public JS headers. r=jwalden,sfink

We should have the same public API available whenever possible, and make
it a no-op or make it throw immediately if JS was built without support
for it, instead of showing or hiding the API in header files using
configure macros. Otherwise embedders can easily get mismatches between
a library with functionality and header files without it, or vice versa.

There was no good reason why JS_GetErrorType() was nightly-only API, so
this also enables it unconditionally.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Philip Chimento 2019-11-26 10:27:27 +00:00
parent daf691f279
commit dda8b08621
14 changed files with 136 additions and 63 deletions

View File

@ -7,14 +7,10 @@
#ifndef js_BinASTFormat_h
#define js_BinASTFormat_h
#if defined(JS_BUILD_BINAST)
namespace JS {
enum class BinASTFormat { Multipart, Context };
} /* namespace JS */
#endif /* JS_BUILD_BINAST */
#endif /* js_BinASTFormat_h */

View File

@ -132,21 +132,20 @@ extern JS_PUBLIC_API bool FinishMultiOffThreadScriptsDecoder(
extern JS_PUBLIC_API void CancelMultiOffThreadScriptsDecoder(
JSContext* cx, OffThreadToken* token);
#if defined(JS_BUILD_BINAST)
// This returns false if built without JS_BUILD_BINAST.
extern JS_PUBLIC_API bool CanDecodeBinASTOffThread(
JSContext* cx, const ReadOnlyCompileOptions& options, size_t length);
// This throws an exception if built without JS_BUILD_BINAST.
extern JS_PUBLIC_API bool DecodeBinASTOffThread(
JSContext* cx, const ReadOnlyCompileOptions& options, const uint8_t* buf,
size_t length, JS::BinASTFormat format, OffThreadCompileCallback callback,
void* callbackData);
// This throws an exception if built without JS_BUILD_BINAST.
extern JS_PUBLIC_API JSScript* FinishOffThreadBinASTDecode(
JSContext* cx, OffThreadToken* token);
#endif // defined(JS_BUILD_BINAST)
} // namespace JS
#endif /* js_OffThreadScriptCompilation_h */

View File

@ -922,12 +922,11 @@ class RootingContext {
class JS_PUBLIC_API AutoGCRooter {
protected:
enum class Tag : uint8_t {
Array, /* js::AutoArrayRooter */
ValueArray, /* js::AutoValueArray */
Parser, /* js::frontend::Parser */
#if defined(JS_BUILD_BINAST)
BinASTParser, /* js::frontend::BinASTParser */
#endif // defined(JS_BUILD_BINAST)
Array, /* js::AutoArrayRooter */
ValueArray, /* js::AutoValueArray */
Parser, /* js::frontend::Parser */
BinASTParser, /* js::frontend::BinASTParser; only used if built with
* JS_BUILD_BINAST support */
WrapperVector, /* js::AutoWrapperVector */
Wrapper, /* js::AutoWrapperRooter */
Custom /* js::CustomAutoRooter */

View File

@ -375,9 +375,8 @@ extern JS_PUBLIC_DATA arena_id_t StringBufferArena;
extern void InitMallocAllocator();
extern void ShutDownMallocAllocator();
# ifdef MOZ_DEBUG
// This is a no-op if built without MOZ_MEMORY and MOZ_DEBUG.
extern void AssertJSStringBufferInCorrectArena(const void* ptr);
# endif
} /* namespace js */

View File

@ -79,12 +79,18 @@ static void* ComputeRandomAllocationAddress() {
# ifdef NEED_JIT_UNWIND_HANDLING
static js::JitExceptionHandler sJitExceptionHandler;
# endif
JS_FRIEND_API void js::SetJitExceptionHandler(JitExceptionHandler handler) {
# ifdef NEED_JIT_UNWIND_HANDLING
MOZ_ASSERT(!sJitExceptionHandler);
sJitExceptionHandler = handler;
# else
// Just do nothing if unwind handling is disabled.
# endif
}
# ifdef NEED_JIT_UNWIND_HANDLING
# if defined(_M_ARM64)
// See the ".xdata records" section of
// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
@ -324,32 +330,32 @@ static void DecommitPages(void* addr, size_t bytes) {
# endif
static void* ComputeRandomAllocationAddress() {
#ifdef __OpenBSD__
# ifdef __OpenBSD__
// OpenBSD already has random mmap and the idea that all x64 cpus
// have 48-bit address space is not correct. Returning nullptr
// allows OpenBSD do to the right thing.
return nullptr;
#else
# else
uint64_t rand = js::GenerateRandomSeed();
# ifdef HAVE_64BIT_BUILD
# ifdef HAVE_64BIT_BUILD
// x64 CPUs have a 48-bit address space and on some platforms the OS will
// give us access to 47 bits, so to be safe we right shift by 18 to leave
// 46 bits.
rand >>= 18;
# else
# else
// On 32-bit, right shift by 34 to leave 30 bits, range [0, 1GiB). Then add
// 512MiB to get range [512MiB, 1.5GiB), or [0x20000000, 0x60000000). This
// is based on V8 comments in platform-posix.cc saying this range is
// relatively unpopulated across a variety of kernels.
rand >>= 34;
rand += 512 * 1024 * 1024;
# endif
# endif
// Ensure page alignment.
uintptr_t mask = ~uintptr_t(gc::SystemPageSize() - 1);
return (void*)uintptr_t(rand & mask);
#endif
# endif
}
static void* ReserveProcessExecutableMemory(size_t bytes) {

View File

@ -171,6 +171,7 @@ MSG_DEF(JSMSG_PROPERTY_ACCESS_DENIED, 1, JSEXN_ERR, "Permission denied to acces
MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 0, JSEXN_TYPEERR, "bad cloned function scope chain")
MSG_DEF(JSMSG_CANT_CLONE_OBJECT, 0, JSEXN_TYPEERR, "can't clone object")
MSG_DEF(JSMSG_CANT_OPEN, 2, JSEXN_ERR, "can't open {0}: {1}")
MSG_DEF(JSMSG_SUPPORT_NOT_ENABLED, 1, JSEXN_ERR, "support for {0} is not enabled")
MSG_DEF(JSMSG_USER_DEFINED_ERROR, 0, JSEXN_ERR, "JS_ReportError was called")
// Internal errors

View File

@ -436,15 +436,20 @@ JS_PUBLIC_API void JS_SetSizeOfIncludingThisCompartmentCallback(
cx->runtime()->sizeOfIncludingThisCompartmentCallback = callback;
}
#if defined(NIGHTLY_BUILD)
JS_PUBLIC_API void JS_SetErrorInterceptorCallback(
JSRuntime* rt, JSErrorInterceptor* callback) {
#if defined(NIGHTLY_BUILD)
rt->errorInterception.interceptor = callback;
#endif // defined(NIGHTLY_BUILD)
}
JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback(
JSRuntime* rt) {
#if defined(NIGHTLY_BUILD)
return rt->errorInterception.interceptor;
#else // !NIGHTLY_BUILD
return nullptr;
#endif // defined(NIGHTLY_BUILD)
}
JS_PUBLIC_API Maybe<JSExnType> JS_GetErrorType(const JS::Value& val) {
@ -465,8 +470,6 @@ JS_PUBLIC_API Maybe<JSExnType> JS_GetErrorType(const JS::Value& val) {
return mozilla::Some(err.type());
}
#endif // defined(NIGHTLY_BUILD)
JS_PUBLIC_API void JS_SetWrapObjectCallbacks(
JSContext* cx, const JSWrapObjectCallbacks* callbacks) {
cx->runtime()->wrapObjectCallbacks = callbacks;
@ -3657,20 +3660,25 @@ CompileOptions& CompileOptions::setIntroductionInfoToCaller(
}
}
#if defined(JS_BUILD_BINAST)
JSScript* JS::DecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
const uint8_t* buf, size_t length,
JS::BinASTFormat format) {
#if defined(JS_BUILD_BINAST)
MOZ_ASSERT(!cx->zone()->isAtomsZone());
AssertHeapIsIdle();
CHECK_THREAD(cx);
return frontend::CompileGlobalBinASTScript(cx, options, buf, length, format);
#else // !JS_BUILD_BINAST
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_SUPPORT_NOT_ENABLED, "BinAST");
return nullptr;
#endif // JS_BUILD_BINAST
}
JSScript* JS::DecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
FILE* file, JS::BinASTFormat format) {
#if defined(JS_BUILD_BINAST)
FileContents fileContents(cx);
if (!ReadCompleteFile(cx, file, fileContents)) {
return nullptr;
@ -3678,10 +3686,13 @@ JSScript* JS::DecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
return DecodeBinAST(cx, options, fileContents.begin(), fileContents.length(),
format);
#else // !JS_BUILD_BINAST
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_SUPPORT_NOT_ENABLED, "BinAST");
return nullptr;
#endif // JS_BUILD_BINAST
}
#endif
JS_PUBLIC_API JSObject* JS_GetGlobalFromScript(JSScript* script) {
return &script->global();
}

View File

@ -398,8 +398,6 @@ extern JS_PUBLIC_API void JS_SetSizeOfIncludingThisCompartmentCallback(
extern JS_PUBLIC_API void JS_SetWrapObjectCallbacks(
JSContext* cx, const JSWrapObjectCallbacks* callbacks);
#if defined(NIGHTLY_BUILD)
// Set a callback that will be called whenever an error
// is thrown in this runtime. This is designed as a mechanism
// for logging errors. Note that the VM makes no attempt to sanitize
@ -412,9 +410,11 @@ extern JS_PUBLIC_API void JS_SetWrapObjectCallbacks(
// will replace the original error.
//
// May be `nullptr`.
// This is a no-op if built without NIGHTLY_BUILD.
extern JS_PUBLIC_API void JS_SetErrorInterceptorCallback(
JSRuntime*, JSErrorInterceptor* callback);
// This returns nullptr if built without NIGHTLY_BUILD.
extern JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback(
JSRuntime*);
@ -423,8 +423,6 @@ extern JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback(
extern JS_PUBLIC_API mozilla::Maybe<JSExnType> JS_GetErrorType(
const JS::Value& val);
#endif // defined(NIGHTLY_BUILD)
extern JS_PUBLIC_API void JS_SetCompartmentPrivate(JS::Compartment* compartment,
void* data);
@ -1946,22 +1944,20 @@ extern JS_PUBLIC_API void SetScriptPrivateReferenceHooks(
} /* namespace JS */
#if defined(JS_BUILD_BINAST)
namespace JS {
// This throws an exception if built without JS_BUILD_BINAST.
extern JS_PUBLIC_API JSScript* DecodeBinAST(
JSContext* cx, const ReadOnlyCompileOptions& options, FILE* file,
JS::BinASTFormat format);
// This throws an exception if built without JS_BUILD_BINAST.
extern JS_PUBLIC_API JSScript* DecodeBinAST(
JSContext* cx, const ReadOnlyCompileOptions& options, const uint8_t* buf,
size_t length, JS::BinASTFormat format);
} /* namespace JS */
#endif /* JS_BUILD_BINAST */
extern JS_PUBLIC_API bool JS_CheckForInterrupt(JSContext* cx);
/*

View File

@ -584,8 +584,6 @@ JS_FRIEND_API JSObject* JS_CloneObject(JSContext* cx, HandleObject obj,
return CloneObject(cx, obj, proto);
}
#if defined(DEBUG) || defined(JS_JITSPEW)
// We don't want jsfriendapi.h to depend on GenericPrinter,
// so these functions are declared directly in the cpp.
@ -611,56 +609,76 @@ extern JS_FRIEND_API void DumpInterpreterFrame(
} // namespace js
JS_FRIEND_API void js::DumpString(JSString* str, js::GenericPrinter& out) {
#if defined(DEBUG) || defined(JS_JITSPEW)
str->dump(out);
#endif
}
JS_FRIEND_API void js::DumpAtom(JSAtom* atom, js::GenericPrinter& out) {
#if defined(DEBUG) || defined(JS_JITSPEW)
atom->dump(out);
#endif
}
JS_FRIEND_API void js::DumpChars(const char16_t* s, size_t n,
js::GenericPrinter& out) {
#if defined(DEBUG) || defined(JS_JITSPEW)
out.printf("char16_t * (%p) = ", (void*)s);
JSString::dumpChars(s, n, out);
out.putChar('\n');
#endif
}
JS_FRIEND_API void js::DumpObject(JSObject* obj, js::GenericPrinter& out) {
#if defined(DEBUG) || defined(JS_JITSPEW)
if (!obj) {
out.printf("NULL\n");
return;
}
obj->dump(out);
#endif
}
JS_FRIEND_API void js::DumpString(JSString* str, FILE* fp) {
#if defined(DEBUG) || defined(JS_JITSPEW)
Fprinter out(fp);
js::DumpString(str, out);
#endif
}
JS_FRIEND_API void js::DumpAtom(JSAtom* atom, FILE* fp) {
#if defined(DEBUG) || defined(JS_JITSPEW)
Fprinter out(fp);
js::DumpAtom(atom, out);
#endif
}
JS_FRIEND_API void js::DumpChars(const char16_t* s, size_t n, FILE* fp) {
#if defined(DEBUG) || defined(JS_JITSPEW)
Fprinter out(fp);
js::DumpChars(s, n, out);
#endif
}
JS_FRIEND_API void js::DumpObject(JSObject* obj, FILE* fp) {
#if defined(DEBUG) || defined(JS_JITSPEW)
Fprinter out(fp);
js::DumpObject(obj, out);
#endif
}
JS_FRIEND_API void js::DumpId(jsid id, FILE* fp) {
#if defined(DEBUG) || defined(JS_JITSPEW)
Fprinter out(fp);
js::DumpId(id, out);
#endif
}
JS_FRIEND_API void js::DumpValue(const JS::Value& val, FILE* fp) {
#if defined(DEBUG) || defined(JS_JITSPEW)
Fprinter out(fp);
js::DumpValue(val, out);
#endif
}
JS_FRIEND_API void js::DumpString(JSString* str) { DumpString(str, stderr); }
@ -675,15 +693,25 @@ JS_FRIEND_API void js::DumpValue(const JS::Value& val) {
JS_FRIEND_API void js::DumpId(jsid id) { DumpId(id, stderr); }
JS_FRIEND_API void js::DumpInterpreterFrame(JSContext* cx,
InterpreterFrame* start) {
#if defined(DEBUG) || defined(JS_JITSPEW)
Fprinter out(stderr);
DumpInterpreterFrame(cx, out, start);
}
JS_FRIEND_API bool js::DumpPC(JSContext* cx) { return DumpPC(cx, stdout); }
JS_FRIEND_API bool js::DumpScript(JSContext* cx, JSScript* scriptArg) {
return DumpScript(cx, scriptArg, stdout);
}
#endif
}
JS_FRIEND_API bool js::DumpPC(JSContext* cx) {
#if defined(DEBUG) || defined(JS_JITSPEW)
return DumpPC(cx, stdout);
#else
return true;
#endif
}
JS_FRIEND_API bool js::DumpScript(JSContext* cx, JSScript* scriptArg) {
#if defined(DEBUG) || defined(JS_JITSPEW)
return DumpScript(cx, scriptArg, stdout);
#else
return true;
#endif
}
static const char* FormatValue(JSContext* cx, HandleValue v,
UniqueChars& bytes) {
@ -1421,3 +1449,27 @@ JS_FRIEND_API bool js::RuntimeIsBeingDestroyed() {
return runtime->isBeingDestroyed();
}
#endif
// No-op implementations of public API that would depend on --with-intl-api
#ifndef ENABLE_INTL_API
static bool IntlNotEnabled(JSContext* cx) {
JS_ReportErrorNumberASCII(cx, js::GetErrorMessage, nullptr,
JSMSG_SUPPORT_NOT_ENABLED, "Intl");
return false;
}
bool js::AddMozDateTimeFormatConstructor(JSContext* cx, JS::HandleObject intl) {
return IntlNotEnabled(cx);
}
bool js::AddListFormatConstructor(JSContext* cx, JS::HandleObject intl) {
return IntlNotEnabled(cx);
}
bool js::AddLocaleConstructor(JSContext* cx, JS::HandleObject intl) {
return IntlNotEnabled(cx);
}
#endif // !ENABLE_INTL_API

View File

@ -254,13 +254,13 @@ JS_FRIEND_API void RemoveRawValueRoot(JSContext* cx, JS::Value* vp);
JS_FRIEND_API JSAtom* GetPropertyNameFromPC(JSScript* script, jsbytecode* pc);
#if defined(DEBUG) || defined(JS_JITSPEW)
/*
* Routines to print out values during debugging. These are FRIEND_API to help
* the debugger find them and to support temporarily hacking js::Dump* calls
* into other code. Note that there are overloads that do not require the FILE*
* parameter, which will default to stderr.
*
* These functions are no-ops unless built with DEBUG or JS_JITSPEW.
*/
extern JS_FRIEND_API void DumpString(JSString* str, FILE* fp);
@ -296,7 +296,8 @@ extern JS_FRIEND_API void DumpInterpreterFrame(
extern JS_FRIEND_API bool DumpPC(JSContext* cx);
extern JS_FRIEND_API bool DumpScript(JSContext* cx, JSScript* scriptArg);
#endif
// DumpBacktrace(), unlike the other dump functions, always dumps a backtrace --
// regardless of DEBUG or JS_JITSPEW.
extern JS_FRIEND_API void DumpBacktrace(JSContext* cx, FILE* fp);
@ -2486,7 +2487,7 @@ extern JS_FRIEND_API JSObject* GetJSMEnvironmentOfScriptedCaller(JSContext* cx);
extern JS_FRIEND_API bool IsJSMEnvironment(JSObject* obj);
// Matches the condition in js/src/jit/ProcessExecutableMemory.cpp
#if defined(XP_WIN) && defined(HAVE_64BIT_BUILD)
#if defined(XP_WIN)
// Parameters use void* types to avoid #including windows.h. The return value of
// this function is returned from the exception handler.
typedef long (*JitExceptionHandler)(void* exceptionRecord, // PEXECTION_RECORD
@ -2592,9 +2593,10 @@ MOZ_ALWAYS_INLINE JSObject* ToWindowProxyIfWindow(JSObject* obj) {
*/
extern JS_FRIEND_API JSObject* ToWindowIfWindowProxy(JSObject* obj);
#if ENABLE_INTL_API
// Create and add the Intl.MozDateTimeFormat constructor function to the
// provided object.
// If JS was built without ENABLE_INTL_API, this function will throw an
// exception.
//
// This custom date/time formatter constructor gives users the ability
// to specify a custom format pattern. This pattern is passed *directly*
@ -2609,12 +2611,15 @@ extern bool AddMozDateTimeFormatConstructor(JSContext* cx,
JS::Handle<JSObject*> intl);
// Create and add the Intl.Locale constructor function to the provided object.
// If JS was built without ENABLE_INTL_API, this function will throw an
// exception.
extern bool AddLocaleConstructor(JSContext* cx, JS::Handle<JSObject*> intl);
// Create and add the Intl.ListFormat constructor function to the provided
// object.
// If JS was built without ENABLE_INTL_API, this function will throw an
// exception.
extern bool AddListFormatConstructor(JSContext* cx, JS::Handle<JSObject*> intl);
#endif // ENABLE_INTL_API
class MOZ_STACK_CLASS JS_FRIEND_API AutoAssertNoContentJS {
public:

View File

@ -1329,16 +1329,16 @@ bool js::InitRuntimeNumberState(JSRuntime* rt) {
return true;
}
#if !ENABLE_INTL_API
void js::FinishRuntimeNumberState(JSRuntime* rt) {
#if !ENABLE_INTL_API
/*
* The free also releases the memory for decimalSeparator and numGrouping
* strings.
*/
char* storage = const_cast<char*>(rt->thousandsSeparator.ref());
js_free(storage);
#endif // !ENABLE_INTL_API
}
#endif
JSObject* NumberObject::createPrototype(JSContext* cx, JSProtoKey key) {
NumberObject* numberProto =

View File

@ -40,9 +40,8 @@ class StringBuffer;
extern MOZ_MUST_USE bool InitRuntimeNumberState(JSRuntime* rt);
#if !ENABLE_INTL_API
// This is a no-op if built with ENABLE_INTL_API.
extern void FinishRuntimeNumberState(JSRuntime* rt);
#endif
/* Initialize the Number class, returning its prototype object. */
extern JSObject* InitNumberClass(JSContext* cx, Handle<GlobalObject*> global);

View File

@ -114,21 +114,19 @@ void js::ShutDownMallocAllocator() {
// moz_dispose_arena(ArrayBufferContentsArena);
}
#ifdef MOZ_DEBUG
extern void js::AssertJSStringBufferInCorrectArena(const void* ptr) {
// `jemalloc_ptr_info()` only exists if MOZ_MEMORY is defined, and it only
// returns an arenaId if MOZ_DEBUG is defined. Otherwise, this function is
// a no-op.
# if defined(MOZ_MEMORY) && defined(MOZ_DEBUG)
#if defined(MOZ_MEMORY) && defined(MOZ_DEBUG)
if (ptr) {
jemalloc_ptr_info_t ptrInfo{};
jemalloc_ptr_info(ptr, &ptrInfo);
MOZ_ASSERT(ptrInfo.tag != TagUnknown);
MOZ_ASSERT(ptrInfo.arenaId == js::StringBufferArena);
}
# endif
}
#endif
}
JS_PUBLIC_API void JS_Assert(const char* s, const char* file, int ln) {
MOZ_ReportAssertionFailure(s, file, ln);

View File

@ -203,26 +203,38 @@ JS_PUBLIC_API void JS::CancelMultiOffThreadScriptsDecoder(
ParseTaskKind::MultiScriptsDecode, token);
}
#ifdef JS_BUILD_BINAST
JS_PUBLIC_API bool JS::CanDecodeBinASTOffThread(
JSContext* cx, const ReadOnlyCompileOptions& options, size_t length) {
#ifdef JS_BUILD_BINAST
return CanDoOffThread(cx, options, length, OffThread::DecodeBinAST);
#else // !JS_BUILD_BINAST
return false;
#endif // JS_BUILD_BINAST
}
JS_PUBLIC_API bool JS::DecodeBinASTOffThread(
JSContext* cx, const ReadOnlyCompileOptions& options, const uint8_t* buf,
size_t length, JS::BinASTFormat format, OffThreadCompileCallback callback,
void* callbackData) {
#ifdef JS_BUILD_BINAST
return StartOffThreadDecodeBinAST(cx, options, buf, length, format, callback,
callbackData);
#else // !JS_BUILD_BINAST
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_SUPPORT_NOT_ENABLED, "BinAST");
return false;
#endif // JS_BUILD_BINAST
}
JS_PUBLIC_API JSScript* JS::FinishOffThreadBinASTDecode(
JSContext* cx, JS::OffThreadToken* token) {
#ifdef JS_BUILD_BINAST
MOZ_ASSERT(cx);
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
return HelperThreadState().finishBinASTDecodeTask(cx, token);
}
#else // !JS_BUILD_BINAST
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_SUPPORT_NOT_ENABLED, "BinAST");
return nullptr;
#endif // JS_BUILD_BINAST
}