Skip to content

Commit 72daaa2

Browse files
tsaichienmeta-codesync[bot]
authored andcommitted
Add TypedArray, UInt8Array in JSI (facebook#56158)
Summary: Pull Request resolved: facebook#56158 Add TypedArray and Uint8Array types to JSI with supporting APIs. New types: - `TypedArray`: Base class for all typed arrays - `Uint8Array`: Uint8Array type extending TypedArray New IRuntime APIs: - `getBuffer(TypedArray)`: Get underlying ArrayBuffer - `getByteOffset(TypedArray)`: Get byte offset property - `getByteLength(TypedArray)`: Get byte length property - `getLength(TypedArray)`: Get length property - `createUint8Array(size_t)`: Create Uint8Array with length - `createUint8Array(ArrayBuffer, offset, length)`: Create from ArrayBuffer - `isUint8Array(Object)`: Check if object is Uint8Array Changelog: [Internal] Reviewed By: lavenzg Differential Revision: D95245175
1 parent ec6e054 commit 72daaa2

File tree

5 files changed

+418
-0
lines changed

5 files changed

+418
-0
lines changed

packages/react-native/ReactCommon/jsi/jsi/decorator.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,12 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
356356
bool isArrayBuffer(const Object& o) const override {
357357
return plain_.isArrayBuffer(o);
358358
}
359+
bool isTypedArray(const Object& o) const override {
360+
return plain_.isTypedArray(o);
361+
}
362+
bool isUint8Array(const Object& o) const override {
363+
return plain_.isUint8Array(o);
364+
}
359365
bool isFunction(const Object& o) const override {
360366
return plain_.isFunction(o);
361367
}
@@ -442,6 +448,30 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
442448
return plain_.tryGetMutableBuffer(arrayBuffer);
443449
}
444450

451+
ArrayBuffer buffer(const TypedArray& typedArray) override {
452+
return plain_.buffer(typedArray);
453+
}
454+
size_t byteOffset(const TypedArray& typedArray) override {
455+
return plain_.byteOffset(typedArray);
456+
}
457+
size_t byteLength(const TypedArray& typedArray) override {
458+
return plain_.byteLength(typedArray);
459+
}
460+
size_t length(const TypedArray& typedArray) override {
461+
return plain_.length(typedArray);
462+
}
463+
464+
Uint8Array createUint8Array(size_t length) override {
465+
return plain_.createUint8Array(length);
466+
}
467+
468+
Uint8Array createUint8Array(
469+
const ArrayBuffer& buffer,
470+
size_t offset,
471+
size_t length) override {
472+
return plain_.createUint8Array(buffer, offset, length);
473+
}
474+
445475
// Private data for managing scopes.
446476
Runtime::ScopeState* pushScope() override {
447477
return plain_.pushScope();
@@ -926,6 +956,14 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
926956
Around around{with_};
927957
return RD::isArrayBuffer(o);
928958
}
959+
bool isTypedArray(const Object& o) const override {
960+
Around around{with_};
961+
return RD::isTypedArray(o);
962+
}
963+
bool isUint8Array(const Object& o) const override {
964+
Around around{with_};
965+
return RD::isUint8Array(o);
966+
}
929967
bool isFunction(const Object& o) const override {
930968
Around around{with_};
931969
return RD::isFunction(o);
@@ -1018,6 +1056,35 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
10181056
return RD::tryGetMutableBuffer(arrayBuffer);
10191057
}
10201058

