commit 9779e5a7bb690b9963473bdf110e6568225e9f34
parent 07ff869641bfdaa1cc898d71d3cc904d4c680fef
Author: André Bargull <andre.bargull@gmail.com>
Date: Tue, 21 Oct 2025 07:05:41 +0000
Bug 1991402 - Part 9: Convert TypedArray getters. r=jandem
Differential Revision: https://phabricator.services.mozilla.com/D266601
Diffstat:
6 files changed, 149 insertions(+), 126 deletions(-)
diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp
@@ -465,7 +465,6 @@ AttachDecision GetPropIRGenerator::tryAttachStub() {
if (nameOrSymbol) {
TRY_ATTACH(tryAttachObjectLength(obj, objId, id));
- TRY_ATTACH(tryAttachTypedArray(obj, objId, id));
TRY_ATTACH(tryAttachDataView(obj, objId, id));
TRY_ATTACH(tryAttachArrayBufferMaybeShared(obj, objId, id));
TRY_ATTACH(tryAttachRegExp(obj, objId, id));
@@ -2464,105 +2463,6 @@ AttachDecision GetPropIRGenerator::tryAttachInlinableNativeGetter(
return nativeGen.tryAttachStub();
}
-AttachDecision GetPropIRGenerator::tryAttachTypedArray(HandleObject obj,
- ObjOperandId objId,
- HandleId id) {
- if (!obj->is<TypedArrayObject>()) {
- return AttachDecision::NoAction;
- }
-
- if (mode_ != ICState::Mode::Specialized) {
- return AttachDecision::NoAction;
- }
-
- // Receiver should be the object.
- if (isSuper()) {
- return AttachDecision::NoAction;
- }
-
- bool isLength = id.isAtom(cx_->names().length);
- bool isByteOffset = id.isAtom(cx_->names().byteOffset);
- if (!isLength && !isByteOffset && !id.isAtom(cx_->names().byteLength)) {
- return AttachDecision::NoAction;
- }
-
- NativeObject* holder = nullptr;
- Maybe<PropertyInfo> prop;
- NativeGetPropKind kind =
- CanAttachNativeGetProp(cx_, obj, id, &holder, &prop, pc_);
- if (kind != NativeGetPropKind::NativeGetter) {
- return AttachDecision::NoAction;
- }
-
- JSFunction& fun = holder->getGetter(*prop)->as<JSFunction>();
- if (isLength) {
- if (!TypedArrayObject::isOriginalLengthGetter(fun.native())) {
- return AttachDecision::NoAction;
- }
- } else if (isByteOffset) {
- if (!TypedArrayObject::isOriginalByteOffsetGetter(fun.native())) {
- return AttachDecision::NoAction;
- }
- } else {
- if (!TypedArrayObject::isOriginalByteLengthGetter(fun.native())) {
- return AttachDecision::NoAction;
- }
- }
-
- auto* tarr = &obj->as<TypedArrayObject>();
-
- maybeEmitIdGuard(id);
- // Emit all the normal guards for calling this native, but specialize
- // callNativeGetterResult.
- emitCallGetterResultGuards(tarr, holder, id, *prop, objId);
- if (isLength) {
- size_t length = tarr->length().valueOr(0);
- if (!tarr->is<ResizableTypedArrayObject>()) {
- if (length <= INT32_MAX) {
- writer.loadArrayBufferViewLengthInt32Result(objId);
- } else {
- writer.loadArrayBufferViewLengthDoubleResult(objId);
- }
- } else {
- if (length <= INT32_MAX) {
- writer.resizableTypedArrayLengthInt32Result(objId);
- } else {
- writer.resizableTypedArrayLengthDoubleResult(objId);
- }
- }
- trackAttached("GetProp.TypedArrayLength");
- } else if (isByteOffset) {
- // byteOffset doesn't need to use different code paths for fixed-length and
- // resizable TypedArrays.
- size_t byteOffset = tarr->byteOffset().valueOr(0);
- if (byteOffset <= INT32_MAX) {
- writer.arrayBufferViewByteOffsetInt32Result(objId);
- } else {
- writer.arrayBufferViewByteOffsetDoubleResult(objId);
- }
- trackAttached("GetProp.TypedArrayByteOffset");
- } else {
- size_t byteLength = tarr->byteLength().valueOr(0);
- if (!tarr->is<ResizableTypedArrayObject>()) {
- if (byteLength <= INT32_MAX) {
- writer.typedArrayByteLengthInt32Result(objId);
- } else {
- writer.typedArrayByteLengthDoubleResult(objId);
- }
- } else {
- if (byteLength <= INT32_MAX) {
- writer.resizableTypedArrayByteLengthInt32Result(objId);
- } else {
- writer.resizableTypedArrayByteLengthDoubleResult(objId);
- }
- }
- trackAttached("GetProp.TypedArrayByteLength");
- }
- writer.returnFromIC();
-
- return AttachDecision::Attach;
-}
-
AttachDecision GetPropIRGenerator::tryAttachDataView(HandleObject obj,
ObjOperandId objId,
HandleId id) {
@@ -11757,6 +11657,135 @@ AttachDecision InlinableNativeIRGenerator::tryAttachTypedArraySubarray() {
return AttachDecision::Attach;
}
+AttachDecision InlinableNativeIRGenerator::tryAttachTypedArrayLength() {
+ // Expecting no arguments.
+ if (args_.length() != 0) {
+ return AttachDecision::NoAction;
+ }
+
+ // Ensure |this| is a TypedArrayObject.
+ if (!thisval_.isObject() || !thisval_.toObject().is<TypedArrayObject>()) {
+ return AttachDecision::NoAction;
+ }
+
+ auto* tarr = &thisval_.toObject().as<TypedArrayObject>();
+
+ // Initialize the input operand.
+ Int32OperandId argcId = initializeInputOperand();
+
+ // Guard callee is the 'length' native function.
+ ObjOperandId calleeId = emitNativeCalleeGuard(argcId);
+
+ // Guard |this| is a TypedArrayObject.
+ ValOperandId thisValId = loadThis(calleeId);
+ ObjOperandId objId = writer.guardToObject(thisValId);
+ writer.guardShapeForClass(objId, tarr->shape());
+
+ size_t length = tarr->length().valueOr(0);
+ if (!tarr->is<ResizableTypedArrayObject>()) {
+ if (length <= INT32_MAX) {
+ writer.loadArrayBufferViewLengthInt32Result(objId);
+ } else {
+ writer.loadArrayBufferViewLengthDoubleResult(objId);
+ }
+ } else {
+ if (length <= INT32_MAX) {
+ writer.resizableTypedArrayLengthInt32Result(objId);
+ } else {
+ writer.resizableTypedArrayLengthDoubleResult(objId);
+ }
+ }
+
+ writer.returnFromIC();
+
+ trackAttached("TypedArrayLength");
+ return AttachDecision::Attach;
+}
+
+AttachDecision InlinableNativeIRGenerator::tryAttachTypedArrayByteLength() {
+ // Expecting no arguments.
+ if (args_.length() != 0) {
+ return AttachDecision::NoAction;
+ }
+
+ // Ensure |this| is a TypedArrayObject.
+ if (!thisval_.isObject() || !thisval_.toObject().is<TypedArrayObject>()) {
+ return AttachDecision::NoAction;
+ }
+
+ auto* tarr = &thisval_.toObject().as<TypedArrayObject>();
+
+ // Initialize the input operand.
+ Int32OperandId argcId = initializeInputOperand();
+
+ // Guard callee is the 'byteLength' native function.
+ ObjOperandId calleeId = emitNativeCalleeGuard(argcId);
+
+ // Guard |this| is a TypedArrayObject.
+ ValOperandId thisValId = loadThis(calleeId);
+ ObjOperandId objId = writer.guardToObject(thisValId);
+ writer.guardShapeForClass(objId, tarr->shape());
+
+ size_t byteLength = tarr->byteLength().valueOr(0);
+ if (!tarr->is<ResizableTypedArrayObject>()) {
+ if (byteLength <= INT32_MAX) {
+ writer.typedArrayByteLengthInt32Result(objId);
+ } else {
+ writer.typedArrayByteLengthDoubleResult(objId);
+ }
+ } else {
+ if (byteLength <= INT32_MAX) {
+ writer.resizableTypedArrayByteLengthInt32Result(objId);
+ } else {
+ writer.resizableTypedArrayByteLengthDoubleResult(objId);
+ }
+ }
+
+ writer.returnFromIC();
+
+ trackAttached("TypedArrayByteLength");
+ return AttachDecision::Attach;
+}
+
+AttachDecision InlinableNativeIRGenerator::tryAttachTypedArrayByteOffset() {
+ // Expecting no arguments.
+ if (args_.length() != 0) {
+ return AttachDecision::NoAction;
+ }
+
+ // Ensure |this| is a TypedArrayObject.
+ if (!thisval_.isObject() || !thisval_.toObject().is<TypedArrayObject>()) {
+ return AttachDecision::NoAction;
+ }
+
+ auto* tarr = &thisval_.toObject().as<TypedArrayObject>();
+
+ // Initialize the input operand.
+ Int32OperandId argcId = initializeInputOperand();
+
+ // Guard callee is the 'byteLength' native function.
+ ObjOperandId calleeId = emitNativeCalleeGuard(argcId);
+
+ // Guard |this| is a TypedArrayObject.
+ ValOperandId thisValId = loadThis(calleeId);
+ ObjOperandId objId = writer.guardToObject(thisValId);
+ writer.guardShapeForClass(objId, tarr->shape());
+
+ // byteOffset doesn't need to use different code paths for fixed-length and
+ // resizable TypedArrays.
+ size_t byteOffset = tarr->byteOffset().valueOr(0);
+ if (byteOffset <= INT32_MAX) {
+ writer.arrayBufferViewByteOffsetInt32Result(objId);
+ } else {
+ writer.arrayBufferViewByteOffsetDoubleResult(objId);
+ }
+
+ writer.returnFromIC();
+
+ trackAttached("TypedArrayByteOffset");
+ return AttachDecision::Attach;
+}
+
AttachDecision InlinableNativeIRGenerator::tryAttachIsTypedArray(
bool isPossiblyWrapped) {
// Self-hosted code calls this with a single object argument.
@@ -13334,6 +13363,12 @@ AttachDecision InlinableNativeIRGenerator::tryAttachStub() {
return tryAttachTypedArraySet();
case InlinableNative::TypedArraySubarray:
return tryAttachTypedArraySubarray();
+ case InlinableNative::TypedArrayLength:
+ return tryAttachTypedArrayLength();
+ case InlinableNative::TypedArrayByteLength:
+ return tryAttachTypedArrayByteLength();
+ case InlinableNative::TypedArrayByteOffset:
+ return tryAttachTypedArrayByteOffset();
// TypedArray intrinsics.
case InlinableNative::IntrinsicIsTypedArray:
diff --git a/js/src/jit/CacheIRGenerator.h b/js/src/jit/CacheIRGenerator.h
@@ -176,8 +176,6 @@ class MOZ_RAII GetPropIRGenerator : public IRGenerator {
ValOperandId receiverId);
AttachDecision tryAttachObjectLength(HandleObject obj, ObjOperandId objId,
HandleId id);
- AttachDecision tryAttachTypedArray(HandleObject obj, ObjOperandId objId,
- HandleId id);
AttachDecision tryAttachDataView(HandleObject obj, ObjOperandId objId,
HandleId id);
AttachDecision tryAttachArrayBufferMaybeShared(HandleObject obj,
@@ -832,6 +830,9 @@ class MOZ_RAII InlinableNativeIRGenerator {
AttachDecision tryAttachTypedArrayFill();
AttachDecision tryAttachTypedArraySet();
AttachDecision tryAttachTypedArraySubarray();
+ AttachDecision tryAttachTypedArrayLength();
+ AttachDecision tryAttachTypedArrayByteLength();
+ AttachDecision tryAttachTypedArrayByteOffset();
AttachDecision tryAttachIsTypedArray(bool isPossiblyWrapped);
AttachDecision tryAttachIsTypedArrayConstructor();
AttachDecision tryAttachTypedArrayLength(bool isPossiblyWrapped);
diff --git a/js/src/jit/InlinableNatives.cpp b/js/src/jit/InlinableNatives.cpp
@@ -358,6 +358,9 @@ bool js::jit::CanInlineNativeCrossRealm(InlinableNative native) {
case InlinableNative::TypedArrayFill:
case InlinableNative::TypedArraySet:
case InlinableNative::TypedArraySubarray:
+ case InlinableNative::TypedArrayLength:
+ case InlinableNative::TypedArrayByteLength:
+ case InlinableNative::TypedArrayByteOffset:
case InlinableNative::WeakMapGet:
case InlinableNative::WeakMapHas:
case InlinableNative::WeakSetHas:
diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h
@@ -204,6 +204,9 @@
_(TypedArrayFill) \
_(TypedArraySet) \
_(TypedArraySubarray) \
+ _(TypedArrayLength) \
+ _(TypedArrayByteLength) \
+ _(TypedArrayByteOffset) \
\
_(TestBailout) \
_(TestAssertFloat32) \
diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp
@@ -1840,10 +1840,12 @@ static bool TypedArray_toStringTagGetter(JSContext* cx, unsigned argc,
}
/* static */ const JSPropertySpec TypedArrayObject::protoAccessors[] = {
- JS_PSG("length", TypedArray_lengthGetter, 0),
+ JS_INLINABLE_PSG("length", TypedArray_lengthGetter, 0, TypedArrayLength),
JS_PSG("buffer", TypedArray_bufferGetter, 0),
- JS_PSG("byteLength", TypedArray_byteLengthGetter, 0),
- JS_PSG("byteOffset", TypedArray_byteOffsetGetter, 0),
+ JS_INLINABLE_PSG("byteLength", TypedArray_byteLengthGetter, 0,
+ TypedArrayByteLength),
+ JS_INLINABLE_PSG("byteOffset", TypedArray_byteOffsetGetter, 0,
+ TypedArrayByteOffset),
JS_SYM_GET(toStringTag, TypedArray_toStringTagGetter, 0),
JS_PS_END,
};
@@ -6186,21 +6188,6 @@ const JSClass TypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType] = {
#undef IMPL_TYPED_ARRAY_PROTO_CLASS
};
-/* static */
-bool TypedArrayObject::isOriginalLengthGetter(Native native) {
- return native == TypedArray_lengthGetter;
-}
-
-/* static */
-bool TypedArrayObject::isOriginalByteOffsetGetter(Native native) {
- return native == TypedArray_byteOffsetGetter;
-}
-
-/* static */
-bool TypedArrayObject::isOriginalByteLengthGetter(Native native) {
- return native == TypedArray_byteLengthGetter;
-}
-
bool js::IsTypedArrayConstructor(const JSObject* obj) {
#define CHECK_TYPED_ARRAY_CONSTRUCTOR(_, T, N) \
if (IsNativeFunction(obj, TypedArrayObjectTemplate<T>::class_constructor)) { \
diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h
@@ -136,12 +136,6 @@ class TypedArrayObject : public ArrayBufferViewObject {
// Maximum allowed byte length for any typed array.
static constexpr size_t ByteLengthLimit = ArrayBufferObject::ByteLengthLimit;
- static bool isOriginalLengthGetter(Native native);
-
- static bool isOriginalByteOffsetGetter(Native native);
-
- static bool isOriginalByteLengthGetter(Native native);
-
/* Accessors and functions */
static bool sort(JSContext* cx, unsigned argc, Value* vp);