icecat: add release icecat-140.6.0-1gnu1 for aramo
This commit is contained in:
parent
92fef42cd6
commit
17ba0259bf
3382 changed files with 457689 additions and 569094 deletions
18
icecat/js/src/jit-test/tests/bigint/loosely-equal.js
Normal file
18
icecat/js/src/jit-test/tests/bigint/loosely-equal.js
Normal 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();
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ UNIFIED_SOURCES += [
|
|||
"testArrayBufferOrViewAPI.cpp",
|
||||
"testArrayBufferView.cpp",
|
||||
"testArrayBufferWithUserOwnedContents.cpp",
|
||||
"testAssemblerCodeGen.cpp",
|
||||
"testAtomicOperations.cpp",
|
||||
"testAtomizeUtf8NonAsciiLatin1CodePoint.cpp",
|
||||
"testAtomizeWithoutActiveZone.cpp",
|
||||
|
|
|
|||
140
icecat/js/src/jsapi-tests/testAssemblerCodeGen.cpp
Normal file
140
icecat/js/src/jsapi-tests/testAssemblerCodeGen.cpp
Normal 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)
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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_);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue