Skip to content

Commit 4cd869d

Browse files
triniwizrigor789edusperoni
authored
feat: JSI support for BigInt, Initial TypedArrays & ArrayBuffer creation (#204)
* feat: JSI support for BigInt, Initial TypedArrays & ArrayBuffer creation * chore(release): 8.5.1-dev.0 --------- Co-authored-by: Igor Randjelovic <[email protected]> Co-authored-by: Eduardo Speroni <[email protected]>
1 parent 5088f5f commit 4cd869d

File tree

10 files changed

+498
-1
lines changed

10 files changed

+498
-1
lines changed

NativeScript/JSIRuntime.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// Copyright © 2022 Progress. All rights reserved.
77
//
88

9+
#pragma once
910
#import <Foundation/Foundation.h>
1011
#import "v8runtime/V8Runtime.h"
1112
#include "runtime/Runtime.h"

NativeScript/jsi/decorator.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,10 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
272272
Array createArray(size_t length) override {
273273
return plain_.createArray(length);
274274
};
275+
ArrayBuffer createArrayBuffer(
276+
std::shared_ptr<MutableBuffer> buffer) override {
277+
return plain_.createArrayBuffer(std::move(buffer));
278+
};
275279
size_t size(const Array& a) override {
276280
return plain_.size(a);
277281
};
@@ -671,6 +675,10 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
671675
Around around{with_};
672676
return RD::createArray(length);
673677
};
678+
ArrayBuffer createArrayBuffer(
679+
std::shared_ptr<MutableBuffer> buffer) override {
680+
return RD::createArrayBuffer(std::move(buffer));
681+
};
674682
size_t size(const Array& a) override {
675683
Around around{with_};
676684
return RD::size(a);

NativeScript/jsi/jsi-inl.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,22 @@ inline ArrayBuffer Object::getArrayBuffer(Runtime& runtime) && {
156156
return ArrayBuffer(value);
157157
}
158158

159+
160+
inline TypedArray Object::getTypedArray(Runtime &runtime) const &{
161+
assert(runtime.isTypedArray(*this));
162+
(void) runtime; // when assert is disabled we need to mark this as used
163+
return TypedArray(runtime.cloneObject(ptr_));
164+
}
165+
166+
inline TypedArray Object::getTypedArray(Runtime &runtime) &&{
167+
assert(runtime.isTypedArray(*this));
168+
(void) runtime; // when assert is disabled we need to mark this as used
169+
Runtime::PointerValue *value = ptr_;
170+
ptr_ = nullptr;
171+
return TypedArray(value);
172+
}
173+
174+
159175
inline Function Object::getFunction(Runtime& runtime) const& {
160176
assert(runtime.isFunction(*this));
161177
return Function(runtime.cloneObject(ptr_));

NativeScript/jsi/jsi.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ Value callGlobalFunction(Runtime& runtime, const char* name, const Value& arg) {
6666

6767
Buffer::~Buffer() = default;
6868

69+
MutableBuffer::~MutableBuffer() = default;
70+
6971
PreparedJavaScript::~PreparedJavaScript() = default;
7072

7173
Value HostObject::get(Runtime&, const PropNameID&) {

NativeScript/jsi/jsi.h

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ class JSI_EXPORT Buffer {
3838
virtual const uint8_t* data() const = 0;
3939
};
4040

41+
/// Base class for buffers of data that need to be passed to the runtime. The
42+
/// result of size() and data() must not change after construction. However, the
43+
/// region pointed to by data() may be modified by the user or the runtime. The
44+
/// user must ensure that access to the contents of the buffer is properly
45+
/// synchronised.
46+
class JSI_EXPORT MutableBuffer {
47+
public:
48+
virtual ~MutableBuffer();
49+
virtual size_t size() const = 0;
50+
virtual uint8_t* data() = 0;
51+
};
52+
4153
class JSI_EXPORT StringBuffer : public Buffer {
4254
public:
4355
StringBuffer(std::string s) : s_(std::move(s)) {}
@@ -80,6 +92,7 @@ class Instrumentation;
8092
class Scope;
8193
class JSIException;
8294
class JSError;
95+
class TypedArray;
8396

8497
/// A function which has this type can be registered as a function
8598
/// callable from JavaScript using Function::createFromHostFunction().
@@ -251,6 +264,8 @@ class JSI_EXPORT Runtime {
251264
friend class Value;
252265
friend class Scope;
253266
friend class JSError;
267+
friend class TypedArray;
268+
254269

255270
// Potential optimization: avoid the cloneFoo() virtual dispatch,
256271
// and instead just fix the number of fields, and copy them, since
@@ -307,18 +322,40 @@ class JSI_EXPORT Runtime {
307322

308323
virtual bool isArray(const Object&) const = 0;
309324
virtual bool isArrayBuffer(const Object&) const = 0;
325+
virtual bool isArrayBufferView(const Object&) const = 0;
326+
virtual bool isTypedArray(const Object&) const = 0;
327+
virtual bool isInt8Array(const Object&) const = 0;
328+
virtual bool isUint8Array(const Object&) const = 0;
329+
virtual bool isUint8ClampedArray(const Object&) const = 0;
330+
virtual bool isInt16Array(const Object&) const = 0;
331+
virtual bool isUint16Array(const Object&) const = 0;
332+
virtual bool isInt32Array(const Object&) const = 0;
333+
virtual bool isUint32Array(const Object&) const = 0;
334+
virtual bool isFloat32Array(const Object&) const = 0;
335+
virtual bool isBigInt64Array(const Object&) const = 0;
336+
virtual bool isBigUint64Array(const Object&) const = 0;
337+
virtual bool isFloat64Array(const Object&) const = 0;
310338
virtual bool isFunction(const Object&) const = 0;
311339
virtual bool isHostObject(const jsi::Object&) const = 0;
312340
virtual bool isHostFunction(const jsi::Function&) const = 0;
313341
virtual Array getPropertyNames(const Object&) = 0;
314342

315343
virtual WeakObject createWeakObject(const Object&) = 0;
316344
virtual Value lockWeakObject(WeakObject&) = 0;
345+
346+
virtual uint64_t uint64Value(const BigInt&, bool *lossless) const = 0;
347+
virtual int64_t int64Value(const BigInt&, bool *lossless) const = 0;
348+
317349

318350
virtual Array createArray(size_t length) = 0;
351+
virtual ArrayBuffer createArrayBuffer(
352+
std::shared_ptr<MutableBuffer> buffer) = 0;
319353
virtual size_t size(const Array&) = 0;
320354
virtual size_t size(const ArrayBuffer&) = 0;
355+
virtual size_t size(const TypedArray&) = 0;
321356
virtual uint8_t* data(const ArrayBuffer&) = 0;
357+
virtual uint8_t* data(const TypedArray&) = 0;
358+
virtual size_t offset(const TypedArray&) = 0;
322359
virtual Value getValueAtIndex(const Array&, size_t i) = 0;
323360
virtual void setValueAtIndexImpl(Array&, size_t i, const Value& value) = 0;
324361

@@ -493,6 +530,26 @@ class JSI_EXPORT BigInt : public Pointer {
493530

494531
BigInt(BigInt&& other) = default;
495532
BigInt& operator=(BigInt&& other) = default;
533+
534+
535+
/**
536+
* Returns the value of this BigInt as an unsigned 64-bit integer.
537+
* If `lossless` is provided, it will reflect whether the return value was
538+
* truncated or wrapped around. In particular, it is set to `false` if this
539+
* BigInt is negative.
540+
*/
541+
uint64_t Uint64Value(Runtime& runtime, bool* lossless = nullptr) const {
542+
return runtime.uint64Value(*this, lossless);
543+
}
544+
545+
/**
546+
* Returns the value of this BigInt as a signed 64-bit integer.
547+
* If `lossless` is provided, it will reflect whether this BigInt was
548+
* truncated or not.
549+
*/
550+
int64_t Int64Value(Runtime& runtime, bool* lossless = nullptr) const {
551+
return runtime.int64Value(*this, lossless);
552+
}
496553

497554
friend class Runtime;
498555
friend class Value;
@@ -641,6 +698,86 @@ class JSI_EXPORT Object : public Pointer {
641698
bool isArrayBuffer(Runtime& runtime) const {
642699
return runtime.isArrayBuffer(*this);
643700
}
701+
702+
703+
/// \return true iff the Object is an isArrayBufferView. If so, then \c
704+
/// getArrayBuffer() will succeed.
705+
bool isArrayBufferView(Runtime& runtime) const {
706+
return runtime.isArrayBufferView(*this);
707+
}
708+
709+
/// \return true iff the Object is an isTypedArray. If so, then \c
710+
/// getArrayBuffer() will succeed.
711+
bool isTypedArray(Runtime& runtime) const {
712+
return runtime.isTypedArray(*this);
713+
}
714+
715+
716+
/// \return true iff the Object is an isInt8Array. If so, then \c
717+
/// getArrayBuffer() will succeed.
718+
bool isInt8Array(Runtime& runtime) const {
719+
return runtime.isInt8Array(*this);
720+
}
721+
722+
/// \return true iff the Object is an isUint8Array. If so, then \c
723+
/// getArrayBuffer() will succeed.
724+
bool isUint8Array(Runtime& runtime) const {
725+
return runtime.isUint8Array(*this);
726+
}
727+
728+
/// \return true iff the Object is an isUint8ClampedArray. If so, then \c
729+
/// getArrayBuffer() will succeed.
730+
bool isUint8ClampedArray(Runtime& runtime) const {
731+
return runtime.isUint8ClampedArray(*this);
732+
}
733+
734+
/// \return true iff the Object is an isInt16Array. If so, then \c
735+
/// getArrayBuffer() will succeed.
736+
bool isInt16Array(Runtime& runtime) const {
737+
return runtime.isInt16Array(*this);
738+
}
739+
740+
/// \return true iff the Object is an isUint16Array. If so, then \c
741+
/// getArrayBuffer() will succeed.
742+
bool isUint16Array(Runtime& runtime) const {
743+
return runtime.isUint16Array(*this);
744+
}
745+
746+
/// \return true iff the Object is an isInt32Array. If so, then \c
747+
/// getArrayBuffer() will succeed.
748+
bool isInt32Array(Runtime& runtime) const {
749+
return runtime.isInt32Array(*this);
750+
}
751+
752+
/// \return true iff the Object is an isUint32Array. If so, then \c
753+
/// getArrayBuffer() will succeed.
754+
bool isUint32Array(Runtime& runtime) const {
755+
return runtime.isUint32Array(*this);
756+
}
757+
758+
/// \return true iff the Object is an isFloat32Array. If so, then \c
759+
/// getArrayBuffer() will succeed.
760+
bool isFloat32Array(Runtime& runtime) const {
761+
return runtime.isFloat32Array(*this);
762+
}
763+
764+
/// \return true iff the Object is an isBigInt64Array. If so, then \c
765+
/// getArrayBuffer() will succeed.
766+
bool isBigInt64Array(Runtime& runtime) const {
767+
return runtime.isBigInt64Array(*this);
768+
}
769+
770+
/// \return true iff the Object is an isBigUint64Array. If so, then \c
771+
/// getArrayBuffer() will succeed.
772+
bool isBigUint64Array(Runtime& runtime) const {
773+
return runtime.isBigUint64Array(*this);
774+
}
775+
776+
/// \return true iff the Object is an isFloat64Array. If so, then \c
777+
/// getArrayBuffer() will succeed.
778+
bool isFloat64Array(Runtime& runtime) const {
779+
return runtime.isFloat64Array(*this);
780+
}
644781

645782
/// \return true iff the Object is callable. If so, then \c
646783
/// getFunction will succeed.
@@ -679,6 +816,16 @@ class JSI_EXPORT Object : public Pointer {
679816
/// \return an ArrayBuffer instance which refers to the same underlying
680817
/// object. If \c isArrayBuffer() would return false, this will assert.
681818
ArrayBuffer getArrayBuffer(Runtime& runtime) &&;
819+
820+
821+
/// \return an TypedArray instance which refers to the same underlying
822+
/// object. If \c isTypedArray() would return false, this will assert.
823+
TypedArray getTypedArray(Runtime& runtime) const&;
824+
825+
/// \return an TypedArray instance which refers to the same underlying
826+
/// object. If \c isTypedArray() would return false, this will assert.
827+
TypedArray getTypedArray(Runtime& runtime) &&;
828+
682829

683830
/// \return a Function instance which refers to the same underlying
684831
/// object. If \c isFunction() would return false, this will assert.
@@ -828,6 +975,8 @@ class JSI_EXPORT ArrayBuffer : public Object {
828975
public:
829976
ArrayBuffer(ArrayBuffer&&) = default;
830977
ArrayBuffer& operator=(ArrayBuffer&&) = default;
978+
ArrayBuffer(Runtime& runtime, std::shared_ptr<MutableBuffer> buffer)
979+
: ArrayBuffer(runtime.createArrayBuffer(std::move(buffer))) {}
831980

832981
/// \return the size of the ArrayBuffer, according to its byteLength property.
833982
/// (C++ naming convention)
@@ -850,6 +999,41 @@ class JSI_EXPORT ArrayBuffer : public Object {
850999
ArrayBuffer(Runtime::PointerValue* value) : Object(value) {}
8511000
};
8521001

1002+
1003+
/// Represents a TypedArray
1004+
class JSI_EXPORT TypedArray : public Object {
1005+
public:
1006+
TypedArray(TypedArray &&) = default;
1007+
1008+
TypedArray &operator=(TypedArray &&) = default;
1009+
1010+
/// \return the size of the TypedArray ArrayBuffer, according to its byteLength property.
1011+
/// (C++ naming convention)
1012+
size_t size(Runtime &runtime) {
1013+
return runtime.size(*this);
1014+
}
1015+
1016+
size_t offset(Runtime &runtime) const {
1017+
return runtime.offset(*this);
1018+
}
1019+
1020+
size_t length(Runtime &runtime) const {
1021+
return runtime.size(*this);
1022+
}
1023+
1024+
uint8_t *data(Runtime &runtime) {
1025+
return runtime.data(*this);
1026+
}
1027+
1028+
private:
1029+
friend class Object;
1030+
1031+
friend class Value;
1032+
1033+
TypedArray(Runtime::PointerValue *value) : Object(value) {}
1034+
};
1035+
1036+
8531037
/// Represents a JS Object which is guaranteed to be Callable.
8541038
class JSI_EXPORT Function : public Object {
8551039
public:

NativeScript/v8runtime/JSIV8ValueConverter.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ jsi::Value JSIV8ValueConverter::ToJSIValue(
3939
if (value->IsObject()) {
4040
return V8Runtime::make<jsi::Object>(new V8PointerValue(isolate, value));
4141
}
42+
43+
if (value->IsBigInt()) {
44+
return V8Runtime::make<jsi::BigInt>(new V8PointerValue(isolate, value));
45+
}
4246

4347
return jsi::Value::undefined();
4448
}
@@ -65,6 +69,9 @@ v8::Local<v8::Value> JSIV8ValueConverter::ToV8Value(
6569
} else if (value.isObject()) {
6670
return scopedHandle.Escape(ToV8Object(
6771
runtime, std::move(value.getObject(const_cast<V8Runtime &>(runtime)))));
72+
}else if(value.isBigInt()){
73+
return scopedHandle.Escape(ToV8BigInt(
74+
runtime, std::move(value.getBigInt(const_cast<V8Runtime &>(runtime)))));
6875
} else {
6976
// What are you?
7077
std::abort();
@@ -132,6 +139,19 @@ v8::Local<v8::Object> JSIV8ValueConverter::ToV8Object(
132139
v8::Local<v8::Object>::Cast(v8PointerValue->Get(runtime.isolate_)));
133140
}
134141

142+
// static
143+
v8::Local<v8::BigInt> JSIV8ValueConverter::ToV8BigInt(
144+
const V8Runtime &runtime,
145+
const jsi::BigInt &bigInt) {
146+
v8::EscapableHandleScope scopedHandle(runtime.isolate_);
147+
const auto *v8PointerValue =
148+
static_cast<const V8PointerValue *>(runtime.getPointerValue(bigInt));
149+
assert(v8PointerValue->Get(runtime.isolate_)->IsBigInt());
150+
return scopedHandle.Escape(
151+
v8::Local<v8::BigInt>::Cast(v8PointerValue->Get(runtime.isolate_)));
152+
}
153+
154+
135155
// static
136156
v8::Local<v8::Array> JSIV8ValueConverter::ToV8Array(
137157
const V8Runtime &runtime,

NativeScript/v8runtime/JSIV8ValueConverter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ class JSIV8ValueConverter {
4747
static v8::Local<v8::Object> ToV8Object(
4848
const V8Runtime &runtime,
4949
const facebook::jsi::Object &object);
50+
51+
static v8::Local<v8::BigInt> ToV8BigInt(
52+
const V8Runtime &runtime,
53+
const facebook::jsi::BigInt &bigInt);
5054

5155
static v8::Local<v8::Array> ToV8Array(
5256
const V8Runtime &runtime,

0 commit comments

Comments
 (0)