commit 99d7fb18a57a0696df663401f4a229727676cf13
parent 2cf5974bdb57bcd4ab0032929e0b6c19d70e65fb
Author: André Bargull <andre.bargull@gmail.com>
Date: Mon, 20 Oct 2025 12:27:42 +0000
Bug 1991402 - Part 10: Convert DataView getters. r=jandem
Differential Revision: https://phabricator.services.mozilla.com/D266602
Diffstat:
6 files changed, 179 insertions(+), 132 deletions(-)
diff --git a/js/src/builtin/DataViewObject.cpp b/js/src/builtin/DataViewObject.cpp
@@ -1211,8 +1211,10 @@ const JSFunctionSpec DataViewObject::methods[] = {
const JSPropertySpec DataViewObject::properties[] = {
JS_PSG("buffer", DataViewObject::bufferGetter, 0),
- JS_PSG("byteLength", DataViewObject::byteLengthGetter, 0),
- JS_PSG("byteOffset", DataViewObject::byteOffsetGetter, 0),
+ JS_INLINABLE_PSG("byteLength", DataViewObject::byteLengthGetter, 0,
+ DataViewByteLength),
+ JS_INLINABLE_PSG("byteOffset", DataViewObject::byteOffsetGetter, 0,
+ DataViewByteOffset),
JS_STRING_SYM_PS(toStringTag, "DataView", JSPROP_READONLY),
JS_PS_END,
};
diff --git a/js/src/builtin/DataViewObject.h b/js/src/builtin/DataViewObject.h
@@ -81,14 +81,6 @@ class DataViewObject : public ArrayBufferViewObject {
return endOffset.isValid() && endOffset.value() <= byteLength;
}
- static bool isOriginalByteOffsetGetter(Native native) {
- return native == byteOffsetGetter;
- }
-
- static bool isOriginalByteLengthGetter(Native native) {
- return native == byteLengthGetter;
- }
-
static bool construct(JSContext* cx, unsigned argc, Value* vp);
static bool getInt8Impl(JSContext* cx, const CallArgs& args);
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(tryAttachDataView(obj, objId, id));
TRY_ATTACH(tryAttachArrayBufferMaybeShared(obj, objId, id));
TRY_ATTACH(tryAttachRegExp(obj, objId, id));
TRY_ATTACH(tryAttachNative(obj, objId, id, receiverId));
@@ -2463,115 +2462,6 @@ AttachDecision GetPropIRGenerator::tryAttachInlinableNativeGetter(
return nativeGen.tryAttachStub();
}
-AttachDecision GetPropIRGenerator::tryAttachDataView(HandleObject obj,
- ObjOperandId objId,
- HandleId id) {
- if (!obj->is<DataViewObject>()) {
- return AttachDecision::NoAction;
- }
- auto* dv = &obj->as<DataViewObject>();
-
- if (mode_ != ICState::Mode::Specialized) {
- return AttachDecision::NoAction;
- }
-
- // Receiver should be the object.
- if (isSuper()) {
- return AttachDecision::NoAction;
- }
-
- bool isByteOffset = id.isAtom(cx_->names().byteOffset);
- if (!isByteOffset && !id.isAtom(cx_->names().byteLength)) {
- return AttachDecision::NoAction;
- }
-
- // byteOffset and byteLength both throw when the ArrayBuffer is detached.
- if (dv->hasDetachedBuffer()) {
- // The has-attached-arraybuffer guard is elided for immutable views. Assert
- // we never see an immutable view with a detached buffer.
- MOZ_ASSERT(!dv->is<ImmutableDataViewObject>(),
- "immutable data views can't have their buffer detached");
- return AttachDecision::NoAction;
- }
-
- // byteOffset and byteLength both throw when the ArrayBuffer is out-of-bounds.
- if (dv->is<ResizableDataViewObject>() &&
- dv->as<ResizableDataViewObject>().isOutOfBounds()) {
- 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;
- }
-
- auto& fun = holder->getGetter(*prop)->as<JSFunction>();
- if (isByteOffset) {
- if (!DataViewObject::isOriginalByteOffsetGetter(fun.native())) {
- return AttachDecision::NoAction;
- }
- } else {
- if (!DataViewObject::isOriginalByteLengthGetter(fun.native())) {
- return AttachDecision::NoAction;
- }
- }
-
- maybeEmitIdGuard(id);
- // Emit all the normal guards for calling this native, but specialize
- // callNativeGetterResult.
- emitCallGetterResultGuards(dv, holder, id, *prop, objId);
-
- // Immutable array buffers can never get detached.
- if (!dv->is<ImmutableDataViewObject>()) {
- writer.guardHasAttachedArrayBuffer(objId);
- } else {
-#ifdef DEBUG
- // Add a guard in debug-mode, so if the buffer unexpectedly got detached,
- // we bail out and rely on the above assertion to fire.
- writer.guardHasAttachedArrayBuffer(objId);
-#endif
- }
-
- // Resizable array buffers can get out-of-bounds when shrunk.
- if (dv->is<ResizableDataViewObject>()) {
- writer.guardResizableArrayBufferViewInBounds(objId);
- }
-
- if (isByteOffset) {
- // byteOffset doesn't need to use different code paths for fixed-length,
- // resizable, or immutable DataViews.
- size_t byteOffset = dv->byteOffset().valueOr(0);
- if (byteOffset <= INT32_MAX) {
- writer.arrayBufferViewByteOffsetInt32Result(objId);
- } else {
- writer.arrayBufferViewByteOffsetDoubleResult(objId);
- }
- trackAttached("GetProp.DataViewByteOffset");
- } else {
- size_t byteLength = dv->byteLength().valueOr(0);
- if (!dv->is<ResizableDataViewObject>()) {
- if (byteLength <= INT32_MAX) {
- writer.loadArrayBufferViewLengthInt32Result(objId);
- } else {
- writer.loadArrayBufferViewLengthDoubleResult(objId);
- }
- } else {
- if (byteLength <= INT32_MAX) {
- writer.resizableDataViewByteLengthInt32Result(objId);
- } else {
- writer.resizableDataViewByteLengthDoubleResult(objId);
- }
- }
- trackAttached("GetProp.DataViewByteLength");
- }
- writer.returnFromIC();
-
- return AttachDecision::Attach;
-}
-
AttachDecision GetPropIRGenerator::tryAttachArrayBufferMaybeShared(
HandleObject obj, ObjOperandId objId, HandleId id) {
if (!obj->is<ArrayBufferObjectMaybeShared>()) {
@@ -7135,14 +7025,11 @@ AttachDecision InlinableNativeIRGenerator::tryAttachDataViewGet(
ObjOperandId objId = writer.guardToObject(thisValId);
if (dv->is<FixedLengthDataViewObject>()) {
- emitOptimisticClassGuard(objId, &thisval_.toObject(),
- GuardClassKind::FixedLengthDataView);
+ emitOptimisticClassGuard(objId, dv, GuardClassKind::FixedLengthDataView);
} else if (dv->is<ImmutableDataViewObject>()) {
- emitOptimisticClassGuard(objId, &thisval_.toObject(),
- GuardClassKind::ImmutableDataView);
+ emitOptimisticClassGuard(objId, dv, GuardClassKind::ImmutableDataView);
} else {
- emitOptimisticClassGuard(objId, &thisval_.toObject(),
- GuardClassKind::ResizableDataView);
+ emitOptimisticClassGuard(objId, dv, GuardClassKind::ResizableDataView);
}
// Convert offset to intPtr.
@@ -7215,11 +7102,9 @@ AttachDecision InlinableNativeIRGenerator::tryAttachDataViewSet(
ObjOperandId objId = writer.guardToObject(thisValId);
if (dv->is<FixedLengthDataViewObject>()) {
- emitOptimisticClassGuard(objId, &thisval_.toObject(),
- GuardClassKind::FixedLengthDataView);
+ emitOptimisticClassGuard(objId, dv, GuardClassKind::FixedLengthDataView);
} else {
- emitOptimisticClassGuard(objId, &thisval_.toObject(),
- GuardClassKind::ResizableDataView);
+ emitOptimisticClassGuard(objId, dv, GuardClassKind::ResizableDataView);
}
// Convert offset to intPtr.
@@ -7249,6 +7134,166 @@ AttachDecision InlinableNativeIRGenerator::tryAttachDataViewSet(
return AttachDecision::Attach;
}
+AttachDecision InlinableNativeIRGenerator::tryAttachDataViewByteLength() {
+ // Expecting no arguments.
+ if (args_.length() != 0) {
+ return AttachDecision::NoAction;
+ }
+
+ // Ensure |this| is a DataViewObject.
+ if (!thisval_.isObject() || !thisval_.toObject().is<DataViewObject>()) {
+ return AttachDecision::NoAction;
+ }
+
+ auto* dv = &thisval_.toObject().as<DataViewObject>();
+
+ // byteLength throws when the ArrayBuffer is detached.
+ if (dv->hasDetachedBuffer()) {
+ // The has-attached-arraybuffer guard is elided for immutable views. Assert
+ // we never see an immutable view with a detached buffer.
+ MOZ_ASSERT(!dv->is<ImmutableDataViewObject>(),
+ "immutable data views can't have their buffer detached");
+ return AttachDecision::NoAction;
+ }
+
+ // byteLength throws when the ArrayBuffer is out-of-bounds.
+ if (dv->is<ResizableDataViewObject>() &&
+ dv->as<ResizableDataViewObject>().isOutOfBounds()) {
+ return AttachDecision::NoAction;
+ }
+
+ // Initialize the input operand.
+ Int32OperandId argcId = initializeInputOperand();
+
+ // Guard callee is the 'byteLength' native function.
+ ObjOperandId calleeId = emitNativeCalleeGuard(argcId);
+
+ // Guard |this| is a DataViewObject.
+ ValOperandId thisValId = loadThis(calleeId);
+ ObjOperandId objId = writer.guardToObject(thisValId);
+
+ if (dv->is<FixedLengthDataViewObject>()) {
+ emitOptimisticClassGuard(objId, dv, GuardClassKind::FixedLengthDataView);
+ } else if (dv->is<ImmutableDataViewObject>()) {
+ emitOptimisticClassGuard(objId, dv, GuardClassKind::ImmutableDataView);
+ } else {
+ emitOptimisticClassGuard(objId, dv, GuardClassKind::ResizableDataView);
+ }
+
+ // Immutable array buffers can never get detached.
+ if (!dv->is<ImmutableDataViewObject>()) {
+ writer.guardHasAttachedArrayBuffer(objId);
+ } else {
+#ifdef DEBUG
+ // Add a guard in debug-mode, so if the buffer unexpectedly got detached,
+ // we bail out and rely on the above assertion to fire.
+ writer.guardHasAttachedArrayBuffer(objId);
+#endif
+ }
+
+ // Resizable array buffers can get out-of-bounds when shrunk.
+ if (dv->is<ResizableDataViewObject>()) {
+ writer.guardResizableArrayBufferViewInBounds(objId);
+ }
+
+ size_t byteLength = dv->byteLength().valueOr(0);
+ if (!dv->is<ResizableDataViewObject>()) {
+ if (byteLength <= INT32_MAX) {
+ writer.loadArrayBufferViewLengthInt32Result(objId);
+ } else {
+ writer.loadArrayBufferViewLengthDoubleResult(objId);
+ }
+ } else {
+ if (byteLength <= INT32_MAX) {
+ writer.resizableDataViewByteLengthInt32Result(objId);
+ } else {
+ writer.resizableDataViewByteLengthDoubleResult(objId);
+ }
+ }
+
+ writer.returnFromIC();
+
+ trackAttached("DataViewByteLength");
+ return AttachDecision::Attach;
+}
+
+AttachDecision InlinableNativeIRGenerator::tryAttachDataViewByteOffset() {
+ // Expecting no arguments.
+ if (args_.length() != 0) {
+ return AttachDecision::NoAction;
+ }
+
+ // Ensure |this| is a DataViewObject.
+ if (!thisval_.isObject() || !thisval_.toObject().is<DataViewObject>()) {
+ return AttachDecision::NoAction;
+ }
+
+ auto* dv = &thisval_.toObject().as<DataViewObject>();
+
+ // byteOffset throws when the ArrayBuffer is detached.
+ if (dv->hasDetachedBuffer()) {
+ // The has-attached-arraybuffer guard is elided for immutable views. Assert
+ // we never see an immutable view with a detached buffer.
+ MOZ_ASSERT(!dv->is<ImmutableDataViewObject>(),
+ "immutable data views can't have their buffer detached");
+ return AttachDecision::NoAction;
+ }
+
+ // byteOffset throws when the ArrayBuffer is out-of-bounds.
+ if (dv->is<ResizableDataViewObject>() &&
+ dv->as<ResizableDataViewObject>().isOutOfBounds()) {
+ return AttachDecision::NoAction;
+ }
+
+ // Initialize the input operand.
+ Int32OperandId argcId = initializeInputOperand();
+
+ // Guard callee is the 'byteLength' native function.
+ ObjOperandId calleeId = emitNativeCalleeGuard(argcId);
+
+ // Guard |this| is a DataViewObject.
+ ValOperandId thisValId = loadThis(calleeId);
+ ObjOperandId objId = writer.guardToObject(thisValId);
+
+ if (dv->is<FixedLengthDataViewObject>()) {
+ emitOptimisticClassGuard(objId, dv, GuardClassKind::FixedLengthDataView);
+ } else if (dv->is<ImmutableDataViewObject>()) {
+ emitOptimisticClassGuard(objId, dv, GuardClassKind::ImmutableDataView);
+ } else {
+ emitOptimisticClassGuard(objId, dv, GuardClassKind::ResizableDataView);
+ }
+
+ // Immutable array buffers can never get detached.
+ if (!dv->is<ImmutableDataViewObject>()) {
+ writer.guardHasAttachedArrayBuffer(objId);
+ } else {
+#ifdef DEBUG
+ // Add a guard in debug-mode, so if the buffer unexpectedly got detached,
+ // we bail out and rely on the above assertion to fire.
+ writer.guardHasAttachedArrayBuffer(objId);
+#endif
+ }
+
+ // Resizable array buffers can get out-of-bounds when shrunk.
+ if (dv->is<ResizableDataViewObject>()) {
+ writer.guardResizableArrayBufferViewInBounds(objId);
+ }
+
+ // byteOffset doesn't need to use different code paths for fixed-length,
+ // resizable, or immutable DataViews.
+ size_t byteOffset = dv->byteOffset().valueOr(0);
+ if (byteOffset <= INT32_MAX) {
+ writer.arrayBufferViewByteOffsetInt32Result(objId);
+ } else {
+ writer.arrayBufferViewByteOffsetDoubleResult(objId);
+ }
+
+ writer.returnFromIC();
+
+ trackAttached("DataViewByteOffset");
+ return AttachDecision::Attach;
+}
+
AttachDecision InlinableNativeIRGenerator::tryAttachUnsafeGetReservedSlot(
InlinableNative native) {
// Self-hosted code calls this with (object, int32) arguments.
@@ -13084,6 +13129,10 @@ AttachDecision InlinableNativeIRGenerator::tryAttachStub() {
return tryAttachDataViewSet(Scalar::BigInt64);
case InlinableNative::DataViewSetBigUint64:
return tryAttachDataViewSet(Scalar::BigUint64);
+ case InlinableNative::DataViewByteLength:
+ return tryAttachDataViewByteLength();
+ case InlinableNative::DataViewByteOffset:
+ return tryAttachDataViewByteOffset();
// Function natives.
case InlinableNative::FunctionBind:
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 tryAttachDataView(HandleObject obj, ObjOperandId objId,
- HandleId id);
AttachDecision tryAttachArrayBufferMaybeShared(HandleObject obj,
ObjOperandId objId,
HandleId id);
@@ -754,6 +752,8 @@ class MOZ_RAII InlinableNativeIRGenerator {
AttachDecision tryAttachArrayIsArray();
AttachDecision tryAttachDataViewGet(Scalar::Type type);
AttachDecision tryAttachDataViewSet(Scalar::Type type);
+ AttachDecision tryAttachDataViewByteLength();
+ AttachDecision tryAttachDataViewByteOffset();
AttachDecision tryAttachFunctionBind();
AttachDecision tryAttachSpecializedFunctionBind(
Handle<JSObject*> target, Handle<BoundFunctionObject*> templateObj);
diff --git a/js/src/jit/InlinableNatives.cpp b/js/src/jit/InlinableNatives.cpp
@@ -303,6 +303,8 @@ bool js::jit::CanInlineNativeCrossRealm(InlinableNative native) {
case InlinableNative::DataViewSetFloat64:
case InlinableNative::DataViewSetBigInt64:
case InlinableNative::DataViewSetBigUint64:
+ case InlinableNative::DataViewByteLength:
+ case InlinableNative::DataViewByteOffset:
case InlinableNative::DateGetTime:
case InlinableNative::DateGetFullYear:
case InlinableNative::DateGetMonth:
diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h
@@ -79,6 +79,8 @@
_(DataViewSetFloat64) \
_(DataViewSetBigInt64) \
_(DataViewSetBigUint64) \
+ _(DataViewByteLength) \
+ _(DataViewByteOffset) \
\
_(DateGetTime) \
_(DateGetFullYear) \