mirror of https://github.com/mongodb/mongo
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:
parent
ae97353d07
commit
800a3faa71
|
|
@ -50,7 +50,7 @@ a notice will be included in
|
||||||
| [libunwind] | MIT | 1.8.1 | | ✗ |
|
| [libunwind] | MIT | 1.8.1 | | ✗ |
|
||||||
| [linenoise] | BSD-2-Clause | 6cdc775807e57b2c3fd64bd207814f8ee1fe35f3 | | ✗ |
|
| [linenoise] | BSD-2-Clause | 6cdc775807e57b2c3fd64bd207814f8ee1fe35f3 | | ✗ |
|
||||||
| [MongoDB C Driver] | Apache-2.0 | 1.28.1 | ✗ | ✗ |
|
| [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 | | ✗ |
|
| [MurmurHash3] | Public Domain | a6bd3ce7be8ad147ea820a7cf6229a975c0c96bb | | ✗ |
|
||||||
| [nlohmann/json] | MIT | 3.11.3 | ✗ | |
|
| [nlohmann/json] | MIT | 3.11.3 | ✗ | |
|
||||||
| [node] | ISC | 22.1.0 | | |
|
| [node] | ISC | 22.1.0 | | |
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,8 @@ last-continuous:
|
||||||
ticket: SERVER-114126
|
ticket: SERVER-114126
|
||||||
- test_file: jstests/replsets/rollback_index_build_start_abort.js
|
- test_file: jstests/replsets/rollback_index_build_start_abort.js
|
||||||
ticket: SERVER-103955
|
ticket: SERVER-103955
|
||||||
|
- test_file: jstests/sharding/query/javascript_heap_limit.js
|
||||||
|
ticket: SERVER-109200
|
||||||
suites: null
|
suites: null
|
||||||
last-lts:
|
last-lts:
|
||||||
all:
|
all:
|
||||||
|
|
@ -716,4 +718,6 @@ last-lts:
|
||||||
ticket: SERVER-114126
|
ticket: SERVER-114126
|
||||||
- test_file: jstests/replsets/rollback_index_build_start_abort.js
|
- test_file: jstests/replsets/rollback_index_build_start_abort.js
|
||||||
ticket: SERVER-103955
|
ticket: SERVER-103955
|
||||||
|
- test_file: jstests/sharding/query/javascript_heap_limit.js
|
||||||
|
ticket: SERVER-109200
|
||||||
suites: null
|
suites: null
|
||||||
|
|
|
||||||
|
|
@ -145,20 +145,20 @@ const largeAccumulator = {
|
||||||
};
|
};
|
||||||
res = coll
|
res = coll
|
||||||
.aggregate([
|
.aggregate([
|
||||||
{$addFields: {a: {$range: [0, 1000000]}}},
|
{$addFields: {a: {$range: [0, 250000]}}},
|
||||||
{$unwind: "$a"}, // Create a number of documents to be executed by the accumulator.
|
{$unwind: "$a"}, // Create a number of documents to be executed by the accumulator.
|
||||||
{$group: {_id: "$groupBy", count: largeAccumulator}},
|
{$group: {_id: "$groupBy", count: largeAccumulator}},
|
||||||
])
|
])
|
||||||
.toArray();
|
.toArray();
|
||||||
assert.sameMembers(res, [
|
assert.sameMembers(res, [
|
||||||
{_id: 1, count: 1000000},
|
{_id: 1, count: 250000},
|
||||||
{_id: 2, count: 1000000},
|
{_id: 2, count: 250000},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// With $bucket.
|
// With $bucket.
|
||||||
res = coll
|
res = coll
|
||||||
.aggregate([
|
.aggregate([
|
||||||
{$addFields: {a: {$range: [0, 1000000]}}},
|
{$addFields: {a: {$range: [0, 250000]}}},
|
||||||
{$unwind: "$a"}, // Create a number of documents to be executed by the accumulator.
|
{$unwind: "$a"}, // Create a number of documents to be executed by the accumulator.
|
||||||
{
|
{
|
||||||
$bucket: {groupBy: "$groupBy", boundaries: [1, 2, 3], output: {count: largeAccumulator}},
|
$bucket: {groupBy: "$groupBy", boundaries: [1, 2, 3], output: {count: largeAccumulator}},
|
||||||
|
|
@ -166,6 +166,6 @@ res = coll
|
||||||
])
|
])
|
||||||
.toArray();
|
.toArray();
|
||||||
assert.sameMembers(res, [
|
assert.sameMembers(res, [
|
||||||
{_id: 1, count: 1000000},
|
{_id: 1, count: 250000},
|
||||||
{_id: 2, count: 1000000},
|
{_id: 2, count: 250000},
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ const expectedGlobalVars = [
|
||||||
"Error",
|
"Error",
|
||||||
"EvalError",
|
"EvalError",
|
||||||
"FinalizationRegistry",
|
"FinalizationRegistry",
|
||||||
|
"Float16Array",
|
||||||
"Float32Array",
|
"Float32Array",
|
||||||
"Float64Array",
|
"Float64Array",
|
||||||
"Function",
|
"Function",
|
||||||
|
|
@ -48,6 +49,7 @@ const expectedGlobalVars = [
|
||||||
"Int32Array",
|
"Int32Array",
|
||||||
"Int8Array",
|
"Int8Array",
|
||||||
"InternalError",
|
"InternalError",
|
||||||
|
"Iterator",
|
||||||
"JSON",
|
"JSON",
|
||||||
"MD5",
|
"MD5",
|
||||||
"Map",
|
"Map",
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ st.shardColl(coll, {_id: 1}, {_id: 0}, {_id: 0});
|
||||||
explain: {
|
explain: {
|
||||||
aggregate: coll.getName(),
|
aggregate: coll.getName(),
|
||||||
pipeline: [
|
pipeline: [
|
||||||
{$addFields: {a: {$range: [0, 1000000]}}},
|
{$addFields: {a: {$range: [0, 250000]}}},
|
||||||
{$unwind: "$a"}, // Create a number of documents to be executed by the accumulator.
|
{$unwind: "$a"}, // Create a number of documents to be executed by the accumulator.
|
||||||
{$group: {_id: "$groupBy", count: largeAccumulator}},
|
{$group: {_id: "$groupBy", count: largeAccumulator}},
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
function allocateLargeString() {
|
||||||
const arraySize = 1000000;
|
const arraySize = 1000000;
|
||||||
let str = new Array(arraySize).fill(0);
|
let str = new Array(arraySize).fill(0);
|
||||||
|
|
@ -116,6 +122,8 @@ const findWithWhere = {
|
||||||
* part of an aggregation pipeline.
|
* part of an aggregation pipeline.
|
||||||
*/
|
*/
|
||||||
function runCommonTests(db) {
|
function runCommonTests(db) {
|
||||||
|
setLegacyMemoryTracking({db: db, useLegacy: false});
|
||||||
|
|
||||||
// All commands are expected to work with a sufficient JS heap size.
|
// All commands are expected to work with a sufficient JS heap size.
|
||||||
setHeapSizeLimitMB({db: db, queryLimit: sufficentHeapSizeMB, globalLimit: sufficentHeapSizeMB});
|
setHeapSizeLimitMB({db: db, queryLimit: sufficentHeapSizeMB, globalLimit: sufficentHeapSizeMB});
|
||||||
assert.commandWorked(db.runCommand(aggregateWithJSFunction));
|
assert.commandWorked(db.runCommand(aggregateWithJSFunction));
|
||||||
|
|
@ -135,6 +143,13 @@ function runCommonTests(db) {
|
||||||
assert.commandFailedWithCode(db.runCommand(aggregateWithJSFunction), ErrorCodes.JSInterpreterFailure);
|
assert.commandFailedWithCode(db.runCommand(aggregateWithJSFunction), ErrorCodes.JSInterpreterFailure);
|
||||||
assert.commandFailedWithCode(db.runCommand(aggregateWithInternalJsReduce), ErrorCodes.JSInterpreterFailure);
|
assert.commandFailedWithCode(db.runCommand(aggregateWithInternalJsReduce), ErrorCodes.JSInterpreterFailure);
|
||||||
assert.commandFailedWithCode(db.runCommand(aggregateWithUserDefinedAccumulator), 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.
|
* only evaluated on mongod, not on mongos.
|
||||||
*/
|
*/
|
||||||
function runShardTests(db) {
|
function runShardTests(db) {
|
||||||
|
setLegacyMemoryTracking({db: db, useLegacy: false});
|
||||||
|
|
||||||
// All commands are expected to work with a sufficient JS heap size.
|
// All commands are expected to work with a sufficient JS heap size.
|
||||||
setHeapSizeLimitMB({db: db, queryLimit: sufficentHeapSizeMB, globalLimit: sufficentHeapSizeMB});
|
setHeapSizeLimitMB({db: db, queryLimit: sufficentHeapSizeMB, globalLimit: sufficentHeapSizeMB});
|
||||||
assert.commandWorked(db.runCommand(findWithJavaScriptFunction));
|
assert.commandWorked(db.runCommand(findWithJavaScriptFunction));
|
||||||
|
|
@ -168,6 +185,14 @@ function runShardTests(db) {
|
||||||
// TODO SERVER-45454: Uncomment when $where is executed via aggregation JavaScript expression.
|
// TODO SERVER-45454: Uncomment when $where is executed via aggregation JavaScript expression.
|
||||||
// assert.commandFailedWithCode(db.runCommand(findWithWhere), ErrorCodes.JSInterpreterFailure);
|
// assert.commandFailedWithCode(db.runCommand(findWithWhere), ErrorCodes.JSInterpreterFailure);
|
||||||
assert.commandFailedWithCode(db.runCommand(mapReduce), 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.
|
// Test command invocations that can execute JavaScript on either mongos or mongod.
|
||||||
|
|
|
||||||
12
sbom.json
12
sbom.json
|
|
@ -71,7 +71,7 @@
|
||||||
"components": [
|
"components": [
|
||||||
{
|
{
|
||||||
"type": "library",
|
"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": {
|
"supplier": {
|
||||||
"name": "Mozilla Corporation",
|
"name": "Mozilla Corporation",
|
||||||
"url": [
|
"url": [
|
||||||
|
|
@ -81,7 +81,7 @@
|
||||||
"author": "Mozilla Corporation",
|
"author": "Mozilla Corporation",
|
||||||
"group": "mozilla",
|
"group": "mozilla",
|
||||||
"name": "Mozilla Firefox ESR",
|
"name": "Mozilla Firefox ESR",
|
||||||
"version": "128.11.0esr",
|
"version": "140.3.0esr",
|
||||||
"description": "The C++-only SpiderMonkey component of FireFox ESR used by MongoDB.",
|
"description": "The C++-only SpiderMonkey component of FireFox ESR used by MongoDB.",
|
||||||
"licenses": [
|
"licenses": [
|
||||||
{
|
{
|
||||||
|
|
@ -91,8 +91,8 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"copyright": "Mozilla Corporation",
|
"copyright": "Mozilla Corporation",
|
||||||
"cpe": "cpe:2.3:a:mozilla:firefox:128.11.0:*:*:*:esr:*:*:*",
|
"cpe": "cpe:2.3:a:mozilla:firefox:140.3.0:*:*:*:esr:*:*:*",
|
||||||
"purl": "pkg:deb/debian/firefox-esr@128.11.0esr-1?arch=source",
|
"purl": "pkg:deb/debian/firefox-esr@140.3.0esr-1?arch=source",
|
||||||
"externalReferences": [
|
"externalReferences": [
|
||||||
{
|
{
|
||||||
"url": "https://github.com/mozilla-firefox/firefox.git",
|
"url": "https://github.com/mozilla-firefox/firefox.git",
|
||||||
|
|
@ -2628,7 +2628,7 @@
|
||||||
"pkg:github/libunwind/libunwind@v1.8.1",
|
"pkg:github/libunwind/libunwind@v1.8.1",
|
||||||
"pkg:github/antirez/linenoise@6cdc775807e57b2c3fd64bd207814f8ee1fe35f3",
|
"pkg:github/antirez/linenoise@6cdc775807e57b2c3fd64bd207814f8ee1fe35f3",
|
||||||
"pkg:github/mongodb/mongo-c-driver@1.28.1",
|
"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: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/ocspbuilder@0.10.2",
|
||||||
"pkg:pypi/ocspresponder@0.5.0",
|
"pkg:pypi/ocspresponder@0.5.0",
|
||||||
|
|
@ -2768,7 +2768,7 @@
|
||||||
"dependsOn": []
|
"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": []
|
"dependsOn": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,8 @@ public:
|
||||||
|
|
||||||
virtual int getJSHeapLimitMB() const = 0;
|
virtual int getJSHeapLimitMB() const = 0;
|
||||||
virtual void setJSHeapLimitMB(int limit) = 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 std::string getLoadPath() const = 0;
|
||||||
virtual void setLoadPath(const std::string& loadPath) = 0;
|
virtual void setLoadPath(const std::string& loadPath) = 0;
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,14 @@ void MozJSScriptEngine::setJSHeapLimitMB(int limit) {
|
||||||
gJSHeapLimitMB.store(limit);
|
gJSHeapLimitMB.store(limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MozJSScriptEngine::getJSUseLegacyMemoryTracking() const {
|
||||||
|
return gJSUseLegacyMemoryTracking.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MozJSScriptEngine::setJSUseLegacyMemoryTracking(bool shouldUseLegacy) {
|
||||||
|
gJSUseLegacyMemoryTracking.store(shouldUseLegacy);
|
||||||
|
}
|
||||||
|
|
||||||
std::string MozJSScriptEngine::getLoadPath() const {
|
std::string MozJSScriptEngine::getLoadPath() const {
|
||||||
return _loadPath;
|
return _loadPath;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,9 @@ public:
|
||||||
int getJSHeapLimitMB() const override;
|
int getJSHeapLimitMB() const override;
|
||||||
void setJSHeapLimitMB(int limit) override;
|
void setJSHeapLimitMB(int limit) override;
|
||||||
|
|
||||||
|
bool getJSUseLegacyMemoryTracking() const override;
|
||||||
|
void setJSUseLegacyMemoryTracking(bool shouldUseLegacyEngine) override;
|
||||||
|
|
||||||
std::string getLoadPath() const override;
|
std::string getLoadPath() const override;
|
||||||
void setLoadPath(const std::string& loadPath) override;
|
void setLoadPath(const std::string& loadPath) override;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,3 +46,11 @@ server_parameters:
|
||||||
cpp_varname: gJSHeapLimitMB
|
cpp_varname: gJSHeapLimitMB
|
||||||
default: 1100
|
default: 1100
|
||||||
redact: false
|
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
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ void mongoToJSException(JSContext* cx) {
|
||||||
JS_SetPendingException(cx, val);
|
JS_SetPendingException(cx, val);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
JS::ReportUncatchableException(cx);
|
||||||
// If a JSAPI callback returns false without setting a pending exception, SpiderMonkey will
|
// If a JSAPI callback returns false without setting a pending exception, SpiderMonkey will
|
||||||
// treat it as an uncatchable error.
|
// treat it as an uncatchable error.
|
||||||
auto scope = getScope(cx);
|
auto scope = getScope(cx);
|
||||||
|
|
|
||||||
|
|
@ -366,9 +366,13 @@ void MozJSImplScope::_gcCallback(JSContext* rt,
|
||||||
LOGV2_INFO(22787,
|
LOGV2_INFO(22787,
|
||||||
"MozJS GC heap stats",
|
"MozJS GC heap stats",
|
||||||
"phase"_attr = (status == JSGC_BEGIN ? "prologue" : "epilogue"),
|
"phase"_attr = (status == JSGC_BEGIN ? "prologue" : "epilogue"),
|
||||||
"reason"_attr = reason,
|
"reason"_attr = ExplainGCReason(reason),
|
||||||
"total"_attr = mongo::sm::get_total_bytes(),
|
"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)
|
#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.");
|
"JavaScript may not be able to initialize with a heap limit less than 10MB.");
|
||||||
}
|
}
|
||||||
size_t mallocMemoryLimit = 1024ul * 1024 * jsHeapLimit;
|
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);
|
stdx::unique_lock<stdx::mutex> lk(gRuntimeCreationMutex);
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "mongo/config.h" // IWYU pragma: keep
|
#include "mongo/config.h" // IWYU pragma: keep
|
||||||
|
#include "mongo/logv2/log.h"
|
||||||
#include "mongo/scripting/mozjs/implscope.h"
|
#include "mongo/scripting/mozjs/implscope.h"
|
||||||
|
|
||||||
#include <jscustomallocator.h>
|
#include <jscustomallocator.h>
|
||||||
|
|
@ -49,6 +50,8 @@
|
||||||
#error "Unsupported platform"
|
#error "Unsupported platform"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kQuery
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This shim interface (which controls dynamic allocation within SpiderMonkey),
|
* This shim interface (which controls dynamic allocation within SpiderMonkey),
|
||||||
* consciously uses std::malloc and friends over mongoMalloc. It does this
|
* 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
|
* maximum number of bytes we will consider handing out. They are set by
|
||||||
* MozJSImplScope on start up.
|
* 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;
|
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
|
} // namespace
|
||||||
|
|
||||||
size_t get_total_bytes() {
|
size_t get_total_bytes() {
|
||||||
return total_bytes;
|
return get_malloc_bytes() + get_mmap_bytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset(size_t bytes) {
|
size_t get_malloc_bytes() {
|
||||||
total_bytes = 0;
|
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;
|
max_bytes = bytes;
|
||||||
|
track_mmap_bytes = track_mmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t get_max_bytes() {
|
size_t get_max_bytes() {
|
||||||
return 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);
|
size_t get_current(void* ptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -99,7 +135,8 @@ size_t get_current(void* ptr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void* wrap_alloc(T&& func, void* ptr, size_t bytes) {
|
void* wrap_alloc(T&& func, void* ptr, size_t bytes) {
|
||||||
size_t mb = get_max_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
|
// 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
|
// SharedImmutableStringsCache while holding its corresponding mutex. Our js_free implementation
|
||||||
|
|
@ -109,13 +146,22 @@ void* wrap_alloc(T&& func, void* ptr, size_t bytes) {
|
||||||
// for the SharedImmutableStringsCache (order 600). This triggered a failure of a MOZ_ASSERT
|
// 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
|
// 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).
|
// 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)) {
|
// In some contexts MozJS has no safe recovery from OOM and crashes the process to avoid
|
||||||
auto scope = mongo::mozjs::MozJSImplScope::getThreadScope();
|
// unsafe behavior. In that case allow the allocation to proceed and go over the allowed
|
||||||
if (scope) {
|
// memory limit. Otherwise fail immediately.
|
||||||
scope->setOOM();
|
if (!oomUnsafe) {
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* p = func(ptr, bytes);
|
void* p = func(ptr, bytes);
|
||||||
|
|
@ -147,7 +193,7 @@ void* wrap_alloc(T&& func, void* ptr, size_t bytes) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
total_bytes += mongo::sm::get_current(p);
|
malloc_bytes += mongo::sm::get_current(p);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,9 +217,12 @@ size_t get_current(void* ptr) {
|
||||||
} // namespace mongo
|
} // namespace mongo
|
||||||
|
|
||||||
JS_PUBLIC_DATA arena_id_t js::MallocArena;
|
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::ArrayBufferContentsArena;
|
||||||
JS_PUBLIC_DATA arena_id_t js::StringBufferArena;
|
JS_PUBLIC_DATA arena_id_t js::StringBufferArena;
|
||||||
|
|
||||||
|
thread_local size_t js::AutoEnterOOMUnsafeRegion::isInOomUnsafeRegion_ = 0;
|
||||||
|
|
||||||
void* mongo_arena_malloc(size_t bytes) {
|
void* mongo_arena_malloc(size_t bytes) {
|
||||||
return std::malloc(bytes);
|
return std::malloc(bytes);
|
||||||
}
|
}
|
||||||
|
|
@ -195,11 +244,11 @@ void* mongo_arena_realloc(void* p, size_t bytes) {
|
||||||
|
|
||||||
void* ptr = std::realloc(p, bytes);
|
void* ptr = std::realloc(p, bytes);
|
||||||
if (!ptr) {
|
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;
|
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;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -208,7 +257,7 @@ void* mongo_free(void* ptr) {
|
||||||
// buffer, so this may result in undercounting
|
// buffer, so this may result in undercounting
|
||||||
size_t current = mongo::sm::get_current(ptr);
|
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);
|
std::free(ptr);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -272,8 +321,9 @@ void js_free(void* p) {
|
||||||
|
|
||||||
void js::InitMallocAllocator() {
|
void js::InitMallocAllocator() {
|
||||||
MallocArena = 0;
|
MallocArena = 0;
|
||||||
ArrayBufferContentsArena = 1;
|
BackgroundMallocArena = 1;
|
||||||
StringBufferArena = 2;
|
ArrayBufferContentsArena = 2;
|
||||||
|
StringBufferArena = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
void js::ShutDownMallocAllocator() {}
|
void js::ShutDownMallocAllocator() {}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ namespace mozjs {
|
||||||
class JSCustomAllocatorTest : public unittest::Test {
|
class JSCustomAllocatorTest : public unittest::Test {
|
||||||
protected:
|
protected:
|
||||||
void setUp() override {
|
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,
|
// Note: get_total_bytes() is an estimate and won't exactly count allocated bytes,
|
||||||
// test should only compare to 0
|
// test should only compare to 0
|
||||||
|
|
@ -55,13 +55,13 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
void tearDown() override {
|
void tearDown() override {
|
||||||
mongo::sm::reset(0);
|
mongo::sm::reset(0, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TEST_F(JSCustomAllocatorTest, MallocUpToLimit) {
|
TEST_F(JSCustomAllocatorTest, MallocUpToLimit) {
|
||||||
mongo::sm::reset(100);
|
mongo::sm::reset(100, false);
|
||||||
ASSERT_EQUALS(mongo::sm::get_total_bytes(), 0);
|
ASSERT_EQUALS(mongo::sm::get_total_bytes(), 0);
|
||||||
|
|
||||||
void* ptr1 = js_malloc(20);
|
void* ptr1 = js_malloc(20);
|
||||||
|
|
@ -85,7 +85,7 @@ TEST_F(JSCustomAllocatorTest, MallocUpToLimit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(JSCustomAllocatorTest, ReallocUpToLimit) {
|
TEST_F(JSCustomAllocatorTest, ReallocUpToLimit) {
|
||||||
mongo::sm::reset(100);
|
mongo::sm::reset(100, false);
|
||||||
ASSERT_EQUALS(mongo::sm::get_total_bytes(), 0);
|
ASSERT_EQUALS(mongo::sm::get_total_bytes(), 0);
|
||||||
|
|
||||||
void* ptr1 = js_malloc(20);
|
void* ptr1 = js_malloc(20);
|
||||||
|
|
@ -104,7 +104,7 @@ TEST_F(JSCustomAllocatorTest, ReallocUpToLimit) {
|
||||||
|
|
||||||
|
|
||||||
TEST_F(JSCustomAllocatorTest, CallocUpToLimit) {
|
TEST_F(JSCustomAllocatorTest, CallocUpToLimit) {
|
||||||
mongo::sm::reset(100);
|
mongo::sm::reset(100, false);
|
||||||
ASSERT_EQUALS(mongo::sm::get_total_bytes(), 0);
|
ASSERT_EQUALS(mongo::sm::get_total_bytes(), 0);
|
||||||
|
|
||||||
void* ptr1 = js_calloc(10, 2);
|
void* ptr1 = js_calloc(10, 2);
|
||||||
|
|
|
||||||
|
|
@ -98,14 +98,21 @@ JSObject* ModuleLoader::loadRootModule(JSContext* cx,
|
||||||
const std::string& path,
|
const std::string& path,
|
||||||
boost::optional<StringData> source) {
|
boost::optional<StringData> source) {
|
||||||
JS::RootedString baseUrl(cx, JS_NewStringCopyN(cx, _baseUrl.c_str(), _baseUrl.size()));
|
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));
|
JS::RootedObject info(cx, createScriptPrivateInfo(cx, baseUrl, source));
|
||||||
if (!info) {
|
if (!info) {
|
||||||
return nullptr;
|
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create info");
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::RootedValue referencingPrivate(cx, JS::ObjectValue(*info));
|
JS::RootedValue referencingPrivate(cx, JS::ObjectValue(*info));
|
||||||
JS::RootedString specifier(cx, JS_NewStringCopyN(cx, path.c_str(), path.size()));
|
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) {
|
if (!moduleRequest) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +155,13 @@ bool ModuleLoader::importModuleDynamically(JSContext* cx,
|
||||||
JS::HandleObject moduleRequest,
|
JS::HandleObject moduleRequest,
|
||||||
JS::HandleObject promise) {
|
JS::HandleObject promise) {
|
||||||
JS::RootedString baseUrl(cx, JS_NewStringCopyN(cx, _baseUrl.c_str(), _baseUrl.size()));
|
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));
|
JS::RootedObject info(cx, createScriptPrivateInfo(cx, baseUrl));
|
||||||
|
if (!info) {
|
||||||
|
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create info");
|
||||||
|
}
|
||||||
JS::RootedValue newReferencingPrivate(cx, JS::ObjectValue(*info));
|
JS::RootedValue newReferencingPrivate(cx, JS::ObjectValue(*info));
|
||||||
|
|
||||||
// The dynamic `import` method returns a Promise, and thus allows us to perform module loading
|
// 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,
|
JS::Rooted<JSString*> path(cx,
|
||||||
resolveAndNormalize(cx, moduleRequest, newReferencingPrivate));
|
resolveAndNormalize(cx, moduleRequest, newReferencingPrivate));
|
||||||
if (!path) {
|
if (!path) {
|
||||||
|
LOGV2_ERROR(716284, "Failed to resolve and normalize path");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::RootedObject module(cx, loadAndParse(cx, path, newReferencingPrivate));
|
JS::RootedObject module(cx, loadAndParse(cx, path, newReferencingPrivate));
|
||||||
if (!module) {
|
if (!module) {
|
||||||
|
LOGV2_ERROR(716285, "Failed to load and parse module");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!JS::ModuleLink(cx, module)) {
|
if (!JS::ModuleLink(cx, module)) {
|
||||||
|
LOGV2_ERROR(716286, "Failed to link module");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,6 +193,10 @@ bool ModuleLoader::importModuleDynamically(JSContext* cx,
|
||||||
|
|
||||||
JSObject* evaluationObject = ok ? &rval.toObject() : nullptr;
|
JSObject* evaluationObject = ok ? &rval.toObject() : nullptr;
|
||||||
JS::RootedObject evaluationPromise(cx, evaluationObject);
|
JS::RootedObject evaluationPromise(cx, evaluationObject);
|
||||||
|
if (!evaluationPromise) {
|
||||||
|
LOGV2_ERROR(716287, "Failed to create evaluation promise");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return JS::FinishDynamicModuleImport(
|
return JS::FinishDynamicModuleImport(
|
||||||
cx, evaluationPromise, newReferencingPrivate, moduleRequest, promise);
|
cx, evaluationPromise, newReferencingPrivate, moduleRequest, promise);
|
||||||
}
|
}
|
||||||
|
|
@ -239,8 +259,18 @@ JSString* ModuleLoader::resolveAndNormalize(JSContext* cx,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::filesystem::path specifierPath(JS_EncodeStringToUTF8(cx, specifierString).get());
|
JS::UniqueChars specifierChars = JS_EncodeStringToUTF8(cx, specifierString);
|
||||||
auto refAbsPath = boost::filesystem::path(JS_EncodeStringToUTF8(cx, refPath).get());
|
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)) {
|
if (is_directory(specifierPath)) {
|
||||||
JS_ReportErrorUTF8(cx,
|
JS_ReportErrorUTF8(cx,
|
||||||
"Directory import '%s' is not supported, imported from %s",
|
"Directory import '%s' is not supported, imported from %s",
|
||||||
|
|
@ -513,10 +543,19 @@ JSObject* ModuleLoader::createScriptPrivateInfo(JSContext* cx,
|
||||||
JS::LossyUTF8CharsToNewTwoByteCharsZ(
|
JS::LossyUTF8CharsToNewTwoByteCharsZ(
|
||||||
cx, JS::UTF8Chars(source->data(), len), &len, js::MallocArena)
|
cx, JS::UTF8Chars(source->data(), len), &len, js::MallocArena)
|
||||||
.get());
|
.get());
|
||||||
|
if (!ucbuf) {
|
||||||
|
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create ucbuf");
|
||||||
|
}
|
||||||
|
|
||||||
JS::RootedString sourceValue(cx, JS_NewUCStringCopyN(cx, ucbuf.get(), len));
|
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)) {
|
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());
|
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;
|
boost::system::error_code ec;
|
||||||
auto resolvedPath =
|
auto resolvedPath =
|
||||||
|
|
|
||||||
|
|
@ -279,9 +279,12 @@ public:
|
||||||
JS::RootedObject proto(_context);
|
JS::RootedObject proto(_context);
|
||||||
|
|
||||||
JS::RealmOptions options;
|
JS::RealmOptions options;
|
||||||
_proto.init(_context,
|
JSObject* global = JS_NewGlobalObject(
|
||||||
_assertPtr(JS_NewGlobalObject(
|
_context, &_jsclass, nullptr, JS::DontFireOnNewGlobalHook, options);
|
||||||
_context, &_jsclass, nullptr, JS::DontFireOnNewGlobalHook, options)));
|
if (!global) {
|
||||||
|
uasserted(ErrorCodes::JSInterpreterFailure, "Failed to create global object");
|
||||||
|
}
|
||||||
|
_proto.init(_context, global);
|
||||||
|
|
||||||
JSAutoRealm ac(_context, _proto);
|
JSAutoRealm ac(_context, _proto);
|
||||||
_installFunctions(_proto, T::freeFunctions);
|
_installFunctions(_proto, T::freeFunctions);
|
||||||
|
|
@ -579,6 +582,15 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* _assertPtr(JSObject* ptr) {
|
JSObject* _assertPtr(JSObject* ptr) {
|
||||||
|
|
||||||
|
// If we don’t 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)
|
if (!ptr)
|
||||||
throwCurrentJSException(
|
throwCurrentJSException(
|
||||||
_context, ErrorCodes::JSInterpreterFailure, "Failed to JS_NewX");
|
_context, ErrorCodes::JSInterpreterFailure, "Failed to JS_NewX");
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ mongo_cc_library(
|
||||||
srcs = [
|
srcs = [
|
||||||
"extract/js/src/builtin/RegExp.cpp",
|
"extract/js/src/builtin/RegExp.cpp",
|
||||||
"extract/js/src/frontend/Parser.cpp",
|
"extract/js/src/frontend/Parser.cpp",
|
||||||
|
"extract/js/src/gc/Memory.cpp",
|
||||||
"extract/js/src/gc/StoreBuffer.cpp",
|
"extract/js/src/gc/StoreBuffer.cpp",
|
||||||
"extract/js/src/irregexp/RegExpNativeMacroAssembler.cpp",
|
"extract/js/src/irregexp/RegExpNativeMacroAssembler.cpp",
|
||||||
"extract/js/src/irregexp/imported/regexp-ast.cc",
|
"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/Interpreter.cpp",
|
||||||
"extract/js/src/vm/ProfilingStack.cpp",
|
"extract/js/src/vm/ProfilingStack.cpp",
|
||||||
"extract/js/src/wasm/WasmCode-platform.cpp",
|
"extract/js/src/wasm/WasmCode-platform.cpp",
|
||||||
"extract/mfbt/lz4/lz4.c",
|
"extract/js/src/xsum/xsum.cpp",
|
||||||
"extract/mfbt/lz4/lz4frame.c",
|
|
||||||
"extract/mfbt/lz4/lz4hc.c",
|
|
||||||
"extract/mfbt/lz4/xxhash.c",
|
|
||||||
"extract/mozglue/misc/AutoProfilerLabel.cpp",
|
"extract/mozglue/misc/AutoProfilerLabel.cpp",
|
||||||
"extract/mozglue/misc/AwakeTimeStamp.cpp",
|
"extract/mozglue/misc/AwakeTimeStamp.cpp",
|
||||||
"extract/mozglue/misc/Debug.cpp",
|
"extract/mozglue/misc/Debug.cpp",
|
||||||
"extract/mozglue/misc/MmapFaultHandler.cpp",
|
"extract/mozglue/misc/MmapFaultHandler.cpp",
|
||||||
|
"extract/mozglue/misc/Now.cpp",
|
||||||
"extract/mozglue/misc/Printf.cpp",
|
"extract/mozglue/misc/Printf.cpp",
|
||||||
"extract/mozglue/misc/SIMD.cpp",
|
"extract/mozglue/misc/SIMD.cpp",
|
||||||
"extract/mozglue/misc/StackWalk.cpp",
|
"extract/mozglue/misc/StackWalk.cpp",
|
||||||
"extract/mozglue/misc/TimeStamp.cpp",
|
"extract/mozglue/misc/TimeStamp.cpp",
|
||||||
"extract/mozglue/misc/Uptime.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/freeOpToJSContext.cpp",
|
||||||
"mongo_sources/mongoErrorReportToString.cpp",
|
"mongo_sources/mongoErrorReportToString.cpp",
|
||||||
] + select({
|
] + select({
|
||||||
|
|
@ -161,6 +164,7 @@ mongo_cc_library(
|
||||||
"extract/mfbt/**/*.h",
|
"extract/mfbt/**/*.h",
|
||||||
"extract/modules/fdlibm/**/*.h",
|
"extract/modules/fdlibm/**/*.h",
|
||||||
"mongo_sources/**/*.h",
|
"mongo_sources/**/*.h",
|
||||||
|
"extract/mozglue/static/lz4/*.h",
|
||||||
]) + PLATFORM_SRCS,
|
]) + PLATFORM_SRCS,
|
||||||
hdrs = glob(["include/**/*.h"]),
|
hdrs = glob(["include/**/*.h"]),
|
||||||
copts = PLATFORM_COPTS + [
|
copts = PLATFORM_COPTS + [
|
||||||
|
|
@ -241,11 +245,15 @@ mongo_cc_library(
|
||||||
# C5101: use of preprocessor directive in function-like macro
|
# C5101: use of preprocessor directive in function-like macro
|
||||||
# argument list is undefined behavior
|
# argument list is undefined behavior
|
||||||
"/wd5101",
|
"/wd5101",
|
||||||
|
|
||||||
|
# Enable extern constexpr variables
|
||||||
|
"/Zc:externConstexpr",
|
||||||
],
|
],
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
"-Wno-sign-compare",
|
"-Wno-sign-compare",
|
||||||
# Disable warnings for third party libraries as no action will be taken to fix them
|
# Disable warnings for third party libraries as no action will be taken to fix them
|
||||||
# and they just clutter the output logs
|
# and they just clutter the output logs
|
||||||
|
"-Wno-unused-value",
|
||||||
"-Wno-unused-variable",
|
"-Wno-unused-variable",
|
||||||
"-Wno-implicit-fallthrough",
|
"-Wno-implicit-fallthrough",
|
||||||
# Bazel doesn't differentiate between compile flags for C and C++.
|
# 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:macos": ["-Wl,-undefined,dynamic_lookup"],
|
||||||
"@platforms//os:windows": [
|
"@platforms//os:windows": [
|
||||||
"ntdll.lib",
|
"ntdll.lib",
|
||||||
|
"mincore.lib",
|
||||||
],
|
],
|
||||||
"//conditions:default": [""],
|
"//conditions:default": [""],
|
||||||
}),
|
}),
|
||||||
|
|
@ -345,6 +354,7 @@ mongo_cc_library(
|
||||||
"**/*.tbl",
|
"**/*.tbl",
|
||||||
]),
|
]),
|
||||||
deps = [
|
deps = [
|
||||||
|
"//src/third_party/fmt",
|
||||||
"//src/third_party/icu4c-57.1/source:icu_i18n",
|
"//src/third_party/icu4c-57.1/source:icu_i18n",
|
||||||
"//src/third_party/zlib",
|
"//src/third_party/zlib",
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ CFLAGS="$CFLAGS -D__STDC_FORMAT_MACROS" \
|
||||||
--enable-optimize \
|
--enable-optimize \
|
||||||
--disable-js-shell \
|
--disable-js-shell \
|
||||||
--disable-tests \
|
--disable-tests \
|
||||||
--disable-new-pass-manager \
|
|
||||||
--disable-wasm-moz-intgemm
|
--disable-wasm-moz-intgemm
|
||||||
|
|
||||||
# we have to run make to generate a byte code version of the self hosted js and
|
# 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
|
# this is all of the EXPORTS.js files from the moz.build
|
||||||
mkdir -p include/js
|
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/
|
cp extract/js/public/$i include/js/
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
@ -121,11 +120,12 @@ cp extract/js/src/_build/js/public/PrefsGenerated.h include/js/
|
||||||
|
|
||||||
for i in 'ProfilingCategoryList.h' ; do
|
for i in 'ProfilingCategoryList.h' ; do
|
||||||
cp extract/js/src/_build/mozglue/baseprofiler/public/$i include/js/
|
cp extract/js/src/_build/mozglue/baseprofiler/public/$i include/js/
|
||||||
|
cp extract/js/src/_build/dist/include/$i include
|
||||||
done
|
done
|
||||||
|
|
||||||
# this is all of the EXPORTS.js.experimental files from the moz.build
|
# this is all of the EXPORTS.js.experimental files from the moz.build
|
||||||
mkdir -p include/js/experimental
|
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/
|
cp extract/js/public/experimental/$i include/js/experimental/
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
@ -143,7 +143,7 @@ done
|
||||||
|
|
||||||
# this is all of the EXPORTS.mozilla files from the moz.build's (i.e mfbt)
|
# this is all of the EXPORTS.mozilla files from the moz.build's (i.e mfbt)
|
||||||
mkdir -p include/mozilla
|
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/
|
cp extract/mfbt/$i include/mozilla/
|
||||||
done
|
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
|
cp extract/js/src/_build/dist/include/mozilla/$i include/mozilla
|
||||||
done
|
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
|
mkdir -p include/mozilla/glue
|
||||||
cp extract/js/src/_build/dist/include/mozilla/glue/Debug.h 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/*.cpp extract/mozglue/misc
|
||||||
cp mozilla-release/mozglue/misc/StackWalk_windows.h include/mozilla/
|
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
|
mkdir -p include/vtune
|
||||||
touch include/vtune/VTuneWrapper.h
|
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/.deps/
|
||||||
extract/js/src/_build/mozglue/misc/Makefile
|
extract/js/src/_build/mozglue/misc/Makefile
|
||||||
extract/js/src/_build/mozinfo.json
|
extract/js/src/_build/mozinfo.json
|
||||||
extract/js/src/_build/old-configure.vars
|
|
||||||
extract/js/src/_build/testing/
|
extract/js/src/_build/testing/
|
||||||
extract/js/src/_build/_tests/mozbase/
|
extract/js/src/_build/_tests/mozbase/
|
||||||
extract/js/src/_build/third_party/
|
extract/js/src/_build/third_party/
|
||||||
|
|
@ -235,8 +251,6 @@ __XARGS_RM__
|
||||||
xargs rm -r<<__XARGS_RM__
|
xargs rm -r<<__XARGS_RM__
|
||||||
extract/js/src/build
|
extract/js/src/build
|
||||||
extract/js/src/devtools/vprof/manifest.mk
|
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/wasm/moz.build
|
||||||
extract/js/src/js-confdefs.h.in
|
extract/js/src/js-confdefs.h.in
|
||||||
extract/js/src/js-config.h.in
|
extract/js/src/js-config.h.in
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,7 @@ class FrontendContext;
|
||||||
|
|
||||||
enum class AllocFunction { Malloc, Calloc, Realloc };
|
enum class AllocFunction { Malloc, Calloc, Realloc };
|
||||||
|
|
||||||
/* Base class allocation policies providing allocation methods. */
|
class ArenaAllocPolicyBase {
|
||||||
class AllocPolicyBase {
|
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T* maybe_pod_arena_malloc(arena_id_t arenaId, size_t numElems) {
|
T* maybe_pod_arena_malloc(arena_id_t arenaId, size_t numElems) {
|
||||||
|
|
@ -54,7 +53,11 @@ class AllocPolicyBase {
|
||||||
size_t newSize) {
|
size_t newSize) {
|
||||||
return maybe_pod_arena_realloc<T>(arenaId, p, oldSize, 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>
|
template <typename T>
|
||||||
T* maybe_pod_malloc(size_t numElems) {
|
T* maybe_pod_malloc(size_t numElems) {
|
||||||
return maybe_pod_arena_malloc<T>(js::MallocArena, 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. */
|
/* Policy for using system memory functions and doing no error reporting. */
|
||||||
class SystemAllocPolicy : public AllocPolicyBase {
|
class SystemAllocPolicy : public AllocPolicyBase {
|
||||||
public:
|
public:
|
||||||
|
|
@ -93,6 +134,12 @@ class SystemAllocPolicy : public AllocPolicyBase {
|
||||||
bool checkSimulatedOOM() const { return !js::oom::ShouldFailWithOOM(); }
|
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(JSContext* cx);
|
||||||
MOZ_COLD JS_PUBLIC_API void ReportOutOfMemory(FrontendContext* fc);
|
MOZ_COLD JS_PUBLIC_API void ReportOutOfMemory(FrontendContext* fc);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -261,13 +261,6 @@ extern JS_PUBLIC_API TwoByteCharsZ
|
||||||
UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars& utf8,
|
UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars& utf8,
|
||||||
size_t* outlen, arena_id_t destArenaId);
|
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
|
* The same as UTF8CharsToNewTwoByteCharsZ(), except that any malformed UTF-8
|
||||||
* characters will be replaced by \uFFFD. No exception will be thrown for
|
* 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,
|
LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars& utf8,
|
||||||
size_t* outlen, arena_id_t destArenaId);
|
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.
|
* Returns the length of the char buffer required to encode |s| as UTF8.
|
||||||
* Does not include the null-terminator.
|
* Does not include the null-terminator.
|
||||||
|
|
@ -329,15 +318,6 @@ extern JS_PUBLIC_API Latin1CharsZ
|
||||||
UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars& utf8, size_t* outlen,
|
UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars& utf8, size_t* outlen,
|
||||||
arena_id_t destArenaId);
|
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
|
* Returns true if all characters in the given null-terminated string are
|
||||||
* ASCII, i.e. < 0x80, false otherwise.
|
* ASCII, i.e. < 0x80, false otherwise.
|
||||||
|
|
|
||||||
|
|
@ -813,11 +813,6 @@ enum class ESClass {
|
||||||
BigInt,
|
BigInt,
|
||||||
Function, // Note: Only JSFunction objects.
|
Function, // Note: Only JSFunction objects.
|
||||||
|
|
||||||
#ifdef ENABLE_RECORD_TUPLE
|
|
||||||
Record,
|
|
||||||
Tuple,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** None of the above. */
|
/** None of the above. */
|
||||||
Other
|
Other
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ union Utf8Unit;
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
class JS_PUBLIC_API EnvironmentChain;
|
||||||
class JS_PUBLIC_API InstantiateOptions;
|
class JS_PUBLIC_API InstantiateOptions;
|
||||||
class JS_PUBLIC_API ReadOnlyCompileOptions;
|
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.
|
* objects that should end up on the script's scope chain.
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
|
extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
|
||||||
JS::HandleObjectVector envChain,
|
const JS::EnvironmentChain& envChain,
|
||||||
JS::Handle<JSScript*> script,
|
JS::Handle<JSScript*> script,
|
||||||
JS::MutableHandle<JS::Value> rval);
|
JS::MutableHandle<JS::Value> rval);
|
||||||
|
|
||||||
extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
|
extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
|
||||||
JS::HandleObjectVector envChain,
|
const JS::EnvironmentChain& envChain,
|
||||||
JS::Handle<JSScript*> script);
|
JS::Handle<JSScript*> script);
|
||||||
|
|
||||||
namespace JS {
|
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
|
* 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.
|
* 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,
|
const ReadOnlyCompileOptions& options,
|
||||||
SourceText<char16_t>& srcBuf,
|
SourceText<char16_t>& srcBuf,
|
||||||
MutableHandle<Value> rval);
|
MutableHandle<Value> rval);
|
||||||
|
|
@ -173,7 +175,7 @@ extern JS_PUBLIC_API JSScript* CompileUtf8Path(
|
||||||
* global must not be explicitly included in the scope chain.
|
* global must not be explicitly included in the scope chain.
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API JSFunction* CompileFunction(
|
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 ReadOnlyCompileOptions& options, const char* name, unsigned nargs,
|
||||||
const char* const* argnames, SourceText<char16_t>& srcBuf);
|
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.
|
* global must not be explicitly included in the scope chain.
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API JSFunction* CompileFunction(
|
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 ReadOnlyCompileOptions& options, const char* name, unsigned nargs,
|
||||||
const char* const* argnames, SourceText<mozilla::Utf8Unit>& srcBuf);
|
const char* const* argnames, SourceText<mozilla::Utf8Unit>& srcBuf);
|
||||||
|
|
||||||
|
|
@ -194,7 +196,7 @@ extern JS_PUBLIC_API JSFunction* CompileFunction(
|
||||||
* Rust-friendly ergonomics.
|
* Rust-friendly ergonomics.
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API JSFunction* CompileFunctionUtf8(
|
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 ReadOnlyCompileOptions& options, const char* name, unsigned nargs,
|
||||||
const char* const* argnames, const char* utf8, size_t length);
|
const char* const* argnames, const char* utf8, size_t length);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,10 @@
|
||||||
|
|
||||||
#include "js/CharacterEncoding.h" // JS::ConstUTF8CharsZ
|
#include "js/CharacterEncoding.h" // JS::ConstUTF8CharsZ
|
||||||
#include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
|
#include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
|
||||||
#include "js/TypeDecls.h" // JS::MutableHandle (fwd)
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
# include "js/Prefs.h" // JS::Prefs::*
|
||||||
|
#endif
|
||||||
|
#include "js/TypeDecls.h" // JS::MutableHandle (fwd)
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
class FrontendContext;
|
class FrontendContext;
|
||||||
|
|
@ -124,22 +127,29 @@ class JS_PUBLIC_API PrefableCompileOptions {
|
||||||
public:
|
public:
|
||||||
PrefableCompileOptions()
|
PrefableCompileOptions()
|
||||||
: importAttributes_(false),
|
: importAttributes_(false),
|
||||||
importAttributesAssertSyntax_(false),
|
|
||||||
sourcePragmas_(true),
|
sourcePragmas_(true),
|
||||||
throwOnAsmJSValidationFailure_(false) {}
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
explicitResourceManagement_(
|
||||||
|
JS::Prefs::experimental_explicit_resource_management()),
|
||||||
|
#endif
|
||||||
|
throwOnAsmJSValidationFailure_(false) {
|
||||||
|
}
|
||||||
|
|
||||||
bool importAttributes() const { return importAttributes_; }
|
bool importAttributes() const { return importAttributes_; }
|
||||||
PrefableCompileOptions& setImportAttributes(bool enabled) {
|
PrefableCompileOptions& setImportAttributes(bool enabled) {
|
||||||
importAttributes_ = enabled;
|
importAttributes_ = enabled;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
bool importAttributesAssertSyntax() const {
|
|
||||||
return importAttributesAssertSyntax_;
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
bool explicitResourceManagement() const {
|
||||||
|
return explicitResourceManagement_;
|
||||||
}
|
}
|
||||||
PrefableCompileOptions& setImportAttributesAssertSyntax(bool enabled) {
|
PrefableCompileOptions& setExplicitResourceManagement(bool enabled) {
|
||||||
importAttributesAssertSyntax_ = enabled;
|
explicitResourceManagement_ = enabled;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Enable/disable support for parsing '//(#@) source(Mapping)?URL=' pragmas.
|
// Enable/disable support for parsing '//(#@) source(Mapping)?URL=' pragmas.
|
||||||
bool sourcePragmas() const { return sourcePragmas_; }
|
bool sourcePragmas() const { return sourcePragmas_; }
|
||||||
|
|
@ -176,9 +186,11 @@ class JS_PUBLIC_API PrefableCompileOptions {
|
||||||
void dumpWith(Printer& print) const {
|
void dumpWith(Printer& print) const {
|
||||||
# define PrintFields_(Name) print(#Name, Name)
|
# define PrintFields_(Name) print(#Name, Name)
|
||||||
PrintFields_(importAttributes_);
|
PrintFields_(importAttributes_);
|
||||||
PrintFields_(importAttributesAssertSyntax_);
|
|
||||||
PrintFields_(sourcePragmas_);
|
PrintFields_(sourcePragmas_);
|
||||||
PrintFields_(throwOnAsmJSValidationFailure_);
|
PrintFields_(throwOnAsmJSValidationFailure_);
|
||||||
|
# ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
PrintFields_(explicitResourceManagement_);
|
||||||
|
# endif
|
||||||
# undef PrintFields_
|
# undef PrintFields_
|
||||||
|
|
||||||
switch (asmJSOption_) {
|
switch (asmJSOption_) {
|
||||||
|
|
@ -204,11 +216,16 @@ class JS_PUBLIC_API PrefableCompileOptions {
|
||||||
private:
|
private:
|
||||||
// ==== Syntax-related options. ====
|
// ==== Syntax-related options. ====
|
||||||
bool importAttributes_ : 1;
|
bool importAttributes_ : 1;
|
||||||
bool importAttributesAssertSyntax_ : 1;
|
|
||||||
|
|
||||||
// The context has specified that source pragmas should be parsed.
|
// The context has specified that source pragmas should be parsed.
|
||||||
bool sourcePragmas_ : 1;
|
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. ====
|
// ==== asm.js options. ====
|
||||||
bool throwOnAsmJSValidationFailure_ : 1;
|
bool throwOnAsmJSValidationFailure_ : 1;
|
||||||
|
|
||||||
|
|
@ -315,16 +332,6 @@ class JS_PUBLIC_API TransitiveCompileOptions {
|
||||||
// called. There is currently no mechanism to release the data sooner.
|
// called. There is currently no mechanism to release the data sooner.
|
||||||
bool usePinnedBytecode = false;
|
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_;
|
PrefableCompileOptions prefableOptions_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -390,10 +397,12 @@ class JS_PUBLIC_API TransitiveCompileOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool importAttributes() const { return prefableOptions_.importAttributes(); }
|
bool importAttributes() const { return prefableOptions_.importAttributes(); }
|
||||||
bool importAttributesAssertSyntax() const {
|
|
||||||
return prefableOptions_.importAttributesAssertSyntax();
|
|
||||||
}
|
|
||||||
bool sourcePragmas() const { return prefableOptions_.sourcePragmas(); }
|
bool sourcePragmas() const { return prefableOptions_.sourcePragmas(); }
|
||||||
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
bool explicitResourceManagement() const {
|
||||||
|
return prefableOptions_.explicitResourceManagement();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
bool throwOnAsmJSValidationFailure() const {
|
bool throwOnAsmJSValidationFailure() const {
|
||||||
return prefableOptions_.throwOnAsmJSValidationFailure();
|
return prefableOptions_.throwOnAsmJSValidationFailure();
|
||||||
}
|
}
|
||||||
|
|
@ -435,7 +444,6 @@ class JS_PUBLIC_API TransitiveCompileOptions {
|
||||||
PrintFields_(topLevelAwait);
|
PrintFields_(topLevelAwait);
|
||||||
PrintFields_(borrowBuffer);
|
PrintFields_(borrowBuffer);
|
||||||
PrintFields_(usePinnedBytecode);
|
PrintFields_(usePinnedBytecode);
|
||||||
PrintFields_(deoptimizeModuleGlobalVars);
|
|
||||||
PrintFields_(introductionType);
|
PrintFields_(introductionType);
|
||||||
PrintFields_(introductionLineno);
|
PrintFields_(introductionLineno);
|
||||||
PrintFields_(introductionOffset);
|
PrintFields_(introductionOffset);
|
||||||
|
|
@ -709,13 +717,16 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void warnAboutConflictingDelazification() const;
|
||||||
CompileOptions& setEagerDelazificationStrategy(
|
CompileOptions& setEagerDelazificationStrategy(
|
||||||
DelazificationOption strategy) {
|
DelazificationOption strategy) {
|
||||||
// forceFullParse is at the moment considered as a non-overridable strategy.
|
const auto PEE = DelazificationOption::ParseEverythingEagerly;
|
||||||
MOZ_RELEASE_ASSERT(eagerDelazificationStrategy_ !=
|
if (eagerDelazificationStrategy_ == PEE && strategy != PEE) {
|
||||||
DelazificationOption::ParseEverythingEagerly ||
|
// Parse Everything Eagerly cannot be replaced, do noting.
|
||||||
strategy ==
|
warnAboutConflictingDelazification();
|
||||||
DelazificationOption::ParseEverythingEagerly);
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
eagerDelazificationStrategy_ = strategy;
|
eagerDelazificationStrategy_ = strategy;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
@ -746,17 +757,22 @@ class JS_PUBLIC_API InstantiateOptions {
|
||||||
bool hideScriptFromDebugger = false;
|
bool hideScriptFromDebugger = false;
|
||||||
bool deferDebugMetadata = false;
|
bool deferDebugMetadata = false;
|
||||||
|
|
||||||
InstantiateOptions() = default;
|
DelazificationOption eagerDelazificationStrategy_ =
|
||||||
|
DelazificationOption::OnDemandOnly;
|
||||||
|
|
||||||
|
InstantiateOptions();
|
||||||
|
|
||||||
explicit InstantiateOptions(const ReadOnlyCompileOptions& options)
|
explicit InstantiateOptions(const ReadOnlyCompileOptions& options)
|
||||||
: skipFilenameValidation(options.skipFilenameValidation_),
|
: skipFilenameValidation(options.skipFilenameValidation_),
|
||||||
hideScriptFromDebugger(options.hideScriptFromDebugger_),
|
hideScriptFromDebugger(options.hideScriptFromDebugger_),
|
||||||
deferDebugMetadata(options.deferDebugMetadata_) {}
|
deferDebugMetadata(options.deferDebugMetadata_),
|
||||||
|
eagerDelazificationStrategy_(options.eagerDelazificationStrategy()) {}
|
||||||
|
|
||||||
void copyTo(CompileOptions& options) const {
|
void copyTo(CompileOptions& options) const {
|
||||||
options.skipFilenameValidation_ = skipFilenameValidation;
|
options.skipFilenameValidation_ = skipFilenameValidation;
|
||||||
options.hideScriptFromDebugger_ = hideScriptFromDebugger;
|
options.hideScriptFromDebugger_ = hideScriptFromDebugger;
|
||||||
options.deferDebugMetadata_ = deferDebugMetadata;
|
options.deferDebugMetadata_ = deferDebugMetadata;
|
||||||
|
options.setEagerDelazificationStrategy(eagerDelazificationStrategy_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hideFromNewScriptInitial() const {
|
bool hideFromNewScriptInitial() const {
|
||||||
|
|
@ -772,6 +788,29 @@ class JS_PUBLIC_API InstantiateOptions {
|
||||||
MOZ_ASSERT(skipFilenameValidation == false);
|
MOZ_ASSERT(skipFilenameValidation == false);
|
||||||
MOZ_ASSERT(hideScriptFromDebugger == false);
|
MOZ_ASSERT(hideScriptFromDebugger == false);
|
||||||
MOZ_ASSERT(deferDebugMetadata == 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
|
#endif
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ class JS_PUBLIC_API ContextOptions {
|
||||||
ContextOptions()
|
ContextOptions()
|
||||||
: wasm_(true),
|
: wasm_(true),
|
||||||
wasmForTrustedPrinciples_(true),
|
wasmForTrustedPrinciples_(true),
|
||||||
wasmVerbose_(false),
|
|
||||||
wasmBaseline_(true),
|
wasmBaseline_(true),
|
||||||
wasmIon_(true),
|
wasmIon_(true),
|
||||||
testWasmAwaitTier2_(false),
|
testWasmAwaitTier2_(false),
|
||||||
|
|
@ -34,10 +33,6 @@ class JS_PUBLIC_API ContextOptions {
|
||||||
asyncStackCaptureDebuggeeOnly_(false),
|
asyncStackCaptureDebuggeeOnly_(false),
|
||||||
throwOnDebuggeeWouldRun_(true),
|
throwOnDebuggeeWouldRun_(true),
|
||||||
dumpStackOnDebuggeeWouldRun_(false),
|
dumpStackOnDebuggeeWouldRun_(false),
|
||||||
#ifdef JS_ENABLE_SMOOSH
|
|
||||||
trackNotImplemented_(false),
|
|
||||||
trySmoosh_(false),
|
|
||||||
#endif
|
|
||||||
fuzzing_(false) {
|
fuzzing_(false) {
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
@ -71,12 +66,6 @@ class JS_PUBLIC_API ContextOptions {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wasmVerbose() const { return wasmVerbose_; }
|
|
||||||
ContextOptions& setWasmVerbose(bool flag) {
|
|
||||||
wasmVerbose_ = flag;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wasmBaseline() const { return wasmBaseline_; }
|
bool wasmBaseline() const { return wasmBaseline_; }
|
||||||
ContextOptions& setWasmBaseline(bool flag) {
|
ContextOptions& setWasmBaseline(bool flag) {
|
||||||
wasmBaseline_ = flag;
|
wasmBaseline_ = flag;
|
||||||
|
|
@ -122,14 +111,6 @@ class JS_PUBLIC_API ContextOptions {
|
||||||
return *this;
|
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
|
// Override to allow disabling the eval restriction security checks for
|
||||||
// this context.
|
// this context.
|
||||||
bool disableEvalSecurityChecks() const { return disableEvalSecurityChecks_; }
|
bool disableEvalSecurityChecks() const { return disableEvalSecurityChecks_; }
|
||||||
|
|
@ -173,24 +154,6 @@ class JS_PUBLIC_API ContextOptions {
|
||||||
return *this;
|
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_; }
|
bool fuzzing() const { return fuzzing_; }
|
||||||
// Defined out-of-line because it depends on a compile-time option
|
// Defined out-of-line because it depends on a compile-time option
|
||||||
ContextOptions& setFuzzing(bool flag);
|
ContextOptions& setFuzzing(bool flag);
|
||||||
|
|
@ -209,7 +172,6 @@ class JS_PUBLIC_API ContextOptions {
|
||||||
// WASM options.
|
// WASM options.
|
||||||
bool wasm_ : 1;
|
bool wasm_ : 1;
|
||||||
bool wasmForTrustedPrinciples_ : 1;
|
bool wasmForTrustedPrinciples_ : 1;
|
||||||
bool wasmVerbose_ : 1;
|
|
||||||
bool wasmBaseline_ : 1;
|
bool wasmBaseline_ : 1;
|
||||||
bool wasmIon_ : 1;
|
bool wasmIon_ : 1;
|
||||||
bool testWasmAwaitTier2_ : 1;
|
bool testWasmAwaitTier2_ : 1;
|
||||||
|
|
@ -223,10 +185,6 @@ class JS_PUBLIC_API ContextOptions {
|
||||||
bool asyncStackCaptureDebuggeeOnly_ : 1;
|
bool asyncStackCaptureDebuggeeOnly_ : 1;
|
||||||
bool throwOnDebuggeeWouldRun_ : 1;
|
bool throwOnDebuggeeWouldRun_ : 1;
|
||||||
bool dumpStackOnDebuggeeWouldRun_ : 1;
|
bool dumpStackOnDebuggeeWouldRun_ : 1;
|
||||||
#ifdef JS_ENABLE_SMOOSH
|
|
||||||
bool trackNotImplemented_ : 1;
|
|
||||||
bool trySmoosh_ : 1;
|
|
||||||
#endif
|
|
||||||
bool fuzzing_ : 1;
|
bool fuzzing_ : 1;
|
||||||
|
|
||||||
// Compile options.
|
// Compile options.
|
||||||
|
|
|
||||||
|
|
@ -272,17 +272,6 @@ inline JSObject* ToObject(JSContext* cx, HandleValue v) {
|
||||||
return js::ToObjectSlow(cx, v, false);
|
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
|
* Convert a double value to UnsignedInteger (an unsigned integral type) using
|
||||||
* ECMAScript-style semantics (that is, in like manner to how ECMAScript's
|
* ECMAScript-style semantics (that is, in like manner to how ECMAScript's
|
||||||
|
|
@ -372,8 +361,9 @@ inline UnsignedInteger ToUnsignedInteger(double d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the congruent value in the signed range.
|
// Compute the congruent value in the signed range.
|
||||||
return (bits & mozilla::FloatingPoint<double>::kSignBit) ? ~result + 1
|
return (bits & mozilla::FloatingPoint<double>::kSignBit)
|
||||||
: result;
|
? UnsignedInteger(~result) + 1
|
||||||
|
: result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename SignedInteger>
|
template <typename SignedInteger>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@
|
||||||
|
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
|
#include "mozilla/BaseProfilerUtils.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
|
#include "mozilla/Vector.h"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
|
@ -29,6 +31,136 @@ class Debugger;
|
||||||
extern JS_PUBLIC_API bool JS_DefineDebuggerObject(JSContext* cx,
|
extern JS_PUBLIC_API bool JS_DefineDebuggerObject(JSContext* cx,
|
||||||
JS::HandleObject obj);
|
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 JS {
|
||||||
namespace dbg {
|
namespace dbg {
|
||||||
|
|
||||||
|
|
@ -302,52 +434,6 @@ JS_PUBLIC_API bool IsDebugger(JSObject& obj);
|
||||||
JS_PUBLIC_API bool GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj,
|
JS_PUBLIC_API bool GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj,
|
||||||
MutableHandleObjectVector vector);
|
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
|
// Returns true if there's any debugger attached to the given context where
|
||||||
// the debugger's "shouldAvoidSideEffects" property is true.
|
// the debugger's "shouldAvoidSideEffects" property is true.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
@ -62,24 +62,40 @@ enum ErrorArgumentsType {
|
||||||
* using the generalized error reporting mechanism. (One side effect of this
|
* 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
|
* 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.
|
* 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 {
|
enum JSExnType {
|
||||||
|
// Generic Errors
|
||||||
JSEXN_ERR,
|
JSEXN_ERR,
|
||||||
JSEXN_FIRST = JSEXN_ERR,
|
JSEXN_FIRST = JSEXN_ERR,
|
||||||
|
// Internal Errors
|
||||||
JSEXN_INTERNALERR,
|
JSEXN_INTERNALERR,
|
||||||
|
// ECMAScript Errors
|
||||||
JSEXN_AGGREGATEERR,
|
JSEXN_AGGREGATEERR,
|
||||||
JSEXN_EVALERR,
|
JSEXN_EVALERR,
|
||||||
JSEXN_RANGEERR,
|
JSEXN_RANGEERR,
|
||||||
JSEXN_REFERENCEERR,
|
JSEXN_REFERENCEERR,
|
||||||
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
JSEXN_SUPPRESSEDERR,
|
||||||
|
#endif
|
||||||
JSEXN_SYNTAXERR,
|
JSEXN_SYNTAXERR,
|
||||||
JSEXN_TYPEERR,
|
JSEXN_TYPEERR,
|
||||||
JSEXN_URIERR,
|
JSEXN_URIERR,
|
||||||
|
// Debugger Errors
|
||||||
JSEXN_DEBUGGEEWOULDRUN,
|
JSEXN_DEBUGGEEWOULDRUN,
|
||||||
|
// WASM Errors
|
||||||
JSEXN_WASMCOMPILEERROR,
|
JSEXN_WASMCOMPILEERROR,
|
||||||
JSEXN_WASMLINKERROR,
|
JSEXN_WASMLINKERROR,
|
||||||
JSEXN_WASMRUNTIMEERROR,
|
JSEXN_WASMRUNTIMEERROR,
|
||||||
|
#ifdef ENABLE_WASM_JSPI
|
||||||
|
JSEXN_WASMSUSPENDERROR,
|
||||||
|
#endif
|
||||||
JSEXN_ERROR_LIMIT,
|
JSEXN_ERROR_LIMIT,
|
||||||
|
// Warnings
|
||||||
JSEXN_WARN = JSEXN_ERROR_LIMIT,
|
JSEXN_WARN = JSEXN_ERROR_LIMIT,
|
||||||
|
// Error Notes
|
||||||
JSEXN_NOTE,
|
JSEXN_NOTE,
|
||||||
JSEXN_LIMIT
|
JSEXN_LIMIT
|
||||||
};
|
};
|
||||||
|
|
@ -540,6 +556,20 @@ extern JS_PUBLIC_API bool CreateError(
|
||||||
JSErrorReport* report, HandleString message,
|
JSErrorReport* report, HandleString message,
|
||||||
Handle<mozilla::Maybe<Value>> cause, MutableHandleValue rval);
|
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 */
|
} /* namespace JS */
|
||||||
|
|
||||||
#endif /* js_ErrorReport_h */
|
#endif /* js_ErrorReport_h */
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ namespace js {
|
||||||
namespace gc {
|
namespace gc {
|
||||||
class GCRuntime;
|
class GCRuntime;
|
||||||
} // namespace gc
|
} // namespace gc
|
||||||
class JS_PUBLIC_API SliceBudget;
|
|
||||||
namespace gcstats {
|
namespace gcstats {
|
||||||
struct Statistics;
|
struct Statistics;
|
||||||
} // namespace gcstats
|
} // namespace gcstats
|
||||||
|
|
@ -36,6 +35,8 @@ struct Statistics;
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
class JS_PUBLIC_API SliceBudget;
|
||||||
|
|
||||||
// Options used when starting a GC.
|
// Options used when starting a GC.
|
||||||
enum class GCOptions : uint32_t {
|
enum class GCOptions : uint32_t {
|
||||||
// Normal GC invocation.
|
// Normal GC invocation.
|
||||||
|
|
@ -261,14 +262,6 @@ typedef enum JSGCParamKey {
|
||||||
*/
|
*/
|
||||||
JSGC_MIN_EMPTY_CHUNK_COUNT = 21,
|
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.
|
* Whether compacting GC is enabled.
|
||||||
*
|
*
|
||||||
|
|
@ -488,6 +481,33 @@ typedef enum JSGCParamKey {
|
||||||
*/
|
*/
|
||||||
JSGC_SLICE_NUMBER = 54,
|
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;
|
} 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
|
* 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.
|
* 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);
|
void* data);
|
||||||
|
|
||||||
typedef enum JSGCStatus { JSGC_BEGIN, JSGC_END } JSGCStatus;
|
typedef enum JSGCStatus { JSGC_BEGIN, JSGC_END } JSGCStatus;
|
||||||
|
|
@ -651,7 +671,7 @@ namespace JS {
|
||||||
D(DOCSHELL, 54) \
|
D(DOCSHELL, 54) \
|
||||||
D(HTML_PARSER, 55) \
|
D(HTML_PARSER, 55) \
|
||||||
D(DOM_TESTUTILS, 56) \
|
D(DOM_TESTUTILS, 56) \
|
||||||
D(PREPARE_FOR_PAGELOAD, 57) \
|
D(PREPARE_FOR_PAGELOAD, LAST_FIREFOX_REASON) \
|
||||||
\
|
\
|
||||||
/* Reasons reserved for embeddings. */ \
|
/* Reasons reserved for embeddings. */ \
|
||||||
D(RESERVED1, FIRST_RESERVED_REASON) \
|
D(RESERVED1, FIRST_RESERVED_REASON) \
|
||||||
|
|
@ -666,6 +686,7 @@ namespace JS {
|
||||||
|
|
||||||
enum class GCReason {
|
enum class GCReason {
|
||||||
FIRST_FIREFOX_REASON = 33,
|
FIRST_FIREFOX_REASON = 33,
|
||||||
|
LAST_FIREFOX_REASON = 57,
|
||||||
FIRST_RESERVED_REASON = 90,
|
FIRST_RESERVED_REASON = 90,
|
||||||
|
|
||||||
#define MAKE_REASON(name, val) name = val,
|
#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);
|
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:
|
* 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,
|
extern JS_PUBLIC_API void StartIncrementalGC(JSContext* cx,
|
||||||
JS::GCOptions options,
|
JS::GCOptions options,
|
||||||
GCReason reason,
|
GCReason reason,
|
||||||
const js::SliceBudget& budget);
|
const JS::SliceBudget& budget);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a slice of an ongoing incremental collection. When this function
|
* 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.
|
* shorter than the requested interval.
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API void IncrementalGCSlice(JSContext* cx, GCReason reason,
|
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
|
* 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
|
extern JS_PUBLIC_API DoCycleCollectionCallback
|
||||||
SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback);
|
SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback);
|
||||||
|
|
||||||
using CreateSliceBudgetCallback = js::SliceBudget (*)(JS::GCReason reason,
|
using CreateSliceBudgetCallback = JS::SliceBudget (*)(JS::GCReason reason,
|
||||||
int64_t millis);
|
int64_t millis);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -971,14 +1004,6 @@ using CreateSliceBudgetCallback = js::SliceBudget (*)(JS::GCReason reason,
|
||||||
extern JS_PUBLIC_API void SetCreateGCSliceBudgetCallback(
|
extern JS_PUBLIC_API void SetCreateGCSliceBudgetCallback(
|
||||||
JSContext* cx, CreateSliceBudgetCallback cb);
|
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
|
* Returns true if incremental GC is enabled. Simply having incremental GC
|
||||||
* enabled is not sufficient to ensure incremental collections are happening.
|
* enabled is not sufficient to ensure incremental collections are happening.
|
||||||
|
|
|
||||||
|
|
@ -646,6 +646,21 @@ class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>> final
|
||||||
|
|
||||||
bool needsIncrementalBarrier() const override { return barrierTracer; }
|
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:
|
private:
|
||||||
static bool entryNeedsSweep(JSTracer* barrierTracer, const Entry& prior) {
|
static bool entryNeedsSweep(JSTracer* barrierTracer, const Entry& prior) {
|
||||||
Entry entry(prior);
|
Entry entry(prior);
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,10 @@ struct GCPolicy<JS::Heap<T>> {
|
||||||
static bool traceWeak(JSTracer* trc, JS::Heap<T>* thingp) {
|
static bool traceWeak(JSTracer* trc, JS::Heap<T>* thingp) {
|
||||||
return !*thingp || js::gc::TraceWeakEdge(trc, 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>.
|
// 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; }
|
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
|
} // namespace JS
|
||||||
|
|
||||||
#endif // GCPolicyAPI_h
|
#endif // GCPolicyAPI_h
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ class GCVector {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
||||||
return vector.sizeOfIncludingThis(mallocSizeOf);
|
return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace(JSTracer* trc) {
|
void trace(JSTracer* trc) {
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,6 @@
|
||||||
/* These values are private to the JS engine. */
|
/* These values are private to the JS engine. */
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
class NurseryDecommitTask;
|
|
||||||
|
|
||||||
JS_PUBLIC_API bool CurrentThreadCanAccessZone(JS::Zone* zone);
|
JS_PUBLIC_API bool CurrentThreadCanAccessZone(JS::Zone* zone);
|
||||||
|
|
||||||
// To prevent false sharing, some data structures are aligned to a typical cache
|
// To prevent false sharing, some data structures are aligned to a typical cache
|
||||||
|
|
@ -37,7 +35,7 @@ namespace gc {
|
||||||
|
|
||||||
class Arena;
|
class Arena;
|
||||||
struct Cell;
|
struct Cell;
|
||||||
class TenuredChunk;
|
class ArenaChunk;
|
||||||
class StoreBuffer;
|
class StoreBuffer;
|
||||||
class TenuredCell;
|
class TenuredCell;
|
||||||
|
|
||||||
|
|
@ -53,6 +51,7 @@ const size_t PageShift = 12;
|
||||||
// Expected page size, so we could initialze ArenasPerPage at compile-time.
|
// Expected page size, so we could initialze ArenasPerPage at compile-time.
|
||||||
// The actual system page size should be queried by SystemPageSize().
|
// The actual system page size should be queried by SystemPageSize().
|
||||||
const size_t PageSize = size_t(1) << PageShift;
|
const size_t PageSize = size_t(1) << PageShift;
|
||||||
|
const size_t PageMask = PageSize - 1;
|
||||||
constexpr size_t ArenasPerPage = PageSize / ArenaSize;
|
constexpr size_t ArenasPerPage = PageSize / ArenaSize;
|
||||||
|
|
||||||
const size_t ChunkShift = 20;
|
const size_t ChunkShift = 20;
|
||||||
|
|
@ -84,7 +83,8 @@ const size_t ArenaBitmapWords = HowMany(ArenaBitmapBits, JS_BITS_PER_WORD);
|
||||||
|
|
||||||
enum class ChunkKind : uint8_t {
|
enum class ChunkKind : uint8_t {
|
||||||
Invalid = 0,
|
Invalid = 0,
|
||||||
TenuredHeap,
|
TenuredArenas,
|
||||||
|
MediumBuffers,
|
||||||
NurseryToSpace,
|
NurseryToSpace,
|
||||||
NurseryFromSpace
|
NurseryFromSpace
|
||||||
};
|
};
|
||||||
|
|
@ -97,13 +97,13 @@ class ChunkBase {
|
||||||
// Initialize a tenured heap chunk.
|
// Initialize a tenured heap chunk.
|
||||||
explicit ChunkBase(JSRuntime* rt) {
|
explicit ChunkBase(JSRuntime* rt) {
|
||||||
MOZ_ASSERT((uintptr_t(this) & ChunkMask) == 0);
|
MOZ_ASSERT((uintptr_t(this) & ChunkMask) == 0);
|
||||||
initBaseForTenuredChunk(rt);
|
initBaseForArenaChunk(rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initBaseForTenuredChunk(JSRuntime* rt) {
|
void initBaseForArenaChunk(JSRuntime* rt) {
|
||||||
runtime = rt;
|
runtime = rt;
|
||||||
storeBuffer = nullptr;
|
storeBuffer = nullptr;
|
||||||
kind = ChunkKind::TenuredHeap;
|
kind = ChunkKind::TenuredArenas;
|
||||||
nurseryChunkIndex = UINT8_MAX;
|
nurseryChunkIndex = UINT8_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,20 +113,33 @@ class ChunkBase {
|
||||||
runtime(rt),
|
runtime(rt),
|
||||||
kind(kind),
|
kind(kind),
|
||||||
nurseryChunkIndex(chunkIndex) {
|
nurseryChunkIndex(chunkIndex) {
|
||||||
MOZ_ASSERT(kind == ChunkKind::NurseryFromSpace ||
|
MOZ_ASSERT(isNurseryChunk());
|
||||||
kind == ChunkKind::NurseryToSpace);
|
|
||||||
MOZ_ASSERT((uintptr_t(this) & ChunkMask) == 0);
|
MOZ_ASSERT((uintptr_t(this) & ChunkMask) == 0);
|
||||||
MOZ_ASSERT(storeBuffer);
|
MOZ_ASSERT(storeBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChunkBase(JSRuntime* rt, ChunkKind kind)
|
||||||
|
: storeBuffer(nullptr),
|
||||||
|
runtime(rt),
|
||||||
|
kind(kind),
|
||||||
|
nurseryChunkIndex(UINT8_MAX) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ChunkKind getKind() const {
|
ChunkKind getKind() const {
|
||||||
MOZ_ASSERT_IF(storeBuffer, kind == ChunkKind::NurseryToSpace ||
|
MOZ_ASSERT_IF(storeBuffer, isNurseryChunk());
|
||||||
kind == ChunkKind::NurseryFromSpace);
|
MOZ_ASSERT_IF(!storeBuffer, isTenuredChunk());
|
||||||
MOZ_ASSERT_IF(!storeBuffer, kind == ChunkKind::TenuredHeap);
|
|
||||||
return kind;
|
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
|
// 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.
|
// chunk. Will be non-null if and only if this is a nursery chunk.
|
||||||
StoreBuffer* storeBuffer;
|
StoreBuffer* storeBuffer;
|
||||||
|
|
@ -139,12 +152,12 @@ class ChunkBase {
|
||||||
uint8_t nurseryChunkIndex;
|
uint8_t nurseryChunkIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Information about tenured heap chunks.
|
// Information about tenured heap chunks containing arenas.
|
||||||
struct TenuredChunkInfo {
|
struct ArenaChunkInfo {
|
||||||
private:
|
private:
|
||||||
friend class ChunkPool;
|
friend class ChunkPool;
|
||||||
TenuredChunk* next = nullptr;
|
ArenaChunk* next = nullptr;
|
||||||
TenuredChunk* prev = nullptr;
|
ArenaChunk* prev = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* Number of free arenas, either committed or decommitted. */
|
/* Number of free arenas, either committed or decommitted. */
|
||||||
|
|
@ -152,6 +165,9 @@ struct TenuredChunkInfo {
|
||||||
|
|
||||||
/* Number of free, committed arenas. */
|
/* Number of free, committed arenas. */
|
||||||
uint32_t numArenasFreeCommitted;
|
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 +
|
(ArenaSize + ArenaBitmapBytes) * ArenasPerPage * CHAR_BIT + ArenasPerPage +
|
||||||
1;
|
1;
|
||||||
const size_t ChunkBitsAvailable =
|
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 PagesPerChunk = ChunkBitsAvailable / BitsPerPageWithHeaders;
|
||||||
const size_t ArenasPerChunk = PagesPerChunk * ArenasPerPage;
|
const size_t ArenasPerChunk = PagesPerChunk * ArenasPerPage;
|
||||||
const size_t FreeCommittedBits = ArenasPerChunk;
|
const size_t FreeCommittedBits = ArenasPerChunk;
|
||||||
|
|
@ -190,7 +206,7 @@ const size_t BitsPerArenaWithHeaders =
|
||||||
(DecommitBits / ArenasPerChunk) + 1;
|
(DecommitBits / ArenasPerChunk) + 1;
|
||||||
|
|
||||||
const size_t CalculatedChunkSizeRequired =
|
const size_t CalculatedChunkSizeRequired =
|
||||||
sizeof(ChunkBase) + sizeof(TenuredChunkInfo) +
|
sizeof(ChunkBase) + sizeof(ArenaChunkInfo) +
|
||||||
RoundUp(ArenasPerChunk * ArenaBitmapBytes, sizeof(uintptr_t)) +
|
RoundUp(ArenasPerChunk * ArenaBitmapBytes, sizeof(uintptr_t)) +
|
||||||
RoundUp(FreeCommittedBits, sizeof(uint32_t) * CHAR_BIT) / CHAR_BIT +
|
RoundUp(FreeCommittedBits, sizeof(uint32_t) * CHAR_BIT) / CHAR_BIT +
|
||||||
RoundUp(DecommitBits, 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,
|
static_assert(ArenasPerChunk == 252,
|
||||||
"Do not accidentally change our heap's density.");
|
"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
|
// 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
|
// main thread while read by sweeping on a background thread. The former does
|
||||||
// not affect the result of the latter.
|
// not affect the result of the latter.
|
||||||
using MarkBitmapWord = mozilla::Atomic<uintptr_t, mozilla::Relaxed>;
|
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
|
* 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 };
|
enum class MarkColor : uint8_t { Gray = 1, Black = 2 };
|
||||||
|
|
||||||
// Mark bitmap for a tenured heap chunk.
|
// Mark bitmap for a tenured heap chunk.
|
||||||
struct alignas(TypicalCacheLineSize) MarkBitmap {
|
template <size_t BytesPerMarkBit, size_t FirstThingOffset>
|
||||||
static constexpr size_t WordCount = ArenaBitmapWords * ArenasPerChunk;
|
class alignas(TypicalCacheLineSize) MarkBitmap {
|
||||||
|
static constexpr size_t ByteCount =
|
||||||
|
(ChunkSize - FirstThingOffset) / BytesPerMarkBit;
|
||||||
|
static constexpr size_t WordCount = HowMany(ByteCount, MarkBitmapWordBits);
|
||||||
MarkBitmapWord bitmap[WordCount];
|
MarkBitmapWord bitmap[WordCount];
|
||||||
|
|
||||||
inline void getMarkWordAndMask(const TenuredCell* cell, ColorBit colorBit,
|
public:
|
||||||
MarkBitmapWord** wordp, uintptr_t* maskp);
|
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:
|
// The following are not exported and are defined in gc/Heap.h:
|
||||||
inline bool markBit(const TenuredCell* cell, ColorBit colorBit);
|
MOZ_ALWAYS_INLINE bool markBit(const void* cell, ColorBit colorBit) {
|
||||||
inline bool isMarkedAny(const TenuredCell* cell);
|
MarkBitmapWord* word;
|
||||||
inline bool isMarkedBlack(const TenuredCell* cell);
|
uintptr_t mask;
|
||||||
inline bool isMarkedGray(const TenuredCell* cell);
|
getMarkWordAndMask(cell, colorBit, &word, &mask);
|
||||||
inline bool markIfUnmarked(const TenuredCell* cell, MarkColor color);
|
return *word & mask;
|
||||||
inline bool markIfUnmarkedAtomic(const TenuredCell* cell, MarkColor color);
|
}
|
||||||
inline void markBlack(const TenuredCell* cell);
|
|
||||||
inline void markBlackAtomic(const TenuredCell* cell);
|
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,
|
inline void copyMarkBit(TenuredCell* dst, const TenuredCell* src,
|
||||||
ColorBit colorBit);
|
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 MarkBitmapWord* arenaBits(Arena* arena);
|
||||||
|
|
||||||
|
inline void copyFrom(const MarkBitmap& other);
|
||||||
|
inline void clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(ArenaBitmapBytes * ArenasPerChunk == sizeof(MarkBitmap),
|
using ChunkMarkBitmap = MarkBitmap<CellBytesPerMarkBit, FirstArenaOffset>;
|
||||||
"Ensure our MarkBitmap actually covers all arenas.");
|
|
||||||
|
|
||||||
// Bitmap with one bit per page used for decommitted page set.
|
// Bitmap with one bit per page used for decommitted page set.
|
||||||
using ChunkPageBitmap = mozilla::BitSet<PagesPerChunk, uint32_t>;
|
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.
|
// Bitmap with one bit per arena used for free committed arena set.
|
||||||
using ChunkArenaBitmap = mozilla::BitSet<ArenasPerChunk, uint32_t>;
|
using ChunkArenaBitmap = mozilla::BitSet<ArenasPerChunk, uint32_t>;
|
||||||
|
|
||||||
// Base class containing data members for a tenured heap chunk.
|
// Base class for a tenured heap chunk containing fixed size arenas.
|
||||||
class TenuredChunkBase : public ChunkBase {
|
class ArenaChunkBase : public ChunkBase {
|
||||||
public:
|
public:
|
||||||
TenuredChunkInfo info;
|
ArenaChunkInfo info;
|
||||||
MarkBitmap markBits;
|
ChunkMarkBitmap markBits;
|
||||||
ChunkArenaBitmap freeCommittedArenas;
|
ChunkArenaBitmap freeCommittedArenas;
|
||||||
ChunkPageBitmap decommittedPages;
|
ChunkPageBitmap decommittedPages;
|
||||||
|
|
||||||
protected:
|
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;
|
info.numArenasFree = ArenasPerChunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initAsCommitted();
|
||||||
void initAsDecommitted();
|
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
|
* 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 ArenaCellIndexBytes = CellAlignBytes;
|
||||||
const size_t MaxArenaCellIndex = ArenaSize / 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 ChunkStoreBufferOffset = offsetof(ChunkBase, storeBuffer);
|
||||||
const size_t ChunkMarkBitmapOffset = offsetof(TenuredChunkBase, markBits);
|
const size_t ChunkMarkBitmapOffset = offsetof(ArenaChunkBase, markBits);
|
||||||
|
|
||||||
// Hardcoded offsets into Arena class.
|
// Hardcoded offsets into Arena class.
|
||||||
const size_t ArenaZoneOffset = 2 * sizeof(uint32_t);
|
const size_t ArenaZoneOffset = 2 * sizeof(uint32_t);
|
||||||
|
|
@ -428,6 +490,9 @@ class JS_PUBLIC_API GCCellPtr {
|
||||||
return asCell();
|
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.
|
// Simplify checks to the kind.
|
||||||
template <typename T, typename = std::enable_if_t<JS::IsBaseTraceType_v<T>>>
|
template <typename T, typename = std::enable_if_t<JS::IsBaseTraceType_v<T>>>
|
||||||
bool is() const {
|
bool is() const {
|
||||||
|
|
@ -518,55 +583,31 @@ void ApplyGCThingTyped(GCCellPtr thing, F&& f) {
|
||||||
|
|
||||||
} /* namespace JS */
|
} /* 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 js {
|
||||||
namespace gc {
|
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 {
|
namespace detail {
|
||||||
|
|
||||||
static MOZ_ALWAYS_INLINE ChunkBase* GetCellChunkBase(const Cell* cell) {
|
// `addr` must be an address within GC-controlled memory. Note that it cannot
|
||||||
MOZ_ASSERT(cell);
|
// point just past GC-controlled memory.
|
||||||
auto* chunk = reinterpret_cast<ChunkBase*>(uintptr_t(cell) & ~ChunkMask);
|
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->runtime);
|
||||||
MOZ_ASSERT(chunk->kind != ChunkKind::Invalid);
|
MOZ_ASSERT(chunk->kind != ChunkKind::Invalid);
|
||||||
return chunk;
|
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) {
|
const TenuredCell* cell) {
|
||||||
MOZ_ASSERT(cell);
|
MOZ_ASSERT(cell);
|
||||||
auto* chunk =
|
auto* chunk = reinterpret_cast<ArenaChunkBase*>(uintptr_t(cell) & ~ChunkMask);
|
||||||
reinterpret_cast<TenuredChunkBase*>(uintptr_t(cell) & ~ChunkMask);
|
|
||||||
MOZ_ASSERT(chunk->runtime);
|
MOZ_ASSERT(chunk->runtime);
|
||||||
MOZ_ASSERT(chunk->kind == ChunkKind::TenuredHeap);
|
MOZ_ASSERT(chunk->kind == ChunkKind::TenuredArenas);
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -580,17 +621,11 @@ static MOZ_ALWAYS_INLINE JS::Zone* GetTenuredGCThingZone(const void* ptr) {
|
||||||
|
|
||||||
static MOZ_ALWAYS_INLINE bool TenuredCellIsMarkedBlack(
|
static MOZ_ALWAYS_INLINE bool TenuredCellIsMarkedBlack(
|
||||||
const TenuredCell* cell) {
|
const TenuredCell* cell) {
|
||||||
// Return true if BlackBit is set.
|
|
||||||
|
|
||||||
MOZ_ASSERT(cell);
|
MOZ_ASSERT(cell);
|
||||||
MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
|
MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
|
||||||
|
|
||||||
MarkBitmapWord* blackWord;
|
ArenaChunkBase* chunk = GetCellChunkBase(cell);
|
||||||
uintptr_t blackMask;
|
return chunk->markBits.isMarkedBlack(cell);
|
||||||
TenuredChunkBase* chunk = GetCellChunkBase(cell);
|
|
||||||
chunk->markBits.getMarkWordAndMask(cell, js::gc::ColorBit::BlackBit,
|
|
||||||
&blackWord, &blackMask);
|
|
||||||
return *blackWord & blackMask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static MOZ_ALWAYS_INLINE bool NonBlackCellIsMarkedGray(
|
static MOZ_ALWAYS_INLINE bool NonBlackCellIsMarkedGray(
|
||||||
|
|
@ -601,16 +636,15 @@ static MOZ_ALWAYS_INLINE bool NonBlackCellIsMarkedGray(
|
||||||
MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
|
MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
|
||||||
MOZ_ASSERT(!TenuredCellIsMarkedBlack(cell));
|
MOZ_ASSERT(!TenuredCellIsMarkedBlack(cell));
|
||||||
|
|
||||||
MarkBitmapWord* grayWord;
|
ArenaChunkBase* chunk = GetCellChunkBase(cell);
|
||||||
uintptr_t grayMask;
|
return chunk->markBits.markBit(cell, ColorBit::GrayOrBlackBit);
|
||||||
TenuredChunkBase* chunk = GetCellChunkBase(cell);
|
|
||||||
chunk->markBits.getMarkWordAndMask(cell, js::gc::ColorBit::GrayOrBlackBit,
|
|
||||||
&grayWord, &grayMask);
|
|
||||||
return *grayWord & grayMask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static MOZ_ALWAYS_INLINE bool TenuredCellIsMarkedGray(const TenuredCell* cell) {
|
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) {
|
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);
|
extern JS_PUBLIC_API bool ObjectIsMarkedBlack(const JSObject* obj);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool CellHasStoreBuffer(const Cell* cell) {
|
MOZ_ALWAYS_INLINE bool ChunkPtrHasStoreBuffer(const void* ptr) {
|
||||||
return GetCellChunkBase(cell)->storeBuffer;
|
return GetGCAddressChunkBase(ptr)->storeBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace detail */
|
} /* namespace detail */
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool IsInsideNursery(const Cell* cell) {
|
MOZ_ALWAYS_INLINE bool IsInsideNursery(const Cell* cell) {
|
||||||
MOZ_ASSERT(cell);
|
MOZ_ASSERT(cell);
|
||||||
return detail::CellHasStoreBuffer(cell);
|
return detail::ChunkPtrHasStoreBuffer(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool IsInsideNursery(const TenuredCell* 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 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)
|
* 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
|
* 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);
|
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 gc
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,10 @@ extern JS_PUBLIC_API void SetHelperThreadTaskCallback(
|
||||||
// Function to call from external thread pool to run a helper thread task.
|
// Function to call from external thread pool to run a helper thread task.
|
||||||
extern JS_PUBLIC_API void RunHelperThreadTask(HelperThreadTask* 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
|
} // namespace JS
|
||||||
|
|
||||||
#endif // js_HelperThreadAPI_h
|
#endif // js_HelperThreadAPI_h
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,7 @@ class PropertyKey {
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool isAtom(JSAtom* atom) const {
|
MOZ_ALWAYS_INLINE bool isAtom(JSAtom* atom) const {
|
||||||
MOZ_ASSERT(PropertyKey::isNonIntAtom(atom));
|
MOZ_ASSERT(PropertyKey::isNonIntAtom(atom));
|
||||||
return isAtom() && toAtom() == atom;
|
return *this == NonIntAtom(atom);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE JSAtom* toAtom() const {
|
MOZ_ALWAYS_INLINE JSAtom* toAtom() const {
|
||||||
|
|
@ -292,6 +292,15 @@ struct BarrierMethods<jsid> {
|
||||||
}
|
}
|
||||||
return nullptr;
|
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) {
|
static void postWriteBarrier(jsid* idp, jsid prev, jsid next) {
|
||||||
MOZ_ASSERT_IF(next.isString(), !gc::IsInsideNursery(next.toString()));
|
MOZ_ASSERT_IF(next.isString(), !gc::IsInsideNursery(next.toString()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,6 @@ inline bool JS_IsInitialized(void) {
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
// Reference to a sequence of bytes.
|
// Reference to a sequence of bytes.
|
||||||
// TODO: This type should be Span<cont uint8_t> (Bug 1709135)
|
|
||||||
using SelfHostedCache = mozilla::Span<const uint8_t>;
|
using SelfHostedCache = mozilla::Span<const uint8_t>;
|
||||||
|
|
||||||
// Callback function used to copy the SelfHosted content to memory or to disk.
|
// Callback function used to copy the SelfHosted content to memory or to disk.
|
||||||
|
|
|
||||||
|
|
@ -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
|
* In cases where JSON.stringify would return undefined, this function calls
|
||||||
* |callback| with the string "null".
|
* |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,
|
extern JS_PUBLIC_API bool JS_Stringify(JSContext* cx,
|
||||||
JS::MutableHandle<JS::Value> value,
|
JS::MutableHandle<JS::Value> value,
|
||||||
JS::Handle<JSObject*> replacer,
|
JS::Handle<JSObject*> replacer,
|
||||||
JS::Handle<JS::Value> space,
|
JS::Handle<JS::Value> space,
|
||||||
JSONWriteCallback callback, void* data);
|
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 {
|
namespace JS {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -31,6 +31,12 @@ extern JS_PUBLIC_API bool MapHas(JSContext* cx, HandleObject obj,
|
||||||
extern JS_PUBLIC_API bool MapSet(JSContext* cx, HandleObject obj,
|
extern JS_PUBLIC_API bool MapSet(JSContext* cx, HandleObject obj,
|
||||||
HandleValue key, HandleValue val);
|
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,
|
extern JS_PUBLIC_API bool MapDelete(JSContext* cx, HandleObject obj,
|
||||||
HandleValue key, bool* rval);
|
HandleValue key, bool* rval);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -181,18 +181,17 @@ struct InefficientNonFlatteningStringHashPolicy {
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
struct ClassInfo {
|
struct ClassInfo {
|
||||||
#define FOR_EACH_SIZE(MACRO) \
|
#define FOR_EACH_SIZE(MACRO) \
|
||||||
MACRO(Objects, GCHeapUsed, objectsGCHeap) \
|
MACRO(Objects, GCHeapUsed, objectsGCHeap) \
|
||||||
MACRO(Objects, MallocHeap, objectsMallocHeapSlots) \
|
MACRO(Objects, MallocHeap, objectsMallocHeapSlots) \
|
||||||
MACRO(Objects, MallocHeap, objectsMallocHeapElementsNormal) \
|
MACRO(Objects, MallocHeap, objectsMallocHeapElementsNormal) \
|
||||||
MACRO(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \
|
MACRO(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \
|
||||||
MACRO(Objects, MallocHeap, objectsMallocHeapGlobalData) \
|
MACRO(Objects, MallocHeap, objectsMallocHeapGlobalData) \
|
||||||
MACRO(Objects, MallocHeap, objectsMallocHeapGlobalVarNamesSet) \
|
MACRO(Objects, MallocHeap, objectsMallocHeapMisc) \
|
||||||
MACRO(Objects, MallocHeap, objectsMallocHeapMisc) \
|
MACRO(Objects, NonHeap, objectsNonHeapElementsNormal) \
|
||||||
MACRO(Objects, NonHeap, objectsNonHeapElementsNormal) \
|
MACRO(Objects, NonHeap, objectsNonHeapElementsShared) \
|
||||||
MACRO(Objects, NonHeap, objectsNonHeapElementsShared) \
|
MACRO(Objects, NonHeap, objectsNonHeapElementsWasm) \
|
||||||
MACRO(Objects, NonHeap, objectsNonHeapElementsWasm) \
|
MACRO(Objects, NonHeap, objectsNonHeapElementsWasmShared) \
|
||||||
MACRO(Objects, NonHeap, objectsNonHeapElementsWasmShared) \
|
|
||||||
MACRO(Objects, NonHeap, objectsNonHeapCodeWasm)
|
MACRO(Objects, NonHeap, objectsNonHeapCodeWasm)
|
||||||
|
|
||||||
ClassInfo() = default;
|
ClassInfo() = default;
|
||||||
|
|
@ -554,7 +553,8 @@ struct UnusedGCThingSizes {
|
||||||
MACRO(Other, GCHeapUnused, bigInt) \
|
MACRO(Other, GCHeapUnused, bigInt) \
|
||||||
MACRO(Other, GCHeapUnused, jitcode) \
|
MACRO(Other, GCHeapUnused, jitcode) \
|
||||||
MACRO(Other, GCHeapUnused, scope) \
|
MACRO(Other, GCHeapUnused, scope) \
|
||||||
MACRO(Other, GCHeapUnused, regExpShared)
|
MACRO(Other, GCHeapUnused, regExpShared) \
|
||||||
|
MACRO(Other, GCHeapUnused, smallBuffer)
|
||||||
|
|
||||||
UnusedGCThingSizes() = default;
|
UnusedGCThingSizes() = default;
|
||||||
UnusedGCThingSizes(UnusedGCThingSizes&& other) = default;
|
UnusedGCThingSizes(UnusedGCThingSizes&& other) = default;
|
||||||
|
|
@ -597,6 +597,9 @@ struct UnusedGCThingSizes {
|
||||||
case JS::TraceKind::RegExpShared:
|
case JS::TraceKind::RegExpShared:
|
||||||
regExpShared += n;
|
regExpShared += n;
|
||||||
break;
|
break;
|
||||||
|
case JS::TraceKind::SmallBuffer:
|
||||||
|
smallBuffer += n;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
MOZ_CRASH("Bad trace kind for UnusedGCThingSizes");
|
MOZ_CRASH("Bad trace kind for UnusedGCThingSizes");
|
||||||
}
|
}
|
||||||
|
|
@ -625,6 +628,36 @@ struct UnusedGCThingSizes {
|
||||||
#undef FOR_EACH_SIZE
|
#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 {
|
struct ZoneStats {
|
||||||
#define FOR_EACH_SIZE(MACRO) \
|
#define FOR_EACH_SIZE(MACRO) \
|
||||||
MACRO(Other, GCHeapUsed, symbolsGCHeap) \
|
MACRO(Other, GCHeapUsed, symbolsGCHeap) \
|
||||||
|
|
@ -642,6 +675,7 @@ struct ZoneStats {
|
||||||
MACRO(Other, MallocHeap, scopesMallocHeap) \
|
MACRO(Other, MallocHeap, scopesMallocHeap) \
|
||||||
MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \
|
MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \
|
||||||
MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \
|
MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \
|
||||||
|
MACRO(Other, GCHeapUsed, smallBuffersGCHeap) \
|
||||||
MACRO(Other, MallocHeap, zoneObject) \
|
MACRO(Other, MallocHeap, zoneObject) \
|
||||||
MACRO(Other, MallocHeap, regexpZone) \
|
MACRO(Other, MallocHeap, regexpZone) \
|
||||||
MACRO(Other, MallocHeap, jitZone) \
|
MACRO(Other, MallocHeap, jitZone) \
|
||||||
|
|
@ -662,6 +696,7 @@ struct ZoneStats {
|
||||||
void addSizes(const ZoneStats& other) {
|
void addSizes(const ZoneStats& other) {
|
||||||
MOZ_ASSERT(isTotals);
|
MOZ_ASSERT(isTotals);
|
||||||
FOR_EACH_SIZE(ADD_OTHER_SIZE);
|
FOR_EACH_SIZE(ADD_OTHER_SIZE);
|
||||||
|
gcBuffers.addSizes(other.gcBuffers);
|
||||||
unusedGCThings.addSizes(other.unusedGCThings);
|
unusedGCThings.addSizes(other.unusedGCThings);
|
||||||
stringInfo.add(other.stringInfo);
|
stringInfo.add(other.stringInfo);
|
||||||
shapeInfo.add(other.shapeInfo);
|
shapeInfo.add(other.shapeInfo);
|
||||||
|
|
@ -679,6 +714,7 @@ struct ZoneStats {
|
||||||
void addToTabSizes(JS::TabSizes* sizes) const {
|
void addToTabSizes(JS::TabSizes* sizes) const {
|
||||||
MOZ_ASSERT(isTotals);
|
MOZ_ASSERT(isTotals);
|
||||||
FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
|
FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
|
||||||
|
gcBuffers.addToTabSizes(sizes);
|
||||||
unusedGCThings.addToTabSizes(sizes);
|
unusedGCThings.addToTabSizes(sizes);
|
||||||
stringInfo.addToTabSizes(sizes);
|
stringInfo.addToTabSizes(sizes);
|
||||||
shapeInfo.addToTabSizes(sizes);
|
shapeInfo.addToTabSizes(sizes);
|
||||||
|
|
@ -687,6 +723,7 @@ struct ZoneStats {
|
||||||
void addToServoSizes(JS::ServoSizes* sizes) const {
|
void addToServoSizes(JS::ServoSizes* sizes) const {
|
||||||
MOZ_ASSERT(isTotals);
|
MOZ_ASSERT(isTotals);
|
||||||
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
|
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
|
||||||
|
gcBuffers.addToServoSizes(sizes);
|
||||||
unusedGCThings.addToServoSizes(sizes);
|
unusedGCThings.addToServoSizes(sizes);
|
||||||
stringInfo.addToServoSizes(sizes);
|
stringInfo.addToServoSizes(sizes);
|
||||||
shapeInfo.addToServoSizes(sizes);
|
shapeInfo.addToServoSizes(sizes);
|
||||||
|
|
@ -695,6 +732,8 @@ struct ZoneStats {
|
||||||
|
|
||||||
FOR_EACH_SIZE(DECL_SIZE_ZERO);
|
FOR_EACH_SIZE(DECL_SIZE_ZERO);
|
||||||
|
|
||||||
|
GCBufferStats gcBuffers;
|
||||||
|
|
||||||
// These string measurements are initially for all strings. At the end,
|
// These string measurements are initially for all strings. At the end,
|
||||||
// if the measurement granularity is FineGrained, we subtract the
|
// if the measurement granularity is FineGrained, we subtract the
|
||||||
// measurements of the notable script sources and move them into
|
// measurements of the notable script sources and move them into
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,15 @@ union Utf8Unit;
|
||||||
|
|
||||||
namespace JS {
|
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.
|
* The HostResolveImportedModule hook.
|
||||||
|
|
@ -179,6 +187,15 @@ extern JS_PUBLIC_API JSObject* CompileJsonModule(
|
||||||
JSContext* cx, const ReadOnlyCompileOptions& options,
|
JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||||
SourceText<char16_t>& srcBuf);
|
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.
|
* 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);
|
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.
|
* 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,
|
JSContext* cx, Handle<JSObject*> moduleRecord, uint32_t index,
|
||||||
uint32_t* lineNumber, JS::ColumnNumberOneOrigin* columnNumber);
|
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.
|
* 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 JSScript* GetModuleScript(Handle<JSObject*> moduleRecord);
|
||||||
|
|
||||||
extern JS_PUBLIC_API JSObject* CreateModuleRequest(
|
extern JS_PUBLIC_API JSObject* CreateModuleRequest(
|
||||||
JSContext* cx, Handle<JSString*> specifierArg);
|
JSContext* cx, Handle<JSString*> specifierArg, ModuleType moduleType);
|
||||||
extern JS_PUBLIC_API JSString* GetModuleRequestSpecifier(
|
extern JS_PUBLIC_API JSString* GetModuleRequestSpecifier(
|
||||||
JSContext* cx, Handle<JSObject*> moduleRequestArg);
|
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.
|
* Get the module record for a module script.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
}; // namespace JS
|
||||||
|
|
||||||
#endif /* js_Prefs_h */
|
#endif /* js_Prefs_h */
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,21 @@ struct JSPrincipals {
|
||||||
|
|
||||||
#ifdef JS_DEBUG
|
#ifdef JS_DEBUG
|
||||||
/* A helper to facilitate principals debugging. */
|
/* A helper to facilitate principals debugging. */
|
||||||
uint32_t debugToken;
|
uint32_t debugToken = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JSPrincipals() = default;
|
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
|
#ifdef JS_DEBUG
|
||||||
debugToken = token;
|
debugToken = token;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -68,23 +77,54 @@ typedef bool (*JSSubsumesOp)(JSPrincipals* first, JSPrincipals* second);
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
enum class RuntimeCode { JS, WASM };
|
enum class RuntimeCode { JS, WASM };
|
||||||
|
enum class CompilationType { DirectEval, IndirectEval, Function, Undefined };
|
||||||
} // namespace JS
|
} // namespace JS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to check if a CSP instance wants to disable eval() and friends.
|
* Used to check if a CSP instance wants to disable eval() and friends.
|
||||||
* See JSContext::isRuntimeCodeGenEnabled() in vm/JSContext.cpp.
|
* See JSContext::isRuntimeCodeGenEnabled() in vm/JSContext.cpp.
|
||||||
*
|
*
|
||||||
* `code` is the JavaScript source code passed to eval/Function, but nullptr
|
* codeString, compilationType, parameterStrings, bodyString, parameterArgs,
|
||||||
* for Wasm.
|
* 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
|
* An Undefined compilationType is used for cases that are not covered by that
|
||||||
* of the code.
|
* 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,
|
typedef bool (*JSCSPEvalChecker)(
|
||||||
JS::HandleString code);
|
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 {
|
struct JSSecurityCallbacks {
|
||||||
JSCSPEvalChecker contentSecurityPolicyAllows;
|
JSCSPEvalChecker contentSecurityPolicyAllows;
|
||||||
|
JSCodeForEvalOp codeForEvalGets;
|
||||||
JSSubsumesOp subsumes;
|
JSSubsumesOp subsumes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/glue/Debug.h"
|
#include "mozilla/glue/Debug.h"
|
||||||
#include "mozilla/Range.h"
|
#include "mozilla/Range.h"
|
||||||
|
#include "mozilla/Vector.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
@ -139,7 +140,7 @@ class LifoAlloc;
|
||||||
// of chunks allocated with a LifoAlloc.
|
// of chunks allocated with a LifoAlloc.
|
||||||
class JS_PUBLIC_API GenericPrinter {
|
class JS_PUBLIC_API GenericPrinter {
|
||||||
protected:
|
protected:
|
||||||
bool hadOOM_; // whether reportOutOfMemory() has been called.
|
bool hadOOM_; // whether setPendingOutOfMemory() has been called.
|
||||||
|
|
||||||
constexpr GenericPrinter() : hadOOM_(false) {}
|
constexpr GenericPrinter() : hadOOM_(false) {}
|
||||||
|
|
||||||
|
|
@ -151,6 +152,7 @@ class JS_PUBLIC_API GenericPrinter {
|
||||||
// still report any of the previous errors.
|
// still report any of the previous errors.
|
||||||
virtual void put(const char* s, size_t len) = 0;
|
virtual void put(const char* s, size_t len) = 0;
|
||||||
inline void put(const char* s) { put(s, strlen(s)); }
|
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
|
// Put a mozilla::Span / mozilla::Range of Latin1Char or char16_t characters
|
||||||
// in the output.
|
// in the output.
|
||||||
|
|
@ -202,11 +204,11 @@ class JS_PUBLIC_API GenericPrinter {
|
||||||
virtual size_t index() const { return 0; }
|
virtual size_t index() const { return 0; }
|
||||||
|
|
||||||
// In some printers, this ensure that the content is fully written.
|
// 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.
|
// Set a flag that a string operation failed to get the memory it requested.
|
||||||
virtual void reportOutOfMemory();
|
// The pending out of memory error should be handled by the consumer.
|
||||||
|
virtual void setPendingOutOfMemory();
|
||||||
|
|
||||||
// Return true if this Sprinter ran out of memory.
|
// Return true if this Sprinter ran out of memory.
|
||||||
virtual bool hadOutOfMemory() const { return hadOOM_; }
|
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(); }
|
size_t index() const final { return out.index(); }
|
||||||
void flush() final { out.flush(); }
|
void flush() final { out.flush(); }
|
||||||
void reportOutOfMemory() final { out.reportOutOfMemory(); }
|
void setPendingOutOfMemory() final { out.setPendingOutOfMemory(); }
|
||||||
bool hadOutOfMemory() const final { return out.hadOutOfMemory(); }
|
bool hadOutOfMemory() const final { return out.hadOutOfMemory(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -490,43 +492,118 @@ class JS_PUBLIC_API StringEscape {
|
||||||
void convertInto(GenericPrinter& out, char16_t c);
|
void convertInto(GenericPrinter& out, char16_t c);
|
||||||
};
|
};
|
||||||
|
|
||||||
// A GenericPrinter that formats everything at a nested indentation level.
|
class JS_PUBLIC_API WATStringEscape {
|
||||||
class JS_PUBLIC_API IndentedPrinter final : public GenericPrinter {
|
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_;
|
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.
|
// The number of spaces to insert for each indent.
|
||||||
uint32_t indentAmount_;
|
int indentAmount_;
|
||||||
// Whether we have seen a line ending and should insert an indent at the
|
|
||||||
// next line fragment.
|
|
||||||
bool pendingIndent_;
|
bool pendingIndent_;
|
||||||
|
|
||||||
// Put an indent to `out_`
|
// The index of the last expanded scope (or -1 if all scopes are collapsed).
|
||||||
void putIndent();
|
int expandedDepth_ = -1;
|
||||||
// Put `s` to `out_`, inserting an indent if we need to
|
|
||||||
void putWithMaybeIndent(const char* s, size_t len);
|
|
||||||
|
|
||||||
public:
|
struct Break {
|
||||||
explicit IndentedPrinter(GenericPrinter& out, uint32_t indentLevel = 0,
|
uint32_t bufferPos;
|
||||||
uint32_t indentAmount = 2)
|
bool isCollapsed;
|
||||||
: out_(out),
|
const char* collapsed;
|
||||||
indentLevel_(indentLevel),
|
const char* expanded;
|
||||||
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); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t indentLevel() const { return indentLevel_; }
|
struct ScopeInfo {
|
||||||
void setIndentLevel(uint32_t indentLevel) { indentLevel_ = indentLevel; }
|
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;
|
virtual void put(const char* s, size_t len) override;
|
||||||
using GenericPrinter::put; // pick up |inline void put(const char* s);|
|
using GenericPrinter::put; // pick up |inline void put(const char* s);|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ class MOZ_NON_PARAM JS_PUBLIC_API ProfilingFrameIterator {
|
||||||
void* endStackAddress_ = nullptr;
|
void* endStackAddress_ = nullptr;
|
||||||
Kind kind_;
|
Kind kind_;
|
||||||
|
|
||||||
static const unsigned StorageSpace = 8 * sizeof(void*);
|
static const unsigned StorageSpace = 9 * sizeof(void*);
|
||||||
alignas(void*) unsigned char storage_[StorageSpace];
|
alignas(void*) unsigned char storage_[StorageSpace];
|
||||||
|
|
||||||
void* storage() { return storage_; }
|
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)
|
// - is weakly monotonically increasing (may be equal for successive frames)
|
||||||
// - will compare greater than newer native and psuedo-stack frame addresses
|
// - will compare greater than newer native and psuedo-stack frame addresses
|
||||||
// and less than older 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;
|
void* stackAddress() const;
|
||||||
|
|
||||||
enum FrameKind {
|
enum FrameKind {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
#define js_ProfilingStack_h
|
#define js_ProfilingStack_h
|
||||||
|
|
||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
|
#include "mozilla/BaseProfilerMarkersPrerequisites.h"
|
||||||
|
#include "mozilla/TimeStamp.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
@ -362,9 +364,11 @@ JS_PUBLIC_API void SetContextProfilingStack(JSContext* cx,
|
||||||
|
|
||||||
JS_PUBLIC_API void EnableContextProfilingStack(JSContext* cx, bool enabled);
|
JS_PUBLIC_API void EnableContextProfilingStack(JSContext* cx, bool enabled);
|
||||||
|
|
||||||
JS_PUBLIC_API void RegisterContextProfilingEventMarker(JSContext* cx,
|
JS_PUBLIC_API void RegisterContextProfilingEventMarker(
|
||||||
void (*fn)(const char*,
|
JSContext* cx,
|
||||||
const char*));
|
void (*mark)(mozilla::MarkerCategory, const char*, const char*),
|
||||||
|
void (*interval)(mozilla::MarkerCategory, const char*, mozilla::TimeStamp,
|
||||||
|
const char*));
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,19 +36,36 @@ class JS_PUBLIC_API JobQueue {
|
||||||
virtual ~JobQueue() = default;
|
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
|
* by the HTML spec, so we need the embedding to provide this. See
|
||||||
* dom/script/ScriptSettings.h for details.
|
* 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
|
* 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 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` can be null if the promise is optimized out.
|
||||||
* `promise` is guaranteed not to be optimized out if the promise has
|
* `promise` is guaranteed not to be optimized out if the promise has
|
||||||
* non-default user-interaction flag.
|
* non-default user-interaction flag.
|
||||||
|
|
@ -56,7 +73,7 @@ class JS_PUBLIC_API JobQueue {
|
||||||
virtual bool enqueuePromiseJob(JSContext* cx, JS::HandleObject promise,
|
virtual bool enqueuePromiseJob(JSContext* cx, JS::HandleObject promise,
|
||||||
JS::HandleObject job,
|
JS::HandleObject job,
|
||||||
JS::HandleObject allocationSite,
|
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
|
* 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.
|
* on a JSContext thread when requested via DispatchToEventLoopCallback.
|
||||||
*/
|
*/
|
||||||
class JS_PUBLIC_API Dispatchable {
|
class JS_PUBLIC_API Dispatchable {
|
||||||
protected:
|
public:
|
||||||
// Dispatchables are created and destroyed by SpiderMonkey.
|
// Destruction of Dispatchables is public in order to be used with
|
||||||
Dispatchable() = default;
|
// UniquePtrs. Their destruction by SpiderMonkey is enforced by
|
||||||
|
// ReleaseFailedTask.
|
||||||
virtual ~Dispatchable() = default;
|
virtual ~Dispatchable() = default;
|
||||||
|
|
||||||
public:
|
|
||||||
// ShuttingDown indicates that SpiderMonkey should abort async tasks to
|
// ShuttingDown indicates that SpiderMonkey should abort async tasks to
|
||||||
// expedite shutdown.
|
// expedite shutdown.
|
||||||
enum MaybeShuttingDown { NotShuttingDown, ShuttingDown };
|
enum MaybeShuttingDown { NotShuttingDown, ShuttingDown };
|
||||||
|
|
||||||
// Called by the embedding after DispatchToEventLoopCallback succeeds.
|
// 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;
|
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
|
* The DispatchToEventLoopCallback set on a particular JSContext must accept
|
||||||
* JS::Dispatchable instances and arrange for their `run` methods to be called
|
* 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,
|
* 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
|
* If the callback returns `true`, it must eventually run the given
|
||||||
* Dispatchable; otherwise, SpiderMonkey may leak memory or hang.
|
* Dispatchable; otherwise, SpiderMonkey may leak memory or hang.
|
||||||
|
|
@ -577,17 +632,21 @@ class JS_PUBLIC_API Dispatchable {
|
||||||
* all subsequently submitted runnables as well.
|
* all subsequently submitted runnables as well.
|
||||||
*
|
*
|
||||||
* To establish a DispatchToEventLoopCallback, the embedding may either call
|
* 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
|
* to select a default implementation built into SpiderMonkey. This latter
|
||||||
* depends on the embedding to call js::RunJobs on the JavaScript thread to
|
* depends on the embedding to call js::RunJobs on the JavaScript thread to
|
||||||
* process queued Dispatchables at appropriate times.
|
* process queued Dispatchables at appropriate times.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef bool (*DispatchToEventLoopCallback)(void* closure,
|
typedef bool (*DispatchToEventLoopCallback)(
|
||||||
Dispatchable* dispatchable);
|
void* closure, js::UniquePtr<Dispatchable>&& dispatchable);
|
||||||
|
|
||||||
extern JS_PUBLIC_API void InitDispatchToEventLoop(
|
typedef bool (*DelayedDispatchToEventLoopCallback)(
|
||||||
JSContext* cx, DispatchToEventLoopCallback callback, void* closure);
|
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
|
* When a JSRuntime is destroyed it implicitly cancels all async tasks in
|
||||||
|
|
|
||||||
|
|
@ -452,6 +452,6 @@ struct JSFunctionSpec {
|
||||||
#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \
|
#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \
|
||||||
JS_FNSPEC(::JS::SymbolCode::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) \
|
#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
|
#endif // js_PropertySpec_h
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,6 @@
|
||||||
# define IF_INTL(REAL, IMAGINARY) IMAGINARY
|
# define IF_INTL(REAL, IMAGINARY) IMAGINARY
|
||||||
#endif
|
#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
|
#ifdef ENABLE_WASM_TYPE_REFLECTIONS
|
||||||
# define IF_WASM_TYPE(REAL, IMAGINARY) REAL
|
# define IF_WASM_TYPE(REAL, IMAGINARY) REAL
|
||||||
#else
|
#else
|
||||||
|
|
@ -65,109 +59,112 @@
|
||||||
# define IF_NIGHTLY(REAL, IMAGINARY) IMAGINARY
|
# define IF_NIGHTLY(REAL, IMAGINARY) IMAGINARY
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define JS_FOR_PROTOTYPES_(REAL, IMAGINARY, REAL_IF_INTL, REAL_IF_TEMPORAL, \
|
#define JS_FOR_PROTOTYPES_(REAL, IMAGINARY, REAL_IF_INTL, REAL_IF_WASM_TYPE, \
|
||||||
REAL_IF_WASM_TYPE, REAL_IF_WASM_JSPI, \
|
REAL_IF_WASM_JSPI, REAL_IF_NIGHTLY) \
|
||||||
REAL_IF_NIGHTLY) \
|
IMAGINARY(Null, dummy) \
|
||||||
IMAGINARY(Null, dummy) \
|
REAL(Object, OCLASP(Plain)) \
|
||||||
REAL(Object, OCLASP(Plain)) \
|
REAL(Function, &FunctionClass) \
|
||||||
REAL(Function, &FunctionClass) \
|
IMAGINARY(BoundFunction, OCLASP(BoundFunction)) \
|
||||||
IMAGINARY(BoundFunction, OCLASP(BoundFunction)) \
|
REAL(Array, OCLASP(Array)) \
|
||||||
REAL(Array, OCLASP(Array)) \
|
REAL(Boolean, OCLASP(Boolean)) \
|
||||||
REAL(Boolean, OCLASP(Boolean)) \
|
REAL(JSON, CLASP(JSON)) \
|
||||||
REAL(JSON, CLASP(JSON)) \
|
REAL(Date, OCLASP(Date)) \
|
||||||
REAL(Date, OCLASP(Date)) \
|
REAL(Math, CLASP(Math)) \
|
||||||
REAL(Math, CLASP(Math)) \
|
REAL(Number, OCLASP(Number)) \
|
||||||
REAL(Number, OCLASP(Number)) \
|
REAL(String, OCLASP(String)) \
|
||||||
REAL(String, OCLASP(String)) \
|
REAL(RegExp, OCLASP(RegExp)) \
|
||||||
REAL(RegExp, OCLASP(RegExp)) \
|
REAL(Error, ERROR_CLASP(JSEXN_ERR)) \
|
||||||
REAL(Error, ERROR_CLASP(JSEXN_ERR)) \
|
REAL(InternalError, ERROR_CLASP(JSEXN_INTERNALERR)) \
|
||||||
REAL(InternalError, ERROR_CLASP(JSEXN_INTERNALERR)) \
|
REAL(AggregateError, ERROR_CLASP(JSEXN_AGGREGATEERR)) \
|
||||||
REAL(AggregateError, ERROR_CLASP(JSEXN_AGGREGATEERR)) \
|
REAL(EvalError, ERROR_CLASP(JSEXN_EVALERR)) \
|
||||||
REAL(EvalError, ERROR_CLASP(JSEXN_EVALERR)) \
|
REAL(RangeError, ERROR_CLASP(JSEXN_RANGEERR)) \
|
||||||
REAL(RangeError, ERROR_CLASP(JSEXN_RANGEERR)) \
|
REAL(ReferenceError, ERROR_CLASP(JSEXN_REFERENCEERR)) \
|
||||||
REAL(ReferenceError, ERROR_CLASP(JSEXN_REFERENCEERR)) \
|
IF_EXPLICIT_RESOURCE_MANAGEMENT( \
|
||||||
REAL(SyntaxError, ERROR_CLASP(JSEXN_SYNTAXERR)) \
|
REAL(SuppressedError, ERROR_CLASP(JSEXN_SUPPRESSEDERR))) \
|
||||||
REAL(TypeError, ERROR_CLASP(JSEXN_TYPEERR)) \
|
REAL(SyntaxError, ERROR_CLASP(JSEXN_SYNTAXERR)) \
|
||||||
REAL(URIError, ERROR_CLASP(JSEXN_URIERR)) \
|
REAL(TypeError, ERROR_CLASP(JSEXN_TYPEERR)) \
|
||||||
REAL(DebuggeeWouldRun, ERROR_CLASP(JSEXN_DEBUGGEEWOULDRUN)) \
|
REAL(URIError, ERROR_CLASP(JSEXN_URIERR)) \
|
||||||
REAL(CompileError, ERROR_CLASP(JSEXN_WASMCOMPILEERROR)) \
|
REAL(DebuggeeWouldRun, ERROR_CLASP(JSEXN_DEBUGGEEWOULDRUN)) \
|
||||||
REAL(LinkError, ERROR_CLASP(JSEXN_WASMLINKERROR)) \
|
REAL(CompileError, ERROR_CLASP(JSEXN_WASMCOMPILEERROR)) \
|
||||||
REAL(RuntimeError, ERROR_CLASP(JSEXN_WASMRUNTIMEERROR)) \
|
REAL(LinkError, ERROR_CLASP(JSEXN_WASMLINKERROR)) \
|
||||||
REAL(ArrayBuffer, OCLASP(FixedLengthArrayBuffer)) \
|
REAL(RuntimeError, ERROR_CLASP(JSEXN_WASMRUNTIMEERROR)) \
|
||||||
REAL(Int8Array, TYPED_ARRAY_CLASP(Int8)) \
|
REAL_IF_WASM_JSPI(SuspendError, ERROR_CLASP(JSEXN_WASMSUSPENDERROR)) \
|
||||||
REAL(Uint8Array, TYPED_ARRAY_CLASP(Uint8)) \
|
REAL(ArrayBuffer, OCLASP(FixedLengthArrayBuffer)) \
|
||||||
REAL(Int16Array, TYPED_ARRAY_CLASP(Int16)) \
|
REAL(Int8Array, TYPED_ARRAY_CLASP(Int8)) \
|
||||||
REAL(Uint16Array, TYPED_ARRAY_CLASP(Uint16)) \
|
REAL(Uint8Array, TYPED_ARRAY_CLASP(Uint8)) \
|
||||||
REAL(Int32Array, TYPED_ARRAY_CLASP(Int32)) \
|
REAL(Int16Array, TYPED_ARRAY_CLASP(Int16)) \
|
||||||
REAL(Uint32Array, TYPED_ARRAY_CLASP(Uint32)) \
|
REAL(Uint16Array, TYPED_ARRAY_CLASP(Uint16)) \
|
||||||
REAL(Float32Array, TYPED_ARRAY_CLASP(Float32)) \
|
REAL(Int32Array, TYPED_ARRAY_CLASP(Int32)) \
|
||||||
REAL(Float64Array, TYPED_ARRAY_CLASP(Float64)) \
|
REAL(Uint32Array, TYPED_ARRAY_CLASP(Uint32)) \
|
||||||
REAL(Uint8ClampedArray, TYPED_ARRAY_CLASP(Uint8Clamped)) \
|
REAL(Float32Array, TYPED_ARRAY_CLASP(Float32)) \
|
||||||
REAL(BigInt64Array, TYPED_ARRAY_CLASP(BigInt64)) \
|
REAL(Float64Array, TYPED_ARRAY_CLASP(Float64)) \
|
||||||
REAL(BigUint64Array, TYPED_ARRAY_CLASP(BigUint64)) \
|
REAL(Uint8ClampedArray, TYPED_ARRAY_CLASP(Uint8Clamped)) \
|
||||||
REAL_IF_NIGHTLY(Float16Array, TYPED_ARRAY_CLASP(Float16)) \
|
REAL(BigInt64Array, TYPED_ARRAY_CLASP(BigInt64)) \
|
||||||
REAL(BigInt, OCLASP(BigInt)) \
|
REAL(BigUint64Array, TYPED_ARRAY_CLASP(BigUint64)) \
|
||||||
REAL(Proxy, CLASP(Proxy)) \
|
REAL(Float16Array, TYPED_ARRAY_CLASP(Float16)) \
|
||||||
REAL(WeakMap, OCLASP(WeakMap)) \
|
REAL(BigInt, OCLASP(BigInt)) \
|
||||||
REAL(Map, OCLASP(Map)) \
|
REAL(Proxy, CLASP(Proxy)) \
|
||||||
REAL(Set, OCLASP(Set)) \
|
REAL(WeakMap, OCLASP(WeakMap)) \
|
||||||
REAL(DataView, OCLASP(FixedLengthDataView)) \
|
REAL(Map, OCLASP(Map)) \
|
||||||
REAL(Symbol, OCLASP(Symbol)) \
|
REAL(Set, OCLASP(Set)) \
|
||||||
REAL(ShadowRealm, OCLASP(ShadowRealm)) \
|
REAL(DataView, OCLASP(FixedLengthDataView)) \
|
||||||
REAL(SharedArrayBuffer, OCLASP(FixedLengthSharedArrayBuffer)) \
|
REAL(Symbol, OCLASP(Symbol)) \
|
||||||
REAL_IF_INTL(Intl, CLASP(Intl)) \
|
REAL(ShadowRealm, OCLASP(ShadowRealm)) \
|
||||||
REAL_IF_INTL(Collator, OCLASP(Collator)) \
|
REAL(SharedArrayBuffer, OCLASP(FixedLengthSharedArrayBuffer)) \
|
||||||
REAL_IF_INTL(DateTimeFormat, OCLASP(DateTimeFormat)) \
|
REAL_IF_INTL(Intl, CLASP(Intl)) \
|
||||||
REAL_IF_INTL(DisplayNames, OCLASP(DisplayNames)) \
|
REAL_IF_INTL(Collator, OCLASP(Collator)) \
|
||||||
REAL_IF_INTL(ListFormat, OCLASP(ListFormat)) \
|
REAL_IF_INTL(DateTimeFormat, OCLASP(DateTimeFormat)) \
|
||||||
REAL_IF_INTL(Locale, OCLASP(Locale)) \
|
REAL_IF_INTL(DisplayNames, OCLASP(DisplayNames)) \
|
||||||
REAL_IF_INTL(NumberFormat, OCLASP(NumberFormat)) \
|
REAL_IF_INTL(DurationFormat, OCLASP(DurationFormat)) \
|
||||||
REAL_IF_INTL(PluralRules, OCLASP(PluralRules)) \
|
REAL_IF_INTL(ListFormat, OCLASP(ListFormat)) \
|
||||||
REAL_IF_INTL(RelativeTimeFormat, OCLASP(RelativeTimeFormat)) \
|
REAL_IF_INTL(Locale, OCLASP(Locale)) \
|
||||||
REAL_IF_INTL(Segmenter, OCLASP(Segmenter)) \
|
REAL_IF_INTL(NumberFormat, OCLASP(NumberFormat)) \
|
||||||
REAL(Reflect, CLASP(Reflect)) \
|
REAL_IF_INTL(PluralRules, OCLASP(PluralRules)) \
|
||||||
REAL(WeakSet, OCLASP(WeakSet)) \
|
REAL_IF_INTL(RelativeTimeFormat, OCLASP(RelativeTimeFormat)) \
|
||||||
REAL(TypedArray, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \
|
REAL_IF_INTL(Segmenter, OCLASP(Segmenter)) \
|
||||||
REAL(Atomics, OCLASP(Atomics)) \
|
REAL(Reflect, CLASP(Reflect)) \
|
||||||
REAL(SavedFrame, &js::SavedFrame::class_) \
|
REAL(WeakSet, OCLASP(WeakSet)) \
|
||||||
REAL(Promise, OCLASP(Promise)) \
|
REAL(TypedArray, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \
|
||||||
REAL(AsyncFunction, CLASP(AsyncFunction)) \
|
REAL(Atomics, OCLASP(Atomics)) \
|
||||||
REAL(GeneratorFunction, CLASP(GeneratorFunction)) \
|
REAL(SavedFrame, &js::SavedFrame::class_) \
|
||||||
REAL(AsyncGeneratorFunction, CLASP(AsyncGeneratorFunction)) \
|
REAL(Promise, OCLASP(Promise)) \
|
||||||
REAL(WebAssembly, OCLASP(WasmNamespace)) \
|
REAL(AsyncFunction, CLASP(AsyncFunction)) \
|
||||||
REAL(WasmModule, OCLASP(WasmModule)) \
|
REAL(GeneratorFunction, CLASP(GeneratorFunction)) \
|
||||||
REAL(WasmInstance, OCLASP(WasmInstance)) \
|
REAL(AsyncGeneratorFunction, CLASP(AsyncGeneratorFunction)) \
|
||||||
REAL(WasmMemory, OCLASP(WasmMemory)) \
|
REAL(WebAssembly, OCLASP(WasmNamespace)) \
|
||||||
REAL(WasmTable, OCLASP(WasmTable)) \
|
REAL(WasmModule, OCLASP(WasmModule)) \
|
||||||
REAL(WasmGlobal, OCLASP(WasmGlobal)) \
|
REAL(WasmInstance, OCLASP(WasmInstance)) \
|
||||||
REAL(WasmTag, OCLASP(WasmTag)) \
|
REAL(WasmMemory, OCLASP(WasmMemory)) \
|
||||||
REAL_IF_WASM_TYPE(WasmFunction, CLASP(WasmFunction)) \
|
REAL(WasmTable, OCLASP(WasmTable)) \
|
||||||
REAL_IF_WASM_JSPI(WasmSuspending, OCLASP(WasmSuspending)) \
|
REAL(WasmGlobal, OCLASP(WasmGlobal)) \
|
||||||
REAL(WasmException, OCLASP(WasmException)) \
|
REAL(WasmTag, OCLASP(WasmTag)) \
|
||||||
REAL(FinalizationRegistry, OCLASP(FinalizationRegistry)) \
|
REAL_IF_WASM_TYPE(WasmFunction, CLASP(WasmFunction)) \
|
||||||
REAL(WeakRef, OCLASP(WeakRef)) \
|
REAL_IF_WASM_JSPI(WasmSuspending, OCLASP(WasmSuspending)) \
|
||||||
REAL(Iterator, OCLASP(Iterator)) \
|
REAL(WasmException, OCLASP(WasmException)) \
|
||||||
REAL(AsyncIterator, OCLASP(AsyncIterator)) \
|
REAL(FinalizationRegistry, OCLASP(FinalizationRegistry)) \
|
||||||
REAL_IF_TEMPORAL(Temporal, OCLASP(temporal::Temporal)) \
|
REAL(WeakRef, OCLASP(WeakRef)) \
|
||||||
REAL_IF_TEMPORAL(Calendar, OCLASP(temporal::Calendar)) \
|
REAL(Iterator, OCLASP(Iterator)) \
|
||||||
REAL_IF_TEMPORAL(Duration, OCLASP(temporal::Duration)) \
|
REAL(AsyncIterator, OCLASP(AsyncIterator)) \
|
||||||
REAL_IF_TEMPORAL(Instant, OCLASP(temporal::Instant)) \
|
IF_EXPLICIT_RESOURCE_MANAGEMENT( \
|
||||||
REAL_IF_TEMPORAL(PlainDate, OCLASP(temporal::PlainDate)) \
|
REAL(DisposableStack, OCLASP(DisposableStack))) \
|
||||||
REAL_IF_TEMPORAL(PlainDateTime, OCLASP(temporal::PlainDateTime)) \
|
IF_EXPLICIT_RESOURCE_MANAGEMENT( \
|
||||||
REAL_IF_TEMPORAL(PlainMonthDay, OCLASP(temporal::PlainMonthDay)) \
|
REAL(AsyncDisposableStack, OCLASP(AsyncDisposableStack))) \
|
||||||
REAL_IF_TEMPORAL(PlainYearMonth, OCLASP(temporal::PlainYearMonth)) \
|
REAL_IF_INTL(Temporal, OCLASP(temporal::Temporal)) \
|
||||||
REAL_IF_TEMPORAL(PlainTime, OCLASP(temporal::PlainTime)) \
|
REAL_IF_INTL(Duration, OCLASP(temporal::Duration)) \
|
||||||
REAL_IF_TEMPORAL(TemporalNow, OCLASP(temporal::TemporalNow)) \
|
REAL_IF_INTL(Instant, OCLASP(temporal::Instant)) \
|
||||||
REAL_IF_TEMPORAL(TimeZone, OCLASP(temporal::TimeZone)) \
|
REAL_IF_INTL(PlainDate, OCLASP(temporal::PlainDate)) \
|
||||||
REAL_IF_TEMPORAL(ZonedDateTime, OCLASP(temporal::ZonedDateTime)) \
|
REAL_IF_INTL(PlainDateTime, OCLASP(temporal::PlainDateTime)) \
|
||||||
IF_RECORD_TUPLE(REAL(Record, (&RecordType::class_))) \
|
REAL_IF_INTL(PlainMonthDay, OCLASP(temporal::PlainMonthDay)) \
|
||||||
IF_RECORD_TUPLE(REAL(Tuple, (&TupleType::class_)))
|
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) \
|
#define JS_FOR_PROTOTYPES(REAL, IMAGINARY) \
|
||||||
JS_FOR_PROTOTYPES_( \
|
JS_FOR_PROTOTYPES_(REAL, IMAGINARY, IF_INTL(REAL, IMAGINARY), \
|
||||||
REAL, IMAGINARY, IF_INTL(REAL, IMAGINARY), IF_TEMPORAL(REAL, IMAGINARY), \
|
IF_WASM_TYPE(REAL, IMAGINARY), \
|
||||||
IF_WASM_TYPE(REAL, IMAGINARY), IF_WASM_JSPI(REAL, IMAGINARY), \
|
IF_WASM_JSPI(REAL, IMAGINARY), \
|
||||||
IF_NIGHTLY(REAL, IMAGINARY))
|
IF_NIGHTLY(REAL, IMAGINARY))
|
||||||
|
|
||||||
#define JS_FOR_EACH_PROTOTYPE(MACRO) JS_FOR_PROTOTYPES(MACRO, MACRO)
|
#define JS_FOR_EACH_PROTOTYPE(MACRO) JS_FOR_PROTOTYPES(MACRO, MACRO)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,10 @@ class JS_PUBLIC_API Wrapper;
|
||||||
* organized in the following hierarchy:
|
* organized in the following hierarchy:
|
||||||
*
|
*
|
||||||
* BaseProxyHandler
|
* BaseProxyHandler
|
||||||
|
* | |
|
||||||
|
* | NurseryAllocableProxyHandler
|
||||||
|
* | // allocated in the nursery; disallows
|
||||||
|
* | // overriding finalize method
|
||||||
* |
|
* |
|
||||||
* ForwardingProxyHandler // has a target and forwards internal methods
|
* ForwardingProxyHandler // has a target and forwards internal methods
|
||||||
* |
|
* |
|
||||||
|
|
@ -378,6 +382,17 @@ class JS_PUBLIC_API BaseProxyHandler {
|
||||||
virtual bool isScripted() const { return false; }
|
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;
|
extern JS_PUBLIC_DATA const JSClass ProxyClass;
|
||||||
|
|
||||||
inline bool IsProxy(const JSObject* obj) {
|
inline bool IsProxy(const JSObject* obj) {
|
||||||
|
|
@ -463,12 +478,12 @@ constexpr ptrdiff_t ProxyReservedSlots::offsetOfPrivateSlot() {
|
||||||
offsetof(ProxyValueArray, privateSlot);
|
offsetof(ProxyValueArray, privateSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All proxies share the same data layout. Following the object's shape and
|
// All proxies share the same data layout. Following the object's shape, the
|
||||||
// type, the proxy has a ProxyDataLayout structure with a pointer to an array
|
// proxy has a ProxyDataLayout structure with a pointer to an array of values
|
||||||
// of values and the proxy's handler. This is designed both so that proxies can
|
// and the proxy's handler. This is designed both so that proxies can be easily
|
||||||
// be easily swapped with other objects (via RemapWrapper) and to mimic the
|
// swapped with other objects (via RemapWrapper) and to mimic the layout of
|
||||||
// layout of other objects (proxies and other objects have the same size) so
|
// other objects (proxies and other objects have the same size) so that common
|
||||||
// that common code can access either type of object.
|
// code can access either type of object.
|
||||||
//
|
//
|
||||||
// See GetReservedOrProxyPrivateSlot below.
|
// See GetReservedOrProxyPrivateSlot below.
|
||||||
struct ProxyDataLayout {
|
struct ProxyDataLayout {
|
||||||
|
|
@ -554,9 +569,8 @@ inline void SetProxyReservedSlot(JSObject* obj, size_t n,
|
||||||
|
|
||||||
inline void SetProxyPrivate(JSObject* obj, const JS::Value& value) {
|
inline void SetProxyPrivate(JSObject* obj, const JS::Value& value) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (gc::detail::ObjectIsMarkedBlack(obj)) {
|
JS::AssertObjectIsNotGray(obj);
|
||||||
JS::AssertValueIsNotGray(value);
|
JS::AssertValueIsNotGray(value);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JS::Value* vp = &detail::GetProxyDataLayout(obj)->values()->privateSlot;
|
JS::Value* vp = &detail::GetProxyDataLayout(obj)->values()->privateSlot;
|
||||||
|
|
@ -693,10 +707,9 @@ class JS_PUBLIC_API AutoWaivePolicy : public AutoEnterPolicy {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
class JS_PUBLIC_API AutoWaivePolicy {
|
class JS_PUBLIC_API AutoWaivePolicy{
|
||||||
public:
|
public : AutoWaivePolicy(JSContext * cx, JS::HandleObject proxy,
|
||||||
AutoWaivePolicy(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
|
JS::HandleId id, BaseProxyHandler::Action act){}
|
||||||
BaseProxyHandler::Action act) {}
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -741,14 +754,14 @@ constexpr unsigned CheckProxyFlags() {
|
||||||
return Flags;
|
return Flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PROXY_CLASS_DEF_WITH_CLASS_SPEC(name, flags, classSpec) \
|
#define PROXY_CLASS_DEF_WITH_CLASS_SPEC(name, flags, classSpec) \
|
||||||
{ \
|
{name, \
|
||||||
name, \
|
JSClass::NON_NATIVE | JSCLASS_IS_PROXY | JSCLASS_DELAY_METADATA_BUILDER | \
|
||||||
JSClass::NON_NATIVE | JSCLASS_IS_PROXY | \
|
js::CheckProxyFlags<flags>(), \
|
||||||
JSCLASS_DELAY_METADATA_BUILDER | js::CheckProxyFlags<flags>(), \
|
&js::ProxyClassOps, \
|
||||||
&js::ProxyClassOps, classSpec, &js::ProxyClassExtension, \
|
classSpec, \
|
||||||
&js::ProxyObjectOps \
|
&js::ProxyClassExtension, \
|
||||||
}
|
&js::ProxyObjectOps}
|
||||||
|
|
||||||
#define PROXY_CLASS_DEF(name, flags) \
|
#define PROXY_CLASS_DEF(name, flags) \
|
||||||
PROXY_CLASS_DEF_WITH_CLASS_SPEC(name, flags, JS_NULL_CLASS_SPEC)
|
PROXY_CLASS_DEF_WITH_CLASS_SPEC(name, flags, JS_NULL_CLASS_SPEC)
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,8 @@ extern JS_PUBLIC_API JS::Handle<JSObject*> GetRealmObjectPrototypeHandle(
|
||||||
JSContext* cx);
|
JSContext* cx);
|
||||||
|
|
||||||
extern JS_PUBLIC_API JSObject* GetRealmFunctionPrototype(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);
|
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);
|
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
|
} // namespace JS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,12 @@ class JS_PUBLIC_API RealmCreationOptions {
|
||||||
|
|
||||||
// Determines whether this realm should preserve JIT code on non-shrinking
|
// Determines whether this realm should preserve JIT code on non-shrinking
|
||||||
// GCs.
|
// 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_; }
|
bool preserveJitCode() const { return preserveJitCode_; }
|
||||||
RealmCreationOptions& setPreserveJitCode(bool flag) {
|
RealmCreationOptions& setPreserveJitCode(bool flag) {
|
||||||
preserveJitCode_ = flag;
|
preserveJitCode_ = flag;
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,7 @@
|
||||||
|
|
||||||
// These types implement the same interface as mozilla::(Atomic)RefCounted and
|
// These types implement the same interface as mozilla::(Atomic)RefCounted and
|
||||||
// must be used instead of mozilla::(Atomic)RefCounted for everything in
|
// must be used instead of mozilla::(Atomic)RefCounted for everything in
|
||||||
// SpiderMonkey. There are two reasons:
|
// SpiderMonkey. This is because Release() needs to call js_delete, not delete.
|
||||||
// - 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).
|
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ class RegExpFlags {
|
||||||
using Flag = uint8_t;
|
using Flag = uint8_t;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Flag flags_;
|
Flag flags_ = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RegExpFlags() = default;
|
RegExpFlags() = default;
|
||||||
|
|
@ -159,7 +159,7 @@ inline RegExpFlags& operator^=(RegExpFlags& flags, RegExpFlags::Flag flag) {
|
||||||
inline RegExpFlags operator&(const RegExpFlags& lhs, const RegExpFlags& rhs) {
|
inline RegExpFlags operator&(const RegExpFlags& lhs, const RegExpFlags& rhs) {
|
||||||
RegExpFlags result = lhs;
|
RegExpFlags result = lhs;
|
||||||
result &= rhs;
|
result &= rhs;
|
||||||
return lhs;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline RegExpFlags operator|(const RegExpFlags& lhs, const RegExpFlags& rhs) {
|
inline RegExpFlags operator|(const RegExpFlags& lhs, const RegExpFlags& rhs) {
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "mozilla/LinkedList.h"
|
#include "mozilla/LinkedList.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
|
@ -23,10 +24,10 @@
|
||||||
#include "js/GCPolicyAPI.h"
|
#include "js/GCPolicyAPI.h"
|
||||||
#include "js/GCTypeMacros.h" // JS_FOR_EACH_PUBLIC_{,TAGGED_}GC_POINTER_TYPE
|
#include "js/GCTypeMacros.h" // JS_FOR_EACH_PUBLIC_{,TAGGED_}GC_POINTER_TYPE
|
||||||
#include "js/HashTable.h"
|
#include "js/HashTable.h"
|
||||||
#include "js/HeapAPI.h" // StackKindCount
|
#include "js/HeapAPI.h" // StackKindCount
|
||||||
|
#include "js/NativeStackLimits.h" // JS::NativeStackLimit
|
||||||
#include "js/ProfilingStack.h"
|
#include "js/ProfilingStack.h"
|
||||||
#include "js/Realm.h"
|
#include "js/Realm.h"
|
||||||
#include "js/Stack.h" // JS::NativeStackLimit
|
|
||||||
#include "js/TypeDecls.h"
|
#include "js/TypeDecls.h"
|
||||||
#include "js/UniquePtr.h"
|
#include "js/UniquePtr.h"
|
||||||
|
|
||||||
|
|
@ -172,18 +173,18 @@ struct Cell;
|
||||||
// Assignment operators on a base class are hidden by the implicitly defined
|
// Assignment operators on a base class are hidden by the implicitly defined
|
||||||
// operator= on the derived class. Thus, define the operator= directly on the
|
// operator= on the derived class. Thus, define the operator= directly on the
|
||||||
// class as we would need to manually pass it through anyway.
|
// class as we would need to manually pass it through anyway.
|
||||||
#define DECLARE_POINTER_ASSIGN_OPS(Wrapper, T) \
|
#define DECLARE_POINTER_ASSIGN_OPS(Wrapper, T) \
|
||||||
Wrapper<T>& operator=(const T& p) { \
|
Wrapper& operator=(const T& p) { \
|
||||||
set(p); \
|
set(p); \
|
||||||
return *this; \
|
return *this; \
|
||||||
} \
|
} \
|
||||||
Wrapper<T>& operator=(T&& p) { \
|
Wrapper& operator=(T&& p) { \
|
||||||
set(std::move(p)); \
|
set(std::move(p)); \
|
||||||
return *this; \
|
return *this; \
|
||||||
} \
|
} \
|
||||||
Wrapper<T>& operator=(const Wrapper<T>& other) { \
|
Wrapper& operator=(const Wrapper& other) { \
|
||||||
set(other.get()); \
|
set(other.get()); \
|
||||||
return *this; \
|
return *this; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DELETE_ASSIGNMENT_OPS(Wrapper, T) \
|
#define DELETE_ASSIGNMENT_OPS(Wrapper, T) \
|
||||||
|
|
@ -205,11 +206,6 @@ namespace JS {
|
||||||
|
|
||||||
JS_PUBLIC_API void HeapObjectPostWriteBarrier(JSObject** objp, JSObject* prev,
|
JS_PUBLIC_API void HeapObjectPostWriteBarrier(JSObject** objp, JSObject* prev,
|
||||||
JSObject* next);
|
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,
|
JS_PUBLIC_API void HeapObjectWriteBarriers(JSObject** objp, JSObject* prev,
|
||||||
JSObject* next);
|
JSObject* next);
|
||||||
JS_PUBLIC_API void HeapStringWriteBarriers(JSString** objp, JSString* prev,
|
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
|
// doesn't offer a type trait indicating whether a class's constructor is
|
||||||
// user-defined, which better approximates our desired semantics.)
|
// user-defined, which better approximates our desired semantics.)
|
||||||
constexpr bool IsNonTriviallyDefaultConstructibleClassOrUnion =
|
constexpr bool IsNonTriviallyDefaultConstructibleClassOrUnion =
|
||||||
(std::is_class_v<T> ||
|
(std::is_class_v<T> || std::is_union_v<T>) &&
|
||||||
std::is_union_v<T>)&&!std::is_trivially_default_constructible_v<T>;
|
!std::is_trivially_default_constructible_v<T>;
|
||||||
|
|
||||||
static_assert(IsPointer || IsNonTriviallyDefaultConstructibleClassOrUnion,
|
static_assert(IsPointer || IsNonTriviallyDefaultConstructibleClassOrUnion,
|
||||||
"T() must evaluate to a safely-initialized T");
|
"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:
|
* Heap<T> implements the following barriers:
|
||||||
*
|
*
|
||||||
|
* - Pre-write barrier (necessary for incremental GC).
|
||||||
* - Post-write barrier (necessary for generational GC).
|
* - Post-write barrier (necessary for generational GC).
|
||||||
* - Read barrier (necessary for incremental GC and cycle collector
|
* - Read barrier (necessary for cycle collector integration).
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* Heap<T> may be moved or destroyed outside of GC finalization and hence may be
|
* Heap<T> may be moved or destroyed outside of GC finalization and hence may be
|
||||||
* used in dynamic storage such as a Vector.
|
* used in dynamic storage such as a Vector.
|
||||||
|
|
@ -302,8 +294,6 @@ inline void AssertGCThingIsNotNurseryAllocable(js::gc::Cell* cell) {}
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class MOZ_NON_MEMMOVABLE Heap : public js::HeapOperations<T, Heap<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,
|
static_assert(js::IsHeapConstructibleType<T>::value,
|
||||||
"Type T must be a public GC pointer type");
|
"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.");
|
"Heap<T> must be binary compatible with T.");
|
||||||
}
|
}
|
||||||
explicit Heap(const T& p) : ptr(p) {
|
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
|
* breaks common usage of move semantics, so we need to define both, even
|
||||||
* though they are equivalent.
|
* though they are equivalent.
|
||||||
*/
|
*/
|
||||||
explicit Heap(const Heap<T>& other) : ptr(other.getWithoutExpose()) {
|
explicit Heap(const Heap<T>& other) : ptr(other.unbarrieredGet()) {
|
||||||
postWriteBarrier(SafelyInitialized<T>::create(), ptr);
|
writeBarriers(SafelyInitialized<T>::create(), ptr);
|
||||||
}
|
}
|
||||||
Heap(Heap<T>&& other) : ptr(other.getWithoutExpose()) {
|
Heap(Heap<T>&& other) : ptr(other.unbarrieredGet()) {
|
||||||
postWriteBarrier(SafelyInitialized<T>::create(), ptr);
|
writeBarriers(SafelyInitialized<T>::create(), ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Heap& operator=(Heap<T>&& other) {
|
Heap& operator=(Heap<T>&& other) {
|
||||||
set(other.getWithoutExpose());
|
set(other.unbarrieredGet());
|
||||||
other.set(SafelyInitialized<T>::create());
|
other.set(SafelyInitialized<T>::create());
|
||||||
return *this;
|
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_CONSTREF_OPS(T);
|
||||||
DECLARE_POINTER_ASSIGN_OPS(Heap, T);
|
DECLARE_POINTER_ASSIGN_OPS(Heap<T>, T);
|
||||||
|
|
||||||
const T* address() const { return &ptr; }
|
|
||||||
|
|
||||||
void exposeToActiveJS() const { js::BarrierMethods<T>::exposeToJS(ptr); }
|
void exposeToActiveJS() const { js::BarrierMethods<T>::exposeToJS(ptr); }
|
||||||
|
|
||||||
|
|
@ -351,32 +340,25 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapOperations<T, Heap<T>> {
|
||||||
exposeToActiveJS();
|
exposeToActiveJS();
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
const T& getWithoutExpose() const {
|
|
||||||
js::BarrierMethods<T>::readBarrier(ptr);
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
const T& unbarrieredGet() const { return ptr; }
|
const T& unbarrieredGet() const { return ptr; }
|
||||||
|
|
||||||
void set(const T& newPtr) {
|
void set(const T& newPtr) {
|
||||||
T tmp = ptr;
|
T tmp = ptr;
|
||||||
ptr = newPtr;
|
ptr = newPtr;
|
||||||
postWriteBarrier(tmp, ptr);
|
writeBarriers(tmp, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
T* unsafeGet() { return &ptr; }
|
|
||||||
|
|
||||||
void unbarrieredSet(const T& newPtr) { ptr = newPtr; }
|
void unbarrieredSet(const T& newPtr) { ptr = newPtr; }
|
||||||
|
|
||||||
|
T* unsafeAddress() { return &ptr; }
|
||||||
|
const T* unsafeAddress() const { return &ptr; }
|
||||||
|
|
||||||
explicit operator bool() const {
|
explicit operator bool() const {
|
||||||
return bool(js::BarrierMethods<T>::asGCThingOrNull(ptr));
|
return bool(js::BarrierMethods<T>::asGCThingOrNull(ptr));
|
||||||
}
|
}
|
||||||
explicit operator bool() {
|
|
||||||
return bool(js::BarrierMethods<T>::asGCThingOrNull(ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void postWriteBarrier(const T& prev, const T& next) {
|
void writeBarriers(const T& prev, const T& next) {
|
||||||
js::BarrierMethods<T>::postWriteBarrier(&ptr, prev, next);
|
js::BarrierMethods<T>::writeBarriers(&ptr, prev, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
T ptr;
|
T ptr;
|
||||||
|
|
@ -448,7 +430,7 @@ inline void AssertObjectIsNotGray(const JS::Heap<JSObject*>& obj) {}
|
||||||
* it has two important differences:
|
* it has two important differences:
|
||||||
*
|
*
|
||||||
* 1) Pointers which are statically known to only reference "tenured" objects
|
* 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
|
* 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
|
* 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>
|
template <typename T>
|
||||||
class TenuredHeap : public js::HeapOperations<T, TenuredHeap<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:
|
public:
|
||||||
using ElementType = T;
|
using ElementType = T;
|
||||||
|
|
||||||
|
|
@ -480,12 +465,29 @@ class TenuredHeap : public js::HeapOperations<T, TenuredHeap<T>> {
|
||||||
static_assert(sizeof(T) == sizeof(TenuredHeap<T>),
|
static_assert(sizeof(T) == sizeof(TenuredHeap<T>),
|
||||||
"TenuredHeap<T> must be binary compatible with 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) {
|
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) {
|
void setPtr(T newPtr) {
|
||||||
|
preWriteBarrier();
|
||||||
|
unbarrieredSetPtr(newPtr);
|
||||||
|
}
|
||||||
|
void unbarrieredSetPtr(T newPtr) {
|
||||||
MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0);
|
MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0);
|
||||||
MOZ_ASSERT(js::gc::IsCellPointerValidOrNull(newPtr));
|
MOZ_ASSERT(js::gc::IsCellPointerValidOrNull(newPtr));
|
||||||
if (newPtr) {
|
if (newPtr) {
|
||||||
|
|
@ -526,19 +528,6 @@ class TenuredHeap : public js::HeapOperations<T, TenuredHeap<T>> {
|
||||||
explicit operator bool() const {
|
explicit operator bool() const {
|
||||||
return bool(js::BarrierMethods<T>::asGCThingOrNull(unbarrieredGetPtr()));
|
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:
|
private:
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -546,6 +535,12 @@ class TenuredHeap : public js::HeapOperations<T, TenuredHeap<T>> {
|
||||||
flagsMask = (1 << maskBits) - 1,
|
flagsMask = (1 << maskBits) - 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void preWriteBarrier() {
|
||||||
|
if (T prev = unbarrieredGetPtr()) {
|
||||||
|
JS::IncrementalPreWriteBarrier(JS::GCCellPtr(prev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uintptr_t bits;
|
uintptr_t bits;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -583,6 +578,8 @@ template <typename T>
|
||||||
class MutableHandle;
|
class MutableHandle;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Rooted;
|
class Rooted;
|
||||||
|
template <typename T, size_t N = SIZE_MAX>
|
||||||
|
class RootedField;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class PersistentRooted;
|
class PersistentRooted;
|
||||||
|
|
||||||
|
|
@ -662,6 +659,11 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleOperations<T, Handle<T>> {
|
||||||
MutableHandle<S>& root,
|
MutableHandle<S>& root,
|
||||||
std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0);
|
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_POINTER_CONSTREF_OPS(T);
|
||||||
DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
|
DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
|
||||||
|
|
||||||
|
|
@ -700,6 +702,8 @@ class MOZ_STACK_CLASS MutableHandle
|
||||||
using ElementType = T;
|
using ElementType = T;
|
||||||
|
|
||||||
inline MOZ_IMPLICIT MutableHandle(Rooted<T>* root);
|
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);
|
inline MOZ_IMPLICIT MutableHandle(PersistentRooted<T>* root);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -783,7 +787,10 @@ struct PtrBarrierMethodsBase {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct BarrierMethods<T*> : public detail::PtrBarrierMethodsBase<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) {
|
if (next) {
|
||||||
JS::AssertGCThingIsNotNurseryAllocable(
|
JS::AssertGCThingIsNotNurseryAllocable(
|
||||||
reinterpret_cast<js::gc::Cell*>(next));
|
reinterpret_cast<js::gc::Cell*>(next));
|
||||||
|
|
@ -794,6 +801,9 @@ struct BarrierMethods<T*> : public detail::PtrBarrierMethodsBase<T> {
|
||||||
template <>
|
template <>
|
||||||
struct BarrierMethods<JSObject*>
|
struct BarrierMethods<JSObject*>
|
||||||
: public detail::PtrBarrierMethodsBase<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) {
|
static void postWriteBarrier(JSObject** vp, JSObject* prev, JSObject* next) {
|
||||||
JS::HeapObjectPostWriteBarrier(vp, prev, next);
|
JS::HeapObjectPostWriteBarrier(vp, prev, next);
|
||||||
}
|
}
|
||||||
|
|
@ -807,11 +817,11 @@ struct BarrierMethods<JSObject*>
|
||||||
template <>
|
template <>
|
||||||
struct BarrierMethods<JSFunction*>
|
struct BarrierMethods<JSFunction*>
|
||||||
: public detail::PtrBarrierMethodsBase<JSFunction> {
|
: public detail::PtrBarrierMethodsBase<JSFunction> {
|
||||||
static void postWriteBarrier(JSFunction** vp, JSFunction* prev,
|
static void writeBarriers(JSFunction** vp, JSFunction* prev,
|
||||||
JSFunction* next) {
|
JSFunction* next) {
|
||||||
JS::HeapObjectPostWriteBarrier(reinterpret_cast<JSObject**>(vp),
|
JS::HeapObjectWriteBarriers(reinterpret_cast<JSObject**>(vp),
|
||||||
reinterpret_cast<JSObject*>(prev),
|
reinterpret_cast<JSObject*>(prev),
|
||||||
reinterpret_cast<JSObject*>(next));
|
reinterpret_cast<JSObject*>(next));
|
||||||
}
|
}
|
||||||
static void exposeToJS(JSFunction* fun) {
|
static void exposeToJS(JSFunction* fun) {
|
||||||
if (fun) {
|
if (fun) {
|
||||||
|
|
@ -823,17 +833,25 @@ struct BarrierMethods<JSFunction*>
|
||||||
template <>
|
template <>
|
||||||
struct BarrierMethods<JSString*>
|
struct BarrierMethods<JSString*>
|
||||||
: public detail::PtrBarrierMethodsBase<JSString> {
|
: public detail::PtrBarrierMethodsBase<JSString> {
|
||||||
static void postWriteBarrier(JSString** vp, JSString* prev, JSString* next) {
|
static void writeBarriers(JSString** vp, JSString* prev, JSString* next) {
|
||||||
JS::HeapStringPostWriteBarrier(vp, prev, 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 <>
|
template <>
|
||||||
struct BarrierMethods<JS::BigInt*>
|
struct BarrierMethods<JS::BigInt*>
|
||||||
: public detail::PtrBarrierMethodsBase<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::BigInt* next) {
|
||||||
JS::HeapBigIntPostWriteBarrier(vp, prev, next);
|
JS::HeapBigIntWriteBarriers(vp, prev, next);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1145,11 +1163,19 @@ using RootedTraits =
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class MOZ_RAII Rooted : public detail::RootedTraits<T>::StackBase,
|
class MOZ_RAII Rooted : public detail::RootedTraits<T>::StackBase,
|
||||||
public js::RootedOperations<T, Rooted<T>> {
|
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) {
|
inline void registerWithRootLists(RootedListHeads& roots) {
|
||||||
this->stack = &roots[JS::MapTypeToRootKind<T>::kind];
|
this->stack = &roots[JS::MapTypeToRootKind<T>::kind];
|
||||||
this->prev = *this->stack;
|
this->prev = *this->stack;
|
||||||
*this->stack = this;
|
*this->stack = this;
|
||||||
}
|
}
|
||||||
|
#if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 12)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
inline RootedListHeads& rootLists(RootingContext* cx) {
|
inline RootedListHeads& rootLists(RootingContext* cx) {
|
||||||
return cx->stackRoots_;
|
return cx->stackRoots_;
|
||||||
|
|
@ -1220,7 +1246,7 @@ class MOZ_RAII Rooted : public detail::RootedTraits<T>::StackBase,
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_POINTER_CONSTREF_OPS(T);
|
DECLARE_POINTER_CONSTREF_OPS(T);
|
||||||
DECLARE_POINTER_ASSIGN_OPS(Rooted, T);
|
DECLARE_POINTER_ASSIGN_OPS(Rooted<T>, T);
|
||||||
|
|
||||||
T& get() { return ptr; }
|
T& get() { return ptr; }
|
||||||
const T& get() const { return ptr; }
|
const T& get() const { return ptr; }
|
||||||
|
|
@ -1243,6 +1269,86 @@ struct DefineComparisonOps<Rooted<T>> : std::true_type {
|
||||||
|
|
||||||
} // namespace detail
|
} // 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 */
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
@ -1342,6 +1448,14 @@ inline Handle<T>::Handle(
|
||||||
ptr = reinterpret_cast<const T*>(root.address());
|
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>
|
template <typename T>
|
||||||
inline MutableHandle<T>::MutableHandle(Rooted<T>* root) {
|
inline MutableHandle<T>::MutableHandle(Rooted<T>* root) {
|
||||||
static_assert(sizeof(MutableHandle<T>) == sizeof(T*),
|
static_assert(sizeof(MutableHandle<T>) == sizeof(T*),
|
||||||
|
|
@ -1349,6 +1463,12 @@ inline MutableHandle<T>::MutableHandle(Rooted<T>* root) {
|
||||||
ptr = root->address();
|
ptr = root->address();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
template <size_t N>
|
||||||
|
inline MutableHandle<T>::MutableHandle(RootedField<T, N>* rootedField) {
|
||||||
|
ptr = rootedField->ptr;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline MutableHandle<T>::MutableHandle(PersistentRooted<T>* root) {
|
inline MutableHandle<T>::MutableHandle(PersistentRooted<T>* root) {
|
||||||
static_assert(sizeof(MutableHandle<T>) == sizeof(T*),
|
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_CONSTREF_OPS(T);
|
||||||
DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T);
|
DECLARE_POINTER_ASSIGN_OPS(PersistentRooted<T>, T);
|
||||||
|
|
||||||
T& get() { return ptr; }
|
T& get() { return ptr; }
|
||||||
const T& get() const { return ptr; }
|
const T& get() const { return ptr; }
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
#include "jstypes.h"
|
#include "jstypes.h"
|
||||||
|
|
||||||
namespace js {
|
namespace JS {
|
||||||
|
|
||||||
struct JS_PUBLIC_API TimeBudget {
|
struct JS_PUBLIC_API TimeBudget {
|
||||||
const mozilla::TimeDuration budget;
|
const mozilla::TimeDuration budget;
|
||||||
|
|
@ -140,6 +140,6 @@ class JS_PUBLIC_API SliceBudget {
|
||||||
int describe(char* buffer, size_t maxlen) const;
|
int describe(char* buffer, size_t maxlen) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace js
|
} // namespace JS
|
||||||
|
|
||||||
#endif /* js_SliceBudget_h */
|
#endif /* js_SliceBudget_h */
|
||||||
|
|
|
||||||
|
|
@ -17,44 +17,9 @@
|
||||||
|
|
||||||
#include "jstypes.h" // JS_PUBLIC_API
|
#include "jstypes.h" // JS_PUBLIC_API
|
||||||
|
|
||||||
|
#include "js/NativeStackLimits.h"
|
||||||
#include "js/Principals.h" // JSPrincipals, JS_HoldPrincipals, JS_DropPrincipals
|
#include "js/Principals.h" // JSPrincipals, JS_HoldPrincipals, JS_DropPrincipals
|
||||||
#include "js/TypeDecls.h" // JSContext, Handle*, MutableHandle*
|
#include "js/RootingAPI.h"
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the size of the native stack that should not be exceed. To disable
|
* 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(
|
extern JS_PUBLIC_API bool CaptureCurrentStack(
|
||||||
JSContext* cx, MutableHandleObject stackp,
|
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
|
* Returns true if capturing stack trace data to associate with an asynchronous
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,15 @@
|
||||||
|
|
||||||
#include "js/shadow/String.h" // JS::shadow::String
|
#include "js/shadow/String.h" // JS::shadow::String
|
||||||
|
|
||||||
#include "mozilla/Assertions.h" // MOZ_ASSERT
|
#include "mozilla/Assertions.h" // MOZ_ASSERT
|
||||||
#include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE
|
#include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE
|
||||||
#include "mozilla/Likely.h" // MOZ_LIKELY
|
#include "mozilla/Likely.h" // MOZ_LIKELY
|
||||||
#include "mozilla/Maybe.h" // mozilla::Maybe
|
#include "mozilla/Maybe.h" // mozilla::Maybe
|
||||||
#include "mozilla/Range.h" // mozilla::Range
|
#include "mozilla/Range.h" // mozilla::Range
|
||||||
#include "mozilla/Span.h" // mozilla::Span
|
#include "mozilla/RefPtr.h" // RefPtr
|
||||||
// std::tuple
|
#include "mozilla/Span.h" // mozilla::Span
|
||||||
|
// std::tuple
|
||||||
|
#include "mozilla/StringBuffer.h" // mozilla::StringBuffer
|
||||||
|
|
||||||
#include <algorithm> // std::copy_n
|
#include <algorithm> // std::copy_n
|
||||||
#include <stddef.h> // size_t
|
#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,
|
extern JS_PUBLIC_API JSString* JS_NewUCStringCopyZ(JSContext* cx,
|
||||||
const char16_t* s);
|
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,
|
extern JS_PUBLIC_API JSString* JS_AtomizeUCStringN(JSContext* cx,
|
||||||
const char16_t* s,
|
const char16_t* s,
|
||||||
size_t length);
|
size_t length);
|
||||||
|
|
@ -430,6 +489,46 @@ MOZ_ALWAYS_INLINE bool IsExternalUCString(
|
||||||
return true;
|
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 {
|
namespace detail {
|
||||||
|
|
||||||
extern JS_PUBLIC_API JSLinearString* StringToLinearStringSlow(JSContext* cx,
|
extern JS_PUBLIC_API JSLinearString* StringToLinearStringSlow(JSContext* cx,
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/BufferList.h"
|
#include "mozilla/BufferList.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
|
#include "mozilla/StringBuffer.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
@ -154,6 +155,13 @@ enum class StructuredCloneScope : uint32_t {
|
||||||
*/
|
*/
|
||||||
DifferentProcess,
|
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
|
* Handle a backwards-compatibility case with IndexedDB (bug 1434308): when
|
||||||
* reading, this means to treat legacy SameProcess data as if it were
|
* 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
|
* 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
|
* read() hook will *not* be called for the same object, since the main data
|
||||||
* will only contain a backreference to the already-read object.
|
* 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)(
|
typedef bool (*ReadTransferStructuredCloneOp)(
|
||||||
JSContext* cx, JSStructuredCloneReader* r,
|
JSContext* cx, JSStructuredCloneReader* r,
|
||||||
|
|
@ -351,11 +364,13 @@ typedef bool (*TransferStructuredCloneOp)(JSContext* cx,
|
||||||
* encountered later and the incomplete serialization is discarded.
|
* encountered later and the incomplete serialization is discarded.
|
||||||
*
|
*
|
||||||
* 2. During deserialization: before an object is Transferred to, an error
|
* 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
|
* 3. Serialized data that includes Transferring is never deserialized (eg when
|
||||||
* the receiver disappears before reading in the message), and the clone data
|
* the receiver disappears before reading in the message), and the clone data
|
||||||
* is destroyed.
|
* is destroyed.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
typedef void (*FreeTransferStructuredCloneOp)(
|
typedef void (*FreeTransferStructuredCloneOp)(
|
||||||
|
|
@ -469,6 +484,10 @@ class MOZ_NON_MEMMOVABLE JS_PUBLIC_API JSStructuredCloneData {
|
||||||
OwnTransferablePolicy::NoTransferables;
|
OwnTransferablePolicy::NoTransferables;
|
||||||
js::SharedArrayRawBufferRefs refsHeld_;
|
js::SharedArrayRawBufferRefs refsHeld_;
|
||||||
|
|
||||||
|
using StringBuffers =
|
||||||
|
js::Vector<RefPtr<mozilla::StringBuffer>, 4, js::SystemAllocPolicy>;
|
||||||
|
StringBuffers stringBufferRefsHeld_;
|
||||||
|
|
||||||
friend struct JSStructuredCloneWriter;
|
friend struct JSStructuredCloneWriter;
|
||||||
friend class JS_PUBLIC_API JSAutoStructuredCloneBuffer;
|
friend class JS_PUBLIC_API JSAutoStructuredCloneBuffer;
|
||||||
template <typename T, typename AllocPolicy>
|
template <typename T, typename AllocPolicy>
|
||||||
|
|
|
||||||
|
|
@ -49,21 +49,22 @@ extern JS_PUBLIC_API Symbol* GetSymbolFor(JSContext* cx, Handle<JSString*> key);
|
||||||
extern JS_PUBLIC_API JSString* GetSymbolDescription(Handle<Symbol*> symbol);
|
extern JS_PUBLIC_API JSString* GetSymbolDescription(Handle<Symbol*> symbol);
|
||||||
|
|
||||||
/* Well-known symbols. */
|
/* Well-known symbols. */
|
||||||
#define JS_FOR_EACH_WELL_KNOWN_SYMBOL(MACRO) \
|
#define JS_FOR_EACH_WELL_KNOWN_SYMBOL(MACRO) \
|
||||||
MACRO(isConcatSpreadable) \
|
MACRO(isConcatSpreadable) \
|
||||||
MACRO(iterator) \
|
MACRO(iterator) \
|
||||||
MACRO(match) \
|
MACRO(match) \
|
||||||
MACRO(replace) \
|
MACRO(replace) \
|
||||||
MACRO(search) \
|
MACRO(search) \
|
||||||
MACRO(species) \
|
MACRO(species) \
|
||||||
MACRO(hasInstance) \
|
MACRO(hasInstance) \
|
||||||
MACRO(split) \
|
MACRO(split) \
|
||||||
MACRO(toPrimitive) \
|
MACRO(toPrimitive) \
|
||||||
MACRO(toStringTag) \
|
MACRO(toStringTag) \
|
||||||
MACRO(unscopables) \
|
MACRO(unscopables) \
|
||||||
MACRO(asyncIterator) \
|
MACRO(asyncIterator) \
|
||||||
MACRO(matchAll) \
|
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 {
|
enum class SymbolCode : uint32_t {
|
||||||
// There is one SymbolCode for each well-known symbol.
|
// There is one SymbolCode for each well-known symbol.
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,9 @@ class PropMap;
|
||||||
class RegExpShared;
|
class RegExpShared;
|
||||||
class Shape;
|
class Shape;
|
||||||
class Scope;
|
class Scope;
|
||||||
|
namespace gc {
|
||||||
|
class SmallBuffer;
|
||||||
|
} // namespace gc
|
||||||
namespace jit {
|
namespace jit {
|
||||||
class JitCode;
|
class JitCode;
|
||||||
} // namespace jit
|
} // namespace jit
|
||||||
|
|
@ -63,6 +66,7 @@ enum class TraceKind {
|
||||||
RegExpShared,
|
RegExpShared,
|
||||||
GetterSetter,
|
GetterSetter,
|
||||||
PropMap,
|
PropMap,
|
||||||
|
SmallBuffer
|
||||||
};
|
};
|
||||||
|
|
||||||
// GCCellPtr packs the trace kind into the low bits of the pointer for common
|
// GCCellPtr packs the trace kind into the low bits of the pointer for common
|
||||||
|
|
@ -88,20 +92,21 @@ struct MapTypeToTraceKind {
|
||||||
// also means they can be used as a keys in WeakMap.
|
// also means they can be used as a keys in WeakMap.
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#define JS_FOR_EACH_TRACEKIND(D) \
|
#define JS_FOR_EACH_TRACEKIND(D) \
|
||||||
/* name type canBeGray inCCGraph */ \
|
/* name type canBeGray inCCGraph */ \
|
||||||
D(BaseShape, js::BaseShape, true, false) \
|
D(BaseShape, js::BaseShape, true, false) \
|
||||||
D(JitCode, js::jit::JitCode, true, false) \
|
D(JitCode, js::jit::JitCode, true, false) \
|
||||||
D(Scope, js::Scope, true, true) \
|
D(Scope, js::Scope, true, true) \
|
||||||
D(Object, JSObject, true, true) \
|
D(Object, JSObject, true, true) \
|
||||||
D(Script, js::BaseScript, true, true) \
|
D(Script, js::BaseScript, true, true) \
|
||||||
D(Shape, js::Shape, true, false) \
|
D(Shape, js::Shape, true, false) \
|
||||||
D(String, JSString, false, false) \
|
D(String, JSString, false, false) \
|
||||||
D(Symbol, JS::Symbol, false, false) \
|
D(Symbol, JS::Symbol, false, false) \
|
||||||
D(BigInt, JS::BigInt, false, false) \
|
D(BigInt, JS::BigInt, false, false) \
|
||||||
D(RegExpShared, js::RegExpShared, true, true) \
|
D(RegExpShared, js::RegExpShared, true, true) \
|
||||||
D(GetterSetter, js::GetterSetter, 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
|
// clang-format on
|
||||||
|
|
||||||
// Returns true if the JS::TraceKind is represented as a node in cycle collector
|
// Returns true if the JS::TraceKind is represented as a node in cycle collector
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ enum class TracerKind {
|
||||||
UnmarkGray,
|
UnmarkGray,
|
||||||
VerifyTraceProtoAndIface,
|
VerifyTraceProtoAndIface,
|
||||||
CompartmentCheck,
|
CompartmentCheck,
|
||||||
|
HeapCheck
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class WeakMapTraceAction {
|
enum class WeakMapTraceAction {
|
||||||
|
|
@ -135,7 +136,8 @@ class TracingContext {
|
||||||
// currently set tracing context.
|
// currently set tracing context.
|
||||||
class Functor {
|
class Functor {
|
||||||
public:
|
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:
|
private:
|
||||||
|
|
@ -348,7 +350,7 @@ template <typename T>
|
||||||
inline void TraceEdge(JSTracer* trc, JS::Heap<T>* thingp, const char* name) {
|
inline void TraceEdge(JSTracer* trc, JS::Heap<T>* thingp, const char* name) {
|
||||||
MOZ_ASSERT(thingp);
|
MOZ_ASSERT(thingp);
|
||||||
if (*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);
|
MOZ_ASSERT(thingp);
|
||||||
if (T ptr = thingp->unbarrieredGetPtr()) {
|
if (T ptr = thingp->unbarrieredGetPtr()) {
|
||||||
js::gc::TraceExternalEdge(trc, &ptr, name);
|
js::gc::TraceExternalEdge(trc, &ptr, name);
|
||||||
thingp->setPtr(ptr);
|
thingp->unbarrieredSetPtr(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,15 @@
|
||||||
|
|
||||||
#include "js/TypeDecls.h"
|
#include "js/TypeDecls.h"
|
||||||
|
|
||||||
|
// Underlying opaque type.
|
||||||
|
namespace js::frontend {
|
||||||
|
struct InitialStencilAndDelazifications;
|
||||||
|
} // namespace js::frontend
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
using Stencil = js::frontend::InitialStencilAndDelazifications;
|
||||||
|
|
||||||
class JS_PUBLIC_API ReadOnlyCompileOptions;
|
class JS_PUBLIC_API ReadOnlyCompileOptions;
|
||||||
|
|
||||||
using TranscodeBuffer = mozilla::Vector<uint8_t>;
|
using TranscodeBuffer = mozilla::Vector<uint8_t>;
|
||||||
|
|
@ -79,52 +86,6 @@ inline bool IsTranscodingBytecodeAligned(const void* offset) {
|
||||||
return IsTranscodingBytecodeOffsetAligned(size_t(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.
|
// Check if the compile options and script's flag matches.
|
||||||
//
|
//
|
||||||
// JS::DecodeScript* and JS::DecodeOffThreadScript internally check this.
|
// JS::DecodeScript* and JS::DecodeOffThreadScript internally check this.
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,6 @@ typedef unsigned char Latin1Char;
|
||||||
|
|
||||||
class JS_PUBLIC_API Symbol;
|
class JS_PUBLIC_API Symbol;
|
||||||
class JS_PUBLIC_API BigInt;
|
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 Value;
|
||||||
|
|
||||||
class JS_PUBLIC_API Compartment;
|
class JS_PUBLIC_API Compartment;
|
||||||
|
|
@ -130,18 +126,6 @@ using MutableHandleVector = MutableHandle<StackGCVector<T>>;
|
||||||
|
|
||||||
using jsid = JS::PropertyKey;
|
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
|
#ifdef ENABLE_DECORATORS
|
||||||
# define IF_DECORATORS(x, ...) x
|
# define IF_DECORATORS(x, ...) x
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -1164,6 +1164,26 @@ class JS_PUBLIC_API Concrete<JSString> : TracerConcrete<JSString> {
|
||||||
static const char16_t concreteTypeName[];
|
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
|
// The ubi::Node null pointer. Any attempt to operate on a null ubi::Node
|
||||||
// asserts.
|
// asserts.
|
||||||
template <>
|
template <>
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,16 @@ extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API void JS_Assert(const char* s,
|
||||||
# include "jscustomallocator.h"
|
# include "jscustomallocator.h"
|
||||||
#else
|
#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 {
|
namespace js {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -54,20 +64,22 @@ namespace js {
|
||||||
* adding new thread types.
|
* adding new thread types.
|
||||||
*/
|
*/
|
||||||
enum ThreadType {
|
enum ThreadType {
|
||||||
THREAD_TYPE_NONE = 0, // 0
|
THREAD_TYPE_NONE = 0, // 0
|
||||||
THREAD_TYPE_MAIN, // 1
|
THREAD_TYPE_MAIN, // 1
|
||||||
THREAD_TYPE_WASM_COMPILE_TIER1, // 2
|
THREAD_TYPE_WASM_COMPILE_TIER1, // 2
|
||||||
THREAD_TYPE_WASM_COMPILE_TIER2, // 3
|
THREAD_TYPE_WASM_COMPILE_TIER2, // 3
|
||||||
THREAD_TYPE_ION, // 4
|
THREAD_TYPE_BASELINE, // 4
|
||||||
THREAD_TYPE_COMPRESS, // 5
|
THREAD_TYPE_ION, // 5
|
||||||
THREAD_TYPE_GCPARALLEL, // 6
|
THREAD_TYPE_COMPRESS, // 6
|
||||||
THREAD_TYPE_PROMISE_TASK, // 7
|
THREAD_TYPE_GCPARALLEL, // 7
|
||||||
THREAD_TYPE_ION_FREE, // 8
|
THREAD_TYPE_PROMISE_TASK, // 8
|
||||||
THREAD_TYPE_WASM_GENERATOR_TIER2, // 9
|
THREAD_TYPE_ION_FREE, // 9
|
||||||
THREAD_TYPE_WORKER, // 10
|
THREAD_TYPE_WASM_GENERATOR_COMPLETE_TIER2, // 10
|
||||||
THREAD_TYPE_DELAZIFY, // 11
|
THREAD_TYPE_WASM_COMPILE_PARTIAL_TIER2, // 11
|
||||||
THREAD_TYPE_DELAZIFY_FREE, // 12
|
THREAD_TYPE_WORKER, // 12
|
||||||
THREAD_TYPE_MAX // Used to check shell function arguments
|
THREAD_TYPE_DELAZIFY, // 13
|
||||||
|
THREAD_TYPE_DELAZIFY_FREE, // 14
|
||||||
|
THREAD_TYPE_MAX // Used to check shell function arguments
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace oom {
|
namespace oom {
|
||||||
|
|
@ -86,7 +98,7 @@ namespace oom {
|
||||||
// Define the range of threads tested by simulated OOM testing and the
|
// Define the range of threads tested by simulated OOM testing and the
|
||||||
// like. Testing worker threads is not supported.
|
// like. Testing worker threads is not supported.
|
||||||
const ThreadType FirstThreadTypeToTest = THREAD_TYPE_MAIN;
|
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 bool InitThreadType(void);
|
||||||
extern void SetThreadType(ThreadType);
|
extern void SetThreadType(ThreadType);
|
||||||
|
|
@ -95,7 +107,7 @@ extern JS_PUBLIC_API uint32_t GetThreadType(void);
|
||||||
# else
|
# else
|
||||||
|
|
||||||
inline bool InitThreadType(void) { return true; }
|
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 GetThreadType(void) { return 0; }
|
||||||
inline uint32_t GetAllocationThreadType(void) { return 0; }
|
inline uint32_t GetAllocationThreadType(void) { return 0; }
|
||||||
inline uint32_t GetStackCheckThreadType(void) { return 0; }
|
inline uint32_t GetStackCheckThreadType(void) { return 0; }
|
||||||
|
|
@ -352,7 +364,21 @@ struct MOZ_RAII JS_PUBLIC_DATA AutoEnterOOMUnsafeRegion {
|
||||||
|
|
||||||
namespace js {
|
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 MallocArena;
|
||||||
|
extern JS_PUBLIC_DATA arena_id_t BackgroundMallocArena;
|
||||||
|
|
||||||
extern JS_PUBLIC_DATA arena_id_t ArrayBufferContentsArena;
|
extern JS_PUBLIC_DATA arena_id_t ArrayBufferContentsArena;
|
||||||
extern JS_PUBLIC_DATA arena_id_t StringBufferArena;
|
extern JS_PUBLIC_DATA arena_id_t StringBufferArena;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -170,9 +170,6 @@ enum JSValueType : uint8_t {
|
||||||
JSVAL_TYPE_SYMBOL = 0x07,
|
JSVAL_TYPE_SYMBOL = 0x07,
|
||||||
JSVAL_TYPE_PRIVATE_GCTHING = 0x08,
|
JSVAL_TYPE_PRIVATE_GCTHING = 0x08,
|
||||||
JSVAL_TYPE_BIGINT = 0x09,
|
JSVAL_TYPE_BIGINT = 0x09,
|
||||||
#ifdef ENABLE_RECORD_TUPLE
|
|
||||||
JSVAL_TYPE_EXTENDED_PRIMITIVE = 0x0b,
|
|
||||||
#endif
|
|
||||||
JSVAL_TYPE_OBJECT = 0x0c,
|
JSVAL_TYPE_OBJECT = 0x0c,
|
||||||
|
|
||||||
// This type never appears in a Value; it's only an out-of-band value.
|
// 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,
|
Symbol = JSVAL_TYPE_SYMBOL,
|
||||||
PrivateGCThing = JSVAL_TYPE_PRIVATE_GCTHING,
|
PrivateGCThing = JSVAL_TYPE_PRIVATE_GCTHING,
|
||||||
BigInt = JSVAL_TYPE_BIGINT,
|
BigInt = JSVAL_TYPE_BIGINT,
|
||||||
#ifdef ENABLE_RECORD_TUPLE
|
|
||||||
ExtendedPrimitive = JSVAL_TYPE_EXTENDED_PRIMITIVE,
|
|
||||||
#endif
|
|
||||||
Object = JSVAL_TYPE_OBJECT,
|
Object = JSVAL_TYPE_OBJECT,
|
||||||
};
|
};
|
||||||
} // namespace JS
|
} // namespace JS
|
||||||
|
|
@ -214,10 +208,6 @@ enum JSValueTag : uint32_t {
|
||||||
JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
|
JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
|
||||||
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING,
|
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING,
|
||||||
JSVAL_TAG_BIGINT = JSVAL_TAG_CLEAR | JSVAL_TYPE_BIGINT,
|
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
|
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_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
|
||||||
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING,
|
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING,
|
||||||
JSVAL_TAG_BIGINT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BIGINT,
|
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
|
JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -262,10 +248,6 @@ enum JSValueShiftedTag : uint64_t {
|
||||||
JSVAL_SHIFTED_TAG_PRIVATE_GCTHING =
|
JSVAL_SHIFTED_TAG_PRIVATE_GCTHING =
|
||||||
(uint64_t(JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT),
|
(uint64_t(JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT),
|
||||||
JSVAL_SHIFTED_TAG_BIGINT = (uint64_t(JSVAL_TAG_BIGINT) << 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)
|
JSVAL_SHIFTED_TAG_OBJECT = (uint64_t(JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -403,14 +385,7 @@ class JS_PUBLIC_API GenericPrinter;
|
||||||
class JSONPrinter;
|
class JSONPrinter;
|
||||||
|
|
||||||
static inline JS::Value PoisonedObjectValue(uintptr_t poison);
|
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
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
@ -631,23 +606,10 @@ class alignas(8) Value {
|
||||||
|
|
||||||
void setObject(JSObject& obj) {
|
void setObject(JSObject& obj) {
|
||||||
MOZ_ASSERT(js::gc::IsCellPointerValid(&obj));
|
MOZ_ASSERT(js::gc::IsCellPointerValid(&obj));
|
||||||
#ifdef ENABLE_RECORD_TUPLE
|
|
||||||
MOZ_ASSERT(!js::gc::MaybeForwardedIsExtendedPrimitive(obj));
|
|
||||||
#endif
|
|
||||||
setObjectNoCheck(&obj);
|
setObjectNoCheck(&obj);
|
||||||
MOZ_ASSERT(&toObject() == &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) {
|
void changeGCThingPayload(js::gc::Cell* cell) {
|
||||||
MOZ_ASSERT(js::gc::IsCellPointerValid(cell));
|
MOZ_ASSERT(js::gc::IsCellPointerValid(cell));
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
@ -813,6 +775,8 @@ class alignas(8) Value {
|
||||||
|
|
||||||
bool isDouble() const { return detail::ValueIsDouble(asBits_); }
|
bool isDouble() const { return detail::ValueIsDouble(asBits_); }
|
||||||
|
|
||||||
|
bool isNaN() const { return isDouble() && std::isnan(toDouble()); }
|
||||||
|
|
||||||
bool isNumber() const {
|
bool isNumber() const {
|
||||||
#if defined(JS_NUNBOX32)
|
#if defined(JS_NUNBOX32)
|
||||||
MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR);
|
MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR);
|
||||||
|
|
@ -837,16 +801,6 @@ class alignas(8) Value {
|
||||||
#endif
|
#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 {
|
bool isPrimitive() const {
|
||||||
#if defined(JS_NUNBOX32)
|
#if defined(JS_NUNBOX32)
|
||||||
return uint32_t(toTag()) < uint32_t(detail::ValueUpperExclPrimitiveTag);
|
return uint32_t(toTag()) < uint32_t(detail::ValueUpperExclPrimitiveTag);
|
||||||
|
|
@ -910,11 +864,6 @@ class alignas(8) Value {
|
||||||
if (MOZ_UNLIKELY(isPrivateGCThing())) {
|
if (MOZ_UNLIKELY(isPrivateGCThing())) {
|
||||||
return JS::GCThingTraceKind(toGCThing());
|
return JS::GCThingTraceKind(toGCThing());
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_RECORD_TUPLE
|
|
||||||
if (isExtendedPrimitive()) {
|
|
||||||
return JS::TraceKind::Object;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return JS::TraceKind(toTag() & 0x03);
|
return JS::TraceKind(toTag() & 0x03);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -990,24 +939,6 @@ class alignas(8) Value {
|
||||||
#endif
|
#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 {
|
js::gc::Cell* toGCThing() const {
|
||||||
MOZ_ASSERT(isGCThing());
|
MOZ_ASSERT(isGCThing());
|
||||||
#if defined(JS_NUNBOX32)
|
#if defined(JS_NUNBOX32)
|
||||||
|
|
@ -1224,14 +1155,6 @@ static inline Value ObjectValue(JSObject& obj) {
|
||||||
return v;
|
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) {
|
static inline Value MagicValue(JSWhyMagic why) {
|
||||||
Value v;
|
Value v;
|
||||||
v.setMagic(why);
|
v.setMagic(why);
|
||||||
|
|
@ -1329,6 +1252,10 @@ struct BarrierMethods<JS::Value> {
|
||||||
static gc::Cell* asGCThingOrNull(const JS::Value& v) {
|
static gc::Cell* asGCThingOrNull(const JS::Value& v) {
|
||||||
return v.isGCThing() ? v.toGCThing() : nullptr;
|
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,
|
static void postWriteBarrier(JS::Value* v, const JS::Value& prev,
|
||||||
const JS::Value& next) {
|
const JS::Value& next) {
|
||||||
JS::HeapValuePostWriteBarrier(v, prev, next);
|
JS::HeapValuePostWriteBarrier(v, prev, next);
|
||||||
|
|
@ -1370,10 +1297,6 @@ class WrappedPtrOperations<JS::Value, Wrapper> {
|
||||||
bool isSymbol() const { return value().isSymbol(); }
|
bool isSymbol() const { return value().isSymbol(); }
|
||||||
bool isBigInt() const { return value().isBigInt(); }
|
bool isBigInt() const { return value().isBigInt(); }
|
||||||
bool isObject() const { return value().isObject(); }
|
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() const { return value().isMagic(); }
|
||||||
bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
|
bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
|
||||||
bool isGCThing() const { return value().isGCThing(); }
|
bool isGCThing() const { return value().isGCThing(); }
|
||||||
|
|
@ -1393,12 +1316,6 @@ class WrappedPtrOperations<JS::Value, Wrapper> {
|
||||||
JS::BigInt* toBigInt() const { return value().toBigInt(); }
|
JS::BigInt* toBigInt() const { return value().toBigInt(); }
|
||||||
JSObject& toObject() const { return value().toObject(); }
|
JSObject& toObject() const { return value().toObject(); }
|
||||||
JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
|
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(); }
|
JS::GCCellPtr toGCCellPtr() const { return value().toGCCellPtr(); }
|
||||||
gc::Cell* toGCThing() const { return value().toGCThing(); }
|
gc::Cell* toGCThing() const { return value().toGCThing(); }
|
||||||
JS::TraceKind traceKind() const { return value().traceKind(); }
|
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 setBigInt(JS::BigInt* bi) { set(JS::BigIntValue(bi)); }
|
||||||
void setObject(JSObject& obj) { set(JS::ObjectValue(obj)); }
|
void setObject(JSObject& obj) { set(JS::ObjectValue(obj)); }
|
||||||
void setObjectOrNull(JSObject* arg) { set(JS::ObjectOrNullValue(arg)); }
|
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 setPrivate(void* ptr) { set(JS::PrivateValue(ptr)); }
|
||||||
void setPrivateUint32(uint32_t ui) { set(JS::PrivateUint32Value(ui)); }
|
void setPrivateUint32(uint32_t ui) { set(JS::PrivateUint32Value(ui)); }
|
||||||
void setPrivateGCThing(js::gc::Cell* cell) {
|
void setPrivateGCThing(js::gc::Cell* cell) {
|
||||||
|
|
@ -1481,11 +1393,8 @@ auto MapGCThingTyped(const JS::Value& val, F&& f) {
|
||||||
MOZ_ASSERT(gc::IsCellPointerValid(str));
|
MOZ_ASSERT(gc::IsCellPointerValid(str));
|
||||||
return mozilla::Some(f(str));
|
return mozilla::Some(f(str));
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_RECORD_TUPLE
|
|
||||||
case JS::ValueType::ExtendedPrimitive:
|
|
||||||
#endif
|
|
||||||
case JS::ValueType::Object: {
|
case JS::ValueType::Object: {
|
||||||
JSObject* obj = &val.getObjectPayload();
|
JSObject* obj = &val.toObject();
|
||||||
MOZ_ASSERT(gc::IsCellPointerValid(obj));
|
MOZ_ASSERT(gc::IsCellPointerValid(obj));
|
||||||
return mozilla::Some(f(obj));
|
return mozilla::Some(f(obj));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,6 @@
|
||||||
#else
|
#else
|
||||||
# define WASM_RELAXED_SIMD_ENABLED 0
|
# define WASM_RELAXED_SIMD_ENABLED 0
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_WASM_GC
|
|
||||||
# define WASM_GC_ENABLED 1
|
|
||||||
#else
|
|
||||||
# define WASM_GC_ENABLED 0
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_WASM_MEMORY64
|
#ifdef ENABLE_WASM_MEMORY64
|
||||||
# define WASM_MEMORY64_ENABLED 1
|
# define WASM_MEMORY64_ENABLED 1
|
||||||
#else
|
#else
|
||||||
|
|
@ -57,11 +52,6 @@
|
||||||
#else
|
#else
|
||||||
# define WASM_MEMORY_CONTROL_ENABLED 0
|
# define WASM_MEMORY_CONTROL_ENABLED 0
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_WASM_TAIL_CALLS
|
|
||||||
# define WASM_TAIL_CALLS_ENABLED 1
|
|
||||||
#else
|
|
||||||
# define WASM_TAIL_CALLS_ENABLED 0
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_WASM_JSPI
|
#ifdef ENABLE_WASM_JSPI
|
||||||
# define WASM_JSPI_ENABLED 1
|
# define WASM_JSPI_ENABLED 1
|
||||||
#else
|
#else
|
||||||
|
|
@ -99,15 +89,6 @@
|
||||||
/* flag force enable */ false, \
|
/* flag force enable */ false, \
|
||||||
/* flag fuzz enable */ true, \
|
/* flag fuzz enable */ true, \
|
||||||
/* preference name */ exnref) \
|
/* 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( \
|
FEATURE( \
|
||||||
/* capitalized name */ JSStringBuiltins, \
|
/* capitalized name */ JSStringBuiltins, \
|
||||||
/* lower case name */ jsStringBuiltins, \
|
/* lower case name */ jsStringBuiltins, \
|
||||||
|
|
@ -153,30 +134,21 @@
|
||||||
/* flag force enable */ false, \
|
/* flag force enable */ false, \
|
||||||
/* flag fuzz enable */ true, \
|
/* flag fuzz enable */ true, \
|
||||||
/* preference name */ multi_memory) \
|
/* 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( \
|
FEATURE( \
|
||||||
/* capitalized name */ JSPromiseIntegration, \
|
/* capitalized name */ JSPromiseIntegration, \
|
||||||
/* lower case name */ jsPromiseIntegration, \
|
/* lower case name */ jsPromiseIntegration, \
|
||||||
/* compile predicate */ WASM_JSPI_ENABLED, \
|
/* compile predicate */ WASM_JSPI_ENABLED, \
|
||||||
/* compiler predicate */ IonAvailable(cx), \
|
/* compiler predicate */ IonPlatformSupport(), \
|
||||||
/* flag predicate */ true, \
|
/* flag predicate */ true, \
|
||||||
/* flag force enable */ false, \
|
/* flag force enable */ false, \
|
||||||
/* flag fuzz enable */ false, \
|
/* flag fuzz enable */ true, \
|
||||||
/* preference name */ js_promise_integration) \
|
/* preference name */ js_promise_integration) \
|
||||||
FEATURE( \
|
FEATURE( \
|
||||||
/* capitalized name */ MozIntGemm, \
|
/* capitalized name */ MozIntGemm, \
|
||||||
/* lower case name */ mozIntGemm, \
|
/* lower case name */ mozIntGemm, \
|
||||||
/* compile predicate */ WASM_MOZ_INTGEMM_ENABLED, \
|
/* compile predicate */ WASM_MOZ_INTGEMM_ENABLED, \
|
||||||
/* compiler predicate */ AnyCompilerAvailable(cx), \
|
/* compiler predicate */ AnyCompilerAvailable(cx), \
|
||||||
/* flag predicate */ IsSimdPrivilegedContext(cx), \
|
/* flag predicate */ IsPrivilegedContext(cx), \
|
||||||
/* flag force enable */ false, \
|
/* flag force enable */ false, \
|
||||||
/* flag fuzz enable */ false, \
|
/* flag fuzz enable */ false, \
|
||||||
/* preference name */ moz_intgemm) \
|
/* preference name */ moz_intgemm) \
|
||||||
|
|
@ -196,7 +168,7 @@
|
||||||
/* compiler predicate */ IonAvailable(cx), \
|
/* compiler predicate */ IonAvailable(cx), \
|
||||||
/* flag predicate */ true, \
|
/* flag predicate */ true, \
|
||||||
/* flag force enable */ false, \
|
/* flag force enable */ false, \
|
||||||
/* flag fuzz enable */ false, \
|
/* flag fuzz enable */ true, \
|
||||||
/* preference name */ branch_hinting)
|
/* preference name */ branch_hinting)
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
|
||||||
|
|
@ -255,6 +255,9 @@ class JS_PUBLIC_API CrossCompartmentWrapper : public Wrapper {
|
||||||
|
|
||||||
// Allocate CrossCompartmentWrappers in the nursery.
|
// Allocate CrossCompartmentWrappers in the nursery.
|
||||||
virtual bool canNurseryAllocate() const override { return true; }
|
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 singleton;
|
||||||
static const CrossCompartmentWrapper singletonWithPrototype;
|
static const CrossCompartmentWrapper singletonWithPrototype;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -38,6 +38,7 @@ struct CompilationStencil;
|
||||||
struct CompilationGCOutput;
|
struct CompilationGCOutput;
|
||||||
struct CompilationInput;
|
struct CompilationInput;
|
||||||
struct PreallocatedCompilationGCOutput;
|
struct PreallocatedCompilationGCOutput;
|
||||||
|
struct InitialStencilAndDelazifications;
|
||||||
} // namespace frontend
|
} // namespace frontend
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
|
|
@ -47,7 +48,7 @@ struct PreallocatedCompilationGCOutput;
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
using Stencil = js::frontend::CompilationStencil;
|
using Stencil = js::frontend::InitialStencilAndDelazifications;
|
||||||
using FrontendContext = js::FrontendContext;
|
using FrontendContext = js::FrontendContext;
|
||||||
|
|
||||||
// Temporary storage used during instantiating Stencil.
|
// Temporary storage used during instantiating Stencil.
|
||||||
|
|
@ -193,6 +194,7 @@ extern JS_PUBLIC_API JSObject* InstantiateModuleStencil(
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
// Serialize the Stencil into the transcode buffer.
|
// Serialize the Stencil into the transcode buffer.
|
||||||
|
// This fails if the stencil contains asm.js.
|
||||||
extern JS_PUBLIC_API TranscodeResult EncodeStencil(JSContext* cx,
|
extern JS_PUBLIC_API TranscodeResult EncodeStencil(JSContext* cx,
|
||||||
Stencil* stencil,
|
Stencil* stencil,
|
||||||
TranscodeBuffer& buffer);
|
TranscodeBuffer& buffer);
|
||||||
|
|
@ -205,10 +207,59 @@ extern JS_PUBLIC_API TranscodeResult
|
||||||
DecodeStencil(JS::FrontendContext* fc, const ReadOnlyDecodeOptions& options,
|
DecodeStencil(JS::FrontendContext* fc, const ReadOnlyDecodeOptions& options,
|
||||||
const TranscodeRange& range, Stencil** stencilOut);
|
const TranscodeRange& range, Stencil** stencilOut);
|
||||||
|
|
||||||
// Register an encoder on its script source, such that all functions can be
|
// ************************************************************************
|
||||||
// encoded as they are delazified.
|
// Collect delazifications
|
||||||
extern JS_PUBLIC_API bool StartIncrementalEncoding(JSContext* cx,
|
// ************************************************************************
|
||||||
RefPtr<Stencil>&& stencil);
|
|
||||||
|
// 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
|
} // namespace JS
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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_ */
|
||||||
|
|
@ -135,8 +135,6 @@ namespace js {
|
||||||
|
|
||||||
extern JS_PUBLIC_API JSObject* UnwrapArrayBufferView(JSObject* obj);
|
extern JS_PUBLIC_API JSObject* UnwrapArrayBufferView(JSObject* obj);
|
||||||
|
|
||||||
extern JS_PUBLIC_API JSObject* UnwrapReadableStream(JSObject* obj);
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
constexpr size_t TypedArrayLengthSlot = 1;
|
constexpr size_t TypedArrayLengthSlot = 1;
|
||||||
|
|
@ -710,6 +708,11 @@ struct BarrierMethods<T, EnableIfABOVType<T>> {
|
||||||
static gc::Cell* asGCThingOrNull(T view) {
|
static gc::Cell* asGCThingOrNull(T view) {
|
||||||
return reinterpret_cast<gc::Cell*>(view.asObjectUnbarriered());
|
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) {
|
static void postWriteBarrier(T* viewp, T prev, T next) {
|
||||||
BarrierMethods<JSObject*>::postWriteBarrier(viewp->addressOfObject(),
|
BarrierMethods<JSObject*>::postWriteBarrier(viewp->addressOfObject(),
|
||||||
prev.asObjectUnbarriered(),
|
prev.asObjectUnbarriered(),
|
||||||
|
|
|
||||||
|
|
@ -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_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_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_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")
|
MSG_DEF(JSMSG_DISPOSABLE_NOT_OBJ, 0, JSEXN_TYPEERR, "Value to be disposed is not an object")
|
||||||
|
|
||||||
// JSON
|
// 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_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_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_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_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_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_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_ASS, 0, JSEXN_SYNTAXERR, "invalid destructuring assignment operator")
|
||||||
MSG_DEF(JSMSG_BAD_DESTRUCT_TARGET, 0, JSEXN_SYNTAXERR, "invalid destructuring target")
|
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_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_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_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_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_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id")
|
||||||
MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function")
|
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_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_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_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_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_AFTER_ID, 0, JSEXN_SYNTAXERR, "missing : after property id")
|
||||||
MSG_DEF(JSMSG_COLON_IN_COND, 0, JSEXN_SYNTAXERR, "missing : in conditional expression")
|
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_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_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_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_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_FORMAL, 1, JSEXN_SYNTAXERR, "duplicate formal argument {0}")
|
||||||
MSG_DEF(JSMSG_DUPLICATE_LABEL, 0, JSEXN_SYNTAXERR, "duplicate label")
|
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_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_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")
|
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_BINDING_NAME, 0, JSEXN_SYNTAXERR, "missing binding name")
|
||||||
MSG_DEF(JSMSG_NO_EXPORT_NAME, 0, JSEXN_SYNTAXERR, "missing export 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_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_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_CATCH, 0, JSEXN_SYNTAXERR, "missing ) after catch")
|
||||||
MSG_DEF(JSMSG_PAREN_AFTER_COND, 0, JSEXN_SYNTAXERR, "missing ) after condition")
|
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_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_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_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_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_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")
|
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_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")
|
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
|
// asm.js
|
||||||
MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL, 1, JSEXN_TYPEERR, "asm.js type error: {0}")
|
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}")
|
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_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_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_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_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_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")
|
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_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_RANGE, 2, JSEXN_RANGEERR, "bad {0} {1}")
|
||||||
MSG_DEF(JSMSG_WASM_BAD_GROW, 1, JSEXN_RANGEERR, "failed to grow {0}")
|
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_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_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")
|
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_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_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_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_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, 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_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_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_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_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_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_DUPLICATE_BUILTIN, 0, JSEXN_TYPEERR, "duplicate builtin")
|
||||||
MSG_DEF(JSMSG_WASM_BAD_CODEPOINT, 0, JSEXN_WASMRUNTIMEERROR, "bad codepoint")
|
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")
|
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_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_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_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
|
// JSPI
|
||||||
MSG_DEF(JSMSG_JSPI_ARG_POSITION, 0, JSEXN_TYPEERR, "Invalid argument position value")
|
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_SUSPENDER, 0, IF_WASM_JSPI(JSEXN_WASMSUSPENDERROR, JSEXN_WASMRUNTIMEERROR), "Invalid suspender")
|
||||||
MSG_DEF(JSMSG_JSPI_INVALID_STATE, 0, JSEXN_WASMRUNTIMEERROR, "Invalid state")
|
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_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_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_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
|
// Proxy
|
||||||
MSG_DEF(JSMSG_BAD_GETPROTOTYPEOF_TRAP_RETURN,0,JSEXN_TYPEERR,"proxy getPrototypeOf handler returned a non-object, non-null value")
|
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_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_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_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_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, 0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'displayURL', 'url', or 'source' property")
|
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_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_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}")
|
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_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_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_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
|
// Testing functions
|
||||||
MSG_DEF(JSMSG_TESTING_SCRIPTS_ONLY, 0, JSEXN_TYPEERR, "only works on scripts")
|
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_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_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_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_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_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}()")
|
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_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_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_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
|
// RegExp
|
||||||
MSG_DEF(JSMSG_BAD_CLASS_RANGE, 0, JSEXN_SYNTAXERR, "invalid range in character class")
|
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_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_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_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_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_INVALID_UNICODE_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid unicode escape in regular expression")
|
||||||
MSG_DEF(JSMSG_MISSING_PAREN, 0, JSEXN_SYNTAXERR, "unterminated parenthetical")
|
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_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_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_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
|
// Typed object
|
||||||
MSG_DEF(JSMSG_TYPEDOBJECT_SETTING_IMMUTABLE, 0, JSEXN_ERR, "setting immutable field")
|
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
|
// Atomics and futexes
|
||||||
MSG_DEF(JSMSG_ATOMICS_BAD_ARRAY, 0, JSEXN_TYPEERR, "invalid array type for the operation")
|
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_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
|
// XPConnect wrappers and DOM bindings
|
||||||
MSG_DEF(JSMSG_CANT_SET_INTERPOSED, 1, JSEXN_TYPEERR, "unable to set interposed data property '{0}'")
|
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_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_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_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_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_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}'")
|
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_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_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_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
|
// Import Attributes
|
||||||
MSG_DEF(JSMSG_IMPORT_ATTRIBUTES_STATIC_IMPORT_UNSUPPORTED_ATTRIBUTE, 1, JSEXN_SYNTAXERR, "Unsupported import attribute: {0}")
|
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_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")
|
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
|
// (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_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")
|
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
|
// Set
|
||||||
MSG_DEF(JSMSG_SET_NEGATIVE_SIZE, 0, JSEXN_RANGEERR, "Set size must be non-negative")
|
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
|
// Shadow Realms
|
||||||
MSG_DEF(JSMSG_NOT_SHADOW_REALM, 0, JSEXN_TYPEERR, "Object is not a ShadowRealm")
|
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")
|
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_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_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_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, "required option {0} is undefined")
|
||||||
MSG_DEF(JSMSG_TEMPORAL_MISSING_OPTION, 1, JSEXN_RANGEERR, "undefined {0} option")
|
MSG_DEF(JSMSG_TEMPORAL_MISSING_PROPERTY, 1, JSEXN_TYPEERR, "required property {0} is undefined")
|
||||||
MSG_DEF(JSMSG_TEMPORAL_MISSING_PROPERTY, 1, JSEXN_TYPEERR, "{0} property is undefined")
|
MSG_DEF(JSMSG_TEMPORAL_UNEXPECTED_PROPERTY, 1, JSEXN_TYPEERR, "expected property {0} to be undefined")
|
||||||
MSG_DEF(JSMSG_TEMPORAL_UNEXPECTED_PROPERTY, 1, JSEXN_TYPEERR, "{0} property is not undefined")
|
|
||||||
MSG_DEF(JSMSG_TEMPORAL_MISSING_TEMPORAL_FIELDS, 0, JSEXN_TYPEERR, "object must have at least one temporal property")
|
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_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_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_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_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_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_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_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_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 lower than 2**53 seconds")
|
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_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_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_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_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_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_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_OVERFLOW_FIELD, 2, JSEXN_RANGEERR, "calendar field \"{0}\" is too large: {1}")
|
||||||
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_DUPLICATE_FIELD, 1, JSEXN_RANGEERR, "duplicate calendar field \"{0}\"")
|
|
||||||
MSG_DEF(JSMSG_TEMPORAL_CALENDAR_INVALID_MONTHCODE, 1, JSEXN_RANGEERR, "invalid \"monthCode\" calendar field: {0}")
|
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_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_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_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, 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_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_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, "month-day must be valid ISO date values")
|
||||||
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 must be valid ISO date values")
|
||||||
MSG_DEF(JSMSG_TEMPORAL_PLAIN_YEAR_MONTH_INVALID, 0, JSEXN_RANGEERR, "year-month-day must be valid iso dates")
|
|
||||||
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_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_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_NEGATIVE_ZERO_YEAR, 1, JSEXN_RANGEERR, "can't parse {0}: 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_EXTENDED_YEAR, 1, JSEXN_RANGEERR, "can't parse {0}: 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_YEAR, 1, JSEXN_RANGEERR, "can't parse {0}: missing four digit year")
|
||||||
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_MONTH, 0, JSEXN_RANGEERR, "missing two digit month")
|
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, 0, JSEXN_RANGEERR, "missing two digit day")
|
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, 0, JSEXN_RANGEERR, "missing two digit hour")
|
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, 0, JSEXN_RANGEERR, "missing two digit minute")
|
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, 0, JSEXN_RANGEERR, "missing two digit second")
|
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, 0, JSEXN_RANGEERR, "missing time zone sign")
|
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, 0, JSEXN_RANGEERR, "month must be a number from 1 to 12")
|
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, 0, JSEXN_RANGEERR, "day must be a number from 1 to 31")
|
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, 0, JSEXN_RANGEERR, "hour must be a number from 0 to 23")
|
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, 0, JSEXN_RANGEERR, "minute must be a number from 0 to 59")
|
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, 0, JSEXN_RANGEERR, "second 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, 0, JSEXN_RANGEERR, "second must be a number from 0 to 60")
|
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, 0, JSEXN_RANGEERR, "missing '[' before time zone annotation")
|
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, 0, JSEXN_RANGEERR, "missing ']' after 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, 0, JSEXN_RANGEERR, "missing time zone")
|
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, 0, JSEXN_RANGEERR, "missing time zone name")
|
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_TIMEZONE_NAME, 1, JSEXN_RANGEERR, "can't parse {0}: 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_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, 0, JSEXN_RANGEERR, "missing duration designator 'P'")
|
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, 0, JSEXN_RANGEERR, "missing time designator 'T'")
|
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, 0, JSEXN_RANGEERR, "missing duration digits")
|
MSG_DEF(JSMSG_TEMPORAL_PARSER_MISSING_DURATION_DIGITS, 1, JSEXN_RANGEERR, "can't parse {0}: 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_MISSING_DURATION_UNIT_DESIGNATOR, 1, JSEXN_RANGEERR, "can't parse {0}: missing duration unit designator")
|
||||||
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_DURATION_MINUTES, 1, JSEXN_RANGEERR, "can't parse {0}: invalid duration minutes after fractional hours")
|
||||||
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_ANNOTATION_KEY, 0, JSEXN_RANGEERR, "invalid annotation key")
|
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_VALUE, 0, JSEXN_RANGEERR, "invalid annotation value")
|
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_ANNOTATION_KEY, 1, JSEXN_RANGEERR, "can't parse {0}: invalid annotation key")
|
||||||
MSG_DEF(JSMSG_TEMPORAL_PARSER_INVALID_CALENDAR_NAME, 0, JSEXN_RANGEERR, "invalid calendar name")
|
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, 0, JSEXN_RANGEERR, "missing ']' before annotation")
|
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, 0, JSEXN_RANGEERR, "missing ']' after 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, 0, JSEXN_RANGEERR, "missing '=' in 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, 0, JSEXN_RANGEERR, "unexpected critical 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, 0, JSEXN_RANGEERR, "missing date-time separator 'T'")
|
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, 0, JSEXN_RANGEERR, "time is ambiguous with a month-day")
|
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, 0, JSEXN_RANGEERR, "time is ambiguous with a year-month")
|
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, 0, JSEXN_RANGEERR, "unexpected UTC designator 'Z'")
|
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, 0, JSEXN_RANGEERR, "unexpected UTC designator 'Z' without a bracketed time zone")
|
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, 0, JSEXN_RANGEERR, "Month-Day formats only support the \"iso8601\" calendar")
|
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, 0, JSEXN_RANGEERR, "Year-Month 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, 0, JSEXN_RANGEERR, "time zone offset must not contain seconds precision")
|
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
|
//clang-format on
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
class JS_PUBLIC_API EnvironmentChain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate a new environment in the current compartment that is compatible with
|
* Allocate a new environment in the current compartment that is compatible with
|
||||||
* JSM shared loading.
|
* JSM shared loading.
|
||||||
|
|
@ -68,7 +70,7 @@ extern JS_PUBLIC_API bool ExecuteInJSMEnvironment(JSContext* cx,
|
||||||
// temporarily placed on the environment chain.
|
// temporarily placed on the environment chain.
|
||||||
extern JS_PUBLIC_API bool ExecuteInJSMEnvironment(
|
extern JS_PUBLIC_API bool ExecuteInJSMEnvironment(
|
||||||
JSContext* cx, Handle<JSScript*> script, Handle<JSObject*> jsmEnv,
|
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
|
// 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
|
// by looking at stack frames. Returns nullptr if top frame isn't a scripted
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,12 @@ struct JS_PUBLIC_API JSContext;
|
||||||
class JS_PUBLIC_API JSObject;
|
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
|
* 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.
|
* 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_REASON_2, Enumeration) \
|
||||||
_(GC_IS_COMPARTMENTAL, Boolean) \
|
_(GC_IS_COMPARTMENTAL, Boolean) \
|
||||||
_(GC_ZONE_COUNT, QuantityDistribution) \
|
_(GC_ZONE_COUNT, QuantityDistribution) \
|
||||||
|
|
@ -60,9 +60,6 @@ class JS_PUBLIC_API JSObject;
|
||||||
_(GC_TIME_BETWEEN_S, TimeDuration_S) \
|
_(GC_TIME_BETWEEN_S, TimeDuration_S) \
|
||||||
_(GC_TIME_BETWEEN_SLICES_MS, TimeDuration_MS) \
|
_(GC_TIME_BETWEEN_SLICES_MS, TimeDuration_MS) \
|
||||||
_(GC_SLICE_COUNT, QuantityDistribution) \
|
_(GC_SLICE_COUNT, QuantityDistribution) \
|
||||||
_(DESERIALIZE_BYTES, MemoryDistribution) \
|
|
||||||
_(DESERIALIZE_ITEMS, QuantityDistribution) \
|
|
||||||
_(DESERIALIZE_US, TimeDuration_US) \
|
|
||||||
_(GC_EFFECTIVENESS, MemoryDistribution) \
|
_(GC_EFFECTIVENESS, MemoryDistribution) \
|
||||||
_(GC_PARALLEL_MARK, Boolean) \
|
_(GC_PARALLEL_MARK, Boolean) \
|
||||||
_(GC_PARALLEL_MARK_SPEEDUP, Integer) \
|
_(GC_PARALLEL_MARK_SPEEDUP, Integer) \
|
||||||
|
|
@ -70,6 +67,20 @@ class JS_PUBLIC_API JSObject;
|
||||||
_(GC_PARALLEL_MARK_INTERRUPTIONS, Integer) \
|
_(GC_PARALLEL_MARK_INTERRUPTIONS, Integer) \
|
||||||
_(GC_TASK_START_DELAY_US, TimeDuration_US)
|
_(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
|
// clang-format off
|
||||||
#define ENUM_DEF(NAME, _) NAME,
|
#define ENUM_DEF(NAME, _) NAME,
|
||||||
enum class JSMetric {
|
enum class JSMetric {
|
||||||
|
|
@ -84,21 +95,29 @@ using JSAccumulateTelemetryDataCallback = void (*)(JSMetric, uint32_t);
|
||||||
extern JS_PUBLIC_API void JS_SetAccumulateTelemetryCallback(
|
extern JS_PUBLIC_API void JS_SetAccumulateTelemetryCallback(
|
||||||
JSContext* cx, JSAccumulateTelemetryDataCallback callback);
|
JSContext* cx, JSAccumulateTelemetryDataCallback callback);
|
||||||
|
|
||||||
#define FOR_EACH_JS_USE_COUNTER(_) \
|
#define FOR_EACH_JS_USE_COUNTER(_) \
|
||||||
_(ASMJS, AsmJS) \
|
_(ASMJS, AsmJS) \
|
||||||
_(WASM, Wasm) \
|
_(WASM, Wasm) \
|
||||||
_(WASM_LEGACY_EXCEPTIONS, WasmLegacyExceptions) \
|
_(WASM_LEGACY_EXCEPTIONS, WasmLegacyExceptions) \
|
||||||
_(SUBCLASSING_ARRAY_TYPE_II, SubclassingArrayTypeII) \
|
_(ISHTMLDDA_FUSE, IsHTMLDDAFuse) \
|
||||||
_(SUBCLASSING_ARRAY_TYPE_III, SubclassingArrayTypeIII) \
|
_(OPTIMIZE_GET_ITERATOR_FUSE, OptimizeGetIteratorFuse) \
|
||||||
_(SUBCLASSING_PROMISE_TYPE_II, SubclassingPromiseTypeII) \
|
_(THENABLE_USE, ThenableUse) \
|
||||||
_(SUBCLASSING_PROMISE_TYPE_III, SubclassingPromiseTypeIII) \
|
_(THENABLE_USE_PROTO, ThenableUseProto) \
|
||||||
_(SUBCLASSING_TYPEDARRAY_TYPE_II, SubclassingTypedArrayTypeII) \
|
_(THENABLE_USE_STANDARD_PROTO, ThenableUseStandardProto) \
|
||||||
_(SUBCLASSING_TYPEDARRAY_TYPE_III, SubclassingTypedArrayTypeIII) \
|
_(THENABLE_USE_OBJECT_PROTO, ThenableUseObjectProto) \
|
||||||
_(SUBCLASSING_ARRAYBUFFER_TYPE_III, SubclassingArrayBufferTypeIII) \
|
_(LEGACY_LANG_SUBTAG, LegacyLangSubtag) \
|
||||||
_(SUBCLASSING_SHAREDARRAYBUFFER_TYPE_III, \
|
_(IC_STUB_TOO_LARGE, ICStubTooLarge) \
|
||||||
SubclassingSharedArrayBufferTypeIII) \
|
_(IC_STUB_OOM, ICStubOOM) \
|
||||||
_(SUBCLASSING_REGEXP_TYPE_III, SubclassingRegExpTypeIII) \
|
_(ERRORSTACK_GETTER, ErrorStackGetter) \
|
||||||
_(SUBCLASSING_REGEXP_TYPE_IV, SubclassingRegExpTypeIV)
|
_(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.
|
* Use counter names passed to the accumulate use counter callback.
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ struct String {
|
||||||
static constexpr uint32_t LINEAR_BIT = js::Bit(4);
|
static constexpr uint32_t LINEAR_BIT = js::Bit(4);
|
||||||
static constexpr uint32_t INLINE_CHARS_BIT = js::Bit(6);
|
static constexpr uint32_t INLINE_CHARS_BIT = js::Bit(6);
|
||||||
static constexpr uint32_t LATIN1_CHARS_BIT = js::Bit(10);
|
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 EXTERNAL_FLAGS = LINEAR_BIT | js::Bit(8);
|
||||||
static constexpr uint32_t TYPE_FLAGS_MASK = js::BitMask(10) - js::BitMask(3);
|
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);
|
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 isLinear() const { return flags() & LINEAR_BIT; }
|
||||||
bool hasLatin1Chars() const { return flags() & LATIN1_CHARS_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.
|
// For hot code, prefer other type queries.
|
||||||
bool isExternal() const {
|
bool isExternal() const {
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@
|
||||||
|
|
||||||
# This script generates js/public/PrefsGenerated.h from StaticPrefList.yaml
|
# This script generates js/public/PrefsGenerated.h from StaticPrefList.yaml
|
||||||
|
|
||||||
|
import io
|
||||||
|
|
||||||
import buildconfig
|
import buildconfig
|
||||||
import six
|
|
||||||
import yaml
|
import yaml
|
||||||
from mozbuild.preprocessor import Preprocessor
|
from mozbuild.preprocessor import Preprocessor
|
||||||
|
|
||||||
|
|
@ -39,7 +40,7 @@ def load_yaml(yaml_path):
|
||||||
if buildconfig.substs.get("MOZ_DEBUG"):
|
if buildconfig.substs.get("MOZ_DEBUG"):
|
||||||
pp.context["DEBUG"] = "1"
|
pp.context["DEBUG"] = "1"
|
||||||
|
|
||||||
pp.out = six.StringIO()
|
pp.out = io.StringIO()
|
||||||
pp.do_filter("substitution")
|
pp.do_filter("substitution")
|
||||||
pp.do_include(yaml_path)
|
pp.do_include(yaml_path)
|
||||||
contents = pp.out.getvalue()
|
contents = pp.out.getvalue()
|
||||||
|
|
@ -56,7 +57,7 @@ def get_cpp_type(type):
|
||||||
return "uint32_t"
|
return "uint32_t"
|
||||||
if type in ("int32_t", "RelaxedAtomicInt32"):
|
if type in ("int32_t", "RelaxedAtomicInt32"):
|
||||||
return "int32_t"
|
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
|
# 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.
|
# after startup.
|
||||||
field_type = type
|
field_type = type
|
||||||
if not is_startup_pref:
|
if not is_startup_pref:
|
||||||
field_type = "mozilla::Atomic<{}, mozilla::Relaxed>".format(field_type)
|
field_type = f"mozilla::Atomic<{field_type}, mozilla::Relaxed>"
|
||||||
class_fields.append("static {} {}_;".format(field_type, cpp_name))
|
class_fields.append(f"static {field_type} {cpp_name}_;")
|
||||||
class_fields_inits.append(
|
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"
|
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:
|
# Generate a MACRO invocation like this:
|
||||||
# MACRO("arraybuffer_transfer", arraybuffer_transfer, bool, setAtStartup_arraybuffer_transfer, true)
|
# MACRO("arraybuffer_transfer", arraybuffer_transfer, bool, setAtStartup_arraybuffer_transfer, true)
|
||||||
macro_entries.append(
|
macro_entries.append(
|
||||||
'MACRO("{}", {}, {}, {}, {})'.format(
|
f'MACRO("{name}", {cpp_name}, {type}, {setter_name}, {is_startup_pref_bool})'
|
||||||
name, cpp_name, type, setter_name, is_startup_pref_bool
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate a C++ statement to set the JS pref based on Gecko's StaticPrefs:
|
# 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):
|
if pref.get("do_not_use_directly", False):
|
||||||
browser_pref_cpp_name += "_DoNotUseDirectly"
|
browser_pref_cpp_name += "_DoNotUseDirectly"
|
||||||
|
|
||||||
statement = "JS::Prefs::{}(mozilla::StaticPrefs::{}());".format(
|
statement = f"JS::Prefs::{setter_name}(mozilla::StaticPrefs::{browser_pref_cpp_name}());"
|
||||||
setter_name, browser_pref_cpp_name
|
|
||||||
)
|
|
||||||
browser_set_statements.append(statement)
|
browser_set_statements.append(statement)
|
||||||
|
|
||||||
# For non-startup prefs, also generate code to update the pref after startup.
|
# 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 = ""
|
||||||
|
|
||||||
contents += "#define JS_PREF_CLASS_FIELDS \\\n"
|
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 += "\n\n"
|
||||||
|
|
||||||
contents += "#define JS_PREF_CLASS_FIELDS_INIT \\\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 += "\n\n"
|
||||||
|
|
||||||
contents += "#define FOR_EACH_JS_PREF(MACRO) \\\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 += "\n\n"
|
||||||
|
|
||||||
contents += "#define SET_JS_PREFS_FROM_BROWSER_PREFS \\\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 += "\n\n"
|
||||||
|
|
||||||
contents += "#define SET_NON_STARTUP_JS_PREFS_FROM_BROWSER_PREFS \\\n"
|
contents += "#define SET_NON_STARTUP_JS_PREFS_FROM_BROWSER_PREFS \\\n"
|
||||||
contents += "".join(
|
contents += "".join(map(lambda s: f" {s}\\\n", browser_set_non_startup_statements))
|
||||||
map(lambda s: " {}\\\n".format(s), browser_set_non_startup_statements)
|
|
||||||
)
|
|
||||||
contents += "\n\n"
|
contents += "\n\n"
|
||||||
|
|
||||||
c_out.write(
|
c_out.write(
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,6 @@ using JS::NullValue;
|
||||||
using JS::NumberValue;
|
using JS::NumberValue;
|
||||||
using JS::ObjectOrNullValue;
|
using JS::ObjectOrNullValue;
|
||||||
using JS::ObjectValue;
|
using JS::ObjectValue;
|
||||||
#ifdef ENABLE_RECORD_TUPLE
|
|
||||||
using JS::ExtendedPrimitiveValue;
|
|
||||||
#endif
|
|
||||||
using JS::PrivateGCThingValue;
|
using JS::PrivateGCThingValue;
|
||||||
using JS::PrivateUint32Value;
|
using JS::PrivateUint32Value;
|
||||||
using JS::PrivateValue;
|
using JS::PrivateValue;
|
||||||
|
|
@ -96,12 +93,14 @@ using JS::NativeImpl;
|
||||||
|
|
||||||
using JS::Rooted;
|
using JS::Rooted;
|
||||||
using JS::RootedBigInt;
|
using JS::RootedBigInt;
|
||||||
|
using JS::RootedField;
|
||||||
using JS::RootedFunction;
|
using JS::RootedFunction;
|
||||||
using JS::RootedId;
|
using JS::RootedId;
|
||||||
using JS::RootedObject;
|
using JS::RootedObject;
|
||||||
using JS::RootedScript;
|
using JS::RootedScript;
|
||||||
using JS::RootedString;
|
using JS::RootedString;
|
||||||
using JS::RootedSymbol;
|
using JS::RootedSymbol;
|
||||||
|
using JS::RootedTuple;
|
||||||
using JS::RootedValue;
|
using JS::RootedValue;
|
||||||
|
|
||||||
using JS::PersistentRooted;
|
using JS::PersistentRooted;
|
||||||
|
|
@ -152,11 +151,6 @@ using JS::Zone;
|
||||||
|
|
||||||
using JS::BigInt;
|
using JS::BigInt;
|
||||||
|
|
||||||
#ifdef ENABLE_RECORD_TUPLE
|
|
||||||
using JS::RecordType;
|
|
||||||
using JS::TupleType;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* NamespaceImports_h */
|
#endif /* NamespaceImports_h */
|
||||||
|
|
|
||||||
|
|
@ -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(.)
|
|
||||||
|
|
@ -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",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
@ -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
|
|
@ -63,7 +63,8 @@ extern ArrayObject* NewDenseFullyAllocatedArray(
|
||||||
// Create a dense array with length == 'length', initialized length set to 0,
|
// Create a dense array with length == 'length', initialized length set to 0,
|
||||||
// and capacity == 'length' clamped to EagerAllocationMaxLength.
|
// and capacity == 'length' clamped to EagerAllocationMaxLength.
|
||||||
extern ArrayObject* NewDensePartlyAllocatedArray(
|
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
|
// Like NewDensePartlyAllocatedArray, but the array will have |proto| as
|
||||||
// prototype (or Array.prototype if |proto| is nullptr).
|
// 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,
|
extern ArrayObject* ArrayConstructorOneArg(JSContext* cx,
|
||||||
Handle<ArrayObject*> templateObject,
|
Handle<ArrayObject*> templateObject,
|
||||||
int32_t lengthInt);
|
int32_t lengthInt,
|
||||||
|
gc::AllocSite* site);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
extern bool ArrayInfo(JSContext* cx, unsigned argc, Value* vp);
|
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(
|
extern ArraySortResult ArraySortFromJit(
|
||||||
JSContext* cx, jit::TrampolineNativeFrameLayout* frame);
|
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 IsArrayConstructor(const JSObject* obj);
|
||||||
|
|
||||||
|
bool intrinsic_CanOptimizeArraySpecies(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* builtin_Array_h */
|
#endif /* builtin_Array_h */
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ function ArrayMap(callbackfn /*, thisArg*/) {
|
||||||
var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
|
var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
|
||||||
|
|
||||||
/* Steps 5. */
|
/* Steps 5. */
|
||||||
var A = ArraySpeciesCreate(O, len);
|
var A = CanOptimizeArraySpecies(O) ? std_Array(len) : ArraySpeciesCreate(O, len);
|
||||||
|
|
||||||
/* Steps 6-7. */
|
/* Steps 6-7. */
|
||||||
/* Steps 7.a (implicit), and 7.d. */
|
/* Steps 7.a (implicit), and 7.d. */
|
||||||
|
|
@ -170,7 +170,7 @@ function ArrayFilter(callbackfn /*, thisArg*/) {
|
||||||
var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
|
var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
|
||||||
|
|
||||||
/* Step 5. */
|
/* Step 5. */
|
||||||
var A = ArraySpeciesCreate(O, 0);
|
var A = CanOptimizeArraySpecies(O) ? [] : ArraySpeciesCreate(O, 0);
|
||||||
|
|
||||||
/* Steps 6-8. */
|
/* Steps 6-8. */
|
||||||
/* Steps 8.a (implicit), and 8.d. */
|
/* Steps 8.a (implicit), and 8.d. */
|
||||||
|
|
@ -520,7 +520,7 @@ function CreateArrayIterator(obj, kind) {
|
||||||
var iterator = NewArrayIterator();
|
var iterator = NewArrayIterator();
|
||||||
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, iteratedObject);
|
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, iteratedObject);
|
||||||
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0);
|
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0);
|
||||||
UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_ITEM_KIND, kind);
|
UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_ITEM_KIND, kind);
|
||||||
return iterator;
|
return iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -552,7 +552,7 @@ function ArrayIteratorNext() {
|
||||||
var index = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX);
|
var index = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX);
|
||||||
|
|
||||||
// Step 7.
|
// Step 7.
|
||||||
var itemKind = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_ITEM_KIND);
|
var itemKind = UnsafeGetInt32FromReservedSlot(obj, ARRAY_ITERATOR_SLOT_ITEM_KIND);
|
||||||
|
|
||||||
// Step 8-9.
|
// Step 8-9.
|
||||||
var len;
|
var len;
|
||||||
|
|
@ -681,9 +681,7 @@ function ArrayFromAsync(asyncItems, mapfn = undefined, thisArg = undefined) {
|
||||||
// Step 3.e.i. Let A be ? Construct(C).
|
// Step 3.e.i. Let A be ? Construct(C).
|
||||||
// Step 3.f. Else,
|
// Step 3.f. Else,
|
||||||
// Step 3.f.i. Let A be ! ArrayCreate(0).
|
// Step 3.f.i. Let A be ! ArrayCreate(0).
|
||||||
var A = IsConstructor(C) ?
|
var A = IsConstructor(C) ? constructContentFunction(C, C) : [];
|
||||||
(ReportUsageCounter(C, SUBCLASS_ARRAY_TYPE_II), constructContentFunction(C, C)) : [];
|
|
||||||
|
|
||||||
|
|
||||||
// Step 3.j.i. Let k be 0.
|
// Step 3.j.i. Let k be 0.
|
||||||
var k = 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.iv.1. Let A be ? Construct(C, « 𝔽(len) »).
|
||||||
// Step 3.k.v. Else,
|
// Step 3.k.v. Else,
|
||||||
// Step 3.k.v.1. Let A be ? ArrayCreate(len).
|
// 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.
|
// Step 3.k.vi. Let k be 0.
|
||||||
var k = 0;
|
var k = 0;
|
||||||
|
|
@ -815,7 +813,7 @@ function ArrayFrom(items, mapfn = undefined, thisArg = undefined) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Steps 5.a-b.
|
// 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.
|
// Step 5.d.
|
||||||
var k = 0;
|
var k = 0;
|
||||||
|
|
@ -858,7 +856,7 @@ function ArrayFrom(items, mapfn = undefined, thisArg = undefined) {
|
||||||
|
|
||||||
// Steps 12-14.
|
// Steps 12-14.
|
||||||
var A = IsConstructor(C)
|
var A = IsConstructor(C)
|
||||||
? (ReportUsageCounter(C, SUBCLASS_ARRAY_TYPE_II), constructContentFunction(C, C, len))
|
? constructContentFunction(C, C, len)
|
||||||
: std_Array(len);
|
: std_Array(len);
|
||||||
|
|
||||||
// Steps 15-16.
|
// Steps 15-16.
|
||||||
|
|
@ -996,7 +994,8 @@ function ArraySpeciesCreate(originalArray, length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5.a.
|
// Step 5.a.
|
||||||
var C = originalArray.constructor;
|
var originalConstructor = originalArray.constructor;
|
||||||
|
var C = originalConstructor;
|
||||||
|
|
||||||
// Step 5.b.
|
// Step 5.b.
|
||||||
if (IsConstructor(C) && IsCrossRealmArrayConstructor(C)) {
|
if (IsConstructor(C) && IsCrossRealmArrayConstructor(C)) {
|
||||||
|
|
@ -1031,7 +1030,6 @@ function ArraySpeciesCreate(originalArray, length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 8.
|
// Step 8.
|
||||||
ReportUsageCounter(C, SUBCLASS_ARRAY_TYPE_III);
|
|
||||||
return constructContentFunction(C, C, length);
|
return constructContentFunction(C, C, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1053,7 +1051,7 @@ function ArrayFlatMap(mapperFunction /*, thisArg*/) {
|
||||||
var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
|
var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
|
||||||
|
|
||||||
// Step 5.
|
// Step 5.
|
||||||
var A = ArraySpeciesCreate(O, 0);
|
var A = CanOptimizeArraySpecies(O) ? [] : ArraySpeciesCreate(O, 0);
|
||||||
|
|
||||||
// Step 6.
|
// Step 6.
|
||||||
FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T);
|
FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T);
|
||||||
|
|
@ -1080,7 +1078,7 @@ function ArrayFlat(/* depth */) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5.
|
// Step 5.
|
||||||
var A = ArraySpeciesCreate(O, 0);
|
var A = CanOptimizeArraySpecies(O) ? [] : ArraySpeciesCreate(O, 0);
|
||||||
|
|
||||||
// Step 6.
|
// Step 6.
|
||||||
FlattenIntoArray(A, O, sourceLen, 0, depthNum);
|
FlattenIntoArray(A, O, sourceLen, 0, depthNum);
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
391
src/third_party/mozjs/extract/js/src/builtin/AsyncDisposableStackObject.cpp
vendored
Normal file
391
src/third_party/mozjs/extract/js/src/builtin/AsyncDisposableStackObject.cpp
vendored
Normal 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_,
|
||||||
|
};
|
||||||
|
|
@ -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
|
|
@ -13,6 +13,7 @@
|
||||||
#include "threading/ConditionVariable.h"
|
#include "threading/ConditionVariable.h"
|
||||||
#include "threading/ProtectedData.h" // js::ThreadData
|
#include "threading/ProtectedData.h" // js::ThreadData
|
||||||
#include "vm/NativeObject.h"
|
#include "vm/NativeObject.h"
|
||||||
|
#include "vm/PlainObject.h"
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
|
@ -23,6 +24,44 @@ class AtomicsObject : public NativeObject {
|
||||||
static const JSClass class_;
|
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 {
|
class FutexThread {
|
||||||
friend class AutoLockFutexAPI;
|
friend class AutoLockFutexAPI;
|
||||||
|
|
||||||
|
|
@ -129,12 +168,29 @@ class FutexThread {
|
||||||
JSContext* cx, SharedArrayRawBuffer* sarb, size_t byteOffset, int64_t value,
|
JSContext* cx, SharedArrayRawBuffer* sarb, size_t byteOffset, int64_t value,
|
||||||
const mozilla::Maybe<mozilla::TimeDuration>& timeout);
|
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
|
// 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
|
// 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
|
// 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`.
|
// `count` is nonnegative then the woken out parameter is never greater than
|
||||||
[[nodiscard]] int64_t atomics_notify_impl(SharedArrayRawBuffer* sarb,
|
// `count`.
|
||||||
size_t byteOffset, int64_t count);
|
[[nodiscard]] bool atomics_notify_impl(JSContext* cx,
|
||||||
|
SharedArrayRawBuffer* sarb,
|
||||||
|
size_t byteOffset, int64_t count,
|
||||||
|
int64_t* woken);
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,14 @@ static bool BigIntConstructor(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Steps 3-4.
|
// Steps 3-4.
|
||||||
BigInt* bi =
|
BigInt* bi;
|
||||||
v.isNumber() ? NumberToBigInt(cx, v.toNumber()) : ToBigInt(cx, v);
|
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) {
|
if (!bi) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -199,36 +205,49 @@ bool BigIntObject::asIntN(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ClassSpec BigIntObject::classSpec_ = {
|
const ClassSpec BigIntObject::classSpec_ = {
|
||||||
GenericCreateConstructor<BigIntConstructor, 1, gc::AllocKind::FUNCTION>,
|
GenericCreateConstructor<BigIntConstructor, 1, gc::AllocKind::FUNCTION,
|
||||||
|
&jit::JitInfo_BigInt>,
|
||||||
GenericCreatePrototype<BigIntObject>,
|
GenericCreatePrototype<BigIntObject>,
|
||||||
BigIntObject::staticMethods,
|
BigIntObject::staticMethods,
|
||||||
nullptr,
|
nullptr,
|
||||||
BigIntObject::methods,
|
BigIntObject::methods,
|
||||||
BigIntObject::properties};
|
BigIntObject::properties,
|
||||||
|
};
|
||||||
|
|
||||||
const JSClass BigIntObject::class_ = {
|
const JSClass BigIntObject::class_ = {
|
||||||
"BigInt",
|
"BigInt",
|
||||||
JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt) |
|
JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt) |
|
||||||
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
|
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
|
||||||
JS_NULL_CLASS_OPS, &BigIntObject::classSpec_};
|
JS_NULL_CLASS_OPS,
|
||||||
|
&BigIntObject::classSpec_,
|
||||||
|
};
|
||||||
|
|
||||||
const JSClass BigIntObject::protoClass_ = {
|
const JSClass BigIntObject::protoClass_ = {
|
||||||
"BigInt.prototype", JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt),
|
"BigInt.prototype",
|
||||||
JS_NULL_CLASS_OPS, &BigIntObject::classSpec_};
|
JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt),
|
||||||
|
JS_NULL_CLASS_OPS,
|
||||||
|
&BigIntObject::classSpec_,
|
||||||
|
};
|
||||||
|
|
||||||
const JSPropertySpec BigIntObject::properties[] = {
|
const JSPropertySpec BigIntObject::properties[] = {
|
||||||
// BigInt proposal section 5.3.5
|
// 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[] = {
|
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
|
#ifdef JS_HAS_INTL_API
|
||||||
JS_SELF_HOSTED_FN("toLocaleString", "BigInt_toLocaleString", 0, 0),
|
JS_SELF_HOSTED_FN("toLocaleString", "BigInt_toLocaleString", 0, 0),
|
||||||
#else
|
#else
|
||||||
JS_FN("toLocaleString", toLocaleString, 0, 0),
|
JS_FN("toLocaleString", toLocaleString, 0, 0),
|
||||||
#endif
|
#endif
|
||||||
JS_FS_END};
|
JS_FS_END,
|
||||||
|
};
|
||||||
|
|
||||||
const JSFunctionSpec BigIntObject::staticMethods[] = {
|
const JSFunctionSpec BigIntObject::staticMethods[] = {
|
||||||
JS_INLINABLE_FN("asUintN", asUintN, 2, 0, BigIntAsUintN),
|
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,
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#include "jit/InlinableNatives.h"
|
#include "jit/InlinableNatives.h"
|
||||||
#include "js/PropertySpec.h"
|
#include "js/PropertySpec.h"
|
||||||
#include "util/StringBuffer.h"
|
#include "util/StringBuilder.h"
|
||||||
#include "vm/BigIntType.h"
|
#include "vm/BigIntType.h"
|
||||||
#include "vm/GlobalObject.h"
|
#include "vm/GlobalObject.h"
|
||||||
#include "vm/JSContext.h"
|
#include "vm/JSContext.h"
|
||||||
|
|
@ -27,7 +27,9 @@ using namespace js;
|
||||||
const JSClass BooleanObject::class_ = {
|
const JSClass BooleanObject::class_ = {
|
||||||
"Boolean",
|
"Boolean",
|
||||||
JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_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) {
|
MOZ_ALWAYS_INLINE bool IsBoolean(HandleValue v) {
|
||||||
return v.isBoolean() || (v.isObject() && v.toObject().is<BooleanObject>());
|
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());
|
bool b = ThisBooleanValue(args.thisv());
|
||||||
|
|
||||||
JSStringBuilder sb(cx);
|
JSStringBuilder sb(cx);
|
||||||
if (!sb.append("(new Boolean(") || !BooleanToStringBuffer(b, sb) ||
|
if (!sb.append("(new Boolean(") || !BooleanToStringBuilder(b, sb) ||
|
||||||
!sb.append("))")) {
|
!sb.append("))")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -102,7 +104,9 @@ static bool bool_valueOf(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
static const JSFunctionSpec boolean_methods[] = {
|
static const JSFunctionSpec boolean_methods[] = {
|
||||||
JS_FN("toSource", bool_toSource, 0, 0),
|
JS_FN("toSource", bool_toSource, 0, 0),
|
||||||
JS_FN("toString", bool_toString, 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
|
// ES2020 draft rev ecb4178012d6b4d9abc13fcbd45f5c6394b832ce
|
||||||
// 19.3.1.1 Boolean ( value )
|
// 19.3.1.1 Boolean ( value )
|
||||||
|
|
@ -152,7 +156,8 @@ const ClassSpec BooleanObject::classSpec_ = {
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
boolean_methods,
|
boolean_methods,
|
||||||
nullptr};
|
nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
PropertyName* js::BooleanToString(JSContext* cx, bool b) {
|
PropertyName* js::BooleanToString(JSContext* cx, bool b) {
|
||||||
return b ? cx->names().true_ : cx->names().false_;
|
return b ? cx->names().true_ : cx->names().false_;
|
||||||
|
|
@ -165,12 +170,6 @@ JS_PUBLIC_API bool js::ToBooleanSlow(HandleValue v) {
|
||||||
if (v.isBigInt()) {
|
if (v.isBigInt()) {
|
||||||
return !v.toBigInt()->isZero();
|
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());
|
MOZ_ASSERT(v.isObject());
|
||||||
return !EmulatesUndefined(&v.toObject());
|
return !EmulatesUndefined(&v.toObject());
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,6 @@ using namespace js;
|
||||||
|
|
||||||
using JS::CanonicalizeNaN;
|
using JS::CanonicalizeNaN;
|
||||||
using JS::ToInt32;
|
using JS::ToInt32;
|
||||||
using mozilla::AssertedCast;
|
|
||||||
using mozilla::WrapToSigned;
|
using mozilla::WrapToSigned;
|
||||||
|
|
||||||
static bool IsDataView(HandleValue v) {
|
static bool IsDataView(HandleValue v) {
|
||||||
|
|
@ -405,7 +404,7 @@ NativeType DataViewObject::read(uint64_t offset, size_t length,
|
||||||
getDataPointer<NativeType>(offset, length, &isSharedMemory);
|
getDataPointer<NativeType>(offset, length, &isSharedMemory);
|
||||||
MOZ_ASSERT(data);
|
MOZ_ASSERT(data);
|
||||||
|
|
||||||
NativeType val = 0;
|
NativeType val{};
|
||||||
if (isSharedMemory) {
|
if (isSharedMemory) {
|
||||||
DataViewIO<NativeType, SharedMem<uint8_t*>>::fromBuffer(&val, data,
|
DataViewIO<NativeType, SharedMem<uint8_t*>>::fromBuffer(&val, data,
|
||||||
isLittleEndian);
|
isLittleEndian);
|
||||||
|
|
@ -417,16 +416,6 @@ NativeType DataViewObject::read(uint64_t offset, size_t length,
|
||||||
return val;
|
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,
|
template uint32_t DataViewObject::read(uint64_t offset, size_t length,
|
||||||
bool isLittleEndian);
|
bool isLittleEndian);
|
||||||
|
|
||||||
|
|
@ -510,7 +499,6 @@ inline bool WebIDLCast<uint64_t>(JSContext* cx, HandleValue value,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NIGHTLY_BUILD
|
|
||||||
template <>
|
template <>
|
||||||
inline bool WebIDLCast<float16>(JSContext* cx, HandleValue value,
|
inline bool WebIDLCast<float16>(JSContext* cx, HandleValue value,
|
||||||
float16* out) {
|
float16* out) {
|
||||||
|
|
@ -521,7 +509,6 @@ inline bool WebIDLCast<float16>(JSContext* cx, HandleValue value,
|
||||||
*out = float16(temp);
|
*out = float16(temp);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline bool WebIDLCast<float>(JSContext* cx, HandleValue value, float* out) {
|
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.
|
// See the comment in ElementSpecific::doubleToNative.
|
||||||
if (js::SupportDifferentialTesting() && TypeIsFloatingPoint<NativeType>()) {
|
if constexpr (!std::numeric_limits<NativeType>::is_integer) {
|
||||||
if constexpr (std::is_same_v<NativeType, float16>) {
|
if (js::SupportDifferentialTesting()) {
|
||||||
value = JS::CanonicalizeNaN(value.toDouble());
|
value = JS::CanonicalizeNaN(static_cast<double>(value));
|
||||||
} else {
|
|
||||||
value = JS::CanonicalizeNaN(value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -767,7 +752,6 @@ bool DataViewObject::fun_getBigUint64(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
return CallNonGenericMethod<IsDataView, getBigUint64Impl>(cx, args);
|
return CallNonGenericMethod<IsDataView, getBigUint64Impl>(cx, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NIGHTLY_BUILD
|
|
||||||
bool DataViewObject::getFloat16Impl(JSContext* cx, const CallArgs& args) {
|
bool DataViewObject::getFloat16Impl(JSContext* cx, const CallArgs& args) {
|
||||||
MOZ_ASSERT(IsDataView(args.thisv()));
|
MOZ_ASSERT(IsDataView(args.thisv()));
|
||||||
|
|
||||||
|
|
@ -779,7 +763,7 @@ bool DataViewObject::getFloat16Impl(JSContext* cx, const CallArgs& args) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
args.rval().setDouble(CanonicalizeNaN(val.toDouble()));
|
args.rval().setDouble(CanonicalizeNaN(static_cast<double>(val)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -787,7 +771,6 @@ bool DataViewObject::fun_getFloat16(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
return CallNonGenericMethod<IsDataView, getFloat16Impl>(cx, args);
|
return CallNonGenericMethod<IsDataView, getFloat16Impl>(cx, args);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
bool DataViewObject::getFloat32Impl(JSContext* cx, const CallArgs& args) {
|
bool DataViewObject::getFloat32Impl(JSContext* cx, const CallArgs& args) {
|
||||||
MOZ_ASSERT(IsDataView(args.thisv()));
|
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);
|
return CallNonGenericMethod<IsDataView, setBigUint64Impl>(cx, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NIGHTLY_BUILD
|
|
||||||
bool DataViewObject::setFloat16Impl(JSContext* cx, const CallArgs& args) {
|
bool DataViewObject::setFloat16Impl(JSContext* cx, const CallArgs& args) {
|
||||||
MOZ_ASSERT(IsDataView(args.thisv()));
|
MOZ_ASSERT(IsDataView(args.thisv()));
|
||||||
|
|
||||||
|
|
@ -995,7 +977,6 @@ bool DataViewObject::fun_setFloat16(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
return CallNonGenericMethod<IsDataView, setFloat16Impl>(cx, args);
|
return CallNonGenericMethod<IsDataView, setFloat16Impl>(cx, args);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
bool DataViewObject::setFloat32Impl(JSContext* cx, const CallArgs& args) {
|
bool DataViewObject::setFloat32Impl(JSContext* cx, const CallArgs& args) {
|
||||||
MOZ_ASSERT(IsDataView(args.thisv()));
|
MOZ_ASSERT(IsDataView(args.thisv()));
|
||||||
|
|
@ -1153,10 +1134,8 @@ const JSFunctionSpec DataViewObject::methods[] = {
|
||||||
DataViewGetInt32),
|
DataViewGetInt32),
|
||||||
JS_INLINABLE_FN("getUint32", DataViewObject::fun_getUint32, 1, 0,
|
JS_INLINABLE_FN("getUint32", DataViewObject::fun_getUint32, 1, 0,
|
||||||
DataViewGetUint32),
|
DataViewGetUint32),
|
||||||
#ifdef NIGHTLY_BUILD
|
JS_INLINABLE_FN("getFloat16", DataViewObject::fun_getFloat16, 1, 0,
|
||||||
// TODO: See Bug 1835034 for JIT support for Float16Array
|
DataViewGetFloat16),
|
||||||
JS_FN("getFloat16", DataViewObject::fun_getFloat16, 1, 0),
|
|
||||||
#endif
|
|
||||||
JS_INLINABLE_FN("getFloat32", DataViewObject::fun_getFloat32, 1, 0,
|
JS_INLINABLE_FN("getFloat32", DataViewObject::fun_getFloat32, 1, 0,
|
||||||
DataViewGetFloat32),
|
DataViewGetFloat32),
|
||||||
JS_INLINABLE_FN("getFloat64", DataViewObject::fun_getFloat64, 1, 0,
|
JS_INLINABLE_FN("getFloat64", DataViewObject::fun_getFloat64, 1, 0,
|
||||||
|
|
@ -1177,10 +1156,8 @@ const JSFunctionSpec DataViewObject::methods[] = {
|
||||||
DataViewSetInt32),
|
DataViewSetInt32),
|
||||||
JS_INLINABLE_FN("setUint32", DataViewObject::fun_setUint32, 2, 0,
|
JS_INLINABLE_FN("setUint32", DataViewObject::fun_setUint32, 2, 0,
|
||||||
DataViewSetUint32),
|
DataViewSetUint32),
|
||||||
#ifdef NIGHTLY_BUILD
|
JS_INLINABLE_FN("setFloat16", DataViewObject::fun_setFloat16, 2, 0,
|
||||||
// TODO: See Bug 1835034 for JIT support for Float16Array
|
DataViewSetFloat16),
|
||||||
JS_FN("setFloat16", DataViewObject::fun_setFloat16, 2, 0),
|
|
||||||
#endif
|
|
||||||
JS_INLINABLE_FN("setFloat32", DataViewObject::fun_setFloat32, 2, 0,
|
JS_INLINABLE_FN("setFloat32", DataViewObject::fun_setFloat32, 2, 0,
|
||||||
DataViewSetFloat32),
|
DataViewSetFloat32),
|
||||||
JS_INLINABLE_FN("setFloat64", DataViewObject::fun_setFloat64, 2, 0,
|
JS_INLINABLE_FN("setFloat64", DataViewObject::fun_setFloat64, 2, 0,
|
||||||
|
|
@ -1189,13 +1166,16 @@ const JSFunctionSpec DataViewObject::methods[] = {
|
||||||
DataViewSetBigInt64),
|
DataViewSetBigInt64),
|
||||||
JS_INLINABLE_FN("setBigUint64", DataViewObject::fun_setBigUint64, 2, 0,
|
JS_INLINABLE_FN("setBigUint64", DataViewObject::fun_setBigUint64, 2, 0,
|
||||||
DataViewSetBigUint64),
|
DataViewSetBigUint64),
|
||||||
JS_FS_END};
|
JS_FS_END,
|
||||||
|
};
|
||||||
|
|
||||||
const JSPropertySpec DataViewObject::properties[] = {
|
const JSPropertySpec DataViewObject::properties[] = {
|
||||||
JS_PSG("buffer", DataViewObject::bufferGetter, 0),
|
JS_PSG("buffer", DataViewObject::bufferGetter, 0),
|
||||||
JS_PSG("byteLength", DataViewObject::byteLengthGetter, 0),
|
JS_PSG("byteLength", DataViewObject::byteLengthGetter, 0),
|
||||||
JS_PSG("byteOffset", DataViewObject::byteOffsetGetter, 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,
|
JS_PUBLIC_API JSObject* JS_NewDataView(JSContext* cx, HandleObject buffer,
|
||||||
size_t byteOffset, size_t byteLength) {
|
size_t byteOffset, size_t byteLength) {
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
@ -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_,
|
||||||
|
};
|
||||||
|
|
@ -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 */
|
||||||
|
|
@ -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
Loading…
Reference in New Issue