icecat: add release icecat-140.6.0-1gnu1 for aramo

This commit is contained in:
Ark74 2026-01-17 18:56:47 -06:00
parent 92fef42cd6
commit 17ba0259bf
3382 changed files with 457689 additions and 569094 deletions

View file

@ -0,0 +1,18 @@
function check() {
for (let i = 1; i < 2000; i++) {
assertEq(Object(true) == 1n, true);
assertEq(1n == Object(true), true);
assertEq(Object(false) == 0n, true);
assertEq(0n == Object(false), true);
let called = false;
assertEq({ valueOf() { called = true; return 0; }} == 0n, true);
assertEq(called, true);
called = false;
assertEq(1n == { valueOf() { called = true; return 1; }}, true);
assertEq(called, true);
}
}
check();

View file

@ -5554,12 +5554,13 @@ bool SetPropIRGenerator::canAttachAddSlotStub(HandleObject obj, HandleId id) {
return false;
}
} else {
// Normal Case: If property exists this isn't an "add"
// Normal Case: If property exists or is an OOB typed array index, this
// isn't an "add".
PropertyResult prop;
if (!LookupOwnPropertyPure(cx_, nobj, id, &prop)) {
return false;
}
if (prop.isFound()) {
if (prop.isFound() || prop.isTypedArrayOutOfRange()) {
return false;
}
}
@ -5663,6 +5664,10 @@ AttachDecision SetPropIRGenerator::tryAttachAddSlotStub(
}
JSObject* obj = &lhsVal_.toObject();
if (!obj->is<NativeObject>()) {
return AttachDecision::NoAction;
}
NativeObject* nobj = &obj->as<NativeObject>();
PropertyResult prop;
if (!LookupOwnPropertyPure(cx_, obj, id, &prop)) {
@ -5672,11 +5677,7 @@ AttachDecision SetPropIRGenerator::tryAttachAddSlotStub(
return AttachDecision::NoAction;
}
if (!obj->is<NativeObject>()) {
return AttachDecision::NoAction;
}
auto* nobj = &obj->as<NativeObject>();
MOZ_RELEASE_ASSERT(prop.isNativeProperty());
PropertyInfo propInfo = prop.propertyInfo();
NativeObject* holder = nobj;
@ -5688,6 +5689,7 @@ AttachDecision SetPropIRGenerator::tryAttachAddSlotStub(
// The property must be the last added property of the object.
SharedShape* newShape = holder->sharedShape();
MOZ_RELEASE_ASSERT(oldShape != newShape);
MOZ_RELEASE_ASSERT(newShape->lastProperty() == propInfo);
#ifdef DEBUG

View file

@ -791,10 +791,10 @@ class MacroAssemblerRiscv64Compat : public MacroAssemblerRiscv64 {
void unboxGCThingForGCBarrier(const Address& src, Register dest) {
loadPtr(src, dest);
ExtractBits(dest, dest, 0, JSVAL_TAG_SHIFT - 1);
ExtractBits(dest, dest, 0, JSVAL_TAG_SHIFT);
}
void unboxGCThingForGCBarrier(const ValueOperand& src, Register dest) {
ExtractBits(dest, src.valueReg(), 0, JSVAL_TAG_SHIFT - 1);
ExtractBits(dest, src.valueReg(), 0, JSVAL_TAG_SHIFT);
}
void unboxWasmAnyRefGCThingForGCBarrier(const Address& src, Register dest) {

View file

@ -746,8 +746,10 @@ struct AssemblerBufferWithConstantPools
// secondary range veneers assuming the worst case deadlines.
// Total pending secondary range veneer size.
size_t secondaryVeneers = guardSize_ * (branchDeadlines_.size() -
branchDeadlines_.maxRangeSize());
size_t secondaryVeneers =
guardSize_ *
(branchDeadlines_.size() - branchDeadlines_.maxRangeSize()) *
InstSize;
if (deadline < poolEnd + secondaryVeneers) {
return false;

View file

@ -1838,24 +1838,24 @@ class BaseAssembler : public GenericAssembler {
void cmpb_rr(RegisterID rhs, RegisterID lhs) {
spew("cmpb %s, %s", GPReg8Name(rhs), GPReg8Name(lhs));
m_formatter.oneByteOp(OP_CMP_GbEb, rhs, lhs);
m_formatter.oneByteOp8(OP_CMP_GbEb, rhs, lhs);
}
void cmpb_rm(RegisterID rhs, int32_t offset, RegisterID base) {
spew("cmpb %s, " MEM_ob, GPReg8Name(rhs), ADDR_ob(offset, base));
m_formatter.oneByteOp(OP_CMP_EbGb, offset, base, rhs);
m_formatter.oneByteOp8(OP_CMP_EbGb, offset, base, rhs);
}
void cmpb_rm(RegisterID rhs, int32_t offset, RegisterID base,
RegisterID index, int scale) {
spew("cmpb %s, " MEM_obs, GPReg8Name(rhs),
ADDR_obs(offset, base, index, scale));
m_formatter.oneByteOp(OP_CMP_EbGb, offset, base, index, scale, rhs);
m_formatter.oneByteOp8(OP_CMP_EbGb, offset, base, index, scale, rhs);
}
void cmpb_rm(RegisterID rhs, const void* addr) {
spew("cmpb %s, %p", GPReg8Name(rhs), addr);
m_formatter.oneByteOp(OP_CMP_EbGb, addr, rhs);
m_formatter.oneByteOp8(OP_CMP_EbGb, addr, rhs);
}
void cmpb_ir(int32_t rhs, RegisterID lhs) {
@ -1866,9 +1866,9 @@ class BaseAssembler : public GenericAssembler {
spew("cmpb $0x%x, %s", uint32_t(rhs), GPReg8Name(lhs));
if (lhs == rax) {
m_formatter.oneByteOp(OP_CMP_EAXIb);
m_formatter.oneByteOp8(OP_CMP_EAXIb);
} else {
m_formatter.oneByteOp(OP_GROUP1_EbIb, lhs, GROUP1_OP_CMP);
m_formatter.oneByteOp8(OP_GROUP1_EbIb, lhs, GROUP1_OP_CMP);
}
m_formatter.immediate8(rhs);
}
@ -2054,7 +2054,7 @@ class BaseAssembler : public GenericAssembler {
void testb_rr(RegisterID rhs, RegisterID lhs) {
spew("testb %s, %s", GPReg8Name(rhs), GPReg8Name(lhs));
m_formatter.oneByteOp(OP_TEST_EbGb, lhs, rhs);
m_formatter.oneByteOp8(OP_TEST_EbGb, lhs, rhs);
}
void testl_ir(int32_t rhs, RegisterID lhs) {
@ -6095,6 +6095,13 @@ class BaseAssembler : public GenericAssembler {
m_buffer.putByteUnchecked(opcode + (r & 7));
}
void oneByteOp8(OneByteOpcodeID opcode, RegisterID rm, RegisterID reg) {
m_buffer.ensureSpace(MaxInstructionSize);
emitRexIf(byteRegRequiresRex(reg) || byteRegRequiresRex(rm), reg, 0, rm);
m_buffer.putByteUnchecked(opcode);
registerModRM(rm, reg);
}
void oneByteOp8(OneByteOpcodeID opcode, RegisterID rm,
GroupOpcodeID groupOp) {
m_buffer.ensureSpace(MaxInstructionSize);

View file

@ -17,6 +17,7 @@ UNIFIED_SOURCES += [
"testArrayBufferOrViewAPI.cpp",
"testArrayBufferView.cpp",
"testArrayBufferWithUserOwnedContents.cpp",
"testAssemblerCodeGen.cpp",
"testAtomicOperations.cpp",
"testAtomizeUtf8NonAsciiLatin1CodePoint.cpp",
"testAtomizeWithoutActiveZone.cpp",

View file

@ -0,0 +1,140 @@
/* -*- 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 "jit/Disassemble.h"
#include "jit/Linker.h"
#include "jit/MacroAssembler.h"
#include "js/GCAPI.h"
#include "jsapi-tests/tests.h"
#include "jsapi-tests/testsJit.h"
#include "jit/MacroAssembler-inl.h"
using namespace js;
using namespace js::jit;
#if defined(JS_JITSPEW) && defined(JS_CODEGEN_X64)
using DisasmCharVector = js::Vector<char, 64, SystemAllocPolicy>;
static MOZ_THREAD_LOCAL(DisasmCharVector*) disasmResult;
static void CaptureDisasmText(const char* text) {
// Skip the instruction offset (8 bytes) and two space characters, because the
// offsets make it harder to modify the test.
MOZ_RELEASE_ASSERT(strlen(text) > 10);
text = text + 10;
MOZ_RELEASE_ASSERT(disasmResult.get()->append(text, text + strlen(text)));
MOZ_RELEASE_ASSERT(disasmResult.get()->append('\n'));
}
BEGIN_TEST(testAssemblerCodeGen_x64_cmp8) {
TempAllocator tempAlloc(&cx->tempLifoAlloc());
JitContext jcx(cx);
StackMacroAssembler masm(cx, tempAlloc);
AutoCreatedBy acb(masm, __func__);
masm.cmp8(Operand(rax), rbx);
masm.cmp8(Operand(rax), rdi);
masm.cmp8(Operand(rdi), rax);
masm.cmp8(Operand(rdi), rdi);
masm.cmp8(Operand(r10), r13);
masm.cmp8(Operand(Address(rax, 0)), rbx);
masm.cmp8(Operand(Address(rax, 1)), rdi);
masm.cmp8(Operand(Address(rdi, 0x10)), rax);
masm.cmp8(Operand(Address(rdi, 0x20)), rdi);
masm.cmp8(Operand(Address(r10, 0x30)), r11);
masm.cmp8(Operand(Address(rsp, 0x40)), rdi);
masm.cmp8(Operand(BaseIndex(rax, rbx, TimesFour, 0)), rcx);
masm.cmp8(Operand(BaseIndex(rax, rbx, TimesEight, 1)), rdi);
masm.cmp8(Operand(BaseIndex(rdi, rax, TimesOne, 2)), rdi);
masm.cmp8(Operand(BaseIndex(rax, rdi, TimesTwo, 3)), rdi);
masm.cmp8(Operand(BaseIndex(r10, r11, TimesFour, 4)), r12);
masm.cmp8(Operand(BaseIndex(rsp, rax, TimesEight, 5)), rdi);
void* ptr = (void*)0x1234;
masm.cmp8(Operand(AbsoluteAddress(ptr)), rax);
masm.cmp8(Operand(AbsoluteAddress(ptr)), rsi);
masm.cmp8(Operand(AbsoluteAddress(ptr)), r15);
// For Imm32(0) we emit a |test| instruction.
masm.cmp8(Operand(rax), Imm32(0));
masm.cmp8(Operand(rbx), Imm32(0));
masm.cmp8(Operand(rdi), Imm32(0));
masm.cmp8(Operand(r8), Imm32(0));
masm.cmp8(Operand(rax), Imm32(1));
masm.cmp8(Operand(rbx), Imm32(-1));
masm.cmp8(Operand(rdi), Imm32(2));
masm.cmp8(Operand(r8), Imm32(-2));
CHECK(!masm.oom());
Linker linker(masm);
JitCode* code = linker.newCode(cx, CodeKind::Other);
CHECK(code);
DisasmCharVector disassembled;
disasmResult.set(&disassembled);
auto onFinish = mozilla::MakeScopeExit([&] { disasmResult.set(nullptr); });
{
// jit::Disassemble can't GC.
JS::AutoSuppressGCAnalysis nogc;
jit::Disassemble(code->raw(), code->instructionsSize(), &CaptureDisasmText);
}
static const char* expected =
"3a c3 cmp %bl, %al\n"
"40 3a c7 cmp %dil, %al\n"
"40 3a f8 cmp %al, %dil\n"
"40 3a ff cmp %dil, %dil\n"
"45 3a d5 cmp %r13b, %r10b\n"
"38 18 cmpb %bl, (%rax)\n"
"40 38 78 01 cmpb %dil, 0x01(%rax)\n"
"38 47 10 cmpb %al, 0x10(%rdi)\n"
"40 38 7f 20 cmpb %dil, 0x20(%rdi)\n"
"45 38 5a 30 cmpb %r11b, 0x30(%r10)\n"
"40 38 7c 24 40 cmpb %dil, 0x40(%rsp)\n"
"38 0c 98 cmpb %cl, (%rax,%rbx,4)\n"
"40 38 7c d8 01 cmpb %dil, 0x01(%rax,%rbx,8)\n"
"40 38 7c 07 02 cmpb %dil, 0x02(%rdi,%rax,1)\n"
"40 38 7c 78 03 cmpb %dil, 0x03(%rax,%rdi,2)\n"
"47 38 64 9a 04 cmpb %r12b, 0x04(%r10,%r11,4)\n"
"40 38 7c c4 05 cmpb %dil, 0x05(%rsp,%rax,8)\n"
"38 04 25 34 12 00 00 cmpb %al, 0x0000000000001234\n"
"40 38 34 25 34 12 00 00 cmpb %sil, 0x0000000000001234\n"
"44 38 3c 25 34 12 00 00 cmpb %r15b, 0x0000000000001234\n"
"84 c0 test %al, %al\n"
"84 db test %bl, %bl\n"
"40 84 ff test %dil, %dil\n"
"45 84 c0 test %r8b, %r8b\n"
"3c 01 cmp $0x01, %al\n"
"80 fb ff cmp $-0x01, %bl\n"
"40 80 ff 02 cmp $0x02, %dil\n"
"41 80 f8 fe cmp $-0x02, %r8b\n"
"0f 0b ud2\n";
bool matched = disassembled.length() == strlen(expected) &&
memcmp(expected, disassembled.begin(), strlen(expected)) == 0;
if (!matched) {
CHECK(disassembled.append('\0'));
fprintf(stderr, "Generated:\n%s\n", disassembled.begin());
fprintf(stderr, "Expected:\n%s\n", expected);
}
CHECK(matched);
return true;
}
END_TEST(testAssemblerCodeGen_x64_cmp8)
#endif // defined(JS_JITSPEW) && defined(JS_CODEGEN_X64)

View file

@ -3684,42 +3684,6 @@ JS::Result<bool> BigInt::equal(JSContext* cx, Handle<BigInt*> lhs,
return equal(lhs, rhsBigInt);
}
// BigInt proposal section 3.2.5
JS::Result<bool> BigInt::looselyEqual(JSContext* cx, HandleBigInt lhs,
HandleValue rhs) {
// Step 1.
if (rhs.isBigInt()) {
return equal(lhs, rhs.toBigInt());
}
// Steps 2-5 (not applicable).
// Steps 6-7.
if (rhs.isString()) {
RootedString rhsString(cx, rhs.toString());
return equal(cx, lhs, rhsString);
}
// Steps 8-9 (not applicable).
// Steps 10-11.
if (rhs.isObject()) {
RootedValue rhsPrimitive(cx, rhs);
if (!ToPrimitive(cx, &rhsPrimitive)) {
return cx->alreadyReportedError();
}
return looselyEqual(cx, lhs, rhsPrimitive);
}
// Step 12.
if (rhs.isNumber()) {
return equal(lhs, rhs.toNumber());
}
// Step 13.
return false;
}
// BigInt proposal section 1.1.12. BigInt::lessThan ( x, y )
bool BigInt::lessThan(const BigInt* x, const BigInt* y) {
return compare(x, y) < 0;

View file

@ -255,8 +255,6 @@ class BigInt final : public js::gc::CellWithLengthAndFlags {
static bool equal(const BigInt* lhs, double rhs);
static JS::Result<bool> equal(JSContext* cx, Handle<BigInt*> lhs,
HandleString rhs);
static JS::Result<bool> looselyEqual(JSContext* cx, Handle<BigInt*> lhs,
HandleValue rhs);
static bool lessThan(const BigInt* x, const BigInt* y);
// These methods return Nothing when the non-BigInt operand is NaN

View file

@ -78,37 +78,47 @@ static bool LooselyEqualBooleanAndOther(JSContext* cx,
return js::LooselyEqual(cx, lvalue, rval, result);
}
// ES6 draft rev32 7.2.12 Abstract Equality Comparison
// ES2026 Draft rev e936549f1c05ac1b206ad4c5817e77ee3ecbc787
//
// IsLooselyEqual ( x, y )
// https://tc39.es/ecma262/#sec-islooselyequal
bool js::LooselyEqual(JSContext* cx, JS::Handle<JS::Value> lval,
JS::Handle<JS::Value> rval, bool* result) {
// Step 3.
// Step 1. If SameType(x, y) is true, then
if (JS::SameType(lval, rval)) {
// Step 1.a. Return IsStrictlyEqual(x, y).
return EqualGivenSameType(cx, lval, rval, result);
}
// Handle int32 x double.
// NOTE: JS::SameType distinguishes between Int32 vs Double,
// but the spec's SameType doesn't.
if (lval.isNumber() && rval.isNumber()) {
*result = (lval.toNumber() == rval.toNumber());
return true;
}
// Step 4. This a bit more complex, because of the undefined emulating object.
// Step 2. If x is null and y is undefined, return true.
// Step 3. If x is undefined and y is null, return true.
// Step 4. Normative Optional
// If the host is a web browser or otherwise supports The
// [[IsHTMLDDA]] Internal Slot, then
// Step 4.a. If x is an Object, x has an [[IsHTMLDDA]] internal slot, and y
// is either undefined or null, return true.
// Step 4.b. If x is either undefined or null, y is an Object, and y has an
// [[IsHTMLDDA]] internal slot, return true.
if (lval.isNullOrUndefined()) {
// We can return early here, because null | undefined is only equal to the
// same set.
*result = rval.isNullOrUndefined() ||
(rval.isObject() && EmulatesUndefined(&rval.toObject()));
return true;
}
// Step 5.
if (rval.isNullOrUndefined()) {
MOZ_ASSERT(!lval.isNullOrUndefined());
*result = lval.isObject() && EmulatesUndefined(&lval.toObject());
return true;
}
// Step 6.
// Step 5. If x is a Number and y is a String, return ! IsLooselyEqual(x, !
// ToNumber(y)).
if (lval.isNumber() && rval.isString()) {
double num;
if (!StringToNumber(cx, rval.toString(), &num)) {
@ -118,7 +128,8 @@ bool js::LooselyEqual(JSContext* cx, JS::Handle<JS::Value> lval,
return true;
}
// Step 7.
// Step 6. If x is a String and y is a Number, return ! IsLooselyEqual(!
// ToNumber(x), y).
if (lval.isString() && rval.isNumber()) {
double num;
if (!StringToNumber(cx, lval.toString(), &num)) {
@ -128,18 +139,50 @@ bool js::LooselyEqual(JSContext* cx, JS::Handle<JS::Value> lval,
return true;
}
// Step 8.
// Step 7. If x is a BigInt and y is a String, then
if (lval.isBigInt() && rval.isString()) {
// Step 7.a. Let n be StringToBigInt(y).
BigInt* n;
JS::Rooted<JSString*> str(cx, rval.toString());
JS_TRY_VAR_OR_RETURN_FALSE(cx, n, StringToBigInt(cx, str));
if (!n) {
// Step 7.b. If n is undefined, return false.
*result = false;
return true;
}
// Step 7.c. Return ! IsLooselyEqual(x, n).
*result = JS::BigInt::equal(lval.toBigInt(), n);
return true;
}
// Step 8. If x is a String and y is a BigInt, return ! IsLooselyEqual(y,
// x).
if (lval.isString() && rval.isBigInt()) {
BigInt* n;
JS::Rooted<JSString*> str(cx, lval.toString());
JS_TRY_VAR_OR_RETURN_FALSE(cx, n, StringToBigInt(cx, str));
if (!n) {
*result = false;
return true;
}
*result = JS::BigInt::equal(rval.toBigInt(), n);
return true;
}
// Step 9. If x is a Boolean, return ! IsLooselyEqual(! ToNumber(x), y).
if (lval.isBoolean()) {
return LooselyEqualBooleanAndOther(cx, lval, rval, result);
}
// Step 9.
// Step 10. If y is a Boolean, return ! IsLooselyEqual(x, ! ToNumber(y)).
if (rval.isBoolean()) {
return LooselyEqualBooleanAndOther(cx, rval, lval, result);
}
// Step 10.
if ((lval.isString() || lval.isNumber() || lval.isSymbol()) &&
// Step 11. If x is either a String, a Number, a BigInt, or a Symbol and y
// is an Object, return ! IsLooselyEqual(x, ? ToPrimitive(y)).
if ((lval.isString() || lval.isNumber() || lval.isBigInt() ||
lval.isSymbol()) &&
rval.isObject()) {
JS::Rooted<JS::Value> rvalue(cx, rval);
if (!ToPrimitive(cx, &rvalue)) {
@ -148,9 +191,10 @@ bool js::LooselyEqual(JSContext* cx, JS::Handle<JS::Value> lval,
return js::LooselyEqual(cx, lval, rvalue, result);
}
// Step 11.
if (lval.isObject() &&
(rval.isString() || rval.isNumber() || rval.isSymbol())) {
// Step 12. If x is an Object and y is either a String, a Number, a BigInt,
// or a Symbol, return ! IsLooselyEqual(? ToPrimitive(x), y).
if (lval.isObject() && (rval.isString() || rval.isNumber() ||
rval.isBigInt() || rval.isSymbol())) {
JS::Rooted<JS::Value> lvalue(cx, lval);
if (!ToPrimitive(cx, &lvalue)) {
return false;
@ -158,25 +202,20 @@ bool js::LooselyEqual(JSContext* cx, JS::Handle<JS::Value> lval,
return js::LooselyEqual(cx, lvalue, rval, result);
}
if (lval.isBigInt()) {
JS::Rooted<JS::BigInt*> lbi(cx, lval.toBigInt());
bool tmpResult;
JS_TRY_VAR_OR_RETURN_FALSE(cx, tmpResult,
JS::BigInt::looselyEqual(cx, lbi, rval));
*result = tmpResult;
// Step 13. If x is a BigInt and y is a Number, or if x is a Number and y
// is a BigInt, then
if (lval.isBigInt() && rval.isNumber()) {
// Step 13.a. If x is not finite or y is not finite, return false.
// Step 13.b. If ℝ(x) = ℝ(y), return true; otherwise return false.
*result = BigInt::equal(lval.toBigInt(), rval.toNumber());
return true;
}
if (lval.isNumber() && rval.isBigInt()) {
*result = BigInt::equal(rval.toBigInt(), lval.toNumber());
return true;
}
if (rval.isBigInt()) {
JS::Rooted<JS::BigInt*> rbi(cx, rval.toBigInt());
bool tmpResult;
JS_TRY_VAR_OR_RETURN_FALSE(cx, tmpResult,
JS::BigInt::looselyEqual(cx, rbi, lval));
*result = tmpResult;
return true;
}
// Step 12.
// Step 14. Return false.
*result = false;
return true;
}

View file

@ -39,6 +39,7 @@
#include "vm/Shape.h"
#include "vm/StringType.h"
#include "vm/TypedArrayObject.h"
#include "vm/Watchtower.h"
#include "vm/NativeObject-inl.h"
#include "vm/PlainObject-inl.h" // js::PlainObject::createWithTemplate
@ -278,6 +279,10 @@ template <bool CheckForDuplicates>
bool PropertyEnumerator::enumerateNativeProperties(JSContext* cx) {
Handle<NativeObject*> pobj = obj_.as<NativeObject>();
if (Watchtower::watchesPropertyValueChange(pobj)) {
markIndicesUnsupported();
}
// We don't need to iterate over the shape's properties if we're only
// interested in enumerable properties and the object is known to have no
// enumerable properties.
@ -394,7 +399,7 @@ bool PropertyEnumerator::enumerateNativeProperties(JSContext* cx) {
continue;
}
PropertyIndex index = iter->isDataProperty()
PropertyIndex index = iter->isDataProperty() && iter->writable()
? PropertyIndex::ForSlot(pobj, iter->slot())
: PropertyIndex::Invalid();
if (!enumerate<CheckForDuplicates>(cx, id, iter->enumerable(), index)) {

View file

@ -176,6 +176,13 @@ class WasmArrayObject : public WasmGcObject,
return offsetToPointer<uint8_t>(offsetOfInlineStorage());
}
// Actual array data that follows DataHeader. The array data is a part of the
// `inlineStorage`.
template <typename T>
T* inlineArrayElements() {
return offsetToPointer<T>(offsetOfInlineArrayData());
}
// This tells us how big the object is if we know the number of inline bytes
// it was created with.
static inline constexpr size_t sizeOfIncludingInlineStorage(
@ -537,9 +544,8 @@ class MOZ_RAII StableWasmArrayObjectElements {
// elements.
MOZ_CRASH();
}
std::copy(array->inlineStorage(),
array->inlineStorage() + array->numElements_ * sizeof(T),
ownElements_->begin());
const T* src = array->inlineArrayElements<T>();
std::copy(src, src + array->numElements_, ownElements_->begin());
elements_ = ownElements_->begin();
} else {
elements_ = reinterpret_cast<T*>(array->data_);

View file

@ -1561,8 +1561,23 @@ WasmModuleObject* WasmModuleObject::create(JSContext* cx, const Module& module,
return obj;
}
static bool GetBufferSource(JSContext* cx, JSObject* obj, unsigned errorNumber,
BytecodeSource* bytecode) {
struct MOZ_STACK_CLASS AutoPinBufferSourceLength {
explicit AutoPinBufferSourceLength(JSContext* cx, JSObject* bufferSource)
: bufferSource_(cx, bufferSource),
wasPinned_(!JS::PinArrayBufferOrViewLength(bufferSource_, true)) {}
~AutoPinBufferSourceLength() {
if (!wasPinned_) {
JS::PinArrayBufferOrViewLength(bufferSource_, false);
}
}
private:
Rooted<JSObject*> bufferSource_;
bool wasPinned_;
};
static bool GetBytecodeSource(JSContext* cx, Handle<JSObject*> obj,
unsigned errorNumber, BytecodeSource* bytecode) {
JSObject* unwrapped = CheckedUnwrapStatic(obj);
SharedMem<uint8_t*> dataPointer;
@ -1578,6 +1593,20 @@ static bool GetBufferSource(JSContext* cx, JSObject* obj, unsigned errorNumber,
return true;
}
static bool GetBytecodeBuffer(JSContext* cx, Handle<JSObject*> obj,
unsigned errorNumber, BytecodeBuffer* bytecode) {
BytecodeSource source;
if (!GetBytecodeSource(cx, obj, errorNumber, &source)) {
return false;
}
AutoPinBufferSourceLength pin(cx, obj);
if (!BytecodeBuffer::fromSource(source, bytecode)) {
ReportOutOfMemory(cx);
return false;
}
return true;
}
static bool ReportCompileWarnings(JSContext* cx,
const UniqueCharsVector& warnings) {
// Avoid spamming the console.
@ -1634,12 +1663,6 @@ bool WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
BytecodeSource source;
if (!GetBufferSource(cx, &callArgs[0].toObject(), JSMSG_WASM_BAD_BUF_ARG,
&source)) {
return false;
}
FeatureOptions options;
if (!options.init(cx, callArgs.get(1))) {
return false;
@ -1651,10 +1674,20 @@ bool WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
BytecodeSource source;
Rooted<JSObject*> sourceObj(cx, &callArgs[0].toObject());
if (!GetBytecodeSource(cx, sourceObj, JSMSG_WASM_BAD_BUF_ARG, &source)) {
return false;
}
UniqueChars error;
UniqueCharsVector warnings;
SharedModule module = CompileBuffer(
*compileArgs, BytecodeBufferOrSource(source), &error, &warnings, nullptr);
SharedModule module;
{
AutoPinBufferSourceLength pin(cx, sourceObj.get());
module = CompileBuffer(*compileArgs, BytecodeBufferOrSource(source), &error,
&warnings, nullptr);
}
if (!ReportCompileWarnings(cx, warnings)) {
return false;
@ -4504,22 +4537,6 @@ static bool EnsurePromiseSupport(JSContext* cx) {
return true;
}
static bool GetBufferSource(JSContext* cx, const CallArgs& callArgs,
const char* name, BytecodeSource* bytecode) {
if (!callArgs.requireAtLeast(cx, name, 1)) {
return false;
}
if (!callArgs[0].isObject()) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_BUF_ARG);
return false;
}
return GetBufferSource(cx, &callArgs[0].toObject(), JSMSG_WASM_BAD_BUF_ARG,
bytecode);
}
static bool WebAssembly_compile(JSContext* cx, unsigned argc, Value* vp) {
if (!EnsurePromiseSupport(cx)) {
return false;
@ -4554,18 +4571,25 @@ static bool WebAssembly_compile(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
BytecodeSource source;
if (!GetBufferSource(cx, callArgs, "WebAssembly.compile", &source)) {
if (!callArgs.requireAtLeast(cx, "WebAssembly.compile", 1)) {
return RejectWithPendingException(cx, promise, callArgs);
}
if (!BytecodeBuffer::fromSource(source, &task->bytecode)) {
ReportOutOfMemory(cx);
return false;
}
FeatureOptions options;
if (!options.init(cx, callArgs.get(1))) {
return false;
return RejectWithPendingException(cx, promise, callArgs);
}
if (!callArgs[0].isObject()) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_BUF_ARG);
return RejectWithPendingException(cx, promise, callArgs);
}
Rooted<JSObject*> sourceObj(cx, &callArgs[0].toObject());
if (!GetBytecodeBuffer(cx, sourceObj, JSMSG_WASM_BAD_BUF_ARG,
&task->bytecode)) {
return RejectWithPendingException(cx, promise, callArgs);
}
if (!task->init(cx, options, "WebAssembly.compile")) {
@ -4658,14 +4682,10 @@ static bool WebAssembly_instantiate(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
BytecodeSource source;
if (!GetBufferSource(cx, firstArg, JSMSG_WASM_BAD_BUF_MOD_ARG, &source)) {
if (!GetBytecodeBuffer(cx, firstArg, JSMSG_WASM_BAD_BUF_MOD_ARG,
&task->bytecode)) {
return RejectWithPendingException(cx, promise, callArgs);
}
if (!BytecodeBuffer::fromSource(source, &task->bytecode)) {
ReportOutOfMemory(cx);
return false;
}
if (!StartOffThreadPromiseHelperTask(cx, std::move(task))) {
return false;
@ -4679,8 +4699,7 @@ static bool WebAssembly_instantiate(JSContext* cx, unsigned argc, Value* vp) {
static bool WebAssembly_validate(JSContext* cx, unsigned argc, Value* vp) {
CallArgs callArgs = CallArgsFromVp(argc, vp);
BytecodeSource source;
if (!GetBufferSource(cx, callArgs, "WebAssembly.validate", &source)) {
if (!callArgs.requireAtLeast(cx, "WebAssembly.validate", 1)) {
return false;
}
@ -4689,8 +4708,24 @@ static bool WebAssembly_validate(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
if (!callArgs[0].isObject()) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_BUF_ARG);
return false;
}
BytecodeSource source;
Rooted<JSObject*> sourceObj(cx, &callArgs[0].toObject());
if (!GetBytecodeSource(cx, sourceObj, JSMSG_WASM_BAD_BUF_ARG, &source)) {
return false;
}
UniqueChars error;
bool validated = Validate(cx, source, options, &error);
bool validated;
{
AutoPinBufferSourceLength pin(cx, sourceObj.get());
validated = Validate(cx, source, options, &error);
}
// If the reason for validation failure was OOM (signalled by null error
// message), report out-of-memory so that validate's return is always