icecat: add release icecat-140.10.1-1gnu1 for ecne

This commit is contained in:
Ark74 2026-05-04 16:58:41 -06:00
parent a5f93cb214
commit ff85d7c623
1256 changed files with 63469 additions and 24141 deletions

View file

@ -169,8 +169,14 @@ JSObject* ModuleLoaderBase::HostResolveImportedModule(
bool ModuleLoaderBase::ImportMetaResolve(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue modulePrivate(
cx, js::GetFunctionNativeReserved(&args.callee(), ModulePrivateSlot));
RootedValue moduleValue(
cx, js::GetFunctionNativeReserved(
&args.callee(),
static_cast<size_t>(ModuleRecordSlot)));
MOZ_ASSERT(!moduleValue.isUndefined());
RootedObject moduleRecord(cx, &moduleValue.toObject());
RootedValue modulePrivate(cx, GetModulePrivate(moduleRecord));
MOZ_ASSERT(!modulePrivate.isUndefined());
// https://html.spec.whatwg.org/#hostgetimportmetaproperties
// Step 4.1. Set specifier to ? ToString(specifier).
@ -280,10 +286,15 @@ bool ModuleLoaderBase::HostPopulateImportMeta(
}
// Store the 'active script' of the meta object into the function slot.
// https://html.spec.whatwg.org/#active-script
// See https://html.spec.whatwg.org/#active-script
//
// Note: Hold a reference to the module record which in turn keeps the
// ModuleScript alive when import.resolve is called.
RootedObject resolveFuncObj(aCx, JS_GetFunctionObject(resolveFunc));
js::SetFunctionNativeReserved(resolveFuncObj, ModulePrivateSlot,
aReferencingPrivate);
RootedObject moduleRecord(aCx, script->ModuleRecord());
js::SetFunctionNativeReserved(
resolveFuncObj, static_cast<size_t>(ModuleRecordSlot),
JS::ObjectValue(*moduleRecord));
return true;
}

View file

@ -557,7 +557,7 @@ class ModuleLoaderBase : public nsISupports {
bool IsFetchingAndHasWaitingRequest(ModuleLoadRequest* aRequest);
// The slot stored in ImportMetaResolve function.
enum { ModulePrivateSlot = 0, SlotCount };
enum { ModuleRecordSlot = 0, SlotCount };
// The number of args in ImportMetaResolve.
static const uint32_t ImportMetaResolveNumArgs = 1;

View file

@ -129,6 +129,12 @@ inline void SetObjectISupports(JSObject* obj, void* nsISupportsValue) {
SetReservedSlot(obj, 0, PrivateValue(nsISupportsValue));
}
/**
* Returns true if the native object has own named properties, i.e. user-added
* properties (expandos). Must not be called on proxy objects.
*/
extern JS_PUBLIC_API bool NativeObjectHasOwnProperties(const JSObject* obj);
} // namespace JS
// JSObject* is an aligned pointer, but this information isn't available in the

View file

@ -0,0 +1,25 @@
/* 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/. */
/*
* APIs for integration with the cycle collector.
*/
#ifndef js_friend_CycleCollector_h
#define js_friend_CycleCollector_h
#include "jstypes.h"
#include "js/HeapAPI.h" // JS::GCCellPtr
namespace JS {
using ShouldClearWeakRefTargetCallback = bool (*)(GCCellPtr ptr, void* data);
extern JS_PUBLIC_API void MaybeClearWeakRefTargets(
JSRuntime* runtime, ShouldClearWeakRefTargetCallback callback, void* data);
} // namespace JS
#endif // js_friend_CycleCollector_h

View file

@ -235,10 +235,10 @@ static BigInt* CreateBigInt(JSContext* cx,
if (!result) {
return nullptr;
}
if (y) {
if (length > 1) {
result->setDigit(1, y);
}
if (x) {
if (length > 0) {
result->setDigit(0, x);
}
return result;

View file

@ -1152,6 +1152,9 @@ bool DebugAPI::slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame,
if (success && completion.get().suspending()) {
Debugger::suspendGeneratorDebuggerFrames(cx, frame);
} else {
if (frame.isWasmDebugFrame()) {
DebugEnvironments::onPopWasm(cx, frame);
}
Debugger::terminateDebuggerFrames(cx, frame);
}
});

View file

@ -15,6 +15,7 @@
#include "builtin/FinalizationRegistryObject.h"
#include "builtin/WeakRefObject.h"
#include "gc/GCRuntime.h"
#include "gc/PublicIterators.h"
#include "gc/Zone.h"
#include "vm/JSContext.h"
@ -517,3 +518,34 @@ void FinalizationRegistryGlobalData::removeRecord(
void FinalizationRegistryGlobalData::trace(JSTracer* trc) {
recordSet.trace(trc);
}
JS_PUBLIC_API void JS::MaybeClearWeakRefTargets(
JSRuntime* runtime, JS::ShouldClearWeakRefTargetCallback callback,
void* data) {
MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime));
AssertHeapIsIdle();
runtime->gc.maybeClearWeakRefTargets(callback, data);
}
void GCRuntime::maybeClearWeakRefTargets(
JS::ShouldClearWeakRefTargetCallback callback, void* data) {
for (AllZonesIter zone(this); !zone.done(); zone.next()) {
FinalizationObservers* observers = zone->finalizationObservers();
if (observers) {
observers->maybeClearWeakRefTargets(callback, data);
}
}
}
void FinalizationObservers::maybeClearWeakRefTargets(
JS::ShouldClearWeakRefTargetCallback callback, void* data) {
for (auto iter = weakRefMap.modIter(); !iter.done(); iter.next()) {
JSObject* target = iter.get().key();
if (callback(JS::GCCellPtr(target), data)) {
for (JSObject* obj : iter.get().value()) {
updateForRemovedWeakRef(obj, UnwrapWeakRef(obj));
}
iter.remove();
}
}
}

View file

@ -10,6 +10,7 @@
#include "gc/Barrier.h"
#include "gc/WeakMap.h"
#include "gc/ZoneAllocator.h"
#include "js/friend/CycleCollector.h"
#include "js/GCHashTable.h"
#include "js/GCVector.h"
@ -81,6 +82,8 @@ class FinalizationObservers {
bool addWeakRefTarget(Handle<JSObject*> target, Handle<JSObject*> weakRef);
void removeWeakRefTarget(Handle<JSObject*> target,
Handle<WeakRefObject*> weakRef);
void maybeClearWeakRefTargets(JS::ShouldClearWeakRefTargetCallback callback,
void* data);
void unregisterWeakRefWrapper(JSObject* wrapper, WeakRefObject* weakRef);

View file

@ -2194,8 +2194,11 @@ void GCRuntime::decommitEmptyChunks(const bool& cancel, AutoLockGC& lock) {
break;
}
// Check whether something used the chunk while lock was released.
if (!CanDecommitWholeChunk(chunk)) {
// Check whether something used the chunk while the lock was released. The
// chunk may have been taken from the empty chunks pool (e.g. adopted as
// the current chunk, or repurposed as a nursery/buffer chunk), so we must
// verify it is still a member of the pool before removing it.
if (!emptyChunks(lock).contains(chunk) || !CanDecommitWholeChunk(chunk)) {
continue;
}

View file

@ -24,6 +24,7 @@
#include "gc/Scheduling.h"
#include "gc/Statistics.h"
#include "gc/StoreBuffer.h"
#include "js/friend/CycleCollector.h"
#include "js/friend/PerformanceHint.h"
#include "js/GCAnnotations.h"
#include "js/UniquePtr.h"
@ -108,13 +109,15 @@ class ChunkPool {
void sort();
// Linear time, use with caution.
bool contains(ArenaChunk* chunk) const;
private:
ArenaChunk* mergeSort(ArenaChunk* list, size_t count);
bool isSorted() const;
#ifdef DEBUG
public:
bool contains(ArenaChunk* chunk) const;
bool verify() const;
void verifyChunks() const;
#endif
@ -686,6 +689,9 @@ class GCRuntime {
bool registerWeakRef(HandleObject target, HandleObject weakRef);
void traceKeptObjects(JSTracer* trc);
void maybeClearWeakRefTargets(JS::ShouldClearWeakRefTargetCallback callback,
void* data);
JS::GCReason lastStartReason() const { return initialReason; }
void updateAllocationRates();

View file

@ -696,10 +696,11 @@ bool ChunkPool::isSorted() const {
return true;
}
#ifdef DEBUG
bool ChunkPool::contains(ArenaChunk* chunk) const {
#ifdef DEBUG
verify();
#endif
for (ArenaChunk* cursor = head_; cursor; cursor = cursor->info.next) {
if (cursor == chunk) {
return true;
@ -708,6 +709,8 @@ bool ChunkPool::contains(ArenaChunk* chunk) const {
return false;
}
#ifdef DEBUG
bool ChunkPool::verify() const {
MOZ_ASSERT(bool(head_) == bool(count_));
uint32_t count = 0;

View file

@ -0,0 +1,17 @@
function makeArgs() {
"use strict";
return arguments;
}
function test() {
for (var alloc = 1; alloc < 50; alloc++) {
var args = makeArgs(1, 2, 3);
oomAtAllocation(alloc);
try {
delete args[0];
} catch (e) {}
resetOOMFailure();
args[0] = "x";
assertEq(args[0], "x");
}
}
test();

View file

@ -0,0 +1,25 @@
function test() {
var f = function() { return arguments; };
var template = new Array(9000).fill(0);
var a = f.apply(null, template);
Object.defineProperty(a, 0, {value: "v1", writable: false, configurable: true});
for (var alloc = 4; alloc < 15; alloc++) {
var args = null;
var ok = false;
oomAtAllocation(alloc);
try {
args = f.apply(null, template);
ok = true;
Object.defineProperty(args, 0, {value: "v1", writable: false, configurable: true});
} catch (e) {}
resetOOMFailure();
if (ok) {
Object.defineProperty(args, 0, {value: "v2"});
assertEq(args[0], "v2");
}
}
}
test();

View file

@ -0,0 +1,14 @@
// |jit-test| slow; error: InternalError: too much recursion
var leaf = parseModule("await 0; throw 1;", "l.js");
registerModule("l", leaf);
moduleLink(leaf);
moduleEvaluate(leaf);
var p = "l";
for (var i = 0; i < 50000; i++) {
var m = parseModule("import '" + p + "'; if(0) await 0;", "m" + i + ".js");
registerModule("m" + i, m);
moduleLink(m);
moduleEvaluate(m);
p = "m" + i;
}
drainJobQueue();

View file

@ -0,0 +1,34 @@
var bytes = new BigUint64Array([
0xfff1000000000002n, // SCTAG_HEADER (version=2)
0xffff002200000000n, // SCTAG_ERROR_OBJECT
0xffff000480000001n, // .message = SCTAG_STRING (length=1, Latin-1)
0x0000000000000078n, // string data: "x"
0xffff000700000000n, // .hasCause = SCTAG_ARRAY_OBJECT (length=0) <-- INVALID!!!
0xffff000480000002n, // .filename = SCTAG_STRING (length=2, Latin-1)
0x000000000000652dn, // string data: "e-"
0xffff000300000002n, // .lineNumber = SCTAG_INT32 (value=2)
0xffff000300000011n, // .column = SCTAG_INT32 (value=17)
0xffff000000000000n, // .cause = SCTAG_NULL
0xffff000000000000n, // .errors = SCTAG_NULL
0xffff0016ffff0018n, // .stack = SCTAG_SAVED_FRAME_OBJECT | SCTAG_NULL_JSPRINCIPALS
0xffff000200000000n, // .mutedErrors = SCTAG_BOOLEAN (value=0)
0xffff000480000002n, // .source = SCTAG_STRING (length=2, Latin-1)
0x000000000000652dn, // string data: "e-"
0xffff000300000002n, // .lineNumber = SCTAG_INT32 (value=2)
0xffff000300000011n, // .columnNumber SCTAG_INT32 (value=17)
0xffff000000000000n, // .functionDisplayName = SCTAG_NULL
0xffff000000000000n, // .asyncCause = SCTAG_NULL
0xffff000000000000n, // .parent = SCTAG_NULL
0xffff001300000000n, // SCTAG_END_OF_KEYS
0xffff001300000000n, // SCTAG_END_OF_KEYS
]);
var buf = serialize(null, undefined, {scope: 'DifferentProcess'});
buf.arraybuffer = bytes.buffer;
var e;
try {
deserialize(buf);
} catch (err) {
e = err;
}
assertEq(e.message.includes("hasCause must be a boolean"), true);

View file

@ -0,0 +1,177 @@
// |jit-test| skip-if: !wasmThreadsEnabled()
const m = new WebAssembly.Module(wasmTextToBinary(`
(module
(memory $m32 1 1)
(memory $m64 i64 1 1)
(memory $m32s 1 1 shared)
(memory $m64s i64 1 1 shared)
${["", "s"].map(s => `
(func (export "wait3232${s}") (param i32) (result i32)
(memory.atomic.wait32 $m32${s}
(local.get 0)
(i32.const 0)
(i64.const 0)
)
)
(func (export "wait3264${s}") (param i32) (result i32)
(memory.atomic.wait64 $m32${s}
(local.get 0)
(i64.const 0)
(i64.const 0)
)
)
(func (export "wait6432${s}") (param i64) (result i32)
(memory.atomic.wait32 $m64${s}
(local.get 0)
(i32.const 0)
(i64.const 0)
)
)
(func (export "wait6464${s}") (param i64) (result i32)
(memory.atomic.wait64 $m64${s}
(local.get 0)
(i64.const 0)
(i64.const 0)
)
)
(func (export "notify32${s}") (param i32) (result i32)
(memory.atomic.notify $m32${s}
(local.get 0)
(i32.const 0)
)
)
(func (export "notify64${s}") (param i64) (result i32)
(memory.atomic.notify $m64${s}
(local.get 0)
(i32.const 0)
)
)
`).join("\n")}
)`));
const {
wait3232, wait3264,
wait6432, wait6464,
notify32, notify64,
wait3232s, wait3264s,
wait6432s, wait6464s,
notify32s, notify64s,
} = new WebAssembly.Instance(m).exports;
//
// Shared memories
//
assertEq(wait3232s(0), 2);
assertEq(wait3232s(65532), 2);
assertErrorMessage(() => wait3232s(65533), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait3232s(65536), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait3232s(-8), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait3232s(-4), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait3232s(-3), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait3232s(-2), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait3232s(-1), WebAssembly.RuntimeError, /unaligned/);
assertEq(wait3264s(0), 2);
assertEq(wait3264s(65528), 2);
assertErrorMessage(() => wait3264s(65529), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait3264s(65536), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait3264s(-16), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait3264s(-8), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait3264s(-7), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait3264s(-6), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait3264s(-5), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait3264s(-4), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait3264s(-3), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait3264s(-2), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait3264s(-1), WebAssembly.RuntimeError, /unaligned/);
assertEq(wait6432s(0n), 2);
assertEq(wait6432s(65532n), 2);
assertErrorMessage(() => wait6432s(65533n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait6432s(65536n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(2n**32n-8n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(2n**32n-4n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(2n**32n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(2n**33n-8n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(2n**33n-4n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(2n**33n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(-8n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(-4n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(-3n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait6432s(-2n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait6432s(-1n), WebAssembly.RuntimeError, /unaligned/);
assertEq(wait6464s(0n), 2);
assertEq(wait6464s(65528n), 2);
assertErrorMessage(() => wait6464s(65529n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait6464s(65536n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(2n**32n-16n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(2n**32n-8n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(2n**32n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(2n**33n-16n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(2n**33n-8n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6432s(2n**33n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6464s(-16n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6464s(-8n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => wait6464s(-7n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait6464s(-6n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait6464s(-5n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait6464s(-4n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait6464s(-3n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait6464s(-2n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait6464s(-1n), WebAssembly.RuntimeError, /unaligned/);
assertEq(notify32s(65532), 0);
assertErrorMessage(() => notify32s(65533), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => notify32s(65536), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => notify32s(-8), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => notify32s(-4), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => notify32s(-3), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => notify32s(-2), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => notify32s(-1), WebAssembly.RuntimeError, /unaligned/);
assertEq(notify64s(65532n), 0);
assertErrorMessage(() => notify64s(65533n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => notify64s(65536n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => notify64s(-8n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => notify64s(-4n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => notify64s(-3n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => notify64s(-2n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => notify64s(-1n), WebAssembly.RuntimeError, /unaligned/);
//
// Non-shared memories
//
assertErrorMessage(() => wait3232(65532), WebAssembly.RuntimeError, /non-shared/);
assertErrorMessage(() => wait3232(65533), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait3232(65536), WebAssembly.RuntimeError, /non-shared/);
assertErrorMessage(() => wait3232(-4), WebAssembly.RuntimeError, /non-shared/);
assertErrorMessage(() => wait3264(65528), WebAssembly.RuntimeError, /non-shared/);
assertErrorMessage(() => wait3264(65529), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait3264(65536), WebAssembly.RuntimeError, /non-shared/);
assertErrorMessage(() => wait3264(-8), WebAssembly.RuntimeError, /non-shared/);
assertErrorMessage(() => wait6432(65532n), WebAssembly.RuntimeError, /non-shared/);
assertErrorMessage(() => wait6432(65533n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait6432(65536n), WebAssembly.RuntimeError, /non-shared/);
assertErrorMessage(() => wait6432(-4n), WebAssembly.RuntimeError, /non-shared/);
assertErrorMessage(() => wait6464(65528n), WebAssembly.RuntimeError, /non-shared/);
assertErrorMessage(() => wait6464(65529n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => wait6464(65536n), WebAssembly.RuntimeError, /non-shared/);
assertErrorMessage(() => wait6464(-8n), WebAssembly.RuntimeError, /non-shared/);
assertEq(notify32(65532), 0);
assertErrorMessage(() => notify32(65533), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => notify32(65536), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => notify32(-4), WebAssembly.RuntimeError, /index out of bounds/);
assertEq(notify64(65532n), 0);
assertErrorMessage(() => notify64(65533n), WebAssembly.RuntimeError, /unaligned/);
assertErrorMessage(() => notify64(65536n), WebAssembly.RuntimeError, /index out of bounds/);
assertErrorMessage(() => notify64(-4n), WebAssembly.RuntimeError, /index out of bounds/);

View file

@ -178,3 +178,26 @@ const { i31GetU_null, i31GetS_null } = wasmEvalText(`(module
assertErrorMessage(() => i31GetU_null(), WebAssembly.RuntimeError, /dereferencing null pointer/);
assertErrorMessage(() => i31GetS_null(), WebAssembly.RuntimeError, /dereferencing null pointer/);
// Test i31.get_s and i31.get_u operations with some cornercases.
let { f } = new WebAssembly.Instance(
new WebAssembly.Module(wasmTextToBinary(`
(module
(func (export "f") (param i32) (result i32)
(local i31ref)
local.get 0
ref.i31
local.tee 1
i31.get_s
local.get 1
i31.get_u
i32.eq
)
)`))).exports;
assertEq(f(-1), 0);
assertEq(f(-2), 0);
assertEq(f(-0x40000000), 0);
assertEq(f(0), 1);
assertEq(f(1), 1);
assertEq(f(0x3FFFFFFF), 1);

View file

@ -0,0 +1,11 @@
var dummy = {abc: 1};
// Non-Latin1 UTF-8 function name that hash-collides with the Latin1 "abc" atom.
// The unreachable trap exercises UTF8EqualsChars when building the error message.
var bytes = wasmTextToBinary('(module (func $"\\ee\\96\\95\\ea\\b5\\81\\04" (export "f") unreachable))');
var ex = null;
try {
new WebAssembly.Instance(new WebAssembly.Module(bytes)).exports.f();
} catch (e) {
ex = e;
}
assertEq(ex.stack.includes("\uE595\uAD41\x04@"), true);

View file

@ -311,6 +311,16 @@ bool MAsmJSLoadHeap::congruentTo(const MDefinition* ins) const {
return load->accessType() == accessType() && congruentIfOperandsEqual(load);
}
bool MWasmI31RefGet::congruentTo(const MDefinition* ins) const {
if (!ins->isWasmI31RefGet()) {
return false;
}
// Make sure that we have a signed/signed or unsigned/unsigned pair to be
// considered congruent.
return congruentIfOperandsEqual(ins) &&
ins->toWasmI31RefGet()->wideningOp() == wideningOp();
}
MDefinition::AliasType MWasmLoadInstanceDataField::mightAlias(
const MDefinition* def) const {
if (def->isWasmStoreInstanceDataField()) {

View file

@ -6549,6 +6549,34 @@ MDefinition* MGuardNumberToIntPtrIndex::foldsTo(TempAllocator& alloc) {
return MConstant::NewIntPtr(alloc, intptr_t(ival));
}
AliasSet MLoadScriptedProxyHandler::getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
AliasSet MGuardIsNativeObject::getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
AliasSet MGuardIsProxy::getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
AliasSet MGuardIsNotProxy::getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
AliasSet MGuardIsNotDOMProxy::getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
AliasSet MGuardHasProxyHandler::getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
AliasSet MIsConstructor::getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
MDefinition* MIsObject::foldsTo(TempAllocator& alloc) {
MDefinition* input = object();
if (!input->isBox()) {

View file

@ -9051,7 +9051,9 @@ class MIsCallable : public MUnaryInstruction,
}
MDefinition* foldsTo(TempAllocator& alloc) override;
AliasSet getAliasSet() const override { return AliasSet::None(); }
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::ObjectFields);
}
};
class MHasClass : public MUnaryInstruction, public SingleObjectPolicy::Data {
@ -9072,7 +9074,9 @@ class MHasClass : public MUnaryInstruction, public SingleObjectPolicy::Data {
const JSClass* getClass() const { return class_; }
MDefinition* foldsTo(TempAllocator& alloc) override;
AliasSet getAliasSet() const override { return AliasSet::None(); }
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::ObjectFields);
}
bool congruentTo(const MDefinition* ins) const override {
if (!ins->isHasClass()) {
return false;
@ -9112,7 +9116,9 @@ class MGuardToClass : public MUnaryInstruction,
}
MDefinition* foldsTo(TempAllocator& alloc) override;
AliasSet getAliasSet() const override { return AliasSet::None(); }
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::ObjectFields);
}
bool congruentTo(const MDefinition* ins) const override {
if (!ins->isGuardToClass()) {
return false;

View file

@ -668,7 +668,7 @@
result_type: Object
guard: true
congruent_to: if_operands_equal
alias_set: none
alias_set: custom
generate_lir: true
#ifdef JS_PUNBOX64
@ -825,7 +825,7 @@
wideningOp: wasm::FieldWideningOp
type_policy: none
result_type: Int32
congruent_to: if_operands_equal
congruent_to: custom
alias_set: none
generate_lir: true
@ -2161,7 +2161,7 @@
guard: true
movable: true
congruent_to: if_operands_equal
alias_set: none
alias_set: custom
- name: GuardGlobalGeneration
arguments:
@ -2180,7 +2180,7 @@
guard: true
movable: true
congruent_to: if_operands_equal
alias_set: none
alias_set: custom
- name: GuardIsNotDOMProxy
operands:
@ -2189,7 +2189,7 @@
guard: true
movable: true
congruent_to: if_operands_equal
alias_set: none
alias_set: custom
- name: GuardIsNotProxy
operands:
@ -2199,7 +2199,7 @@
movable: true
congruent_to: if_operands_equal
folds_to: custom
alias_set: none
alias_set: custom
- name: ProxyGet
operands:
@ -2401,7 +2401,7 @@
guard: true
movable: true
congruent_to: if_operands_equal
alias_set: none
alias_set: custom
# Loads a specific JSObject* that was originally nursery-allocated.
# See also WarpObjectField.
@ -2965,7 +2965,7 @@
result_type: Boolean
movable: true
congruent_to: if_operands_equal
alias_set: none
alias_set: custom
generate_lir: true
- name: IsCrossRealmArrayConstructor

View file

@ -5765,6 +5765,7 @@ static ReturnCallTrampolineData MakeReturnCallTrampoline(MacroAssembler& masm) {
masm.loadPtr(
Address(masm.getStackPointer(), WasmCallerInstanceOffsetBeforeCall),
InstanceReg);
masm.loadWasmPinnedRegsFromInstance(mozilla::Nothing());
masm.switchToWasmInstanceRealm(ABINonArgReturnReg0, ABINonArgReturnReg1);
masm.moveToStackPtr(FramePointer);
#ifdef JS_CODEGEN_ARM64

View file

@ -3044,11 +3044,7 @@ class WasmStructMemoryView : public MDefinitionVisitorDefaultNoop {
bool mergeIntoSuccessorState(MBasicBlock* curr, MBasicBlock* succ,
BlockState** pSuccState);
#ifdef DEBUG
void assertSuccess();
#else
void assertSuccess() {}
#endif
bool oom() const { return oom_; }
@ -3065,15 +3061,13 @@ void WasmStructMemoryView::setEntryBlockState(BlockState* state) {
state_ = state;
}
#ifdef DEBUG
void WasmStructMemoryView::assertSuccess() {
// Make sure that the undefined value used as a placeholder is not used.
MOZ_ASSERT(!undefinedVal_->hasUses());
MOZ_RELEASE_ASSERT(!undefinedVal_->hasUses());
// Make sure that the MWasmNewStruct instruction is not used anymore.
MOZ_ASSERT(!struct_->hasUses());
MOZ_RELEASE_ASSERT(!struct_->hasUses());
}
#endif
MBasicBlock* WasmStructMemoryView::startingBlock() { return startBlock_; }
@ -3323,7 +3317,7 @@ static bool IsWasmStructEscaped(MDefinition* ins, MInstruction* newStruct) {
}
case MDefinition::Opcode::WasmStoreFieldRef: {
// Escaped if it's stored into another struct.
if (def->toWasmStoreFieldRef()->value() == newStruct) {
if (def->toWasmStoreFieldRef()->value() == ins) {
JitSpewDef(JitSpew_Escape, "is escaped by\n", def);
return true;
}

View file

@ -479,6 +479,10 @@ void JS::detail::SetReservedSlotWithBarrier(JSObject* obj, size_t slot,
}
}
bool JS::NativeObjectHasOwnProperties(const JSObject* obj) {
return !obj->as<NativeObject>().empty();
}
void js::SetPreserveWrapperCallbacks(
JSContext* cx, PreserveWrapperCallback preserveWrapper,
HasReleasedWrapperCallback hasReleasedWrapper) {

View file

@ -259,6 +259,7 @@ EXPORTS.js.experimental += [
# a clean design. Use this only if you absolutely must, and feel free to
# propose clean APIs to replace what's here!
EXPORTS.js.friend += [
"../public/friend/CycleCollector.h",
"../public/friend/DOMProxy.h",
"../public/friend/DumpFunctions.h",
"../public/friend/ErrorMessages.h",

View file

@ -425,7 +425,9 @@ bool js::ProxyHas(JSContext* cx, HandleObject proxy, HandleValue idVal,
if (!ToPropertyKey(cx, idVal, &id)) {
return false;
}
if (MOZ_UNLIKELY(!proxy->is<ProxyObject>())) {
return HasProperty(cx, proxy, id, result);
}
return Proxy::has(cx, proxy, id, result);
}
@ -466,7 +468,9 @@ bool js::ProxyHasOwn(JSContext* cx, HandleObject proxy, HandleValue idVal,
if (!ToPropertyKey(cx, idVal, &id)) {
return false;
}
if (MOZ_UNLIKELY(!proxy->is<ProxyObject>())) {
return HasOwnProperty(cx, proxy, id, result);
}
return Proxy::hasOwn(cx, proxy, id, result);
}
@ -548,6 +552,9 @@ bool js::ProxyGetPropertyByValue(JSContext* cx, HandleObject proxy,
}
RootedValue receiver(cx, ObjectValue(*proxy));
if (MOZ_UNLIKELY(!proxy->is<ProxyObject>())) {
return GetProperty(cx, proxy, receiver, id, vp);
}
return Proxy::getInternal(cx, proxy, receiver, id, vp);
}
@ -621,7 +628,11 @@ bool js::ProxySetPropertyByValue(JSContext* cx, HandleObject proxy,
ObjectOpResult result;
RootedValue receiver(cx, ObjectValue(*proxy));
if (!Proxy::setInternal(cx, proxy, id, val, receiver, result)) {
if (MOZ_UNLIKELY(!proxy->is<ProxyObject>())) {
if (!SetProperty(cx, proxy, id, val, receiver, result)) {
return false;
}
} else if (!Proxy::setInternal(cx, proxy, id, val, receiver, result)) {
return false;
}
return result.checkStrictModeError(cx, proxy, id, strict);

View file

@ -864,6 +864,12 @@ bool MappedArgumentsObject::obj_defineProperty(JSContext* cx, HandleObject obj,
}
}
// Ensure the arguments object has RareArgumentsData so that step 8 is
// infallible.
if (isMapped && !argsobj->getOrCreateRareData(cx)) {
return false;
}
// Step 6. NativeDefineProperty will lookup [[Value]] for us.
if (defineMapped) {
if (!DefineMappedIndex(cx, argsobj, id, &newArgDesc, result)) {
@ -884,17 +890,15 @@ bool MappedArgumentsObject::obj_defineProperty(JSContext* cx, HandleObject obj,
if (isMapped) {
unsigned arg = unsigned(id.toInt());
if (desc.isAccessorDescriptor()) {
if (!argsobj->markElementDeleted(cx, arg)) {
return false;
}
bool ok = argsobj->markElementDeleted(cx, arg);
MOZ_RELEASE_ASSERT(ok, "shouldn't fail after getOrCreateRareData");
} else {
if (desc.hasValue()) {
argsobj->setElement(arg, desc.value());
}
if (desc.hasWritable() && !desc.writable()) {
if (!argsobj->markElementDeleted(cx, arg)) {
return false;
}
bool ok = argsobj->markElementDeleted(cx, arg);
MOZ_RELEASE_ASSERT(ok, "shouldn't fail after getOrCreateRareData");
}
}
}
@ -940,7 +944,7 @@ bool js::UnmappedArgSetter(JSContext* cx, HandleObject obj, HandleId id,
if (id.isInt()) {
unsigned arg = unsigned(id.toInt());
if (arg < argsobj->initialLength()) {
if (argsobj->isElement(arg)) {
argsobj->setElement(arg, v);
return result.succeed();
}

View file

@ -316,9 +316,8 @@ static bool AsyncModuleExecutionRejectedHandler(JSContext* cx, unsigned argc,
cx, &func.getExtendedSlot(FunctionExtended::MODULE_SLOT)
.toObject()
.as<ModuleObject>());
AsyncModuleExecutionRejected(cx, module, args.get(0));
args.rval().setUndefined();
return true;
return AsyncModuleExecutionRejected(cx, module, args.get(0));
}
AsyncFunctionGeneratorObject* AsyncFunctionGeneratorObject::create(

View file

@ -536,21 +536,14 @@ bool GetUTF8AtomizationData(JSContext* cx, const JS::UTF8Chars& utf8,
template <typename CharT>
bool UTF8EqualsChars(const JS::UTF8Chars& utfChars, const CharT* chars) {
static_assert(std::is_same_v<CharT, JS::Latin1Char> ||
std::is_same_v<CharT, char16_t>);
size_t ind = 0;
bool isEqual = true;
auto checkEqual = [&isEqual, &ind, chars](char16_t c) -> LoopDisposition {
#ifdef DEBUG
JS::SmallestEncoding encoding = JS::SmallestEncoding::ASCII;
UpdateSmallestEncodingForChar(c, &encoding);
if (std::is_same_v<CharT, JS::Latin1Char>) {
MOZ_ASSERT(encoding <= JS::SmallestEncoding::Latin1);
} else if (!std::is_same_v<CharT, char16_t>) {
MOZ_CRASH("Invalid character type in UTF8EqualsChars");
}
#endif
if (CharT(c) != chars[ind]) {
if (c != char16_t(chars[ind])) {
isEqual = false;
return LoopDisposition::Break;
}
@ -559,7 +552,7 @@ bool UTF8EqualsChars(const JS::UTF8Chars& utfChars, const CharT* chars) {
return LoopDisposition::Continue;
};
// To get here, you must have checked your work.
// The caller must have already validated UTF-8 well-formedness.
InflateUTF8ToUTF16<OnUTF8Error::Crash>(/* cx = */ nullptr, utfChars,
checkEqual);

View file

@ -3081,6 +3081,30 @@ void DebugEnvironments::onPopModule(JSContext* cx, const EnvironmentIter& ei) {
onPopGeneric<ModuleEnvironmentObject, ModuleScope>(cx, ei);
}
void DebugEnvironments::onPopWasm(JSContext* cx, AbstractFramePtr frame) {
MOZ_ASSERT(frame.isWasmDebugFrame());
DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs) {
return;
}
Rooted<WasmInstanceObject*> instance(cx, frame.wasmInstance()->object());
uint32_t funcIndex = frame.asWasmDebugFrame()->funcIndex();
Rooted<Scope*> wasmFunctionScope(
cx, instance->getExistingFunctionScope(funcIndex));
if (!wasmFunctionScope) {
return;
}
MissingEnvironmentKey key(frame, wasmFunctionScope);
if (MissingEnvironmentMap::Ptr p = envs->missingEnvs.lookup(key)) {
EnvironmentObject& env = p->value()->environment();
envs->liveEnvs.remove(&env);
envs->missingEnvs.remove(p);
}
}
void DebugEnvironments::onRealmUnsetIsDebuggee(Realm* realm) {
if (DebugEnvironments* envs = realm->debugEnvs()) {
envs->proxiedEnvs.clear();

View file

@ -1518,6 +1518,7 @@ class DebugEnvironments {
const jsbytecode* pc);
static void onPopWith(AbstractFramePtr frame);
static void onPopModule(JSContext* cx, const EnvironmentIter& ei);
static void onPopWasm(JSContext* cx, AbstractFramePtr frame);
static void onRealmUnsetIsDebuggee(Realm* realm);
};

View file

@ -72,7 +72,10 @@ class MatchPairs {
friend class RegExpShared;
friend class RegExpStatics;
void forgetArray() { pairs_ = nullptr; }
void forgetArray() {
pairs_ = nullptr;
pairCount_ = 0;
}
public:
void checkAgainst(size_t inputLength) {

View file

@ -1973,7 +1973,9 @@ static void RejectExecutionWithPendingException(JSContext* cx,
std::ignore = cx->getPendingException(&exception);
}
cx->clearPendingException();
AsyncModuleExecutionRejected(cx, module, exception);
if (!AsyncModuleExecutionRejected(cx, module, exception)) {
MOZ_ASSERT(cx->isThrowingOverRecursed());
}
}
// https://tc39.es/ecma262/#sec-async-module-execution-fulfilled
@ -2112,25 +2114,30 @@ void js::AsyncModuleExecutionFulfilled(JSContext* cx,
// https://tc39.es/ecma262/#sec-async-module-execution-rejected
// ES2023 16.2.1.5.2.5 AsyncModuleExecutionRejected
void js::AsyncModuleExecutionRejected(JSContext* cx,
bool js::AsyncModuleExecutionRejected(JSContext* cx,
Handle<ModuleObject*> module,
HandleValue error) {
AutoCheckRecursionLimit recursion(cx);
if (!recursion.check(cx)) {
return false;
}
// Step 1. If module.[[Status]] is evaluated, then:
if (module->status() == ModuleStatus::Evaluated) {
// Step 1.a. Assert: module.[[EvaluationError]] is not empty
MOZ_ASSERT(module->hadEvaluationError());
// Step 1.b. Return unused.
return;
return true;
}
// Step 2. Assert: module.[[Status]] is evaluating-async.
MOZ_ASSERT(module->status() == ModuleStatus::EvaluatingAsync);
// Step 3. Assert: module.[[AsyncEvaluation]] is true.
// Step 3. Assert: module.[[AsyncEvaluationOrder]] is an integer.
MOZ_ASSERT(module->isAsyncEvaluating());
// Step 4. 4. Assert: module.[[EvaluationError]] is empty.
// Step 4. Assert: module.[[EvaluationError]] is empty.
MOZ_ASSERT(!module->hadEvaluationError());
ModuleObject::onTopLevelEvaluationFinished(module);
@ -2141,25 +2148,15 @@ void js::AsyncModuleExecutionRejected(JSContext* cx,
// Step 6. Set module.[[Status]] to evaluated.
MOZ_ASSERT(module->status() == ModuleStatus::Evaluated);
// Step 7. Set module.[[AsyncEvaluationOrder]] to done.
module->clearAsyncEvaluatingPostOrder();
// Step 7. For each Cyclic Module Record m of module.[[AsyncParentModules]],
// do:
Rooted<ListObject*> parents(cx, module->asyncParentModules());
Rooted<ModuleObject*> parent(cx);
for (uint32_t i = 0; i < parents->length(); i++) {
parent = &parents->get(i).toObject().as<ModuleObject>();
// Step 7.a. Perform AsyncModuleExecutionRejected(m, error).
AsyncModuleExecutionRejected(cx, parent, error);
}
// Step 8. If module.[[TopLevelCapability]] is not empty, then:
// Step 9. If module.[[TopLevelCapability]] is not empty, then:
if (module->hasTopLevelCapability()) {
// Step 8.a. Assert: module.[[CycleRoot]] is module.
// Step 9.a. Assert: module.[[CycleRoot]] is module.
MOZ_ASSERT(module->getCycleRoot() == module);
// Step 8.b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]],
// Step 9.b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]],
// undefined, error).
if (!ModuleObject::topLevelCapabilityReject(cx, module, error)) {
// If Reject fails, there's nothing more we can do here.
@ -2167,5 +2164,19 @@ void js::AsyncModuleExecutionRejected(JSContext* cx,
}
}
// Step 9. Return unused.
// Step 10. For each Cyclic Module Record m of module.[[AsyncParentModules]],
// do:
Rooted<ListObject*> parents(cx, module->asyncParentModules());
Rooted<ModuleObject*> parent(cx);
for (uint32_t i = 0; i < parents->length(); i++) {
parent = &parents->get(i).toObject().as<ModuleObject>();
// Step 10.a. Perform AsyncModuleExecutionRejected(m, error).
if (!AsyncModuleExecutionRejected(cx, parent, error)) {
return false;
}
}
// Step 11. Return unused.
return true;
}

View file

@ -49,7 +49,9 @@ ModuleNamespaceObject* GetOrCreateModuleNamespace(JSContext* cx,
void AsyncModuleExecutionFulfilled(JSContext* cx, Handle<ModuleObject*> module);
void AsyncModuleExecutionRejected(JSContext* cx, Handle<ModuleObject*> module,
// This function recusively calls AsyncModuleExecutionRejected on async parent
// modules. It returns false if the stack recusion limit is exceeded.
bool AsyncModuleExecutionRejected(JSContext* cx, Handle<ModuleObject*> module,
HandleValue error);
} // namespace js

View file

@ -248,6 +248,7 @@ inline bool RegExpStatics::updateFromMatchPairs(JSContext* cx,
if (!matches.initArrayFrom(newPairs)) {
ReportOutOfMemory(cx);
clear();
return false;
}

View file

@ -1582,6 +1582,7 @@ bool JSStructuredCloneWriter::writeSharedWasmMemory(HandleObject obj) {
Rooted<WasmMemoryObject*> memoryObj(context(),
&obj->unwrapAs<WasmMemoryObject>());
JSAutoRealm ar(context(), memoryObj);
Rooted<SharedArrayBufferObject*> sab(
context(), &memoryObj->buffer().as<SharedArrayBufferObject>());
@ -2989,6 +2990,12 @@ bool JSStructuredCloneReader::readSharedWasmMemory(uint32_t nbytes,
if (!startRead(&isHuge)) {
return false;
}
if (!isHuge.isBoolean()) {
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
JSMSG_SC_BAD_SERIALIZED_DATA,
"isHuge must be a boolean");
return false;
}
// Read the SharedArrayBuffer object.
RootedValue payload(cx);
@ -3807,7 +3814,13 @@ JSObject* JSStructuredCloneReader::readErrorHeader(uint32_t type) {
if (!startRead(&val)) {
return nullptr;
}
bool hasCause = ToBoolean(val);
if (!val.isBoolean()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_SC_BAD_SERIALIZED_DATA,
"hasCause must be a boolean");
return nullptr;
}
bool hasCause = val.toBoolean();
Rooted<Maybe<Value>> cause(cx, mozilla::Nothing());
if (hasCause) {
cause = mozilla::Some(BooleanValue(true));
@ -3873,6 +3886,12 @@ bool JSStructuredCloneReader::readErrorFields(Handle<ErrorObject*> errorObj,
}
if (errorObj->type() == JSEXN_AGGREGATEERR) {
if (!errors.isObject() || !errors.toObject().is<ArrayObject>()) {
JS_ReportErrorNumberASCII(
cx, GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
"AggregateError 'errors' field must be an Array");
return false;
}
if (!DefineDataProperty(context(), errorObj, cx->names().errors, errors,
0)) {
return false;

View file

@ -393,18 +393,18 @@ static int32_t PerformWait(Instance* instance, uint32_t memoryIndex,
PtrT byteOffset, ValT value, int64_t timeout_ns) {
JSContext* cx = instance->cx();
if (!instance->memory(memoryIndex)->isShared()) {
ReportTrapError(cx, JSMSG_WASM_NONSHARED_WAIT);
return -1;
}
if (byteOffset & (sizeof(ValT) - 1)) {
ReportTrapError(cx, JSMSG_WASM_UNALIGNED_ACCESS);
return -1;
}
if (byteOffset + sizeof(ValT) >
instance->memory(memoryIndex)->volatileMemoryLength()) {
if (!instance->memory(memoryIndex)->isShared()) {
ReportTrapError(cx, JSMSG_WASM_NONSHARED_WAIT);
return -1;
}
size_t memSizeBytes = instance->memory(memoryIndex)->volatileMemoryLength();
if (memSizeBytes < sizeof(ValT) || byteOffset > memSizeBytes - sizeof(ValT)) {
ReportTrapError(cx, JSMSG_WASM_OUT_OF_BOUNDS);
return -1;
}
@ -468,16 +468,14 @@ static int32_t PerformWake(Instance* instance, PtrT byteOffset, int32_t count,
uint32_t memoryIndex) {
JSContext* cx = instance->cx();
// The alignment guard is not in the wasm spec as of 2017-11-02, but is
// considered likely to appear, as 4-byte alignment is required for WAKE by
// the spec's validation algorithm.
if (byteOffset & 3) {
ReportTrapError(cx, JSMSG_WASM_UNALIGNED_ACCESS);
return -1;
}
if (byteOffset >= instance->memory(memoryIndex)->volatileMemoryLength()) {
size_t memSizeBytes = instance->memory(memoryIndex)->volatileMemoryLength();
if (memSizeBytes < sizeof(int32_t) ||
byteOffset > memSizeBytes - sizeof(int32_t)) {
ReportTrapError(cx, JSMSG_WASM_OUT_OF_BOUNDS);
return -1;
}

View file

@ -2009,6 +2009,15 @@ JSObject& WasmInstanceObject::exportsObj() const {
return getReservedSlot(EXPORTS_OBJ_SLOT).toObject();
}
WasmFunctionScope* WasmInstanceObject::getExistingFunctionScope(
uint32_t funcIndex) const {
if (auto p = scopes().asWasmFunctionScopeMap().lookup(funcIndex)) {
return p->value();
}
return nullptr;
}
WasmInstanceObject::UnspecifiedScopeMap& WasmInstanceObject::scopes() const {
return *(UnspecifiedScopeMap*)(getReservedSlot(SCOPES_SLOT).toPrivate());
}

View file

@ -223,6 +223,7 @@ class WasmInstanceObject : public NativeObject {
wasm::Instance& instance() const;
JSObject& exportsObj() const;
WasmFunctionScope* getExistingFunctionScope(uint32_t funcIndex) const;
[[nodiscard]] static bool getExportedFunction(
JSContext* cx, Handle<WasmInstanceObject*> instanceObj,

View file

@ -402,7 +402,7 @@ bool NewFunctionForwarder(JSContext* cx, HandleId idArg, HandleObject callable,
FunctionForwarderOptions& options,
MutableHandleValue vp) {
RootedId id(cx, idArg);
if (id.isVoid()) {
if (!id.isString()) {
id = GetJSIDByIndex(cx, XPCJSContext::IDX_EMPTYSTRING);
}
@ -501,7 +501,7 @@ bool ExportFunction(JSContext* cx, HandleValue vfunction, HandleValue vscope,
}
}
if (!funName) {
funName = JS_AtomizeAndPinString(cx, "");
funName = JS_GetEmptyString(cx);
}
JS_MarkCrossZoneIdValue(cx, StringValue(funName));
@ -511,7 +511,11 @@ bool ExportFunction(JSContext* cx, HandleValue vfunction, HandleValue vscope,
} else {
JS_MarkCrossZoneId(cx, id);
}
MOZ_ASSERT(id.isString());
if (!id.isString()) {
JS_ReportErrorASCII(cx, "defineAs must be a string");
return false;
}
// The function forwarder will live in the target compartment. Since
// this function will be referenced from its private slot, to avoid a

View file

@ -956,6 +956,8 @@ void XPCJSRuntime::WeakPointerZonesCallback(JSTracer* trc, void* data) {
self->mWrappedJSMap->UpdateWeakPointersAfterGC(trc);
self->mUAWidgetScopeMap.traceWeak(trc);
BrowsingContext::SweepWindowProxies(trc);
}
/* static */