SERVER-109200: Upgrade MozJS to esr140.3 (#44151)

Co-authored-by: Erin Zhu <erin.zhu@mongodb.com>
Co-authored-by: Lee Maguire <lee.maguire@mongodb.com>
GitOrigin-RevId: e9c2c8cb36c2aeae7a7150326154b8e676122057
This commit is contained in:
Anna Veselova 2025-12-15 13:22:42 -06:00 committed by MongoDB Bot
parent ae97353d07
commit 800a3faa71
1688 changed files with 238147 additions and 152660 deletions

View File

@ -50,7 +50,7 @@ a notice will be included in
| [libunwind] | MIT | 1.8.1 | | ✗ |
| [linenoise] | BSD-2-Clause | 6cdc775807e57b2c3fd64bd207814f8ee1fe35f3 | | ✗ |
| [MongoDB C Driver] | Apache-2.0 | 1.28.1 | ✗ | ✗ |
| [Mozilla Firefox ESR] | MPL-2.0 | 128.11.0esr | | ✗ |
| [Mozilla Firefox ESR] | MPL-2.0 | 140.3.0esr | | ✗ |
| [MurmurHash3] | Public Domain | a6bd3ce7be8ad147ea820a7cf6229a975c0c96bb | | ✗ |
| [nlohmann/json] | MIT | 3.11.3 | ✗ | |
| [node] | ISC | 22.1.0 | | |

View File

@ -107,6 +107,8 @@ last-continuous:
ticket: SERVER-114126
- test_file: jstests/replsets/rollback_index_build_start_abort.js
ticket: SERVER-103955
- test_file: jstests/sharding/query/javascript_heap_limit.js
ticket: SERVER-109200
suites: null
last-lts:
all:
@ -716,4 +718,6 @@ last-lts:
ticket: SERVER-114126
- test_file: jstests/replsets/rollback_index_build_start_abort.js
ticket: SERVER-103955
- test_file: jstests/sharding/query/javascript_heap_limit.js
ticket: SERVER-109200
suites: null

View File

@ -145,20 +145,20 @@ const largeAccumulator = {
};
res = coll
.aggregate([
{$addFields: {a: {$range: [0, 1000000]}}},
{$addFields: {a: {$range: [0, 250000]}}},
{$unwind: "$a"}, // Create a number of documents to be executed by the accumulator.
{$group: {_id: "$groupBy", count: largeAccumulator}},
])
.toArray();
assert.sameMembers(res, [
{_id: 1, count: 1000000},
{_id: 2, count: 1000000},
{_id: 1, count: 250000},
{_id: 2, count: 250000},
]);
// With $bucket.
res = coll
.aggregate([
{$addFields: {a: {$range: [0, 1000000]}}},
{$addFields: {a: {$range: [0, 250000]}}},
{$unwind: "$a"}, // Create a number of documents to be executed by the accumulator.
{
$bucket: {groupBy: "$groupBy", boundaries: [1, 2, 3], output: {count: largeAccumulator}},
@ -166,6 +166,6 @@ res = coll
])
.toArray();
assert.sameMembers(res, [
{_id: 1, count: 1000000},
{_id: 2, count: 1000000},
{_id: 1, count: 250000},
{_id: 2, count: 250000},
]);

View File

@ -38,6 +38,7 @@ const expectedGlobalVars = [
"Error",
"EvalError",
"FinalizationRegistry",
"Float16Array",
"Float32Array",
"Float64Array",
"Function",
@ -48,6 +49,7 @@ const expectedGlobalVars = [
"Int32Array",
"Int8Array",
"InternalError",
"Iterator",
"JSON",
"MD5",
"Map",

View File

@ -40,7 +40,7 @@ st.shardColl(coll, {_id: 1}, {_id: 0}, {_id: 0});
explain: {
aggregate: coll.getName(),
pipeline: [
{$addFields: {a: {$range: [0, 1000000]}}},
{$addFields: {a: {$range: [0, 250000]}}},
{$unwind: "$a"}, // Create a number of documents to be executed by the accumulator.
{$group: {_id: "$groupBy", count: largeAccumulator}},
],

View File

@ -39,6 +39,12 @@ function setHeapSizeLimitMB({queryLimit, globalLimit}) {
});
}
function setLegacyMemoryTracking({useLegacy}) {
st.forEachConnection((conn) => {
assert.commandWorked(conn.getDB("test").adminCommand({setParameter: 1, jsUseLegacyMemoryTracking: useLegacy}));
});
}
function allocateLargeString() {
const arraySize = 1000000;
let str = new Array(arraySize).fill(0);
@ -116,6 +122,8 @@ const findWithWhere = {
* part of an aggregation pipeline.
*/
function runCommonTests(db) {
setLegacyMemoryTracking({db: db, useLegacy: false});
// All commands are expected to work with a sufficient JS heap size.
setHeapSizeLimitMB({db: db, queryLimit: sufficentHeapSizeMB, globalLimit: sufficentHeapSizeMB});
assert.commandWorked(db.runCommand(aggregateWithJSFunction));
@ -135,6 +143,13 @@ function runCommonTests(db) {
assert.commandFailedWithCode(db.runCommand(aggregateWithJSFunction), ErrorCodes.JSInterpreterFailure);
assert.commandFailedWithCode(db.runCommand(aggregateWithInternalJsReduce), ErrorCodes.JSInterpreterFailure);
assert.commandFailedWithCode(db.runCommand(aggregateWithUserDefinedAccumulator), ErrorCodes.JSInterpreterFailure);
// Enabling legacy memory tracking doesn't count large buffers, so queries should pass that otherwise fail
setLegacyMemoryTracking({db: db, useLegacy: true});
setHeapSizeLimitMB({db: db, queryLimit: tooSmallHeapSizeMB, globalLimit: tooSmallHeapSizeMB});
assert.commandWorked(db.runCommand(aggregateWithJSFunction));
assert.commandWorked(db.runCommand(aggregateWithInternalJsReduce));
assert.commandWorked(db.runCommand(aggregateWithUserDefinedAccumulator));
}
/**
@ -142,6 +157,8 @@ function runCommonTests(db) {
* only evaluated on mongod, not on mongos.
*/
function runShardTests(db) {
setLegacyMemoryTracking({db: db, useLegacy: false});
// All commands are expected to work with a sufficient JS heap size.
setHeapSizeLimitMB({db: db, queryLimit: sufficentHeapSizeMB, globalLimit: sufficentHeapSizeMB});
assert.commandWorked(db.runCommand(findWithJavaScriptFunction));
@ -168,6 +185,14 @@ function runShardTests(db) {
// TODO SERVER-45454: Uncomment when $where is executed via aggregation JavaScript expression.
// assert.commandFailedWithCode(db.runCommand(findWithWhere), ErrorCodes.JSInterpreterFailure);
assert.commandFailedWithCode(db.runCommand(mapReduce), ErrorCodes.JSInterpreterFailure);
// Enabling legacy memory tracking doesn't count large buffers, so queries should pass that otherwise fail
setLegacyMemoryTracking({db: db, useLegacy: true});
setHeapSizeLimitMB({db: db, queryLimit: tooSmallHeapSizeMB, globalLimit: tooSmallHeapSizeMB});
assert.commandWorked(db.runCommand(findWithJavaScriptFunction));
// TODO SERVER-45454: Uncomment when $where is executed via aggregation JavaScript expression.
// assert.commandWorked(db.runCommand(findWithWhere));
assert.commandWorked(db.runCommand(mapReduce));
}
// Test command invocations that can execute JavaScript on either mongos or mongod.

View File

@ -71,7 +71,7 @@
"components": [
{
"type": "library",
"bom-ref": "pkg:deb/debian/firefox-esr@128.11.0esr-1?arch=source",
"bom-ref": "pkg:deb/debian/firefox-esr@140.3.0esr-1?arch=source",
"supplier": {
"name": "Mozilla Corporation",
"url": [
@ -81,7 +81,7 @@
"author": "Mozilla Corporation",
"group": "mozilla",
"name": "Mozilla Firefox ESR",
"version": "128.11.0esr",
"version": "140.3.0esr",
"description": "The C++-only SpiderMonkey component of FireFox ESR used by MongoDB.",
"licenses": [
{
@ -91,8 +91,8 @@
}
],
"copyright": "Mozilla Corporation",
"cpe": "cpe:2.3:a:mozilla:firefox:128.11.0:*:*:*:esr:*:*:*",
"purl": "pkg:deb/debian/firefox-esr@128.11.0esr-1?arch=source",
"cpe": "cpe:2.3:a:mozilla:firefox:140.3.0:*:*:*:esr:*:*:*",
"purl": "pkg:deb/debian/firefox-esr@140.3.0esr-1?arch=source",
"externalReferences": [
{
"url": "https://github.com/mozilla-firefox/firefox.git",
@ -2628,7 +2628,7 @@
"pkg:github/libunwind/libunwind@v1.8.1",
"pkg:github/antirez/linenoise@6cdc775807e57b2c3fd64bd207814f8ee1fe35f3",
"pkg:github/mongodb/mongo-c-driver@1.28.1",
"pkg:deb/debian/firefox-esr@128.11.0esr-1?arch=source",
"pkg:deb/debian/firefox-esr@140.3.0esr-1?arch=source",
"pkg:github/nodejs/node@22.1.0?download_url=https%3A%2F%2Fgithub.com%2Fnodejs%2Fnode%2Fblob%2F8b45c5d26a829bcd3280401dbc1874bcd1302289%2Fsrc%2Fnode_i18n.cc%23L825%23src%2Fnode_i18n.cc%3AGetStringWidth#src/node_i18n.cc",
"pkg:pypi/ocspbuilder@0.10.2",
"pkg:pypi/ocspresponder@0.5.0",
@ -2768,7 +2768,7 @@
"dependsOn": []
},
{
"ref": "pkg:deb/debian/firefox-esr@128.11.0esr-1?arch=source",
"ref": "pkg:deb/debian/firefox-esr@140.3.0esr-1?arch=source",
"dependsOn": []
},
{

View File

@ -266,6 +266,8 @@ public:
virtual int getJSHeapLimitMB() const = 0;
virtual void setJSHeapLimitMB(int limit) = 0;
virtual bool getJSUseLegacyMemoryTracking() const = 0;
virtual void setJSUseLegacyMemoryTracking(bool shouldUseLegacy) = 0;
virtual std::string getLoadPath() const = 0;
virtual void setLoadPath(const std::string& loadPath) = 0;

View File

@ -140,6 +140,14 @@ void MozJSScriptEngine::setJSHeapLimitMB(int limit) {
gJSHeapLimitMB.store(limit);
}
bool MozJSScriptEngine::getJSUseLegacyMemoryTracking() const {
return gJSUseLegacyMemoryTracking.load();
}
void MozJSScriptEngine::setJSUseLegacyMemoryTracking(bool shouldUseLegacy) {
gJSUseLegacyMemoryTracking.store(shouldUseLegacy);
}
std::string MozJSScriptEngine::getLoadPath() const {
return _loadPath;
}

View File

@ -69,6 +69,9 @@ public:
int getJSHeapLimitMB() const override;
void setJSHeapLimitMB(int limit) override;
bool getJSUseLegacyMemoryTracking() const override;
void setJSUseLegacyMemoryTracking(bool shouldUseLegacyEngine) override;
std::string getLoadPath() const override;
void setLoadPath(const std::string& loadPath) override;

View File

@ -46,3 +46,11 @@ server_parameters:
cpp_varname: gJSHeapLimitMB
default: 1100
redact: false
jsUseLegacyMemoryTracking:
description: "fallback to use legacy memory tracking"
set_at: [startup, runtime]
cpp_vartype: Atomic<bool>
cpp_varname: gJSUseLegacyMemoryTracking
default: false
redact: false

View File

@ -61,6 +61,7 @@ void mongoToJSException(JSContext* cx) {
JS_SetPendingException(cx, val);
}
} else {
JS::ReportUncatchableException(cx);
// If a JSAPI callback returns false without setting a pending exception, SpiderMonkey will
// treat it as an uncatchable error.
auto scope = getScope(cx);

View File

@ -366,9 +366,13 @@ void MozJSImplScope::_gcCallback(JSContext* rt,
LOGV2_INFO(22787,
"MozJS GC heap stats",
"phase"_attr = (status == JSGC_BEGIN ? "prologue" : "epilogue"),
"reason"_attr = reason,
"reason"_attr = ExplainGCReason(reason),
"total"_attr = mongo::sm::get_total_bytes(),
"limit"_attr = mongo::sm::get_max_bytes());
"limit"_attr = mongo::sm::get_max_bytes(),
"gc total"_attr = js::GetGCHeapUsage(rt),
"gc bytes"_attr = JS_GetGCParameter(rt, JSGC_BYTES),
"gc total chunks"_attr = JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS),
"gc unused chunks"_attr = JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS));
}
#if __has_feature(address_sanitizer)
@ -440,7 +444,13 @@ MozJSImplScope::MozRuntime::MozRuntime(const MozJSScriptEngine* engine,
"JavaScript may not be able to initialize with a heap limit less than 10MB.");
}
size_t mallocMemoryLimit = 1024ul * 1024 * jsHeapLimit;
mongo::sm::reset(mallocMemoryLimit);
/*
* Flag to disable newer memory tracking logic that accounts for mmap-ed memory
*/
const auto useLegacyMemoryTracking = engine->getJSUseLegacyMemoryTracking();
mongo::sm::reset(mallocMemoryLimit, !useLegacyMemoryTracking);
{
stdx::unique_lock<stdx::mutex> lk(gRuntimeCreationMutex);

View File

@ -28,6 +28,7 @@
*/
#include "mongo/config.h" // IWYU pragma: keep
#include "mongo/logv2/log.h"
#include "mongo/scripting/mozjs/implscope.h"
#include <jscustomallocator.h>
@ -49,6 +50,8 @@
#error "Unsupported platform"
#endif
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kQuery
/**
* This shim interface (which controls dynamic allocation within SpiderMonkey),
* consciously uses std::malloc and friends over mongoMalloc. It does this
@ -71,24 +74,57 @@ namespace {
* maximum number of bytes we will consider handing out. They are set by
* MozJSImplScope on start up.
*/
thread_local size_t total_bytes = 0;
thread_local size_t malloc_bytes = 0;
thread_local size_t max_bytes = 0;
// Allow disabling mmap tracking as a fallback in case counted memory goes too high
thread_local bool track_mmap_bytes = true;
} // namespace
size_t get_total_bytes() {
return total_bytes;
return get_malloc_bytes() + get_mmap_bytes();
}
void reset(size_t bytes) {
total_bytes = 0;
size_t get_malloc_bytes() {
return malloc_bytes;
}
size_t get_mmap_bytes() {
return track_mmap_bytes ? js::gc::GetProfilerMemoryCounts().bytes : 0;
}
void reset(size_t bytes, bool track_mmap) {
malloc_bytes = 0;
max_bytes = bytes;
track_mmap_bytes = track_mmap;
}
size_t get_max_bytes() {
return max_bytes;
}
void signal_oom() {
auto scope = mongo::mozjs::MozJSImplScope::getThreadScope();
if (scope) {
scope->setOOM();
}
}
void check_oom_on_mmap_allocation(size_t bytes) {
// called after an mmap allocation to check whether an oom signal is required
// if track_mmap_bytes is disabled we fall back to legacy logic and completely bypass this path
size_t mb = get_max_bytes();
size_t tb = get_total_bytes();
if (track_mmap_bytes && mb > 0 && get_total_bytes() + bytes > mb) {
LOGV2(10920001,
"Out of memory on MozJS mmap allocation",
"bytes"_attr = bytes,
"totalBytes"_attr = tb,
"maxBytes"_attr = mb);
signal_oom();
}
}
size_t get_current(void* ptr);
/**
@ -99,7 +135,8 @@ size_t get_current(void* ptr);
template <typename T>
void* wrap_alloc(T&& func, void* ptr, size_t bytes) {
size_t mb = get_max_bytes();
size_t tb = get_total_bytes();
size_t mlb = get_malloc_bytes();
size_t mmb = get_mmap_bytes();
// During a GC cycle, GC::purgeRuntime() is called, which tries to free unused items in the
// SharedImmutableStringsCache while holding its corresponding mutex. Our js_free implementation
@ -109,14 +146,23 @@ void* wrap_alloc(T&& func, void* ptr, size_t bytes) {
// for the SharedImmutableStringsCache (order 600). This triggered a failure of a MOZ_ASSERT
// which enforces correct lock ordering in the JS engine. For this reason, we avoid checking
// for an OOM here if we are requesting zero bytes (i.e freeing memory).
if (mb && bytes && (mlb + mmb + bytes > mb)) {
bool oomUnsafe = js::AutoEnterOOMUnsafeRegion::isInOOMUnsafeRegion();
LOGV2(10920000,
"Out of memory on MozJS malloc allocation",
"bytes"_attr = bytes,
"totalBytes"_attr = mlb + mmb,
"maxBytes"_attr = mb,
"isInOOMUnsafeRegion"_attr = oomUnsafe);
signal_oom();
if (mb && bytes && (tb + bytes > mb)) {
auto scope = mongo::mozjs::MozJSImplScope::getThreadScope();
if (scope) {
scope->setOOM();
}
// In some contexts MozJS has no safe recovery from OOM and crashes the process to avoid
// unsafe behavior. In that case allow the allocation to proceed and go over the allowed
// memory limit. Otherwise fail immediately.
if (!oomUnsafe) {
return nullptr;
}
}
void* p = func(ptr, bytes);
@ -147,7 +193,7 @@ void* wrap_alloc(T&& func, void* ptr, size_t bytes) {
return nullptr;
}
total_bytes += mongo::sm::get_current(p);
malloc_bytes += mongo::sm::get_current(p);
return p;
}
@ -171,9 +217,12 @@ size_t get_current(void* ptr) {
} // namespace mongo
JS_PUBLIC_DATA arena_id_t js::MallocArena;
JS_PUBLIC_DATA arena_id_t js::BackgroundMallocArena;
JS_PUBLIC_DATA arena_id_t js::ArrayBufferContentsArena;
JS_PUBLIC_DATA arena_id_t js::StringBufferArena;
thread_local size_t js::AutoEnterOOMUnsafeRegion::isInOomUnsafeRegion_ = 0;
void* mongo_arena_malloc(size_t bytes) {
return std::malloc(bytes);
}
@ -195,11 +244,11 @@ void* mongo_arena_realloc(void* p, size_t bytes) {
void* ptr = std::realloc(p, bytes);
if (!ptr) {
// on failure the old ptr isn't freed, no need to adjust total_bytes
// on failure the old ptr isn't freed, no need to adjust malloc_bytes
return nullptr;
}
mongo::sm::total_bytes -= std::min(mongo::sm::total_bytes, current);
mongo::sm::malloc_bytes -= std::min(mongo::sm::malloc_bytes, current);
return ptr;
}
@ -208,7 +257,7 @@ void* mongo_free(void* ptr) {
// buffer, so this may result in undercounting
size_t current = mongo::sm::get_current(ptr);
mongo::sm::total_bytes -= std::min(mongo::sm::total_bytes, current);
mongo::sm::malloc_bytes -= std::min(mongo::sm::malloc_bytes, current);
std::free(ptr);
return nullptr;
@ -272,8 +321,9 @@ void js_free(void* p) {
void js::InitMallocAllocator() {
MallocArena = 0;
ArrayBufferContentsArena = 1;
StringBufferArena = 2;
BackgroundMallocArena = 1;
ArrayBufferContentsArena = 2;
StringBufferArena = 3;
}
void js::ShutDownMallocAllocator() {}

View File

@ -47,7 +47,7 @@ namespace mozjs {
class JSCustomAllocatorTest : public unittest::Test {
protected:
void setUp() override {
mongo::sm::reset(0);
mongo::sm::reset(0, false);
// Note: get_total_bytes() is an estimate and won't exactly count allocated bytes,
// test should only compare to 0
@ -55,13 +55,13 @@ protected:
}
void tearDown() override {
mongo::sm::reset(0);
mongo::sm::reset(0, false);
}
};
TEST_F(JSCustomAllocatorTest, MallocUpToLimit) {
mongo::sm::reset(100);
mongo::sm::reset(100, false);
ASSERT_EQUALS(mongo::sm::get_total_bytes(), 0);
void* ptr1 = js_malloc(20);
@ -85,7 +85,7 @@ TEST_F(JSCustomAllocatorTest, MallocUpToLimit) {
}
TEST_F(JSCustomAllocatorTest, ReallocUpToLimit) {
mongo::sm::reset(100);
mongo::sm::reset(100, false);
ASSERT_EQUALS(mongo::sm::get_total_bytes(), 0);
void* ptr1 = js_malloc(20);
@ -104,7 +104,7 @@ TEST_F(JSCustomAllocatorTest, ReallocUpToLimit) {
TEST_F(JSCustomAllocatorTest, CallocUpToLimit) {
mongo::sm::reset(100);
mongo::sm::reset(100, false);
ASSERT_EQUALS(mongo::sm::get_total_bytes(), 0);
void* ptr1 = js_calloc(10, 2);

View File

@ -98,14 +98,21 @@ JSObject* ModuleLoader::loadRootModule(JSContext* cx,
const std::string& path,
boost::optional<StringData> source) {
JS::RootedString baseUrl(cx, JS_NewStringCopyN(cx, _baseUrl.c_str(), _baseUrl.size()));
if (!baseUrl) {
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create baseUrl");
}
JS::RootedObject info(cx, createScriptPrivateInfo(cx, baseUrl, source));
if (!info) {
return nullptr;
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create info");
}
JS::RootedValue referencingPrivate(cx, JS::ObjectValue(*info));
JS::RootedString specifier(cx, JS_NewStringCopyN(cx, path.c_str(), path.size()));
JS::RootedObject moduleRequest(cx, JS::CreateModuleRequest(cx, specifier));
if (!specifier) {
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create specifier");
}
JS::RootedObject moduleRequest(
cx, JS::CreateModuleRequest(cx, specifier, JS::ModuleType::JavaScript));
if (!moduleRequest) {
return nullptr;
}
@ -148,7 +155,13 @@ bool ModuleLoader::importModuleDynamically(JSContext* cx,
JS::HandleObject moduleRequest,
JS::HandleObject promise) {
JS::RootedString baseUrl(cx, JS_NewStringCopyN(cx, _baseUrl.c_str(), _baseUrl.size()));
if (!baseUrl) {
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create baseUrl");
}
JS::RootedObject info(cx, createScriptPrivateInfo(cx, baseUrl));
if (!info) {
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create info");
}
JS::RootedValue newReferencingPrivate(cx, JS::ObjectValue(*info));
// The dynamic `import` method returns a Promise, and thus allows us to perform module loading
@ -160,15 +173,18 @@ bool ModuleLoader::importModuleDynamically(JSContext* cx,
JS::Rooted<JSString*> path(cx,
resolveAndNormalize(cx, moduleRequest, newReferencingPrivate));
if (!path) {
LOGV2_ERROR(716284, "Failed to resolve and normalize path");
return false;
}
JS::RootedObject module(cx, loadAndParse(cx, path, newReferencingPrivate));
if (!module) {
LOGV2_ERROR(716285, "Failed to load and parse module");
return false;
}
if (!JS::ModuleLink(cx, module)) {
LOGV2_ERROR(716286, "Failed to link module");
return false;
}
@ -177,6 +193,10 @@ bool ModuleLoader::importModuleDynamically(JSContext* cx,
JSObject* evaluationObject = ok ? &rval.toObject() : nullptr;
JS::RootedObject evaluationPromise(cx, evaluationObject);
if (!evaluationPromise) {
LOGV2_ERROR(716287, "Failed to create evaluation promise");
return false;
}
return JS::FinishDynamicModuleImport(
cx, evaluationPromise, newReferencingPrivate, moduleRequest, promise);
}
@ -239,8 +259,18 @@ JSString* ModuleLoader::resolveAndNormalize(JSContext* cx,
return nullptr;
}
boost::filesystem::path specifierPath(JS_EncodeStringToUTF8(cx, specifierString).get());
auto refAbsPath = boost::filesystem::path(JS_EncodeStringToUTF8(cx, refPath).get());
JS::UniqueChars specifierChars = JS_EncodeStringToUTF8(cx, specifierString);
uassert(ErrorCodes::JSInterpreterFailure,
"Failed to UTF-8 encode module specifier",
specifierChars);
boost::filesystem::path specifierPath(specifierChars.get());
JS::UniqueChars refPathChars = JS_EncodeStringToUTF8(cx, refPath);
uassert(ErrorCodes::JSInterpreterFailure,
"Failed to UTF-8 encode referencing module path",
refPathChars);
boost::filesystem::path refAbsPath(refPathChars.get());
if (is_directory(specifierPath)) {
JS_ReportErrorUTF8(cx,
"Directory import '%s' is not supported, imported from %s",
@ -513,10 +543,19 @@ JSObject* ModuleLoader::createScriptPrivateInfo(JSContext* cx,
JS::LossyUTF8CharsToNewTwoByteCharsZ(
cx, JS::UTF8Chars(source->data(), len), &len, js::MallocArena)
.get());
if (!ucbuf) {
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create ucbuf");
}
JS::RootedString sourceValue(cx, JS_NewUCStringCopyN(cx, ucbuf.get(), len));
if (!sourceValue) {
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create sourceValue");
}
if (!JS_DefineProperty(cx, info, "source", sourceValue, JSPROP_ENUMERATE)) {
return nullptr;
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create source property");
}
}
@ -575,7 +614,11 @@ std::string ModuleLoader::resolveBaseUrl(JSContext* cx, const std::string& loadP
}
JS::RootedString baseUrlString(cx, baseUrlValue.toString());
auto baseUrl = std::string{JS_EncodeStringToUTF8(cx, baseUrlString).get()};
JS::UniqueChars baseUrlChars = JS_EncodeStringToUTF8(cx, baseUrlString);
uassert(ErrorCodes::JSInterpreterFailure,
"Failed to UTF-8 encode baseUrl from jsconfig.json",
baseUrlChars); // returns nullptr on OOM/encoding errors
std::string baseUrl{baseUrlChars.get()};
boost::system::error_code ec;
auto resolvedPath =

View File

@ -279,9 +279,12 @@ public:
JS::RootedObject proto(_context);
JS::RealmOptions options;
_proto.init(_context,
_assertPtr(JS_NewGlobalObject(
_context, &_jsclass, nullptr, JS::DontFireOnNewGlobalHook, options)));
JSObject* global = JS_NewGlobalObject(
_context, &_jsclass, nullptr, JS::DontFireOnNewGlobalHook, options);
if (!global) {
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create global object");
}
_proto.init(_context, global);
JSAutoRealm ac(_context, _proto);
_installFunctions(_proto, T::freeFunctions);
@ -579,6 +582,15 @@ private:
}
JSObject* _assertPtr(JSObject* ptr) {
// If we dont even have a realm/global yet, calling throwCurrentJSException()
// would recurse into JSContext::getPendingException(), which expects a
// compartment and will crash. Instead, translate to a plain uassert with context.
if (!JS::CurrentGlobalOrNull(_context)) {
uasserted(ErrorCodes::JSInterpreterFailure,
"Failed to create JS object: no global realm initialized");
}
if (!ptr)
throwCurrentJSException(
_context, ErrorCodes::JSInterpreterFailure, "Failed to JS_NewX");

View File

@ -59,6 +59,7 @@ mongo_cc_library(
srcs = [
"extract/js/src/builtin/RegExp.cpp",
"extract/js/src/frontend/Parser.cpp",
"extract/js/src/gc/Memory.cpp",
"extract/js/src/gc/StoreBuffer.cpp",
"extract/js/src/irregexp/RegExpNativeMacroAssembler.cpp",
"extract/js/src/irregexp/imported/regexp-ast.cc",
@ -70,19 +71,21 @@ mongo_cc_library(
"extract/js/src/vm/Interpreter.cpp",
"extract/js/src/vm/ProfilingStack.cpp",
"extract/js/src/wasm/WasmCode-platform.cpp",
"extract/mfbt/lz4/lz4.c",
"extract/mfbt/lz4/lz4frame.c",
"extract/mfbt/lz4/lz4hc.c",
"extract/mfbt/lz4/xxhash.c",
"extract/js/src/xsum/xsum.cpp",
"extract/mozglue/misc/AutoProfilerLabel.cpp",
"extract/mozglue/misc/AwakeTimeStamp.cpp",
"extract/mozglue/misc/Debug.cpp",
"extract/mozglue/misc/MmapFaultHandler.cpp",
"extract/mozglue/misc/Now.cpp",
"extract/mozglue/misc/Printf.cpp",
"extract/mozglue/misc/SIMD.cpp",
"extract/mozglue/misc/StackWalk.cpp",
"extract/mozglue/misc/TimeStamp.cpp",
"extract/mozglue/misc/Uptime.cpp",
"extract/mozglue/static/lz4/lz4.c",
"extract/mozglue/static/lz4/lz4frame.c",
"extract/mozglue/static/lz4/lz4hc.c",
"extract/mozglue/static/lz4/xxhash.c",
"mongo_sources/freeOpToJSContext.cpp",
"mongo_sources/mongoErrorReportToString.cpp",
] + select({
@ -161,6 +164,7 @@ mongo_cc_library(
"extract/mfbt/**/*.h",
"extract/modules/fdlibm/**/*.h",
"mongo_sources/**/*.h",
"extract/mozglue/static/lz4/*.h",
]) + PLATFORM_SRCS,
hdrs = glob(["include/**/*.h"]),
copts = PLATFORM_COPTS + [
@ -241,11 +245,15 @@ mongo_cc_library(
# C5101: use of preprocessor directive in function-like macro
# argument list is undefined behavior
"/wd5101",
# Enable extern constexpr variables
"/Zc:externConstexpr",
],
"//conditions:default": [
"-Wno-sign-compare",
# Disable warnings for third party libraries as no action will be taken to fix them
# and they just clutter the output logs
"-Wno-unused-value",
"-Wno-unused-variable",
"-Wno-implicit-fallthrough",
# Bazel doesn't differentiate between compile flags for C and C++.
@ -310,6 +318,7 @@ mongo_cc_library(
"@platforms//os:macos": ["-Wl,-undefined,dynamic_lookup"],
"@platforms//os:windows": [
"ntdll.lib",
"mincore.lib",
],
"//conditions:default": [""],
}),
@ -345,6 +354,7 @@ mongo_cc_library(
"**/*.tbl",
]),
deps = [
"//src/third_party/fmt",
"//src/third_party/icu4c-57.1/source:icu_i18n",
"//src/third_party/zlib",
],

View File

@ -27,7 +27,6 @@ CFLAGS="$CFLAGS -D__STDC_FORMAT_MACROS" \
--enable-optimize \
--disable-js-shell \
--disable-tests \
--disable-new-pass-manager \
--disable-wasm-moz-intgemm
# we have to run make to generate a byte code version of the self hosted js and
@ -112,7 +111,7 @@ done
# this is all of the EXPORTS.js files from the moz.build
mkdir -p include/js
for i in 'AllocationLogging.h' 'AllocationRecording.h' 'AllocPolicy.h' 'Array.h' 'ArrayBuffer.h' 'ArrayBufferMaybeShared.h' 'BigInt.h' 'BuildId.h' 'CallAndConstruct.h' 'CallArgs.h' 'CallNonGenericMethod.h' 'CharacterEncoding.h' 'Class.h' 'ColumnNumber.h' 'ComparisonOperators.h' 'CompilationAndEvaluation.h' 'CompileOptions.h' 'Context.h' 'ContextOptions.h' 'Conversions.h' 'Date.h' 'Debug.h' 'Equality.h' 'ErrorInterceptor.h' 'ErrorReport.h' 'Exception.h' 'ForOfIterator.h' 'GCAnnotations.h' 'GCAPI.h' 'GCHashTable.h' 'GCPolicyAPI.h' 'GCTypeMacros.h' 'GCVariant.h' 'GCVector.h' 'GlobalObject.h' 'HashTable.h' 'HeapAPI.h' 'HelperThreadAPI.h' 'Id.h' 'Initialization.h' 'Interrupt.h' 'Iterator.h' 'JitCodeAPI.h' 'JSON.h' 'LocaleSensitive.h' 'MapAndSet.h' 'MemoryCallbacks.h' 'MemoryFunctions.h' 'MemoryMetrics.h' 'Modules.h' 'Object.h' 'Prefs.h' 'Principals.h' 'Printer.h' 'Printf.h' 'ProfilingCategory.h' 'ProfilingFrameIterator.h' 'ProfilingStack.h' 'Promise.h' 'PropertyAndElement.h' 'PropertyDescriptor.h' 'PropertySpec.h' 'ProtoKey.h' 'Proxy.h' 'Realm.h' 'RealmIterators.h' 'RealmOptions.h' 'RefCounted.h' 'RegExp.h' 'RegExpFlags.h' 'Result.h' 'RootingAPI.h' 'SavedFrameAPI.h' 'ScalarType.h' 'ScriptPrivate.h' 'ShadowRealmCallbacks.h' 'SharedArrayBuffer.h' 'SliceBudget.h' 'SourceText.h' 'StableStringChars.h' 'Stack.h' 'StreamConsumer.h' 'String.h' 'StructuredClone.h' 'SweepingAPI.h' 'Symbol.h' 'TelemetryTimers.h' 'TraceKind.h' 'TracingAPI.h' 'Transcoding.h' 'TypeDecls.h' 'UbiNode.h' 'UbiNodeBreadthFirst.h' 'UbiNodeCensus.h' 'UbiNodeDominatorTree.h' 'UbiNodePostOrder.h' 'UbiNodeShortestPaths.h' 'UbiNodeUtils.h' 'UniquePtr.h' 'Utility.h' 'Value.h' 'ValueArray.h' 'Vector.h' 'WaitCallbacks.h' 'Warnings.h' 'WasmFeatures.h' 'WasmModule.h' 'WeakMap.h' 'WeakMapPtr.h' 'Wrapper.h' 'WrapperCallbacks.h' 'Zone.h' ; do
for i in 'AllocationLogging.h' 'AllocationRecording.h' 'AllocPolicy.h' 'Array.h' 'ArrayBuffer.h' 'ArrayBufferMaybeShared.h' 'BigInt.h' 'BuildId.h' 'CallAndConstruct.h' 'CallArgs.h' 'CallNonGenericMethod.h' 'CharacterEncoding.h' 'Class.h' 'ColumnNumber.h' 'ComparisonOperators.h' 'CompilationAndEvaluation.h' 'CompileOptions.h' 'Context.h' 'ContextOptions.h' 'Conversions.h' 'Date.h' 'Debug.h' 'EnvironmentChain.h' 'Equality.h' 'ErrorInterceptor.h' 'ErrorReport.h' 'Exception.h' 'ForOfIterator.h' 'GCAnnotations.h' 'GCAPI.h' 'GCHashTable.h' 'GCPolicyAPI.h' 'GCTypeMacros.h' 'GCVariant.h' 'GCVector.h' 'GlobalObject.h' 'HashTable.h' 'HeapAPI.h' 'HelperThreadAPI.h' 'Id.h' 'Initialization.h' 'Interrupt.h' 'Iterator.h' 'JSON.h' 'LocaleSensitive.h' 'MapAndSet.h' 'MemoryCallbacks.h' 'MemoryFunctions.h' 'MemoryMetrics.h' 'Modules.h' 'NativeStackLimits.h' 'Object.h' 'ObjectWithStashedPointer.h' 'Prefs.h' 'Principals.h' 'Printer.h' 'Printf.h' 'ProfilingCategory.h' 'ProfilingFrameIterator.h' 'ProfilingStack.h' 'Promise.h' 'PropertyAndElement.h' 'PropertyDescriptor.h' 'PropertySpec.h' 'ProtoKey.h' 'Proxy.h' 'Realm.h' 'RealmIterators.h' 'RealmOptions.h' 'RefCounted.h' 'RegExp.h' 'RegExpFlags.h' 'Result.h' 'RootingAPI.h' 'SavedFrameAPI.h' 'ScalarType.h' 'ScriptPrivate.h' 'ShadowRealmCallbacks.h' 'SharedArrayBuffer.h' 'SliceBudget.h' 'SourceText.h' 'StableStringChars.h' 'Stack.h' 'StreamConsumer.h' 'String.h' 'StructuredClone.h' 'SweepingAPI.h' 'Symbol.h' 'TelemetryTimers.h' 'TraceKind.h' 'TracingAPI.h' 'Transcoding.h' 'TypeDecls.h' 'UbiNode.h' 'UbiNodeBreadthFirst.h' 'UbiNodeCensus.h' 'UbiNodeDominatorTree.h' 'UbiNodePostOrder.h' 'UbiNodeShortestPaths.h' 'UbiNodeUtils.h' 'UniquePtr.h' 'Utility.h' 'Value.h' 'ValueArray.h' 'Vector.h' 'WaitCallbacks.h' 'Warnings.h' 'WasmFeatures.h' 'WasmModule.h' 'WeakMap.h' 'WeakMapPtr.h' 'Wrapper.h' 'WrapperCallbacks.h' 'Zone.h' ; do
cp extract/js/public/$i include/js/
done
@ -121,11 +120,12 @@ cp extract/js/src/_build/js/public/PrefsGenerated.h include/js/
for i in 'ProfilingCategoryList.h' ; do
cp extract/js/src/_build/mozglue/baseprofiler/public/$i include/js/
cp extract/js/src/_build/dist/include/$i include
done
# this is all of the EXPORTS.js.experimental files from the moz.build
mkdir -p include/js/experimental
for i in 'CodeCoverage.h' 'CompileScript.h' 'CTypes.h' 'Intl.h' 'JitInfo.h' 'JSStencil.h' 'PCCountProfiling.h' 'SourceHook.h' 'TypedData.h' ; do
for i in 'BindingAllocs.h' 'CodeCoverage.h' 'CompileScript.h' 'CTypes.h' 'Intl.h' 'JitInfo.h' 'JSStencil.h' 'LoggingInterface.h' 'PCCountProfiling.h' 'SourceHook.h' 'TypedData.h' ; do
cp extract/js/public/experimental/$i include/js/experimental/
done
@ -143,7 +143,7 @@ done
# this is all of the EXPORTS.mozilla files from the moz.build's (i.e mfbt)
mkdir -p include/mozilla
for i in 'Algorithm.h' 'Alignment.h' 'AllocPolicy.h' 'AlreadyAddRefed.h' 'Array.h' 'ArrayUtils.h' 'Assertions.h' 'AtomicBitfields.h' 'Atomics.h' 'Attributes.h' 'BinarySearch.h' 'BitSet.h' 'BloomFilter.h' 'Buffer.h' 'BufferList.h' 'Casting.h' 'ChaosMode.h' 'Char16.h' 'CheckedInt.h' 'CompactPair.h' 'Compiler.h' 'Compression.h' 'DbgMacro.h' 'DebugOnly.h' 'DefineEnum.h' 'DoublyLinkedList.h' 'EndianUtils.h' 'EnumeratedArray.h' 'EnumeratedRange.h' 'EnumSet.h' 'EnumTypeTraits.h' 'fallible.h' 'FastBernoulliTrial.h' 'FloatingPoint.h' 'FStream.h' 'FunctionRef.h' 'FunctionTypeTraits.h' 'Fuzzing.h' 'HashFunctions.h' 'HashTable.h' 'HelperMacros.h' 'InitializedOnce.h' 'IntegerRange.h' 'IntegerTypeTraits.h' 'JSONWriter.h' 'JsRust.h' 'Latin1.h' 'Likely.h' 'LinkedList.h' 'MacroArgs.h' 'MacroForEach.h' 'MathAlgorithms.h' 'Maybe.h' 'MaybeOneOf.h' 'MaybeStorageBase.h' 'MemoryChecking.h' 'MemoryReporting.h' 'MoveOnlyFunction.h' 'MruCache.h' 'NonDereferenceable.h' 'NotNull.h' 'Opaque.h' 'OperatorNewExtensions.h' 'PairHash.h' 'Path.h' 'PodOperations.h' 'Poison.h' 'RandomNum.h' 'Range.h' 'RangedArray.h' 'RangedPtr.h' 'ReentrancyGuard.h' 'RefCounted.h' 'RefCountType.h' 'RefPtr.h' 'Result.h' 'ResultExtensions.h' 'ResultVariant.h' 'ReverseIterator.h' 'RollingMean.h' 'Saturate.h' 'ScopeExit.h' 'SegmentedVector.h' 'SHA1.h' 'SharedLibrary.h' 'SmallPointerArray.h' 'Span.h' 'SplayTree.h' 'SPSCQueue.h' 'StaticAnalysisFunctions.h' 'TaggedAnonymousMemory.h' 'Tainting.h' 'TemplateLib.h' 'TextUtils.h' 'ThreadLocal.h' 'ThreadSafety.h' 'ThreadSafeWeakPtr.h' 'ToString.h' 'Try.h' 'TypedEnumBits.h' 'Types.h' 'UniquePtr.h' 'UniquePtrExtensions.h' 'Unused.h' 'Utf8.h' 'Variant.h' 'Vector.h' 'WeakPtr.h' 'WindowsVersion.h' 'WrappingOperations.h' 'XorShift128PlusRNG.h' ; do
for i in 'Algorithm.h' 'Alignment.h' 'AllocPolicy.h' 'AlreadyAddRefed.h' 'Array.h' 'ArrayUtils.h' 'Assertions.h' 'AtomicBitfields.h' 'Atomics.h' 'Attributes.h' 'BinarySearch.h' 'BitSet.h' 'BloomFilter.h' 'Buffer.h' 'BufferList.h' 'Casting.h' 'ChaosMode.h' 'Char16.h' 'CheckedInt.h' 'CompactPair.h' 'Compiler.h' 'DbgMacro.h' 'DebugOnly.h' 'DefineEnum.h' 'DoublyLinkedList.h' 'EndianUtils.h' 'EnumeratedArray.h' 'EnumeratedRange.h' 'EnumSet.h' 'EnumTypeTraits.h' 'fallible.h' 'FastBernoulliTrial.h' 'FloatingPoint.h' 'FStream.h' 'FunctionRef.h' 'FunctionTypeTraits.h' 'Fuzzing.h' 'HashFunctions.h' 'HashTable.h' 'HelperMacros.h' 'InitializedOnce.h' 'IntegerRange.h' 'IntegerTypeTraits.h' 'JSONWriter.h' 'JsRust.h' 'Latin1.h' 'Likely.h' 'LinkedList.h' 'Literals.h' 'MacroArgs.h' 'MacroForEach.h' 'MathAlgorithms.h' 'Maybe.h' 'MaybeOneOf.h' 'MaybeStorageBase.h' 'MemoryChecking.h' 'MemoryReporting.h' 'MoveOnlyFunction.h' 'MPSCQueue.h' 'MruCache.h' 'NeverDestroyed.h' 'NonDereferenceable.h' 'NotNull.h' 'Opaque.h' 'OperatorNewExtensions.h' 'PairHash.h' 'Path.h' 'PodOperations.h' 'Poison.h' 'RandomNum.h' 'Range.h' 'RangedArray.h' 'RangedPtr.h' 'ReentrancyGuard.h' 'RefCounted.h' 'RefCountType.h' 'RefPtr.h' 'Result.h' 'ResultExtensions.h' 'ResultVariant.h' 'ReverseIterator.h' 'RollingMean.h' 'Saturate.h' 'ScopeExit.h' 'SegmentedVector.h' 'SHA1.h' 'SharedLibrary.h' 'SmallPointerArray.h' 'Span.h' 'SplayTree.h' 'SPSCQueue.h' 'StaticAnalysisFunctions.h' 'StringBuffer.h' 'TaggedAnonymousMemory.h' 'Tainting.h' 'TemplateLib.h' 'TextUtils.h' 'ThreadLocal.h' 'ThreadSafety.h' 'ThreadSafeWeakPtr.h' 'ToString.h' 'Try.h' 'TypedEnumBits.h' 'Types.h' 'UniquePtr.h' 'UniquePtrExtensions.h' 'Unused.h' 'Utf8.h' 'Variant.h' 'Vector.h' 'WeakPtr.h' 'WrappingOperations.h' 'XorShift128PlusRNG.h' 'WindowsVersion.h' ; do
cp extract/mfbt/$i include/mozilla/
done
@ -158,6 +158,15 @@ for i in 'AutoProfilerLabel.h' 'PlatformConditionVariable.h' 'PlatformMutex.h' '
cp extract/js/src/_build/dist/include/mozilla/$i include/mozilla
done
#exports in baseprofiler
for i in 'BaseProfilingCategory.h' ; do
cp extract/js/src/_build/dist/include/$i include
done
# exports.mozilla from baseprofiler
for i in 'BaseAndGeckoProfilerDetail.h' 'BaseProfileJSONWriter.h' 'BaseProfilerCounts.h' 'BaseProfilerDetail.h' 'BaseProfilerLabels.h' 'BaseProfilerMarkers.h' 'BaseProfilerMarkersDetail.h' 'BaseProfilerMarkersPrerequisites.h' 'BaseProfilerMarkerTypes.h' 'BaseProfilerRAIIMacro.h' 'BaseProfilerState.h' 'BaseProfilerUtils.h' 'FailureLatch.h' 'Flow.h' 'leb128iterator.h' 'ModuloBuffer.h' 'PowerOfTwo.h' 'ProfileBufferChunk.h' 'ProfileBufferChunkManager.h' 'ProfileBufferChunkManagerSingle.h' 'ProfileBufferChunkManagerWithLocalLimit.h' 'ProfileBufferControlledChunkManager.h' 'ProfileBufferEntryKinds.h' 'ProfileBufferEntrySerialization.h' 'ProfileBufferIndex.h' 'ProfileChunkedBuffer.h' 'ProfileChunkedBufferDetail.h' 'ProfilerBufferSize.h' 'ProgressLogger.h' 'ProportionValue.h'; do
cp extract/js/src/_build/dist/include/mozilla/$i include/mozilla
done
mkdir -p include/mozilla/glue
cp extract/js/src/_build/dist/include/mozilla/glue/Debug.h include/mozilla/glue
@ -171,6 +180,14 @@ mkdir -p extract/mozglue/misc
cp mozilla-release/mozglue/misc/*.cpp extract/mozglue/misc
cp mozilla-release/mozglue/misc/StackWalk_windows.h include/mozilla/
cp mozilla-release/mozglue/static/*.h include/mozilla
mkdir -p extract/mozglue/static
cp mozilla-release/mozglue/static/*.cpp extract/mozglue/static
mkdir -p extract/mozglue/static/lz4
cp mozilla-release/mozglue/static/lz4/*.h extract/mozglue/static/lz4
cp mozilla-release/mozglue/static/lz4/*.c extract/mozglue/static/lz4
mkdir -p include/vtune
touch include/vtune/VTuneWrapper.h
@ -226,7 +243,6 @@ extract/js/src/_build/mozglue/misc/backend.mk
extract/js/src/_build/mozglue/misc/.deps/
extract/js/src/_build/mozglue/misc/Makefile
extract/js/src/_build/mozinfo.json
extract/js/src/_build/old-configure.vars
extract/js/src/_build/testing/
extract/js/src/_build/_tests/mozbase/
extract/js/src/_build/third_party/
@ -235,8 +251,6 @@ __XARGS_RM__
xargs rm -r<<__XARGS_RM__
extract/js/src/build
extract/js/src/devtools/vprof/manifest.mk
extract/js/src/old-configure
extract/js/src/old-configure.in
extract/js/src/wasm/moz.build
extract/js/src/js-confdefs.h.in
extract/js/src/js-config.h.in

View File

@ -25,8 +25,7 @@ class FrontendContext;
enum class AllocFunction { Malloc, Calloc, Realloc };
/* Base class allocation policies providing allocation methods. */
class AllocPolicyBase {
class ArenaAllocPolicyBase {
public:
template <typename T>
T* maybe_pod_arena_malloc(arena_id_t arenaId, size_t numElems) {
@ -54,7 +53,11 @@ class AllocPolicyBase {
size_t newSize) {
return maybe_pod_arena_realloc<T>(arenaId, p, oldSize, newSize);
}
};
/* Base class allocation policies providing allocation methods. */
class AllocPolicyBase : public ArenaAllocPolicyBase {
public:
template <typename T>
T* maybe_pod_malloc(size_t numElems) {
return maybe_pod_arena_malloc<T>(js::MallocArena, numElems);
@ -86,6 +89,44 @@ class AllocPolicyBase {
}
};
/*
* Base class allocation policies providing allocation methods for allocations
* off the main thread.
*/
class BackgroundAllocPolicyBase : ArenaAllocPolicyBase {
public:
template <typename T>
T* maybe_pod_malloc(size_t numElems) {
return maybe_pod_arena_malloc<T>(js::BackgroundMallocArena, numElems);
}
template <typename T>
T* maybe_pod_calloc(size_t numElems) {
return maybe_pod_arena_calloc<T>(js::BackgroundMallocArena, numElems);
}
template <typename T>
T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) {
return maybe_pod_arena_realloc<T>(js::BackgroundMallocArena, p, oldSize,
newSize);
}
template <typename T>
T* pod_malloc(size_t numElems) {
return pod_arena_malloc<T>(js::BackgroundMallocArena, numElems);
}
template <typename T>
T* pod_calloc(size_t numElems) {
return pod_arena_calloc<T>(js::BackgroundMallocArena, numElems);
}
template <typename T>
T* pod_realloc(T* p, size_t oldSize, size_t newSize) {
return pod_arena_realloc<T>(js::BackgroundMallocArena, p, oldSize, newSize);
}
template <typename T>
void free_(T* p, size_t numElems = 0) {
js_free(p);
}
};
/* Policy for using system memory functions and doing no error reporting. */
class SystemAllocPolicy : public AllocPolicyBase {
public:
@ -93,6 +134,12 @@ class SystemAllocPolicy : public AllocPolicyBase {
bool checkSimulatedOOM() const { return !js::oom::ShouldFailWithOOM(); }
};
class BackgroundSystemAllocPolicy : public BackgroundAllocPolicyBase {
public:
void reportAllocOverflow() const {}
bool checkSimulatedOOM() const { return !js::oom::ShouldFailWithOOM(); }
};
MOZ_COLD JS_PUBLIC_API void ReportOutOfMemory(JSContext* cx);
MOZ_COLD JS_PUBLIC_API void ReportOutOfMemory(FrontendContext* fc);

View File

@ -261,13 +261,6 @@ extern JS_PUBLIC_API TwoByteCharsZ
UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars& utf8,
size_t* outlen, arena_id_t destArenaId);
/*
* Like UTF8CharsToNewTwoByteCharsZ, but for ConstUTF8CharsZ.
*/
extern JS_PUBLIC_API TwoByteCharsZ
UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8,
size_t* outlen, arena_id_t destArenaId);
/*
* The same as UTF8CharsToNewTwoByteCharsZ(), except that any malformed UTF-8
* characters will be replaced by \uFFFD. No exception will be thrown for
@ -277,10 +270,6 @@ extern JS_PUBLIC_API TwoByteCharsZ
LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars& utf8,
size_t* outlen, arena_id_t destArenaId);
extern JS_PUBLIC_API TwoByteCharsZ
LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8,
size_t* outlen, arena_id_t destArenaId);
/*
* Returns the length of the char buffer required to encode |s| as UTF8.
* Does not include the null-terminator.
@ -329,15 +318,6 @@ extern JS_PUBLIC_API Latin1CharsZ
UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars& utf8, size_t* outlen,
arena_id_t destArenaId);
/*
* Return a null-terminated Latin-1 string copied from the input string,
* storing its length (excluding null terminator) in |*outlen|. Non-Latin-1
* codepoints are replaced by '?'. Returns Latin1CharsZ() on failure.
*/
extern JS_PUBLIC_API Latin1CharsZ
LossyUTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars& utf8,
size_t* outlen, arena_id_t destArenaId);
/*
* Returns true if all characters in the given null-terminated string are
* ASCII, i.e. < 0x80, false otherwise.

View File

@ -813,11 +813,6 @@ enum class ESClass {
BigInt,
Function, // Note: Only JSFunction objects.
#ifdef ENABLE_RECORD_TUPLE
Record,
Tuple,
#endif
/** None of the above. */
Other
};

View File

@ -27,6 +27,7 @@ union Utf8Unit;
namespace JS {
class JS_PUBLIC_API EnvironmentChain;
class JS_PUBLIC_API InstantiateOptions;
class JS_PUBLIC_API ReadOnlyCompileOptions;
@ -84,12 +85,12 @@ extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
* objects that should end up on the script's scope chain.
*/
extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
JS::HandleObjectVector envChain,
const JS::EnvironmentChain& envChain,
JS::Handle<JSScript*> script,
JS::MutableHandle<JS::Value> rval);
extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
JS::HandleObjectVector envChain,
const JS::EnvironmentChain& envChain,
JS::Handle<JSScript*> script);
namespace JS {
@ -108,7 +109,8 @@ extern JS_PUBLIC_API bool Evaluate(JSContext* cx,
* the global object on it; that's implicit. It needs to contain the other
* objects that should end up on the script's scope chain.
*/
extern JS_PUBLIC_API bool Evaluate(JSContext* cx, HandleObjectVector envChain,
extern JS_PUBLIC_API bool Evaluate(JSContext* cx,
const JS::EnvironmentChain& envChain,
const ReadOnlyCompileOptions& options,
SourceText<char16_t>& srcBuf,
MutableHandle<Value> rval);
@ -173,7 +175,7 @@ extern JS_PUBLIC_API JSScript* CompileUtf8Path(
* global must not be explicitly included in the scope chain.
*/
extern JS_PUBLIC_API JSFunction* CompileFunction(
JSContext* cx, HandleObjectVector envChain,
JSContext* cx, const JS::EnvironmentChain& envChain,
const ReadOnlyCompileOptions& options, const char* name, unsigned nargs,
const char* const* argnames, SourceText<char16_t>& srcBuf);
@ -185,7 +187,7 @@ extern JS_PUBLIC_API JSFunction* CompileFunction(
* global must not be explicitly included in the scope chain.
*/
extern JS_PUBLIC_API JSFunction* CompileFunction(
JSContext* cx, HandleObjectVector envChain,
JSContext* cx, const JS::EnvironmentChain& envChain,
const ReadOnlyCompileOptions& options, const char* name, unsigned nargs,
const char* const* argnames, SourceText<mozilla::Utf8Unit>& srcBuf);
@ -194,7 +196,7 @@ extern JS_PUBLIC_API JSFunction* CompileFunction(
* Rust-friendly ergonomics.
*/
extern JS_PUBLIC_API JSFunction* CompileFunctionUtf8(
JSContext* cx, HandleObjectVector envChain,
JSContext* cx, const JS::EnvironmentChain& envChain,
const ReadOnlyCompileOptions& options, const char* name, unsigned nargs,
const char* const* argnames, const char* utf8, size_t length);

View File

@ -62,6 +62,9 @@
#include "js/CharacterEncoding.h" // JS::ConstUTF8CharsZ
#include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
# include "js/Prefs.h" // JS::Prefs::*
#endif
#include "js/TypeDecls.h" // JS::MutableHandle (fwd)
namespace js {
@ -124,22 +127,29 @@ class JS_PUBLIC_API PrefableCompileOptions {
public:
PrefableCompileOptions()
: importAttributes_(false),
importAttributesAssertSyntax_(false),
sourcePragmas_(true),
throwOnAsmJSValidationFailure_(false) {}
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
explicitResourceManagement_(
JS::Prefs::experimental_explicit_resource_management()),
#endif
throwOnAsmJSValidationFailure_(false) {
}
bool importAttributes() const { return importAttributes_; }
PrefableCompileOptions& setImportAttributes(bool enabled) {
importAttributes_ = enabled;
return *this;
}
bool importAttributesAssertSyntax() const {
return importAttributesAssertSyntax_;
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
bool explicitResourceManagement() const {
return explicitResourceManagement_;
}
PrefableCompileOptions& setImportAttributesAssertSyntax(bool enabled) {
importAttributesAssertSyntax_ = enabled;
PrefableCompileOptions& setExplicitResourceManagement(bool enabled) {
explicitResourceManagement_ = enabled;
return *this;
}
#endif
// Enable/disable support for parsing '//(#@) source(Mapping)?URL=' pragmas.
bool sourcePragmas() const { return sourcePragmas_; }
@ -176,9 +186,11 @@ class JS_PUBLIC_API PrefableCompileOptions {
void dumpWith(Printer& print) const {
# define PrintFields_(Name) print(#Name, Name)
PrintFields_(importAttributes_);
PrintFields_(importAttributesAssertSyntax_);
PrintFields_(sourcePragmas_);
PrintFields_(throwOnAsmJSValidationFailure_);
# ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
PrintFields_(explicitResourceManagement_);
# endif
# undef PrintFields_
switch (asmJSOption_) {
@ -204,11 +216,16 @@ class JS_PUBLIC_API PrefableCompileOptions {
private:
// ==== Syntax-related options. ====
bool importAttributes_ : 1;
bool importAttributesAssertSyntax_ : 1;
// The context has specified that source pragmas should be parsed.
bool sourcePragmas_ : 1;
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
// The context has specified that explicit resource management syntax
// should be parsed.
bool explicitResourceManagement_ : 1;
#endif
// ==== asm.js options. ====
bool throwOnAsmJSValidationFailure_ : 1;
@ -315,16 +332,6 @@ class JS_PUBLIC_API TransitiveCompileOptions {
// called. There is currently no mechanism to release the data sooner.
bool usePinnedBytecode = false;
// De-optimize ES module's top-level `var`s, in order to define all of them
// on the ModuleEnvironmentObject, instead of local slot.
//
// This is used for providing all global variables in Cu.import return value
// (see bug 1766761 for more details), and this is temporary solution until
// ESM-ification finishes.
//
// WARNING: This option will eventually be removed.
bool deoptimizeModuleGlobalVars = false;
PrefableCompileOptions prefableOptions_;
/**
@ -390,10 +397,12 @@ class JS_PUBLIC_API TransitiveCompileOptions {
}
bool importAttributes() const { return prefableOptions_.importAttributes(); }
bool importAttributesAssertSyntax() const {
return prefableOptions_.importAttributesAssertSyntax();
}
bool sourcePragmas() const { return prefableOptions_.sourcePragmas(); }
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
bool explicitResourceManagement() const {
return prefableOptions_.explicitResourceManagement();
}
#endif
bool throwOnAsmJSValidationFailure() const {
return prefableOptions_.throwOnAsmJSValidationFailure();
}
@ -435,7 +444,6 @@ class JS_PUBLIC_API TransitiveCompileOptions {
PrintFields_(topLevelAwait);
PrintFields_(borrowBuffer);
PrintFields_(usePinnedBytecode);
PrintFields_(deoptimizeModuleGlobalVars);
PrintFields_(introductionType);
PrintFields_(introductionLineno);
PrintFields_(introductionOffset);
@ -709,13 +717,16 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
return *this;
}
void warnAboutConflictingDelazification() const;
CompileOptions& setEagerDelazificationStrategy(
DelazificationOption strategy) {
// forceFullParse is at the moment considered as a non-overridable strategy.
MOZ_RELEASE_ASSERT(eagerDelazificationStrategy_ !=
DelazificationOption::ParseEverythingEagerly ||
strategy ==
DelazificationOption::ParseEverythingEagerly);
const auto PEE = DelazificationOption::ParseEverythingEagerly;
if (eagerDelazificationStrategy_ == PEE && strategy != PEE) {
// Parse Everything Eagerly cannot be replaced, do noting.
warnAboutConflictingDelazification();
return *this;
}
eagerDelazificationStrategy_ = strategy;
return *this;
}
@ -746,17 +757,22 @@ class JS_PUBLIC_API InstantiateOptions {
bool hideScriptFromDebugger = false;
bool deferDebugMetadata = false;
InstantiateOptions() = default;
DelazificationOption eagerDelazificationStrategy_ =
DelazificationOption::OnDemandOnly;
InstantiateOptions();
explicit InstantiateOptions(const ReadOnlyCompileOptions& options)
: skipFilenameValidation(options.skipFilenameValidation_),
hideScriptFromDebugger(options.hideScriptFromDebugger_),
deferDebugMetadata(options.deferDebugMetadata_) {}
deferDebugMetadata(options.deferDebugMetadata_),
eagerDelazificationStrategy_(options.eagerDelazificationStrategy()) {}
void copyTo(CompileOptions& options) const {
options.skipFilenameValidation_ = skipFilenameValidation;
options.hideScriptFromDebugger_ = hideScriptFromDebugger;
options.deferDebugMetadata_ = deferDebugMetadata;
options.setEagerDelazificationStrategy(eagerDelazificationStrategy_);
}
bool hideFromNewScriptInitial() const {
@ -772,6 +788,29 @@ class JS_PUBLIC_API InstantiateOptions {
MOZ_ASSERT(skipFilenameValidation == false);
MOZ_ASSERT(hideScriptFromDebugger == false);
MOZ_ASSERT(deferDebugMetadata == false);
MOZ_ASSERT(eagerDelazificationStrategy_ ==
DelazificationOption::OnDemandOnly);
}
// Assert that all fields have values compatible with the default value.
//
// This can be used in the same way as assertDefault, in case the
// setForceFullParse() is used on the original compile options.
void assertCompatibleWithDefault() const {
MOZ_ASSERT(skipFilenameValidation == false);
MOZ_ASSERT(hideScriptFromDebugger == false);
MOZ_ASSERT(deferDebugMetadata == false);
// The instantiation step uses the eagerDelazificationStrategy_ field
// only for TransitiveCompileOptions::populateDelazificationCache().
//
// Both the default OnDemandOnly and
// the ParseEverythingEagerly from setForceFullParse() returns
// false, and they're are compatible.
MOZ_ASSERT(eagerDelazificationStrategy_ ==
DelazificationOption::OnDemandOnly ||
eagerDelazificationStrategy_ ==
DelazificationOption::ParseEverythingEagerly);
}
#endif
};

View File

@ -24,7 +24,6 @@ class JS_PUBLIC_API ContextOptions {
ContextOptions()
: wasm_(true),
wasmForTrustedPrinciples_(true),
wasmVerbose_(false),
wasmBaseline_(true),
wasmIon_(true),
testWasmAwaitTier2_(false),
@ -34,10 +33,6 @@ class JS_PUBLIC_API ContextOptions {
asyncStackCaptureDebuggeeOnly_(false),
throwOnDebuggeeWouldRun_(true),
dumpStackOnDebuggeeWouldRun_(false),
#ifdef JS_ENABLE_SMOOSH
trackNotImplemented_(false),
trySmoosh_(false),
#endif
fuzzing_(false) {
}
// clang-format on
@ -71,12 +66,6 @@ class JS_PUBLIC_API ContextOptions {
return *this;
}
bool wasmVerbose() const { return wasmVerbose_; }
ContextOptions& setWasmVerbose(bool flag) {
wasmVerbose_ = flag;
return *this;
}
bool wasmBaseline() const { return wasmBaseline_; }
ContextOptions& setWasmBaseline(bool flag) {
wasmBaseline_ = flag;
@ -122,14 +111,6 @@ class JS_PUBLIC_API ContextOptions {
return *this;
}
bool importAttributesAssertSyntax() const {
return compileOptions_.importAttributesAssertSyntax();
}
ContextOptions& setImportAttributesAssertSyntax(bool enabled) {
compileOptions_.setImportAttributesAssertSyntax(enabled);
return *this;
}
// Override to allow disabling the eval restriction security checks for
// this context.
bool disableEvalSecurityChecks() const { return disableEvalSecurityChecks_; }
@ -173,24 +154,6 @@ class JS_PUBLIC_API ContextOptions {
return *this;
}
#ifdef JS_ENABLE_SMOOSH
// Track Number of Not Implemented Calls by writing to a file
bool trackNotImplemented() const { return trackNotImplemented_; }
ContextOptions& setTrackNotImplemented(bool flag) {
trackNotImplemented_ = flag;
return *this;
}
// Try compiling SmooshMonkey frontend first, and fallback to C++
// implementation when it fails.
bool trySmoosh() const { return trySmoosh_; }
ContextOptions& setTrySmoosh(bool flag) {
trySmoosh_ = flag;
return *this;
}
#endif // JS_ENABLE_SMOOSH
bool fuzzing() const { return fuzzing_; }
// Defined out-of-line because it depends on a compile-time option
ContextOptions& setFuzzing(bool flag);
@ -209,7 +172,6 @@ class JS_PUBLIC_API ContextOptions {
// WASM options.
bool wasm_ : 1;
bool wasmForTrustedPrinciples_ : 1;
bool wasmVerbose_ : 1;
bool wasmBaseline_ : 1;
bool wasmIon_ : 1;
bool testWasmAwaitTier2_ : 1;
@ -223,10 +185,6 @@ class JS_PUBLIC_API ContextOptions {
bool asyncStackCaptureDebuggeeOnly_ : 1;
bool throwOnDebuggeeWouldRun_ : 1;
bool dumpStackOnDebuggeeWouldRun_ : 1;
#ifdef JS_ENABLE_SMOOSH
bool trackNotImplemented_ : 1;
bool trySmoosh_ : 1;
#endif
bool fuzzing_ : 1;
// Compile options.

View File

@ -272,17 +272,6 @@ inline JSObject* ToObject(JSContext* cx, HandleValue v) {
return js::ToObjectSlow(cx, v, false);
}
#ifdef ENABLE_RECORD_TUPLE
inline JSObject* ToObjectOrGetObjectPayload(JSContext* cx, HandleValue v) {
detail::AssertArgumentsAreSane(cx, v);
if (v.hasObjectPayload()) {
return &v.getObjectPayload();
}
return js::ToObjectSlow(cx, v, false);
}
#endif
/**
* Convert a double value to UnsignedInteger (an unsigned integral type) using
* ECMAScript-style semantics (that is, in like manner to how ECMAScript's
@ -372,7 +361,8 @@ inline UnsignedInteger ToUnsignedInteger(double d) {
}
// Compute the congruent value in the signed range.
return (bits & mozilla::FloatingPoint<double>::kSignBit) ? ~result + 1
return (bits & mozilla::FloatingPoint<double>::kSignBit)
? UnsignedInteger(~result) + 1
: result;
}

View File

@ -11,7 +11,9 @@
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/BaseProfilerUtils.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Vector.h"
#include <utility>
@ -29,6 +31,136 @@ class Debugger;
extern JS_PUBLIC_API bool JS_DefineDebuggerObject(JSContext* cx,
JS::HandleObject obj);
// If the JS execution tracer is running, this will generate a
// ENTRY_KIND_LABEL_ENTER entry with the specified label.
// The consumer of the trace can then, for instance, correlate all code running
// after this entry and before the corresponding ENTRY_KIND_LABEL_LEAVE with the
// provided label.
// If the tracer is not running, this does nothing.
extern JS_PUBLIC_API void JS_TracerEnterLabelLatin1(JSContext* cx,
const char* label);
extern JS_PUBLIC_API void JS_TracerEnterLabelTwoByte(JSContext* cx,
const char16_t* label);
extern JS_PUBLIC_API bool JS_TracerIsTracing(JSContext* cx);
// If the JS execution tracer is running, this will generate a
// ENTRY_KIND_LABEL_LEAVE entry with the specified label.
// It is up to the consumer to decide what to do with a ENTRY_KIND_LABEL_LEAVE
// entry is encountered without a corresponding ENTRY_KIND_LABEL_ENTER.
// If the tracer is not running, this does nothing.
extern JS_PUBLIC_API void JS_TracerLeaveLabelLatin1(JSContext* cx,
const char* label);
extern JS_PUBLIC_API void JS_TracerLeaveLabelTwoByte(JSContext* cx,
const char16_t* label);
#ifdef MOZ_EXECUTION_TRACING
// This will begin execution tracing for the JSContext, i.e., this will begin
// recording every entrance into / exit from a function for the given context.
// The trace can be read via JS_TracerSnapshotTrace, and populates the
// ExecutionTrace struct defined below.
//
// This throws if the code coverage is active for any realm in the context.
extern JS_PUBLIC_API bool JS_TracerBeginTracing(JSContext* cx);
// This ends execution tracing for the JSContext, discards the tracing
// buffers, and clears some caches used for tracing. JS_TracerSnapshotTrace
// should be called *before* JS_TracerEndTracing if you want to read the trace
// data for this JSContext.
extern JS_PUBLIC_API bool JS_TracerEndTracing(JSContext* cx);
namespace JS {
// This is populated by JS_TracerSnapshotTrace and just represent a minimal
// structure for natively representing an execution trace across a range of
// JSContexts (see below). The core of the trace is an array of events, each of
// which is a tagged union with data corresponding to that event. Events can
// also point into various tables, and store all of their string data in a
// contiguous UTF-8 stringBuffer (each string is null-terminated within the
// buffer.)
struct ExecutionTrace {
enum class EventKind : uint8_t {
FunctionEnter = 0,
FunctionLeave = 1,
LabelEnter = 2,
LabelLeave = 3,
// NOTE: the `Error` event has no TracedEvent payload, and will always
// represent the end of the trace when encountered.
Error = 4,
};
enum class ImplementationType : uint8_t {
Interpreter = 0,
Baseline = 1,
Ion = 2,
Wasm = 3,
};
struct TracedEvent {
EventKind kind;
union {
// For FunctionEnter / FunctionLeave
struct {
ImplementationType implementation;
// 1-origin line number of the function
uint32_t lineNumber;
// 1-origin column of the function
uint32_t column;
// Keys into the thread's scriptUrls HashMap. This key can be missing
// from the HashMap, although ideally that situation is rare (it is
// more likely in long running traces with *many* unique functions
// and/or scripts)
uint32_t scriptId;
// ID to the realm that the frame was in. It's used for finding which
// frame comes from which window/page.
uint64_t realmID;
// Keys into the thread's atoms HashMap. This key can be missing from
// the HashMap as well (see comment above scriptId)
uint32_t functionNameId;
} functionEvent;
// For LabelEnter / LabelLeave
struct {
size_t label; // Indexes directly into the trace's stringBuffer
} labelEvent;
};
// Milliseconds since process creation
double time;
};
struct TracedJSContext {
mozilla::baseprofiler::BaseProfilerThreadId id;
// Maps ids to indices into the trace's stringBuffer
mozilla::HashMap<uint32_t, size_t> scriptUrls;
// Similar to scriptUrls
mozilla::HashMap<uint32_t, size_t> atoms;
mozilla::Vector<TracedEvent> events;
};
mozilla::Vector<char> stringBuffer;
// This will be populated with an entry for each context which had tracing
// enabled via JS_TracerBeginTracing.
mozilla::Vector<TracedJSContext> contexts;
};
} // namespace JS
// Captures the trace for all JSContexts in the process which are currently
// tracing.
extern JS_PUBLIC_API bool JS_TracerSnapshotTrace(JS::ExecutionTrace& trace);
#endif /* MOZ_EXECUTION_TRACING */
namespace JS {
namespace dbg {
@ -302,52 +434,6 @@ JS_PUBLIC_API bool IsDebugger(JSObject& obj);
JS_PUBLIC_API bool GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj,
MutableHandleObjectVector vector);
// Hooks for reporting where JavaScript execution began.
//
// Our performance tools would like to be able to label blocks of JavaScript
// execution with the function name and source location where execution began:
// the event handler, the callback, etc.
//
// Construct an instance of this class on the stack, providing a JSContext
// belonging to the runtime in which execution will occur. Each time we enter
// JavaScript --- specifically, each time we push a JavaScript stack frame that
// has no older JS frames younger than this AutoEntryMonitor --- we will
// call the appropriate |Entry| member function to indicate where we've begun
// execution.
class MOZ_STACK_CLASS JS_PUBLIC_API AutoEntryMonitor {
JSContext* cx_;
AutoEntryMonitor* savedMonitor_;
public:
explicit AutoEntryMonitor(JSContext* cx);
~AutoEntryMonitor();
// SpiderMonkey reports the JavaScript entry points occuring within this
// AutoEntryMonitor's scope to the following member functions, which the
// embedding is expected to override.
//
// It is important to note that |asyncCause| is owned by the caller and its
// lifetime must outlive the lifetime of the AutoEntryMonitor object. It is
// strongly encouraged that |asyncCause| be a string constant or similar
// statically allocated string.
// We have begun executing |function|. Note that |function| may not be the
// actual closure we are running, but only the canonical function object to
// which the script refers.
virtual void Entry(JSContext* cx, JSFunction* function,
HandleValue asyncStack, const char* asyncCause) = 0;
// Execution has begun at the entry point of |script|, which is not a
// function body. (This is probably being executed by 'eval' or some
// JSAPI equivalent.)
virtual void Entry(JSContext* cx, JSScript* script, HandleValue asyncStack,
const char* asyncCause) = 0;
// Execution of the function or script has ended.
virtual void Exit(JSContext* cx) {}
};
// Returns true if there's any debugger attached to the given context where
// the debugger's "shouldAvoidSideEffects" property is true.
//

View File

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 js_EnvironmentChain_h
#define js_EnvironmentChain_h
#include "mozilla/Attributes.h" // MOZ_RAII
#include <stddef.h> // size_t
#include "jstypes.h" // JS_PUBLIC_API
#include "js/GCVector.h" // JS::RootedVector
struct JS_PUBLIC_API JSContext;
class JS_PUBLIC_API JSObject;
namespace JS {
enum class SupportUnscopables : bool { No = false, Yes = true };
/**
* JS::EnvironmentChain stores a list of objects to put on the environment
* chain.
*
* Internally the engine will create a non-syntactic 'with' environment for each
* of these objects. Note that 'with' environments aren't optimized well so you
* should use this class only if you really have to.
*
* The SupportUnscopables enum class controls whether these non-syntactic 'with'
* environments support Symbol.unscopables similar to syntactic 'with'
* statements in JS.
*
* Passing SupportUnscopables::No is better for performance because it lets us
* skip the Symbol.unscopables property lookup. Some Web APIs require supporting
* Symbol.unscopables though. In Firefox, SupportUnscopables::Yes is used for
* event handlers.
*/
class MOZ_RAII JS_PUBLIC_API EnvironmentChain {
JS::RootedObjectVector chain_;
SupportUnscopables supportUnscopables_;
public:
EnvironmentChain(JSContext* cx, SupportUnscopables supportUnscopables)
: chain_(cx), supportUnscopables_(supportUnscopables) {}
EnvironmentChain(const EnvironmentChain&) = delete;
void operator=(const EnvironmentChain&) = delete;
[[nodiscard]] bool append(JSObject* obj) { return chain_.append(obj); }
bool empty() const { return chain_.empty(); }
size_t length() const { return chain_.length(); }
RootedObjectVector& chain() { return chain_; }
const RootedObjectVector& chain() const { return chain_; }
void setSupportUnscopables(SupportUnscopables supportUnscopables) {
supportUnscopables_ = supportUnscopables;
}
SupportUnscopables supportUnscopables() const { return supportUnscopables_; }
};
} // namespace JS
#endif /* js_EnvironmentChain_h */

View File

@ -62,24 +62,40 @@ enum ErrorArgumentsType {
* using the generalized error reporting mechanism. (One side effect of this
* type is to not prepend 'Error:' to warning messages.) This value can go away
* if we ever decide to use an entirely separate mechanism for warnings.
*
* The errors and warnings are arranged in alphabetically within their
* respective categories as defined in the comments below.
*/
enum JSExnType {
// Generic Errors
JSEXN_ERR,
JSEXN_FIRST = JSEXN_ERR,
// Internal Errors
JSEXN_INTERNALERR,
// ECMAScript Errors
JSEXN_AGGREGATEERR,
JSEXN_EVALERR,
JSEXN_RANGEERR,
JSEXN_REFERENCEERR,
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
JSEXN_SUPPRESSEDERR,
#endif
JSEXN_SYNTAXERR,
JSEXN_TYPEERR,
JSEXN_URIERR,
// Debugger Errors
JSEXN_DEBUGGEEWOULDRUN,
// WASM Errors
JSEXN_WASMCOMPILEERROR,
JSEXN_WASMLINKERROR,
JSEXN_WASMRUNTIMEERROR,
#ifdef ENABLE_WASM_JSPI
JSEXN_WASMSUSPENDERROR,
#endif
JSEXN_ERROR_LIMIT,
// Warnings
JSEXN_WARN = JSEXN_ERROR_LIMIT,
// Error Notes
JSEXN_NOTE,
JSEXN_LIMIT
};
@ -540,6 +556,20 @@ extern JS_PUBLIC_API bool CreateError(
JSErrorReport* report, HandleString message,
Handle<mozilla::Maybe<Value>> cause, MutableHandleValue rval);
/**
* An uncatchable exception is used to terminate execution by returning false
* or nullptr without reporting a pending exception on the context. These
* exceptions are called "uncatchable" because try-catch can't be used to catch
* them.
*
* This is mainly used to terminate JS execution from the interrupt handler.
*
* If the context has a pending exception, this function will clear it. Also, in
* debug builds, it sets a flag on the context to improve exception handling
* assertions in the engine.
*/
extern JS_PUBLIC_API void ReportUncatchableException(JSContext* cx);
} /* namespace JS */
#endif /* js_ErrorReport_h */

View File

@ -28,7 +28,6 @@ namespace js {
namespace gc {
class GCRuntime;
} // namespace gc
class JS_PUBLIC_API SliceBudget;
namespace gcstats {
struct Statistics;
} // namespace gcstats
@ -36,6 +35,8 @@ struct Statistics;
namespace JS {
class JS_PUBLIC_API SliceBudget;
// Options used when starting a GC.
enum class GCOptions : uint32_t {
// Normal GC invocation.
@ -261,14 +262,6 @@ typedef enum JSGCParamKey {
*/
JSGC_MIN_EMPTY_CHUNK_COUNT = 21,
/**
* We never keep more than this many unused chunks in the free chunk pool.
*
* Pref: javascript.options.mem.gc_max_empty_chunk_count
* Default: MaxEmptyChunkCount
*/
JSGC_MAX_EMPTY_CHUNK_COUNT = 22,
/**
* Whether compacting GC is enabled.
*
@ -488,6 +481,33 @@ typedef enum JSGCParamKey {
*/
JSGC_SLICE_NUMBER = 54,
/**
* Whether the nursery is enabled.
*
* Pref: javascript.options.mem.gc_generational
* Default: true
*/
JSGC_NURSERY_ENABLED = 55,
/*
* Whether we are in high frequency GC mode, where the time between
* collections is less than that specified by JSGC_HIGH_FREQUENCY_TIME_LIMIT.
*/
JSGC_HIGH_FREQUENCY_MODE = 56,
/**
* The engine attempts to keep nursery collection time less than this limit by
* restricting the size of the nursery.
*
* This only happens in optimized builds. It does not happen during pageload
* (as indicated by js::gc::SetPerformanceHint).
*
* Setting this to zero disables this feature.
*
* Default: 4
* Pref: javascript.options.mem.nursery_max_time_goal_ms
*/
JSGC_NURSERY_MAX_TIME_GOAL_MS = 57,
} JSGCParamKey;
/*
@ -505,7 +525,7 @@ typedef void (*JSTraceDataOp)(JSTracer* trc, void* data);
* While tracing this should check the budget and return false if it has been
* exceeded. When passed an unlimited budget it should always return true.
*/
typedef bool (*JSGrayRootsTracer)(JSTracer* trc, js::SliceBudget& budget,
typedef bool (*JSGrayRootsTracer)(JSTracer* trc, JS::SliceBudget& budget,
void* data);
typedef enum JSGCStatus { JSGC_BEGIN, JSGC_END } JSGCStatus;
@ -651,7 +671,7 @@ namespace JS {
D(DOCSHELL, 54) \
D(HTML_PARSER, 55) \
D(DOM_TESTUTILS, 56) \
D(PREPARE_FOR_PAGELOAD, 57) \
D(PREPARE_FOR_PAGELOAD, LAST_FIREFOX_REASON) \
\
/* Reasons reserved for embeddings. */ \
D(RESERVED1, FIRST_RESERVED_REASON) \
@ -666,6 +686,7 @@ namespace JS {
enum class GCReason {
FIRST_FIREFOX_REASON = 33,
LAST_FIREFOX_REASON = 57,
FIRST_RESERVED_REASON = 90,
#define MAKE_REASON(name, val) name = val,
@ -692,6 +713,18 @@ extern JS_PUBLIC_API const char* ExplainGCReason(JS::GCReason reason);
*/
extern JS_PUBLIC_API bool InternalGCReason(JS::GCReason reason);
/**
* Get a statically allocated C string explaining the given Abort reason.
* Input is the integral value of the enum.
*/
extern JS_PUBLIC_API const char* ExplainGCAbortReason(uint32_t reason);
/**
* Get a statically allocated C string describing the Phase.
* Input is the integral value of the enum.
*/
extern JS_PUBLIC_API const char* GetGCPhaseName(uint32_t phase);
/*
* Zone GC:
*
@ -778,7 +811,7 @@ extern JS_PUBLIC_API void NonIncrementalGC(JSContext* cx, JS::GCOptions options,
extern JS_PUBLIC_API void StartIncrementalGC(JSContext* cx,
JS::GCOptions options,
GCReason reason,
const js::SliceBudget& budget);
const JS::SliceBudget& budget);
/**
* Perform a slice of an ongoing incremental collection. When this function
@ -789,7 +822,7 @@ extern JS_PUBLIC_API void StartIncrementalGC(JSContext* cx,
* shorter than the requested interval.
*/
extern JS_PUBLIC_API void IncrementalGCSlice(JSContext* cx, GCReason reason,
const js::SliceBudget& budget);
const JS::SliceBudget& budget);
/**
* Return whether an incremental GC has work to do on the foreground thread and
@ -957,7 +990,7 @@ typedef void (*DoCycleCollectionCallback)(JSContext* cx);
extern JS_PUBLIC_API DoCycleCollectionCallback
SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback);
using CreateSliceBudgetCallback = js::SliceBudget (*)(JS::GCReason reason,
using CreateSliceBudgetCallback = JS::SliceBudget (*)(JS::GCReason reason,
int64_t millis);
/**
@ -971,14 +1004,6 @@ using CreateSliceBudgetCallback = js::SliceBudget (*)(JS::GCReason reason,
extern JS_PUBLIC_API void SetCreateGCSliceBudgetCallback(
JSContext* cx, CreateSliceBudgetCallback cb);
/**
* Incremental GC defaults to enabled, but may be disabled for testing or in
* embeddings that have not yet implemented barriers on their native classes.
* There is not currently a way to re-enable incremental GC once it has been
* disabled on the runtime.
*/
extern JS_PUBLIC_API void DisableIncrementalGC(JSContext* cx);
/**
* Returns true if incremental GC is enabled. Simply having incremental GC
* enabled is not sufficient to ensure incremental collections are happening.

View File

@ -646,6 +646,21 @@ class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>> final
bool needsIncrementalBarrier() const override { return barrierTracer; }
// Steal the contents of this weak cache.
Set stealContents() {
// This operation is not currently allowed while barriers are in place
// since it doesn't make sense to steal the contents while we are
// sweeping.
MOZ_ASSERT(!barrierTracer);
auto rval = std::move(set);
// Ensure set is in a specified (empty) state after the move
set.clear();
// Return set; no move to avoid invalidating NRVO.
return rval;
}
private:
static bool entryNeedsSweep(JSTracer* barrierTracer, const Entry& prior) {
Entry entry(prior);

View File

@ -165,6 +165,10 @@ struct GCPolicy<JS::Heap<T>> {
static bool traceWeak(JSTracer* trc, JS::Heap<T>* thingp) {
return !*thingp || js::gc::TraceWeakEdge(trc, thingp);
}
static bool needsSweep(JSTracer* trc, const JS::Heap<T>* thingp) {
T* thing = const_cast<T*>(thingp->unsafeAddress());
return thing && js::gc::EdgeNeedsSweepUnbarrieredSlow(thing);
}
};
// GCPolicy<UniquePtr<T>> forwards the contained pointer to GCPolicy<T>.
@ -255,6 +259,36 @@ struct GCPolicy<mozilla::Result<V, E>> {
static bool isValid(const mozilla::Result<V, E>& t) { return true; }
};
template <typename... Fs>
struct GCPolicy<std::tuple<Fs...>> {
using T = std::tuple<Fs...>;
static void trace(JSTracer* trc, T* tp, const char* name) {
traceFieldsFrom<0>(trc, *tp, name);
}
static bool isValid(const T& t) { return areFieldsValidFrom<0>(t); }
private:
template <size_t N>
static void traceFieldsFrom(JSTracer* trc, T& tuple, const char* name) {
if constexpr (N != std::tuple_size_v<T>) {
using F = std::tuple_element_t<N, T>;
GCPolicy<F>::trace(trc, &std::get<N>(tuple), name);
traceFieldsFrom<N + 1>(trc, tuple, name);
}
}
template <size_t N>
static bool areFieldsValidFrom(const T& tuple) {
if constexpr (N != std::tuple_size_v<T>) {
using F = std::tuple_element_t<N, T>;
return GCPolicy<F>::isValid(std::get<N>(tuple)) &&
areFieldsValidFrom<N + 1>(tuple);
}
return true;
}
};
} // namespace JS
#endif // GCPolicyAPI_h

View File

@ -160,7 +160,7 @@ class GCVector {
}
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
return vector.sizeOfIncludingThis(mallocSizeOf);
return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
}
void trace(JSTracer* trc) {

View File

@ -25,8 +25,6 @@
/* These values are private to the JS engine. */
namespace js {
class NurseryDecommitTask;
JS_PUBLIC_API bool CurrentThreadCanAccessZone(JS::Zone* zone);
// To prevent false sharing, some data structures are aligned to a typical cache
@ -37,7 +35,7 @@ namespace gc {
class Arena;
struct Cell;
class TenuredChunk;
class ArenaChunk;
class StoreBuffer;
class TenuredCell;
@ -53,6 +51,7 @@ const size_t PageShift = 12;
// Expected page size, so we could initialze ArenasPerPage at compile-time.
// The actual system page size should be queried by SystemPageSize().
const size_t PageSize = size_t(1) << PageShift;
const size_t PageMask = PageSize - 1;
constexpr size_t ArenasPerPage = PageSize / ArenaSize;
const size_t ChunkShift = 20;
@ -84,7 +83,8 @@ const size_t ArenaBitmapWords = HowMany(ArenaBitmapBits, JS_BITS_PER_WORD);
enum class ChunkKind : uint8_t {
Invalid = 0,
TenuredHeap,
TenuredArenas,
MediumBuffers,
NurseryToSpace,
NurseryFromSpace
};
@ -97,13 +97,13 @@ class ChunkBase {
// Initialize a tenured heap chunk.
explicit ChunkBase(JSRuntime* rt) {
MOZ_ASSERT((uintptr_t(this) & ChunkMask) == 0);
initBaseForTenuredChunk(rt);
initBaseForArenaChunk(rt);
}
void initBaseForTenuredChunk(JSRuntime* rt) {
void initBaseForArenaChunk(JSRuntime* rt) {
runtime = rt;
storeBuffer = nullptr;
kind = ChunkKind::TenuredHeap;
kind = ChunkKind::TenuredArenas;
nurseryChunkIndex = UINT8_MAX;
}
@ -113,20 +113,33 @@ class ChunkBase {
runtime(rt),
kind(kind),
nurseryChunkIndex(chunkIndex) {
MOZ_ASSERT(kind == ChunkKind::NurseryFromSpace ||
kind == ChunkKind::NurseryToSpace);
MOZ_ASSERT(isNurseryChunk());
MOZ_ASSERT((uintptr_t(this) & ChunkMask) == 0);
MOZ_ASSERT(storeBuffer);
}
ChunkBase(JSRuntime* rt, ChunkKind kind)
: storeBuffer(nullptr),
runtime(rt),
kind(kind),
nurseryChunkIndex(UINT8_MAX) {}
public:
ChunkKind getKind() const {
MOZ_ASSERT_IF(storeBuffer, kind == ChunkKind::NurseryToSpace ||
kind == ChunkKind::NurseryFromSpace);
MOZ_ASSERT_IF(!storeBuffer, kind == ChunkKind::TenuredHeap);
MOZ_ASSERT_IF(storeBuffer, isNurseryChunk());
MOZ_ASSERT_IF(!storeBuffer, isTenuredChunk());
return kind;
}
bool isNurseryChunk() const {
return kind == ChunkKind::NurseryToSpace ||
kind == ChunkKind::NurseryFromSpace;
}
bool isTenuredChunk() const {
return kind == ChunkKind::TenuredArenas || kind == ChunkKind::MediumBuffers;
}
// The store buffer for pointers from tenured things to things in this
// chunk. Will be non-null if and only if this is a nursery chunk.
StoreBuffer* storeBuffer;
@ -139,12 +152,12 @@ class ChunkBase {
uint8_t nurseryChunkIndex;
};
// Information about tenured heap chunks.
struct TenuredChunkInfo {
// Information about tenured heap chunks containing arenas.
struct ArenaChunkInfo {
private:
friend class ChunkPool;
TenuredChunk* next = nullptr;
TenuredChunk* prev = nullptr;
ArenaChunk* next = nullptr;
ArenaChunk* prev = nullptr;
public:
/* Number of free arenas, either committed or decommitted. */
@ -152,6 +165,9 @@ struct TenuredChunkInfo {
/* Number of free, committed arenas. */
uint32_t numArenasFreeCommitted;
/* Whether this chunk is the chunk currently being allocated from. */
bool isCurrentChunk = false;
};
/*
@ -180,7 +196,7 @@ const size_t BitsPerPageWithHeaders =
(ArenaSize + ArenaBitmapBytes) * ArenasPerPage * CHAR_BIT + ArenasPerPage +
1;
const size_t ChunkBitsAvailable =
(ChunkSize - sizeof(ChunkBase) - sizeof(TenuredChunkInfo)) * CHAR_BIT;
(ChunkSize - sizeof(ChunkBase) - sizeof(ArenaChunkInfo)) * CHAR_BIT;
const size_t PagesPerChunk = ChunkBitsAvailable / BitsPerPageWithHeaders;
const size_t ArenasPerChunk = PagesPerChunk * ArenasPerPage;
const size_t FreeCommittedBits = ArenasPerChunk;
@ -190,7 +206,7 @@ const size_t BitsPerArenaWithHeaders =
(DecommitBits / ArenasPerChunk) + 1;
const size_t CalculatedChunkSizeRequired =
sizeof(ChunkBase) + sizeof(TenuredChunkInfo) +
sizeof(ChunkBase) + sizeof(ArenaChunkInfo) +
RoundUp(ArenasPerChunk * ArenaBitmapBytes, sizeof(uintptr_t)) +
RoundUp(FreeCommittedBits, sizeof(uint32_t) * CHAR_BIT) / CHAR_BIT +
RoundUp(DecommitBits, sizeof(uint32_t) * CHAR_BIT) / CHAR_BIT +
@ -205,10 +221,13 @@ static_assert(CalculatedChunkPadSize * CHAR_BIT < BitsPerArenaWithHeaders,
static_assert(ArenasPerChunk == 252,
"Do not accidentally change our heap's density.");
const size_t FirstArenaOffset = ChunkSize - ArenasPerChunk * ArenaSize;
// Mark bitmaps are atomic because they can be written by gray unmarking on the
// main thread while read by sweeping on a background thread. The former does
// not affect the result of the latter.
using MarkBitmapWord = mozilla::Atomic<uintptr_t, mozilla::Relaxed>;
static constexpr size_t MarkBitmapWordBits = sizeof(MarkBitmapWord) * CHAR_BIT;
/*
* Live objects are marked black or gray. Everything reachable from a JS root is
@ -227,30 +246,77 @@ enum class ColorBit : uint32_t { BlackBit = 0, GrayOrBlackBit = 1 };
enum class MarkColor : uint8_t { Gray = 1, Black = 2 };
// Mark bitmap for a tenured heap chunk.
struct alignas(TypicalCacheLineSize) MarkBitmap {
static constexpr size_t WordCount = ArenaBitmapWords * ArenasPerChunk;
template <size_t BytesPerMarkBit, size_t FirstThingOffset>
class alignas(TypicalCacheLineSize) MarkBitmap {
static constexpr size_t ByteCount =
(ChunkSize - FirstThingOffset) / BytesPerMarkBit;
static constexpr size_t WordCount = HowMany(ByteCount, MarkBitmapWordBits);
MarkBitmapWord bitmap[WordCount];
inline void getMarkWordAndMask(const TenuredCell* cell, ColorBit colorBit,
MarkBitmapWord** wordp, uintptr_t* maskp);
public:
static constexpr size_t FirstThingAdjustmentBits =
FirstThingOffset / BytesPerMarkBit;
static constexpr size_t FirstThingAdjustmentWords =
FirstThingAdjustmentBits / MarkBitmapWordBits;
MOZ_ALWAYS_INLINE void getMarkWordAndMask(const void* cell, ColorBit colorBit,
MarkBitmapWord** wordp,
uintptr_t* maskp) {
// Note: the JIT pre-barrier trampolines inline this code. Update
// MacroAssembler::emitPreBarrierFastPath code too when making changes here!
MOZ_ASSERT(size_t(colorBit) < MarkBitsPerCell);
size_t offset = uintptr_t(cell) & ChunkMask;
MOZ_ASSERT(offset >= FirstThingOffset);
const size_t bit = offset / BytesPerMarkBit + size_t(colorBit);
size_t word = bit / MarkBitmapWordBits - FirstThingAdjustmentWords;
MOZ_ASSERT(word < WordCount);
*wordp = &bitmap[word];
*maskp = uintptr_t(1) << (bit % MarkBitmapWordBits);
}
// The following are not exported and are defined in gc/Heap.h:
inline bool markBit(const TenuredCell* cell, ColorBit colorBit);
inline bool isMarkedAny(const TenuredCell* cell);
inline bool isMarkedBlack(const TenuredCell* cell);
inline bool isMarkedGray(const TenuredCell* cell);
inline bool markIfUnmarked(const TenuredCell* cell, MarkColor color);
inline bool markIfUnmarkedAtomic(const TenuredCell* cell, MarkColor color);
inline void markBlack(const TenuredCell* cell);
inline void markBlackAtomic(const TenuredCell* cell);
MOZ_ALWAYS_INLINE bool markBit(const void* cell, ColorBit colorBit) {
MarkBitmapWord* word;
uintptr_t mask;
getMarkWordAndMask(cell, colorBit, &word, &mask);
return *word & mask;
}
MOZ_ALWAYS_INLINE bool isMarkedAny(const void* cell) {
return markBit(cell, ColorBit::BlackBit) ||
markBit(cell, ColorBit::GrayOrBlackBit);
}
MOZ_ALWAYS_INLINE bool isMarkedBlack(const void* cell) {
// Return true if BlackBit is set.
return markBit(cell, ColorBit::BlackBit);
}
MOZ_ALWAYS_INLINE bool isMarkedGray(const void* cell) {
// Return true if GrayOrBlackBit is set and BlackBit is not set.
return !markBit(cell, ColorBit::BlackBit) &&
markBit(cell, ColorBit::GrayOrBlackBit);
}
inline bool markIfUnmarked(const void* cell, MarkColor color);
inline bool markIfUnmarkedThreadSafe(const void* cell, MarkColor color);
inline void markBlack(const void* cell);
inline void markBlackAtomic(const void* cell);
inline void copyMarkBit(TenuredCell* dst, const TenuredCell* src,
ColorBit colorBit);
inline void unmark(const TenuredCell* cell);
inline void unmark(const void* cell);
inline void unmarkOneBit(const void* cell, ColorBit colorBit);
inline MarkBitmapWord* arenaBits(Arena* arena);
inline void copyFrom(const MarkBitmap& other);
inline void clear();
};
static_assert(ArenaBitmapBytes * ArenasPerChunk == sizeof(MarkBitmap),
"Ensure our MarkBitmap actually covers all arenas.");
using ChunkMarkBitmap = MarkBitmap<CellBytesPerMarkBit, FirstArenaOffset>;
// Bitmap with one bit per page used for decommitted page set.
using ChunkPageBitmap = mozilla::BitSet<PagesPerChunk, uint32_t>;
@ -258,21 +324,26 @@ using ChunkPageBitmap = mozilla::BitSet<PagesPerChunk, uint32_t>;
// Bitmap with one bit per arena used for free committed arena set.
using ChunkArenaBitmap = mozilla::BitSet<ArenasPerChunk, uint32_t>;
// Base class containing data members for a tenured heap chunk.
class TenuredChunkBase : public ChunkBase {
// Base class for a tenured heap chunk containing fixed size arenas.
class ArenaChunkBase : public ChunkBase {
public:
TenuredChunkInfo info;
MarkBitmap markBits;
ArenaChunkInfo info;
ChunkMarkBitmap markBits;
ChunkArenaBitmap freeCommittedArenas;
ChunkPageBitmap decommittedPages;
protected:
explicit TenuredChunkBase(JSRuntime* runtime) : ChunkBase(runtime) {
explicit ArenaChunkBase(JSRuntime* runtime) : ChunkBase(runtime) {
static_assert(sizeof(markBits) == ArenaBitmapBytes * ArenasPerChunk,
"Ensure our MarkBitmap actually covers all arenas.");
info.numArenasFree = ArenasPerChunk;
}
void initAsCommitted();
void initAsDecommitted();
};
static_assert(FirstArenaOffset ==
RoundUp(sizeof(gc::ArenaChunkBase), ArenaSize));
/*
* We sometimes use an index to refer to a cell in an arena. The index for a
@ -282,17 +353,8 @@ class TenuredChunkBase : public ChunkBase {
const size_t ArenaCellIndexBytes = CellAlignBytes;
const size_t MaxArenaCellIndex = ArenaSize / CellAlignBytes;
const size_t MarkBitmapWordBits = sizeof(MarkBitmapWord) * CHAR_BIT;
constexpr size_t FirstArenaAdjustmentBits =
RoundUp(sizeof(gc::TenuredChunkBase), ArenaSize) / gc::CellBytesPerMarkBit;
static_assert((FirstArenaAdjustmentBits % MarkBitmapWordBits) == 0);
constexpr size_t FirstArenaAdjustmentWords =
FirstArenaAdjustmentBits / MarkBitmapWordBits;
const size_t ChunkStoreBufferOffset = offsetof(ChunkBase, storeBuffer);
const size_t ChunkMarkBitmapOffset = offsetof(TenuredChunkBase, markBits);
const size_t ChunkMarkBitmapOffset = offsetof(ArenaChunkBase, markBits);
// Hardcoded offsets into Arena class.
const size_t ArenaZoneOffset = 2 * sizeof(uint32_t);
@ -428,6 +490,9 @@ class JS_PUBLIC_API GCCellPtr {
return asCell();
}
bool operator==(const GCCellPtr other) const { return ptr == other.ptr; }
bool operator!=(const GCCellPtr other) const { return ptr != other.ptr; }
// Simplify checks to the kind.
template <typename T, typename = std::enable_if_t<JS::IsBaseTraceType_v<T>>>
bool is() const {
@ -518,55 +583,31 @@ void ApplyGCThingTyped(GCCellPtr thing, F&& f) {
} /* namespace JS */
// These are defined in the toplevel namespace instead of within JS so that
// they won't shadow other operator== overloads (see bug 1456512.)
inline bool operator==(JS::GCCellPtr ptr1, JS::GCCellPtr ptr2) {
return ptr1.asCell() == ptr2.asCell();
}
inline bool operator!=(JS::GCCellPtr ptr1, JS::GCCellPtr ptr2) {
return !(ptr1 == ptr2);
}
namespace js {
namespace gc {
/* static */
MOZ_ALWAYS_INLINE void MarkBitmap::getMarkWordAndMask(const TenuredCell* cell,
ColorBit colorBit,
MarkBitmapWord** wordp,
uintptr_t* maskp) {
// Note: the JIT pre-barrier trampolines inline this code. Update
// MacroAssembler::emitPreBarrierFastPath code too when making changes here!
MOZ_ASSERT(size_t(colorBit) < MarkBitsPerCell);
size_t offset = uintptr_t(cell) & ChunkMask;
const size_t bit = offset / CellBytesPerMarkBit + size_t(colorBit);
size_t word = bit / MarkBitmapWordBits - FirstArenaAdjustmentWords;
MOZ_ASSERT(word < WordCount);
*wordp = &bitmap[word];
*maskp = uintptr_t(1) << (bit % MarkBitmapWordBits);
}
namespace detail {
static MOZ_ALWAYS_INLINE ChunkBase* GetCellChunkBase(const Cell* cell) {
MOZ_ASSERT(cell);
auto* chunk = reinterpret_cast<ChunkBase*>(uintptr_t(cell) & ~ChunkMask);
// `addr` must be an address within GC-controlled memory. Note that it cannot
// point just past GC-controlled memory.
static MOZ_ALWAYS_INLINE ChunkBase* GetGCAddressChunkBase(const void* addr) {
MOZ_ASSERT(addr);
auto* chunk = reinterpret_cast<ChunkBase*>(uintptr_t(addr) & ~ChunkMask);
MOZ_ASSERT(chunk->runtime);
MOZ_ASSERT(chunk->kind != ChunkKind::Invalid);
return chunk;
}
static MOZ_ALWAYS_INLINE TenuredChunkBase* GetCellChunkBase(
static MOZ_ALWAYS_INLINE ChunkBase* GetCellChunkBase(const Cell* cell) {
return GetGCAddressChunkBase(cell);
}
static MOZ_ALWAYS_INLINE ArenaChunkBase* GetCellChunkBase(
const TenuredCell* cell) {
MOZ_ASSERT(cell);
auto* chunk =
reinterpret_cast<TenuredChunkBase*>(uintptr_t(cell) & ~ChunkMask);
auto* chunk = reinterpret_cast<ArenaChunkBase*>(uintptr_t(cell) & ~ChunkMask);
MOZ_ASSERT(chunk->runtime);
MOZ_ASSERT(chunk->kind == ChunkKind::TenuredHeap);
MOZ_ASSERT(chunk->kind == ChunkKind::TenuredArenas);
return chunk;
}
@ -580,17 +621,11 @@ static MOZ_ALWAYS_INLINE JS::Zone* GetTenuredGCThingZone(const void* ptr) {
static MOZ_ALWAYS_INLINE bool TenuredCellIsMarkedBlack(
const TenuredCell* cell) {
// Return true if BlackBit is set.
MOZ_ASSERT(cell);
MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
MarkBitmapWord* blackWord;
uintptr_t blackMask;
TenuredChunkBase* chunk = GetCellChunkBase(cell);
chunk->markBits.getMarkWordAndMask(cell, js::gc::ColorBit::BlackBit,
&blackWord, &blackMask);
return *blackWord & blackMask;
ArenaChunkBase* chunk = GetCellChunkBase(cell);
return chunk->markBits.isMarkedBlack(cell);
}
static MOZ_ALWAYS_INLINE bool NonBlackCellIsMarkedGray(
@ -601,16 +636,15 @@ static MOZ_ALWAYS_INLINE bool NonBlackCellIsMarkedGray(
MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
MOZ_ASSERT(!TenuredCellIsMarkedBlack(cell));
MarkBitmapWord* grayWord;
uintptr_t grayMask;
TenuredChunkBase* chunk = GetCellChunkBase(cell);
chunk->markBits.getMarkWordAndMask(cell, js::gc::ColorBit::GrayOrBlackBit,
&grayWord, &grayMask);
return *grayWord & grayMask;
ArenaChunkBase* chunk = GetCellChunkBase(cell);
return chunk->markBits.markBit(cell, ColorBit::GrayOrBlackBit);
}
static MOZ_ALWAYS_INLINE bool TenuredCellIsMarkedGray(const TenuredCell* cell) {
return !TenuredCellIsMarkedBlack(cell) && NonBlackCellIsMarkedGray(cell);
MOZ_ASSERT(cell);
MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
ArenaChunkBase* chunk = GetCellChunkBase(cell);
return chunk->markBits.isMarkedGray(cell);
}
static MOZ_ALWAYS_INLINE bool CellIsMarkedGray(const Cell* cell) {
@ -631,15 +665,15 @@ extern JS_PUBLIC_API void AssertCellIsNotGray(const Cell* cell);
extern JS_PUBLIC_API bool ObjectIsMarkedBlack(const JSObject* obj);
#endif
MOZ_ALWAYS_INLINE bool CellHasStoreBuffer(const Cell* cell) {
return GetCellChunkBase(cell)->storeBuffer;
MOZ_ALWAYS_INLINE bool ChunkPtrHasStoreBuffer(const void* ptr) {
return GetGCAddressChunkBase(ptr)->storeBuffer;
}
} /* namespace detail */
MOZ_ALWAYS_INLINE bool IsInsideNursery(const Cell* cell) {
MOZ_ASSERT(cell);
return detail::CellHasStoreBuffer(cell);
return detail::ChunkPtrHasStoreBuffer(cell);
}
MOZ_ALWAYS_INLINE bool IsInsideNursery(const TenuredCell* cell) {
@ -749,14 +783,6 @@ static MOZ_ALWAYS_INLINE bool GCThingIsMarkedGrayInCC(GCCellPtr thing) {
extern JS_PUBLIC_API JS::TraceKind GCThingTraceKind(void* thing);
extern JS_PUBLIC_API void EnableNurseryStrings(JSContext* cx);
extern JS_PUBLIC_API void DisableNurseryStrings(JSContext* cx);
extern JS_PUBLIC_API void EnableNurseryBigInts(JSContext* cx);
extern JS_PUBLIC_API void DisableNurseryBigInts(JSContext* cx);
/*
* Returns true when writes to GC thing pointers (and reads from weak pointers)
* must call an incremental barrier. This is generally only true when running
@ -860,6 +886,16 @@ static MOZ_ALWAYS_INLINE bool EdgeNeedsSweepUnbarriered(JSObject** objp) {
return EdgeNeedsSweepUnbarrieredSlow(objp);
}
/*
* Sample data about internally mapped memory. This includes all GC heap
* allocations (and excludes js_alloc allocations).
*/
struct ProfilerMemoryCounts {
size_t bytes = 0;
uint64_t operations = 0;
};
JS_PUBLIC_API ProfilerMemoryCounts GetProfilerMemoryCounts();
} // namespace gc
} // namespace js

View File

@ -32,6 +32,10 @@ extern JS_PUBLIC_API void SetHelperThreadTaskCallback(
// Function to call from external thread pool to run a helper thread task.
extern JS_PUBLIC_API void RunHelperThreadTask(HelperThreadTask* task);
// Function to get the name of the helper thread task.
extern JS_PUBLIC_API const char* GetHelperThreadTaskName(
HelperThreadTask* task);
} // namespace JS
#endif // js_HelperThreadAPI_h

View File

@ -199,7 +199,7 @@ class PropertyKey {
MOZ_ALWAYS_INLINE bool isAtom(JSAtom* atom) const {
MOZ_ASSERT(PropertyKey::isNonIntAtom(atom));
return isAtom() && toAtom() == atom;
return *this == NonIntAtom(atom);
}
MOZ_ALWAYS_INLINE JSAtom* toAtom() const {
@ -292,6 +292,15 @@ struct BarrierMethods<jsid> {
}
return nullptr;
}
static void writeBarriers(jsid* idp, jsid prev, jsid next) {
if (prev.isString()) {
JS::IncrementalPreWriteBarrier(JS::GCCellPtr(prev.toString()));
}
if (prev.isSymbol()) {
JS::IncrementalPreWriteBarrier(JS::GCCellPtr(prev.toSymbol()));
}
postWriteBarrier(idp, prev, next);
}
static void postWriteBarrier(jsid* idp, jsid prev, jsid next) {
MOZ_ASSERT_IF(next.isString(), !gc::IsInsideNursery(next.toString()));
}

View File

@ -118,7 +118,6 @@ inline bool JS_IsInitialized(void) {
namespace JS {
// Reference to a sequence of bytes.
// TODO: This type should be Span<cont uint8_t> (Bug 1709135)
using SelfHostedCache = mozilla::Span<const uint8_t>;
// Callback function used to copy the SelfHosted content to memory or to disk.

View File

@ -26,12 +26,19 @@ using JSONWriteCallback = bool (*)(const char16_t* buf, uint32_t len,
*
* In cases where JSON.stringify would return undefined, this function calls
* |callback| with the string "null".
*
* If a length hint is passed, space will be reserved for at least that many
* characters.
*/
extern JS_PUBLIC_API bool JS_Stringify(JSContext* cx,
JS::MutableHandle<JS::Value> value,
JS::Handle<JSObject*> replacer,
JS::Handle<JS::Value> space,
JSONWriteCallback callback, void* data);
extern JS_PUBLIC_API bool JS_StringifyWithLengthHint(
JSContext* cx, JS::MutableHandle<JS::Value> value,
JS::Handle<JSObject*> replacer, JS::Handle<JS::Value> space,
JSONWriteCallback callback, void* data, size_t lengthHint);
namespace JS {

View File

@ -1,97 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/* SpiderMonkey API for obtaining JitCode information. */
#ifndef js_JitCodeAPI_h
#define js_JitCodeAPI_h
#include "js/AllocPolicy.h"
#include "js/ColumnNumber.h" // JS::LimitedColumnNumberOneOrigin
#include "js/Initialization.h"
#include "js/Printf.h"
#include "js/Vector.h"
namespace JS {
enum class JitTier { Baseline, IC, Ion, Other };
class JitOpcodeDictionary {
typedef js::Vector<UniqueChars, 0, js::SystemAllocPolicy> StringVector;
public:
JitOpcodeDictionary();
StringVector& GetBaselineDictionary() { return baselineDictionary; }
StringVector& GetIonDictionary() { return ionDictionary; }
StringVector& GetInlineCacheDictionary() { return icDictionary; }
private:
StringVector baselineDictionary;
StringVector icDictionary;
StringVector ionDictionary;
};
struct JitCodeSourceInfo {
UniqueChars filename;
uint32_t offset = 0;
// Line number (1-origin).
uint32_t lineno = 0;
// Column number in UTF-16 code units.
JS::LimitedColumnNumberOneOrigin colno;
};
struct JitCodeIRInfo {
uint32_t offset = 0;
uint32_t opcode = 0;
UniqueChars str;
};
typedef js::Vector<JitCodeSourceInfo, 0, js::SystemAllocPolicy>
SourceInfoVector;
typedef js::Vector<JitCodeIRInfo, 0, js::SystemAllocPolicy> IRInfoVector;
struct JitCodeRecord {
UniqueChars functionName;
uint64_t code_addr = 0;
uint32_t instructionSize = 0;
JitTier tier = JitTier::Other;
SourceInfoVector sourceInfo;
IRInfoVector irInfo;
};
class JitCodeIterator {
void getDataForIndex(size_t iteratorIndex);
public:
JitCodeIterator();
~JitCodeIterator();
void operator++(int) {
iteratorIndex++;
getDataForIndex(iteratorIndex);
}
explicit operator bool() const { return data != nullptr; }
SourceInfoVector& sourceData() { return data->sourceInfo; }
IRInfoVector& irData() { return data->irInfo; }
const char* functionName() const { return data->functionName.get(); }
uint64_t code_addr() const { return data->code_addr; }
uint32_t instructionSize() { return data->instructionSize; }
JitTier jit_tier() const { return data->tier; }
private:
JitCodeRecord* data = nullptr;
size_t iteratorIndex = 0;
};
} // namespace JS
#endif /* js_JitCodeAPI_h */

View File

@ -31,6 +31,12 @@ extern JS_PUBLIC_API bool MapHas(JSContext* cx, HandleObject obj,
extern JS_PUBLIC_API bool MapSet(JSContext* cx, HandleObject obj,
HandleValue key, HandleValue val);
#ifdef NIGHTLY_BUILD
extern JS_PUBLIC_API bool MapGetOrInsert(JSContext* cx, HandleObject obj,
HandleValue key, HandleValue val,
MutableHandleValue rval);
#endif // #ifdef NIGHTLY_BUILD
extern JS_PUBLIC_API bool MapDelete(JSContext* cx, HandleObject obj,
HandleValue key, bool* rval);

View File

@ -187,7 +187,6 @@ struct ClassInfo {
MACRO(Objects, MallocHeap, objectsMallocHeapElementsNormal) \
MACRO(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \
MACRO(Objects, MallocHeap, objectsMallocHeapGlobalData) \
MACRO(Objects, MallocHeap, objectsMallocHeapGlobalVarNamesSet) \
MACRO(Objects, MallocHeap, objectsMallocHeapMisc) \
MACRO(Objects, NonHeap, objectsNonHeapElementsNormal) \
MACRO(Objects, NonHeap, objectsNonHeapElementsShared) \
@ -554,7 +553,8 @@ struct UnusedGCThingSizes {
MACRO(Other, GCHeapUnused, bigInt) \
MACRO(Other, GCHeapUnused, jitcode) \
MACRO(Other, GCHeapUnused, scope) \
MACRO(Other, GCHeapUnused, regExpShared)
MACRO(Other, GCHeapUnused, regExpShared) \
MACRO(Other, GCHeapUnused, smallBuffer)
UnusedGCThingSizes() = default;
UnusedGCThingSizes(UnusedGCThingSizes&& other) = default;
@ -597,6 +597,9 @@ struct UnusedGCThingSizes {
case JS::TraceKind::RegExpShared:
regExpShared += n;
break;
case JS::TraceKind::SmallBuffer:
smallBuffer += n;
break;
default:
MOZ_CRASH("Bad trace kind for UnusedGCThingSizes");
}
@ -625,6 +628,36 @@ struct UnusedGCThingSizes {
#undef FOR_EACH_SIZE
};
struct GCBufferStats {
#define FOR_EACH_SIZE(MACRO) \
MACRO(Other, MallocHeap, usedBytes) \
MACRO(Other, MallocHeap, freeBytes) \
MACRO(Other, MallocHeap, adminBytes)
GCBufferStats() = default;
GCBufferStats(GCBufferStats&& other) = default;
void addSizes(const GCBufferStats& other) { FOR_EACH_SIZE(ADD_OTHER_SIZE); }
size_t totalSize() const {
size_t n = 0;
FOR_EACH_SIZE(ADD_SIZE_TO_N);
return n;
}
void addToTabSizes(JS::TabSizes* sizes) const {
FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
}
void addToServoSizes(JS::ServoSizes* sizes) const {
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
}
FOR_EACH_SIZE(DECL_SIZE_ZERO);
#undef FOR_EACH_SIZE
};
struct ZoneStats {
#define FOR_EACH_SIZE(MACRO) \
MACRO(Other, GCHeapUsed, symbolsGCHeap) \
@ -642,6 +675,7 @@ struct ZoneStats {
MACRO(Other, MallocHeap, scopesMallocHeap) \
MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \
MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \
MACRO(Other, GCHeapUsed, smallBuffersGCHeap) \
MACRO(Other, MallocHeap, zoneObject) \
MACRO(Other, MallocHeap, regexpZone) \
MACRO(Other, MallocHeap, jitZone) \
@ -662,6 +696,7 @@ struct ZoneStats {
void addSizes(const ZoneStats& other) {
MOZ_ASSERT(isTotals);
FOR_EACH_SIZE(ADD_OTHER_SIZE);
gcBuffers.addSizes(other.gcBuffers);
unusedGCThings.addSizes(other.unusedGCThings);
stringInfo.add(other.stringInfo);
shapeInfo.add(other.shapeInfo);
@ -679,6 +714,7 @@ struct ZoneStats {
void addToTabSizes(JS::TabSizes* sizes) const {
MOZ_ASSERT(isTotals);
FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
gcBuffers.addToTabSizes(sizes);
unusedGCThings.addToTabSizes(sizes);
stringInfo.addToTabSizes(sizes);
shapeInfo.addToTabSizes(sizes);
@ -687,6 +723,7 @@ struct ZoneStats {
void addToServoSizes(JS::ServoSizes* sizes) const {
MOZ_ASSERT(isTotals);
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
gcBuffers.addToServoSizes(sizes);
unusedGCThings.addToServoSizes(sizes);
stringInfo.addToServoSizes(sizes);
shapeInfo.addToServoSizes(sizes);
@ -695,6 +732,8 @@ struct ZoneStats {
FOR_EACH_SIZE(DECL_SIZE_ZERO);
GCBufferStats gcBuffers;
// These string measurements are initially for all strings. At the end,
// if the measurement granularity is FineGrained, we subtract the
// measurements of the notable script sources and move them into

View File

@ -36,7 +36,15 @@ union Utf8Unit;
namespace JS {
enum class ModuleType : uint32_t { Unknown = 0, JavaScript, JSON };
// This enum is used to index into an array, and we assume that we have
// sequential numbers starting at zero for the unknown type.
enum class ModuleType : uint32_t {
Unknown = 0,
JavaScript,
JSON,
Limit = JSON,
};
/**
* The HostResolveImportedModule hook.
@ -179,6 +187,15 @@ extern JS_PUBLIC_API JSObject* CompileJsonModule(
JSContext* cx, const ReadOnlyCompileOptions& options,
SourceText<char16_t>& srcBuf);
/**
* Parse the given source buffer as a JSON module in the scope of the current
* global of cx and return a synthetic module record. An error is reported if a
* UTF-8 encoding error is encountered.
*/
extern JS_PUBLIC_API JSObject* CompileJsonModule(
JSContext* cx, const ReadOnlyCompileOptions& options,
SourceText<mozilla::Utf8Unit>& srcBuf);
/**
* Set a private value associated with a source text module record.
*/
@ -197,6 +214,11 @@ extern JS_PUBLIC_API void ClearModulePrivate(JSObject* module);
*/
extern JS_PUBLIC_API Value GetModulePrivate(JSObject* module);
/**
* Checks if the given module is a cyclic module.
*/
extern JS_PUBLIC_API bool IsCyclicModule(JSObject* module);
/*
* Perform the ModuleLink operation on the given source text module record.
*
@ -267,16 +289,28 @@ extern JS_PUBLIC_API void GetRequestedModuleSourcePos(
JSContext* cx, Handle<JSObject*> moduleRecord, uint32_t index,
uint32_t* lineNumber, JS::ColumnNumberOneOrigin* columnNumber);
/*
* Get the module type of a requested module.
*/
extern JS_PUBLIC_API ModuleType GetRequestedModuleType(
JSContext* cx, Handle<JSObject*> moduleRecord, uint32_t index);
/*
* Get the top-level script for a module which has not yet been executed.
*/
extern JS_PUBLIC_API JSScript* GetModuleScript(Handle<JSObject*> moduleRecord);
extern JS_PUBLIC_API JSObject* CreateModuleRequest(
JSContext* cx, Handle<JSString*> specifierArg);
JSContext* cx, Handle<JSString*> specifierArg, ModuleType moduleType);
extern JS_PUBLIC_API JSString* GetModuleRequestSpecifier(
JSContext* cx, Handle<JSObject*> moduleRequestArg);
/*
* Get the module type of the specified module request.
*/
extern JS_PUBLIC_API ModuleType
GetModuleRequestType(JSContext* cx, Handle<JSObject*> moduleRequestArg);
/*
* Get the module record for a module script.
*/

View File

@ -0,0 +1,52 @@
/* -*- 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 js_public_NativeStackLimit_h
#define js_public_NativeStackLimit_h
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include <stddef.h> // size_t
#include <stdint.h> // uint32_t, uintptr_t, UINTPTR_MAX
#include <utility> // std::move
namespace JS {
using NativeStackSize = size_t;
using NativeStackBase = uintptr_t;
using NativeStackLimit = uintptr_t;
#if JS_STACK_GROWTH_DIRECTION > 0
constexpr NativeStackLimit NativeStackLimitMin = 0;
constexpr NativeStackLimit NativeStackLimitMax = UINTPTR_MAX;
#else
constexpr NativeStackLimit NativeStackLimitMin = UINTPTR_MAX;
constexpr NativeStackLimit NativeStackLimitMax = 0;
#endif
#ifdef __wasi__
// We build with the "stack-first" wasm-ld option, so the stack grows downward
// toward zero. Let's set a limit just a bit above this so that we catch an
// overflow before a Wasm trap occurs.
constexpr NativeStackLimit WASINativeStackLimit = 1024;
#endif // __wasi__
inline NativeStackLimit GetNativeStackLimit(NativeStackBase base,
NativeStackSize size) {
#if JS_STACK_GROWTH_DIRECTION > 0
MOZ_ASSERT(base <= size_t(-1) - size);
return base + size - 1;
#else // stack grows up
MOZ_ASSERT(base >= size);
return base - (size - 1);
#endif // stack grows down
}
} // namespace JS
#endif /* js_public_NativeStackLimit_h */

View File

@ -0,0 +1,72 @@
/* -*- 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 js_public_ObjectWithStashedPointer_h
#define js_public_ObjectWithStashedPointer_h
#include "jstypes.h" // JS_PUBLIC_API
#include "js/RootingAPI.h" // JS::Handle
struct JS_PUBLIC_API JSContext;
class JS_PUBLIC_API JSObject;
namespace JS {
namespace detail {
using UntypedFreeFunction = void (*)(void*);
extern JS_PUBLIC_API JSObject* NewObjectWithUntypedStashedPointer(
JSContext* cx, void* ptr, UntypedFreeFunction freeFunc);
extern JS_PUBLIC_API void* ObjectGetUntypedStashedPointer(JSContext* cx,
JSObject* obj);
} // namespace detail
/**
* Convenience function for creating a JS object that has an embedder C++
* pointer stashed in it. The JS object assumes ownership of the pointer. When
* the JS object is finalized, freeFunc will be called on the pointer to free
* it.
*
* The pointer is not known to the garbage collector, and not traced. If it
* points to a GC thing, the embedder is responsible for tracing it manually.
*
* freeFunc must not call any JSAPI functions that could cause a garbage
* collection.
*/
template <typename T, typename F>
inline JSObject* NewObjectWithStashedPointer(JSContext* cx, T* ptr,
F freeFunc) {
using FreeFunction = void (*)(T*);
static_assert(std::is_convertible_v<F, FreeFunction>,
"free function is not of a compatible type");
return detail::NewObjectWithUntypedStashedPointer(
cx, ptr,
reinterpret_cast<detail::UntypedFreeFunction>(
static_cast<FreeFunction>(freeFunc)));
}
/**
* As above, but without a free function for the pointer.
*/
template <typename T>
inline JSObject* NewObjectWithStashedPointer(JSContext* cx, T* ptr) {
return detail::NewObjectWithUntypedStashedPointer(cx, ptr, nullptr);
}
/**
* Retrieve the stashed pointer from an object created using
* NewObjectWithStashedPointer().
*/
template <typename T>
inline T* ObjectGetStashedPointer(JSContext* cx, JSObject* obj) {
return static_cast<T*>(detail::ObjectGetUntypedStashedPointer(cx, obj));
}
} // namespace JS
#endif // js_public_ObjectWithStashedPointer_h

View File

@ -121,26 +121,6 @@ class Prefs {
};
/**
* Specification for whether weak refs should be enabled and if so whether the
* FinalizationRegistry.cleanupSome method should be present.
*/
enum class WeakRefSpecifier {
Disabled,
EnabledWithCleanupSome,
EnabledWithoutCleanupSome
};
inline WeakRefSpecifier GetWeakRefsEnabled() {
if (!Prefs::weakrefs()) {
return WeakRefSpecifier::Disabled;
}
if (Prefs::experimental_weakrefs_expose_cleanupSome()) {
return WeakRefSpecifier::EnabledWithCleanupSome;
}
return WeakRefSpecifier::EnabledWithoutCleanupSome;
}
}; // namespace JS
#endif /* js_Prefs_h */

View File

@ -26,12 +26,21 @@ struct JSPrincipals {
#ifdef JS_DEBUG
/* A helper to facilitate principals debugging. */
uint32_t debugToken;
uint32_t debugToken = 0;
#endif
JSPrincipals() = default;
void setDebugToken(uint32_t token) {
struct RefCount {
const int32_t value;
constexpr explicit RefCount(int32_t value) : value(value) {}
RefCount(const RefCount&) = delete;
};
/* Initialize a JSPrincipals with the given refcount in a constexpr-compatible
* way. */
explicit constexpr JSPrincipals(RefCount c) : refcount{c.value} {}
void setDebugToken(int32_t token) {
#ifdef JS_DEBUG
debugToken = token;
#endif
@ -68,23 +77,54 @@ typedef bool (*JSSubsumesOp)(JSPrincipals* first, JSPrincipals* second);
namespace JS {
enum class RuntimeCode { JS, WASM };
enum class CompilationType { DirectEval, IndirectEval, Function, Undefined };
} // namespace JS
/*
* Used to check if a CSP instance wants to disable eval() and friends.
* See JSContext::isRuntimeCodeGenEnabled() in vm/JSContext.cpp.
*
* `code` is the JavaScript source code passed to eval/Function, but nullptr
* for Wasm.
* codeString, compilationType, parameterStrings, bodyString, parameterArgs,
* and bodyArg are defined in the "Dynamic Code Brand Checks" spec
* (see https://tc39.es/proposal-dynamic-code-brand-checks).
*
* Returning `false` from this callback will prevent the execution/compilation
* of the code.
* An Undefined compilationType is used for cases that are not covered by that
* spec and unused parameters are null/empty. Currently, this includes Wasm
* (only check if compilation is enabled) and ShadowRealmEval (only check
* codeString).
*
* `outCanCompileStrings` is set to false if this callback prevents the
* execution/compilation of the code and to true otherwise.
*
* Return false on failure, true on success. The |outCanCompileStrings|
* parameter should not be modified in case of failure.
*/
typedef bool (*JSCSPEvalChecker)(JSContext* cx, JS::RuntimeCode kind,
JS::HandleString code);
typedef bool (*JSCSPEvalChecker)(
JSContext* cx, JS::RuntimeCode kind, JS::Handle<JSString*> codeString,
JS::CompilationType compilationType,
JS::Handle<JS::StackGCVector<JSString*>> parameterStrings,
JS::Handle<JSString*> bodyString,
JS::Handle<JS::StackGCVector<JS::Value>> parameterArgs,
JS::Handle<JS::Value> bodyArg, bool* outCanCompileStrings);
/*
* Provide a string of code from an Object argument, to be used by eval.
* See JSContext::getCodeForEval() in vm/JSContext.cpp as well as
* https://tc39.es/proposal-dynamic-code-brand-checks/#sec-hostgetcodeforeval
*
* `code` is the JavaScript object passed by the user.
* `outCode` is the JavaScript string to be actually executed, with nullptr
* meaning NO-CODE.
*
* Return false on failure, true on success. The |outCode| parameter should not
* be modified in case of failure.
*/
typedef bool (*JSCodeForEvalOp)(JSContext* cx, JS::HandleObject code,
JS::MutableHandle<JSString*> outCode);
struct JSSecurityCallbacks {
JSCSPEvalChecker contentSecurityPolicyAllows;
JSCodeForEvalOp codeForEvalGets;
JSSubsumesOp subsumes;
};

View File

@ -10,6 +10,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/glue/Debug.h"
#include "mozilla/Range.h"
#include "mozilla/Vector.h"
#include <stdarg.h>
#include <stddef.h>
@ -139,7 +140,7 @@ class LifoAlloc;
// of chunks allocated with a LifoAlloc.
class JS_PUBLIC_API GenericPrinter {
protected:
bool hadOOM_; // whether reportOutOfMemory() has been called.
bool hadOOM_; // whether setPendingOutOfMemory() has been called.
constexpr GenericPrinter() : hadOOM_(false) {}
@ -151,6 +152,7 @@ class JS_PUBLIC_API GenericPrinter {
// still report any of the previous errors.
virtual void put(const char* s, size_t len) = 0;
inline void put(const char* s) { put(s, strlen(s)); }
inline void put(mozilla::Span<const char> s) { put(s.data(), s.size()); };
// Put a mozilla::Span / mozilla::Range of Latin1Char or char16_t characters
// in the output.
@ -202,11 +204,11 @@ class JS_PUBLIC_API GenericPrinter {
virtual size_t index() const { return 0; }
// In some printers, this ensure that the content is fully written.
virtual void flush() { /* Do nothing */
}
virtual void flush() { /* Do nothing */ }
// Report that a string operation failed to get the memory it requested.
virtual void reportOutOfMemory();
// Set a flag that a string operation failed to get the memory it requested.
// The pending out of memory error should be handled by the consumer.
virtual void setPendingOutOfMemory();
// Return true if this Sprinter ran out of memory.
virtual bool hadOutOfMemory() const { return hadOOM_; }
@ -469,7 +471,7 @@ class JS_PUBLIC_API EscapePrinter final : public GenericPrinter {
}
size_t index() const final { return out.index(); }
void flush() final { out.flush(); }
void reportOutOfMemory() final { out.reportOutOfMemory(); }
void setPendingOutOfMemory() final { out.setPendingOutOfMemory(); }
bool hadOutOfMemory() const final { return out.hadOutOfMemory(); }
};
@ -490,43 +492,118 @@ class JS_PUBLIC_API StringEscape {
void convertInto(GenericPrinter& out, char16_t c);
};
// A GenericPrinter that formats everything at a nested indentation level.
class JS_PUBLIC_API IndentedPrinter final : public GenericPrinter {
class JS_PUBLIC_API WATStringEscape {
public:
bool isSafeChar(char16_t c);
void convertInto(GenericPrinter& out, char16_t c);
};
// A GenericPrinter that can format its output in a structured way, with nice
// formatting.
//
// Suppose you want to print wasm structs, and you want to change the
// presentation depending on the number of fields:
//
// (struct)
// (struct (field i32))
// (struct
// (field i32)
// (field i64)
// )
//
// All three of these can be handled identically with quite straightforward
// code:
//
// out.printf("(struct");
// {
// StructuredPrinter::Scope _(out);
//
// for (auto field : fields) {
// out.brk(" ", "\n");
// out.printf("(field ");
// DumpFieldType(field.type, out);
// out.printf(")");
// }
// out.brk("", "\n");
//
// if (fields.length() > 1) {
// out.expand();
// }
// }
// out.printf(")");
//
// The `brk` method can be used to emit one of two "break" characters depending
// on whether the output is "expanded" or "collapsed". The decision about which
// style to emit is made later, by conditionally calling `out.expand()`.
// Additionally, the use of `StructuredPrinter::Scope` ensures that the struct
// fields are indented *if* the output is expanded.
//
// Newlines may still be printed at any time. Newlines will force the current
// scope to be expanded, along with any parent scopes.
class JS_PUBLIC_API StructuredPrinter final : public GenericPrinter {
GenericPrinter& out_;
// The number of indents to insert at the beginning of each line.
uint32_t indentLevel_;
// The number of spaces to insert for each indent.
uint32_t indentAmount_;
// Whether we have seen a line ending and should insert an indent at the
// next line fragment.
int indentAmount_;
bool pendingIndent_;
// Put an indent to `out_`
void putIndent();
// Put `s` to `out_`, inserting an indent if we need to
void putWithMaybeIndent(const char* s, size_t len);
// The index of the last expanded scope (or -1 if all scopes are collapsed).
int expandedDepth_ = -1;
public:
explicit IndentedPrinter(GenericPrinter& out, uint32_t indentLevel = 0,
uint32_t indentAmount = 2)
: out_(out),
indentLevel_(indentLevel),
indentAmount_(indentAmount),
pendingIndent_(false) {}
// Automatically insert and remove and indent for a scope
class AutoIndent {
IndentedPrinter& printer_;
public:
explicit AutoIndent(IndentedPrinter& printer) : printer_(printer) {
printer_.setIndentLevel(printer_.indentLevel() + 1);
}
~AutoIndent() { printer_.setIndentLevel(printer_.indentLevel() - 1); }
struct Break {
uint32_t bufferPos;
bool isCollapsed;
const char* collapsed;
const char* expanded;
};
uint32_t indentLevel() const { return indentLevel_; }
void setIndentLevel(uint32_t indentLevel) { indentLevel_ = indentLevel; }
struct ScopeInfo {
uint32_t startPos;
int indent;
};
// Content is buffered while in collapsed mode in case it gets expanded later.
mozilla::Vector<char, 80> buffer_;
// Info about break characters in the buffer.
// Cleared when the buffer is cleared.
mozilla::Vector<Break, 8> breaks_;
// The stack of scopes maintained by the printer.
mozilla::Vector<ScopeInfo, 16> scopes_;
int scopeDepth() { return int(scopes_.length()) - 1; }
void putIndent(int level = -1);
void putBreak(const Break& brk);
void putWithMaybeIndent(const char* s, size_t len, int level = -1);
public:
explicit StructuredPrinter(GenericPrinter& out, int indentAmount = 2)
: out_(out), indentAmount_(indentAmount) {
pushScope();
}
~StructuredPrinter() {
popScope();
flush();
}
void pushScope();
void popScope();
void brk(const char* collapsed, const char* expanded);
void expand();
bool isExpanded();
void flush() override;
class Scope {
StructuredPrinter& printer_;
public:
explicit Scope(StructuredPrinter& printer) : printer_(printer) {
printer_.pushScope();
}
~Scope() { printer_.popScope(); }
};
virtual void put(const char* s, size_t len) override;
using GenericPrinter::put; // pick up |inline void put(const char* s);|

View File

@ -55,7 +55,7 @@ class MOZ_NON_PARAM JS_PUBLIC_API ProfilingFrameIterator {
void* endStackAddress_ = nullptr;
Kind kind_;
static const unsigned StorageSpace = 8 * sizeof(void*);
static const unsigned StorageSpace = 9 * sizeof(void*);
alignas(void*) unsigned char storage_[StorageSpace];
void* storage() { return storage_; }
@ -136,6 +136,8 @@ class MOZ_NON_PARAM JS_PUBLIC_API ProfilingFrameIterator {
// - is weakly monotonically increasing (may be equal for successive frames)
// - will compare greater than newer native and psuedo-stack frame addresses
// and less than older native and psuedo-stack frame addresses
// The exception is at the point of stack switching between the main stack
// and a suspendable one (see WebAssembly JS Promise Integration proposal).
void* stackAddress() const;
enum FrameKind {

View File

@ -8,6 +8,8 @@
#define js_ProfilingStack_h
#include "mozilla/Atomics.h"
#include "mozilla/BaseProfilerMarkersPrerequisites.h"
#include "mozilla/TimeStamp.h"
#include <stdint.h>
@ -362,8 +364,10 @@ JS_PUBLIC_API void SetContextProfilingStack(JSContext* cx,
JS_PUBLIC_API void EnableContextProfilingStack(JSContext* cx, bool enabled);
JS_PUBLIC_API void RegisterContextProfilingEventMarker(JSContext* cx,
void (*fn)(const char*,
JS_PUBLIC_API void RegisterContextProfilingEventMarker(
JSContext* cx,
void (*mark)(mozilla::MarkerCategory, const char*, const char*),
void (*interval)(mozilla::MarkerCategory, const char*, mozilla::TimeStamp,
const char*));
} // namespace js

View File

@ -36,19 +36,36 @@ class JS_PUBLIC_API JobQueue {
virtual ~JobQueue() = default;
/**
* Ask the embedding for the incumbent global.
* Ask the embedding for the host defined data.
*
* SpiderMonkey doesn't itself have a notion of incumbent globals as defined
* This is the step 5 in
* https://html.spec.whatwg.org/multipage/webappapis.html#hostmakejobcallback
*
* SpiderMonkey doesn't itself have a notion of host defined data as defined
* by the HTML spec, so we need the embedding to provide this. See
* dom/script/ScriptSettings.h for details.
*
* If the embedding has the host defined data, this method should return the
* host defined data via the `data` out parameter and return `true`.
* The object in the `data` out parameter can belong to any compartment.
* If the embedding doesn't need the host defined data, this method should
* set the `data` out parameter to `nullptr` and return `true`.
* If any error happens while generating the host defined data, this method
* should set a pending exception to `cx` and return `false`.
*/
virtual JSObject* getIncumbentGlobal(JSContext* cx) = 0;
virtual bool getHostDefinedData(JSContext* cx,
JS::MutableHandle<JSObject*> data) const = 0;
/**
* Enqueue a reaction job `job` for `promise`, which was allocated at
* `allocationSite`. Provide `incumbentGlobal` as the incumbent global for
* `allocationSite`. Provide `hostDefineData` as the host defined data for
* the reaction job's execution.
*
* The `hostDefinedData` value comes from `getHostDefinedData` method.
* The object is unwrapped, and it can belong to a different compartment
* than the current compartment. It can be `nullptr` if `getHostDefinedData`
* returns `nullptr`.
*
* `promise` can be null if the promise is optimized out.
* `promise` is guaranteed not to be optimized out if the promise has
* non-default user-interaction flag.
@ -56,7 +73,7 @@ class JS_PUBLIC_API JobQueue {
virtual bool enqueuePromiseJob(JSContext* cx, JS::HandleObject promise,
JS::HandleObject job,
JS::HandleObject allocationSite,
JS::HandleObject incumbentGlobal) = 0;
JS::HandleObject hostDefinedData) = 0;
/**
* Run all jobs in the queue. Running one job may enqueue others; continue to
@ -546,27 +563,65 @@ extern JS_PUBLIC_API JSObject* GetWaitForAllPromise(
* on a JSContext thread when requested via DispatchToEventLoopCallback.
*/
class JS_PUBLIC_API Dispatchable {
protected:
// Dispatchables are created and destroyed by SpiderMonkey.
Dispatchable() = default;
public:
// Destruction of Dispatchables is public in order to be used with
// UniquePtrs. Their destruction by SpiderMonkey is enforced by
// ReleaseFailedTask.
virtual ~Dispatchable() = default;
public:
// ShuttingDown indicates that SpiderMonkey should abort async tasks to
// expedite shutdown.
enum MaybeShuttingDown { NotShuttingDown, ShuttingDown };
// Called by the embedding after DispatchToEventLoopCallback succeeds.
// Used to correctly release the unique ptr and call the run task.
static void Run(JSContext* cx, js::UniquePtr<Dispatchable>&& task,
MaybeShuttingDown maybeShuttingDown);
// Used to correctly release the unique ptr. Relies on the
// OffThreadRuntimePromiseState to handle cleanup via iteration over the
// live() set.
static void ReleaseFailedTask(js::UniquePtr<Dispatchable>&& task);
protected:
// Dispatchables are created exclusively by SpiderMonkey.
Dispatchable() = default;
// These two methods must be implemented in order to correctly handle
// success and failure cases for the task.
// Used to execute the task, run on the owning thread.
// A subclass should override this method to
// 1) execute the task as necessary and
// 2) delete the task.
virtual void run(JSContext* cx, MaybeShuttingDown maybeShuttingDown) = 0;
// Used to transfer the task back to the runtime if the embedding, upon
// taking ownership of the task, fails to dispatch and run it. This allows
// the runtime to delete the task during shutdown. This method can be called
// from any thread.
// Typically, this will be used with a UniquePtr like so:
// auto task = myTask.release();
// task->transferToRuntime();
virtual void transferToRuntime() = 0;
};
/**
* Callback to dispatch a JS::Dispatchable to a JSContext's thread's event loop.
* Callbacks to dispatch a JS::Dispatchable to a JSContext's thread's event
* loop.
*
* The DispatchToEventLoopCallback set on a particular JSContext must accept
* JS::Dispatchable instances and arrange for their `run` methods to be called
* eventually on the JSContext's thread. This is used for cross-thread dispatch,
* so the callback itself must be safe to call from any thread.
* so the callback itself must be safe to call from any thread. It cannot
* trigger a GC.
*
* The DelayedDispatchToEventLoopCallback in addition takes a delay, and it
* must accept JS::Dispatchable instances and arrange for their `run` methods
* to be called after the delay on the JSContext's thread.
* The embeddings must have its own timeout manager to handle the delay.
* If a timeout manager is not available for given context, it should return
* false, optionally with a warning message printed.
*
* If the callback returns `true`, it must eventually run the given
* Dispatchable; otherwise, SpiderMonkey may leak memory or hang.
@ -577,17 +632,21 @@ class JS_PUBLIC_API Dispatchable {
* all subsequently submitted runnables as well.
*
* To establish a DispatchToEventLoopCallback, the embedding may either call
* InitDispatchToEventLoop to provide its own, or call js::UseInternalJobQueues
* InitDispatchsToEventLoop to provide its own, or call js::UseInternalJobQueues
* to select a default implementation built into SpiderMonkey. This latter
* depends on the embedding to call js::RunJobs on the JavaScript thread to
* process queued Dispatchables at appropriate times.
*/
typedef bool (*DispatchToEventLoopCallback)(void* closure,
Dispatchable* dispatchable);
typedef bool (*DispatchToEventLoopCallback)(
void* closure, js::UniquePtr<Dispatchable>&& dispatchable);
extern JS_PUBLIC_API void InitDispatchToEventLoop(
JSContext* cx, DispatchToEventLoopCallback callback, void* closure);
typedef bool (*DelayedDispatchToEventLoopCallback)(
void* closure, js::UniquePtr<Dispatchable>&& dispatchable, uint32_t delay);
extern JS_PUBLIC_API void InitDispatchsToEventLoop(
JSContext* cx, DispatchToEventLoopCallback callback,
DelayedDispatchToEventLoopCallback delayedCallback, void* closure);
/**
* When a JSRuntime is destroyed it implicitly cancels all async tasks in

View File

@ -452,6 +452,6 @@ struct JSFunctionSpec {
#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \
JS_FNSPEC(::JS::SymbolCode::symbol, call, info, nargs, flags, selfHostedName)
#define JS_FNSPEC(name, call, info, nargs, flags, selfHostedName) \
{ JSFunctionSpec::Name(name), {call, info}, nargs, flags, selfHostedName }
{JSFunctionSpec::Name(name), {call, info}, nargs, flags, selfHostedName}
#endif // js_PropertySpec_h

View File

@ -41,12 +41,6 @@
# define IF_INTL(REAL, IMAGINARY) IMAGINARY
#endif
#ifdef JS_HAS_TEMPORAL_API
# define IF_TEMPORAL(REAL, IMAGINARY) REAL
#else
# define IF_TEMPORAL(REAL, IMAGINARY) IMAGINARY
#endif
#ifdef ENABLE_WASM_TYPE_REFLECTIONS
# define IF_WASM_TYPE(REAL, IMAGINARY) REAL
#else
@ -65,9 +59,8 @@
# define IF_NIGHTLY(REAL, IMAGINARY) IMAGINARY
#endif
#define JS_FOR_PROTOTYPES_(REAL, IMAGINARY, REAL_IF_INTL, REAL_IF_TEMPORAL, \
REAL_IF_WASM_TYPE, REAL_IF_WASM_JSPI, \
REAL_IF_NIGHTLY) \
#define JS_FOR_PROTOTYPES_(REAL, IMAGINARY, REAL_IF_INTL, REAL_IF_WASM_TYPE, \
REAL_IF_WASM_JSPI, REAL_IF_NIGHTLY) \
IMAGINARY(Null, dummy) \
REAL(Object, OCLASP(Plain)) \
REAL(Function, &FunctionClass) \
@ -86,6 +79,8 @@
REAL(EvalError, ERROR_CLASP(JSEXN_EVALERR)) \
REAL(RangeError, ERROR_CLASP(JSEXN_RANGEERR)) \
REAL(ReferenceError, ERROR_CLASP(JSEXN_REFERENCEERR)) \
IF_EXPLICIT_RESOURCE_MANAGEMENT( \
REAL(SuppressedError, ERROR_CLASP(JSEXN_SUPPRESSEDERR))) \
REAL(SyntaxError, ERROR_CLASP(JSEXN_SYNTAXERR)) \
REAL(TypeError, ERROR_CLASP(JSEXN_TYPEERR)) \
REAL(URIError, ERROR_CLASP(JSEXN_URIERR)) \
@ -93,6 +88,7 @@
REAL(CompileError, ERROR_CLASP(JSEXN_WASMCOMPILEERROR)) \
REAL(LinkError, ERROR_CLASP(JSEXN_WASMLINKERROR)) \
REAL(RuntimeError, ERROR_CLASP(JSEXN_WASMRUNTIMEERROR)) \
REAL_IF_WASM_JSPI(SuspendError, ERROR_CLASP(JSEXN_WASMSUSPENDERROR)) \
REAL(ArrayBuffer, OCLASP(FixedLengthArrayBuffer)) \
REAL(Int8Array, TYPED_ARRAY_CLASP(Int8)) \
REAL(Uint8Array, TYPED_ARRAY_CLASP(Uint8)) \
@ -105,7 +101,7 @@
REAL(Uint8ClampedArray, TYPED_ARRAY_CLASP(Uint8Clamped)) \
REAL(BigInt64Array, TYPED_ARRAY_CLASP(BigInt64)) \
REAL(BigUint64Array, TYPED_ARRAY_CLASP(BigUint64)) \
REAL_IF_NIGHTLY(Float16Array, TYPED_ARRAY_CLASP(Float16)) \
REAL(Float16Array, TYPED_ARRAY_CLASP(Float16)) \
REAL(BigInt, OCLASP(BigInt)) \
REAL(Proxy, CLASP(Proxy)) \
REAL(WeakMap, OCLASP(WeakMap)) \
@ -119,6 +115,7 @@
REAL_IF_INTL(Collator, OCLASP(Collator)) \
REAL_IF_INTL(DateTimeFormat, OCLASP(DateTimeFormat)) \
REAL_IF_INTL(DisplayNames, OCLASP(DisplayNames)) \
REAL_IF_INTL(DurationFormat, OCLASP(DurationFormat)) \
REAL_IF_INTL(ListFormat, OCLASP(ListFormat)) \
REAL_IF_INTL(Locale, OCLASP(Locale)) \
REAL_IF_INTL(NumberFormat, OCLASP(NumberFormat)) \
@ -148,25 +145,25 @@
REAL(WeakRef, OCLASP(WeakRef)) \
REAL(Iterator, OCLASP(Iterator)) \
REAL(AsyncIterator, OCLASP(AsyncIterator)) \
REAL_IF_TEMPORAL(Temporal, OCLASP(temporal::Temporal)) \
REAL_IF_TEMPORAL(Calendar, OCLASP(temporal::Calendar)) \
REAL_IF_TEMPORAL(Duration, OCLASP(temporal::Duration)) \
REAL_IF_TEMPORAL(Instant, OCLASP(temporal::Instant)) \
REAL_IF_TEMPORAL(PlainDate, OCLASP(temporal::PlainDate)) \
REAL_IF_TEMPORAL(PlainDateTime, OCLASP(temporal::PlainDateTime)) \
REAL_IF_TEMPORAL(PlainMonthDay, OCLASP(temporal::PlainMonthDay)) \
REAL_IF_TEMPORAL(PlainYearMonth, OCLASP(temporal::PlainYearMonth)) \
REAL_IF_TEMPORAL(PlainTime, OCLASP(temporal::PlainTime)) \
REAL_IF_TEMPORAL(TemporalNow, OCLASP(temporal::TemporalNow)) \
REAL_IF_TEMPORAL(TimeZone, OCLASP(temporal::TimeZone)) \
REAL_IF_TEMPORAL(ZonedDateTime, OCLASP(temporal::ZonedDateTime)) \
IF_RECORD_TUPLE(REAL(Record, (&RecordType::class_))) \
IF_RECORD_TUPLE(REAL(Tuple, (&TupleType::class_)))
IF_EXPLICIT_RESOURCE_MANAGEMENT( \
REAL(DisposableStack, OCLASP(DisposableStack))) \
IF_EXPLICIT_RESOURCE_MANAGEMENT( \
REAL(AsyncDisposableStack, OCLASP(AsyncDisposableStack))) \
REAL_IF_INTL(Temporal, OCLASP(temporal::Temporal)) \
REAL_IF_INTL(Duration, OCLASP(temporal::Duration)) \
REAL_IF_INTL(Instant, OCLASP(temporal::Instant)) \
REAL_IF_INTL(PlainDate, OCLASP(temporal::PlainDate)) \
REAL_IF_INTL(PlainDateTime, OCLASP(temporal::PlainDateTime)) \
REAL_IF_INTL(PlainMonthDay, OCLASP(temporal::PlainMonthDay)) \
REAL_IF_INTL(PlainYearMonth, OCLASP(temporal::PlainYearMonth)) \
REAL_IF_INTL(PlainTime, OCLASP(temporal::PlainTime)) \
REAL_IF_INTL(TemporalNow, OCLASP(temporal::TemporalNow)) \
REAL_IF_INTL(ZonedDateTime, OCLASP(temporal::ZonedDateTime))
#define JS_FOR_PROTOTYPES(REAL, IMAGINARY) \
JS_FOR_PROTOTYPES_( \
REAL, IMAGINARY, IF_INTL(REAL, IMAGINARY), IF_TEMPORAL(REAL, IMAGINARY), \
IF_WASM_TYPE(REAL, IMAGINARY), IF_WASM_JSPI(REAL, IMAGINARY), \
JS_FOR_PROTOTYPES_(REAL, IMAGINARY, IF_INTL(REAL, IMAGINARY), \
IF_WASM_TYPE(REAL, IMAGINARY), \
IF_WASM_JSPI(REAL, IMAGINARY), \
IF_NIGHTLY(REAL, IMAGINARY))
#define JS_FOR_EACH_PROTOTYPE(MACRO) JS_FOR_PROTOTYPES(MACRO, MACRO)

View File

@ -100,6 +100,10 @@ class JS_PUBLIC_API Wrapper;
* organized in the following hierarchy:
*
* BaseProxyHandler
* | |
* | NurseryAllocableProxyHandler
* | // allocated in the nursery; disallows
* | // overriding finalize method
* |
* ForwardingProxyHandler // has a target and forwards internal methods
* |
@ -378,6 +382,17 @@ class JS_PUBLIC_API BaseProxyHandler {
virtual bool isScripted() const { return false; }
};
class JS_PUBLIC_API NurseryAllocableProxyHandler : public BaseProxyHandler {
using BaseProxyHandler::BaseProxyHandler;
// Don't allow overriding the default finalize method.
void finalize(JS::GCContext* gcx, JSObject* proxy) const final {
BaseProxyHandler::finalize(gcx, proxy);
}
// Can allocate in the nursery as long as we use the default finalize method.
bool canNurseryAllocate() const override { return true; }
};
extern JS_PUBLIC_DATA const JSClass ProxyClass;
inline bool IsProxy(const JSObject* obj) {
@ -463,12 +478,12 @@ constexpr ptrdiff_t ProxyReservedSlots::offsetOfPrivateSlot() {
offsetof(ProxyValueArray, privateSlot);
}
// All proxies share the same data layout. Following the object's shape and
// type, the proxy has a ProxyDataLayout structure with a pointer to an array
// of values and the proxy's handler. This is designed both so that proxies can
// be easily swapped with other objects (via RemapWrapper) and to mimic the
// layout of other objects (proxies and other objects have the same size) so
// that common code can access either type of object.
// All proxies share the same data layout. Following the object's shape, the
// proxy has a ProxyDataLayout structure with a pointer to an array of values
// and the proxy's handler. This is designed both so that proxies can be easily
// swapped with other objects (via RemapWrapper) and to mimic the layout of
// other objects (proxies and other objects have the same size) so that common
// code can access either type of object.
//
// See GetReservedOrProxyPrivateSlot below.
struct ProxyDataLayout {
@ -554,9 +569,8 @@ inline void SetProxyReservedSlot(JSObject* obj, size_t n,
inline void SetProxyPrivate(JSObject* obj, const JS::Value& value) {
#ifdef DEBUG
if (gc::detail::ObjectIsMarkedBlack(obj)) {
JS::AssertObjectIsNotGray(obj);
JS::AssertValueIsNotGray(value);
}
#endif
JS::Value* vp = &detail::GetProxyDataLayout(obj)->values()->privateSlot;
@ -693,10 +707,9 @@ class JS_PUBLIC_API AutoWaivePolicy : public AutoEnterPolicy {
}
};
#else
class JS_PUBLIC_API AutoWaivePolicy {
public:
AutoWaivePolicy(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
BaseProxyHandler::Action act) {}
class JS_PUBLIC_API AutoWaivePolicy{
public : AutoWaivePolicy(JSContext * cx, JS::HandleObject proxy,
JS::HandleId id, BaseProxyHandler::Action act){}
};
#endif
@ -742,13 +755,13 @@ constexpr unsigned CheckProxyFlags() {
}
#define PROXY_CLASS_DEF_WITH_CLASS_SPEC(name, flags, classSpec) \
{ \
name, \
JSClass::NON_NATIVE | JSCLASS_IS_PROXY | \
JSCLASS_DELAY_METADATA_BUILDER | js::CheckProxyFlags<flags>(), \
&js::ProxyClassOps, classSpec, &js::ProxyClassExtension, \
&js::ProxyObjectOps \
}
{name, \
JSClass::NON_NATIVE | JSCLASS_IS_PROXY | JSCLASS_DELAY_METADATA_BUILDER | \
js::CheckProxyFlags<flags>(), \
&js::ProxyClassOps, \
classSpec, \
&js::ProxyClassExtension, \
&js::ProxyObjectOps}
#define PROXY_CLASS_DEF(name, flags) \
PROXY_CLASS_DEF_WITH_CLASS_SPEC(name, flags, JS_NULL_CLASS_SPEC)

View File

@ -106,6 +106,8 @@ extern JS_PUBLIC_API JS::Handle<JSObject*> GetRealmObjectPrototypeHandle(
JSContext* cx);
extern JS_PUBLIC_API JSObject* GetRealmFunctionPrototype(JSContext* cx);
extern JS_PUBLIC_API JS::Handle<JSObject*> GetRealmFunctionPrototypeHandle(
JSContext* cx);
extern JS_PUBLIC_API JSObject* GetRealmArrayPrototype(JSContext* cx);
@ -142,6 +144,14 @@ extern JS_PUBLIC_API JS::Realm* EnterRealm(JSContext* cx, JSObject* target);
extern JS_PUBLIC_API void LeaveRealm(JSContext* cx, JS::Realm* oldRealm);
/**
* Reset the seed for Math.random() within the current realm.
*
* Enables embedders to reset the seed at controlled points, e.g. after
* resuming execution from an instance snapshot of SpiderMonkey's VM.
*/
extern JS_PUBLIC_API void ResetRealmMathRandomSeed(JSContext* cx);
} // namespace JS
/*

View File

@ -113,6 +113,12 @@ class JS_PUBLIC_API RealmCreationOptions {
// Determines whether this realm should preserve JIT code on non-shrinking
// GCs.
//
// Useful for embedders who know their code is relatively stable. See
// Bug 1068697 for motivation.
//
// This is a hint not a guarantee and can be overriden by other heuristics in
// the engine.
bool preserveJitCode() const { return preserveJitCode_; }
RealmCreationOptions& setPreserveJitCode(bool flag) {
preserveJitCode_ = flag;

View File

@ -14,11 +14,7 @@
// These types implement the same interface as mozilla::(Atomic)RefCounted and
// must be used instead of mozilla::(Atomic)RefCounted for everything in
// SpiderMonkey. There are two reasons:
// - Release() needs to call js_delete, not delete
// - SpiderMonkey does not have MOZILLA_INTERNAL_API defined which can lead
// to ODR violations that show up as spurious leak reports when ref-counted
// types are allocated by SpiderMonkey and released by Gecko (or vice versa).
// SpiderMonkey. This is because Release() needs to call js_delete, not delete.
namespace js {

View File

@ -79,7 +79,7 @@ class RegExpFlags {
using Flag = uint8_t;
private:
Flag flags_;
Flag flags_ = 0;
public:
RegExpFlags() = default;
@ -159,7 +159,7 @@ inline RegExpFlags& operator^=(RegExpFlags& flags, RegExpFlags::Flag flag) {
inline RegExpFlags operator&(const RegExpFlags& lhs, const RegExpFlags& rhs) {
RegExpFlags result = lhs;
result &= rhs;
return lhs;
return result;
}
inline RegExpFlags operator|(const RegExpFlags& lhs, const RegExpFlags& rhs) {

View File

@ -13,6 +13,7 @@
#include "mozilla/LinkedList.h"
#include "mozilla/Maybe.h"
#include <tuple>
#include <type_traits>
#include <utility>
@ -24,9 +25,9 @@
#include "js/GCTypeMacros.h" // JS_FOR_EACH_PUBLIC_{,TAGGED_}GC_POINTER_TYPE
#include "js/HashTable.h"
#include "js/HeapAPI.h" // StackKindCount
#include "js/NativeStackLimits.h" // JS::NativeStackLimit
#include "js/ProfilingStack.h"
#include "js/Realm.h"
#include "js/Stack.h" // JS::NativeStackLimit
#include "js/TypeDecls.h"
#include "js/UniquePtr.h"
@ -173,15 +174,15 @@ struct Cell;
// operator= on the derived class. Thus, define the operator= directly on the
// class as we would need to manually pass it through anyway.
#define DECLARE_POINTER_ASSIGN_OPS(Wrapper, T) \
Wrapper<T>& operator=(const T& p) { \
Wrapper& operator=(const T& p) { \
set(p); \
return *this; \
} \
Wrapper<T>& operator=(T&& p) { \
Wrapper& operator=(T&& p) { \
set(std::move(p)); \
return *this; \
} \
Wrapper<T>& operator=(const Wrapper<T>& other) { \
Wrapper& operator=(const Wrapper& other) { \
set(other.get()); \
return *this; \
}
@ -205,11 +206,6 @@ namespace JS {
JS_PUBLIC_API void HeapObjectPostWriteBarrier(JSObject** objp, JSObject* prev,
JSObject* next);
JS_PUBLIC_API void HeapStringPostWriteBarrier(JSString** objp, JSString* prev,
JSString* next);
JS_PUBLIC_API void HeapBigIntPostWriteBarrier(JS::BigInt** bip,
JS::BigInt* prev,
JS::BigInt* next);
JS_PUBLIC_API void HeapObjectWriteBarriers(JSObject** objp, JSObject* prev,
JSObject* next);
JS_PUBLIC_API void HeapStringWriteBarriers(JSString** objp, JSString* prev,
@ -244,8 +240,8 @@ struct SafelyInitialized {
// doesn't offer a type trait indicating whether a class's constructor is
// user-defined, which better approximates our desired semantics.)
constexpr bool IsNonTriviallyDefaultConstructibleClassOrUnion =
(std::is_class_v<T> ||
std::is_union_v<T>)&&!std::is_trivially_default_constructible_v<T>;
(std::is_class_v<T> || std::is_union_v<T>) &&
!std::is_trivially_default_constructible_v<T>;
static_assert(IsPointer || IsNonTriviallyDefaultConstructibleClassOrUnion,
"T() must evaluate to a safely-initialized T");
@ -281,13 +277,9 @@ inline void AssertGCThingIsNotNurseryAllocable(js::gc::Cell* cell) {}
*
* Heap<T> implements the following barriers:
*
* - Pre-write barrier (necessary for incremental GC).
* - Post-write barrier (necessary for generational GC).
* - Read barrier (necessary for incremental GC and cycle collector
* integration).
*
* Note Heap<T> does not have a pre-write barrier as used internally in the
* engine. The read barrier is used to mark anything read from a Heap<T> during
* an incremental GC.
* - Read barrier (necessary for cycle collector integration).
*
* Heap<T> may be moved or destroyed outside of GC finalization and hence may be
* used in dynamic storage such as a Vector.
@ -302,8 +294,6 @@ inline void AssertGCThingIsNotNurseryAllocable(js::gc::Cell* cell) {}
*/
template <typename T>
class MOZ_NON_MEMMOVABLE Heap : public js::HeapOperations<T, Heap<T>> {
// Please note: this can actually also be used by nsXBLMaybeCompiled<T>, for
// legacy reasons.
static_assert(js::IsHeapConstructibleType<T>::value,
"Type T must be a public GC pointer type");
@ -316,7 +306,7 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapOperations<T, Heap<T>> {
"Heap<T> must be binary compatible with T.");
}
explicit Heap(const T& p) : ptr(p) {
postWriteBarrier(SafelyInitialized<T>::create(), ptr);
writeBarriers(SafelyInitialized<T>::create(), ptr);
}
/*
@ -325,25 +315,24 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapOperations<T, Heap<T>> {
* breaks common usage of move semantics, so we need to define both, even
* though they are equivalent.
*/
explicit Heap(const Heap<T>& other) : ptr(other.getWithoutExpose()) {
postWriteBarrier(SafelyInitialized<T>::create(), ptr);
explicit Heap(const Heap<T>& other) : ptr(other.unbarrieredGet()) {
writeBarriers(SafelyInitialized<T>::create(), ptr);
}
Heap(Heap<T>&& other) : ptr(other.getWithoutExpose()) {
postWriteBarrier(SafelyInitialized<T>::create(), ptr);
Heap(Heap<T>&& other) : ptr(other.unbarrieredGet()) {
writeBarriers(SafelyInitialized<T>::create(), ptr);
}
Heap& operator=(Heap<T>&& other) {
set(other.getWithoutExpose());
set(other.unbarrieredGet());
other.set(SafelyInitialized<T>::create());
return *this;
}
// Copy constructor defined by DECLARE_POINTER_ASSIGN_OPS.
~Heap() { postWriteBarrier(ptr, SafelyInitialized<T>::create()); }
~Heap() { writeBarriers(ptr, SafelyInitialized<T>::create()); }
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_POINTER_ASSIGN_OPS(Heap, T);
const T* address() const { return &ptr; }
DECLARE_POINTER_ASSIGN_OPS(Heap<T>, T);
void exposeToActiveJS() const { js::BarrierMethods<T>::exposeToJS(ptr); }
@ -351,32 +340,25 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapOperations<T, Heap<T>> {
exposeToActiveJS();
return ptr;
}
const T& getWithoutExpose() const {
js::BarrierMethods<T>::readBarrier(ptr);
return ptr;
}
const T& unbarrieredGet() const { return ptr; }
void set(const T& newPtr) {
T tmp = ptr;
ptr = newPtr;
postWriteBarrier(tmp, ptr);
writeBarriers(tmp, ptr);
}
T* unsafeGet() { return &ptr; }
void unbarrieredSet(const T& newPtr) { ptr = newPtr; }
T* unsafeAddress() { return &ptr; }
const T* unsafeAddress() const { return &ptr; }
explicit operator bool() const {
return bool(js::BarrierMethods<T>::asGCThingOrNull(ptr));
}
explicit operator bool() {
return bool(js::BarrierMethods<T>::asGCThingOrNull(ptr));
}
private:
void postWriteBarrier(const T& prev, const T& next) {
js::BarrierMethods<T>::postWriteBarrier(&ptr, prev, next);
void writeBarriers(const T& prev, const T& next) {
js::BarrierMethods<T>::writeBarriers(&ptr, prev, next);
}
T ptr;
@ -448,7 +430,7 @@ inline void AssertObjectIsNotGray(const JS::Heap<JSObject*>& obj) {}
* it has two important differences:
*
* 1) Pointers which are statically known to only reference "tenured" objects
* can avoid the extra overhead of SpiderMonkey's write barriers.
* can avoid the extra overhead of SpiderMonkey's post write barriers.
*
* 2) Objects in the "tenured" heap have stronger alignment restrictions than
* those in the "nursery", so it is possible to store flags in the lower
@ -473,6 +455,9 @@ inline void AssertObjectIsNotGray(const JS::Heap<JSObject*>& obj) {}
*/
template <typename T>
class TenuredHeap : public js::HeapOperations<T, TenuredHeap<T>> {
static_assert(js::IsHeapConstructibleType<T>::value,
"Type T must be a public GC pointer type");
public:
using ElementType = T;
@ -480,12 +465,29 @@ class TenuredHeap : public js::HeapOperations<T, TenuredHeap<T>> {
static_assert(sizeof(T) == sizeof(TenuredHeap<T>),
"TenuredHeap<T> must be binary compatible with T.");
}
explicit TenuredHeap(T p) : bits(0) { setPtr(p); }
explicit TenuredHeap(T p) : bits(0) { unbarrieredSetPtr(p); }
explicit TenuredHeap(const TenuredHeap<T>& p) : bits(0) {
setPtr(p.getPtr());
unbarrieredSetPtr(p.getPtr());
}
TenuredHeap<T>& operator=(T p) {
setPtr(p);
return *this;
}
TenuredHeap<T>& operator=(const TenuredHeap<T>& other) {
preWriteBarrier();
bits = other.bits;
return *this;
}
~TenuredHeap() { preWriteBarrier(); }
void setPtr(T newPtr) {
preWriteBarrier();
unbarrieredSetPtr(newPtr);
}
void unbarrieredSetPtr(T newPtr) {
MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0);
MOZ_ASSERT(js::gc::IsCellPointerValidOrNull(newPtr));
if (newPtr) {
@ -526,19 +528,6 @@ class TenuredHeap : public js::HeapOperations<T, TenuredHeap<T>> {
explicit operator bool() const {
return bool(js::BarrierMethods<T>::asGCThingOrNull(unbarrieredGetPtr()));
}
explicit operator bool() {
return bool(js::BarrierMethods<T>::asGCThingOrNull(unbarrieredGetPtr()));
}
TenuredHeap<T>& operator=(T p) {
setPtr(p);
return *this;
}
TenuredHeap<T>& operator=(const TenuredHeap<T>& other) {
bits = other.bits;
return *this;
}
private:
enum {
@ -546,6 +535,12 @@ class TenuredHeap : public js::HeapOperations<T, TenuredHeap<T>> {
flagsMask = (1 << maskBits) - 1,
};
void preWriteBarrier() {
if (T prev = unbarrieredGetPtr()) {
JS::IncrementalPreWriteBarrier(JS::GCCellPtr(prev));
}
}
uintptr_t bits;
};
@ -583,6 +578,8 @@ template <typename T>
class MutableHandle;
template <typename T>
class Rooted;
template <typename T, size_t N = SIZE_MAX>
class RootedField;
template <typename T>
class PersistentRooted;
@ -662,6 +659,11 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleOperations<T, Handle<T>> {
MutableHandle<S>& root,
std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0);
template <size_t N, typename S>
inline MOZ_IMPLICIT Handle(
const RootedField<S, N>& rootedField,
std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0);
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
@ -700,6 +702,8 @@ class MOZ_STACK_CLASS MutableHandle
using ElementType = T;
inline MOZ_IMPLICIT MutableHandle(Rooted<T>* root);
template <size_t N>
inline MOZ_IMPLICIT MutableHandle(RootedField<T, N>* root);
inline MOZ_IMPLICIT MutableHandle(PersistentRooted<T>* root);
private:
@ -783,7 +787,10 @@ struct PtrBarrierMethodsBase {
template <typename T>
struct BarrierMethods<T*> : public detail::PtrBarrierMethodsBase<T> {
static void postWriteBarrier(T** vp, T* prev, T* next) {
static void writeBarriers(T** vp, T* prev, T* next) {
if (prev) {
JS::IncrementalPreWriteBarrier(JS::GCCellPtr(prev));
}
if (next) {
JS::AssertGCThingIsNotNurseryAllocable(
reinterpret_cast<js::gc::Cell*>(next));
@ -794,6 +801,9 @@ struct BarrierMethods<T*> : public detail::PtrBarrierMethodsBase<T> {
template <>
struct BarrierMethods<JSObject*>
: public detail::PtrBarrierMethodsBase<JSObject> {
static void writeBarriers(JSObject** vp, JSObject* prev, JSObject* next) {
JS::HeapObjectWriteBarriers(vp, prev, next);
}
static void postWriteBarrier(JSObject** vp, JSObject* prev, JSObject* next) {
JS::HeapObjectPostWriteBarrier(vp, prev, next);
}
@ -807,9 +817,9 @@ struct BarrierMethods<JSObject*>
template <>
struct BarrierMethods<JSFunction*>
: public detail::PtrBarrierMethodsBase<JSFunction> {
static void postWriteBarrier(JSFunction** vp, JSFunction* prev,
static void writeBarriers(JSFunction** vp, JSFunction* prev,
JSFunction* next) {
JS::HeapObjectPostWriteBarrier(reinterpret_cast<JSObject**>(vp),
JS::HeapObjectWriteBarriers(reinterpret_cast<JSObject**>(vp),
reinterpret_cast<JSObject*>(prev),
reinterpret_cast<JSObject*>(next));
}
@ -823,17 +833,25 @@ struct BarrierMethods<JSFunction*>
template <>
struct BarrierMethods<JSString*>
: public detail::PtrBarrierMethodsBase<JSString> {
static void postWriteBarrier(JSString** vp, JSString* prev, JSString* next) {
JS::HeapStringPostWriteBarrier(vp, prev, next);
static void writeBarriers(JSString** vp, JSString* prev, JSString* next) {
JS::HeapStringWriteBarriers(vp, prev, next);
}
};
template <>
struct BarrierMethods<JSScript*>
: public detail::PtrBarrierMethodsBase<JSScript> {
static void writeBarriers(JSScript** vp, JSScript* prev, JSScript* next) {
JS::HeapScriptWriteBarriers(vp, prev, next);
}
};
template <>
struct BarrierMethods<JS::BigInt*>
: public detail::PtrBarrierMethodsBase<JS::BigInt> {
static void postWriteBarrier(JS::BigInt** vp, JS::BigInt* prev,
static void writeBarriers(JS::BigInt** vp, JS::BigInt* prev,
JS::BigInt* next) {
JS::HeapBigIntPostWriteBarrier(vp, prev, next);
JS::HeapBigIntWriteBarriers(vp, prev, next);
}
};
@ -1145,11 +1163,19 @@ using RootedTraits =
template <typename T>
class MOZ_RAII Rooted : public detail::RootedTraits<T>::StackBase,
public js::RootedOperations<T, Rooted<T>> {
// Intentionally store a pointer into the stack.
#if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 12)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdangling-pointer"
#endif
inline void registerWithRootLists(RootedListHeads& roots) {
this->stack = &roots[JS::MapTypeToRootKind<T>::kind];
this->prev = *this->stack;
*this->stack = this;
}
#if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 12)
# pragma GCC diagnostic pop
#endif
inline RootedListHeads& rootLists(RootingContext* cx) {
return cx->stackRoots_;
@ -1220,7 +1246,7 @@ class MOZ_RAII Rooted : public detail::RootedTraits<T>::StackBase,
}
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_POINTER_ASSIGN_OPS(Rooted, T);
DECLARE_POINTER_ASSIGN_OPS(Rooted<T>, T);
T& get() { return ptr; }
const T& get() const { return ptr; }
@ -1243,6 +1269,86 @@ struct DefineComparisonOps<Rooted<T>> : std::true_type {
} // namespace detail
template <typename... Fs>
using RootedTuple = Rooted<std::tuple<Fs...>>;
// Reference to a field in a RootedTuple. This is a drop-in replacement for an
// individual Rooted.
//
// This is very similar to a MutableHandle but with two differences: it has an
// assignment operator so doesn't require set() to be called and its address
// converts to a MutableHandle in the same way as a Rooted.
//
// The field is specified by the type parameter, optionally disambiguated by
// supplying the field index too.
//
// Used like this:
//
// RootedTuple<JSObject*, JSString*> roots(cx);
// RootedField<JSObject*> obj(roots);
// RootedField<JSString*> str(roots);
//
// or:
//
// RootedTuple<JString*, JSObject*, JSObject*> roots(cx);
// RootedField<JString*, 0> str(roots);
// RootedField<JSObject*, 1> obj1(roots);
// RootedField<JSObject*, 2> obj2(roots);
template <typename T, size_t N /* = SIZE_MAX */>
class MOZ_RAII RootedField : public js::RootedOperations<T, RootedField<T, N>> {
T* ptr;
friend class Handle<T>;
friend class MutableHandle<T>;
public:
using ElementType = T;
template <typename... Fs>
explicit RootedField(RootedTuple<Fs...>& rootedTuple) {
using Tuple = std::tuple<Fs...>;
if constexpr (N == SIZE_MAX) {
ptr = &std::get<T>(rootedTuple.get());
} else {
static_assert(N < std::tuple_size_v<Tuple>);
static_assert(std::is_same_v<T, std::tuple_element_t<N, Tuple>>);
ptr = &std::get<N>(rootedTuple.get());
}
}
template <typename... Fs, typename S>
explicit RootedField(RootedTuple<Fs...>& rootedTuple, S&& value)
: RootedField(rootedTuple) {
*ptr = std::forward<S>(value);
}
T& get() { return *ptr; }
const T& get() const { return *ptr; }
void set(const T& value) {
*ptr = value;
MOZ_ASSERT(GCPolicy<T>::isValid(*ptr));
}
void set(T&& value) {
*ptr = std::move(value);
MOZ_ASSERT(GCPolicy<T>::isValid(*ptr));
}
using WrapperT = RootedField<T, N>;
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_POINTER_ASSIGN_OPS(WrapperT, T);
// DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
// DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr);
private:
RootedField() = delete;
RootedField(const RootedField& other) = delete;
};
namespace detail {
template <size_t N, typename T>
struct DefineComparisonOps<JS::RootedField<T, N>> : std::true_type {
static const T& get(const JS::RootedField<T, N>& v) { return v.get(); }
};
} // namespace detail
} /* namespace JS */
namespace js {
@ -1342,6 +1448,14 @@ inline Handle<T>::Handle(
ptr = reinterpret_cast<const T*>(root.address());
}
template <typename T>
template <size_t N, typename S>
inline Handle<T>::Handle(
const RootedField<S, N>& rootedField,
std::enable_if_t<std::is_convertible_v<S, T>, int> dummy) {
ptr = reinterpret_cast<const T*>(rootedField.ptr);
}
template <typename T>
inline MutableHandle<T>::MutableHandle(Rooted<T>* root) {
static_assert(sizeof(MutableHandle<T>) == sizeof(T*),
@ -1349,6 +1463,12 @@ inline MutableHandle<T>::MutableHandle(Rooted<T>* root) {
ptr = root->address();
}
template <typename T>
template <size_t N>
inline MutableHandle<T>::MutableHandle(RootedField<T, N>* rootedField) {
ptr = rootedField->ptr;
}
template <typename T>
inline MutableHandle<T>::MutableHandle(PersistentRooted<T>* root) {
static_assert(sizeof(MutableHandle<T>) == sizeof(T*),
@ -1480,7 +1600,7 @@ class PersistentRooted : public detail::RootedTraits<T>::PersistentBase,
}
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T);
DECLARE_POINTER_ASSIGN_OPS(PersistentRooted<T>, T);
T& get() { return ptr; }
const T& get() const { return ptr; }

View File

@ -16,7 +16,7 @@
#include "jstypes.h"
namespace js {
namespace JS {
struct JS_PUBLIC_API TimeBudget {
const mozilla::TimeDuration budget;
@ -140,6 +140,6 @@ class JS_PUBLIC_API SliceBudget {
int describe(char* buffer, size_t maxlen) const;
};
} // namespace js
} // namespace JS
#endif /* js_SliceBudget_h */

View File

@ -17,44 +17,9 @@
#include "jstypes.h" // JS_PUBLIC_API
#include "js/NativeStackLimits.h"
#include "js/Principals.h" // JSPrincipals, JS_HoldPrincipals, JS_DropPrincipals
#include "js/TypeDecls.h" // JSContext, Handle*, MutableHandle*
namespace JS {
using NativeStackSize = size_t;
using NativeStackBase = uintptr_t;
using NativeStackLimit = uintptr_t;
#if JS_STACK_GROWTH_DIRECTION > 0
constexpr NativeStackLimit NativeStackLimitMin = 0;
constexpr NativeStackLimit NativeStackLimitMax = UINTPTR_MAX;
#else
constexpr NativeStackLimit NativeStackLimitMin = UINTPTR_MAX;
constexpr NativeStackLimit NativeStackLimitMax = 0;
#endif
#ifdef __wasi__
// We build with the "stack-first" wasm-ld option, so the stack grows downward
// toward zero. Let's set a limit just a bit above this so that we catch an
// overflow before a Wasm trap occurs.
constexpr NativeStackLimit WASINativeStackLimit = 1024;
#endif // __wasi__
inline NativeStackLimit GetNativeStackLimit(NativeStackBase base,
NativeStackSize size) {
#if JS_STACK_GROWTH_DIRECTION > 0
MOZ_ASSERT(base <= size_t(-1) - size);
return base + size - 1;
#else // stack grows up
MOZ_ASSERT(base >= size);
return base - (size - 1);
#endif // stack grows down
}
} // namespace JS
#include "js/RootingAPI.h"
/**
* Set the size of the native stack that should not be exceed. To disable
@ -177,7 +142,8 @@ using StackCapture = mozilla::Variant<AllFrames, MaxFrames, FirstSubsumedFrame>;
*/
extern JS_PUBLIC_API bool CaptureCurrentStack(
JSContext* cx, MutableHandleObject stackp,
StackCapture&& capture = StackCapture(AllFrames()));
StackCapture&& capture = StackCapture(AllFrames()),
HandleObject startAfter = nullptr);
/**
* Returns true if capturing stack trace data to associate with an asynchronous

View File

@ -16,8 +16,10 @@
#include "mozilla/Likely.h" // MOZ_LIKELY
#include "mozilla/Maybe.h" // mozilla::Maybe
#include "mozilla/Range.h" // mozilla::Range
#include "mozilla/RefPtr.h" // RefPtr
#include "mozilla/Span.h" // mozilla::Span
// std::tuple
#include "mozilla/StringBuffer.h" // mozilla::StringBuffer
#include <algorithm> // std::copy_n
#include <stddef.h> // size_t
@ -102,6 +104,63 @@ extern JS_PUBLIC_API JSString* JS_NewUCStringCopyN(JSContext* cx,
extern JS_PUBLIC_API JSString* JS_NewUCStringCopyZ(JSContext* cx,
const char16_t* s);
namespace JS {
/**
* Create a new JSString possibly backed by |buffer|. The contents of |buffer|
* will be interpreted as an array of Latin1 characters.
*
* Note that the returned string is not guaranteed to use |buffer|: as an
* optimization, this API can return an inline string or a previously allocated
* string.
*
* Increments the buffer's refcount iff the JS string holds a reference to it.
*/
extern JS_PUBLIC_API JSString* NewStringFromLatin1Buffer(
JSContext* cx, RefPtr<mozilla::StringBuffer> buffer, size_t length);
/**
* Like NewStringFromLatin1Buffer, but can be used to avoid refcounting overhead
* in cases where the returned string doesn't use the buffer. The caller must
* ensure the buffer outlives this call.
*/
extern JS_PUBLIC_API JSString* NewStringFromKnownLiveLatin1Buffer(
JSContext* cx, mozilla::StringBuffer* buffer, size_t length);
/**
* Similar to NewStringFromLatin1Buffer but for char16_t buffers.
*/
extern JS_PUBLIC_API JSString* NewStringFromTwoByteBuffer(
JSContext* cx, RefPtr<mozilla::StringBuffer> buffer, size_t length);
/**
* Similar to NewStringFromKnownLiveLatin1Buffer but for char16_t buffers.
*/
extern JS_PUBLIC_API JSString* NewStringFromKnownLiveTwoByteBuffer(
JSContext* cx, mozilla::StringBuffer* buffer, size_t length);
/**
* Similar to NewStringFromLatin1Buffer but for UTF8 buffers.
*
* This can create a Latin1 string backed by |buffer| iff the utf8 buffer
* contains only ASCII chars. If there are non-ASCII chars, |buffer| can't be
* used so this API will copy and inflate the characters for the new JS string.
*
* Note that |length| must be the (byte) length of the UTF8 buffer.
*/
extern JS_PUBLIC_API JSString* NewStringFromUTF8Buffer(
JSContext* cx, RefPtr<mozilla::StringBuffer> buffer, size_t length);
/**
* Like NewStringFromUTF8Buffer, but can be used to avoid refcounting overhead
* in cases where the returned string doesn't use the buffer. The caller must
* ensure the buffer outlives this call.
*/
extern JS_PUBLIC_API JSString* NewStringFromKnownLiveUTF8Buffer(
JSContext* cx, mozilla::StringBuffer* buffer, size_t length);
} // namespace JS
extern JS_PUBLIC_API JSString* JS_AtomizeUCStringN(JSContext* cx,
const char16_t* s,
size_t length);
@ -430,6 +489,46 @@ MOZ_ALWAYS_INLINE bool IsExternalUCString(
return true;
}
/**
* If the provided string is backed by a StringBuffer for latin-1 storage,
* return true and set |*buffer| to the string buffer.
*
* Note: this function doesn't increment the buffer's refcount. The buffer
* remains valid as long as the provided string is kept alive.
*/
MOZ_ALWAYS_INLINE bool IsLatin1StringWithStringBuffer(
JSString* str, mozilla::StringBuffer** buffer) {
shadow::String* s = shadow::AsShadowString(str);
if (!s->hasStringBuffer() || !s->hasLatin1Chars()) {
return false;
}
void* data = const_cast<JS::Latin1Char*>(s->nonInlineCharsLatin1);
*buffer = mozilla::StringBuffer::FromData(data);
return true;
}
/**
* If the provided string is backed by a StringBuffer for char16_t storage,
* return true and set |*buffer| to the string buffer.
*
* Note: this function doesn't increment the buffer's refcount. The buffer
* remains valid as long as the provided string is kept alive.
*/
MOZ_ALWAYS_INLINE bool IsTwoByteStringWithStringBuffer(
JSString* str, mozilla::StringBuffer** buffer) {
shadow::String* s = shadow::AsShadowString(str);
if (!s->hasStringBuffer() || s->hasLatin1Chars()) {
return false;
}
void* data = const_cast<char16_t*>(s->nonInlineCharsTwoByte);
*buffer = mozilla::StringBuffer::FromData(data);
return true;
}
namespace detail {
extern JS_PUBLIC_API JSLinearString* StringToLinearStringSlow(JSContext* cx,

View File

@ -10,6 +10,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/BufferList.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/StringBuffer.h"
#include <stdint.h>
#include <utility>
@ -154,6 +155,13 @@ enum class StructuredCloneScope : uint32_t {
*/
DifferentProcess,
/**
* Values greater than this are temporary markers used when the actual scope
* is not yet known. The allowed scope will be resolved by the time
* readHeader() is complete.
*/
LastResolvedScope = DifferentProcess,
/**
* Handle a backwards-compatibility case with IndexedDB (bug 1434308): when
* reading, this means to treat legacy SameProcess data as if it were
@ -311,6 +319,11 @@ typedef void (*StructuredCloneErrorOp)(JSContext* cx, uint32_t errorid,
* If this readTransfer() hook is called and produces an object, then the
* read() hook will *not* be called for the same object, since the main data
* will only contain a backreference to the already-read object.
*
* The clone buffer will relinquish ownership of this Transferable if and only
* if this hook returns true -- as in, the freeTransfer hook will not be called
* on this entry if this hook returns true, but it will still be called if it
* returns false.
*/
typedef bool (*ReadTransferStructuredCloneOp)(
JSContext* cx, JSStructuredCloneReader* r,
@ -351,7 +364,9 @@ typedef bool (*TransferStructuredCloneOp)(JSContext* cx,
* encountered later and the incomplete serialization is discarded.
*
* 2. During deserialization: before an object is Transferred to, an error
* is encountered and the incompletely deserialized clone is discarded.
* is encountered and the incompletely deserialized clone is discarded. This
* will happen with internally-implemented Transferables as well as those
* where the readTransfer hook returns false.
*
* 3. Serialized data that includes Transferring is never deserialized (eg when
* the receiver disappears before reading in the message), and the clone data
@ -469,6 +484,10 @@ class MOZ_NON_MEMMOVABLE JS_PUBLIC_API JSStructuredCloneData {
OwnTransferablePolicy::NoTransferables;
js::SharedArrayRawBufferRefs refsHeld_;
using StringBuffers =
js::Vector<RefPtr<mozilla::StringBuffer>, 4, js::SystemAllocPolicy>;
StringBuffers stringBufferRefsHeld_;
friend struct JSStructuredCloneWriter;
friend class JS_PUBLIC_API JSAutoStructuredCloneBuffer;
template <typename T, typename AllocPolicy>

View File

@ -63,7 +63,8 @@ extern JS_PUBLIC_API JSString* GetSymbolDescription(Handle<Symbol*> symbol);
MACRO(unscopables) \
MACRO(asyncIterator) \
MACRO(matchAll) \
IF_EXPLICIT_RESOURCE_MANAGEMENT(MACRO(dispose))
IF_EXPLICIT_RESOURCE_MANAGEMENT(MACRO(dispose)) \
IF_EXPLICIT_RESOURCE_MANAGEMENT(MACRO(asyncDispose))
enum class SymbolCode : uint32_t {
// There is one SymbolCode for each well-known symbol.

View File

@ -22,6 +22,9 @@ class PropMap;
class RegExpShared;
class Shape;
class Scope;
namespace gc {
class SmallBuffer;
} // namespace gc
namespace jit {
class JitCode;
} // namespace jit
@ -63,6 +66,7 @@ enum class TraceKind {
RegExpShared,
GetterSetter,
PropMap,
SmallBuffer
};
// GCCellPtr packs the trace kind into the low bits of the pointer for common
@ -101,7 +105,8 @@ struct MapTypeToTraceKind {
D(BigInt, JS::BigInt, false, false) \
D(RegExpShared, js::RegExpShared, true, true) \
D(GetterSetter, js::GetterSetter, true, true) \
D(PropMap, js::PropMap, false, false)
D(PropMap, js::PropMap, false, false) \
D(SmallBuffer, js::gc::SmallBuffer, false, false)
// clang-format on
// Returns true if the JS::TraceKind is represented as a node in cycle collector

View File

@ -48,6 +48,7 @@ enum class TracerKind {
UnmarkGray,
VerifyTraceProtoAndIface,
CompartmentCheck,
HeapCheck
};
enum class WeakMapTraceAction {
@ -135,7 +136,8 @@ class TracingContext {
// currently set tracing context.
class Functor {
public:
virtual void operator()(TracingContext* tcx, char* buf, size_t bufsize) = 0;
virtual void operator()(TracingContext* tcx, const char* name, char* buf,
size_t bufsize) = 0;
};
private:
@ -348,7 +350,7 @@ template <typename T>
inline void TraceEdge(JSTracer* trc, JS::Heap<T>* thingp, const char* name) {
MOZ_ASSERT(thingp);
if (*thingp) {
js::gc::TraceExternalEdge(trc, thingp->unsafeGet(), name);
js::gc::TraceExternalEdge(trc, thingp->unsafeAddress(), name);
}
}
@ -358,7 +360,7 @@ inline void TraceEdge(JSTracer* trc, JS::TenuredHeap<T>* thingp,
MOZ_ASSERT(thingp);
if (T ptr = thingp->unbarrieredGetPtr()) {
js::gc::TraceExternalEdge(trc, &ptr, name);
thingp->setPtr(ptr);
thingp->unbarrieredSetPtr(ptr);
}
}

View File

@ -19,8 +19,15 @@
#include "js/TypeDecls.h"
// Underlying opaque type.
namespace js::frontend {
struct InitialStencilAndDelazifications;
} // namespace js::frontend
namespace JS {
using Stencil = js::frontend::InitialStencilAndDelazifications;
class JS_PUBLIC_API ReadOnlyCompileOptions;
using TranscodeBuffer = mozilla::Vector<uint8_t>;
@ -79,52 +86,6 @@ inline bool IsTranscodingBytecodeAligned(const void* offset) {
return IsTranscodingBytecodeOffsetAligned(size_t(offset));
}
// Finish incremental encoding started by JS::StartIncrementalEncoding.
//
// * Regular script case
// the |script| argument must be the top-level script returned from
// |JS::InstantiateGlobalStencil| with the same stencil
//
// * Module script case
// the |script| argument must be the script returned by
// |JS::GetModuleScript| called on the module returned by
// |JS::InstantiateModuleStencil| with the same stencil
//
// NOTE: |JS::GetModuleScript| doesn't work after evaluating the
// module script. For the case, use Handle<JSObject*> variant of
// this function below.
//
// The |buffer| argument of |FinishIncrementalEncoding| is used for appending
// the encoded bytecode into the buffer. If any of these functions failed, the
// content of |buffer| would be undefined.
//
// |buffer| contains encoded CompilationStencil.
//
// If the `buffer` isn't empty, the start of the `buffer` should meet
// IsTranscodingBytecodeAligned, and the length should meet
// IsTranscodingBytecodeOffsetAligned.
//
// NOTE: As long as IsTranscodingBytecodeOffsetAligned is met, that means
// there's JS::BytecodeOffsetAlignment+extra bytes in the buffer,
// IsTranscodingBytecodeAligned should be guaranteed to meet by
// malloc, used by MallocAllocPolicy in mozilla::Vector.
extern JS_PUBLIC_API bool FinishIncrementalEncoding(JSContext* cx,
Handle<JSScript*> script,
TranscodeBuffer& buffer);
// Similar to |JS::FinishIncrementalEncoding|, but receives module obect.
//
// The |module| argument must be the module returned by
// |JS::InstantiateModuleStencil| with the same stencil that's passed to
// |JS::StartIncrementalEncoding|.
extern JS_PUBLIC_API bool FinishIncrementalEncoding(JSContext* cx,
Handle<JSObject*> module,
TranscodeBuffer& buffer);
// Abort incremental encoding started by JS::StartIncrementalEncoding.
extern JS_PUBLIC_API void AbortIncrementalEncoding(Handle<JSScript*> script);
extern JS_PUBLIC_API void AbortIncrementalEncoding(Handle<JSObject*> module);
// Check if the compile options and script's flag matches.
//
// JS::DecodeScript* and JS::DecodeOffThreadScript internally check this.

View File

@ -47,10 +47,6 @@ typedef unsigned char Latin1Char;
class JS_PUBLIC_API Symbol;
class JS_PUBLIC_API BigInt;
#ifdef ENABLE_RECORD_TUPLE
class JS_PUBLIC_API RecordType;
class JS_PUBLIC_API TupleType;
#endif
class JS_PUBLIC_API Value;
class JS_PUBLIC_API Compartment;
@ -130,18 +126,6 @@ using MutableHandleVector = MutableHandle<StackGCVector<T>>;
using jsid = JS::PropertyKey;
#ifdef ENABLE_RECORD_TUPLE
// This takes 1 or 2 parameters. ... is just used so that
// it's possible to omit the comma when passing a single
// param:
// IF_RECORD_TUPLE(doThis)
// IF_RECORD_TUPLE(doThis, elseThis)
# define IF_RECORD_TUPLE(x, ...) x
#else
# define IF_RECORD_TUPLE(x, ...) __VA_ARGS__
#endif
// Follows the same pattern as IF_RECORD_TUPLE
#ifdef ENABLE_DECORATORS
# define IF_DECORATORS(x, ...) x
#else

View File

@ -1164,6 +1164,26 @@ class JS_PUBLIC_API Concrete<JSString> : TracerConcrete<JSString> {
static const char16_t concreteTypeName[];
};
template <>
class JS_PUBLIC_API Concrete<js::gc::SmallBuffer>
: TracerConcrete<js::gc::SmallBuffer> {
protected:
explicit Concrete(js::gc::SmallBuffer* ptr)
: TracerConcrete<js::gc::SmallBuffer>(ptr) {}
public:
static void construct(void* storage, js::gc::SmallBuffer* ptr) {
new (storage) Concrete(ptr);
}
Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
CoarseType coarseType() const final { return CoarseType::Object; }
const char16_t* typeName() const override { return concreteTypeName; }
static const char16_t concreteTypeName[];
};
// The ubi::Node null pointer. Any attempt to operate on a null ubi::Node
// asserts.
template <>

View File

@ -43,6 +43,16 @@ extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API void JS_Assert(const char* s,
# include "jscustomallocator.h"
#else
/*
* MONGODB MODIFICATION: These functions are implemented by jscustomallocator
* This logic is unused when running Without JS_USE_CUSTOM_ALLOCATOR
*/
namespace mongo {
namespace sm {
JS_PUBLIC_API void check_oom_on_mmap_allocation(size_t bytes);
} // namespace sm
} // namespace mongo
namespace js {
/*
@ -58,15 +68,17 @@ enum ThreadType {
THREAD_TYPE_MAIN, // 1
THREAD_TYPE_WASM_COMPILE_TIER1, // 2
THREAD_TYPE_WASM_COMPILE_TIER2, // 3
THREAD_TYPE_ION, // 4
THREAD_TYPE_COMPRESS, // 5
THREAD_TYPE_GCPARALLEL, // 6
THREAD_TYPE_PROMISE_TASK, // 7
THREAD_TYPE_ION_FREE, // 8
THREAD_TYPE_WASM_GENERATOR_TIER2, // 9
THREAD_TYPE_WORKER, // 10
THREAD_TYPE_DELAZIFY, // 11
THREAD_TYPE_DELAZIFY_FREE, // 12
THREAD_TYPE_BASELINE, // 4
THREAD_TYPE_ION, // 5
THREAD_TYPE_COMPRESS, // 6
THREAD_TYPE_GCPARALLEL, // 7
THREAD_TYPE_PROMISE_TASK, // 8
THREAD_TYPE_ION_FREE, // 9
THREAD_TYPE_WASM_GENERATOR_COMPLETE_TIER2, // 10
THREAD_TYPE_WASM_COMPILE_PARTIAL_TIER2, // 11
THREAD_TYPE_WORKER, // 12
THREAD_TYPE_DELAZIFY, // 13
THREAD_TYPE_DELAZIFY_FREE, // 14
THREAD_TYPE_MAX // Used to check shell function arguments
};
@ -86,7 +98,7 @@ namespace oom {
// Define the range of threads tested by simulated OOM testing and the
// like. Testing worker threads is not supported.
const ThreadType FirstThreadTypeToTest = THREAD_TYPE_MAIN;
const ThreadType LastThreadTypeToTest = THREAD_TYPE_WASM_GENERATOR_TIER2;
const ThreadType LastThreadTypeToTest = THREAD_TYPE_WASM_COMPILE_PARTIAL_TIER2;
extern bool InitThreadType(void);
extern void SetThreadType(ThreadType);
@ -95,7 +107,7 @@ extern JS_PUBLIC_API uint32_t GetThreadType(void);
# else
inline bool InitThreadType(void) { return true; }
inline void SetThreadType(ThreadType t){};
inline void SetThreadType(ThreadType t) {};
inline uint32_t GetThreadType(void) { return 0; }
inline uint32_t GetAllocationThreadType(void) { return 0; }
inline uint32_t GetStackCheckThreadType(void) { return 0; }
@ -352,7 +364,21 @@ struct MOZ_RAII JS_PUBLIC_DATA AutoEnterOOMUnsafeRegion {
namespace js {
// The following two arenas require a little bit of clarification. We have
// observed that, particularly on devices with heterogeneous CPU architectures
// where background work can run on significantly slower cores than main thread
// work, the lock contention in the allocator can be a big problem for the
// main thread. So we introduced an arena for background allocations which can
// reduce that contention.
//
// The general rule for these is: if it's easy to determine at the time of
// authorship that an allocation will be *off* the main thread, use the
// BackgroundMallocArena, and vice versa. If it is hard to determine, just make
// a guess, and that will be fine. Do not spend too much time on this, and
// don't do anything fancy at runtime to try to determine which to use.
extern JS_PUBLIC_DATA arena_id_t MallocArena;
extern JS_PUBLIC_DATA arena_id_t BackgroundMallocArena;
extern JS_PUBLIC_DATA arena_id_t ArrayBufferContentsArena;
extern JS_PUBLIC_DATA arena_id_t StringBufferArena;

View File

@ -170,9 +170,6 @@ enum JSValueType : uint8_t {
JSVAL_TYPE_SYMBOL = 0x07,
JSVAL_TYPE_PRIVATE_GCTHING = 0x08,
JSVAL_TYPE_BIGINT = 0x09,
#ifdef ENABLE_RECORD_TUPLE
JSVAL_TYPE_EXTENDED_PRIMITIVE = 0x0b,
#endif
JSVAL_TYPE_OBJECT = 0x0c,
// This type never appears in a Value; it's only an out-of-band value.
@ -191,9 +188,6 @@ enum class ValueType : uint8_t {
Symbol = JSVAL_TYPE_SYMBOL,
PrivateGCThing = JSVAL_TYPE_PRIVATE_GCTHING,
BigInt = JSVAL_TYPE_BIGINT,
#ifdef ENABLE_RECORD_TUPLE
ExtendedPrimitive = JSVAL_TYPE_EXTENDED_PRIMITIVE,
#endif
Object = JSVAL_TYPE_OBJECT,
};
} // namespace JS
@ -214,10 +208,6 @@ enum JSValueTag : uint32_t {
JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING,
JSVAL_TAG_BIGINT = JSVAL_TAG_CLEAR | JSVAL_TYPE_BIGINT,
# ifdef ENABLE_RECORD_TUPLE
JSVAL_TAG_EXTENDED_PRIMITIVE =
JSVAL_TAG_CLEAR | JSVAL_TYPE_EXTENDED_PRIMITIVE,
# endif
JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
};
@ -237,10 +227,6 @@ enum JSValueTag : uint32_t {
JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING,
JSVAL_TAG_BIGINT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BIGINT,
# ifdef ENABLE_RECORD_TUPLE
JSVAL_TAG_EXTENDED_PRIMITIVE =
JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_EXTENDED_PRIMITIVE,
# endif
JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
};
@ -262,10 +248,6 @@ enum JSValueShiftedTag : uint64_t {
JSVAL_SHIFTED_TAG_PRIVATE_GCTHING =
(uint64_t(JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_BIGINT = (uint64_t(JSVAL_TAG_BIGINT) << JSVAL_TAG_SHIFT),
# ifdef ENABLE_RECORD_TUPLE
JSVAL_SHIFTED_TAG_EXTENDED_PRIMITIVE =
(uint64_t(JSVAL_TYPE_EXTENDED_PRIMITIVE) << JSVAL_TAG_SHIFT),
# endif
JSVAL_SHIFTED_TAG_OBJECT = (uint64_t(JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT)
};
@ -403,14 +385,7 @@ class JS_PUBLIC_API GenericPrinter;
class JSONPrinter;
static inline JS::Value PoisonedObjectValue(uintptr_t poison);
#ifdef ENABLE_RECORD_TUPLE
// Re-defined in vm/RecordTupleBoxShared.h. We cannot include that
// file because it circularly includes this one.
bool IsExtendedPrimitive(const JSObject& obj);
namespace gc {
bool MaybeForwardedIsExtendedPrimitive(const JSObject& obj);
} // namespace gc
#endif
} // namespace js
namespace JS {
@ -631,23 +606,10 @@ class alignas(8) Value {
void setObject(JSObject& obj) {
MOZ_ASSERT(js::gc::IsCellPointerValid(&obj));
#ifdef ENABLE_RECORD_TUPLE
MOZ_ASSERT(!js::gc::MaybeForwardedIsExtendedPrimitive(obj));
#endif
setObjectNoCheck(&obj);
MOZ_ASSERT(&toObject() == &obj);
}
#ifdef ENABLE_RECORD_TUPLE
void setExtendedPrimitive(JSObject& obj) {
MOZ_ASSERT(js::gc::IsCellPointerValid(&obj));
MOZ_ASSERT(js::gc::MaybeForwardedIsExtendedPrimitive(obj));
asBits_ =
bitsFromTagAndPayload(JSVAL_TAG_EXTENDED_PRIMITIVE, PayloadType(&obj));
MOZ_ASSERT(&toExtendedPrimitive() == &obj);
}
#endif
void changeGCThingPayload(js::gc::Cell* cell) {
MOZ_ASSERT(js::gc::IsCellPointerValid(cell));
#ifdef DEBUG
@ -813,6 +775,8 @@ class alignas(8) Value {
bool isDouble() const { return detail::ValueIsDouble(asBits_); }
bool isNaN() const { return isDouble() && std::isnan(toDouble()); }
bool isNumber() const {
#if defined(JS_NUNBOX32)
MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR);
@ -837,16 +801,6 @@ class alignas(8) Value {
#endif
}
#ifdef ENABLE_RECORD_TUPLE
bool isExtendedPrimitive() const {
return toTag() == JSVAL_TAG_EXTENDED_PRIMITIVE;
}
#endif
bool hasObjectPayload() const {
return isObject() || IF_RECORD_TUPLE(isExtendedPrimitive(), false);
}
bool isPrimitive() const {
#if defined(JS_NUNBOX32)
return uint32_t(toTag()) < uint32_t(detail::ValueUpperExclPrimitiveTag);
@ -910,11 +864,6 @@ class alignas(8) Value {
if (MOZ_UNLIKELY(isPrivateGCThing())) {
return JS::GCThingTraceKind(toGCThing());
}
#ifdef ENABLE_RECORD_TUPLE
if (isExtendedPrimitive()) {
return JS::TraceKind::Object;
}
#endif
return JS::TraceKind(toTag() & 0x03);
}
@ -990,24 +939,6 @@ class alignas(8) Value {
#endif
}
#ifdef ENABLE_RECORD_TUPLE
JSObject& toExtendedPrimitive() const {
MOZ_ASSERT(isExtendedPrimitive());
# if defined(JS_PUNBOX64)
MOZ_ASSERT((asBits_ & detail::ValueGCThingPayloadMask) != 0);
# endif
return *unboxGCPointer<JSObject, JSVAL_TAG_EXTENDED_PRIMITIVE>();
}
#endif
JSObject& getObjectPayload() const {
#ifdef ENABLE_RECORD_TUPLE
return isExtendedPrimitive() ? toExtendedPrimitive() : toObject();
#else
return toObject();
#endif
}
js::gc::Cell* toGCThing() const {
MOZ_ASSERT(isGCThing());
#if defined(JS_NUNBOX32)
@ -1224,14 +1155,6 @@ static inline Value ObjectValue(JSObject& obj) {
return v;
}
#ifdef ENABLE_RECORD_TUPLE
static inline Value ExtendedPrimitiveValue(JSObject& obj) {
Value v;
v.setExtendedPrimitive(obj);
return v;
}
#endif
static inline Value MagicValue(JSWhyMagic why) {
Value v;
v.setMagic(why);
@ -1329,6 +1252,10 @@ struct BarrierMethods<JS::Value> {
static gc::Cell* asGCThingOrNull(const JS::Value& v) {
return v.isGCThing() ? v.toGCThing() : nullptr;
}
static void writeBarriers(JS::Value* v, const JS::Value& prev,
const JS::Value& next) {
JS::HeapValueWriteBarriers(v, prev, next);
}
static void postWriteBarrier(JS::Value* v, const JS::Value& prev,
const JS::Value& next) {
JS::HeapValuePostWriteBarrier(v, prev, next);
@ -1370,10 +1297,6 @@ class WrappedPtrOperations<JS::Value, Wrapper> {
bool isSymbol() const { return value().isSymbol(); }
bool isBigInt() const { return value().isBigInt(); }
bool isObject() const { return value().isObject(); }
#ifdef ENABLE_RECORD_TUPLE
bool isExtendedPrimitive() const { return value().isExtendedPrimitive(); }
#endif
bool hasObjectPayload() const { return value().hasObjectPayload(); }
bool isMagic() const { return value().isMagic(); }
bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
bool isGCThing() const { return value().isGCThing(); }
@ -1393,12 +1316,6 @@ class WrappedPtrOperations<JS::Value, Wrapper> {
JS::BigInt* toBigInt() const { return value().toBigInt(); }
JSObject& toObject() const { return value().toObject(); }
JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
#ifdef ENABLE_RECORD_TUPLE
JSObject& toExtendedPrimitive() const {
return value().toExtendedPrimitive();
}
#endif
JSObject& getObjectPayload() const { return value().getObjectPayload(); }
JS::GCCellPtr toGCCellPtr() const { return value().toGCCellPtr(); }
gc::Cell* toGCThing() const { return value().toGCThing(); }
JS::TraceKind traceKind() const { return value().traceKind(); }
@ -1448,11 +1365,6 @@ class MutableWrappedPtrOperations<JS::Value, Wrapper>
void setBigInt(JS::BigInt* bi) { set(JS::BigIntValue(bi)); }
void setObject(JSObject& obj) { set(JS::ObjectValue(obj)); }
void setObjectOrNull(JSObject* arg) { set(JS::ObjectOrNullValue(arg)); }
#ifdef ENABLE_RECORD_TUPLE
void setExtendedPrimitive(JSObject& obj) {
return set(JS::ExtendedPrimitiveValue(obj));
}
#endif
void setPrivate(void* ptr) { set(JS::PrivateValue(ptr)); }
void setPrivateUint32(uint32_t ui) { set(JS::PrivateUint32Value(ui)); }
void setPrivateGCThing(js::gc::Cell* cell) {
@ -1481,11 +1393,8 @@ auto MapGCThingTyped(const JS::Value& val, F&& f) {
MOZ_ASSERT(gc::IsCellPointerValid(str));
return mozilla::Some(f(str));
}
#ifdef ENABLE_RECORD_TUPLE
case JS::ValueType::ExtendedPrimitive:
#endif
case JS::ValueType::Object: {
JSObject* obj = &val.getObjectPayload();
JSObject* obj = &val.toObject();
MOZ_ASSERT(gc::IsCellPointerValid(obj));
return mozilla::Some(f(obj));
}

View File

@ -42,11 +42,6 @@
#else
# define WASM_RELAXED_SIMD_ENABLED 0
#endif
#ifdef ENABLE_WASM_GC
# define WASM_GC_ENABLED 1
#else
# define WASM_GC_ENABLED 0
#endif
#ifdef ENABLE_WASM_MEMORY64
# define WASM_MEMORY64_ENABLED 1
#else
@ -57,11 +52,6 @@
#else
# define WASM_MEMORY_CONTROL_ENABLED 0
#endif
#ifdef ENABLE_WASM_TAIL_CALLS
# define WASM_TAIL_CALLS_ENABLED 1
#else
# define WASM_TAIL_CALLS_ENABLED 0
#endif
#ifdef ENABLE_WASM_JSPI
# define WASM_JSPI_ENABLED 1
#else
@ -99,15 +89,6 @@
/* flag force enable */ false, \
/* flag fuzz enable */ true, \
/* preference name */ exnref) \
FEATURE( \
/* capitalized name */ Gc, \
/* lower case name */ gc, \
/* compile predicate */ WASM_GC_ENABLED, \
/* compiler predicate */ AnyCompilerAvailable(cx), \
/* flag predicate */ true, \
/* flag force enable */ false, \
/* flag fuzz enable */ false, \
/* preference name */ gc) \
FEATURE( \
/* capitalized name */ JSStringBuiltins, \
/* lower case name */ jsStringBuiltins, \
@ -153,30 +134,21 @@
/* flag force enable */ false, \
/* flag fuzz enable */ true, \
/* preference name */ multi_memory) \
FEATURE( \
/* capitalized name */ TailCalls, \
/* lower case name */ tailCalls, \
/* compile predicate */ WASM_TAIL_CALLS_ENABLED, \
/* compiler predicate */ AnyCompilerAvailable(cx), \
/* flag predicate */ true, \
/* flag force enable */ false, \
/* flag fuzz enable */ true, \
/* preference name */ tail_calls) \
FEATURE( \
/* capitalized name */ JSPromiseIntegration, \
/* lower case name */ jsPromiseIntegration, \
/* compile predicate */ WASM_JSPI_ENABLED, \
/* compiler predicate */ IonAvailable(cx), \
/* compiler predicate */ IonPlatformSupport(), \
/* flag predicate */ true, \
/* flag force enable */ false, \
/* flag fuzz enable */ false, \
/* flag fuzz enable */ true, \
/* preference name */ js_promise_integration) \
FEATURE( \
/* capitalized name */ MozIntGemm, \
/* lower case name */ mozIntGemm, \
/* compile predicate */ WASM_MOZ_INTGEMM_ENABLED, \
/* compiler predicate */ AnyCompilerAvailable(cx), \
/* flag predicate */ IsSimdPrivilegedContext(cx), \
/* flag predicate */ IsPrivilegedContext(cx), \
/* flag force enable */ false, \
/* flag fuzz enable */ false, \
/* preference name */ moz_intgemm) \
@ -196,7 +168,7 @@
/* compiler predicate */ IonAvailable(cx), \
/* flag predicate */ true, \
/* flag force enable */ false, \
/* flag fuzz enable */ false, \
/* flag fuzz enable */ true, \
/* preference name */ branch_hinting)
// clang-format on

View File

@ -255,6 +255,9 @@ class JS_PUBLIC_API CrossCompartmentWrapper : public Wrapper {
// Allocate CrossCompartmentWrappers in the nursery.
virtual bool canNurseryAllocate() const override { return true; }
void finalize(JS::GCContext* gcx, JSObject* proxy) const final {
Wrapper::finalize(gcx, proxy);
}
static const CrossCompartmentWrapper singleton;
static const CrossCompartmentWrapper singletonWithPrototype;

View File

@ -0,0 +1,31 @@
/* -*- 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/. */
/*
* Special allocation functions for DOM binding code.
*
*/
#ifndef js_experimental_BindingAllocs_h
#define js_experimental_BindingAllocs_h
#include "jstypes.h"
/**
* Unlike JS_NewObject, JS_NewObjectWithGivenProtoAndUseAllocSite does not
* compute a default proto. If proto is nullptr, the JS object will have `null`
* as [[Prototype]].
*
* If the JIT code has set an allocation site, this allocation will consume that
* allocation site. This only happens for DOM calls with Object return type.
*
* Must be called with a non-null clasp.
*
*/
extern JS_PUBLIC_API JSObject* JS_NewObjectWithGivenProtoAndUseAllocSite(
JSContext* cx, const JSClass* clasp, JS::Handle<JSObject*> proto);
#endif // js_experimental_BindingAllocs_h

View File

@ -38,6 +38,7 @@ struct CompilationStencil;
struct CompilationGCOutput;
struct CompilationInput;
struct PreallocatedCompilationGCOutput;
struct InitialStencilAndDelazifications;
} // namespace frontend
} // namespace js
@ -47,7 +48,7 @@ struct PreallocatedCompilationGCOutput;
namespace JS {
using Stencil = js::frontend::CompilationStencil;
using Stencil = js::frontend::InitialStencilAndDelazifications;
using FrontendContext = js::FrontendContext;
// Temporary storage used during instantiating Stencil.
@ -193,6 +194,7 @@ extern JS_PUBLIC_API JSObject* InstantiateModuleStencil(
namespace JS {
// Serialize the Stencil into the transcode buffer.
// This fails if the stencil contains asm.js.
extern JS_PUBLIC_API TranscodeResult EncodeStencil(JSContext* cx,
Stencil* stencil,
TranscodeBuffer& buffer);
@ -205,10 +207,59 @@ extern JS_PUBLIC_API TranscodeResult
DecodeStencil(JS::FrontendContext* fc, const ReadOnlyDecodeOptions& options,
const TranscodeRange& range, Stencil** stencilOut);
// Register an encoder on its script source, such that all functions can be
// encoded as they are delazified.
extern JS_PUBLIC_API bool StartIncrementalEncoding(JSContext* cx,
RefPtr<Stencil>&& stencil);
// ************************************************************************
// Collect delazifications
// ************************************************************************
// Start collecting delazifications for given script or module's source object.
//
// If the source object is already collecting delazifications, alreadyStarted is
// set to true and returns true. alreadyStarted is set to false otherwise.
extern JS_PUBLIC_API bool StartCollectingDelazifications(
JSContext* cx, JS::Handle<JSScript*> script, Stencil* stencil,
bool& alreadyStarted);
extern JS_PUBLIC_API bool StartCollectingDelazifications(
JSContext* cx, JS::Handle<JSObject*> module, Stencil* stencil,
bool& alreadyStarted);
// Finish collecting delazifications and retrieve the result.
//
// With |buffer| out-parameter, the result is encoded and appended to the
// buffer. If failed, the content of |buffer| would be undefined.
//
// If the `buffer` isn't empty, the start of the `buffer` should meet
// JS::IsTranscodingBytecodeAligned, and the length should meet
// JS::IsTranscodingBytecodeOffsetAligned.
//
// NOTE: As long as IsTranscodingBytecodeOffsetAligned is met, that means
// there's JS::BytecodeOffsetAlignment+extra bytes in the buffer,
// IsTranscodingBytecodeAligned should be guaranteed to meet by
// malloc, used by MallocAllocPolicy in mozilla::Vector.
extern JS_PUBLIC_API bool FinishCollectingDelazifications(
JSContext* cx, Handle<JSScript*> script, TranscodeBuffer& buffer);
// Similar to |JS::FinishCollectingDelazifications|, but receives module obect.
extern JS_PUBLIC_API bool FinishCollectingDelazifications(
JSContext* cx, Handle<JSObject*> module, TranscodeBuffer& buffer);
// Instead of transcoding to a buffer, return the JS::Stencil that reflects
// the delazification from the execution.
extern JS_PUBLIC_API bool FinishCollectingDelazifications(
JSContext* cx, Handle<JSScript*> script, JS::Stencil** stencilOut);
extern JS_PUBLIC_API void AbortCollectingDelazifications(
Handle<JSScript*> script);
extern JS_PUBLIC_API void AbortCollectingDelazifications(
Handle<JSObject*> module);
// ************************************************************************
// Cache
// ************************************************************************
// Returns true if the stencil is compatible with caching.
// This returns false if the stencil contains asm.js.
extern JS_PUBLIC_API bool IsStencilCacheable(JS::Stencil* stencil);
} // namespace JS

View File

@ -0,0 +1,98 @@
/* -*- 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/. */
// An experimental logging interface for connecting the JS Engine to some
// (*cough*Gecko*cough*) consumer.
#ifndef _js_experimental_LoggingInterface_h_
#define _js_experimental_LoggingInterface_h_
#include "mozilla/LoggingCore.h"
#include "jstypes.h"
#include "fmt/format.h"
#include "js/GCAPI.h"
struct JSContext;
namespace JS {
// An Opaque pointer to a LoggerType. It must be possible for this logger type
// to conform to the interface below, using the LogLevel type exported in
// mozglue LoggingCore.h
//
// There are some requirements that we cannot express through the type-system:
//
// - A Logger must outlive any caller. This is an obvious statement, but in the
// context of the JS engine means that a logger must live until after the JS
// engine is shutdown.
// - A logger cannot move. The logging interfaces assumes 1) That an
// OpaqueLogger will remain a valid handle to a logger for the entire duration
// of an initialize JS library, and 2) We are able to cache a reference to the
// log level of a particular logger (see getLevelRef below).
using OpaqueLogger = void*;
// [SMDOC] Logging Interface
//
// The logging interface contains a set of function pointers which explain how
// to talk to an embedder provided logging system.
//
// The design of the JS Consumer of this relies heavily on these to be freely
// copyable.
struct LoggingInterface {
// Acquire a new logger for a given name.
//
// This interface has no way of indicating backwards that a logger is no
// longer needed, and as such this pointer needs to be kept alive by the
// embedding for the lifetime of the JS engine.
OpaqueLogger (*getLoggerByName)(const char* loggerName) = nullptr;
// Print a message to a particular logger with a particular level and
// format.
void (*logPrintVA)(const OpaqueLogger aModule, mozilla::LogLevel aLevel,
const char* aFmt, va_list ap)
MOZ_FORMAT_PRINTF(3, 0) = nullptr;
void (*logPrintFMT)(const OpaqueLogger aModule, mozilla::LogLevel aLevel,
fmt::string_view, fmt::format_args);
// Return a reference to the provided OpaqueLogger's level ref; Implementation
// wise this can be a small violation of encapsulation but is intended to help
// ensure that we can build lightweight logging without egregious costs to
// simply check even if a mesage will the writen
mozilla::AtomicLogLevel& (*getLevelRef)(OpaqueLogger) = nullptr;
// Wrapper function for calling va-version
void logPrint(const OpaqueLogger aModule, mozilla::LogLevel aLevel,
const char* aFmt, ...) MOZ_FORMAT_PRINTF(4, 5) {
JS::AutoSuppressGCAnalysis suppress;
va_list ap;
va_start(ap, aFmt);
this->logPrintVA(aModule, aLevel, aFmt, ap);
va_end(ap);
}
template <typename... T>
void logPrintFmt(const OpaqueLogger aModule, mozilla::LogLevel aLevel,
fmt::format_string<T...> aFmt, T&&... aArgs) {
JS::AutoSuppressGCAnalysis suppress;
this->logPrintFMT(aModule, aLevel, aFmt, fmt::make_format_args(aArgs...));
}
// Used to ensure that before we use an interface, it's successfully been
// completely filled in.
bool isComplete() const {
return getLoggerByName && logPrintVA && getLevelRef;
}
};
// Install the logging interface. This will also install the interface into
// any JS loggers
extern JS_PUBLIC_API bool SetLoggingInterface(LoggingInterface& iface);
} // namespace JS
#endif /* _js_experimental_LoggingInterface_h_ */

View File

@ -135,8 +135,6 @@ namespace js {
extern JS_PUBLIC_API JSObject* UnwrapArrayBufferView(JSObject* obj);
extern JS_PUBLIC_API JSObject* UnwrapReadableStream(JSObject* obj);
namespace detail {
constexpr size_t TypedArrayLengthSlot = 1;
@ -710,6 +708,11 @@ struct BarrierMethods<T, EnableIfABOVType<T>> {
static gc::Cell* asGCThingOrNull(T view) {
return reinterpret_cast<gc::Cell*>(view.asObjectUnbarriered());
}
static void writeBarriers(T* viewp, T prev, T next) {
BarrierMethods<JSObject*>::writeBarriers(viewp->addressOfObject(),
prev.asObjectUnbarriered(),
next.asObjectUnbarriered());
}
static void postWriteBarrier(T* viewp, T prev, T next) {
BarrierMethods<JSObject*>::postWriteBarrier(viewp->addressOfObject(),
prev.asObjectUnbarriered(),

View File

@ -136,7 +136,7 @@ MSG_DEF(JSMSG_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class construc
MSG_DEF(JSMSG_BAD_HERITAGE, 2, JSEXN_TYPEERR, "class heritage {0} is {1}")
MSG_DEF(JSMSG_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0} is not an object or null")
MSG_DEF(JSMSG_CONSTRUCTOR_DISABLED, 1, JSEXN_TYPEERR, "{0} is disabled")
MSG_DEF(JSMSG_NO_DISPOSE_IN_USING, 0, JSEXN_TYPEERR, "'Symbol.dispose' property is not callable")
MSG_DEF(JSMSG_DISPOSE_NOT_CALLABLE, 0, JSEXN_TYPEERR, "'Symbol.dispose' property is not callable")
MSG_DEF(JSMSG_DISPOSABLE_NOT_OBJ, 0, JSEXN_TYPEERR, "Value to be disposed is not an object")
// JSON
@ -225,8 +225,11 @@ MSG_DEF(JSMSG_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "await is only valid
MSG_DEF(JSMSG_AWAIT_OUTSIDE_ASYNC_OR_MODULE, 0, JSEXN_SYNTAXERR, "await is only valid in async functions, async generators and modules")
MSG_DEF(JSMSG_TOP_LEVEL_AWAIT_NOT_SUPPORTED, 0, JSEXN_SYNTAXERR, "top level await is not supported in this context")
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
MSG_DEF(JSMSG_BAD_CLASS_MEMBER_DEF, 0, JSEXN_SYNTAXERR, "bad class member definition")
MSG_DEF(JSMSG_BAD_COALESCE_MIXING, 0, JSEXN_SYNTAXERR, "cannot use `??` unparenthesized within `||` and `&&` expressions")
MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration")
MSG_DEF(JSMSG_BAD_USING_DECL, 0, JSEXN_SYNTAXERR, "missing = in using declaration")
MSG_DEF(JSMSG_BAD_CONSTRUCTOR_DEF, 0, JSEXN_SYNTAXERR, "a class constructor definition must be a plain public method")
MSG_DEF(JSMSG_BAD_CONTINUE, 0, JSEXN_SYNTAXERR, "continue must be inside loop")
MSG_DEF(JSMSG_BAD_DESTRUCT_ASS, 0, JSEXN_SYNTAXERR, "invalid destructuring assignment operator")
MSG_DEF(JSMSG_BAD_DESTRUCT_TARGET, 0, JSEXN_SYNTAXERR, "invalid destructuring target")
@ -239,7 +242,6 @@ MSG_DEF(JSMSG_BAD_STARTING_FOROF_LHS, 1, JSEXN_SYNTAXERR, "an expression X in '
MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand")
MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 0, JSEXN_SYNTAXERR, "invalid assignment left-hand side")
MSG_DEF(JSMSG_BAD_LOCAL_STRING_EXPORT, 0, JSEXN_SYNTAXERR, "string exports can't be used without 'from'")
MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition")
MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unary expression can't appear on the left-hand side of '**'")
MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id")
MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function")
@ -258,6 +260,7 @@ MSG_DEF(JSMSG_BRACKET_OPENED, 2, JSEXN_NOTE, "[ opened at line {0}, col
MSG_DEF(JSMSG_CATCH_IDENTIFIER, 0, JSEXN_SYNTAXERR, "missing identifier in catch")
MSG_DEF(JSMSG_CATCH_OR_FINALLY, 0, JSEXN_SYNTAXERR, "missing catch or finally after try")
MSG_DEF(JSMSG_CATCH_WITHOUT_TRY, 0, JSEXN_SYNTAXERR, "catch without try")
MSG_DEF(JSMSG_CLASS_STATIC_PROTO, 0, JSEXN_SYNTAXERR, "a class may not have a static property named 'prototype'")
MSG_DEF(JSMSG_COLON_AFTER_CASE, 0, JSEXN_SYNTAXERR, "missing : after case label")
MSG_DEF(JSMSG_COLON_AFTER_ID, 0, JSEXN_SYNTAXERR, "missing : after property id")
MSG_DEF(JSMSG_COLON_IN_COND, 0, JSEXN_SYNTAXERR, "missing : in conditional expression")
@ -282,10 +285,10 @@ MSG_DEF(JSMSG_DEPRECATED_OCTAL_LITERAL,0, JSEXN_SYNTAXERR, "\"0\"-prefixed octal
MSG_DEF(JSMSG_DEPRECATED_OCTAL_ESCAPE ,0, JSEXN_SYNTAXERR, "octal escape sequences can't be used in untagged template literals or in strict mode code")
MSG_DEF(JSMSG_DEPRECATED_EIGHT_OR_NINE_ESCAPE, 0, JSEXN_SYNTAXERR, "the escapes \\8 and \\9 can't be used in untagged template literals or in strict mode code")
MSG_DEF(JSMSG_DEPRECATED_PRAGMA, 1, JSEXN_WARN, "Using //@ to indicate {0} pragmas is deprecated. Use //# instead")
MSG_DEF(JSMSG_DUPLICATE_CONSTRUCTOR, 0, JSEXN_SYNTAXERR, "a class cannot have more than one constructor definition")
MSG_DEF(JSMSG_DUPLICATE_EXPORT_NAME, 1, JSEXN_SYNTAXERR, "duplicate export name '{0}'")
MSG_DEF(JSMSG_DUPLICATE_FORMAL, 1, JSEXN_SYNTAXERR, "duplicate formal argument {0}")
MSG_DEF(JSMSG_DUPLICATE_LABEL, 0, JSEXN_SYNTAXERR, "duplicate label")
MSG_DEF(JSMSG_DUPLICATE_PROPERTY, 1, JSEXN_SYNTAXERR, "property name {0} appears more than once in object literal")
MSG_DEF(JSMSG_DUPLICATE_PROTO_PROPERTY, 0, JSEXN_SYNTAXERR, "property name __proto__ appears more than once in object literal")
MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 0, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?")
MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL,0, JSEXN_SYNTAXERR, "export declarations may only appear at top level of a module")
@ -328,7 +331,7 @@ MSG_DEF(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT, 0, JSEXN_SYNTAXERR, "expected n
MSG_DEF(JSMSG_NO_BINDING_NAME, 0, JSEXN_SYNTAXERR, "missing binding name")
MSG_DEF(JSMSG_NO_EXPORT_NAME, 0, JSEXN_SYNTAXERR, "missing export name")
MSG_DEF(JSMSG_NO_IMPORT_NAME, 0, JSEXN_SYNTAXERR, "missing import name")
MSG_DEF(JSMSG_NO_VARIABLE_NAME, 0, JSEXN_SYNTAXERR, "missing variable name")
MSG_DEF(JSMSG_NO_VARIABLE_NAME, 1, JSEXN_SYNTAXERR, "missing variable name, got {0}")
MSG_DEF(JSMSG_PAREN_AFTER_ARGS, 0, JSEXN_SYNTAXERR, "missing ) after argument list")
MSG_DEF(JSMSG_PAREN_AFTER_CATCH, 0, JSEXN_SYNTAXERR, "missing ) after catch")
MSG_DEF(JSMSG_PAREN_AFTER_COND, 0, JSEXN_SYNTAXERR, "missing ) after condition")
@ -388,7 +391,7 @@ MSG_DEF(JSMSG_BAD_LINE_NUMBER, 0, JSEXN_RANGEERR, "line number out of ra
MSG_DEF(JSMSG_BAD_NEWTARGET, 0, JSEXN_SYNTAXERR, "new.target only allowed within functions")
MSG_DEF(JSMSG_BAD_NEW_OPTIONAL, 0, JSEXN_SYNTAXERR, "new keyword cannot be used with an optional chain")
MSG_DEF(JSMSG_BAD_OPTIONAL_TEMPLATE, 0, JSEXN_SYNTAXERR, "tagged template cannot be used with optional chain")
MSG_DEF(JSMSG_IMPORT_ASSERTIONS_NOT_SUPPORTED, 0, JSEXN_SYNTAXERR, "import assertions are not currently supported")
MSG_DEF(JSMSG_IMPORT_ATTRIBUTES_NOT_SUPPORTED, 0, JSEXN_SYNTAXERR, "import attributes are not currently supported")
MSG_DEF(JSMSG_ILLEGAL_PRIVATE_FIELD, 0, JSEXN_SYNTAXERR, "private fields aren't valid in this context")
MSG_DEF(JSMSG_ILLEGAL_PRIVATE_NAME, 0, JSEXN_SYNTAXERR, "private names aren't valid in this context")
MSG_DEF(JSMSG_INVALID_PRIVATE_NAME_PRECEDENCE, 0, JSEXN_SYNTAXERR, "invalid use of private name due to operator precedence")
@ -419,10 +422,6 @@ MSG_DEF(JSMSG_CANT_CONVERT_TO_WIDE, 0, JSEXN_ERR, "can't convert to wide stri
MSG_DEF(JSMSG_CANT_CONVERT_WIDE_TO_UTF8, 0, JSEXN_ERR, "can't convert wide string to UTF-8")
MSG_DEF(JSMSG_CANT_CONVERT_UTF8_TO_WIDE, 0, JSEXN_ERR, "can't convert UTF-8 to wide string")
// SmooshMonkey
MSG_DEF(JSMSG_SMOOSH_COMPILE_ERROR, 1, JSEXN_SYNTAXERR, "{0}")
MSG_DEF(JSMSG_SMOOSH_UNIMPLEMENTED, 1, JSEXN_INTERNALERR, "{0}")
// asm.js
MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL, 1, JSEXN_TYPEERR, "asm.js type error: {0}")
MSG_DEF(JSMSG_USE_ASM_LINK_FAIL, 1, JSEXN_TYPEERR, "asm.js link error: {0}")
@ -437,7 +436,7 @@ MSG_DEF(JSMSG_WASM_COMPILE_ERROR, 1, JSEXN_WASMCOMPILEERROR, "{0}")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_TYPE, 2, JSEXN_WASMLINKERROR, "import object field '{0}' is not a {1}")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG, 2, JSEXN_WASMLINKERROR, "imported function '{0}.{1}' signature mismatch")
MSG_DEF(JSMSG_WASM_BAD_TAG_SIG, 2, JSEXN_WASMLINKERROR, "imported tag '{0}.{1}' signature mismatch")
MSG_DEF(JSMSG_WASM_BAD_IMP_INDEX, 1, JSEXN_WASMLINKERROR, "imported {0} with incompatible index type")
MSG_DEF(JSMSG_WASM_BAD_IMP_ADDRESS, 2, JSEXN_WASMLINKERROR, "imported {0} with incompatible address type {1}")
MSG_DEF(JSMSG_WASM_BAD_IMP_SIZE, 1, JSEXN_WASMLINKERROR, "imported {0} with incompatible size")
MSG_DEF(JSMSG_WASM_BAD_IMP_MAX, 1, JSEXN_WASMLINKERROR, "imported {0} with incompatible maximum size")
MSG_DEF(JSMSG_WASM_IMP_SHARED_REQD, 0, JSEXN_WASMLINKERROR, "imported unshared memory but shared required")
@ -464,6 +463,7 @@ MSG_DEF(JSMSG_WASM_ARRAY_IMP_LIMIT, 0, JSEXN_WASMRUNTIMEERROR, "too many arra
MSG_DEF(JSMSG_WASM_ARRAY_NEW_ELEM_NOT_IMPLEMENTED, 0, JSEXN_WASMRUNTIMEERROR, "array.new_elem does not yet support the expression encoding of element segments")
MSG_DEF(JSMSG_WASM_BAD_RANGE, 2, JSEXN_RANGEERR, "bad {0} {1}")
MSG_DEF(JSMSG_WASM_BAD_GROW, 1, JSEXN_RANGEERR, "failed to grow {0}")
MSG_DEF(JSMSG_WASM_MAX_LT_INITIAL, 1, JSEXN_RANGEERR, "initial {0} size cannot be greater than maximum")
MSG_DEF(JSMSG_WASM_TABLE_OUT_OF_BOUNDS, 0, JSEXN_WASMRUNTIMEERROR, "table index out of bounds")
MSG_DEF(JSMSG_WASM_BAD_ENFORCE_RANGE, 2, JSEXN_TYPEERR, "bad {0} {1}")
MSG_DEF(JSMSG_WASM_BAD_BUF_ARG, 0, JSEXN_TYPEERR, "first argument must be an ArrayBuffer or typed array object")
@ -485,15 +485,15 @@ MSG_DEF(JSMSG_WASM_BAD_ARRAYREF_VALUE, 0, JSEXN_TYPEERR, "can only pass a W
MSG_DEF(JSMSG_WASM_BAD_TYPEREF_VALUE, 0, JSEXN_TYPEERR, "bad type")
MSG_DEF(JSMSG_WASM_BAD_VAL_TYPE, 0, JSEXN_TYPEERR, "cannot pass value to or from JS")
MSG_DEF(JSMSG_WASM_BAD_STRING_VAL_TYPE, 0, JSEXN_TYPEERR, "bad value type")
MSG_DEF(JSMSG_WASM_BAD_STRING_IDX_TYPE, 0, JSEXN_TYPEERR, "bad index type")
MSG_DEF(JSMSG_WASM_BAD_STRING_ADDR_TYPE, 0, JSEXN_TYPEERR, "bad address type")
MSG_DEF(JSMSG_WASM_BAD_EXN_ARG, 0, JSEXN_TYPEERR, "first argument must be a WebAssembly.Tag")
MSG_DEF(JSMSG_WASM_BAD_EXN_PAYLOAD, 0, JSEXN_TYPEERR, "second argument must be an object")
MSG_DEF(JSMSG_WASM_BAD_EXN_PAYLOAD_LEN, 2, JSEXN_TYPEERR, "expected {0} values but got {1}")
MSG_DEF(JSMSG_WASM_BAD_EXN_TAG, 0, JSEXN_TYPEERR, "exception's tag did not match the provided exception tag")
MSG_DEF(JSMSG_WASM_BAD_EXN_OPTIONS, 0, JSEXN_TYPEERR, "argument cannot be converted to an ExceptionOptions")
MSG_DEF(JSMSG_WASM_BAD_FUNCTION_TYPE, 1, JSEXN_TYPEERR, "too many function {0}")
MSG_DEF(JSMSG_WASM_BAD_FUNCTION_VALUE, 0, JSEXN_TYPEERR, "second argument must be a function")
MSG_DEF(JSMSG_WASM_BAD_COMPILE_OPTIONS, 0, JSEXN_TYPEERR, "argument cannot be converted to a CompileOptions")
MSG_DEF(JSMSG_WASM_UNKNOWN_BUILTIN, 0, JSEXN_TYPEERR, "unknown builtin")
MSG_DEF(JSMSG_WASM_DUPLICATE_BUILTIN, 0, JSEXN_TYPEERR, "duplicate builtin")
MSG_DEF(JSMSG_WASM_BAD_CODEPOINT, 0, JSEXN_WASMRUNTIMEERROR, "bad codepoint")
MSG_DEF(JSMSG_WASM_NO_TRANSFER, 0, JSEXN_TYPEERR, "cannot transfer WebAssembly/asm.js ArrayBuffer")
@ -505,15 +505,22 @@ MSG_DEF(JSMSG_WASM_NONSHARED_WAIT, 0, JSEXN_WASMRUNTIMEERROR, "atomic wait o
MSG_DEF(JSMSG_WASM_SUPPLY_ONLY_ONE, 2, JSEXN_TYPEERR, "exactly one of {0} and {1} must be supplied")
MSG_DEF(JSMSG_WASM_MISSING_REQUIRED, 1, JSEXN_TYPEERR, "Missing required argument {0}")
MSG_DEF(JSMSG_WASM_MODIFIED_GC_OBJECT, 0, JSEXN_TYPEERR, "can't modify WebAssembly GC objects")
MSG_DEF(JSMSG_WASM_ARRAYBUFFER_PAGE_MULTIPLE, 0, JSEXN_RANGEERR, "can only grow by WebAssembly page multiples")
MSG_DEF(JSMSG_WASM_ARRAYBUFFER_CANNOT_SHRINK, 0, JSEXN_RANGEERR, "cannot shrink WebAssembly memory")
MSG_DEF(JSMSG_WASM_MEMORY_NOT_RESIZABLE, 0, JSEXN_TYPEERR, "WebAssembly memory non-resizable, maximum length is not provided")
// Wasm/asm.js deprecation warnings
MSG_DEF(JSMSG_WASM_LEGACY_EXCEPTIONS_DEPRECATED, 0, JSEXN_WARN, "The WebAssembly exception handling 'try' instruction is deprecated and should no longer be used. Please recompile to use the 'try_table' instruction instead.")
MSG_DEF(JSMSG_USE_ASM_DEPRECATED, 0, JSEXN_WARN, "asm.js is deprecated and should no longer be used. Please recompile using WebAssembly to get the best performance.")
// JSPI
MSG_DEF(JSMSG_JSPI_ARG_POSITION, 0, JSEXN_TYPEERR, "Invalid argument position value")
MSG_DEF(JSMSG_JSPI_INVALID_SUSPENDER, 0, JSEXN_WASMRUNTIMEERROR, "Invalid suspender")
MSG_DEF(JSMSG_JSPI_INVALID_STATE, 0, JSEXN_WASMRUNTIMEERROR, "Invalid state")
MSG_DEF(JSMSG_JSPI_INVALID_SUSPENDER, 0, IF_WASM_JSPI(JSEXN_WASMSUSPENDERROR, JSEXN_WASMRUNTIMEERROR), "Invalid suspender")
MSG_DEF(JSMSG_JSPI_INVALID_STATE, 0, IF_WASM_JSPI(JSEXN_WASMSUSPENDERROR, JSEXN_WASMRUNTIMEERROR), "Invalid state")
MSG_DEF(JSMSG_JSPI_EXPECTED_SUSPENDER, 0, JSEXN_TYPEERR, "Expected externref for suspender")
MSG_DEF(JSMSG_JSPI_EXPECTED_PROMISE, 0, JSEXN_TYPEERR, "Expected externref for returned promise")
MSG_DEF(JSMSG_JSPI_SIGNATURE_MISMATCH, 0, JSEXN_TYPEERR, "Signature mismatch")
MSG_DEF(JSMSG_JSPI_SUSPENDER_LIMIT, 0, JSEXN_WASMRUNTIMEERROR, "Too many suspenders")
MSG_DEF(JSMSG_JSPI_SUSPENDER_LIMIT, 0, IF_WASM_JSPI(JSEXN_WASMSUSPENDERROR, JSEXN_WASMRUNTIMEERROR), "Too many suspenders")
// Proxy
MSG_DEF(JSMSG_BAD_GETPROTOTYPEOF_TRAP_RETURN,0,JSEXN_TYPEERR,"proxy getPrototypeOf handler returned a non-object, non-null value")
@ -595,8 +602,10 @@ MSG_DEF(JSMSG_DEBUGGEE_WOULD_RUN, 2, JSEXN_DEBUGGEEWOULDRUN, "debuggee '{0}
MSG_DEF(JSMSG_NOT_CALLABLE_OR_UNDEFINED, 0, JSEXN_TYPEERR, "value is not a function or undefined")
MSG_DEF(JSMSG_NOT_TRACKING_ALLOCATIONS, 1, JSEXN_ERR, "Cannot call {0} without setting trackingAllocationSites to true")
MSG_DEF(JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET, 0, JSEXN_ERR, "Cannot track object allocation, because other tools are already doing so")
MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL, 0, JSEXN_TYPEERR, "findScripts query object with 'innermost' property must have 'line' and either 'displayURL', 'url', or 'source'")
MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL, 0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'displayURL', 'url', or 'source' property")
MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL, 0, JSEXN_TYPEERR, "findScripts query object with 'innermost' property must have 'line', or 'start' and 'end', and either 'displayURL', 'url', or 'source'")
MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL, 1, JSEXN_TYPEERR, "findScripts query object has {0}, but no 'displayURL', 'url', or 'source' property")
MSG_DEF(JSMSG_QUERY_USE_START_AND_END_TOGETHER, 0, JSEXN_ERR, "findScripts query object's 'start' and 'end' properties must be used together")
MSG_DEF(JSMSG_QUERY_START_LINE_IS_AFTER_END, 0, JSEXN_ERR, "findScripts query object's 'start.line' property is greater than its 'end.line' property, but it must be less than or equal to 'end.line'")
MSG_DEF(JSMSG_DEBUG_CANT_SET_OPT_ENV, 1, JSEXN_REFERENCEERR, "can't set '{0}' in an optimized-out environment")
MSG_DEF(JSMSG_DEBUG_INVISIBLE_COMPARTMENT, 0, JSEXN_TYPEERR, "object in compartment marked as invisible to Debugger")
MSG_DEF(JSMSG_DEBUG_CENSUS_BREAKDOWN, 1, JSEXN_TYPEERR, "unrecognized 'by' value in takeCensus breakdown: {0}")
@ -606,6 +615,8 @@ MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_FULFILLED, 0, JSEXN_TYPEERR, "Promise hasn't bee
MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_REJECTED, 0, JSEXN_TYPEERR, "Promise hasn't been rejected")
MSG_DEF(JSMSG_DEBUG_NO_BINARY_SOURCE, 0, JSEXN_ERR, "WebAssembly binary source is not available")
MSG_DEF(JSMSG_DEBUG_EXCLUSIVE_FRAME_COVERAGE, 0, JSEXN_ERR, "onEnterFrame and collectCoverageInfo cannot be active at the same time")
MSG_DEF(JSMSG_DEBUG_EXCLUSIVE_EXECUTION_TRACE_COVERAGE, 0, JSEXN_ERR, "execution trace and collectCoverageInfo cannot be active at the same time")
MSG_DEF(JSMSG_NATIVE_TRACING_BUFFER_MALFORMED, 0, JSEXN_ERR, "bad data encountered while reading the native tracing buffer")
// Testing functions
MSG_DEF(JSMSG_TESTING_SCRIPTS_ONLY, 0, JSEXN_TYPEERR, "only works on scripts")
@ -628,7 +639,7 @@ MSG_DEF(JSMSG_INVALID_LOCALE_MATCHER, 1, JSEXN_RANGEERR, "invalid locale matche
MSG_DEF(JSMSG_INVALID_OPTION_VALUE, 2, JSEXN_RANGEERR, "invalid value {1} for option {0}")
MSG_DEF(JSMSG_INVALID_TIME_ZONE, 1, JSEXN_RANGEERR, "invalid time zone in DateTimeFormat(): {0}")
MSG_DEF(JSMSG_INVALID_DATETIME_OPTION, 2, JSEXN_TYPEERR, "can't set option {0} when {1} is used")
MSG_DEF(JSMSG_INVALID_DATETIME_STYLE, 2, JSEXN_TYPEERR, "can't set option {0} in Date.{1}()")
MSG_DEF(JSMSG_INVALID_DATETIME_STYLE, 2, JSEXN_TYPEERR, "can't set option {0} for {1} formats")
MSG_DEF(JSMSG_UNDEFINED_CURRENCY, 0, JSEXN_TYPEERR, "undefined currency in NumberFormat() with currency style")
MSG_DEF(JSMSG_UNDEFINED_UNIT, 0, JSEXN_TYPEERR, "undefined unit in NumberFormat() with unit style")
MSG_DEF(JSMSG_UNDEFINED_DATE, 2, JSEXN_TYPEERR, "undefined {0}-date in DateTimeFormat.{1}()")
@ -637,6 +648,16 @@ MSG_DEF(JSMSG_UNDEFINED_TYPE, 0, JSEXN_TYPEERR, "missing \"type\" optio
MSG_DEF(JSMSG_NAN_NUMBER_RANGE, 3, JSEXN_RANGEERR, "range can't {0} with NaN in {1}.{2}()")
MSG_DEF(JSMSG_INVALID_NUMBER_OPTION, 2, JSEXN_TYPEERR, "can't set option {0} when {1} is used")
MSG_DEF(JSMSG_UNEQUAL_FRACTION_DIGITS, 0, JSEXN_RANGEERR, "fraction digits must be the same when roundingIncrement is used")
MSG_DEF(JSMSG_INTL_DURATION_INVALID_NON_NUMERIC_OPTION, 2, JSEXN_RANGEERR, "invalid non-numeric value {0} for option {1}")
MSG_DEF(JSMSG_INTL_DURATION_INVALID_DISPLAY_OPTION, 1, JSEXN_RANGEERR, "{0} can't use \"numeric\" style with \"always\" display")
MSG_DEF(JSMSG_INTL_DURATION_INVALID_DISPLAY_OPTION_DEFAULT_STYLE, 1, JSEXN_RANGEERR, "{0} can't use \"always\" display when style defaults to \"numeric\"")
MSG_DEF(JSMSG_INTL_DURATION_INVALID_DISPLAY_OPTION_DEFAULT_DISPLAY, 1, JSEXN_RANGEERR, "{0} can't use \"numeric\" style when display defaults to \"always\"")
MSG_DEF(JSMSG_INTL_DURATION_NOT_INTEGER, 1, JSEXN_RANGEERR, "{0} isn't a valid duration value because it isn't an integer")
MSG_DEF(JSMSG_INTL_DURATION_INVALID_SIGN, 0, JSEXN_RANGEERR, "duration elements must have the same sign")
MSG_DEF(JSMSG_INTL_DURATION_INVALID_LIMIT, 0, JSEXN_RANGEERR, "duration elements must be below valid limits")
MSG_DEF(JSMSG_INTL_DURATION_MISSING_UNIT, 0, JSEXN_TYPEERR, "Duration-like objects must have at least one duration unit")
MSG_DEF(JSMSG_INTL_DURATION_UNEXPECTED_STRING, 0, JSEXN_RANGEERR, "duration can't be a string")
MSG_DEF(JSMSG_INVALID_FORMAT_OPTIONS, 1, JSEXN_TYPEERR, "can't format {0} using the requested options")
// RegExp
MSG_DEF(JSMSG_BAD_CLASS_RANGE, 0, JSEXN_SYNTAXERR, "invalid range in character class")
@ -644,6 +665,8 @@ MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 0, JSEXN_SYNTAXERR, "\\ at end of pattern
MSG_DEF(JSMSG_EXEC_NOT_OBJORNULL, 0, JSEXN_TYPEERR, "RegExp exec method should return object or null")
MSG_DEF(JSMSG_INVALID_DECIMAL_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid decimal escape in regular expression")
MSG_DEF(JSMSG_INVALID_GROUP, 0, JSEXN_SYNTAXERR, "invalid regexp group")
MSG_DEF(JSMSG_REPEATED_FLAG, 0, JSEXN_SYNTAXERR, "repeated flag in regexp modifier")
MSG_DEF(JSMSG_INVALID_FLAG_GROUP, 0, JSEXN_SYNTAXERR, "invalid flag group")
MSG_DEF(JSMSG_INVALID_IDENTITY_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid identity escape in regular expression")
MSG_DEF(JSMSG_INVALID_UNICODE_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid unicode escape in regular expression")
MSG_DEF(JSMSG_MISSING_PAREN, 0, JSEXN_SYNTAXERR, "unterminated parenthetical")
@ -668,6 +691,7 @@ MSG_DEF(JSMSG_INCOMPATIBLE_REGEXP_GETTER, 2, JSEXN_TYPEERR, "RegExp.prototype.{
MSG_DEF(JSMSG_INVALID_CLASS_SET_OP, 0, JSEXN_SYNTAXERR, "invalid class set operation in regular expression")
MSG_DEF(JSMSG_INVALID_CHAR_IN_CLASS, 0, JSEXN_SYNTAXERR, "invalid character in class in regular expression")
MSG_DEF(JSMSG_NEGATED_CLASS_WITH_STR, 0, JSEXN_SYNTAXERR, "negated character class with strings in regular expression")
MSG_DEF(JSMSG_MULTIPLE_FLAG_DASHES, 0, JSEXN_SYNTAXERR, "multiple dashes in flag group")
// Typed object
MSG_DEF(JSMSG_TYPEDOBJECT_SETTING_IMMUTABLE, 0, JSEXN_ERR, "setting immutable field")
@ -726,6 +750,7 @@ MSG_DEF(JSMSG_SYMBOL_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert symbol t
// Atomics and futexes
MSG_DEF(JSMSG_ATOMICS_BAD_ARRAY, 0, JSEXN_TYPEERR, "invalid array type for the operation")
MSG_DEF(JSMSG_ATOMICS_WAIT_NOT_ALLOWED, 0, JSEXN_TYPEERR, "waiting is not allowed on this thread")
MSG_DEF(JSMSG_ATOMICS_PAUSE_BAD_COUNT, 0, JSEXN_TYPEERR, "Atomics.pause called with non-integral Number")
// XPConnect wrappers and DOM bindings
MSG_DEF(JSMSG_CANT_SET_INTERPOSED, 1, JSEXN_TYPEERR, "unable to set interposed data property '{0}'")
@ -733,7 +758,7 @@ MSG_DEF(JSMSG_CANT_DEFINE_WINDOW_ELEMENT, 0, JSEXN_TYPEERR, "can't define elemen
MSG_DEF(JSMSG_CANT_DELETE_WINDOW_ELEMENT, 0, JSEXN_TYPEERR, "can't delete elements from a Window object")
MSG_DEF(JSMSG_CANT_DEFINE_WINDOW_NAMED_PROPERTY, 1, JSEXN_TYPEERR, "can't define property {0} on window's named properties object")
MSG_DEF(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY, 1, JSEXN_TYPEERR, "can't delete property {0} from window's named properties object")
MSG_DEF(JSMSG_CANT_PREVENT_EXTENSIONS, 0, JSEXN_TYPEERR, "can't prevent extensions on this proxy object")
MSG_DEF(JSMSG_CANT_PREVENT_EXTENSIONS, 0, JSEXN_TYPEERR, "can't prevent extensions on this object")
MSG_DEF(JSMSG_CANT_DEFINE_WINDOW_NC, 0, JSEXN_TYPEERR, "can't define non-configurable property on WindowProxy")
MSG_DEF(JSMSG_NO_NAMED_SETTER, 2, JSEXN_TYPEERR, "{0} doesn't have a named property setter for '{1}'")
MSG_DEF(JSMSG_NO_INDEXED_SETTER, 2, JSEXN_TYPEERR, "{0} doesn't have an indexed property setter for '{1}'")
@ -759,6 +784,7 @@ MSG_DEF(JSMSG_IMPORT_MAPS_NOT_A_MAP, 0, JSEXN_TYPEERR, "the top-level value need
MSG_DEF(JSMSG_IMPORT_MAPS_IMPORTS_NOT_A_MAP, 0, JSEXN_TYPEERR, "the imports top-level key needs to be a JSON object")
MSG_DEF(JSMSG_IMPORT_MAPS_SCOPES_NOT_A_MAP, 0, JSEXN_TYPEERR, "the scopes top-level key needs to be a JSON object")
MSG_DEF(JSMSG_IMPORT_MAPS_SCOPE_VALUE_NOT_A_MAP, 1, JSEXN_TYPEERR, "the value of the scope with prefix '{0}' needs to be a JSON object")
MSG_DEF(JSMSG_IMPORT_MAPS_INTEGRITY_NOT_A_MAP, 0, JSEXN_TYPEERR, "the integrity top-level key needs to be a JSON object")
// Import Attributes
MSG_DEF(JSMSG_IMPORT_ATTRIBUTES_STATIC_IMPORT_UNSUPPORTED_ATTRIBUTE, 1, JSEXN_SYNTAXERR, "Unsupported import attribute: {0}")
@ -785,29 +811,6 @@ MSG_DEF(JSMSG_NOT_AN_ASYNC_GENERATOR, 0, JSEXN_TYPEERR, "Not an async generator
MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.asyncIterator]() returned a non-object value")
MSG_DEF(JSMSG_SUSPENDED_QUEUE_NOT_EMPTY, 0, JSEXN_INTERNALERR, "Async generator is in invalid state due to debugger interaction")
// ReadableStream
MSG_DEF(JSMSG_READABLESTREAM_UNDERLYINGSOURCE_TYPE_WRONG,0, JSEXN_RANGEERR,"'underlyingSource.type' must be \"bytes\" or undefined.")
MSG_DEF(JSMSG_READABLESTREAM_BYTES_TYPE_NOT_IMPLEMENTED, 0, JSEXN_RANGEERR,"support for 'new ReadableStream({ type: \"bytes\" })' is not yet implemented")
MSG_DEF(JSMSG_READABLESTREAM_BYOB_READER_FOR_NON_BYTE_STREAM,0,JSEXN_TYPEERR,"can't get a BYOB reader for a non-byte stream")
MSG_DEF(JSMSG_READABLESTREAM_INVALID_READER_MODE, 0, JSEXN_TYPEERR,"'mode' must be \"byob\" or undefined.")
MSG_DEF(JSMSG_NUMBER_MUST_BE_FINITE_NON_NEGATIVE, 1, JSEXN_RANGEERR, "'{0}' must be a finite, non-negative number.")
MSG_DEF(JSMSG_READABLESTREAM_LOCKED_METHOD, 1, JSEXN_TYPEERR, "'{0}' can't be called on a locked stream.")
MSG_DEF(JSMSG_READABLESTREAM_LOCKED, 0, JSEXN_TYPEERR, "A Reader may only be created for an unlocked ReadableStream.")
MSG_DEF(JSMSG_READABLESTREAM_NOT_DEFAULT_CONTROLLER, 1, JSEXN_TYPEERR, "{0} requires a ReadableStreamDefaultController.")
MSG_DEF(JSMSG_READABLESTREAMREADER_NOT_OWNED, 1, JSEXN_TYPEERR, "The ReadableStream reader method '{0}' may only be called on a reader owned by a stream.")
MSG_DEF(JSMSG_READABLESTREAMREADER_NOT_EMPTY, 1, JSEXN_TYPEERR, "The ReadableStream reader method '{0}' may not be called on a reader with read requests.")
MSG_DEF(JSMSG_READABLESTREAMREADER_RELEASED, 0, JSEXN_TYPEERR, "The ReadableStream reader was released.")
MSG_DEF(JSMSG_READABLESTREAMCONTROLLER_CLOSED, 1, JSEXN_TYPEERR, "'{0}' called on a stream already closing.")
MSG_DEF(JSMSG_READABLESTREAMCONTROLLER_NOT_READABLE, 1, JSEXN_TYPEERR, "'{0}' may only be called on a stream in the 'readable' state.")
MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_BAD_CHUNKSIZE,0, JSEXN_RANGEERR, "ReadableByteStreamController requires a positive integer or undefined for 'autoAllocateChunkSize'.")
MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_BAD_CHUNK, 1, JSEXN_TYPEERR, "{0} passed a bad chunk.")
MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_CLOSE_PENDING_PULL, 0, JSEXN_TYPEERR, "The ReadableByteStreamController cannot be closed while the buffer is being filled.")
// Other Stream-related
MSG_DEF(JSMSG_STREAM_MISSING_HIGHWATERMARK, 0, JSEXN_TYPEERR, "'highWaterMark' must not be undefined.")
MSG_DEF(JSMSG_STREAM_INVALID_HIGHWATERMARK, 0, JSEXN_RANGEERR, "'highWaterMark' must be a non-negative, non-NaN number.")
MSG_DEF(JSMSG_STREAM_CONSUME_ERROR, 0, JSEXN_TYPEERR, "error consuming stream body")
// (wasm) Response-related
MSG_DEF(JSMSG_WASM_ERROR_CONSUMING_RESPONSE, 0, JSEXN_TYPEERR, "WebAssembly: There was an error consuming the Response")
MSG_DEF(JSMSG_WASM_BAD_RESPONSE_VALUE, 0, JSEXN_TYPEERR, "WebAssembly: Expected Response or Promise resolving to Response")
@ -841,15 +844,6 @@ MSG_DEF(JSMSG_NEGATIVE_LIMIT, 0, JSEXN_RANGEERR, "Ite
// Set
MSG_DEF(JSMSG_SET_NEGATIVE_SIZE, 0, JSEXN_RANGEERR, "Set size must be non-negative")
// Record and Tuple
MSG_DEF(JSMSG_RECORD_TUPLE_NO_OBJECT, 0, JSEXN_TYPEERR, "Record and Tuple can only contain primitive values")
MSG_DEF(JSMSG_RECORD_NO_PROTO, 0, JSEXN_SYNTAXERR, "__proto__ is not a valid literal key in records")
MSG_DEF(JSMSG_RECORD_NO_SYMBOL_KEY, 0, JSEXN_TYPEERR, "Symbols cannot be used as record keys")
MSG_DEF(JSMSG_BAD_TUPLE_INDEX, 0, JSEXN_RANGEERR, "index out of range for tuple")
MSG_DEF(JSMSG_BAD_TUPLE_OBJECT, 0, JSEXN_TYPEERR, "value of TupleObject must be a Tuple")
MSG_DEF(JSMSG_RECORD_TUPLE_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert Record or Tuple to number")
// Shadow Realms
MSG_DEF(JSMSG_NOT_SHADOW_REALM, 0, JSEXN_TYPEERR, "Object is not a ShadowRealm")
MSG_DEF(JSMSG_SHADOW_REALM_EVALUATE_NOT_STRING, 0, JSEXN_TYPEERR, "a ShadowRealm can only evaluate a string")
@ -872,86 +866,109 @@ MSG_DEF(JSMSG_TEMPORAL_INVALID_UNIT_RANGE, 0, JSEXN_RANGEERR, "smallest
MSG_DEF(JSMSG_TEMPORAL_INVALID_UNIT_OPTION, 2, JSEXN_RANGEERR, "{0} is not a valid {1} option in this context")
MSG_DEF(JSMSG_TEMPORAL_INVALID_NUMBER, 1, JSEXN_RANGEERR, "{0} must be larger than zero")
MSG_DEF(JSMSG_TEMPORAL_INVALID_INTEGER, 1, JSEXN_RANGEERR, "{0} must be an integer")
MSG_DEF(JSMSG_TEMPORAL_INVALID_OBJECT, 2, JSEXN_TYPEERR, "{0} must not be a {1} object")
MSG_DEF(JSMSG_TEMPORAL_MISSING_OPTION, 1, JSEXN_RANGEERR, "undefined {0} option")
MSG_DEF(JSMSG_TEMPORAL_MISSING_PROPERTY, 1, JSEXN_TYPEERR, "{0} property is undefined")
MSG_DEF(JSMSG_TEMPORAL_UNEXPECTED_PROPERTY, 1, JSEXN_TYPEERR, "{0} property is not undefined")
MSG_DEF(JSMSG_TEMPORAL_MISSING_OPTION, 1, JSEXN_RANGEERR, "required option {0} is undefined")
MSG_DEF(JSMSG_TEMPORAL_MISSING_PROPERTY, 1, JSEXN_TYPEERR, "required property {0} is undefined")
MSG_DEF(JSMSG_TEMPORAL_UNEXPECTED_PROPERTY, 1, JSEXN_TYPEERR, "expected property {0} to be undefined")
MSG_DEF(JSMSG_TEMPORAL_MISSING_TEMPORAL_FIELDS, 0, JSEXN_TYPEERR, "object must have at least one temporal property")
MSG_DEF(JSMSG_TEMPORAL_DUPLICATE_PROPERTY, 1, JSEXN_RANGEERR, "duplicate property name \"{0}\"")
MSG_DEF(JSMSG_TEMPORAL_INVALID_PROPERTY, 1, JSEXN_RANGEERR, "invalid property name \"{0}\"")
MSG_DEF(JSMSG_TEMPORAL_INSTANT_INVALID, 0, JSEXN_RANGEERR, "epoch nanoseconds too large")
MSG_DEF(JSMSG_TEMPORAL_INSTANT_NONINTEGER, 1, JSEXN_RANGEERR, "Instant must be an integer, but received {0}")
MSG_DEF(JSMSG_TEMPORAL_INSTANT_BAD_DURATION, 1, JSEXN_RANGEERR, "duration \"{0}\" property must be zero")
MSG_DEF(JSMSG_TEMPORAL_TIMEZONE_INVALID_IDENTIFIER, 1, JSEXN_RANGEERR, "invalid time zone: {0}")
MSG_DEF(JSMSG_TEMPORAL_TIMEZONE_NANOS_RANGE, 1, JSEXN_RANGEERR, "nanoseconds out of range: {0}")
MSG_DEF(JSMSG_TEMPORAL_TIMEZONE_INCOMPATIBLE, 2, JSEXN_RANGEERR, "time zones \"{0}\" and \"{1}\" aren't compatible")
MSG_DEF(JSMSG_TEMPORAL_TIMEZONE_INSTANT_AMBIGUOUS, 0, JSEXN_RANGEERR, "instant is ambiguous")
MSG_DEF(JSMSG_TEMPORAL_TIMEZONE_OFFSET_SHIFT_ONE_DAY, 0, JSEXN_RANGEERR, "time zone offset shift must not exceed a 24-hour span")
MSG_DEF(JSMSG_TEMPORAL_DURATION_INVALID_SIGN, 2, JSEXN_RANGEERR, "duration value \"{0}\" has a mismatched sign: {1}")
MSG_DEF(JSMSG_TEMPORAL_DURATION_INVALID_NON_FINITE, 2, JSEXN_RANGEERR, "duration value \"{0}\" is {1}")
MSG_DEF(JSMSG_TEMPORAL_DURATION_INVALID_NORMALIZED_TIME, 0, JSEXN_RANGEERR, "time duration values must be lower than 2**53 seconds")
MSG_DEF(JSMSG_TEMPORAL_DURATION_INVALID_NON_FINITE, 2, JSEXN_RANGEERR, "duration value \"{0}\" is non-finite: {1}")
MSG_DEF(JSMSG_TEMPORAL_DURATION_INVALID_NORMALIZED_TIME, 0, JSEXN_RANGEERR, "time duration values must be smaller than 2**53 seconds")
MSG_DEF(JSMSG_TEMPORAL_DURATION_MISSING_UNIT, 0, JSEXN_TYPEERR, "Duration-like objects must have at least one duration unit")
MSG_DEF(JSMSG_TEMPORAL_DURATION_NOT_INTEGER, 2, JSEXN_RANGEERR, "{0} isn't a valid {1} duration because it isn't an integer")
MSG_DEF(JSMSG_TEMPORAL_DURATION_MISSING_UNIT_SPECIFIER, 0, JSEXN_RANGEERR, "at least one of \"smallestUnit\" and \"largestUnit\" must be present")
MSG_DEF(JSMSG_TEMPORAL_DURATION_UNCOMPARABLE, 1, JSEXN_RANGEERR, "can't compare durations when \"{0}\" is undefined")
MSG_DEF(JSMSG_TEMPORAL_DURATION_COMBINE_INVALID_SIGN, 0, JSEXN_RANGEERR, "can't combine date- and time-durations with different signs")
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_INVALID_ID, 1, JSEXN_RANGEERR, "invalid calendar: {0}")
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_MISSING_FIELD, 1, JSEXN_TYPEERR, "missing \"{0}\" calendar field")
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_INVALID_FIELD, 1, JSEXN_RANGEERR, "invalid calendar field name \"{0}\"")
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_DUPLICATE_FIELD, 1, JSEXN_RANGEERR, "duplicate calendar field \"{0}\"")
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_OVERFLOW_FIELD, 2, JSEXN_RANGEERR, "calendar field \"{0}\" is too large: {1}")
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_INVALID_MONTHCODE, 1, JSEXN_RANGEERR, "invalid \"monthCode\" calendar field: {0}")
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_INVALID_ERA, 1, JSEXN_RANGEERR, "invalid \"era\" calendar field: {0}")
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_INCOMPATIBLE, 2, JSEXN_RANGEERR, "calendars \"{0}\" and \"{1}\" aren't compatible")
MSG_DEF(JSMSG_TEMPORAL_PLAIN_DATE_INVALID, 0, JSEXN_RANGEERR, "year-month-day must be valid iso dates")
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_INCOMPATIBLE_YEAR, 2, JSEXN_RANGEERR, "\"year\" and computed \"year\" calendar fields are inconsistent: {0} - {1}")
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_INCOMPATIBLE_MONTHCODE, 2, JSEXN_RANGEERR, "\"monthCode\" and \"month\" calendar fields are inconsistent: {0} - {1}")
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_INTERNAL_ERROR, 0, JSEXN_ERR, "internal error while computing calendar data")
MSG_DEF(JSMSG_TEMPORAL_PLAIN_DATE_INVALID, 0, JSEXN_RANGEERR, "year-month-day must be valid ISO date values")
MSG_DEF(JSMSG_TEMPORAL_PLAIN_DATE_INVALID_VALUE, 4, JSEXN_RANGEERR, "date value \"{0}\" not in {1}..{2}: {3}")
MSG_DEF(JSMSG_TEMPORAL_PLAIN_DATE_TIME_INVALID, 0, JSEXN_RANGEERR, "arguments must be valid ISO date-time values")
MSG_DEF(JSMSG_TEMPORAL_PLAIN_TIME_INVALID, 0, JSEXN_RANGEERR, "arguments must be valid ISO time values")
MSG_DEF(JSMSG_TEMPORAL_PLAIN_TIME_INVALID_VALUE, 4, JSEXN_RANGEERR, "time value \"{0}\" not in {1}..{2}: {3}")
MSG_DEF(JSMSG_TEMPORAL_PLAIN_TIME_MISSING_UNIT, 0, JSEXN_TYPEERR, "Time-like objects must have at least one time unit")
MSG_DEF(JSMSG_TEMPORAL_PLAIN_TIME_CALENDAR_NOT_ISO8601, 1, JSEXN_RANGEERR, "PlainTime only supports the \"iso8601\" calendar: {0}")
MSG_DEF(JSMSG_TEMPORAL_PLAIN_MONTH_DAY_INVALID, 0, JSEXN_RANGEERR, "year-month-day must be valid iso dates")
MSG_DEF(JSMSG_TEMPORAL_PLAIN_YEAR_MONTH_INVALID, 0, JSEXN_RANGEERR, "year-month-day must be valid iso dates")
MSG_DEF(JSMSG_TEMPORAL_PLAIN_MONTH_DAY_INVALID, 0, JSEXN_RANGEERR, "month-day must be valid ISO date values")
MSG_DEF(JSMSG_TEMPORAL_PLAIN_YEAR_MONTH_INVALID, 0, JSEXN_RANGEERR, "year-month must be valid ISO date values")
MSG_DEF(JSMSG_TEMPORAL_ZONED_DATE_TIME_NO_TIME_FOUND, 0, JSEXN_RANGEERR, "date-time can't be represented in the given time zone")
MSG_DEF(JSMSG_TEMPORAL_ZONED_DATE_TIME_INCORRECT_SIGN, 1, JSEXN_RANGEERR, "computed {0} has an incorrect sign")
MSG_DEF(JSMSG_TEMPORAL_ZONED_DATE_TIME_INCONSISTENT_INSTANT, 0, JSEXN_RANGEERR, "time zone computed inconsistent instant values")
MSG_DEF(JSMSG_TEMPORAL_PARSER_NEGATIVE_ZERO_YEAR, 0, JSEXN_RANGEERR, "year 0 must not start with \"-\"")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_EXTENDED_YEAR, 0, JSEXN_RANGEERR, "signed year must be followed by six digits")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_YEAR, 0, JSEXN_RANGEERR, "missing four digit year")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_MONTH, 0, JSEXN_RANGEERR, "missing two digit month")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_DAY, 0, JSEXN_RANGEERR, "missing two digit day")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_HOUR, 0, JSEXN_RANGEERR, "missing two digit hour")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_MINUTE, 0, JSEXN_RANGEERR, "missing two digit minute")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_SECOND, 0, JSEXN_RANGEERR, "missing two digit second")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_TIMEZONE_SIGN, 0, JSEXN_RANGEERR, "missing time zone sign")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_MONTH, 0, JSEXN_RANGEERR, "month must be a number from 1 to 12")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_DAY, 0, JSEXN_RANGEERR, "day must be a number from 1 to 31")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_HOUR, 0, JSEXN_RANGEERR, "hour must be a number from 0 to 23")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_MINUTE, 0, JSEXN_RANGEERR, "minute must be a number from 0 to 59")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_SECOND, 0, JSEXN_RANGEERR, "second must be a number from 0 to 59")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_LEAPSECOND, 0, JSEXN_RANGEERR, "second must be a number from 0 to 60")
MSG_DEF(JSMSG_TEMPORAL_PARSER_BRACKET_BEFORE_TIMEZONE, 0, JSEXN_RANGEERR, "missing '[' before time zone annotation")
MSG_DEF(JSMSG_TEMPORAL_PARSER_BRACKET_AFTER_TIMEZONE, 0, JSEXN_RANGEERR, "missing ']' after time zone annotation")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_TIMEZONE, 0, JSEXN_RANGEERR, "missing time zone")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_TIMEZONE_NAME, 0, JSEXN_RANGEERR, "missing time zone name")
MSG_DEF(JSMSG_TEMPORAL_PARSER_GARBAGE_AFTER_INPUT, 0, JSEXN_RANGEERR, "unexpected garbage after end of input")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_DURATION_DESIGNATOR, 0, JSEXN_RANGEERR, "missing duration designator 'P'")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_TIME_DESIGNATOR, 0, JSEXN_RANGEERR, "missing time designator 'T'")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_DURATION_DIGITS, 0, JSEXN_RANGEERR, "missing duration digits")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_DURATION_MINUTES, 0, JSEXN_RANGEERR, "invalid duration minutes after fractional hours")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_DURATION_SECONDS, 0, JSEXN_RANGEERR, "invalid duration seconds after fractional hours or minutes")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_ANNOTATION_KEY, 0, JSEXN_RANGEERR, "invalid annotation key")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_ANNOTATION_VALUE, 0, JSEXN_RANGEERR, "invalid annotation value")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_CALENDAR_NAME, 0, JSEXN_RANGEERR, "invalid calendar name")
MSG_DEF(JSMSG_TEMPORAL_PARSER_BRACKET_BEFORE_ANNOTATION, 0, JSEXN_RANGEERR, "missing ']' before annotation")
MSG_DEF(JSMSG_TEMPORAL_PARSER_BRACKET_AFTER_ANNOTATION, 0, JSEXN_RANGEERR, "missing ']' after annotation")
MSG_DEF(JSMSG_TEMPORAL_PARSER_ASSIGNMENT_IN_ANNOTATION, 0, JSEXN_RANGEERR, "missing '=' in annotation")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_CRITICAL_ANNOTATION, 0, JSEXN_RANGEERR, "unexpected critical annotation")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_DATE_TIME_SEPARATOR, 0, JSEXN_RANGEERR, "missing date-time separator 'T'")
MSG_DEF(JSMSG_TEMPORAL_PARSER_AMBIGUOUS_TIME_MONTH_DAY, 0, JSEXN_RANGEERR, "time is ambiguous with a month-day")
MSG_DEF(JSMSG_TEMPORAL_PARSER_AMBIGUOUS_TIME_YEAR_MONTH, 0, JSEXN_RANGEERR, "time is ambiguous with a year-month")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_UTC_DESIGNATOR, 0, JSEXN_RANGEERR, "unexpected UTC designator 'Z'")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_UTC_DESIGNATOR_WITHOUT_NAME, 0, JSEXN_RANGEERR, "unexpected UTC designator 'Z' without a bracketed time zone")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MONTH_DAY_CALENDAR_NOT_ISO8601, 0, JSEXN_RANGEERR, "Month-Day formats only support the \"iso8601\" calendar")
MSG_DEF(JSMSG_TEMPORAL_PARSER_YEAR_MONTH_CALENDAR_NOT_ISO8601, 0, JSEXN_RANGEERR, "Year-Month formats only support the \"iso8601\" calendar")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_SUBMINUTE_TIMEZONE, 0, JSEXN_RANGEERR, "time zone offset must not contain seconds precision")
MSG_DEF(JSMSG_TEMPORAL_PARSER_NEGATIVE_ZERO_YEAR, 1, JSEXN_RANGEERR, "can't parse {0}: year 0 must not start with \"-\"")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_EXTENDED_YEAR, 1, JSEXN_RANGEERR, "can't parse {0}: signed year must be followed by six digits")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_YEAR, 1, JSEXN_RANGEERR, "can't parse {0}: missing four digit year")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_MONTH, 1, JSEXN_RANGEERR, "can't parse {0}: missing two digit month")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_DAY, 1, JSEXN_RANGEERR, "can't parse {0}: missing two digit day")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_HOUR, 1, JSEXN_RANGEERR, "can't parse {0}: missing two digit hour")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_MINUTE, 1, JSEXN_RANGEERR, "can't parse {0}: missing two digit minute")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_SECOND, 1, JSEXN_RANGEERR, "can't parse {0}: missing two digit second")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_TIMEZONE_SIGN, 1, JSEXN_RANGEERR, "can't parse {0}: missing time zone sign")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_MONTH, 1, JSEXN_RANGEERR, "can't parse {0}: month must be a number from 1 to 12")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_DAY, 1, JSEXN_RANGEERR, "can't parse {0}: day must be a number from 1 to 31")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_HOUR, 1, JSEXN_RANGEERR, "can't parse {0}: hour must be a number from 0 to 23")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_MINUTE, 1, JSEXN_RANGEERR, "can't parse {0}: minute must be a number from 0 to 59")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_SECOND, 1, JSEXN_RANGEERR, "can't parse {0}: second must be a number from 0 to 59")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_LEAPSECOND, 1, JSEXN_RANGEERR, "can't parse {0}: second must be a number from 0 to 60")
MSG_DEF(JSMSG_TEMPORAL_PARSER_BRACKET_BEFORE_TIMEZONE, 1, JSEXN_RANGEERR, "can't parse {0}: missing '[' before time zone annotation")
MSG_DEF(JSMSG_TEMPORAL_PARSER_BRACKET_AFTER_TIMEZONE, 1, JSEXN_RANGEERR, "can't parse {0}: missing ']' after time zone annotation")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_TIMEZONE, 1, JSEXN_RANGEERR, "can't parse {0}: missing time zone")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_TIMEZONE_NAME, 1, JSEXN_RANGEERR, "can't parse {0}: missing time zone name")
MSG_DEF(JSMSG_TEMPORAL_PARSER_UNEXPECTED_CHARACTERS_AT_END, 1, JSEXN_RANGEERR, "can't parse {0}: unexpected characters at end of string")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_DURATION_DESIGNATOR, 1, JSEXN_RANGEERR, "can't parse {0}: missing duration designator 'P'")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_TIME_DESIGNATOR, 1, JSEXN_RANGEERR, "can't parse {0}: missing time designator 'T'")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_DURATION_DIGITS, 1, JSEXN_RANGEERR, "can't parse {0}: missing duration digits")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_DURATION_UNIT_DESIGNATOR, 1, JSEXN_RANGEERR, "can't parse {0}: missing duration unit designator")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_DURATION_MINUTES, 1, JSEXN_RANGEERR, "can't parse {0}: invalid duration minutes after fractional hours")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_DURATION_SECONDS, 1, JSEXN_RANGEERR, "can't parse {0}: invalid duration seconds after fractional hours or minutes")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_ANNOTATION_KEY, 1, JSEXN_RANGEERR, "can't parse {0}: invalid annotation key")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_ANNOTATION_VALUE, 1, JSEXN_RANGEERR, "can't parse {0}: invalid annotation value")
MSG_DEF(JSMSG_TEMPORAL_PARSER_BRACKET_BEFORE_ANNOTATION, 1, JSEXN_RANGEERR, "can't parse {0}: missing '[' before annotation")
MSG_DEF(JSMSG_TEMPORAL_PARSER_BRACKET_AFTER_ANNOTATION, 1, JSEXN_RANGEERR, "can't parse {0}: missing ']' after annotation")
MSG_DEF(JSMSG_TEMPORAL_PARSER_ASSIGNMENT_IN_ANNOTATION, 1, JSEXN_RANGEERR, "can't parse {0}: missing '=' in annotation")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_CRITICAL_ANNOTATION, 1, JSEXN_RANGEERR, "can't parse {0}: unexpected critical annotation")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_DATE_TIME_SEPARATOR, 1, JSEXN_RANGEERR, "can't parse {0}: missing date-time separator 'T'")
MSG_DEF(JSMSG_TEMPORAL_PARSER_AMBIGUOUS_TIME_MONTH_DAY, 1, JSEXN_RANGEERR, "can't parse {0}: time is ambiguous with a month-day")
MSG_DEF(JSMSG_TEMPORAL_PARSER_AMBIGUOUS_TIME_YEAR_MONTH, 1, JSEXN_RANGEERR, "can't parse {0}: time is ambiguous with a year-month")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_UTC_DESIGNATOR, 1, JSEXN_RANGEERR, "can't parse {0}: unexpected UTC designator 'Z'")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_UTC_DESIGNATOR_WITHOUT_NAME, 1, JSEXN_RANGEERR, "can't parse {0}: unexpected UTC designator 'Z' without a bracketed time zone")
MSG_DEF(JSMSG_TEMPORAL_PARSER_MONTH_DAY_CALENDAR_NOT_ISO8601, 1, JSEXN_RANGEERR, "can't parse {0}: Month-Day formats only support the \"iso8601\" calendar")
MSG_DEF(JSMSG_TEMPORAL_PARSER_YEAR_MONTH_CALENDAR_NOT_ISO8601, 1, JSEXN_RANGEERR, "can't parse {0}: Year-Month formats only support the \"iso8601\" calendar")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_SUBMINUTE_TIMEZONE, 1, JSEXN_RANGEERR, "can't parse {0}: time zone offset must not contain seconds precision")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INCONSISTENT_DATE_SEPARATOR, 1, JSEXN_RANGEERR, "can't parse {0}: date separator '-' must be consistent")
MSG_DEF(JSMSG_TEMPORAL_PARSER_INCONSISTENT_TIME_SEPARATOR, 1, JSEXN_RANGEERR, "can't parse {0}: time separator ':' must be consistent")
MSG_DEF(JSMSG_TEMPORAL_PARSER_EMPTY_STRING, 1, JSEXN_RANGEERR, "can't parse empty string as {0}")
// Explicit Resource Management
// TODO: Improve the messaging for suppressed errors (Bug 1906150)
MSG_DEF(JSMSG_ERROR_WAS_SUPPRESSED, 0, IF_EXPLICIT_RESOURCE_MANAGEMENT(JSEXN_SUPPRESSEDERR, JSEXN_INTERNALERR), "An error is suppressed because another error happened while disposing an object")
// DisposableStack
MSG_DEF(JSMSG_DISPOSABLE_STACK_DISPOSED, 0, JSEXN_REFERENCEERR, "DisposableStack has already been disposed")
// Iterator.range
MSG_DEF(JSMSG_ITERATOR_RANGE_INVALID_START, 0, JSEXN_TYPEERR, "The 'start' argument must be a number or BigInt")
MSG_DEF(JSMSG_ITERATOR_RANGE_INVALID_START_RANGEERR, 0, JSEXN_RANGEERR, "The 'start' argument cannot be NaN")
MSG_DEF(JSMSG_ITERATOR_RANGE_INVALID_END_RANGEERR, 0, JSEXN_RANGEERR, "The 'end' argument cannot be NaN")
MSG_DEF(JSMSG_ITERATOR_RANGE_INVALID_END, 0, JSEXN_TYPEERR, "The 'end' argument must be a number or BigInt")
MSG_DEF(JSMSG_ITERATOR_RANGE_START_INFINITY, 0, JSEXN_RANGEERR, "The 'start' argument must be a finite number")
MSG_DEF(JSMSG_ITERATOR_RANGE_STEP_NAN, 0, JSEXN_RANGEERR, "The 'step' argument must not be NaN")
MSG_DEF(JSMSG_ITERATOR_RANGE_STEP_NOT_NUMBER, 0, JSEXN_TYPEERR, "The 'step' argument must be a number")
MSG_DEF(JSMSG_ITERATOR_RANGE_STEP_NOT_FINITE, 0, JSEXN_RANGEERR, "The 'step' argument must be a finite number")
MSG_DEF(JSMSG_ITERATOR_RANGE_STEP_ZERO, 0, JSEXN_RANGEERR, "The 'step' argument must not be zero when 'start' is not equal to 'end'")
MSG_DEF(JSMSG_ITERATOR_RANGE_INVALID_STEP, 0, JSEXN_TYPEERR, "The 'step' or options argument must be a valid number, BigInt, or an Object with valid properties")
MSG_DEF(JSMSG_ITERATOR_RANGE_STEP_NOT_BIGINT, 0, JSEXN_TYPEERR, "The 'step' argument must be a BigInt when iterating over BigInt ranges")
// Math.sumPrecise
MSG_DEF(JSMSG_SUMPRECISE_TOO_MANY_VALUES, 0, JSEXN_RANGEERR, "too many values passed to Math.sumPrecise")
MSG_DEF(JSMSG_SUMPRECISE_EXPECTED_NUMBER, 0, JSEXN_TYPEERR, "values passed to Math.sumPrecise must be numbers")
//clang-format on

View File

@ -45,6 +45,8 @@
namespace JS {
class JS_PUBLIC_API EnvironmentChain;
/**
* Allocate a new environment in the current compartment that is compatible with
* JSM shared loading.
@ -68,7 +70,7 @@ extern JS_PUBLIC_API bool ExecuteInJSMEnvironment(JSContext* cx,
// temporarily placed on the environment chain.
extern JS_PUBLIC_API bool ExecuteInJSMEnvironment(
JSContext* cx, Handle<JSScript*> script, Handle<JSObject*> jsmEnv,
Handle<StackGCVector<JSObject*>> targetObj);
const EnvironmentChain& targetObj);
// Used by native methods to determine the JSMEnvironment of caller if possible
// by looking at stack frames. Returns nullptr if top frame isn't a scripted

View File

@ -17,12 +17,12 @@ struct JS_PUBLIC_API JSContext;
class JS_PUBLIC_API JSObject;
/*
* Telemetry reasons passed to the accumulate telemetry callback.
* Legacy telemetry metrics passed to the accumulate telemetry callback.
*
* It's OK for these enum values to change as they will be mapped to a fixed
* member of the mozilla::Telemetry::HistogramID enum by the callback.
*/
#define FOR_EACH_JS_METRIC(_) \
#define FOR_EACH_JS_LEGACY_METRIC(_) \
_(GC_REASON_2, Enumeration) \
_(GC_IS_COMPARTMENTAL, Boolean) \
_(GC_ZONE_COUNT, QuantityDistribution) \
@ -60,9 +60,6 @@ class JS_PUBLIC_API JSObject;
_(GC_TIME_BETWEEN_S, TimeDuration_S) \
_(GC_TIME_BETWEEN_SLICES_MS, TimeDuration_MS) \
_(GC_SLICE_COUNT, QuantityDistribution) \
_(DESERIALIZE_BYTES, MemoryDistribution) \
_(DESERIALIZE_ITEMS, QuantityDistribution) \
_(DESERIALIZE_US, TimeDuration_US) \
_(GC_EFFECTIVENESS, MemoryDistribution) \
_(GC_PARALLEL_MARK, Boolean) \
_(GC_PARALLEL_MARK_SPEEDUP, Integer) \
@ -70,6 +67,20 @@ class JS_PUBLIC_API JSObject;
_(GC_PARALLEL_MARK_INTERRUPTIONS, Integer) \
_(GC_TASK_START_DELAY_US, TimeDuration_US)
/*
* Append any glean only telemetry metrics to the following list.
* However, unlike the legacy list, each glean metric must be manually added
* to the switch statement in AccumulateTelemetryCallback().
*/
#define FOR_EACH_JS_GLEAN_METRIC(_) \
_(ION_COMPILE_TIME, TimeDuration_US) \
_(GC_GLEAN_SLOW_PHASE, Enumeration) \
_(GC_GLEAN_SLOW_TASK, Enumeration)
#define FOR_EACH_JS_METRIC(_) \
FOR_EACH_JS_LEGACY_METRIC(_) \
FOR_EACH_JS_GLEAN_METRIC(_)
// clang-format off
#define ENUM_DEF(NAME, _) NAME,
enum class JSMetric {
@ -88,17 +99,25 @@ extern JS_PUBLIC_API void JS_SetAccumulateTelemetryCallback(
_(ASMJS, AsmJS) \
_(WASM, Wasm) \
_(WASM_LEGACY_EXCEPTIONS, WasmLegacyExceptions) \
_(SUBCLASSING_ARRAY_TYPE_II, SubclassingArrayTypeII) \
_(SUBCLASSING_ARRAY_TYPE_III, SubclassingArrayTypeIII) \
_(SUBCLASSING_PROMISE_TYPE_II, SubclassingPromiseTypeII) \
_(SUBCLASSING_PROMISE_TYPE_III, SubclassingPromiseTypeIII) \
_(SUBCLASSING_TYPEDARRAY_TYPE_II, SubclassingTypedArrayTypeII) \
_(SUBCLASSING_TYPEDARRAY_TYPE_III, SubclassingTypedArrayTypeIII) \
_(SUBCLASSING_ARRAYBUFFER_TYPE_III, SubclassingArrayBufferTypeIII) \
_(SUBCLASSING_SHAREDARRAYBUFFER_TYPE_III, \
SubclassingSharedArrayBufferTypeIII) \
_(SUBCLASSING_REGEXP_TYPE_III, SubclassingRegExpTypeIII) \
_(SUBCLASSING_REGEXP_TYPE_IV, SubclassingRegExpTypeIV)
_(ISHTMLDDA_FUSE, IsHTMLDDAFuse) \
_(OPTIMIZE_GET_ITERATOR_FUSE, OptimizeGetIteratorFuse) \
_(THENABLE_USE, ThenableUse) \
_(THENABLE_USE_PROTO, ThenableUseProto) \
_(THENABLE_USE_STANDARD_PROTO, ThenableUseStandardProto) \
_(THENABLE_USE_OBJECT_PROTO, ThenableUseObjectProto) \
_(LEGACY_LANG_SUBTAG, LegacyLangSubtag) \
_(IC_STUB_TOO_LARGE, ICStubTooLarge) \
_(IC_STUB_OOM, ICStubOOM) \
_(ERRORSTACK_GETTER, ErrorStackGetter) \
_(ERRORSTACK_GETTER_NO_ERRORDATA, ErrorStackGetterNoErrorData) \
_(ERRORSTACK_SETTER, ErrorStackSetter) \
_(ERRORSTACK_SETTER_NONSTRING, ErrorStackSetterNonString) \
_(ERRORSTACK_SETTER_NO_ERRORDATA, ErrorStackSetterNoErrorData) \
_(DATEPARSE, DateParse) \
_(DATEPARSE_IMPL_DEF, DateParseImplDef) \
_(OPTIMIZE_ARRAY_SPECIES_FUSE, OptimizeArraySpeciesFuse) \
_(OPTIMIZE_PROMISE_LOOKUP_FUSE, OptimizePromiseLookupFuse) \
_(REGEXP_SYMBOL_PROTOCOL_ON_PRIMITIVE, RegExpSymbolProtocolOnPrimitive)
/*
* Use counter names passed to the accumulate use counter callback.

View File

@ -35,6 +35,7 @@ struct String {
static constexpr uint32_t LINEAR_BIT = js::Bit(4);
static constexpr uint32_t INLINE_CHARS_BIT = js::Bit(6);
static constexpr uint32_t LATIN1_CHARS_BIT = js::Bit(10);
static constexpr uint32_t HAS_STRING_BUFFER_BIT = js::Bit(12);
static constexpr uint32_t EXTERNAL_FLAGS = LINEAR_BIT | js::Bit(8);
static constexpr uint32_t TYPE_FLAGS_MASK = js::BitMask(10) - js::BitMask(3);
static constexpr uint32_t PERMANENT_ATOM_MASK = ATOM_BIT | js::Bit(8);
@ -68,6 +69,7 @@ struct String {
bool isLinear() const { return flags() & LINEAR_BIT; }
bool hasLatin1Chars() const { return flags() & LATIN1_CHARS_BIT; }
bool hasStringBuffer() const { return flags() & HAS_STRING_BUFFER_BIT; }
// For hot code, prefer other type queries.
bool isExternal() const {

View File

@ -4,8 +4,9 @@
# This script generates js/public/PrefsGenerated.h from StaticPrefList.yaml
import io
import buildconfig
import six
import yaml
from mozbuild.preprocessor import Preprocessor
@ -39,7 +40,7 @@ def load_yaml(yaml_path):
if buildconfig.substs.get("MOZ_DEBUG"):
pp.context["DEBUG"] = "1"
pp.out = six.StringIO()
pp.out = io.StringIO()
pp.do_filter("substitution")
pp.do_include(yaml_path)
contents = pp.out.getvalue()
@ -56,7 +57,7 @@ def get_cpp_type(type):
return "uint32_t"
if type in ("int32_t", "RelaxedAtomicInt32"):
return "int32_t"
raise Exception("Unexpected type: {}".format(type))
raise Exception(f"Unexpected type: {type}")
# Returns a C++ expression for the default pref value. Booleans in the YAML file
@ -116,10 +117,10 @@ def generate_prefs_header(c_out, yaml_path):
# after startup.
field_type = type
if not is_startup_pref:
field_type = "mozilla::Atomic<{}, mozilla::Relaxed>".format(field_type)
class_fields.append("static {} {}_;".format(field_type, cpp_name))
field_type = f"mozilla::Atomic<{field_type}, mozilla::Relaxed>"
class_fields.append(f"static {field_type} {cpp_name}_;")
class_fields_inits.append(
"{} JS::Prefs::{}_{{{}}};".format(field_type, cpp_name, init_value)
f"{field_type} JS::Prefs::{cpp_name}_{{{init_value}}};"
)
is_startup_pref_bool = "true" if is_startup_pref else "false"
@ -127,9 +128,7 @@ def generate_prefs_header(c_out, yaml_path):
# Generate a MACRO invocation like this:
# MACRO("arraybuffer_transfer", arraybuffer_transfer, bool, setAtStartup_arraybuffer_transfer, true)
macro_entries.append(
'MACRO("{}", {}, {}, {}, {})'.format(
name, cpp_name, type, setter_name, is_startup_pref_bool
)
f'MACRO("{name}", {cpp_name}, {type}, {setter_name}, {is_startup_pref_bool})'
)
# Generate a C++ statement to set the JS pref based on Gecko's StaticPrefs:
@ -138,9 +137,7 @@ def generate_prefs_header(c_out, yaml_path):
if pref.get("do_not_use_directly", False):
browser_pref_cpp_name += "_DoNotUseDirectly"
statement = "JS::Prefs::{}(mozilla::StaticPrefs::{}());".format(
setter_name, browser_pref_cpp_name
)
statement = f"JS::Prefs::{setter_name}(mozilla::StaticPrefs::{browser_pref_cpp_name}());"
browser_set_statements.append(statement)
# For non-startup prefs, also generate code to update the pref after startup.
@ -150,25 +147,23 @@ def generate_prefs_header(c_out, yaml_path):
contents = ""
contents += "#define JS_PREF_CLASS_FIELDS \\\n"
contents += "".join(map(lambda s: " {}\\\n".format(s), class_fields))
contents += "".join(map(lambda s: f" {s}\\\n", class_fields))
contents += "\n\n"
contents += "#define JS_PREF_CLASS_FIELDS_INIT \\\n"
contents += "".join(map(lambda s: " {}\\\n".format(s), class_fields_inits))
contents += "".join(map(lambda s: f" {s}\\\n", class_fields_inits))
contents += "\n\n"
contents += "#define FOR_EACH_JS_PREF(MACRO) \\\n"
contents += "".join(map(lambda s: " {}\\\n".format(s), macro_entries))
contents += "".join(map(lambda s: f" {s}\\\n", macro_entries))
contents += "\n\n"
contents += "#define SET_JS_PREFS_FROM_BROWSER_PREFS \\\n"
contents += "".join(map(lambda s: " {}\\\n".format(s), browser_set_statements))
contents += "".join(map(lambda s: f" {s}\\\n", browser_set_statements))
contents += "\n\n"
contents += "#define SET_NON_STARTUP_JS_PREFS_FROM_BROWSER_PREFS \\\n"
contents += "".join(
map(lambda s: " {}\\\n".format(s), browser_set_non_startup_statements)
)
contents += "".join(map(lambda s: f" {s}\\\n", browser_set_non_startup_statements))
contents += "\n\n"
c_out.write(

View File

@ -50,9 +50,6 @@ using JS::NullValue;
using JS::NumberValue;
using JS::ObjectOrNullValue;
using JS::ObjectValue;
#ifdef ENABLE_RECORD_TUPLE
using JS::ExtendedPrimitiveValue;
#endif
using JS::PrivateGCThingValue;
using JS::PrivateUint32Value;
using JS::PrivateValue;
@ -96,12 +93,14 @@ using JS::NativeImpl;
using JS::Rooted;
using JS::RootedBigInt;
using JS::RootedField;
using JS::RootedFunction;
using JS::RootedId;
using JS::RootedObject;
using JS::RootedScript;
using JS::RootedString;
using JS::RootedSymbol;
using JS::RootedTuple;
using JS::RootedValue;
using JS::PersistentRooted;
@ -152,11 +151,6 @@ using JS::Zone;
using JS::BigInt;
#ifdef ENABLE_RECORD_TUPLE
using JS::RecordType;
using JS::TupleType;
#endif
} /* namespace js */
#endif /* NamespaceImports_h */

View File

@ -1,31 +0,0 @@
dnl
dnl Local autoconf macros used with mozilla
dnl The contents of this file are under the Public Domain.
dnl
builtin(include, ../../build/autoconf/hooks.m4)dnl
builtin(include, ../../build/autoconf/config.status.m4)dnl
builtin(include, ../../build/autoconf/toolchain.m4)dnl
builtin(include, ../../build/autoconf/altoptions.m4)dnl
builtin(include, ../../build/autoconf/mozprog.m4)dnl
builtin(include, ../../build/autoconf/mozheader.m4)dnl
builtin(include, ../../build/autoconf/compiler-opts.m4)dnl
builtin(include, ../../build/autoconf/arch.m4)dnl
builtin(include, ../../build/autoconf/clang-plugin.m4)dnl
builtin(include, ../../build/autoconf/sanitize.m4)dnl
define([__MOZ_AC_INIT_PREPARE], defn([AC_INIT_PREPARE]))
define([AC_INIT_PREPARE],
[if test -z "$srcdir"; then
srcdir=`dirname "[$]0"`
fi
srcdir="$srcdir/../.."
__MOZ_AC_INIT_PREPARE($1)
])
MOZ_PROG_CHECKMSYS()
dnl This won't actually read the mozconfig, but data that configure.py
dnl will have placed for us to read. Configure.py takes care of not reading
dnl the mozconfig where appropriate but can still give us some variables
dnl to read.
MOZ_READ_MOZCONFIG(.)

View File

@ -1,175 +0,0 @@
/* 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/. */
"use strict";
module.exports = {
plugins: ["spidermonkey-js"],
overrides: [
{
files: ["*.js"],
excludedFiles: ".eslintrc.js",
processor: "spidermonkey-js/processor",
env: {
// Disable all built-in environments.
node: false,
browser: false,
builtin: false,
// We need to explicitly disable the default environments added from
// "tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js".
es2021: false,
"mozilla/privileged": false,
"mozilla/specific": false,
// Enable SpiderMonkey's self-hosted environment.
"spidermonkey-js/environment": true,
},
parserOptions: {
ecmaVersion: "latest",
sourceType: "script",
// Self-hosted code defaults to strict mode.
ecmaFeatures: {
impliedStrict: true,
},
// Strict mode has to be enabled separately for the Babel parser.
babelOptions: {
parserOpts: {
strictMode: true,
},
},
},
rules: {
// We should fix those at some point, but we use this to detect NaNs.
"no-self-compare": "off",
"no-lonely-if": "off",
// Disabled until we can use let/const to fix those erorrs, and undefined
// names cause an exception and abort during runtime initialization.
"no-redeclare": "off",
// Disallow use of |void 0|. Instead use |undefined|.
"no-void": ["error", { allowAsStatement: true }],
// Disallow loose equality because of objects with the [[IsHTMLDDA]]
// internal slot, aka |document.all|, aka "objects emulating undefined".
eqeqeq: "error",
// All self-hosted code is implicitly strict mode, so there's no need to
// add a strict-mode directive.
strict: ["error", "never"],
// Disallow syntax not supported in self-hosted code.
"no-restricted-syntax": [
"error",
{
selector: "ClassDeclaration",
message: "Class declarations are not allowed",
},
{
selector: "ClassExpression",
message: "Class expressions are not allowed",
},
{
selector: "Literal[regex]",
message: "Regular expression literals are not allowed",
},
{
selector: "CallExpression > MemberExpression.callee",
message:
"Direct method calls are not allowed, use callFunction() or callContentFunction()",
},
{
selector: "NewExpression > MemberExpression.callee",
message:
"Direct method calls are not allowed, use constructContentFunction()",
},
{
selector: "YieldExpression[delegate=true]",
message:
"yield* is not allowed because it can run user-modifiable iteration code",
},
{
selector: "ForOfStatement > :not(CallExpression).right",
message:
"for-of loops must use allowContentIter(), allowContentIterWith(), or allowContentIterWithNext()",
},
{
selector:
"ForOfStatement > CallExpression.right > :not(Identifier[name='allowContentIter'], Identifier[name='allowContentIterWith'], Identifier[name='allowContentIterWithNext']).callee",
message:
"for-of loops must use allowContentIter(), allowContentIterWith(), or allowContentIterWithNext",
},
{
selector:
"CallExpression[callee.name='TO_PROPERTY_KEY'] > :not(Identifier).arguments:first-child",
message:
"TO_PROPERTY_KEY macro must be called with a simple identifier",
},
{
selector: "Identifier[name='arguments']",
message:
"'arguments' is disallowed, use ArgumentsLength(), GetArgument(n), or rest-parameters",
},
{
selector: "VariableDeclaration[kind='let']",
message: "'let' declarations are disallowed to avoid TDZ checks, use 'var' instead",
},
{
selector: "VariableDeclaration[kind='const']",
message: "'const' declarations are disallowed to avoid TDZ checks, use 'var' instead",
},
],
// Method signatures are important in builtins so disable unused argument errors.
"no-unused-vars": [
"error",
{
args: "none",
vars: "local",
},
],
},
globals: {
// The bytecode compiler special-cases these identifiers.
ArgumentsLength: "readonly",
allowContentIter: "readonly",
allowContentIterWith: "readonly",
allowContentIterWithNext: "readonly",
callContentFunction: "readonly",
callFunction: "readonly",
constructContentFunction: "readonly",
DefineDataProperty: "readonly",
forceInterpreter: "readonly",
GetArgument: "readonly",
GetBuiltinConstructor: "readonly",
GetBuiltinPrototype: "readonly",
GetBuiltinSymbol: "readonly",
getPropertySuper: "readonly",
hasOwn: "readonly",
IsNullOrUndefined: "readonly",
IteratorClose: "readonly",
resumeGenerator: "readonly",
SetCanonicalName: "readonly",
SetIsInlinableLargeFunction: "readonly",
ToNumeric: "readonly",
ToString: "readonly",
// We've disabled all built-in environments, which also removed
// `undefined` from the list of globals. Put it back because it's
// actually allowed in self-hosted code.
undefined: "readonly",
// Disable globals from stage 2/3 proposals for which we have work in
// progress patches. Eventually these will be part of a future ES
// release, in which case we can remove these extra entries.
AsyncIterator: "off",
Iterator: "off",
Record: "off",
Temporal: "off",
Tuple: "off",
},
},
],
};

View File

@ -0,0 +1,178 @@
/* 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/. */
import spidermonkeyJS from "eslint-plugin-spidermonkey-js";
import mozilla from "eslint-plugin-mozilla";
import globals from "globals";
export default [
{
plugins: { "spidermonkey-js": spidermonkeyJS },
files: ["**/*.js"],
processor: "spidermonkey-js/processor",
rules: {
// We should fix those at some point, but we use this to detect NaNs.
"no-self-compare": "off",
"no-lonely-if": "off",
// Disabled until we can use let/const to fix those erorrs, and undefined
// names cause an exception and abort during runtime initialization.
"no-redeclare": "off",
// Disallow use of |void 0|. Instead use |undefined|.
"no-void": ["error", { allowAsStatement: true }],
// Disallow loose equality because of objects with the [[IsHTMLDDA]]
// internal slot, aka |document.all|, aka "objects emulating undefined".
eqeqeq: "error",
// All self-hosted code is implicitly strict mode, so there's no need to
// add a strict-mode directive.
strict: ["error", "never"],
// Disallow syntax not supported in self-hosted code.
"no-restricted-syntax": [
"error",
{
selector: "ClassDeclaration",
message: "Class declarations are not allowed",
},
{
selector: "ClassExpression",
message: "Class expressions are not allowed",
},
{
selector: "Literal[regex]",
message: "Regular expression literals are not allowed",
},
{
selector: "CallExpression > MemberExpression.callee",
message:
"Direct method calls are not allowed, use callFunction() or callContentFunction()",
},
{
selector: "NewExpression > MemberExpression.callee",
message:
"Direct method calls are not allowed, use constructContentFunction()",
},
{
selector: "YieldExpression[delegate=true]",
message:
"yield* is not allowed because it can run user-modifiable iteration code",
},
{
selector: "ForOfStatement > :not(CallExpression).right",
message:
"for-of loops must use allowContentIter(), allowContentIterWith(), or allowContentIterWithNext()",
},
{
selector:
"ForOfStatement > CallExpression.right > :not(Identifier[name='allowContentIter'], Identifier[name='allowContentIterWith'], Identifier[name='allowContentIterWithNext']).callee",
message:
"for-of loops must use allowContentIter(), allowContentIterWith(), or allowContentIterWithNext",
},
{
selector:
"CallExpression[callee.name='TO_PROPERTY_KEY'] > :not(Identifier).arguments:first-child",
message:
"TO_PROPERTY_KEY macro must be called with a simple identifier",
},
{
selector: "Identifier[name='arguments']",
message:
"'arguments' is disallowed, use ArgumentsLength(), GetArgument(n), or rest-parameters",
},
{
selector: "VariableDeclaration[kind='let']",
message:
"'let' declarations are disallowed to avoid TDZ checks, use 'var' instead",
},
{
selector: "VariableDeclaration[kind='const']",
message:
"'const' declarations are disallowed to avoid TDZ checks, use 'var' instead",
},
],
// Method signatures are important in builtins so disable unused argument errors.
"no-unused-vars": [
"error",
{
args: "none",
vars: "local",
},
],
},
languageOptions: {
parserOptions: {
ecmaVersion: "latest",
// Self-hosted code defaults to strict mode.
ecmaFeatures: {
impliedStrict: true,
},
// Strict mode has to be enabled separately for the Babel parser.
babelOptions: {
parserOpts: {
strictMode: true,
},
},
},
sourceType: "script",
globals: {
// Disable all built-in environments.
...mozilla.turnOff(globals.node),
...mozilla.turnOff(globals.browser),
...mozilla.turnOff(globals.builtin),
// We need to explicitly disable the default environments added from
// "tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js".
...mozilla.turnOff(globals.es2021),
...mozilla.turnOff(mozilla.environments.privileged.globals),
...mozilla.turnOff(mozilla.environments.specific.globals),
// Enable SpiderMonkey's self-hosted environment.
...spidermonkeyJS.environments.environment.globals,
// The bytecode compiler special-cases these identifiers.
ArgumentsLength: "readonly",
allowContentIter: "readonly",
allowContentIterWith: "readonly",
allowContentIterWithNext: "readonly",
callContentFunction: "readonly",
callFunction: "readonly",
constructContentFunction: "readonly",
DefineDataProperty: "readonly",
forceInterpreter: "readonly",
GetArgument: "readonly",
GetBuiltinConstructor: "readonly",
GetBuiltinPrototype: "readonly",
GetBuiltinSymbol: "readonly",
getPropertySuper: "readonly",
hasOwn: "readonly",
IsNullOrUndefined: "readonly",
IteratorClose: "readonly",
resumeGenerator: "readonly",
SetCanonicalName: "readonly",
SetIsInlinableLargeFunction: "readonly",
ToNumeric: "readonly",
ToString: "readonly",
DisposeResourcesAsync: "readonly",
DisposeResourcesSync: "readonly",
// We've disabled all built-in environments, which also removed
// `undefined` from the list of globals. Put it back because it's
// actually allowed in self-hosted code.
undefined: "readonly",
// Disable globals from stage 2/3 proposals for which we have work in
// progress patches. Eventually these will be part of a future ES
// release, in which case we can remove these extra entries.
AsyncIterator: "off",
Iterator: "off",
Record: "off",
Temporal: "off",
Tuple: "off",
},
},
},
];

File diff suppressed because it is too large Load Diff

View File

@ -63,7 +63,8 @@ extern ArrayObject* NewDenseFullyAllocatedArray(
// Create a dense array with length == 'length', initialized length set to 0,
// and capacity == 'length' clamped to EagerAllocationMaxLength.
extern ArrayObject* NewDensePartlyAllocatedArray(
JSContext* cx, uint32_t length, NewObjectKind newKind = GenericObject);
JSContext* cx, uint32_t length, NewObjectKind newKind = GenericObject,
gc::AllocSite* site = nullptr);
// Like NewDensePartlyAllocatedArray, but the array will have |proto| as
// prototype (or Array.prototype if |proto| is nullptr).
@ -142,7 +143,8 @@ extern bool NewbornArrayPush(JSContext* cx, HandleObject obj, const Value& v);
extern ArrayObject* ArrayConstructorOneArg(JSContext* cx,
Handle<ArrayObject*> templateObject,
int32_t lengthInt);
int32_t lengthInt,
gc::AllocSite* site);
#ifdef DEBUG
extern bool ArrayInfo(JSContext* cx, unsigned argc, Value* vp);
@ -177,88 +179,10 @@ extern bool ArrayLengthSetter(JSContext* cx, HandleObject obj, HandleId id,
extern ArraySortResult ArraySortFromJit(
JSContext* cx, jit::TrampolineNativeFrameLayout* frame);
class MOZ_NON_TEMPORARY_CLASS ArraySpeciesLookup final {
/*
* An ArraySpeciesLookup holds the following:
*
* Array.prototype (arrayProto_)
* To ensure that the incoming array has the standard proto.
*
* Array.prototype's shape (arrayProtoShape_)
* To ensure that Array.prototype has not been modified.
*
* Array (arrayConstructor_)
* Array's shape (arrayConstructorShape_)
* To ensure that Array has not been modified.
*
* Array.prototype's slot number for constructor (arrayProtoConstructorSlot_)
* To quickly retrieve and ensure that the Array constructor
* stored in the slot has not changed.
*
* Array's slot number for the @@species getter. (arraySpeciesGetterSlot_)
* Array's canonical value for @@species (canonicalSpeciesFunc_)
* To quickly retrieve and ensure that the @@species getter for Array
* has not changed.
*
* MOZ_INIT_OUTSIDE_CTOR fields below are set in |initialize()|. The
* constructor only initializes a |state_| field, that defines whether the
* other fields are accessible.
*/
// Pointer to canonical Array.prototype and Array.
MOZ_INIT_OUTSIDE_CTOR NativeObject* arrayProto_;
MOZ_INIT_OUTSIDE_CTOR NativeObject* arrayConstructor_;
// Shape of matching Array, and slot containing the @@species property, and
// the canonical value.
MOZ_INIT_OUTSIDE_CTOR Shape* arrayConstructorShape_;
MOZ_INIT_OUTSIDE_CTOR uint32_t arraySpeciesGetterSlot_;
MOZ_INIT_OUTSIDE_CTOR JSFunction* canonicalSpeciesFunc_;
// Shape of matching Array.prototype object, and slot containing the
// constructor for it.
MOZ_INIT_OUTSIDE_CTOR Shape* arrayProtoShape_;
MOZ_INIT_OUTSIDE_CTOR uint32_t arrayProtoConstructorSlot_;
enum class State : uint8_t {
// Flags marking the lazy initialization of the above fields.
Uninitialized,
Initialized,
// The disabled flag is set when we don't want to try optimizing
// anymore because core objects were changed.
Disabled
};
State state_ = State::Uninitialized;
// Initialize the internal fields.
void initialize(JSContext* cx);
// Reset the cache.
void reset();
// Check if the global array-related objects have not been messed with
// in a way that would disable this cache.
bool isArrayStateStillSane();
public:
/** Construct an |ArraySpeciesLookup| in the uninitialized state. */
ArraySpeciesLookup() { reset(); }
// Try to optimize the @@species lookup for an array.
bool tryOptimizeArray(JSContext* cx, ArrayObject* array);
// Purge the cache and all info associated with it.
void purge() {
if (state_ == State::Initialized) {
reset();
}
}
};
bool IsArrayConstructor(const JSObject* obj);
bool intrinsic_CanOptimizeArraySpecies(JSContext* cx, unsigned argc, Value* vp);
} /* namespace js */
#endif /* builtin_Array_h */

View File

@ -131,7 +131,7 @@ function ArrayMap(callbackfn /*, thisArg*/) {
var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
/* Steps 5. */
var A = ArraySpeciesCreate(O, len);
var A = CanOptimizeArraySpecies(O) ? std_Array(len) : ArraySpeciesCreate(O, len);
/* Steps 6-7. */
/* Steps 7.a (implicit), and 7.d. */
@ -170,7 +170,7 @@ function ArrayFilter(callbackfn /*, thisArg*/) {
var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
/* Step 5. */
var A = ArraySpeciesCreate(O, 0);
var A = CanOptimizeArraySpecies(O) ? [] : ArraySpeciesCreate(O, 0);
/* Steps 6-8. */
/* Steps 8.a (implicit), and 8.d. */
@ -520,7 +520,7 @@ function CreateArrayIterator(obj, kind) {
var iterator = NewArrayIterator();
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, iteratedObject);
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0);
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_ITEM_KIND, kind);
UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_ITEM_KIND, kind);
return iterator;
}
@ -552,7 +552,7 @@ function ArrayIteratorNext() {
var index = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX);
// Step 7.
var itemKind = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_ITEM_KIND);
var itemKind = UnsafeGetInt32FromReservedSlot(obj, ARRAY_ITERATOR_SLOT_ITEM_KIND);
// Step 8-9.
var len;
@ -681,9 +681,7 @@ function ArrayFromAsync(asyncItems, mapfn = undefined, thisArg = undefined) {
// Step 3.e.i. Let A be ? Construct(C).
// Step 3.f. Else,
// Step 3.f.i. Let A be ! ArrayCreate(0).
var A = IsConstructor(C) ?
(ReportUsageCounter(C, SUBCLASS_ARRAY_TYPE_II), constructContentFunction(C, C)) : [];
var A = IsConstructor(C) ? constructContentFunction(C, C) : [];
// Step 3.j.i. Let k be 0.
var k = 0;
@ -751,7 +749,7 @@ function ArrayFromAsync(asyncItems, mapfn = undefined, thisArg = undefined) {
// Step 3.k.iv.1. Let A be ? Construct(C, « 𝔽(len) »).
// Step 3.k.v. Else,
// Step 3.k.v.1. Let A be ? ArrayCreate(len).
var A = IsConstructor(C) ? (ReportUsageCounter(C, SUBCLASS_ARRAY_TYPE_II), constructContentFunction(C, C, len)) : std_Array(len);
var A = IsConstructor(C) ? constructContentFunction(C, C, len) : std_Array(len);
// Step 3.k.vi. Let k be 0.
var k = 0;
@ -815,7 +813,7 @@ function ArrayFrom(items, mapfn = undefined, thisArg = undefined) {
}
// Steps 5.a-b.
var A = IsConstructor(C) ? (ReportUsageCounter(C, SUBCLASS_ARRAY_TYPE_II), constructContentFunction(C, C)) : [];
var A = IsConstructor(C) ? constructContentFunction(C, C) : [];
// Step 5.d.
var k = 0;
@ -858,7 +856,7 @@ function ArrayFrom(items, mapfn = undefined, thisArg = undefined) {
// Steps 12-14.
var A = IsConstructor(C)
? (ReportUsageCounter(C, SUBCLASS_ARRAY_TYPE_II), constructContentFunction(C, C, len))
? constructContentFunction(C, C, len)
: std_Array(len);
// Steps 15-16.
@ -996,7 +994,8 @@ function ArraySpeciesCreate(originalArray, length) {
}
// Step 5.a.
var C = originalArray.constructor;
var originalConstructor = originalArray.constructor;
var C = originalConstructor;
// Step 5.b.
if (IsConstructor(C) && IsCrossRealmArrayConstructor(C)) {
@ -1031,7 +1030,6 @@ function ArraySpeciesCreate(originalArray, length) {
}
// Step 8.
ReportUsageCounter(C, SUBCLASS_ARRAY_TYPE_III);
return constructContentFunction(C, C, length);
}
@ -1053,7 +1051,7 @@ function ArrayFlatMap(mapperFunction /*, thisArg*/) {
var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
// Step 5.
var A = ArraySpeciesCreate(O, 0);
var A = CanOptimizeArraySpecies(O) ? [] : ArraySpeciesCreate(O, 0);
// Step 6.
FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T);
@ -1080,7 +1078,7 @@ function ArrayFlat(/* depth */) {
}
// Step 5.
var A = ArraySpeciesCreate(O, 0);
var A = CanOptimizeArraySpecies(O) ? [] : ArraySpeciesCreate(O, 0);
// Step 6.
FlattenIntoArray(A, O, sourceLen, 0, depthNum);

View File

@ -0,0 +1,54 @@
/* 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/. */
// Explicit Resource Management
// 27.4.3.3 AsyncDisposableStack.prototype.disposeAsync ( )
// https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-asyncdisposablestack.prototype.disposeAsync
async function $AsyncDisposableStackDisposeAsync() {
// Step 1. Let asyncDisposableStack be the this value.
var asyncDisposableStack = this;
if (!IsObject(asyncDisposableStack) || (asyncDisposableStack = GuardToAsyncDisposableStackHelper(asyncDisposableStack)) === null) {
return callFunction(
CallAsyncDisposableStackMethodIfWrapped,
this,
"$AsyncDisposableStackDisposeAsync"
);
}
// Step 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
// (implicit)
// Step 3. If asyncDisposableStack does not have an [[AsyncDisposableState]] internal slot, then
var state = UnsafeGetReservedSlot(asyncDisposableStack, DISPOSABLE_STACK_STATE_SLOT);
if (state === undefined) {
// Step 3.a. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
// Step 3.b. Return promiseCapability.[[Promise]].
// (implicit)
ThrowTypeError(JSMSG_INCOMPATIBLE_METHOD, 'disposeAsync', 'method', 'AsyncDisposableStack');
}
// Step 4. If asyncDisposableStack.[[AsyncDisposableState]] is disposed, then
if (state === DISPOSABLE_STACK_STATE_DISPOSED) {
// Step 4.a. Perform ! Call(promiseCapability.[[Resolve]], undefined, « undefined »).
// Step 4.b. Return promiseCapability.[[Promise]].
return undefined;
}
// Step 5. Set asyncDisposableStack.[[AsyncDisposableState]] to disposed.
UnsafeSetReservedSlot(asyncDisposableStack, DISPOSABLE_STACK_STATE_SLOT, DISPOSABLE_STACK_STATE_DISPOSED);
// Step 6. Let result be Completion(DisposeResources(asyncDisposableStack.[[DisposeCapability]], NormalCompletion(undefined))).
// Step 7. IfAbruptRejectPromise(result, promiseCapability).
var disposeCapability = UnsafeGetReservedSlot(asyncDisposableStack, DISPOSABLE_STACK_DISPOSABLE_RESOURCE_STACK_SLOT);
UnsafeSetReservedSlot(asyncDisposableStack, DISPOSABLE_STACK_DISPOSABLE_RESOURCE_STACK_SLOT, undefined);
if (disposeCapability === undefined) {
return undefined;
}
DisposeResourcesAsync(disposeCapability, disposeCapability.length);
// Step 8. Perform ! Call(promiseCapability.[[Resolve]], undefined, « result »).
// Step 9. Return promiseCapability.[[Promise]].
return undefined;
}
SetCanonicalName($AsyncDisposableStackDisposeAsync, "disposeAsync");

View File

@ -0,0 +1,391 @@
/* -*- 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/. */
#include "builtin/AsyncDisposableStackObject.h"
#include "vm/UsingHint.h"
#include "vm/JSObject-inl.h"
#include "vm/NativeObject-inl.h"
using namespace js;
/* static */ AsyncDisposableStackObject* AsyncDisposableStackObject::create(
JSContext* cx, JS::Handle<JSObject*> proto,
JS::Handle<JS::Value>
initialDisposeCapability /* = JS::UndefinedHandleValue */) {
AsyncDisposableStackObject* obj =
NewObjectWithClassProto<AsyncDisposableStackObject>(cx, proto);
if (!obj) {
return nullptr;
}
MOZ_ASSERT(initialDisposeCapability.isUndefined() ||
initialDisposeCapability.isObject());
MOZ_ASSERT_IF(initialDisposeCapability.isObject(),
initialDisposeCapability.toObject().is<ArrayObject>());
obj->initReservedSlot(
AsyncDisposableStackObject::DISPOSABLE_RESOURCE_STACK_SLOT,
initialDisposeCapability);
obj->initReservedSlot(
AsyncDisposableStackObject::STATE_SLOT,
JS::Int32Value(
int32_t(AsyncDisposableStackObject::DisposableState::Pending)));
return obj;
}
/**
* Explicit Resource Management Proposal
*
* 27.4.1.1 AsyncDisposableStack ( )
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-asyncdisposablestack
*/
/* static */ bool AsyncDisposableStackObject::construct(JSContext* cx,
unsigned argc,
JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
// Step 1. If NewTarget is undefined, throw a TypeError exception.
if (!ThrowIfNotConstructing(cx, args, "AsyncDisposableStack")) {
return false;
}
// Step 2. Let asyncDisposableStack be ?
// OrdinaryCreateFromConstructor(NewTarget,
// "%AsyncDisposableStack.prototype%", « [[AsyncDisposableState]],
// [[DisposeCapability]] »).
// Step 3. Set asyncDisposableStack.[[AsyncDisposableState]] to pending.
// Step 4. Set asyncDisposableStack.[[DisposeCapability]] to
// NewDisposeCapability().
JS::Rooted<JSObject*> proto(cx);
if (!GetPrototypeFromBuiltinConstructor(
cx, args, JSProto_AsyncDisposableStack, &proto)) {
return false;
}
AsyncDisposableStackObject* obj =
AsyncDisposableStackObject::create(cx, proto);
if (!obj) {
return false;
}
// Step 5. Return asyncDisposableStack.
args.rval().setObject(*obj);
return true;
}
/* static */ bool AsyncDisposableStackObject::is(JS::Handle<JS::Value> val) {
return val.isObject() && val.toObject().is<AsyncDisposableStackObject>();
}
/**
* Explicit Resource Management Proposal
*
* 27.4.3.6 AsyncDisposableStack.prototype.use ( value )
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-asyncdisposablestack.prototype.use
*/
/* static */ bool AsyncDisposableStackObject::use_impl(
JSContext* cx, const JS::CallArgs& args) {
// Step 1. Let asyncDisposableStack be the this value.
JS::Rooted<AsyncDisposableStackObject*> asyncDisposableStack(
cx, &args.thisv().toObject().as<AsyncDisposableStackObject>());
// Step 2. Perform ? RequireInternalSlot(asyncDisposableStack,
// [[AsyncDisposableState]]).
// (done by caller)
// Step 3. If asyncDisposableStack.[[AsyncDisposableState]] is disposed, throw
// a ReferenceError exception.
if (asyncDisposableStack->state() == DisposableState::Disposed) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DISPOSABLE_STACK_DISPOSED);
return false;
}
// Step 4. Perform ?
// AddDisposableResource(asyncDisposableStack.[[DisposeCapability]], value,
// async-dispose).
JS::Rooted<ArrayObject*> disposeCapability(
cx, GetOrCreateDisposeCapability(cx, asyncDisposableStack));
if (!disposeCapability) {
return false;
}
JS::Rooted<JS::Value> val(cx, args.get(0));
if (!AddDisposableResource(cx, disposeCapability, val, UsingHint::Async)) {
return false;
}
// Step 5. Return value.
args.rval().set(val);
return true;
}
/* static */ bool AsyncDisposableStackObject::use(JSContext* cx, unsigned argc,
JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
return JS::CallNonGenericMethod<is, use_impl>(cx, args);
}
/**
* Explicit Resource Management Proposal
*
* 27.4.3.4 get AsyncDisposableStack.prototype.disposed
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-get-asyncdisposablestack.prototype.disposed
*/
/* static */ bool AsyncDisposableStackObject::disposed_impl(
JSContext* cx, const JS::CallArgs& args) {
// Step 1. Let disposableStack be the this value.
JS::Rooted<AsyncDisposableStackObject*> disposableStack(
cx, &args.thisv().toObject().as<AsyncDisposableStackObject>());
// Step 2. Perform ? RequireInternalSlot(disposableStack,
// [[DisposableState]]).
// (done by caller)
// Step 3. If disposableStack.[[DisposableState]] is disposed, return true.
// Step 4. Otherwise, return false.
args.rval().setBoolean(disposableStack->state() == DisposableState::Disposed);
return true;
}
/* static */ bool AsyncDisposableStackObject::disposed(JSContext* cx,
unsigned argc,
JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
return JS::CallNonGenericMethod<is, disposed_impl>(cx, args);
}
/**
* Explicit Resource Management Proposal
*
* 27.4.3.5 AsyncDisposableStack.prototype.move ( )
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-asyncdisposablestack.prototype.move
*/
/* static */ bool AsyncDisposableStackObject::move_impl(
JSContext* cx, const JS::CallArgs& args) {
// Step 1. Let asyncDisposableStack be the this value.
JS::Rooted<AsyncDisposableStackObject*> asyncDisposableStack(
cx, &args.thisv().toObject().as<AsyncDisposableStackObject>());
// Step 2. Perform ? RequireInternalSlot(asyncDisposableStack,
// [[AsyncDisposableState]]).
// (done by caller)
// Step 3. If asyncDisposableStack.[[AsyncDisposableState]] is disposed, throw
// a ReferenceError exception.
if (asyncDisposableStack->state() == DisposableState::Disposed) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DISPOSABLE_STACK_DISPOSED);
return false;
}
// Step 4. Let newAsyncDisposableStack be ?
// OrdinaryCreateFromConstructor(%AsyncDisposableStack%,
// "%AsyncDisposableStack.prototype%", « [[AsyncDisposableState]],
// [[DisposeCapability]] »).
// Step 5. Set newAsyncDisposableStack.[[AsyncDisposableState]] to pending.
// Step 6. Set newAsyncDisposableStack.[[DisposeCapability]] to
// asyncDisposableStack.[[DisposeCapability]].
JS::Rooted<JS::Value> existingDisposeCapability(
cx, asyncDisposableStack->getReservedSlot(
AsyncDisposableStackObject::DISPOSABLE_RESOURCE_STACK_SLOT));
AsyncDisposableStackObject* newAsyncDisposableStack =
AsyncDisposableStackObject::create(cx, nullptr,
existingDisposeCapability);
if (!newAsyncDisposableStack) {
return false;
}
// Step 7. Set asyncDisposableStack.[[DisposeCapability]] to
// NewDisposeCapability().
asyncDisposableStack->clearDisposableResourceStack();
// Step 8. Set asyncDisposableStack.[[AsyncDisposableState]] to disposed.
asyncDisposableStack->setState(DisposableState::Disposed);
// Step 9. Return newAsyncDisposableStack.
args.rval().setObject(*newAsyncDisposableStack);
return true;
}
/* static */ bool AsyncDisposableStackObject::move(JSContext* cx, unsigned argc,
JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
return JS::CallNonGenericMethod<is, move_impl>(cx, args);
}
/**
* Explicit Resource Management Proposal
*
* 27.4.3.2 AsyncDisposableStack.prototype.defer ( onDisposeAsync )
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-asyncdisposablestack.prototype.defer
*/
/* static */ bool AsyncDisposableStackObject::defer_impl(
JSContext* cx, const JS::CallArgs& args) {
// Step 1. Let asyncDisposableStack be the this value.
JS::Rooted<AsyncDisposableStackObject*> asyncDisposableStack(
cx, &args.thisv().toObject().as<AsyncDisposableStackObject>());
// Step 2. Perform ? RequireInternalSlot(asyncDisposableStack,
// [[AsyncDisposableState]]).
// (done by caller)
// Step 3. If asyncDisposableStack.[[AsyncDisposableState]] is disposed,
// throw a ReferenceError exception.
if (asyncDisposableStack->state() == DisposableState::Disposed) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DISPOSABLE_STACK_DISPOSED);
return false;
}
// Step 4. If IsCallable(onDisposeAsync) is false, throw a TypeError
// exception.
JS::Handle<JS::Value> onDisposeAsync = args.get(0);
if (!ThrowIfOnDisposeNotCallable(cx, onDisposeAsync)) {
return false;
}
// Step 5. Perform ?
// AddDisposableResource(asyncDisposableStack.[[DisposeCapability]],
// undefined, async-dispose, onDisposeAsync).
JS::Rooted<ArrayObject*> disposeCapability(
cx, GetOrCreateDisposeCapability(cx, asyncDisposableStack));
if (!disposeCapability) {
return false;
}
if (!AddDisposableResource(cx, disposeCapability, JS::UndefinedHandleValue,
UsingHint::Async, onDisposeAsync)) {
return false;
}
// Step 6. Return undefined.
args.rval().setUndefined();
return true;
}
/* static */ bool AsyncDisposableStackObject::defer(JSContext* cx,
unsigned argc,
JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
return JS::CallNonGenericMethod<is, defer_impl>(cx, args);
}
/**
* Explicit Resource Management Proposal
*
* 27.4.3.1 AsyncDisposableStack.prototype.adopt ( value, onDisposeAsync )
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-asyncdisposablestack.prototype.adopt
*/
/* static */ bool AsyncDisposableStackObject::adopt_impl(
JSContext* cx, const JS::CallArgs& args) {
// Step 1. Let asyncDisposableStack be the this value.
JS::Rooted<AsyncDisposableStackObject*> asyncDisposableStack(
cx, &args.thisv().toObject().as<AsyncDisposableStackObject>());
// Step 2. Perform ? RequireInternalSlot(asyncDisposableStack,
// [[AsyncDisposableState]]).
// (done by caller)
// Step 3. If asyncDisposableStack.[[AsyncDisposableState]] is disposed, throw
// a ReferenceError exception.
if (asyncDisposableStack->state() == DisposableState::Disposed) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DISPOSABLE_STACK_DISPOSED);
return false;
}
// Step 4. If IsCallable(onDisposeAsync) is false, throw a TypeError
// exception.
JS::Handle<JS::Value> onDisposeAsync = args.get(1);
if (!ThrowIfOnDisposeNotCallable(cx, onDisposeAsync)) {
return false;
}
// Step 5. Let closure be a new Abstract Closure with no parameters that
// captures value and onDisposeAsync and performs the following steps when
// called:
// Step 5.a. (see AdoptClosure)
// Step 6. Let F be CreateBuiltinFunction(closure, 0, "", « »).
JS::Handle<PropertyName*> funName = cx->names().empty_;
JS::Rooted<JSFunction*> F(
cx, NewNativeFunction(cx, AdoptClosure, 0, funName,
gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
if (!F) {
return false;
}
JS::Handle<JS::Value> value = args.get(0);
F->initExtendedSlot(AdoptClosureSlot_ValueSlot, value);
F->initExtendedSlot(AdoptClosureSlot_OnDisposeSlot, onDisposeAsync);
// Step 7. Perform ?
// AddDisposableResource(asyncDisposableStack.[[DisposeCapability]],
// undefined, async-dispose, F).
JS::Rooted<ArrayObject*> disposeCapability(
cx, GetOrCreateDisposeCapability(cx, asyncDisposableStack));
if (!disposeCapability) {
return false;
}
JS::Rooted<JS::Value> FVal(cx, ObjectValue(*F));
if (!AddDisposableResource(cx, disposeCapability, JS::UndefinedHandleValue,
UsingHint::Async, FVal)) {
return false;
}
// Step 8. Return value.
args.rval().set(value);
return true;
}
/* static */ bool AsyncDisposableStackObject::adopt(JSContext* cx,
unsigned argc,
JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
return JS::CallNonGenericMethod<is, adopt_impl>(cx, args);
}
const JSPropertySpec AsyncDisposableStackObject::properties[] = {
JS_STRING_SYM_PS(toStringTag, "AsyncDisposableStack", JSPROP_READONLY),
JS_PSG("disposed", disposed, 0),
JS_PS_END,
};
const JSFunctionSpec AsyncDisposableStackObject::methods[] = {
JS_FN("adopt", AsyncDisposableStackObject::adopt, 2, 0),
JS_FN("defer", AsyncDisposableStackObject::defer, 1, 0),
JS_SELF_HOSTED_FN("disposeAsync", "$AsyncDisposableStackDisposeAsync", 0,
0),
JS_FN("move", AsyncDisposableStackObject::move, 0, 0),
JS_FN("use", AsyncDisposableStackObject::use, 1, 0),
JS_SELF_HOSTED_SYM_FN(asyncDispose, "$AsyncDisposableStackDisposeAsync", 0,
0),
JS_FS_END,
};
const ClassSpec AsyncDisposableStackObject::classSpec_ = {
GenericCreateConstructor<AsyncDisposableStackObject::construct, 0,
gc::AllocKind::FUNCTION>,
GenericCreatePrototype<AsyncDisposableStackObject>,
nullptr,
nullptr,
AsyncDisposableStackObject::methods,
AsyncDisposableStackObject::properties,
nullptr,
};
const JSClass AsyncDisposableStackObject::class_ = {
"AsyncDisposableStack",
JSCLASS_HAS_RESERVED_SLOTS(AsyncDisposableStackObject::RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_AsyncDisposableStack),
JS_NULL_CLASS_OPS,
&AsyncDisposableStackObject::classSpec_,
};
const JSClass AsyncDisposableStackObject::protoClass_ = {
"AsyncDisposableStack.prototype",
JSCLASS_HAS_CACHED_PROTO(JSProto_AsyncDisposableStack),
JS_NULL_CLASS_OPS,
&AsyncDisposableStackObject::classSpec_,
};

View File

@ -0,0 +1,47 @@
/* -*- 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 builtin_AsyncDisposableStackObject_h
#define builtin_AsyncDisposableStackObject_h
#include "builtin/DisposableStackObjectBase.h"
#include "vm/JSObject.h"
namespace js {
class AsyncDisposableStackObject : public DisposableStackObjectBase {
public:
static const JSClass class_;
static const JSClass protoClass_;
static AsyncDisposableStackObject* create(
JSContext* cx, JS::Handle<JSObject*> proto,
JS::Handle<JS::Value> initialDisposeCapability =
JS::UndefinedHandleValue);
private:
static const ClassSpec classSpec_;
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
static bool is(JS::Handle<JS::Value> val);
static bool construct(JSContext* cx, unsigned argc, JS::Value* vp);
static bool use_impl(JSContext* cx, const JS::CallArgs& args);
static bool use(JSContext* cx, unsigned argc, JS::Value* vp);
static bool disposed_impl(JSContext* cx, const JS::CallArgs& args);
static bool disposed(JSContext* cx, unsigned argc, JS::Value* vp);
static bool move_impl(JSContext* cx, const JS::CallArgs& args);
static bool move(JSContext* cx, unsigned argc, JS::Value* vp);
static bool defer_impl(JSContext* cx, const JS::CallArgs& args);
static bool defer(JSContext* cx, unsigned argc, JS::Value* vp);
static bool adopt_impl(JSContext* cx, const JS::CallArgs& args);
static bool adopt(JSContext* cx, unsigned argc, JS::Value* vp);
};
} /* namespace js */
#endif /* builtin_AsyncDisposableStackObject_h */

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,7 @@
#include "threading/ConditionVariable.h"
#include "threading/ProtectedData.h" // js::ThreadData
#include "vm/NativeObject.h"
#include "vm/PlainObject.h"
namespace js {
@ -23,6 +24,44 @@ class AtomicsObject : public NativeObject {
static const JSClass class_;
};
enum class FutexWaiterKind { Sync, Async, ListHead };
class FutexWaiter;
class SyncFutexWaiter;
class AsyncFutexWaiter;
class FutexWaiterListNode {
private:
FutexWaiterListNode* next_ = nullptr; // Lower priority node in waiter list
FutexWaiterListNode* prev_ = nullptr; // Higher priority node in waiter list
protected:
explicit FutexWaiterListNode(FutexWaiterKind kind) : kind_(kind) {}
FutexWaiterKind kind_;
public:
FutexWaiter* toWaiter() {
MOZ_ASSERT(kind_ != FutexWaiterKind::ListHead);
return reinterpret_cast<FutexWaiter*>(this);
}
FutexWaiterKind kind() const { return kind_; }
FutexWaiterListNode* next() { return next_; }
void setNext(FutexWaiterListNode* next) { next_ = next; }
FutexWaiterListNode* prev() { return prev_; }
void setPrev(FutexWaiterListNode* prev) { prev_ = prev; }
};
class FutexWaiterListHead : public FutexWaiterListNode {
public:
FutexWaiterListHead() : FutexWaiterListNode(FutexWaiterKind::ListHead) {
setNext(this);
setPrev(this);
}
~FutexWaiterListHead();
};
class FutexThread {
friend class AutoLockFutexAPI;
@ -129,12 +168,29 @@ class FutexThread {
JSContext* cx, SharedArrayRawBuffer* sarb, size_t byteOffset, int64_t value,
const mozilla::Maybe<mozilla::TimeDuration>& timeout);
// If the int32_t value at the given address equals `value`, return a result
// object containing a promise that will be resolved when that address is
// notified.
[[nodiscard]] PlainObject* atomics_wait_async_impl(
JSContext* cx, SharedArrayRawBuffer* sarb, size_t byteOffset, int32_t value,
const mozilla::Maybe<mozilla::TimeDuration>& timeout);
// If the int64_t value at the given address equals `value`, return a result
// object containing a promise that will be resolved when that address is
// notified.
[[nodiscard]] PlainObject* atomics_wait_async_impl(
JSContext* cx, SharedArrayRawBuffer* sarb, size_t byteOffset, int64_t value,
const mozilla::Maybe<mozilla::TimeDuration>& timeout);
// Notify some waiters on the given address. If `count` is negative then notify
// all. The return value is nonnegative and is the number of waiters woken. If
// the number of waiters woken exceeds INT64_MAX then this never returns. If
// `count` is nonnegative then the return value is never greater than `count`.
[[nodiscard]] int64_t atomics_notify_impl(SharedArrayRawBuffer* sarb,
size_t byteOffset, int64_t count);
// `count` is nonnegative then the woken out parameter is never greater than
// `count`.
[[nodiscard]] bool atomics_notify_impl(JSContext* cx,
SharedArrayRawBuffer* sarb,
size_t byteOffset, int64_t count,
int64_t* woken);
} /* namespace js */

View File

@ -39,8 +39,14 @@ static bool BigIntConstructor(JSContext* cx, unsigned argc, Value* vp) {
}
// Steps 3-4.
BigInt* bi =
v.isNumber() ? NumberToBigInt(cx, v.toNumber()) : ToBigInt(cx, v);
BigInt* bi;
if (!v.isNumber()) {
bi = ToBigInt(cx, v);
} else if (v.isInt32()) {
bi = BigInt::createFromInt64(cx, int64_t(v.toInt32()));
} else {
bi = NumberToBigInt(cx, v.toDouble());
}
if (!bi) {
return false;
}
@ -199,36 +205,49 @@ bool BigIntObject::asIntN(JSContext* cx, unsigned argc, Value* vp) {
}
const ClassSpec BigIntObject::classSpec_ = {
GenericCreateConstructor<BigIntConstructor, 1, gc::AllocKind::FUNCTION>,
GenericCreateConstructor<BigIntConstructor, 1, gc::AllocKind::FUNCTION,
&jit::JitInfo_BigInt>,
GenericCreatePrototype<BigIntObject>,
BigIntObject::staticMethods,
nullptr,
BigIntObject::methods,
BigIntObject::properties};
BigIntObject::properties,
};
const JSClass BigIntObject::class_ = {
"BigInt",
JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt) |
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
JS_NULL_CLASS_OPS, &BigIntObject::classSpec_};
JS_NULL_CLASS_OPS,
&BigIntObject::classSpec_,
};
const JSClass BigIntObject::protoClass_ = {
"BigInt.prototype", JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt),
JS_NULL_CLASS_OPS, &BigIntObject::classSpec_};
"BigInt.prototype",
JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt),
JS_NULL_CLASS_OPS,
&BigIntObject::classSpec_,
};
const JSPropertySpec BigIntObject::properties[] = {
// BigInt proposal section 5.3.5
JS_STRING_SYM_PS(toStringTag, "BigInt", JSPROP_READONLY), JS_PS_END};
JS_STRING_SYM_PS(toStringTag, "BigInt", JSPROP_READONLY),
JS_PS_END,
};
const JSFunctionSpec BigIntObject::methods[] = {
JS_FN("valueOf", valueOf, 0, 0), JS_FN("toString", toString, 0, 0),
JS_FN("valueOf", valueOf, 0, 0),
JS_FN("toString", toString, 0, 0),
#ifdef JS_HAS_INTL_API
JS_SELF_HOSTED_FN("toLocaleString", "BigInt_toLocaleString", 0, 0),
#else
JS_FN("toLocaleString", toLocaleString, 0, 0),
#endif
JS_FS_END};
JS_FS_END,
};
const JSFunctionSpec BigIntObject::staticMethods[] = {
JS_INLINABLE_FN("asUintN", asUintN, 2, 0, BigIntAsUintN),
JS_INLINABLE_FN("asIntN", asIntN, 2, 0, BigIntAsIntN), JS_FS_END};
JS_INLINABLE_FN("asIntN", asIntN, 2, 0, BigIntAsIntN),
JS_FS_END,
};

View File

@ -14,7 +14,7 @@
#include "jit/InlinableNatives.h"
#include "js/PropertySpec.h"
#include "util/StringBuffer.h"
#include "util/StringBuilder.h"
#include "vm/BigIntType.h"
#include "vm/GlobalObject.h"
#include "vm/JSContext.h"
@ -27,7 +27,9 @@ using namespace js;
const JSClass BooleanObject::class_ = {
"Boolean",
JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean),
JS_NULL_CLASS_OPS, &BooleanObject::classSpec_};
JS_NULL_CLASS_OPS,
&BooleanObject::classSpec_,
};
MOZ_ALWAYS_INLINE bool IsBoolean(HandleValue v) {
return v.isBoolean() || (v.isObject() && v.toObject().is<BooleanObject>());
@ -52,7 +54,7 @@ MOZ_ALWAYS_INLINE bool bool_toSource_impl(JSContext* cx, const CallArgs& args) {
bool b = ThisBooleanValue(args.thisv());
JSStringBuilder sb(cx);
if (!sb.append("(new Boolean(") || !BooleanToStringBuffer(b, sb) ||
if (!sb.append("(new Boolean(") || !BooleanToStringBuilder(b, sb) ||
!sb.append("))")) {
return false;
}
@ -102,7 +104,9 @@ static bool bool_valueOf(JSContext* cx, unsigned argc, Value* vp) {
static const JSFunctionSpec boolean_methods[] = {
JS_FN("toSource", bool_toSource, 0, 0),
JS_FN("toString", bool_toString, 0, 0),
JS_FN("valueOf", bool_valueOf, 0, 0), JS_FS_END};
JS_FN("valueOf", bool_valueOf, 0, 0),
JS_FS_END,
};
// ES2020 draft rev ecb4178012d6b4d9abc13fcbd45f5c6394b832ce
// 19.3.1.1 Boolean ( value )
@ -152,7 +156,8 @@ const ClassSpec BooleanObject::classSpec_ = {
nullptr,
nullptr,
boolean_methods,
nullptr};
nullptr,
};
PropertyName* js::BooleanToString(JSContext* cx, bool b) {
return b ? cx->names().true_ : cx->names().false_;
@ -165,12 +170,6 @@ JS_PUBLIC_API bool js::ToBooleanSlow(HandleValue v) {
if (v.isBigInt()) {
return !v.toBigInt()->isZero();
}
#ifdef ENABLE_RECORD_TUPLE
// proposal-record-tuple Section 3.1.1
if (v.isExtendedPrimitive()) {
return true;
}
#endif
MOZ_ASSERT(v.isObject());
return !EmulatesUndefined(&v.toObject());

View File

@ -43,7 +43,6 @@ using namespace js;
using JS::CanonicalizeNaN;
using JS::ToInt32;
using mozilla::AssertedCast;
using mozilla::WrapToSigned;
static bool IsDataView(HandleValue v) {
@ -405,7 +404,7 @@ NativeType DataViewObject::read(uint64_t offset, size_t length,
getDataPointer<NativeType>(offset, length, &isSharedMemory);
MOZ_ASSERT(data);
NativeType val = 0;
NativeType val{};
if (isSharedMemory) {
DataViewIO<NativeType, SharedMem<uint8_t*>>::fromBuffer(&val, data,
isLittleEndian);
@ -417,16 +416,6 @@ NativeType DataViewObject::read(uint64_t offset, size_t length,
return val;
}
#ifdef NIGHTLY_BUILD
template <>
float16 DataViewObject::read(uint64_t offset, size_t length,
bool isLittleEndian) {
float16 val{};
val.val = read<uint16_t>(offset, length, isLittleEndian);
return val;
}
#endif
template uint32_t DataViewObject::read(uint64_t offset, size_t length,
bool isLittleEndian);
@ -510,7 +499,6 @@ inline bool WebIDLCast<uint64_t>(JSContext* cx, HandleValue value,
return true;
}
#ifdef NIGHTLY_BUILD
template <>
inline bool WebIDLCast<float16>(JSContext* cx, HandleValue value,
float16* out) {
@ -521,7 +509,6 @@ inline bool WebIDLCast<float16>(JSContext* cx, HandleValue value,
*out = float16(temp);
return true;
}
#endif
template <>
inline bool WebIDLCast<float>(JSContext* cx, HandleValue value, float* out) {
@ -560,11 +547,9 @@ bool DataViewObject::write(JSContext* cx, Handle<DataViewObject*> obj,
}
// See the comment in ElementSpecific::doubleToNative.
if (js::SupportDifferentialTesting() && TypeIsFloatingPoint<NativeType>()) {
if constexpr (std::is_same_v<NativeType, float16>) {
value = JS::CanonicalizeNaN(value.toDouble());
} else {
value = JS::CanonicalizeNaN(value);
if constexpr (!std::numeric_limits<NativeType>::is_integer) {
if (js::SupportDifferentialTesting()) {
value = JS::CanonicalizeNaN(static_cast<double>(value));
}
}
@ -767,7 +752,6 @@ bool DataViewObject::fun_getBigUint64(JSContext* cx, unsigned argc, Value* vp) {
return CallNonGenericMethod<IsDataView, getBigUint64Impl>(cx, args);
}
#ifdef NIGHTLY_BUILD
bool DataViewObject::getFloat16Impl(JSContext* cx, const CallArgs& args) {
MOZ_ASSERT(IsDataView(args.thisv()));
@ -779,7 +763,7 @@ bool DataViewObject::getFloat16Impl(JSContext* cx, const CallArgs& args) {
return false;
}
args.rval().setDouble(CanonicalizeNaN(val.toDouble()));
args.rval().setDouble(CanonicalizeNaN(static_cast<double>(val)));
return true;
}
@ -787,7 +771,6 @@ bool DataViewObject::fun_getFloat16(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsDataView, getFloat16Impl>(cx, args);
}
#endif
bool DataViewObject::getFloat32Impl(JSContext* cx, const CallArgs& args) {
MOZ_ASSERT(IsDataView(args.thisv()));
@ -977,7 +960,6 @@ bool DataViewObject::fun_setBigUint64(JSContext* cx, unsigned argc, Value* vp) {
return CallNonGenericMethod<IsDataView, setBigUint64Impl>(cx, args);
}
#ifdef NIGHTLY_BUILD
bool DataViewObject::setFloat16Impl(JSContext* cx, const CallArgs& args) {
MOZ_ASSERT(IsDataView(args.thisv()));
@ -995,7 +977,6 @@ bool DataViewObject::fun_setFloat16(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsDataView, setFloat16Impl>(cx, args);
}
#endif
bool DataViewObject::setFloat32Impl(JSContext* cx, const CallArgs& args) {
MOZ_ASSERT(IsDataView(args.thisv()));
@ -1153,10 +1134,8 @@ const JSFunctionSpec DataViewObject::methods[] = {
DataViewGetInt32),
JS_INLINABLE_FN("getUint32", DataViewObject::fun_getUint32, 1, 0,
DataViewGetUint32),
#ifdef NIGHTLY_BUILD
// TODO: See Bug 1835034 for JIT support for Float16Array
JS_FN("getFloat16", DataViewObject::fun_getFloat16, 1, 0),
#endif
JS_INLINABLE_FN("getFloat16", DataViewObject::fun_getFloat16, 1, 0,
DataViewGetFloat16),
JS_INLINABLE_FN("getFloat32", DataViewObject::fun_getFloat32, 1, 0,
DataViewGetFloat32),
JS_INLINABLE_FN("getFloat64", DataViewObject::fun_getFloat64, 1, 0,
@ -1177,10 +1156,8 @@ const JSFunctionSpec DataViewObject::methods[] = {
DataViewSetInt32),
JS_INLINABLE_FN("setUint32", DataViewObject::fun_setUint32, 2, 0,
DataViewSetUint32),
#ifdef NIGHTLY_BUILD
// TODO: See Bug 1835034 for JIT support for Float16Array
JS_FN("setFloat16", DataViewObject::fun_setFloat16, 2, 0),
#endif
JS_INLINABLE_FN("setFloat16", DataViewObject::fun_setFloat16, 2, 0,
DataViewSetFloat16),
JS_INLINABLE_FN("setFloat32", DataViewObject::fun_setFloat32, 2, 0,
DataViewSetFloat32),
JS_INLINABLE_FN("setFloat64", DataViewObject::fun_setFloat64, 2, 0,
@ -1189,13 +1166,16 @@ const JSFunctionSpec DataViewObject::methods[] = {
DataViewSetBigInt64),
JS_INLINABLE_FN("setBigUint64", DataViewObject::fun_setBigUint64, 2, 0,
DataViewSetBigUint64),
JS_FS_END};
JS_FS_END,
};
const JSPropertySpec DataViewObject::properties[] = {
JS_PSG("buffer", DataViewObject::bufferGetter, 0),
JS_PSG("byteLength", DataViewObject::byteLengthGetter, 0),
JS_PSG("byteOffset", DataViewObject::byteOffsetGetter, 0),
JS_STRING_SYM_PS(toStringTag, "DataView", JSPROP_READONLY), JS_PS_END};
JS_STRING_SYM_PS(toStringTag, "DataView", JSPROP_READONLY),
JS_PS_END,
};
JS_PUBLIC_API JSObject* JS_NewDataView(JSContext* cx, HandleObject buffer,
size_t byteOffset, size_t byteLength) {

View File

@ -0,0 +1,43 @@
/* 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/. */
// Explicit Resource Management Proposal
// 27.3.3.3 DisposableStack.prototype.dispose ( )
// https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-disposablestack.prototype.dispose
function $DisposableStackDispose() {
// Step 1. Let disposableStack be the this value.
var disposableStack = this;
if (!IsObject(disposableStack) || (disposableStack = GuardToDisposableStackHelper(disposableStack)) === null) {
return callFunction(
CallDisposableStackMethodIfWrapped,
this,
"$DisposableStackDispose"
);
}
// Step 2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
var state = UnsafeGetReservedSlot(disposableStack, DISPOSABLE_STACK_STATE_SLOT);
// Step 3. If disposableStack.[[DisposableState]] is disposed, return undefined.
if (state === DISPOSABLE_STACK_STATE_DISPOSED) {
return undefined;
}
// Step 4. Set disposableStack.[[DisposableState]] to disposed.
UnsafeSetReservedSlot(disposableStack, DISPOSABLE_STACK_STATE_SLOT, DISPOSABLE_STACK_STATE_DISPOSED);
// Step 5. Return ? DisposeResources(disposableStack.[[DisposeCapability]], NormalCompletion(undefined)).
var disposeCapability = UnsafeGetReservedSlot(disposableStack, DISPOSABLE_STACK_DISPOSABLE_RESOURCE_STACK_SLOT);
UnsafeSetReservedSlot(disposableStack, DISPOSABLE_STACK_DISPOSABLE_RESOURCE_STACK_SLOT, undefined);
// disposeCapability being undefined indicates that its an empty stack, thus
// all the following operations are no-ops, hence we can return early.
if (disposeCapability === undefined) {
return undefined;
}
DisposeResourcesSync(disposeCapability, disposeCapability.length);
return undefined;
}
SetCanonicalName($DisposableStackDispose, "dispose");

View File

@ -0,0 +1,373 @@
/* -*- 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/. */
#include "builtin/DisposableStackObject.h"
#include "builtin/Array.h"
#include "builtin/DisposableStackObjectBase.h"
#include "js/friend/ErrorMessages.h"
#include "js/PropertyAndElement.h"
#include "js/PropertySpec.h"
#include "vm/GlobalObject.h"
#include "vm/JSContext.h"
#include "vm/JSObject.h"
#include "vm/UsingHint.h"
#include "vm/NativeObject-inl.h"
using namespace js;
/* static */ DisposableStackObject* DisposableStackObject::create(
JSContext* cx, JS::Handle<JSObject*> proto,
JS::Handle<JS::Value>
initialDisposeCapability /* = JS::UndefinedHandleValue */) {
DisposableStackObject* obj =
NewObjectWithClassProto<DisposableStackObject>(cx, proto);
if (!obj) {
return nullptr;
}
MOZ_ASSERT(initialDisposeCapability.isUndefined() ||
initialDisposeCapability.isObject());
MOZ_ASSERT_IF(initialDisposeCapability.isObject(),
initialDisposeCapability.toObject().is<ArrayObject>());
obj->initReservedSlot(DisposableStackObject::DISPOSABLE_RESOURCE_STACK_SLOT,
initialDisposeCapability);
obj->initReservedSlot(
DisposableStackObject::STATE_SLOT,
JS::Int32Value(int32_t(DisposableStackObject::DisposableState::Pending)));
return obj;
}
/**
* Explicit Resource Management Proposal
* 27.3.1.1 DisposableStack ( )
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-disposablestack
*/
/* static */ bool DisposableStackObject::construct(JSContext* cx, unsigned argc,
JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
// Step 1. If NewTarget is undefined, throw a TypeError exception.
if (!ThrowIfNotConstructing(cx, args, "DisposableStack")) {
return false;
}
// Step 2. Let disposableStack be ? OrdinaryCreateFromConstructor(NewTarget,
// "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]]
// »).
// Step 3. Set disposableStack.[[DisposableState]] to pending.
// Step 4. Set disposableStack.[[DisposeCapability]] to
// NewDisposeCapability().
JS::Rooted<JSObject*> proto(cx);
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DisposableStack,
&proto)) {
return false;
}
DisposableStackObject* obj = DisposableStackObject::create(cx, proto);
if (!obj) {
return false;
}
// Step 5. Return disposableStack.
args.rval().setObject(*obj);
return true;
}
/* static */ bool DisposableStackObject::is(JS::Handle<JS::Value> val) {
return val.isObject() && val.toObject().is<DisposableStackObject>();
}
/**
* Explicit Resource Management Proposal
* 27.3.3.6 DisposableStack.prototype.use ( value )
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-disposablestack.prototype.use
*/
/* static */ bool DisposableStackObject::use_impl(JSContext* cx,
const JS::CallArgs& args) {
// Step 1. Let disposableStack be the this value.
JS::Rooted<DisposableStackObject*> disposableStack(
cx, &args.thisv().toObject().as<DisposableStackObject>());
// Step 2. Perform ? RequireInternalSlot(disposableStack,
// [[DisposableState]]).
// Step 3. If disposableStack.[[DisposableState]] is disposed, throw a
// ReferenceError exception.
if (disposableStack->state() == DisposableState::Disposed) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DISPOSABLE_STACK_DISPOSED);
return false;
}
// Step 4. Perform ?
// AddDisposableResource(disposableStack.[[DisposeCapability]], value,
// sync-dispose).
JS::Rooted<ArrayObject*> disposeCapability(
cx, GetOrCreateDisposeCapability(cx, disposableStack));
if (!disposeCapability) {
return false;
}
JS::Rooted<JS::Value> val(cx, args.get(0));
if (!AddDisposableResource(cx, disposeCapability, val, UsingHint::Sync)) {
return false;
}
// Step 5. Return value.
args.rval().set(val);
return true;
}
/* static */ bool DisposableStackObject::use(JSContext* cx, unsigned argc,
JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
return JS::CallNonGenericMethod<is, use_impl>(cx, args);
}
/**
* Explicit Resource Management Proposal
* 27.3.3.2 DisposableStack.prototype.defer ( onDispose )
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-disposablestack.prototype.defer
*/
/* static */ bool DisposableStackObject::defer_impl(JSContext* cx,
const JS::CallArgs& args) {
// Step 1. Let disposableStack be the this value.
JS::Rooted<DisposableStackObject*> disposableStack(
cx, &args.thisv().toObject().as<DisposableStackObject>());
// Step 2. Perform ? RequireInternalSlot(disposableStack,
// [[DisposableState]]).
// Step 3. If disposableStack.[[DisposableState]] is disposed, throw a
// ReferenceError exception.
if (disposableStack->state() == DisposableState::Disposed) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DISPOSABLE_STACK_DISPOSED);
return false;
}
// Step 4. If IsCallable(onDispose) is false, throw a TypeError exception.
JS::Handle<JS::Value> onDispose = args.get(0);
if (!ThrowIfOnDisposeNotCallable(cx, onDispose)) {
return false;
}
// Step 5. Perform ?
// AddDisposableResource(disposableStack.[[DisposeCapability]], undefined,
// sync-dispose, onDispose).
JS::Rooted<ArrayObject*> disposeCapability(
cx, GetOrCreateDisposeCapability(cx, disposableStack));
if (!disposeCapability) {
return false;
}
if (!AddDisposableResource(cx, disposeCapability, JS::UndefinedHandleValue,
UsingHint::Sync, onDispose)) {
return false;
}
// Step 6. Return undefined.
args.rval().setUndefined();
return true;
}
/* static */ bool DisposableStackObject::defer(JSContext* cx, unsigned argc,
JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
return JS::CallNonGenericMethod<is, defer_impl>(cx, args);
}
/**
* Explicit Resource Management Proposal
* 27.3.3.5 DisposableStack.prototype.move ( )
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-disposablestack.prototype.move
*/
/* static */ bool DisposableStackObject::move_impl(JSContext* cx,
const JS::CallArgs& args) {
// Step 1. Let disposableStack be the this value.
JS::Rooted<DisposableStackObject*> disposableStack(
cx, &args.thisv().toObject().as<DisposableStackObject>());
// Step 2. Perform ? RequireInternalSlot(disposableStack,
// [[DisposableState]]).
// Step 3. If disposableStack.[[DisposableState]] is disposed, throw a
// ReferenceError exception.
if (disposableStack->state() == DisposableState::Disposed) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DISPOSABLE_STACK_DISPOSED);
return false;
}
// Step 4. Let newDisposableStack be ?
// OrdinaryCreateFromConstructor(%DisposableStack%,
// "%DisposableStack.prototype%", « [[DisposableState]], [[DisposeCapability]]
// »).
// Step 5. Set newDisposableStack.[[DisposableState]] to pending.
// Step 6. Set newDisposableStack.[[DisposeCapability]] to
// disposableStack.[[DisposeCapability]].
JS::Rooted<JS::Value> existingDisposeCapability(
cx, disposableStack->getReservedSlot(
DisposableStackObject::DISPOSABLE_RESOURCE_STACK_SLOT));
DisposableStackObject* newDisposableStack =
DisposableStackObject::create(cx, nullptr, existingDisposeCapability);
if (!newDisposableStack) {
return false;
}
// Step 7. Set disposableStack.[[DisposeCapability]] to
// NewDisposeCapability().
disposableStack->clearDisposableResourceStack();
// Step 8. Set disposableStack.[[DisposableState]] to disposed.
disposableStack->setState(DisposableState::Disposed);
// Step 9. Return newDisposableStack.
args.rval().setObject(*newDisposableStack);
return true;
}
/* static */ bool DisposableStackObject::move(JSContext* cx, unsigned argc,
JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
return JS::CallNonGenericMethod<is, move_impl>(cx, args);
}
/**
* Explicit Resource Management Proposal
* 27.3.3.1 DisposableStack.prototype.adopt ( value, onDispose )
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-disposablestack.prototype.adopt
*/
/* static */ bool DisposableStackObject::adopt_impl(JSContext* cx,
const JS::CallArgs& args) {
// Step 1. Let disposableStack be the this value.
JS::Rooted<DisposableStackObject*> disposableStack(
cx, &args.thisv().toObject().as<DisposableStackObject>());
// Step 2. Perform ? RequireInternalSlot(disposableStack,
// [[DisposableState]]).
// Step 3. If disposableStack.[[DisposableState]] is disposed, throw a
// ReferenceError exception.
if (disposableStack->state() == DisposableState::Disposed) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DISPOSABLE_STACK_DISPOSED);
return false;
}
// Step 4. If IsCallable(onDispose) is false, throw a TypeError exception.
JS::Handle<JS::Value> onDispose = args.get(1);
if (!ThrowIfOnDisposeNotCallable(cx, onDispose)) {
return false;
}
// Step 5. Let closure be a new Abstract Closure with no parameters that
// captures value and onDispose and performs the following steps when called:
// Step 5.a. (see AdoptClosure)
// Step 6. Let F be CreateBuiltinFunction(closure, 0, "", « »).
JS::Handle<PropertyName*> funName = cx->names().empty_;
JS::Rooted<JSFunction*> F(
cx, NewNativeFunction(cx, AdoptClosure, 0, funName,
gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
if (!F) {
return false;
}
JS::Handle<JS::Value> value = args.get(0);
F->initExtendedSlot(AdoptClosureSlot_ValueSlot, value);
F->initExtendedSlot(AdoptClosureSlot_OnDisposeSlot, onDispose);
// Step 7. Perform ?
// AddDisposableResource(disposableStack.[[DisposeCapability]], undefined,
// sync-dispose, F).
JS::Rooted<ArrayObject*> disposeCapability(
cx, GetOrCreateDisposeCapability(cx, disposableStack));
if (!disposeCapability) {
return false;
}
JS::Rooted<JS::Value> FVal(cx, ObjectValue(*F));
if (!AddDisposableResource(cx, disposeCapability, JS::UndefinedHandleValue,
UsingHint::Sync, FVal)) {
return false;
}
// Step 8. Return value.
args.rval().set(value);
return true;
}
/* static */ bool DisposableStackObject::adopt(JSContext* cx, unsigned argc,
JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
return JS::CallNonGenericMethod<is, adopt_impl>(cx, args);
}
/**
* Explicit Resource Management Proposal
* 27.3.3.4 get DisposableStack.prototype.disposed
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-get-disposablestack.prototype.disposed
*/
/* static */ bool DisposableStackObject::disposed_impl(
JSContext* cx, const JS::CallArgs& args) {
// Step 1. Let disposableStack be the this value.
JS::Rooted<DisposableStackObject*> disposableStack(
cx, &args.thisv().toObject().as<DisposableStackObject>());
// Step 2. Perform ? RequireInternalSlot(disposableStack,
// [[DisposableState]]).
// Step 3. If disposableStack.[[DisposableState]] is disposed, return true.
// Step 4. Otherwise, return false.
args.rval().setBoolean(disposableStack->state() == DisposableState::Disposed);
return true;
}
/* static */ bool DisposableStackObject::disposed(JSContext* cx, unsigned argc,
JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
return JS::CallNonGenericMethod<is, disposed_impl>(cx, args);
}
const JSPropertySpec DisposableStackObject::properties[] = {
JS_STRING_SYM_PS(toStringTag, "DisposableStack", JSPROP_READONLY),
JS_PSG("disposed", disposed, 0),
JS_PS_END,
};
const JSFunctionSpec DisposableStackObject::methods[] = {
JS_FN("use", DisposableStackObject::use, 1, 0),
JS_SELF_HOSTED_FN("dispose", "$DisposableStackDispose", 0, 0),
JS_FN("defer", DisposableStackObject::defer, 1, 0),
JS_FN("move", DisposableStackObject::move, 0, 0),
JS_FN("adopt", DisposableStackObject::adopt, 2, 0),
JS_SELF_HOSTED_SYM_FN(dispose, "$DisposableStackDispose", 0, 0),
JS_FS_END,
};
const ClassSpec DisposableStackObject::classSpec_ = {
GenericCreateConstructor<DisposableStackObject::construct, 0,
gc::AllocKind::FUNCTION>,
GenericCreatePrototype<DisposableStackObject>,
nullptr,
nullptr,
DisposableStackObject::methods,
DisposableStackObject::properties,
nullptr,
};
const JSClass DisposableStackObject::class_ = {
"DisposableStack",
JSCLASS_HAS_RESERVED_SLOTS(DisposableStackObject::RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_DisposableStack),
JS_NULL_CLASS_OPS,
&DisposableStackObject::classSpec_,
};
const JSClass DisposableStackObject::protoClass_ = {
"DisposableStack.prototype",
JSCLASS_HAS_CACHED_PROTO(JSProto_DisposableStack),
JS_NULL_CLASS_OPS,
&DisposableStackObject::classSpec_,
};

View File

@ -0,0 +1,49 @@
/* -*- 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 builtin_DisposableStackObject_h
#define builtin_DisposableStackObject_h
#include "builtin/DisposableStackObjectBase.h"
#include "vm/JSObject.h"
namespace js {
class DisposableStackObject : public DisposableStackObjectBase {
public:
static const JSClass class_;
static const JSClass protoClass_;
static DisposableStackObject* create(
JSContext* cx, JS::Handle<JSObject*> proto,
JS::Handle<JS::Value> initialDisposeCapability =
JS::UndefinedHandleValue);
private:
static const ClassSpec classSpec_;
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
static bool is(JS::Handle<JS::Value> val);
static bool finishInit(JSContext* cx, JS::Handle<JSObject*> ctor,
JS::Handle<JSObject*> proto);
static bool construct(JSContext* cx, unsigned argc, JS::Value* vp);
static bool use_impl(JSContext* cx, const JS::CallArgs& args);
static bool use(JSContext* cx, unsigned argc, JS::Value* vp);
static bool adopt_impl(JSContext* cx, const JS::CallArgs& args);
static bool adopt(JSContext* cx, unsigned argc, JS::Value* vp);
static bool defer_impl(JSContext* cx, const JS::CallArgs& args);
static bool defer(JSContext* cx, unsigned argc, JS::Value* vp);
static bool move_impl(JSContext* cx, const JS::CallArgs& args);
static bool move(JSContext* cx, unsigned argc, JS::Value* vp);
static bool disposed_impl(JSContext* cx, const JS::CallArgs& args);
static bool disposed(JSContext* cx, unsigned argc, JS::Value* vp);
};
} /* namespace js */
#endif /* builtin_DisposableStackObject_h */

View File

@ -0,0 +1,319 @@
/* -*- 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/. */
#include "builtin/DisposableStackObjectBase.h"
#include "builtin/Array.h"
#include "vm/ArrayObject.h"
#include "vm/Interpreter.h"
#include "vm/DisposableRecord-inl.h"
#include "vm/JSObject-inl.h"
using namespace js;
/**
* Explicit Resource Management Proposal
*
* 27.4.3.1 AsyncDisposableStack.prototype.adopt ( value, onDisposeAsync )
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-asyncdisposablestack.prototype.adopt
* Step 5.a
* 27.3.3.1 DisposableStack.prototype.adopt ( value, onDispose )
* https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-disposablestack.prototype.adopt
* Step 5.a
*/
bool js::AdoptClosure(JSContext* cx, unsigned argc, JS::Value* vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
JS::Rooted<JSFunction*> callee(cx, &args.callee().as<JSFunction>());
JS::Rooted<JS::Value> value(
cx, callee->getExtendedSlot(AdoptClosureSlot_ValueSlot));
JS::Rooted<JS::Value> onDispose(
cx, callee->getExtendedSlot(AdoptClosureSlot_OnDisposeSlot));
// Step 5.a. Return ? Call(onDispose, undefined, « value »).
return Call(cx, onDispose, JS::UndefinedHandleValue, value, args.rval());
}
bool js::ThrowIfOnDisposeNotCallable(JSContext* cx,
JS::Handle<JS::Value> onDispose) {
if (IsCallable(onDispose)) {
return true;
}
JS::UniqueChars bytes =
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, onDispose, nullptr);
if (!bytes) {
return false;
}
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_NOT_FUNCTION,
bytes.get());
return false;
}
// Explicit Resource Management Proposal
// CreateDisposableResource ( V, hint [ , method ] )
// https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-createdisposableresource
// Steps 1, 3.
bool js::CreateDisposableResource(JSContext* cx, JS::Handle<JS::Value> objVal,
UsingHint hint,
JS::MutableHandle<JS::Value> result) {
// Step 1. If method is not present, then
// (implicit)
JS::Rooted<JS::Value> method(cx);
JS::Rooted<JS::Value> object(cx);
// Step 1.a. If V is either null or undefined, then
if (objVal.isNullOrUndefined()) {
// Step 1.a.i. Set V to undefined.
// Step 1.a.ii. Set method to undefined.
object.setUndefined();
method.setUndefined();
} else {
// Step 1.b. Else,
// Step 1.b.i. If V is not an Object, throw a TypeError exception.
if (!objVal.isObject()) {
return ThrowCheckIsObject(cx, CheckIsObjectKind::Disposable);
}
// Step 1.b.ii. Set method to ? GetDisposeMethod(V, hint).
// Step 1.b.iii. If method is undefined, throw a TypeError exception.
object.set(objVal);
if (!GetDisposeMethod(cx, object, hint, &method)) {
return false;
}
}
// Step 3. Return the
// DisposableResource Record { [[ResourceValue]]: V, [[Hint]]: hint,
// [[DisposeMethod]]: method }.
DisposableRecordObject* disposableRecord =
DisposableRecordObject::create(cx, object, method, hint);
if (!disposableRecord) {
return false;
}
result.set(ObjectValue(*disposableRecord));
return true;
}
// Explicit Resource Management Proposal
// CreateDisposableResource ( V, hint [ , method ] )
// https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-createdisposableresource
// Steps 2, 3.
bool js::CreateDisposableResource(JSContext* cx, JS::Handle<JS::Value> obj,
UsingHint hint,
JS::Handle<JS::Value> methodVal,
JS::MutableHandle<JS::Value> result) {
JS::Rooted<JS::Value> method(cx);
JS::Rooted<JS::Value> object(cx);
// Step 2. Else,
// Step 2.a. If IsCallable(method) is false, throw a TypeError exception.
if (!IsCallable(methodVal)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DISPOSE_NOT_CALLABLE);
return false;
}
object.set(obj);
method.set(methodVal);
// Step 3. Return the
// DisposableResource Record { [[ResourceValue]]: V, [[Hint]]: hint,
// [[DisposeMethod]]: method }.
DisposableRecordObject* disposableRecord =
DisposableRecordObject::create(cx, object, method, hint);
if (!disposableRecord) {
return false;
}
result.set(ObjectValue(*disposableRecord));
return true;
}
// Explicit Resource Management Proposal
// 7.5.4 AddDisposableResource ( disposeCapability, V, hint [ , method ] )
// https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-adddisposableresource
// Steps 1, 3.
bool js::AddDisposableResource(JSContext* cx,
JS::Handle<ArrayObject*> disposeCapability,
JS::Handle<JS::Value> val, UsingHint hint) {
JS::Rooted<JS::Value> resource(cx);
// Step 1. If method is not present, then
// (implicit)
// Step 1.a. If V is either null or undefined and hint is sync-dispose,
// return unused.
if (val.isNullOrUndefined() && hint == UsingHint::Sync) {
return true;
}
// Step 1.c. Let resource be ? CreateDisposableResource(V, hint).
if (!CreateDisposableResource(cx, val, hint, &resource)) {
return false;
}
// Step 3. Append resource to disposeCapability.[[DisposableResourceStack]].
return NewbornArrayPush(cx, disposeCapability, resource);
}
// Explicit Resource Management Proposal
// 7.5.4 AddDisposableResource ( disposeCapability, V, hint [ , method ] )
// https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-adddisposableresource
bool js::AddDisposableResource(JSContext* cx,
JS::Handle<ArrayObject*> disposeCapability,
JS::Handle<JS::Value> val, UsingHint hint,
JS::Handle<JS::Value> methodVal) {
JS::Rooted<JS::Value> resource(cx);
// Step 2. Else,
// Step 2.a. Assert: V is undefined.
MOZ_ASSERT(val.isUndefined());
// Step 2.b. Let resource be ? CreateDisposableResource(undefined, hint,
// method).
if (!CreateDisposableResource(cx, val, hint, methodVal, &resource)) {
return false;
}
// Step 3. Append resource to disposeCapability.[[DisposableResourceStack]].
return NewbornArrayPush(cx, disposeCapability, resource);
}
// Explicit Resource Management Proposal
// GetDisposeMethod ( V, hint )
// https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-getdisposemethod
bool js::GetDisposeMethod(JSContext* cx, JS::Handle<JS::Value> objVal,
UsingHint hint,
JS::MutableHandle<JS::Value> disposeMethod) {
switch (hint) {
case UsingHint::Async: {
// Step 1. If hint is async-dispose, then
// Step 1.a. Let method be ? GetMethod(V, @@asyncDispose).
// GetMethod throws TypeError if method is not callable
// this is handled below at the end of the function.
JS::Rooted<JS::PropertyKey> idAsync(
cx, PropertyKey::Symbol(cx->wellKnownSymbols().asyncDispose));
JS::Rooted<JSObject*> obj(cx, &objVal.toObject());
if (!GetProperty(cx, obj, obj, idAsync, disposeMethod)) {
return false;
}
// Step 1.b. If method is undefined, then
// GetMethod returns undefined if the function is null but
// since we do not do the conversion here we check for
// null or undefined here.
if (disposeMethod.isNullOrUndefined()) {
// Step 1.b.i. Set method to ? GetMethod(V, @@dispose).
JS::Rooted<JS::PropertyKey> idSync(
cx, PropertyKey::Symbol(cx->wellKnownSymbols().dispose));
JS::Rooted<JS::Value> syncDisposeMethod(cx);
if (!GetProperty(cx, obj, obj, idSync, &syncDisposeMethod)) {
return false;
}
if (!syncDisposeMethod.isNullOrUndefined()) {
// Step 1.b.ii. If method is not undefined, then
if (!IsCallable(syncDisposeMethod)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DISPOSE_NOT_CALLABLE);
return false;
}
// Step 1.b.ii.1. Let closure be a new Abstract Closure with no
// parameters that captures method and performs the following steps
// when called:
// Steps 1.b.ii.1.a-f: See SyncDisposalClosure
// Step 1.b.ii.3. Return CreateBuiltinFunction(closure, 0, "", « »).
JS::Handle<PropertyName*> funName = cx->names().empty_;
JSFunction* asyncWrapper = NewNativeFunction(
cx, SyncDisposalClosure, 0, funName,
gc::AllocKind::FUNCTION_EXTENDED, GenericObject);
if (!asyncWrapper) {
return false;
}
asyncWrapper->initExtendedSlot(
uint8_t(SyncDisposalClosureSlots::Method), syncDisposeMethod);
disposeMethod.set(JS::ObjectValue(*asyncWrapper));
}
}
break;
}
case UsingHint::Sync: {
// Step 2. Else,
// Step 2.a. Let method be ? GetMethod(V, @@dispose).
JS::Rooted<JS::PropertyKey> id(
cx, PropertyKey::Symbol(cx->wellKnownSymbols().dispose));
JS::Rooted<JSObject*> obj(cx, &objVal.toObject());
if (!GetProperty(cx, obj, obj, id, disposeMethod)) {
return false;
}
break;
}
default:
MOZ_CRASH("Invalid UsingHint");
}
// CreateDisposableResource ( V, hint [ , method ] )
// https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-createdisposableresource
//
// Step 1.b.iii. If method is undefined, throw a TypeError exception.
if (disposeMethod.isNullOrUndefined() || !IsCallable(disposeMethod)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DISPOSE_NOT_CALLABLE);
return false;
}
return true;
}
/* static */ ArrayObject*
DisposableStackObjectBase::GetOrCreateDisposeCapability(
JSContext* cx, JS::Handle<DisposableStackObjectBase*> obj) {
ArrayObject* disposablesList = nullptr;
if (obj->isDisposableResourceStackEmpty()) {
disposablesList = NewDenseEmptyArray(cx);
if (!disposablesList) {
return nullptr;
}
obj->setReservedSlot(DISPOSABLE_RESOURCE_STACK_SLOT,
ObjectValue(*disposablesList));
} else {
disposablesList = obj->nonEmptyDisposableResourceStack();
}
return disposablesList;
}
bool DisposableStackObjectBase::isDisposableResourceStackEmpty() const {
return getReservedSlot(DISPOSABLE_RESOURCE_STACK_SLOT).isUndefined();
}
void DisposableStackObjectBase::clearDisposableResourceStack() {
setReservedSlot(DISPOSABLE_RESOURCE_STACK_SLOT, JS::UndefinedValue());
}
ArrayObject* DisposableStackObjectBase::nonEmptyDisposableResourceStack()
const {
MOZ_ASSERT(!isDisposableResourceStackEmpty());
return &getReservedSlot(DISPOSABLE_RESOURCE_STACK_SLOT)
.toObject()
.as<ArrayObject>();
}
DisposableStackObjectBase::DisposableState DisposableStackObjectBase::state()
const {
return DisposableState(uint8_t(getReservedSlot(STATE_SLOT).toInt32()));
}
void DisposableStackObjectBase::setState(DisposableState state) {
setReservedSlot(STATE_SLOT, JS::Int32Value(int32_t(state)));
}

Some files were not shown because too many files have changed in this diff Show More