1059+
ArrayBuffer buffer(const TypedArray& typedArray) override {
1060+
Around around{with_};
1061+
return RD::buffer(typedArray);
1062+
}
1063+
size_t byteOffset(const TypedArray& typedArray) override {
1064+
Around around{with_};
1065+
return RD::byteOffset(typedArray);
1066+
}
1067+
size_t byteLength(const TypedArray& typedArray) override {
1068+
Around around{with_};
1069+
return RD::byteLength(typedArray);
1070+
}
1071+
size_t length(const TypedArray& typedArray) override {
1072+
Around around{with_};
1073+
return RD::length(typedArray);
1074+
}
1075+
1076+
Uint8Array createUint8Array(size_t length) override {
1077+
Around around{with_};
1078+
return RD::createUint8Array(length);
1079+
}
1080+
Uint8Array createUint8Array(
1081+
const ArrayBuffer& buffer,
1082+
size_t offset,
1083+
size_t length) override {
1084+
Around around{with_};
1085+
return RD::createUint8Array(buffer, offset, length);
1086+
}
1087+
10211088
// Private data for managing scopes.
10221089
Runtime::ScopeState* pushScope() override {
10231090
Around around{with_};

packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,16 @@ inline ArrayBuffer Object::getArrayBuffer(IRuntime& runtime) && {
209209
return ArrayBuffer(value);
210210
}
211211

212+
inline TypedArray Object::getTypedArray(IRuntime& runtime) const& {
213+
assert(runtime.isTypedArray(*this));
214+
return TypedArray(runtime.cloneObject(ptr_));
215+
}
216+
217+
inline Uint8Array Object::getUint8Array(IRuntime& runtime) const& {
218+
assert(runtime.isUint8Array(*this));
219+
return Uint8Array(runtime.cloneObject(ptr_));
220+
}
221+
212222
inline Function Object::getFunction(IRuntime& runtime) const& {
213223
assert(runtime.isFunction(*this));
214224
return Function(runtime.cloneObject(ptr_));

packages/react-native/ReactCommon/jsi/jsi/jsi.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,23 @@ std::shared_ptr<MutableBuffer> Runtime::tryGetMutableBuffer(
557557
return nullptr;
558558
}
559559

560+
Uint8Array Runtime::createUint8Array(size_t length) {
561+
auto uint8ArrayCtor = global().getPropertyAsFunction(*this, "Uint8Array");
562+
auto result =
563+
uint8ArrayCtor.callAsConstructor(*this, static_cast<int>(length));
564+
return Uint8Array(cloneObject(getPointerValue(result.getObject(*this))));
565+
}
566+
567+
Uint8Array Runtime::createUint8Array(
568+
const ArrayBuffer& buffer,
569+
size_t offset,
570+
size_t length) {
571+
auto uint8ArrayCtor = global().getPropertyAsFunction(*this, "Uint8Array");
572+
auto result = uint8ArrayCtor.callAsConstructor(
573+
*this, buffer, static_cast<int>(offset), static_cast<int>(length));
574+
return Uint8Array(cloneObject(getPointerValue(result.getObject(*this))));
575+
}
576+
560577
bool Runtime::detached(const ArrayBuffer& buffer) {
561578
Value prop = buffer.getProperty(*this, "detached");
562579
if (!prop.isBool()) {
@@ -566,6 +583,57 @@ bool Runtime::detached(const ArrayBuffer& buffer) {
566583
return prop.getBool();
567584
}
568585

586+
ArrayBuffer Runtime::buffer(const TypedArray& typedArray) {
587+
Value buffer = typedArray.getProperty(*this, "buffer");
588+
if (!buffer.isObject()) {
589+
throw JSINativeException("TypedArray.buffer is not an object");
590+
}
591+
Object bufferObj = buffer.getObject(*this);
592+
if (!bufferObj.isArrayBuffer(*this)) {
593+
throw JSINativeException("TypedArray.buffer is not an ArrayBuffer");
594+
}
595+
return bufferObj.getArrayBuffer(*this);
596+
}
597+
598+
size_t Runtime::byteOffset(const TypedArray& typedArray) {
599+
Value byteOffset = typedArray.getProperty(*this, "byteOffset");
600+
if (!byteOffset.isNumber()) {
601+
throw JSINativeException("TypedArray.byteOffset is not a number");
602+
}
603+
return static_cast<size_t>(byteOffset.getNumber());
604+
}
605+
606+
size_t Runtime::byteLength(const TypedArray& typedArray) {
607+
Value byteLength = typedArray.getProperty(*this, "byteLength");
608+
if (!byteLength.isNumber()) {
609+
throw JSINativeException("TypedArray.byteLength is not a number");
610+
}
611+
return static_cast<size_t>(byteLength.getNumber());
612+
}
613+
614+
size_t Runtime::length(const TypedArray& typedArray) {
615+
Value length = typedArray.getProperty(*this, "length");
616+
if (!length.isNumber()) {
617+
throw JSINativeException("TypedArray.length is not a number");
618+
}
619+
return static_cast<size_t>(length.getNumber());
620+
}
621+
622+
bool Runtime::isTypedArray(const Object& obj) const {
623+
Runtime& self = const_cast<Runtime&>(*this);
624+
// Uint8Array.__proto__ is the %TypedArray% intrinsic constructor.
625+
auto uint8ArrayCtor = self.global().getPropertyAsFunction(self, "Uint8Array");
626+
auto typedArrayCtor =
627+
uint8ArrayCtor.getProperty(self, "__proto__").getObject(self);
628+
return self.instanceOf(obj, typedArrayCtor.getFunction(self));
629+
}
630+
631+
bool Runtime::isUint8Array(const Object& obj) const {
632+
Runtime& self = const_cast<Runtime&>(*this);
633+
auto uint8ArrayCtor = self.global().getPropertyAsFunction(self, "Uint8Array");
634+
return self.instanceOf(obj, uint8ArrayCtor);
635+
}
636+
569637
Pointer& Pointer::operator=(Pointer&& other) noexcept {
570638
if (ptr_) {
571639
ptr_->invalidate();
@@ -641,6 +709,26 @@ Function Object::asFunction(IRuntime& runtime) && {
641709
return std::move(*this).getFunction(runtime);
642710
}
643711

712+
TypedArray Object::asTypedArray(IRuntime& runtime) const& {
713+
if (!isTypedArray(runtime)) {
714+
throw JSError(
715+
runtime,
716+
"Object is " + kindToString(Value(runtime, *this), &runtime) +
717+
", expected a TypedArray");
718+
}
719+
return getTypedArray(runtime);
720+
}
721+
722+
Uint8Array Object::asUint8Array(IRuntime& runtime) const& {
723+
if (!isUint8Array(runtime)) {
724+
throw JSError(
725+
runtime,
726+
"Object is " + kindToString(Value(runtime, *this), &runtime) +
727+
", expected a Uint8Array");
728+
}
729+
return getUint8Array(runtime);
730+
}
731+
644732
Value::Value(Value&& other) noexcept : Value(other.kind_) {
645733
if (kind_ == BooleanKind) {
646734
data_.boolean = other.data_.boolean;

packages/react-native/ReactCommon/jsi/jsi/jsi.h

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ class Instrumentation;
199199
class Scope;
200200
class JSIException;
201201
class JSError;
202+
class TypedArray;
203+
class Uint8Array;
202204

203205
/// A function which has this type can be registered as a function
204206
/// callable from JavaScript using Function::createFromHostFunction().
@@ -549,6 +551,8 @@ class JSI_EXPORT IRuntime : public ICast {
549551

550552
virtual bool isArray(const Object&) const = 0;
551553
virtual bool isArrayBuffer(const Object&) const = 0;
554+
virtual bool isTypedArray(const Object&) const = 0;
555+
virtual bool isUint8Array(const Object&) const = 0;
552556
virtual bool isFunction(const Object&) const = 0;
553557
virtual bool isHostObject(const jsi::Object&) const = 0;
554558
virtual bool isHostFunction(const jsi::Function&) const = 0;
@@ -637,6 +641,22 @@ class JSI_EXPORT IRuntime : public ICast {
637641
virtual std::shared_ptr<MutableBuffer> tryGetMutableBuffer(
638642
const jsi::ArrayBuffer& arrayBuffer) = 0;
639643

644+
/// \return the underlying buffer of the \p typedArray.
645+
virtual ArrayBuffer buffer(const TypedArray& typedArray) = 0;
646+
/// \return the 'byteOffset' property of the \p typedArray.
647+
virtual size_t byteOffset(const TypedArray& typedArray) = 0;
648+
/// \return the 'byteLength' property of the \p typedArray.
649+
virtual size_t byteLength(const TypedArray& typedArray) = 0;
650+
/// \return the 'length; property of the \p typedArray.
651+
virtual size_t length(const TypedArray& typedArray) = 0;
652+
653+
/// Create a JS UInt8Array with length \p length.
654+
virtual Uint8Array createUint8Array(size_t length) = 0;
655+
/// Create a JS UInt8Array using the ArrayBuffer \p buffer starting at byte
656+
/// offset \p offset and length \p length.
657+
virtual Uint8Array
658+
createUint8Array(const ArrayBuffer& buffer, size_t offset, size_t length) = 0;
659+
640660
protected:
641661
virtual ~IRuntime() = default;
642662
};
@@ -727,6 +747,19 @@ class JSI_EXPORT Runtime : public IRuntime {
727747

728748
bool detached(const ArrayBuffer&) override;
729749

750+
ArrayBuffer buffer(const TypedArray& typedArray) override;
751+
size_t byteOffset(const TypedArray& typedArray) override;
752+
size_t byteLength(const TypedArray& typedArray) override;
753+
size_t length(const TypedArray& typedArray) override;
754+
755+
bool isTypedArray(const Object&) const override;
756+
bool isUint8Array(const Object&) const override;
757+
Uint8Array createUint8Array(size_t length) override;
758+
Uint8Array createUint8Array(
759+
const ArrayBuffer& buffer,
760+
size_t offset,
761+
size_t length) override;
762+
730763
protected:
731764
friend class Pointer;
732765
friend class PropNameID;
@@ -1214,6 +1247,18 @@ class JSI_EXPORT Object : public Pointer {
12141247
return runtime.isArrayBuffer(*this);
12151248
}
12161249

1250+
/// \return true iff the Object is a TypedArray (Uint8Array, Int32Array,
1251+
/// Float64Array, etc.). If so, then \c getTypedArray() will succeed.
1252+
bool isTypedArray(IRuntime& runtime) const {
1253+
return runtime.isTypedArray(*this);
1254+
}
1255+
1256+
/// \return true iff the Object is an Uint8Array. If so, then \c
1257+
/// getUint8Array() will succeed
1258+
bool isUint8Array(IRuntime& runtime) const {
1259+
return runtime.isUint8Array(*this);
1260+
}
1261+
12171262
/// \return true iff the Object is callable. If so, then \c
12181263
/// getFunction will succeed.
12191264
bool isFunction(IRuntime& runtime) const {
@@ -1244,6 +1289,16 @@ class JSI_EXPORT Object : public Pointer {
12441289
/// JSIException.
12451290
Array asArray(IRuntime& runtime) &&;
12461291

1292+
/// \return a TypedArray instance which refers to the same underlying
1293+
/// object. If \c isTypedArray() would return false, this will throw
1294+
/// JSIException.
1295+
TypedArray asTypedArray(IRuntime& runtime) const&;
1296+
1297+
/// \return an Uint8Array instance which refers to the same underlying
1298+
/// object. If \c isUint8Array() would return false, this will throw
1299+
/// JSIException.
1300+
Uint8Array asUint8Array(IRuntime& runtime) const&;
1301+
12471302
/// \return an ArrayBuffer instance which refers to the same underlying
12481303
/// object. If \c isArrayBuffer() would return false, this will assert.
12491304
ArrayBuffer getArrayBuffer(IRuntime& runtime) const&;
@@ -1252,6 +1307,14 @@ class JSI_EXPORT Object : public Pointer {
12521307
/// object. If \c isArrayBuffer() would return false, this will assert.
12531308
ArrayBuffer getArrayBuffer(IRuntime& runtime) &&;
12541309

1310+
/// \return a TypedArray instance which refers to the same underlying
1311+
/// object. If \c isTypedArray() would return false, this will assert.
1312+
TypedArray getTypedArray(IRuntime& runtime) const&;
1313+
1314+
/// \return an Uint8Array instance which refers to the same underlying
1315+
/// object. If \c isUint8Array() would return false, this will assert.
1316+
Uint8Array getUint8Array(IRuntime& runtime) const&;
1317+
12551318
/// \return a Function instance which refers to the same underlying
12561319
/// object. If \c isFunction() would return false, this will assert.
12571320
Function getFunction(IRuntime& runtime) const&;
@@ -1601,6 +1664,64 @@ class JSI_EXPORT Function : public Object {
16011664
Function(Runtime::PointerValue* value) : Object(value) {}
16021665
};
16031666

1667+
/// Represents a JS TypedArray
1668+
class JSI_EXPORT TypedArray : public Object {
1669+
public:
1670+
TypedArray(TypedArray&&) = default;
1671+
TypedArray& operator=(TypedArray&&) = default;
1672+
1673+
// Gets the buffer of this TypedArray
1674+
ArrayBuffer buffer(IRuntime& runtime) {
1675+
return runtime.buffer(*this);
1676+
}
1677+
1678+
// Gets the byte offset of this TypedArray
1679+
size_t byteOffset(IRuntime& runtime) {
1680+
return runtime.byteOffset(*this);
1681+
}
1682+
1683+
// Gets the byte length of this TypedArray
1684+
size_t byteLength(IRuntime& runtime) {
1685+
return runtime.byteLength(*this);
1686+
}
1687+
1688+
// Gets the element length of this TypedArray
1689+
size_t length(IRuntime& runtime) {
1690+
return runtime.length(*this);
1691+
}
1692+
1693+
private:
1694+
friend class Object;
1695+
friend class Value;
1696+
friend class Runtime;
1697+
friend class Uint8Array;
1698+
1699+
explicit TypedArray(Runtime::PointerValue* value) : Object(value) {}
1700+
};
1701+
1702+
// Represents a JS Uint8Array
1703+
class JSI_EXPORT Uint8Array : public TypedArray {
1704+
public:
1705+
Uint8Array(Uint8Array&&) = default;
1706+
Uint8Array& operator=(Uint8Array&&) = default;
1707+
1708+
Uint8Array(IRuntime& runtime, size_t length)
1709+
: Uint8Array(runtime.createUint8Array(length)) {}
1710+
Uint8Array(
1711+
IRuntime& runtime,
1712+
const ArrayBuffer& buffer,
1713+
size_t offset,
1714+
size_t length)
1715+
: Uint8Array(runtime.createUint8Array(buffer, offset, length)) {}
1716+
1717+
private:
1718+
friend class Object;
1719+
friend class Value;
1720+
friend class Runtime;
1721+
1722+
explicit Uint8Array(Runtime::PointerValue* value) : TypedArray(value) {}
1723+
};
1724+
16041725
/// Represents any JS Value (undefined, null, boolean, number, symbol,
16051726
/// string, or object). Movable, or explicitly copyable (has no copy
16061727
/// ctor).

0 commit comments

Comments
 (0)