From 89b016d4660325603dd840d9bb81be11dbee41a0 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Mon, 20 Jan 2025 12:48:08 -0800 Subject: [PATCH] feat: latest jsi updates --- NativeScript/NativeScript-Prefix.pch | 2 +- NativeScript/jsi/decorator.h | 387 ++++-- NativeScript/jsi/instrumentation.h | 30 +- NativeScript/jsi/jsi-inl.h | 192 ++- NativeScript/jsi/jsi.cpp | 414 ++++-- NativeScript/jsi/jsi.h | 736 +++++----- NativeScript/jsi/jsilib-posix.cpp | 41 +- NativeScript/jsi/jsilib-windows.cpp | 6 +- NativeScript/jsi/jsilib.h | 29 +- NativeScript/jsi/threadsafe.h | 27 +- NativeScript/v8runtime/HostProxy.cpp | 144 +- NativeScript/v8runtime/HostProxy.h | 47 +- .../v8runtime/JSIV8ValueConverter.cpp | 99 +- NativeScript/v8runtime/JSIV8ValueConverter.h | 58 +- NativeScript/v8runtime/V8PointerValue.cpp | 47 +- NativeScript/v8runtime/V8PointerValue.h | 20 +- NativeScript/v8runtime/V8Runtime.cpp | 1231 ++++++++++------- NativeScript/v8runtime/V8Runtime.h | 292 ++-- NativeScript/v8runtime/V8RuntimeConfig.h | 10 +- NativeScript/v8runtime/V8RuntimeFactory.cpp | 17 +- NativeScript/v8runtime/V8RuntimeFactory.h | 9 +- 21 files changed, 2091 insertions(+), 1747 deletions(-) diff --git a/NativeScript/NativeScript-Prefix.pch b/NativeScript/NativeScript-Prefix.pch index 12e1daf3..ec0604b8 100644 --- a/NativeScript/NativeScript-Prefix.pch +++ b/NativeScript/NativeScript-Prefix.pch @@ -1,7 +1,7 @@ #ifndef NativeScript_Prefix_pch #define NativeScript_Prefix_pch -#define NATIVESCRIPT_VERSION "8.8.1" +#define NATIVESCRIPT_VERSION "8.9.0" #ifdef DEBUG #define SIZEOF_OFF_T 8 diff --git a/NativeScript/jsi/decorator.h b/NativeScript/jsi/decorator.h index 2fab930a..deaa86b7 100644 --- a/NativeScript/jsi/decorator.h +++ b/NativeScript/jsi/decorator.h @@ -27,12 +27,10 @@ class DecoratedHostFunction { DecoratedHostFunction(Runtime& drt, HostFunctionType plainHF) : drt_(drt), plainHF_(std::move(plainHF)) {} - Runtime& decoratedRuntime() { - return drt_; - } + Runtime& decoratedRuntime() { return drt_; } - Value - operator()(Runtime&, const Value& thisVal, const Value* args, size_t count) { + Value operator()(Runtime&, const Value& thisVal, const Value* args, + size_t count) { return plainHF_(decoratedRuntime(), thisVal, args, count); } @@ -62,9 +60,7 @@ class DecoratedHostObject : public HostObject { // The derived class methods can call this to get a reference to the // decorated runtime, since the rt passed to the callback will be // the plain runtime. - Runtime& decoratedRuntime() { - return drt_; - } + Runtime& decoratedRuntime() { return drt_; } Value get(Runtime&, const PropNameID& name) override { return plainHO_->get(decoratedRuntime(), name); @@ -103,18 +99,14 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { static_assert( std::is_base_of::value, "RuntimeDecorator's Plain type must derive from jsi::Runtime"); - static_assert( - std::is_base_of::value, - "RuntimeDecorator's Base type must derive from jsi::Runtime"); - return plain_; - } - const Plain& plain() const { + static_assert(std::is_base_of::value, + "RuntimeDecorator's Base type must derive from jsi::Runtime"); return plain_; } + const Plain& plain() const { return plain_; } - Value evaluateJavaScript( - const std::shared_ptr& buffer, - const std::string& sourceURL) override { + Value evaluateJavaScript(const std::shared_ptr& buffer, + const std::string& sourceURL) override { return plain().evaluateJavaScript(buffer, sourceURL); } std::shared_ptr prepareJavaScript( @@ -126,21 +118,16 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { const std::shared_ptr& js) override { return plain().evaluatePreparedJavaScript(js); } + void queueMicrotask(const jsi::Function& callback) override { + return plain().queueMicrotask(callback); + } bool drainMicrotasks(int maxMicrotasksHint) override { return plain().drainMicrotasks(maxMicrotasksHint); } - Object global() override { - return plain().global(); - } - std::string description() override { - return plain().description(); - }; - bool isInspectable() override { - return plain().isInspectable(); - }; - Instrumentation& instrumentation() override { - return *this; - } + Object global() override { return plain().global(); } + std::string description() override { return plain().description(); }; + bool isInspectable() override { return plain().isInspectable(); }; + Instrumentation& instrumentation() override { return *this; } protected: // plain is generally going to be a reference to an object managed @@ -168,12 +155,12 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { return plain_.clonePropNameID(pv); }; - PropNameID createPropNameIDFromAscii(const char* str, size_t length) - override { + PropNameID createPropNameIDFromAscii(const char* str, + size_t length) override { return plain_.createPropNameIDFromAscii(str, length); }; - PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, size_t length) - override { + PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, + size_t length) override { return plain_.createPropNameIDFromUtf8(utf8, length); }; PropNameID createPropNameIDFromString(const String& str) override { @@ -182,9 +169,7 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { PropNameID createPropNameIDFromSymbol(const Symbol& sym) override { return plain_.createPropNameIDFromSymbol(sym); }; - std::string utf8(const PropNameID& id) override { - return plain_.utf8(id); - }; + std::string utf8(const PropNameID& id) override { return plain_.utf8(id); }; bool compare(const PropNameID& a, const PropNameID& b) override { return plain_.compare(a, b); }; @@ -193,19 +178,53 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { return plain_.symbolToString(sym); } + BigInt createBigIntFromInt64(int64_t value) override { + return plain_.createBigIntFromInt64(value); + } + BigInt createBigIntFromUint64(uint64_t value) override { + return plain_.createBigIntFromUint64(value); + } + bool bigintIsInt64(const BigInt& b) override { + return plain_.bigintIsInt64(b); + } + bool bigintIsUint64(const BigInt& b) override { + return plain_.bigintIsUint64(b); + } + uint64_t truncate(const BigInt& b) override { return plain_.truncate(b); } + String bigintToString(const BigInt& bigint, int radix) override { + return plain_.bigintToString(bigint, radix); + } + String createStringFromAscii(const char* str, size_t length) override { return plain_.createStringFromAscii(str, length); }; String createStringFromUtf8(const uint8_t* utf8, size_t length) override { return plain_.createStringFromUtf8(utf8, length); }; - std::string utf8(const String& s) override { - return plain_.utf8(s); + std::string utf8(const String& s) override { return plain_.utf8(s); } + + std::u16string utf16(const String& str) override { return plain_.utf16(str); } + std::u16string utf16(const PropNameID& sym) override { + return plain_.utf16(sym); } - Object createObject() override { - return plain_.createObject(); - }; + void getStringData(const jsi::String& str, void* ctx, + void (*cb)(void* ctx, bool ascii, const void* data, + size_t num)) override { + plain_.getStringData(str, ctx, cb); + } + + void getPropNameIdData(const jsi::PropNameID& sym, void* ctx, + void (*cb)(void* ctx, bool ascii, const void* data, + size_t num)) override { + plain_.getPropNameIdData(sym, ctx, cb); + } + + Object createObjectWithPrototype(const Value& prototype) override { + return plain_.createObjectWithPrototype(prototype); + } + + Object createObject() override { return plain_.createObject(); }; Object createObject(std::shared_ptr ho) override { return plain_.createObject( @@ -222,6 +241,29 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { return dhf.target()->plainHF_; }; + bool hasNativeState(const Object& o) override { + return plain_.hasNativeState(o); + } + std::shared_ptr getNativeState(const Object& o) override { + return plain_.getNativeState(o); + } + void setNativeState(const Object& o, + std::shared_ptr state) override { + plain_.setNativeState(o, state); + } + + void setExternalMemoryPressure(const Object& obj, size_t amt) override { + plain_.setExternalMemoryPressure(obj, amt); + } + + void setPrototypeOf(const Object& object, const Value& prototype) override { + plain_.setPrototypeOf(object, prototype); + } + + Value getPrototypeOf(const Object& object) override { + return plain_.getPrototypeOf(object); + } + Value getProperty(const Object& o, const PropNameID& name) override { return plain_.getProperty(o, name); }; @@ -234,18 +276,16 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { bool hasProperty(const Object& o, const String& name) override { return plain_.hasProperty(o, name); }; - void setPropertyValue(Object& o, const PropNameID& name, const Value& value) - override { + void setPropertyValue(const Object& o, const PropNameID& name, + const Value& value) override { plain_.setPropertyValue(o, name, value); }; - void setPropertyValue(Object& o, const String& name, const Value& value) - override { + void setPropertyValue(const Object& o, const String& name, + const Value& value) override { plain_.setPropertyValue(o, name, value); }; - bool isArray(const Object& o) const override { - return plain_.isArray(o); - }; + bool isArray(const Object& o) const override { return plain_.isArray(o); }; bool isArrayBuffer(const Object& o) const override { return plain_.isArrayBuffer(o); }; @@ -265,7 +305,7 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { WeakObject createWeakObject(const Object& o) override { return plain_.createWeakObject(o); }; - Value lockWeakObject(WeakObject& wo) override { + Value lockWeakObject(const WeakObject& wo) override { return plain_.lockWeakObject(wo); }; @@ -273,51 +313,38 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { return plain_.createArray(length); }; ArrayBuffer createArrayBuffer( - std::shared_ptr buffer) override { - return plain_.createArrayBuffer(std::move(buffer)); - }; - size_t size(const Array& a) override { - return plain_.size(a); - }; - size_t size(const ArrayBuffer& ab) override { - return plain_.size(ab); - }; - uint8_t* data(const ArrayBuffer& ab) override { - return plain_.data(ab); + std::shared_ptr buffer) override { + return plain_.createArrayBuffer(std::move(buffer)); }; + size_t size(const Array& a) override { return plain_.size(a); }; + size_t size(const ArrayBuffer& ab) override { return plain_.size(ab); }; + uint8_t* data(const ArrayBuffer& ab) override { return plain_.data(ab); }; Value getValueAtIndex(const Array& a, size_t i) override { return plain_.getValueAtIndex(a, i); }; - void setValueAtIndexImpl(Array& a, size_t i, const Value& value) override { + void setValueAtIndexImpl(const Array& a, size_t i, + const Value& value) override { plain_.setValueAtIndexImpl(a, i, value); }; - Function createFunctionFromHostFunction( - const PropNameID& name, - unsigned int paramCount, - HostFunctionType func) override { + Function createFunctionFromHostFunction(const PropNameID& name, + unsigned int paramCount, + HostFunctionType func) override { return plain_.createFunctionFromHostFunction( name, paramCount, DecoratedHostFunction(*this, std::move(func))); }; - Value call( - const Function& f, - const Value& jsThis, - const Value* args, - size_t count) override { + Value call(const Function& f, const Value& jsThis, const Value* args, + size_t count) override { return plain_.call(f, jsThis, args, count); }; - Value callAsConstructor(const Function& f, const Value* args, size_t count) - override { + Value callAsConstructor(const Function& f, const Value* args, + size_t count) override { return plain_.callAsConstructor(f, args, count); }; // Private data for managing scopes. - Runtime::ScopeState* pushScope() override { - return plain_.pushScope(); - } - void popScope(Runtime::ScopeState* ss) override { - plain_.popScope(ss); - } + Runtime::ScopeState* pushScope() override { return plain_.pushScope(); } + void popScope(Runtime::ScopeState* ss) override { plain_.popScope(ss); } bool strictEquals(const Symbol& a, const Symbol& b) const override { return plain_.strictEquals(a, b); @@ -352,10 +379,9 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { } void startTrackingHeapObjectStackTraces( - std::function)> callback) override { + std::function)> + callback) override { plain().instrumentation().startTrackingHeapObjectStackTraces( std::move(callback)); } @@ -372,12 +398,14 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { plain().instrumentation().stopHeapSampling(os); } - void createSnapshotToFile(const std::string& path) override { - plain().instrumentation().createSnapshotToFile(path); + void createSnapshotToFile(const std::string& path, + const HeapSnapshotOptions& options) override { + plain().instrumentation().createSnapshotToFile(path, options); } - void createSnapshotToStream(std::ostream& os) override { - plain().instrumentation().createSnapshotToStream(os); + void createSnapshotToStream(std::ostream& os, + const HeapSnapshotOptions& options) override { + plain().instrumentation().createSnapshotToStream(os, options); } std::string flushAndDisableBridgeTrafficTrace() override { @@ -424,16 +452,12 @@ struct AfterCaller { // default above exists, and that is used instead. template struct BeforeCaller { - static void before(T& t) { - t.before(); - } + static void before(T& t) { t.before(); } }; template struct AfterCaller { - static void after(T& t) { - t.after(); - } + static void after(T& t) { t.after(); } }; // It's possible to use multiple decorators by nesting @@ -442,9 +466,7 @@ struct AfterCaller { // example. template struct BeforeCaller> { - static void before(std::tuple& tuple) { - all_before<0, T...>(tuple); - } + static void before(std::tuple& tuple) { all_before<0, T...>(tuple); } private: template @@ -459,9 +481,7 @@ struct BeforeCaller> { template struct AfterCaller> { - static void after(std::tuple& tuple) { - all_after<0, T...>(tuple); - } + static void after(std::tuple& tuple) { all_after<0, T...>(tuple); } private: template @@ -474,7 +494,7 @@ struct AfterCaller> { static void all_after(std::tuple&) {} }; -} // namespace detail +} // namespace detail // A decorator which implements an around idiom. A With instance is // RAII constructed before each call to the undecorated class; the @@ -490,9 +510,8 @@ class WithRuntimeDecorator : public RuntimeDecorator { // the derived class. WithRuntimeDecorator(Plain& plain, With& with) : RD(plain), with_(with) {} - Value evaluateJavaScript( - const std::shared_ptr& buffer, - const std::string& sourceURL) override { + Value evaluateJavaScript(const std::shared_ptr& buffer, + const std::string& sourceURL) override { Around around{with_}; return RD::evaluateJavaScript(buffer, sourceURL); } @@ -507,6 +526,10 @@ class WithRuntimeDecorator : public RuntimeDecorator { Around around{with_}; return RD::evaluatePreparedJavaScript(js); } + void queueMicrotask(const Function& callback) override { + Around around{with_}; + RD::queueMicrotask(callback); + } bool drainMicrotasks(int maxMicrotasksHint) override { Around around{with_}; return RD::drainMicrotasks(maxMicrotasksHint); @@ -538,6 +561,10 @@ class WithRuntimeDecorator : public RuntimeDecorator { Around around{with_}; return RD::cloneSymbol(pv); }; + Runtime::PointerValue* cloneBigInt(const Runtime::PointerValue* pv) override { + Around around{with_}; + return RD::cloneBigInt(pv); + }; Runtime::PointerValue* cloneString(const Runtime::PointerValue* pv) override { Around around{with_}; return RD::cloneString(pv); @@ -552,13 +579,13 @@ class WithRuntimeDecorator : public RuntimeDecorator { return RD::clonePropNameID(pv); }; - PropNameID createPropNameIDFromAscii(const char* str, size_t length) - override { + PropNameID createPropNameIDFromAscii(const char* str, + size_t length) override { Around around{with_}; return RD::createPropNameIDFromAscii(str, length); }; - PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, size_t length) - override { + PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, + size_t length) override { Around around{with_}; return RD::createPropNameIDFromUtf8(utf8, length); }; @@ -566,6 +593,10 @@ class WithRuntimeDecorator : public RuntimeDecorator { Around around{with_}; return RD::createPropNameIDFromString(str); }; + PropNameID createPropNameIDFromSymbol(const Symbol& sym) override { + Around around{with_}; + return RD::createPropNameIDFromSymbol(sym); + }; std::string utf8(const PropNameID& id) override { Around around{with_}; return RD::utf8(id); @@ -580,6 +611,31 @@ class WithRuntimeDecorator : public RuntimeDecorator { return RD::symbolToString(sym); }; + BigInt createBigIntFromInt64(int64_t i) override { + Around around{with_}; + return RD::createBigIntFromInt64(i); + }; + BigInt createBigIntFromUint64(uint64_t i) override { + Around around{with_}; + return RD::createBigIntFromUint64(i); + }; + bool bigintIsInt64(const BigInt& bi) override { + Around around{with_}; + return RD::bigintIsInt64(bi); + }; + bool bigintIsUint64(const BigInt& bi) override { + Around around{with_}; + return RD::bigintIsUint64(bi); + }; + uint64_t truncate(const BigInt& bi) override { + Around around{with_}; + return RD::truncate(bi); + }; + String bigintToString(const BigInt& bi, int i) override { + Around around{with_}; + return RD::bigintToString(bi, i); + }; + String createStringFromAscii(const char* str, size_t length) override { Around around{with_}; return RD::createStringFromAscii(str, length); @@ -593,6 +649,39 @@ class WithRuntimeDecorator : public RuntimeDecorator { return RD::utf8(s); } + std::u16string utf16(const String& str) override { + Around around{with_}; + return RD::utf16(str); + } + std::u16string utf16(const PropNameID& sym) override { + Around around{with_}; + return RD::utf16(sym); + } + + void getStringData(const jsi::String& str, void* ctx, + void (*cb)(void* ctx, bool ascii, const void* data, + size_t num)) override { + Around around{with_}; + RD::getStringData(str, ctx, cb); + } + + void getPropNameIdData(const jsi::PropNameID& sym, void* ctx, + void (*cb)(void* ctx, bool ascii, const void* data, + size_t num)) override { + Around around{with_}; + RD::getPropNameIdData(sym, ctx, cb); + } + + Value createValueFromJsonUtf8(const uint8_t* json, size_t length) override { + Around around{with_}; + return RD::createValueFromJsonUtf8(json, length); + }; + + Object createObjectWithPrototype(const Value& prototype) override { + Around around{with_}; + return RD::createObjectWithPrototype(prototype); + } + Object createObject() override { Around around{with_}; return RD::createObject(); @@ -610,6 +699,30 @@ class WithRuntimeDecorator : public RuntimeDecorator { return RD::getHostFunction(f); }; + bool hasNativeState(const Object& o) override { + Around around{with_}; + return RD::hasNativeState(o); + }; + std::shared_ptr getNativeState(const Object& o) override { + Around around{with_}; + return RD::getNativeState(o); + }; + void setNativeState(const Object& o, + std::shared_ptr state) override { + Around around{with_}; + RD::setNativeState(o, state); + }; + + void setPrototypeOf(const Object& object, const Value& prototype) override { + Around around{with_}; + RD::setPrototypeOf(object, prototype); + } + + Value getPrototypeOf(const Object& object) override { + Around around{with_}; + return RD::getPrototypeOf(object); + } + Value getProperty(const Object& o, const PropNameID& name) override { Around around{with_}; return RD::getProperty(o, name); @@ -626,13 +739,13 @@ class WithRuntimeDecorator : public RuntimeDecorator { Around around{with_}; return RD::hasProperty(o, name); }; - void setPropertyValue(Object& o, const PropNameID& name, const Value& value) - override { + void setPropertyValue(const Object& o, const PropNameID& name, + const Value& value) override { Around around{with_}; RD::setPropertyValue(o, name, value); }; - void setPropertyValue(Object& o, const String& name, const Value& value) - override { + void setPropertyValue(const Object& o, const String& name, + const Value& value) override { Around around{with_}; RD::setPropertyValue(o, name, value); }; @@ -666,7 +779,7 @@ class WithRuntimeDecorator : public RuntimeDecorator { Around around{with_}; return RD::createWeakObject(o); }; - Value lockWeakObject(WeakObject& wo) override { + Value lockWeakObject(const WeakObject& wo) override { Around around{with_}; return RD::lockWeakObject(wo); }; @@ -675,10 +788,10 @@ class WithRuntimeDecorator : public RuntimeDecorator { Around around{with_}; return RD::createArray(length); }; - ArrayBuffer createArrayBuffer( - std::shared_ptr buffer) override { - return RD::createArrayBuffer(std::move(buffer)); - }; + ArrayBuffer createArrayBuffer( + std::shared_ptr buffer) override { + return RD::createArrayBuffer(std::move(buffer)); + }; size_t size(const Array& a) override { Around around{with_}; return RD::size(a); @@ -695,29 +808,26 @@ class WithRuntimeDecorator : public RuntimeDecorator { Around around{with_}; return RD::getValueAtIndex(a, i); }; - void setValueAtIndexImpl(Array& a, size_t i, const Value& value) override { + void setValueAtIndexImpl(const Array& a, size_t i, + const Value& value) override { Around around{with_}; RD::setValueAtIndexImpl(a, i, value); }; - Function createFunctionFromHostFunction( - const PropNameID& name, - unsigned int paramCount, - HostFunctionType func) override { + Function createFunctionFromHostFunction(const PropNameID& name, + unsigned int paramCount, + HostFunctionType func) override { Around around{with_}; - return RD::createFunctionFromHostFunction( - name, paramCount, std::move(func)); + return RD::createFunctionFromHostFunction(name, paramCount, + std::move(func)); }; - Value call( - const Function& f, - const Value& jsThis, - const Value* args, - size_t count) override { + Value call(const Function& f, const Value& jsThis, const Value* args, + size_t count) override { Around around{with_}; return RD::call(f, jsThis, args, count); }; - Value callAsConstructor(const Function& f, const Value* args, size_t count) - override { + Value callAsConstructor(const Function& f, const Value* args, + size_t count) override { Around around{with_}; return RD::callAsConstructor(f, args, count); }; @@ -736,6 +846,11 @@ class WithRuntimeDecorator : public RuntimeDecorator { Around around{with_}; return RD::strictEquals(a, b); }; + bool strictEquals(const BigInt& a, const BigInt& b) const override { + Around around{with_}; + return RD::strictEquals(a, b); + }; + bool strictEquals(const String& a, const String& b) const override { Around around{with_}; return RD::strictEquals(a, b); @@ -750,15 +865,19 @@ class WithRuntimeDecorator : public RuntimeDecorator { return RD::instanceOf(o, f); }; + void setExternalMemoryPressure(const jsi::Object& obj, + size_t amount) override { + Around around{with_}; + RD::setExternalMemoryPressure(obj, amount); + }; + private: // Wrap an RAII type around With& to guarantee after always happens. struct Around { Around(With& with) : with_(with) { detail::BeforeCaller::before(with_); } - ~Around() { - detail::AfterCaller::after(with_); - } + ~Around() { detail::AfterCaller::after(with_); } With& with_; }; @@ -766,5 +885,5 @@ class WithRuntimeDecorator : public RuntimeDecorator { With& with_; }; -} // namespace jsi -} // namespace facebook +} // namespace jsi +} // namespace facebook \ No newline at end of file diff --git a/NativeScript/jsi/instrumentation.h b/NativeScript/jsi/instrumentation.h index e559e9c3..db22f4a4 100644 --- a/NativeScript/jsi/instrumentation.h +++ b/NativeScript/jsi/instrumentation.h @@ -25,6 +25,12 @@ namespace jsi { /// it modify the values of any jsi values in the heap (although GCs are fine). class JSI_EXPORT Instrumentation { public: + /// Additional options controlling what to include when capturing a heap + /// snapshot. + struct HeapSnapshotOptions { + bool captureNumericValue{false}; + }; + virtual ~Instrumentation() = default; /// Returns GC statistics as a JSON-encoded string, with an object containing @@ -68,10 +74,10 @@ class JSI_EXPORT Instrumentation { /// been updated. This callback will be invoked on the same thread that the /// runtime is using. virtual void startTrackingHeapObjectStackTraces( - std::function stats)> fragmentCallback) = 0; + std::function stats)> + fragmentCallback) = 0; /// Stop capture JS stack-traces for JS heap allocated objects. virtual void stopTrackingHeapObjectStackTraces() = 0; @@ -91,13 +97,19 @@ class JSI_EXPORT Instrumentation { /// Captures the heap to a file /// - /// \param path to save the heap capture - virtual void createSnapshotToFile(const std::string& path) = 0; + /// \param path to save the heap capture. + /// \param options additional options for what to capture. + virtual void createSnapshotToFile(const std::string& path, + const HeapSnapshotOptions& options = { + false}) = 0; /// Captures the heap to an output stream /// /// \param os output stream to write to. - virtual void createSnapshotToStream(std::ostream& os) = 0; + /// \param options additional options for what to capture. + virtual void createSnapshotToStream(std::ostream& os, + const HeapSnapshotOptions& options = { + false}) = 0; /// If the runtime has been created to trace to a temp file, flush /// any unwritten parts of the trace of bridge traffic to the file, @@ -113,5 +125,5 @@ class JSI_EXPORT Instrumentation { virtual void dumpProfilerSymbolsToFile(const std::string& fileName) const = 0; }; -} // namespace jsi -} // namespace facebook +} // namespace jsi +} // namespace facebook \ No newline at end of file diff --git a/NativeScript/jsi/jsi-inl.h b/NativeScript/jsi/jsi-inl.h index 3f78e629..8f30c056 100644 --- a/NativeScript/jsi/jsi-inl.h +++ b/NativeScript/jsi/jsi-inl.h @@ -11,21 +11,13 @@ namespace facebook { namespace jsi { namespace detail { -inline Value toValue(Runtime&, std::nullptr_t) { - return Value::null(); -} -inline Value toValue(Runtime&, bool b) { - return Value(b); -} -inline Value toValue(Runtime&, double d) { - return Value(d); -} +inline Value toValue(Runtime&, std::nullptr_t) { return Value::null(); } +inline Value toValue(Runtime&, bool b) { return Value(b); } +inline Value toValue(Runtime&, double d) { return Value(d); } inline Value toValue(Runtime&, float f) { return Value(static_cast(f)); } -inline Value toValue(Runtime&, int i) { - return Value(i); -} +inline Value toValue(Runtime&, int i) { return Value(i); } inline Value toValue(Runtime& runtime, const char* str) { return String::createFromAscii(runtime, str); } @@ -34,17 +26,14 @@ inline Value toValue(Runtime& runtime, const std::string& str) { } template inline Value toValue(Runtime& runtime, const T& other) { - static_assert( - std::is_base_of::value, - "This type cannot be converted to Value"); + static_assert(std::is_base_of::value, + "This type cannot be converted to Value"); return Value(runtime, other); } inline Value toValue(Runtime& runtime, const Value& value) { return Value(runtime, value); } -inline Value&& toValue(Runtime&, Value&& value) { - return std::move(value); -} +inline Value&& toValue(Runtime&, Value&& value) { return std::move(value); } inline PropNameID toPropNameID(Runtime& runtime, const char* name) { return PropNameID::forAscii(runtime, name); @@ -63,7 +52,7 @@ template std::make_exception_ptr(E{std::forward(args)...})); } -} // namespace detail +} // namespace detail template inline T Runtime::make(Runtime::PointerValue* pv) { @@ -84,6 +73,10 @@ inline const Runtime::PointerValue* Runtime::getPointerValue( return value.data_.pointer.ptr_; } +Value Object::getPrototype(Runtime& runtime) const { + return runtime.getPrototypeOf(*this); +} + inline Value Object::getProperty(Runtime& runtime, const char* name) const { return getProperty(runtime, String::createFromAscii(runtime, name)); } @@ -92,8 +85,8 @@ inline Value Object::getProperty(Runtime& runtime, const String& name) const { return runtime.getProperty(*this, name); } -inline Value Object::getProperty(Runtime& runtime, const PropNameID& name) - const { +inline Value Object::getProperty(Runtime& runtime, + const PropNameID& name) const { return runtime.getProperty(*this, name); } @@ -105,38 +98,40 @@ inline bool Object::hasProperty(Runtime& runtime, const String& name) const { return runtime.hasProperty(*this, name); } -inline bool Object::hasProperty(Runtime& runtime, const PropNameID& name) - const { +inline bool Object::hasProperty(Runtime& runtime, + const PropNameID& name) const { return runtime.hasProperty(*this, name); } template -void Object::setProperty(Runtime& runtime, const char* name, T&& value) { - setProperty( - runtime, String::createFromAscii(runtime, name), std::forward(value)); +void Object::setProperty(Runtime& runtime, const char* name, T&& value) const { + setProperty(runtime, String::createFromAscii(runtime, name), + std::forward(value)); } template -void Object::setProperty(Runtime& runtime, const String& name, T&& value) { - setPropertyValue( - runtime, name, detail::toValue(runtime, std::forward(value))); +void Object::setProperty(Runtime& runtime, const String& name, + T&& value) const { + setPropertyValue(runtime, name, + detail::toValue(runtime, std::forward(value))); } template -void Object::setProperty(Runtime& runtime, const PropNameID& name, T&& value) { - setPropertyValue( - runtime, name, detail::toValue(runtime, std::forward(value))); +void Object::setProperty(Runtime& runtime, const PropNameID& name, + T&& value) const { + setPropertyValue(runtime, name, + detail::toValue(runtime, std::forward(value))); } inline Array Object::getArray(Runtime& runtime) const& { assert(runtime.isArray(*this)); - (void)runtime; // when assert is disabled we need to mark this as used + (void)runtime; // when assert is disabled we need to mark this as used return Array(runtime.cloneObject(ptr_)); } inline Array Object::getArray(Runtime& runtime) && { assert(runtime.isArray(*this)); - (void)runtime; // when assert is disabled we need to mark this as used + (void)runtime; // when assert is disabled we need to mark this as used Runtime::PointerValue* value = ptr_; ptr_ = nullptr; return Array(value); @@ -144,34 +139,18 @@ inline Array Object::getArray(Runtime& runtime) && { inline ArrayBuffer Object::getArrayBuffer(Runtime& runtime) const& { assert(runtime.isArrayBuffer(*this)); - (void)runtime; // when assert is disabled we need to mark this as used + (void)runtime; // when assert is disabled we need to mark this as used return ArrayBuffer(runtime.cloneObject(ptr_)); } inline ArrayBuffer Object::getArrayBuffer(Runtime& runtime) && { assert(runtime.isArrayBuffer(*this)); - (void)runtime; // when assert is disabled we need to mark this as used + (void)runtime; // when assert is disabled we need to mark this as used Runtime::PointerValue* value = ptr_; ptr_ = nullptr; return ArrayBuffer(value); } - -inline TypedArray Object::getTypedArray(Runtime &runtime) const &{ - assert(runtime.isTypedArray(*this)); - (void) runtime; // when assert is disabled we need to mark this as used - return TypedArray(runtime.cloneObject(ptr_)); -} - -inline TypedArray Object::getTypedArray(Runtime &runtime) &&{ - assert(runtime.isTypedArray(*this)); - (void) runtime; // when assert is disabled we need to mark this as used - Runtime::PointerValue *value = ptr_; - ptr_ = nullptr; - return TypedArray(value); -} - - inline Function Object::getFunction(Runtime& runtime) const& { assert(runtime.isFunction(*this)); return Function(runtime.cloneObject(ptr_)); @@ -179,7 +158,7 @@ inline Function Object::getFunction(Runtime& runtime) const& { inline Function Object::getFunction(Runtime& runtime) && { assert(runtime.isFunction(*this)); - (void)runtime; // when assert is disabled we need to mark this as used + (void)runtime; // when assert is disabled we need to mark this as used Runtime::PointerValue* value = ptr_; ptr_ = nullptr; return Function(value); @@ -188,7 +167,7 @@ inline Function Object::getFunction(Runtime& runtime) && { template inline bool Object::isHostObject(Runtime& runtime) const { return runtime.isHostObject(*this) && - std::dynamic_pointer_cast(runtime.getHostObject(*this)); + std::dynamic_pointer_cast(runtime.getHostObject(*this)); } template <> @@ -218,40 +197,66 @@ inline std::shared_ptr Object::getHostObject( return runtime.getHostObject(*this); } +template +inline bool Object::hasNativeState(Runtime& runtime) const { + return runtime.hasNativeState(*this) && + std::dynamic_pointer_cast(runtime.getNativeState(*this)); +} + +template <> +inline bool Object::hasNativeState(Runtime& runtime) const { + return runtime.hasNativeState(*this); +} + +template +inline std::shared_ptr Object::getNativeState(Runtime& runtime) const { + assert(hasNativeState(runtime)); + return std::static_pointer_cast(runtime.getNativeState(*this)); +} + +inline void Object::setNativeState(Runtime& runtime, + std::shared_ptr state) const { + runtime.setNativeState(*this, state); +} + +inline void Object::setExternalMemoryPressure(Runtime& runtime, + size_t amt) const { + runtime.setExternalMemoryPressure(*this, amt); +} + inline Array Object::getPropertyNames(Runtime& runtime) const { return runtime.getPropertyNames(*this); } -inline Value WeakObject::lock(Runtime& runtime) { +inline Value WeakObject::lock(Runtime& runtime) const { return runtime.lockWeakObject(*this); } template -void Array::setValueAtIndex(Runtime& runtime, size_t i, T&& value) { - setValueAtIndexImpl( - runtime, i, detail::toValue(runtime, std::forward(value))); +void Array::setValueAtIndex(Runtime& runtime, size_t i, T&& value) const { + setValueAtIndexImpl(runtime, i, + detail::toValue(runtime, std::forward(value))); } inline Value Array::getValueAtIndex(Runtime& runtime, size_t i) const { return runtime.getValueAtIndex(*this, i); } -inline Function Function::createFromHostFunction( - Runtime& runtime, - const jsi::PropNameID& name, - unsigned int paramCount, - jsi::HostFunctionType func) { - return runtime.createFunctionFromHostFunction( - name, paramCount, std::move(func)); +inline Function Function::createFromHostFunction(Runtime& runtime, + const jsi::PropNameID& name, + unsigned int paramCount, + jsi::HostFunctionType func) { + return runtime.createFunctionFromHostFunction(name, paramCount, + std::move(func)); } -inline Value Function::call(Runtime& runtime, const Value* args, size_t count) - const { +inline Value Function::call(Runtime& runtime, const Value* args, + size_t count) const { return runtime.call(*this, Value::undefined(), args, count); } -inline Value Function::call(Runtime& runtime, std::initializer_list args) - const { +inline Value Function::call(Runtime& runtime, + std::initializer_list args) const { return call(runtime, args.begin(), args.size()); } @@ -263,31 +268,24 @@ inline Value Function::call(Runtime& runtime, Args&&... args) const { return call(runtime, {detail::toValue(runtime, std::forward(args))...}); } -inline Value Function::callWithThis( - Runtime& runtime, - const Object& jsThis, - const Value* args, - size_t count) const { +inline Value Function::callWithThis(Runtime& runtime, const Object& jsThis, + const Value* args, size_t count) const { return runtime.call(*this, Value(runtime, jsThis), args, count); } -inline Value Function::callWithThis( - Runtime& runtime, - const Object& jsThis, - std::initializer_list args) const { +inline Value Function::callWithThis(Runtime& runtime, const Object& jsThis, + std::initializer_list args) const { return callWithThis(runtime, jsThis, args.begin(), args.size()); } template -inline Value Function::callWithThis( - Runtime& runtime, - const Object& jsThis, - Args&&... args) const { +inline Value Function::callWithThis(Runtime& runtime, const Object& jsThis, + Args&&... args) const { // A more awesome version of this would be able to create raw values // which can be used directly without wrapping and unwrapping, but // this will do for now. - return callWithThis( - runtime, jsThis, {detail::toValue(runtime, std::forward(args))...}); + return callWithThis(runtime, jsThis, + {detail::toValue(runtime, std::forward(args))...}); } template @@ -297,9 +295,8 @@ inline Array Array::createWithElements(Runtime& runtime, Args&&... args) { } template -inline std::vector PropNameID::names( - Runtime& runtime, - Args&&... args) { +inline std::vector PropNameID::names(Runtime& runtime, + Args&&... args) { return names({detail::toPropNameID(runtime, std::forward(args))...}); } @@ -314,25 +311,26 @@ inline std::vector PropNameID::names( return result; } -inline Value Function::callAsConstructor( - Runtime& runtime, - const Value* args, - size_t count) const { +inline Value Function::callAsConstructor(Runtime& runtime, const Value* args, + size_t count) const { return runtime.callAsConstructor(*this, args, count); } inline Value Function::callAsConstructor( - Runtime& runtime, - std::initializer_list args) const { + Runtime& runtime, std::initializer_list args) const { return callAsConstructor(runtime, args.begin(), args.size()); } template -inline Value Function::callAsConstructor(Runtime& runtime, Args&&... args) - const { +inline Value Function::callAsConstructor(Runtime& runtime, + Args&&... args) const { return callAsConstructor( runtime, {detail::toValue(runtime, std::forward(args))...}); } -} // namespace jsi -} // namespace facebook +String BigInt::toString(Runtime& runtime, int radix) const { + return runtime.bigintToString(*this, radix); +} + +} // namespace jsi +} // namespace facebook \ No newline at end of file diff --git a/NativeScript/jsi/jsi.cpp b/NativeScript/jsi/jsi.cpp index 480a2109..5e3aac99 100644 --- a/NativeScript/jsi/jsi.cpp +++ b/NativeScript/jsi/jsi.cpp @@ -5,13 +5,14 @@ * LICENSE file in the root directory of this source tree. */ +#include "jsi/jsi.h" + #include #include #include #include #include "jsi/instrumentation.h" -#include "jsi/jsi.h" namespace facebook { namespace jsi { @@ -62,7 +63,108 @@ Value callGlobalFunction(Runtime& runtime, const char* name, const Value& arg) { return f.call(runtime, arg); } -} // namespace +// Given a sequence of UTF8 encoded bytes, advance the input to past where a +// 32-bit unicode codepoint as been decoded and return the codepoint. If the +// UTF8 encoding is invalid, then return the value with the unicode replacement +// character (U+FFFD). This decoder also relies on zero termination at end of +// the input for bound checks. +// \param input char pointer pointing to the current character +// \return Unicode codepoint +uint32_t decodeUTF8(const char*& input) { + uint32_t ch = (unsigned char)input[0]; + if (ch <= 0x7f) { + input += 1; + return ch; + } + uint32_t ret; + constexpr uint32_t replacementCharacter = 0xFFFD; + if ((ch & 0xE0) == 0xC0) { + uint32_t ch1 = (unsigned char)input[1]; + if ((ch1 & 0xC0) != 0x80) { + input += 1; + return replacementCharacter; + } + ret = ((ch & 0x1F) << 6) | (ch1 & 0x3F); + input += 2; + if (ret <= 0x7F) { + return replacementCharacter; + } + } else if ((ch & 0xF0) == 0xE0) { + uint32_t ch1 = (unsigned char)input[1]; + if ((ch1 & 0x40) != 0 || (ch1 & 0x80) == 0) { + input += 1; + return replacementCharacter; + } + uint32_t ch2 = (unsigned char)input[2]; + if ((ch2 & 0x40) != 0 || (ch2 & 0x80) == 0) { + input += 2; + return replacementCharacter; + } + ret = ((ch & 0x0F) << 12) | ((ch1 & 0x3F) << 6) | (ch2 & 0x3F); + input += 3; + if (ret <= 0x7FF) { + return replacementCharacter; + } + } else if ((ch & 0xF8) == 0xF0) { + uint32_t ch1 = (unsigned char)input[1]; + if ((ch1 & 0x40) != 0 || (ch1 & 0x80) == 0) { + input += 1; + return replacementCharacter; + } + uint32_t ch2 = (unsigned char)input[2]; + if ((ch2 & 0x40) != 0 || (ch2 & 0x80) == 0) { + input += 2; + return replacementCharacter; + } + uint32_t ch3 = (unsigned char)input[3]; + if ((ch3 & 0x40) != 0 || (ch3 & 0x80) == 0) { + input += 3; + return replacementCharacter; + } + ret = ((ch & 0x07) << 18) | ((ch1 & 0x3F) << 12) | ((ch2 & 0x3F) << 6) | + (ch3 & 0x3F); + input += 4; + if (ret <= 0xFFFF) { + return replacementCharacter; + } + if (ret > 0x10FFFF) { + return replacementCharacter; + } + } else { + input += 1; + return replacementCharacter; + } + return ret; +} + +// Given a valid 32-bit unicode codepoint, encode it as UTF-16 into the output. +void encodeUTF16(std::u16string& out, uint32_t cp) { + if (cp < 0x10000) { + out.push_back((uint16_t)cp); + return; + } + cp -= 0x10000; + uint16_t highSurrogate = 0xD800 + ((cp >> 10) & 0x3FF); + out.push_back(highSurrogate); + uint16_t lowSurrogate = 0xDC00 + (cp & 0x3FF); + out.push_back(lowSurrogate); +} + +// Convert the UTF8 encoded string into a UTF16 encoded string. If the +// input is not valid UTF8, the replacement character (U+FFFD) is used to +// represent the invalid sequence. +std::u16string convertUTF8ToUTF16(const std::string& utf8) { + std::u16string ret; + const char* curr = utf8.data(); + const char* end = curr + utf8.length(); + while (curr < end) { + auto cp = decodeUTF8(curr); + encodeUTF16(ret, cp); + } + return ret; +} + +} // namespace Buffer::~Buffer() = default; @@ -70,9 +172,7 @@ MutableBuffer::~MutableBuffer() = default; PreparedJavaScript::~PreparedJavaScript() = default; -Value HostObject::get(Runtime&, const PropNameID&) { - return Value(); -} +Value HostObject::get(Runtime&, const PropNameID&) { return Value(); } void HostObject::set(Runtime& rt, const PropNameID& name, const Value&) { std::string msg("TypeError: Cannot assign to property '"); @@ -83,13 +183,13 @@ void HostObject::set(Runtime& rt, const PropNameID& name, const Value&) { HostObject::~HostObject() {} +NativeState::~NativeState() {} + Runtime::~Runtime() {} Instrumentation& Runtime::instrumentation() { class NoInstrumentation : public Instrumentation { - std::string getRecordedGCStats() override { - return ""; - } + std::string getRecordedGCStats() override { return ""; } std::unordered_map getHeapInfo(bool) override { return std::unordered_map{}; @@ -98,28 +198,26 @@ Instrumentation& Runtime::instrumentation() { void collectGarbage(std::string) override {} void startTrackingHeapObjectStackTraces( - std::function)>) override {} + std::function)>) override {} void stopTrackingHeapObjectStackTraces() override {} void startHeapSampling(size_t) override {} void stopHeapSampling(std::ostream&) override {} - void createSnapshotToFile(const std::string&) override { + void createSnapshotToFile(const std::string& /*path*/, + const HeapSnapshotOptions& /*options*/) override { throw JSINativeException( "Default instrumentation cannot create a heap snapshot"); } - void createSnapshotToStream(std::ostream&) override { + void createSnapshotToStream( + std::ostream& /*os*/, const HeapSnapshotOptions& /*options*/) override { throw JSINativeException( "Default instrumentation cannot create a heap snapshot"); } - std::string flushAndDisableBridgeTrafficTrace() override { - std::abort(); - } + std::string flushAndDisableBridgeTrafficTrace() override { std::abort(); } void writeBasicBlockProfileTraceToFile(const std::string&) const override { std::abort(); @@ -141,7 +239,52 @@ Value Runtime::createValueFromJsonUtf8(const uint8_t* json, size_t length) { return parseJson.call(*this, String::createFromUtf8(*this, json, length)); } -Pointer& Pointer::operator=(Pointer&& other) { +std::u16string Runtime::utf16(const PropNameID& sym) { + auto utf8Str = utf8(sym); + return convertUTF8ToUTF16(utf8Str); +} + +std::u16string Runtime::utf16(const String& str) { + auto utf8Str = utf8(str); + return convertUTF8ToUTF16(utf8Str); +} + +void Runtime::getStringData(const jsi::String& str, void* ctx, + void (*cb)(void* ctx, bool ascii, const void* data, + size_t num)) { + auto utf16Str = utf16(str); + cb(ctx, false, utf16Str.data(), utf16Str.size()); +} + +void Runtime::getPropNameIdData(const jsi::PropNameID& sym, void* ctx, + void (*cb)(void* ctx, bool ascii, + const void* data, size_t num)) { + auto utf16Str = utf16(sym); + cb(ctx, false, utf16Str.data(), utf16Str.size()); +} + +void Runtime::setPrototypeOf(const Object& object, const Value& prototype) { + auto setPrototypeOfFn = global() + .getPropertyAsObject(*this, "Object") + .getPropertyAsFunction(*this, "setPrototypeOf"); + setPrototypeOfFn.call(*this, object, prototype).asObject(*this); +} + +Value Runtime::getPrototypeOf(const Object& object) { + auto setPrototypeOfFn = global() + .getPropertyAsObject(*this, "Object") + .getPropertyAsFunction(*this, "getPrototypeOf"); + return setPrototypeOfFn.call(*this, object); +} + +Object Runtime::createObjectWithPrototype(const Value& prototype) { + auto createFn = global() + .getPropertyAsObject(*this, "Object") + .getPropertyAsFunction(*this, "create"); + return createFn.call(*this, prototype).asObject(*this); +} + +Pointer& Pointer::operator=(Pointer&& other) noexcept { if (ptr_) { ptr_->invalidate(); } @@ -154,23 +297,22 @@ Object Object::getPropertyAsObject(Runtime& runtime, const char* name) const { Value v = getProperty(runtime, name); if (!v.isObject()) { - throw JSError( - runtime, - std::string("getPropertyAsObject: property '") + name + "' is " + - kindToString(v, &runtime) + ", expected an Object"); + throw JSError(runtime, std::string("getPropertyAsObject: property '") + + name + "' is " + kindToString(v, &runtime) + + ", expected an Object"); } return v.getObject(runtime); } -Function Object::getPropertyAsFunction(Runtime& runtime, const char* name) - const { +Function Object::getPropertyAsFunction(Runtime& runtime, + const char* name) const { Object obj = getPropertyAsObject(runtime, name); if (!obj.isFunction(runtime)) { - throw JSError( - runtime, - std::string("getPropertyAsFunction: property '") + name + "' is " + - kindToString(std::move(obj), &runtime) + ", expected a Function"); + throw JSError(runtime, std::string("getPropertyAsFunction: property '") + + name + "' is " + + kindToString(std::move(obj), &runtime) + + ", expected a Function"); }; return std::move(obj).getFunction(runtime); @@ -178,45 +320,41 @@ Function Object::getPropertyAsFunction(Runtime& runtime, const char* name) Array Object::asArray(Runtime& runtime) const& { if (!isArray(runtime)) { - throw JSError( - runtime, - "Object is " + kindToString(Value(runtime, *this), &runtime) + - ", expected an array"); + throw JSError(runtime, "Object is " + + kindToString(Value(runtime, *this), &runtime) + + ", expected an array"); } return getArray(runtime); } Array Object::asArray(Runtime& runtime) && { if (!isArray(runtime)) { - throw JSError( - runtime, - "Object is " + kindToString(Value(runtime, *this), &runtime) + - ", expected an array"); + throw JSError(runtime, "Object is " + + kindToString(Value(runtime, *this), &runtime) + + ", expected an array"); } return std::move(*this).getArray(runtime); } Function Object::asFunction(Runtime& runtime) const& { if (!isFunction(runtime)) { - throw JSError( - runtime, - "Object is " + kindToString(Value(runtime, *this), &runtime) + - ", expected a function"); + throw JSError(runtime, "Object is " + + kindToString(Value(runtime, *this), &runtime) + + ", expected a function"); } return getFunction(runtime); } Function Object::asFunction(Runtime& runtime) && { if (!isFunction(runtime)) { - throw JSError( - runtime, - "Object is " + kindToString(Value(runtime, *this), &runtime) + - ", expected a function"); + throw JSError(runtime, "Object is " + + kindToString(Value(runtime, *this), &runtime) + + ", expected a function"); } return std::move(*this).getFunction(runtime); } -Value::Value(Value&& other) : Value(other.kind_) { +Value::Value(Value&& other) noexcept : Value(other.kind_) { if (kind_ == BooleanKind) { data_.boolean = other.data_.boolean; } else if (kind_ == NumberKind) { @@ -266,29 +404,25 @@ bool Value::strictEquals(Runtime& runtime, const Value& a, const Value& b) { case NumberKind: return a.data_.number == b.data_.number; case SymbolKind: - return runtime.strictEquals( - static_cast(a.data_.pointer), - static_cast(b.data_.pointer)); + return runtime.strictEquals(static_cast(a.data_.pointer), + static_cast(b.data_.pointer)); case BigIntKind: - return runtime.strictEquals( - static_cast(a.data_.pointer), - static_cast(b.data_.pointer)); + return runtime.strictEquals(static_cast(a.data_.pointer), + static_cast(b.data_.pointer)); case StringKind: - return runtime.strictEquals( - static_cast(a.data_.pointer), - static_cast(b.data_.pointer)); + return runtime.strictEquals(static_cast(a.data_.pointer), + static_cast(b.data_.pointer)); case ObjectKind: - return runtime.strictEquals( - static_cast(a.data_.pointer), - static_cast(b.data_.pointer)); + return runtime.strictEquals(static_cast(a.data_.pointer), + static_cast(b.data_.pointer)); } return false; } bool Value::asBool() const { if (!isBool()) { - throw JSINativeException( - "Value is " + kindToString(*this) + ", expected a boolean"); + throw JSINativeException("Value is " + kindToString(*this) + + ", expected a boolean"); } return getBool(); @@ -296,8 +430,8 @@ bool Value::asBool() const { double Value::asNumber() const { if (!isNumber()) { - throw JSINativeException( - "Value is " + kindToString(*this) + ", expected a number"); + throw JSINativeException("Value is " + kindToString(*this) + + ", expected a number"); } return getNumber(); @@ -381,9 +515,22 @@ String Value::toString(Runtime& runtime) const { return toString.call(runtime, *this).getString(runtime); } -Array Array::createWithElements( - Runtime& rt, - std::initializer_list elements) { +uint64_t BigInt::asUint64(Runtime& runtime) const { + if (!isUint64(runtime)) { + throw JSError(runtime, "Lossy truncation in BigInt64::asUint64"); + } + return getUint64(runtime); +} + +int64_t BigInt::asInt64(Runtime& runtime) const { + if (!isInt64(runtime)) { + throw JSError(runtime, "Lossy truncation in BigInt64::asInt64"); + } + return getInt64(runtime); +} + +Array Array::createWithElements(Runtime& rt, + std::initializer_list elements) { Array result(rt, elements.size()); size_t index = 0; for (const auto& element : elements) { @@ -392,30 +539,21 @@ Array Array::createWithElements( return result; } -std::vector HostObject::getPropertyNames(Runtime&) { - return {}; -} +std::vector HostObject::getPropertyNames(Runtime&) { return {}; } -Runtime::ScopeState* Runtime::pushScope() { - return nullptr; -} +Runtime::ScopeState* Runtime::pushScope() { return nullptr; } void Runtime::popScope(ScopeState*) {} -JSError::JSError(Runtime& rt, Value&& value) { - setValue(rt, std::move(value)); -} +JSError::JSError(Runtime& rt, Value&& value) { setValue(rt, std::move(value)); } JSError::JSError(Runtime& rt, std::string msg) : message_(std::move(msg)) { try { - setValue( - rt, - callGlobalFunction(rt, "Error", String::createFromUtf8(rt, message_))); - } catch (const std::exception& ex) { + setValue(rt, callGlobalFunction(rt, "Error", + String::createFromUtf8(rt, message_))); + } catch (const JSIException& ex) { message_ = std::string(ex.what()) + " (while raising " + message_ + ")"; setValue(rt, String::createFromUtf8(rt, message_)); - } catch (...) { - setValue(rt, Value()); } } @@ -426,10 +564,8 @@ JSError::JSError(Runtime& rt, std::string msg, std::string stack) e.setProperty(rt, "message", String::createFromUtf8(rt, message_)); e.setProperty(rt, "stack", String::createFromUtf8(rt, stack_)); setValue(rt, std::move(e)); - } catch (const std::exception& ex) { + } catch (const JSIException& ex) { setValue(rt, String::createFromUtf8(rt, ex.what())); - } catch (...) { - setValue(rt, Value()); } } @@ -438,77 +574,77 @@ JSError::JSError(std::string what, Runtime& rt, Value&& value) setValue(rt, std::move(value)); } +JSError::JSError(Value&& value, std::string message, std::string stack) + : JSIException(message + "\n\n" + stack), + value_(std::make_shared(std::move(value))), + message_(std::move(message)), + stack_(std::move(stack)) {} + void JSError::setValue(Runtime& rt, Value&& value) { value_ = std::make_shared(std::move(value)); - try { - if ((message_.empty() || stack_.empty()) && value_->isObject()) { - auto obj = value_->getObject(rt); - - if (message_.empty()) { - try { - Value message = obj.getProperty(rt, "message"); - if (!message.isUndefined() && !message.isString()) { - message = callGlobalFunction(rt, "String", message); - } - if (message.isString()) { - message_ = message.getString(rt).utf8(rt); - } else if (!message.isUndefined()) { - message_ = "String(e.message) is a " + kindToString(message, &rt); - } - } catch (const std::exception& ex) { - message_ = std::string("[Exception while creating message string: ") + - ex.what() + "]"; + if ((message_.empty() || stack_.empty()) && value_->isObject()) { + auto obj = value_->getObject(rt); + + if (message_.empty()) { + try { + Value message = obj.getProperty(rt, "message"); + if (!message.isUndefined() && !message.isString()) { + message = callGlobalFunction(rt, "String", message); + } + if (message.isString()) { + message_ = message.getString(rt).utf8(rt); + } else if (!message.isUndefined()) { + message_ = "String(e.message) is a " + kindToString(message, &rt); } + } catch (const JSIException& ex) { + message_ = std::string("[Exception while creating message string: ") + + ex.what() + "]"; } + } - if (stack_.empty()) { - try { - Value stack = obj.getProperty(rt, "stack"); - if (!stack.isUndefined() && !stack.isString()) { - stack = callGlobalFunction(rt, "String", stack); - } - if (stack.isString()) { - stack_ = stack.getString(rt).utf8(rt); - } else if (!stack.isUndefined()) { - stack_ = "String(e.stack) is a " + kindToString(stack, &rt); - } - } catch (const std::exception& ex) { - message_ = std::string("[Exception while creating stack string: ") + - ex.what() + "]"; + if (stack_.empty()) { + try { + Value stack = obj.getProperty(rt, "stack"); + if (!stack.isUndefined() && !stack.isString()) { + stack = callGlobalFunction(rt, "String", stack); + } + if (stack.isString()) { + stack_ = stack.getString(rt).utf8(rt); + } else if (!stack.isUndefined()) { + stack_ = "String(e.stack) is a " + kindToString(stack, &rt); } + } catch (const JSIException& ex) { + message_ = std::string("[Exception while creating stack string: ") + + ex.what() + "]"; } } + } - if (message_.empty()) { - try { - if (value_->isString()) { - message_ = value_->getString(rt).utf8(rt); + if (message_.empty()) { + try { + if (value_->isString()) { + message_ = value_->getString(rt).utf8(rt); + } else { + Value message = callGlobalFunction(rt, "String", *value_); + if (message.isString()) { + message_ = message.getString(rt).utf8(rt); } else { - Value message = callGlobalFunction(rt, "String", *value_); - if (message.isString()) { - message_ = message.getString(rt).utf8(rt); - } else { - message_ = "String(e) is a " + kindToString(message, &rt); - } + message_ = "String(e) is a " + kindToString(message, &rt); } - } catch (const std::exception& ex) { - message_ = std::string("[Exception while creating message string: ") + - ex.what() + "]"; } + } catch (const JSIException& ex) { + message_ = std::string("[Exception while creating message string: ") + + ex.what() + "]"; } + } - if (stack_.empty()) { - stack_ = "no stack"; - } + if (stack_.empty()) { + stack_ = "no stack"; + } - if (what_.empty()) { - what_ = message_ + "\n\n" + stack_; - } - } catch (...) { - message_ = "[Exception caught creating message string]"; - stack_ = "[Exception caught creating stack string]"; - what_ = "[Exception caught getting value fields]"; + if (what_.empty()) { + what_ = message_ + "\n\n" + stack_; } } @@ -518,5 +654,5 @@ JSINativeException::~JSINativeException() {} JSError::~JSError() {} -} // namespace jsi -} // namespace facebook +} // namespace jsi +} // namespace facebook \ No newline at end of file diff --git a/NativeScript/jsi/jsi.h b/NativeScript/jsi/jsi.h index cf8ac5b0..7d760ef5 100644 --- a/NativeScript/jsi/jsi.h +++ b/NativeScript/jsi/jsi.h @@ -21,16 +21,20 @@ #define JSI_EXPORT __declspec(dllexport) #else #define JSI_EXPORT -#endif // CREATE_SHARED_LIBRARY -#else // _MSC_VER +#endif // CREATE_SHARED_LIBRARY +#else // _MSC_VER #define JSI_EXPORT __attribute__((visibility("default"))) -#endif // _MSC_VER -#endif // !defined(JSI_EXPORT) +#endif // _MSC_VER +#endif // !defined(JSI_EXPORT) class FBJSRuntime; namespace facebook { namespace jsi { +/// Base class for buffers of data or bytecode that need to be passed to the +/// runtime. The buffer is expected to be fully immutable, so the result of +/// size(), data(), and the contents of the pointer returned by data() must not +/// change after construction. class JSI_EXPORT Buffer { public: virtual ~Buffer(); @@ -38,24 +42,10 @@ class JSI_EXPORT Buffer { virtual const uint8_t* data() const = 0; }; -/// Base class for buffers of data that need to be passed to the runtime. The -/// result of size() and data() must not change after construction. However, the -/// region pointed to by data() may be modified by the user or the runtime. The -/// user must ensure that access to the contents of the buffer is properly -/// synchronised. -class JSI_EXPORT MutableBuffer { - public: - virtual ~MutableBuffer(); - virtual size_t size() const = 0; - virtual uint8_t* data() = 0; -}; - class JSI_EXPORT StringBuffer : public Buffer { public: StringBuffer(std::string s) : s_(std::move(s)) {} - size_t size() const override { - return s_.size(); - } + size_t size() const override { return s_.size(); } const uint8_t* data() const override { return reinterpret_cast(s_.data()); } @@ -64,6 +54,18 @@ class JSI_EXPORT StringBuffer : public Buffer { std::string s_; }; +/// Base class for buffers of data that need to be passed to the runtime. The +/// result of size() and data() must not change after construction. However, the +/// region pointed to by data() may be modified by the user or the runtime. The +/// user must ensure that access to the contents of the buffer is properly +/// synchronised. +class JSI_EXPORT MutableBuffer { + public: + virtual ~MutableBuffer(); + virtual size_t size() const = 0; + virtual uint8_t* data() = 0; +}; + /// PreparedJavaScript is a base class representing JavaScript which is in a /// form optimized for execution, in a runtime-specific way. Construct one via /// jsi::Runtime::prepareJavaScript(). @@ -92,7 +94,6 @@ class Instrumentation; class Scope; class JSIException; class JSError; -class TypedArray; /// A function which has this type can be registered as a function /// callable from JavaScript using Function::createFromHostFunction(). @@ -105,8 +106,8 @@ class TypedArray; /// HostFunctions may or may not be called in strict mode; that is `thisVal` /// can be any value - it will not necessarily be coerced to an object or /// or set to the global object. -using HostFunctionType = std::function< - Value(Runtime& rt, const Value& thisVal, const Value* args, size_t count)>; +using HostFunctionType = std::function; /// An object which implements this interface can be registered as an /// Object with the JS runtime. @@ -141,6 +142,13 @@ class JSI_EXPORT HostObject { virtual std::vector getPropertyNames(Runtime& rt); }; +/// Native state (and destructor) that can be attached to any JS object +/// using setNativeState. +class JSI_EXPORT NativeState { + public: + virtual ~NativeState(); +}; + /// Represents a JS runtime. Movable, but not copyable. Note that /// this object may not be thread-aware, but cannot be used safely from /// multiple threads at once. The application is responsible for @@ -173,9 +181,8 @@ class JSI_EXPORT Runtime { /// through the JSI API. For example, it will be much slower to use this to /// call a global function than using the JSI APIs to read the function /// property from the global object and then calling it explicitly. - virtual Value evaluateJavaScript( - const std::shared_ptr& buffer, - const std::string& sourceURL) = 0; + virtual Value evaluateJavaScript(const std::shared_ptr& buffer, + const std::string& sourceURL) = 0; /// Prepares to evaluate the given JavaScript \c buffer by processing it into /// a form optimized for execution. This may include pre-parsing, compiling, @@ -189,8 +196,7 @@ class JSI_EXPORT Runtime { /// As with evaluateJavaScript(), using JavaScript code should be avoided /// when the JSI API is sufficient. virtual std::shared_ptr prepareJavaScript( - const std::shared_ptr& buffer, - std::string sourceURL) = 0; + const std::shared_ptr& buffer, std::string sourceURL) = 0; /// Evaluates a PreparedJavaScript. If evaluation causes an error, a /// JSIException will be thrown. @@ -199,6 +205,13 @@ class JSI_EXPORT Runtime { virtual Value evaluatePreparedJavaScript( const std::shared_ptr& js) = 0; + /// Queues a microtask in the JavaScript VM internal Microtask (a.k.a. Job in + /// ECMA262) queue, to be executed when the host drains microtasks in + /// its event loop implementation. + /// + /// \param callback a function to be executed as a microtask. + virtual void queueMicrotask(const jsi::Function& callback) = 0; + /// Drain the JavaScript VM internal Microtask (a.k.a. Job in ECMA262) queue. /// /// \param maxMicrotasksHint a hint to tell an implementation that it should @@ -264,8 +277,6 @@ class JSI_EXPORT Runtime { friend class Value; friend class Scope; friend class JSError; - friend class TypedArray; - // Potential optimization: avoid the cloneFoo() virtual dispatch, // and instead just fix the number of fields, and copy them, since @@ -285,12 +296,10 @@ class JSI_EXPORT Runtime { virtual PointerValue* cloneObject(const Runtime::PointerValue* pv) = 0; virtual PointerValue* clonePropNameID(const Runtime::PointerValue* pv) = 0; - virtual PropNameID createPropNameIDFromAscii( - const char* str, - size_t length) = 0; - virtual PropNameID createPropNameIDFromUtf8( - const uint8_t* utf8, - size_t length) = 0; + virtual PropNameID createPropNameIDFromAscii(const char* str, + size_t length) = 0; + virtual PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, + size_t length) = 0; virtual PropNameID createPropNameIDFromString(const String& str) = 0; virtual PropNameID createPropNameIDFromSymbol(const Symbol& sym) = 0; virtual std::string utf8(const PropNameID&) = 0; @@ -298,6 +307,13 @@ class JSI_EXPORT Runtime { virtual std::string symbolToString(const Symbol&) = 0; + virtual BigInt createBigIntFromInt64(int64_t) = 0; + virtual BigInt createBigIntFromUint64(uint64_t) = 0; + virtual bool bigintIsInt64(const BigInt&) = 0; + virtual bool bigintIsUint64(const BigInt&) = 0; + virtual uint64_t truncate(const BigInt&) = 0; + virtual String bigintToString(const BigInt&, int) = 0; + virtual String createStringFromAscii(const char* str, size_t length) = 0; virtual String createStringFromUtf8(const uint8_t* utf8, size_t length) = 0; virtual std::string utf8(const String&) = 0; @@ -311,65 +327,53 @@ class JSI_EXPORT Runtime { virtual std::shared_ptr getHostObject(const jsi::Object&) = 0; virtual HostFunctionType& getHostFunction(const jsi::Function&) = 0; + // Creates a new Object with the custom prototype + virtual Object createObjectWithPrototype(const Value& prototype); + + virtual bool hasNativeState(const jsi::Object&) = 0; + virtual std::shared_ptr getNativeState(const jsi::Object&) = 0; + virtual void setNativeState(const jsi::Object&, + std::shared_ptr state) = 0; + + virtual void setPrototypeOf(const Object& object, const Value& prototype); + virtual Value getPrototypeOf(const Object& object); + virtual Value getProperty(const Object&, const PropNameID& name) = 0; virtual Value getProperty(const Object&, const String& name) = 0; virtual bool hasProperty(const Object&, const PropNameID& name) = 0; virtual bool hasProperty(const Object&, const String& name) = 0; - virtual void - setPropertyValue(Object&, const PropNameID& name, const Value& value) = 0; - virtual void - setPropertyValue(Object&, const String& name, const Value& value) = 0; + virtual void setPropertyValue(const Object&, const PropNameID& name, + const Value& value) = 0; + virtual void setPropertyValue(const Object&, const String& name, + const Value& value) = 0; virtual bool isArray(const Object&) const = 0; virtual bool isArrayBuffer(const Object&) const = 0; - virtual bool isArrayBufferView(const Object&) const = 0; - virtual bool isTypedArray(const Object&) const = 0; - virtual bool isInt8Array(const Object&) const = 0; - virtual bool isUint8Array(const Object&) const = 0; - virtual bool isUint8ClampedArray(const Object&) const = 0; - virtual bool isInt16Array(const Object&) const = 0; - virtual bool isUint16Array(const Object&) const = 0; - virtual bool isInt32Array(const Object&) const = 0; - virtual bool isUint32Array(const Object&) const = 0; - virtual bool isFloat32Array(const Object&) const = 0; - virtual bool isBigInt64Array(const Object&) const = 0; - virtual bool isBigUint64Array(const Object&) const = 0; - virtual bool isFloat64Array(const Object&) const = 0; virtual bool isFunction(const Object&) const = 0; virtual bool isHostObject(const jsi::Object&) const = 0; virtual bool isHostFunction(const jsi::Function&) const = 0; virtual Array getPropertyNames(const Object&) = 0; virtual WeakObject createWeakObject(const Object&) = 0; - virtual Value lockWeakObject(WeakObject&) = 0; - - virtual uint64_t uint64Value(const BigInt&, bool *lossless) const = 0; - virtual int64_t int64Value(const BigInt&, bool *lossless) const = 0; - + virtual Value lockWeakObject(const WeakObject&) = 0; virtual Array createArray(size_t length) = 0; virtual ArrayBuffer createArrayBuffer( - std::shared_ptr buffer) = 0; + std::shared_ptr buffer) = 0; virtual size_t size(const Array&) = 0; virtual size_t size(const ArrayBuffer&) = 0; - virtual size_t size(const TypedArray&) = 0; virtual uint8_t* data(const ArrayBuffer&) = 0; - virtual uint8_t* data(const TypedArray&) = 0; - virtual size_t offset(const TypedArray&) = 0; virtual Value getValueAtIndex(const Array&, size_t i) = 0; - virtual void setValueAtIndexImpl(Array&, size_t i, const Value& value) = 0; - - virtual Function createFunctionFromHostFunction( - const PropNameID& name, - unsigned int paramCount, - HostFunctionType func) = 0; - virtual Value call( - const Function&, - const Value& jsThis, - const Value* args, - size_t count) = 0; - virtual Value - callAsConstructor(const Function&, const Value* args, size_t count) = 0; + virtual void setValueAtIndexImpl(const Array&, size_t i, + const Value& value) = 0; + + virtual Function createFunctionFromHostFunction(const PropNameID& name, + unsigned int paramCount, + HostFunctionType func) = 0; + virtual Value call(const Function&, const Value& jsThis, const Value* args, + size_t count) = 0; + virtual Value callAsConstructor(const Function&, const Value* args, + size_t count) = 0; // Private data for managing scopes. struct ScopeState; @@ -383,6 +387,39 @@ class JSI_EXPORT Runtime { virtual bool instanceOf(const Object& o, const Function& f) = 0; + /// See Object::setExternalMemoryPressure. + virtual void setExternalMemoryPressure(const jsi::Object& obj, + size_t amount) = 0; + + virtual std::u16string utf16(const String& str); + virtual std::u16string utf16(const PropNameID& sym); + + /// Invokes the provided callback \p cb with the String content in \p str. + /// The callback must take in three arguments: bool ascii, const void* data, + /// and size_t num, respectively. \p ascii indicates whether the \p data + /// passed to the callback should be interpreted as a pointer to a sequence of + /// \p num ASCII characters or UTF16 characters. Depending on the internal + /// representation of the string, the function may invoke the callback + /// multiple times, with a different format on each invocation. The callback + /// must not access runtime functionality, as any operation on the runtime may + /// invalidate the data pointers. + virtual void getStringData(const jsi::String& str, void* ctx, + void (*cb)(void* ctx, bool ascii, const void* data, + size_t num)); + + /// Invokes the provided callback \p cb with the PropNameID content in \p sym. + /// The callback must take in three arguments: bool ascii, const void* data, + /// and size_t num, respectively. \p ascii indicates whether the \p data + /// passed to the callback should be interpreted as a pointer to a sequence of + /// \p num ASCII characters or UTF16 characters. Depending on the internal + /// representation of the string, the function may invoke the callback + /// multiple times, with a different format on each invocation. The callback + /// must not access runtime functionality, as any operation on the runtime may + /// invalidate the data pointers. + virtual void getPropNameIdData(const jsi::PropNameID& sym, void* ctx, + void (*cb)(void* ctx, bool ascii, + const void* data, size_t num)); + // These exist so derived classes can access the private parts of // Value, Symbol, String, and Object, which are all friends of Runtime. template @@ -399,7 +436,7 @@ class JSI_EXPORT Runtime { // Base class for pointer-storing types. class JSI_EXPORT Pointer { protected: - explicit Pointer(Pointer&& other) : ptr_(other.ptr_) { + explicit Pointer(Pointer&& other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; } @@ -409,7 +446,7 @@ class JSI_EXPORT Pointer { } } - Pointer& operator=(Pointer&& other); + Pointer& operator=(Pointer&& other) noexcept; friend class Runtime; friend class Value; @@ -449,8 +486,8 @@ class JSI_EXPORT PropNameID : public Pointer { /// Create a PropNameID from utf8 values. The data is copied. /// Results are undefined if \p utf8 contains invalid code points. - static PropNameID - forUtf8(Runtime& runtime, const uint8_t* utf8, size_t length) { + static PropNameID forUtf8(Runtime& runtime, const uint8_t* utf8, + size_t length) { return runtime.createPropNameIDFromUtf8(utf8, length); } @@ -481,14 +518,29 @@ class JSI_EXPORT PropNameID : public Pointer { static std::vector names(PropNameID(&&propertyNames)[N]); /// Copies the data in a PropNameID as utf8 into a C++ string. - std::string utf8(Runtime& runtime) const { - return runtime.utf8(*this); - } - - static bool compare( - Runtime& runtime, - const jsi::PropNameID& a, - const jsi::PropNameID& b) { + std::string utf8(Runtime& runtime) const { return runtime.utf8(*this); } + + /// Copies the data in a PropNameID as utf16 into a C++ string. + std::u16string utf16(Runtime& runtime) const { return runtime.utf16(*this); } + + /// Invokes the user provided callback to process the content in PropNameId. + /// The callback must take in three arguments: bool ascii, const void* data, + /// and size_t num, respectively. \p ascii indicates whether the \p data + /// passed to the callback should be interpreted as a pointer to a sequence of + /// \p num ASCII characters or UTF16 characters. The function may invoke the + /// callback multiple times, with a different format on each invocation. The + /// callback must not access runtime functionality, as any operation on the + /// runtime may invalidate the data pointers. + template + void getPropNameIdData(Runtime& runtime, CB& cb) const { + runtime.getPropNameIdData( + *this, &cb, [](void* ctx, bool ascii, const void* data, size_t num) { + (*((CB*)ctx))(ascii, data, num); + }); + } + + static bool compare(Runtime& runtime, const jsi::PropNameID& a, + const jsi::PropNameID& b) { return runtime.compare(a, b); } @@ -530,26 +582,47 @@ class JSI_EXPORT BigInt : public Pointer { BigInt(BigInt&& other) = default; BigInt& operator=(BigInt&& other) = default; - - - /** - * Returns the value of this BigInt as an unsigned 64-bit integer. - * If `lossless` is provided, it will reflect whether the return value was - * truncated or wrapped around. In particular, it is set to `false` if this - * BigInt is negative. - */ - uint64_t Uint64Value(Runtime& runtime, bool* lossless = nullptr) const { - return runtime.uint64Value(*this, lossless); - } - - /** - * Returns the value of this BigInt as a signed 64-bit integer. - * If `lossless` is provided, it will reflect whether this BigInt was - * truncated or not. - */ - int64_t Int64Value(Runtime& runtime, bool* lossless = nullptr) const { - return runtime.int64Value(*this, lossless); - } + + /// Create a BigInt representing the signed 64-bit \p value. + static BigInt fromInt64(Runtime& runtime, int64_t value) { + return runtime.createBigIntFromInt64(value); + } + + /// Create a BigInt representing the unsigned 64-bit \p value. + static BigInt fromUint64(Runtime& runtime, uint64_t value) { + return runtime.createBigIntFromUint64(value); + } + + /// \return whether a === b. + static bool strictEquals(Runtime& runtime, const BigInt& a, const BigInt& b) { + return runtime.strictEquals(a, b); + } + + /// \returns This bigint truncated to a signed 64-bit integer. + int64_t getInt64(Runtime& runtime) const { return runtime.truncate(*this); } + + /// \returns Whether this bigint can be losslessly converted to int64_t. + bool isInt64(Runtime& runtime) const { return runtime.bigintIsInt64(*this); } + + /// \returns This bigint truncated to a signed 64-bit integer. Throws a + /// JSIException if the truncation is lossy. + int64_t asInt64(Runtime& runtime) const; + + /// \returns This bigint truncated to an unsigned 64-bit integer. + uint64_t getUint64(Runtime& runtime) const { return runtime.truncate(*this); } + + /// \returns Whether this bigint can be losslessly converted to uint64_t. + bool isUint64(Runtime& runtime) const { + return runtime.bigintIsUint64(*this); + } + + /// \returns This bigint truncated to an unsigned 64-bit integer. Throws a + /// JSIException if the truncation is lossy. + uint64_t asUint64(Runtime& runtime) const; + + /// \returns this BigInt converted to a String in base \p radix. Throws a + /// JSIException if radix is not in the [2, 36] range. + inline String toString(Runtime& runtime, int radix = 10) const; friend class Runtime; friend class Value; @@ -565,8 +638,8 @@ class JSI_EXPORT String : public Pointer { /// Create a JS string from ascii values. The string data is /// copied. - static String - createFromAscii(Runtime& runtime, const char* str, size_t length) { + static String createFromAscii(Runtime& runtime, const char* str, + size_t length) { return runtime.createStringFromAscii(str, length); } @@ -585,8 +658,8 @@ class JSI_EXPORT String : public Pointer { /// Create a JS string from utf8-encoded octets. The string data is /// transformed and copied. Results are undefined if \p utf8 contains invalid /// code points. - static String - createFromUtf8(Runtime& runtime, const uint8_t* utf8, size_t length) { + static String createFromUtf8(Runtime& runtime, const uint8_t* utf8, + size_t length) { return runtime.createStringFromUtf8(utf8, length); } @@ -604,8 +677,25 @@ class JSI_EXPORT String : public Pointer { } /// Copies the data in a JS string as utf8 into a C++ string. - std::string utf8(Runtime& runtime) const { - return runtime.utf8(*this); + std::string utf8(Runtime& runtime) const { return runtime.utf8(*this); } + + /// Copies the data in a JS string as utf16 into a C++ string. + std::u16string utf16(Runtime& runtime) const { return runtime.utf16(*this); } + + /// Invokes the user provided callback to process content in String. The + /// callback must take in three arguments: bool ascii, const void* data, and + /// size_t num, respectively. \p ascii indicates whether the \p data passed to + /// the callback should be interpreted as a pointer to a sequence of \p num + /// ASCII characters or UTF16 characters. The function may invoke the callback + /// multiple times, with a different format on each invocation. The callback + /// must not access runtime functionality, as any operation on the runtime may + /// invalidate the data pointers. + template + void getStringData(Runtime& runtime, CB& cb) const { + runtime.getStringData( + *this, &cb, [](void* ctx, bool ascii, const void* data, size_t num) { + (*((CB*)ctx))(ascii, data, num); + }); } friend class Runtime; @@ -626,22 +716,36 @@ class JSI_EXPORT Object : public Pointer { /// Creates a new Object instance, like '{}' in JS. Object(Runtime& runtime) : Object(runtime.createObject()) {} - static Object createFromHostObject( - Runtime& runtime, - std::shared_ptr ho) { + static Object createFromHostObject(Runtime& runtime, + std::shared_ptr ho) { return runtime.createObject(ho); } + /// Creates a new Object with the custom prototype + static Object create(Runtime& runtime, const Value& prototype) { + return runtime.createObjectWithPrototype(prototype); + } + /// \return whether this and \c obj are the same JSObject or not. static bool strictEquals(Runtime& runtime, const Object& a, const Object& b) { return runtime.strictEquals(a, b); } /// \return the result of `this instanceOf ctor` in JS. - bool instanceOf(Runtime& rt, const Function& ctor) { + bool instanceOf(Runtime& rt, const Function& ctor) const { return rt.instanceOf(*this, ctor); } + /// Sets \p prototype as the prototype of the object. The prototype must be + /// either an Object or null. If the prototype was not set successfully, this + /// method will throw. + void setPrototype(Runtime& runtime, const Value& prototype) const { + return runtime.setPrototypeOf(*this, prototype); + } + + /// \return the prototype of the object + inline Value getPrototype(Runtime& runtime) const; + /// \return the property of the object with the given ascii name. /// If the name isn't a property on the object, returns the /// undefined value. @@ -673,117 +777,33 @@ class JSI_EXPORT Object : public Pointer { /// used to make one: nullptr_t, bool, double, int, const char*, /// String, or Object. template - void setProperty(Runtime& runtime, const char* name, T&& value); + void setProperty(Runtime& runtime, const char* name, T&& value) const; /// Sets the property value from a Value or anything which can be /// used to make one: nullptr_t, bool, double, int, const char*, /// String, or Object. template - void setProperty(Runtime& runtime, const String& name, T&& value); + void setProperty(Runtime& runtime, const String& name, T&& value) const; /// Sets the property value from a Value or anything which can be /// used to make one: nullptr_t, bool, double, int, const char*, /// String, or Object. template - void setProperty(Runtime& runtime, const PropNameID& name, T&& value); + void setProperty(Runtime& runtime, const PropNameID& name, T&& value) const; /// \return true iff JS \c Array.isArray() would return \c true. If /// so, then \c getArray() will succeed. - bool isArray(Runtime& runtime) const { - return runtime.isArray(*this); - } + bool isArray(Runtime& runtime) const { return runtime.isArray(*this); } /// \return true iff the Object is an ArrayBuffer. If so, then \c /// getArrayBuffer() will succeed. bool isArrayBuffer(Runtime& runtime) const { return runtime.isArrayBuffer(*this); } - - - /// \return true iff the Object is an isArrayBufferView. If so, then \c - /// getArrayBuffer() will succeed. - bool isArrayBufferView(Runtime& runtime) const { - return runtime.isArrayBufferView(*this); - } - - /// \return true iff the Object is an isTypedArray. If so, then \c - /// getArrayBuffer() will succeed. - bool isTypedArray(Runtime& runtime) const { - return runtime.isTypedArray(*this); - } - - - /// \return true iff the Object is an isInt8Array. If so, then \c - /// getArrayBuffer() will succeed. - bool isInt8Array(Runtime& runtime) const { - return runtime.isInt8Array(*this); - } - - /// \return true iff the Object is an isUint8Array. If so, then \c - /// getArrayBuffer() will succeed. - bool isUint8Array(Runtime& runtime) const { - return runtime.isUint8Array(*this); - } - - /// \return true iff the Object is an isUint8ClampedArray. If so, then \c - /// getArrayBuffer() will succeed. - bool isUint8ClampedArray(Runtime& runtime) const { - return runtime.isUint8ClampedArray(*this); - } - - /// \return true iff the Object is an isInt16Array. If so, then \c - /// getArrayBuffer() will succeed. - bool isInt16Array(Runtime& runtime) const { - return runtime.isInt16Array(*this); - } - - /// \return true iff the Object is an isUint16Array. If so, then \c - /// getArrayBuffer() will succeed. - bool isUint16Array(Runtime& runtime) const { - return runtime.isUint16Array(*this); - } - - /// \return true iff the Object is an isInt32Array. If so, then \c - /// getArrayBuffer() will succeed. - bool isInt32Array(Runtime& runtime) const { - return runtime.isInt32Array(*this); - } - - /// \return true iff the Object is an isUint32Array. If so, then \c - /// getArrayBuffer() will succeed. - bool isUint32Array(Runtime& runtime) const { - return runtime.isUint32Array(*this); - } - - /// \return true iff the Object is an isFloat32Array. If so, then \c - /// getArrayBuffer() will succeed. - bool isFloat32Array(Runtime& runtime) const { - return runtime.isFloat32Array(*this); - } - - /// \return true iff the Object is an isBigInt64Array. If so, then \c - /// getArrayBuffer() will succeed. - bool isBigInt64Array(Runtime& runtime) const { - return runtime.isBigInt64Array(*this); - } - - /// \return true iff the Object is an isBigUint64Array. If so, then \c - /// getArrayBuffer() will succeed. - bool isBigUint64Array(Runtime& runtime) const { - return runtime.isBigUint64Array(*this); - } - - /// \return true iff the Object is an isFloat64Array. If so, then \c - /// getArrayBuffer() will succeed. - bool isFloat64Array(Runtime& runtime) const { - return runtime.isFloat64Array(*this); - } /// \return true iff the Object is callable. If so, then \c /// getFunction will succeed. - bool isFunction(Runtime& runtime) const { - return runtime.isFunction(*this); - } + bool isFunction(Runtime& runtime) const { return runtime.isFunction(*this); } /// \return true iff the Object was initialized with \c createFromHostObject /// and the HostObject passed is of type \c T. If returns \c true then @@ -816,16 +836,6 @@ class JSI_EXPORT Object : public Pointer { /// \return an ArrayBuffer instance which refers to the same underlying /// object. If \c isArrayBuffer() would return false, this will assert. ArrayBuffer getArrayBuffer(Runtime& runtime) &&; - - - /// \return an TypedArray instance which refers to the same underlying - /// object. If \c isTypedArray() would return false, this will assert. - TypedArray getTypedArray(Runtime& runtime) const&; - - /// \return an TypedArray instance which refers to the same underlying - /// object. If \c isTypedArray() would return false, this will assert. - TypedArray getTypedArray(Runtime& runtime) &&; - /// \return a Function instance which refers to the same underlying /// object. If \c isFunction() would return false, this will assert. @@ -858,6 +868,25 @@ class JSI_EXPORT Object : public Pointer { template std::shared_ptr asHostObject(Runtime& runtime) const; + /// \return whether this object has native state of type T previously set by + /// \c setNativeState. + template + bool hasNativeState(Runtime& runtime) const; + + /// \return a shared_ptr to the state previously set by \c setNativeState. + /// If \c hasNativeState is false, this will assert. Note that this does a + /// type check and will assert if the native state isn't of type \c T + template + std::shared_ptr getNativeState(Runtime& runtime) const; + + /// Set the internal native state property of this object, overwriting any old + /// value. Creates a new shared_ptr to the object managed by \p state, which + /// will live until the value at this property becomes unreachable. + /// + /// Throws a type error if this object is a proxy or host object. + void setNativeState(Runtime& runtime, + std::shared_ptr state) const; + /// \return same as \c getProperty(name).asObject(), except with /// a better exception message. Object getPropertyAsObject(Runtime& runtime, const char* name) const; @@ -874,16 +903,24 @@ class JSI_EXPORT Object : public Pointer { /// works. I only need it in one place.) Array getPropertyNames(Runtime& runtime) const; + /// Inform the runtime that there is additional memory associated with a given + /// JavaScript object that is not visible to the GC. This can be used if an + /// object is known to retain some native memory, and may be used to guide + /// decisions about when to run garbage collection. + /// This method may be invoked multiple times on an object, and subsequent + /// calls will overwrite any previously set value. Once the object is garbage + /// collected, the associated external memory will be considered freed and may + /// no longer factor into GC decisions. + void setExternalMemoryPressure(Runtime& runtime, size_t amt) const; + protected: - void - setPropertyValue(Runtime& runtime, const String& name, const Value& value) { + void setPropertyValue(Runtime& runtime, const String& name, + const Value& value) const { return runtime.setPropertyValue(*this, name, value); } - void setPropertyValue( - Runtime& runtime, - const PropNameID& name, - const Value& value) { + void setPropertyValue(Runtime& runtime, const PropNameID& name, + const Value& value) const { return runtime.setPropertyValue(*this, name, value); } @@ -909,7 +946,7 @@ class JSI_EXPORT WeakObject : public Pointer { /// otherwise returns \c undefined. Note that this method has nothing to do /// with threads or concurrency. The name is based on std::weak_ptr::lock() /// which serves a similar purpose. - Value lock(Runtime& runtime); + Value lock(Runtime& runtime) const; friend class Runtime; }; @@ -926,15 +963,11 @@ class JSI_EXPORT Array : public Object { /// \return the size of the Array, according to its length property. /// (C++ naming convention) - size_t size(Runtime& runtime) const { - return runtime.size(*this); - } + size_t size(Runtime& runtime) const { return runtime.size(*this); } /// \return the size of the Array, according to its length property. /// (JS naming convention) - size_t length(Runtime& runtime) const { - return size(runtime); - } + size_t length(Runtime& runtime) const { return size(runtime); } /// \return the property of the array at index \c i. If there is no /// such property, returns the undefined value. If \c i is out of @@ -945,7 +978,7 @@ class JSI_EXPORT Array : public Object { /// value behaves as with Object::setProperty(). If \c i is out of /// range [ 0..\c length ] throws a JSIException. template - void setValueAtIndex(Runtime& runtime, size_t i, T&& value); + void setValueAtIndex(Runtime& runtime, size_t i, T&& value) const; /// There is no current API for changing the size of an array once /// created. We'll probably need that eventually. @@ -955,15 +988,16 @@ class JSI_EXPORT Array : public Object { static Array createWithElements(Runtime&, Args&&... args); /// Creates a new Array instance from initializer list. - static Array createWithElements( - Runtime& runtime, - std::initializer_list elements); + static Array createWithElements(Runtime& runtime, + std::initializer_list elements); private: friend class Object; friend class Value; + friend class Runtime; - void setValueAtIndexImpl(Runtime& runtime, size_t i, const Value& value) { + void setValueAtIndexImpl(Runtime& runtime, size_t i, + const Value& value) const { return runtime.setValueAtIndexImpl(*this, i, value); } @@ -975,65 +1009,27 @@ class JSI_EXPORT ArrayBuffer : public Object { public: ArrayBuffer(ArrayBuffer&&) = default; ArrayBuffer& operator=(ArrayBuffer&&) = default; - ArrayBuffer(Runtime& runtime, std::shared_ptr buffer) - : ArrayBuffer(runtime.createArrayBuffer(std::move(buffer))) {} - /// \return the size of the ArrayBuffer, according to its byteLength property. + ArrayBuffer(Runtime& runtime, std::shared_ptr buffer) + : ArrayBuffer(runtime.createArrayBuffer(std::move(buffer))) {} + + /// \return the size of the ArrayBuffer storage. This is not affected by + /// overriding the byteLength property. /// (C++ naming convention) - size_t size(Runtime& runtime) const { - return runtime.size(*this); - } + size_t size(Runtime& runtime) const { return runtime.size(*this); } - size_t length(Runtime& runtime) const { - return runtime.size(*this); - } + size_t length(Runtime& runtime) const { return runtime.size(*this); } - uint8_t* data(Runtime& runtime) { - return runtime.data(*this); - } + uint8_t* data(Runtime& runtime) const { return runtime.data(*this); } private: friend class Object; friend class Value; + friend class Runtime; ArrayBuffer(Runtime::PointerValue* value) : Object(value) {} }; - -/// Represents a TypedArray -class JSI_EXPORT TypedArray : public Object { -public: - TypedArray(TypedArray &&) = default; - - TypedArray &operator=(TypedArray &&) = default; - - /// \return the size of the TypedArray ArrayBuffer, according to its byteLength property. - /// (C++ naming convention) - size_t size(Runtime &runtime) { - return runtime.size(*this); - } - - size_t offset(Runtime &runtime) const { - return runtime.offset(*this); - } - - size_t length(Runtime &runtime) const { - return runtime.size(*this); - } - - uint8_t *data(Runtime &runtime) { - return runtime.data(*this); - } - -private: - friend class Object; - - friend class Value; - - TypedArray(Runtime::PointerValue *value) : Object(value) {} -}; - - /// Represents a JS Object which is guaranteed to be Callable. class JSI_EXPORT Function : public Object { public: @@ -1046,11 +1042,15 @@ class JSI_EXPORT Function : public Object { /// \param name the name property for the function. /// \param paramCount the length property for the function, which /// may not be the number of arguments the function is passed. - static Function createFromHostFunction( - Runtime& runtime, - const jsi::PropNameID& name, - unsigned int paramCount, - jsi::HostFunctionType func); + /// \note The std::function's dtor will be called when the GC finalizes this + /// function. As with HostObject, this may be as late as when the Runtime is + /// shut down, and may occur on an arbitrary thread. If the function contains + /// any captured values, you are responsible for ensuring that their + /// destructors are safe to call on any thread. + static Function createFromHostFunction(Runtime& runtime, + const jsi::PropNameID& name, + unsigned int paramCount, + jsi::HostFunctionType func); /// Calls the function with \c count \c args. The \c this value of the JS /// function will not be set by the C++ caller, similar to calling @@ -1081,35 +1081,30 @@ class JSI_EXPORT Function : public Object { /// Calls the function with \c count \c args and \c jsThis value passed /// as the \c this value. - Value callWithThis( - Runtime& Runtime, - const Object& jsThis, - const Value* args, - size_t count) const; + Value callWithThis(Runtime& Runtime, const Object& jsThis, const Value* args, + size_t count) const; /// Calls the function with a \c std::initializer_list of Value /// arguments and \c jsThis passed as the \c this value. - Value callWithThis( - Runtime& runtime, - const Object& jsThis, - std::initializer_list args) const; + Value callWithThis(Runtime& runtime, const Object& jsThis, + std::initializer_list args) const; /// Calls the function with any number of arguments similarly to /// Object::setProperty(), and with \c jsThis passed as the \c this value. template - Value callWithThis(Runtime& runtime, const Object& jsThis, Args&&... args) - const; + Value callWithThis(Runtime& runtime, const Object& jsThis, + Args&&... args) const; /// Calls the function as a constructor with \c count \c args. Equivalent /// to calling `new Func` where `Func` is the js function reqresented by /// this. - Value callAsConstructor(Runtime& runtime, const Value* args, size_t count) - const; + Value callAsConstructor(Runtime& runtime, const Value* args, + size_t count) const; /// Same as above `callAsConstructor`, except use an initializer_list to /// supply the arguments. - Value callAsConstructor(Runtime& runtime, std::initializer_list args) - const; + Value callAsConstructor(Runtime& runtime, + std::initializer_list args) const; /// Same as above `callAsConstructor`, but automatically converts/wraps /// any argument with a jsi Value. @@ -1138,6 +1133,7 @@ class JSI_EXPORT Function : public Object { private: friend class Object; friend class Value; + friend class Runtime; Function(Runtime::PointerValue* value) : Object(value) {} }; @@ -1148,35 +1144,27 @@ class JSI_EXPORT Function : public Object { class JSI_EXPORT Value { public: /// Default ctor creates an \c undefined JS value. - Value() : Value(UndefinedKind) {} + Value() noexcept : Value(UndefinedKind) {} /// Creates a \c null JS value. /* implicit */ Value(std::nullptr_t) : kind_(NullKind) {} /// Creates a boolean JS value. - /* implicit */ Value(bool b) : Value(BooleanKind) { - data_.boolean = b; - } + /* implicit */ Value(bool b) : Value(BooleanKind) { data_.boolean = b; } /// Creates a number JS value. - /* implicit */ Value(double d) : Value(NumberKind) { - data_.number = d; - } + /* implicit */ Value(double d) : Value(NumberKind) { data_.number = d; } /// Creates a number JS value. - /* implicit */ Value(int i) : Value(NumberKind) { - data_.number = i; - } + /* implicit */ Value(int i) : Value(NumberKind) { data_.number = i; } /// Moves a Symbol, String, or Object rvalue into a new JS value. - template + template ::value || + std::is_base_of::value || + std::is_base_of::value || + std::is_base_of::value>> /* implicit */ Value(T&& other) : Value(kindOf(other)) { - static_assert( - std::is_base_of::value || - std::is_base_of::value || - std::is_base_of::value || - std::is_base_of::value, - "Value cannot be implicitly move-constructed from this type"); new (&data_.pointer) T(std::move(other)); } @@ -1184,12 +1172,11 @@ class JSI_EXPORT Value { /// compile error. template Value(const char*) { - static_assert( - !std::is_same::value, - "Value cannot be constructed directly from const char*"); + static_assert(!std::is_same::value, + "Value cannot be constructed directly from const char*"); } - Value(Value&& value); + Value(Value&& other) noexcept; /// Copies a Symbol lvalue into a new JS value. Value(Runtime& runtime, const Symbol& sym) : Value(SymbolKind) { @@ -1218,25 +1205,20 @@ class JSI_EXPORT Value { /// that a compile error. template Value(Runtime&, const char*) { - static_assert( - !std::is_same::value, - "Value cannot be constructed directly from const char*"); + static_assert(!std::is_same::value, + "Value cannot be constructed directly from const char*"); } ~Value(); // \return the undefined \c Value. - static Value undefined() { - return Value(); - } + static Value undefined() { return Value(); } // \return the null \c Value. - static Value null() { - return Value(nullptr); - } + static Value null() { return Value(nullptr); } // \return a \c Value created from a utf8-encoded JSON string. - static Value - createFromJsonUtf8(Runtime& runtime, const uint8_t* json, size_t length) { + static Value createFromJsonUtf8(Runtime& runtime, const uint8_t* json, + size_t length) { return runtime.createValueFromJsonUtf8(json, length); } @@ -1244,43 +1226,27 @@ class JSI_EXPORT Value { /// https://262.ecma-international.org/11.0/#sec-strict-equality-comparison static bool strictEquals(Runtime& runtime, const Value& a, const Value& b); - Value& operator=(Value&& other) { + Value& operator=(Value&& other) noexcept { this->~Value(); new (this) Value(std::move(other)); return *this; } - bool isUndefined() const { - return kind_ == UndefinedKind; - } + bool isUndefined() const { return kind_ == UndefinedKind; } - bool isNull() const { - return kind_ == NullKind; - } + bool isNull() const { return kind_ == NullKind; } - bool isBool() const { - return kind_ == BooleanKind; - } + bool isBool() const { return kind_ == BooleanKind; } - bool isNumber() const { - return kind_ == NumberKind; - } + bool isNumber() const { return kind_ == NumberKind; } - bool isString() const { - return kind_ == StringKind; - } + bool isString() const { return kind_ == StringKind; } - bool isBigInt() const { - return kind_ == BigIntKind; - } + bool isBigInt() const { return kind_ == BigIntKind; } - bool isSymbol() const { - return kind_ == SymbolKind; - } + bool isSymbol() const { return kind_ == SymbolKind; } - bool isObject() const { - return kind_ == ObjectKind; - } + bool isObject() const { return kind_ == ObjectKind; } /// \return the boolean value, or asserts if not a boolean. bool getBool() const { @@ -1403,9 +1369,8 @@ class JSI_EXPORT Value { union Data { // Value's ctor and dtor will manage the lifecycle of the contained Data. Data() { - static_assert( - sizeof(Data) == sizeof(uint64_t), - "Value data should fit in a 64-bit register"); + static_assert(sizeof(Data) == sizeof(uint64_t), + "Value data should fit in a 64-bit register"); } ~Data() {} @@ -1413,23 +1378,15 @@ class JSI_EXPORT Value { bool boolean; double number; // pointers - Pointer pointer; // Symbol, String, Object, Array, Function + Pointer pointer; // Symbol, String, Object, Array, Function }; Value(ValueKind kind) : kind_(kind) {} - constexpr static ValueKind kindOf(const Symbol&) { - return SymbolKind; - } - constexpr static ValueKind kindOf(const BigInt&) { - return BigIntKind; - } - constexpr static ValueKind kindOf(const String&) { - return StringKind; - } - constexpr static ValueKind kindOf(const Object&) { - return ObjectKind; - } + constexpr static ValueKind kindOf(const Symbol&) { return SymbolKind; } + constexpr static ValueKind kindOf(const BigInt&) { return BigIntKind; } + constexpr static ValueKind kindOf(const String&) { return StringKind; } + constexpr static ValueKind kindOf(const Object&) { return ObjectKind; } ValueKind kind_; Data data_; @@ -1458,9 +1415,7 @@ class JSI_EXPORT Value { class JSI_EXPORT Scope { public: explicit Scope(Runtime& rt) : rt_(rt), prv_(rt.pushScope()) {} - ~Scope() { - rt_.popScope(prv_); - }; + ~Scope() { rt_.popScope(prv_); } Scope(const Scope&) = delete; Scope(Scope&&) = delete; @@ -1482,15 +1437,13 @@ class JSI_EXPORT Scope { /// Base class for jsi exceptions class JSI_EXPORT JSIException : public std::exception { protected: - JSIException(){}; - JSIException(std::string what) : what_(std::move(what)){}; + JSIException() {} + JSIException(std::string what) : what_(std::move(what)) {} public: JSIException(const JSIException&) = default; - virtual const char* what() const noexcept override { - return what_.c_str(); - } + virtual const char* what() const noexcept override { return what_.c_str(); } virtual ~JSIException() override; @@ -1524,7 +1477,7 @@ class JSI_EXPORT JSError : public JSIException { /// Creates a JSError referring to new \c Error instance capturing current /// JavaScript stack. The error message property is set to given \c message. JSError(Runtime& rt, const char* message) - : JSError(rt, std::string(message)){}; + : JSError(rt, std::string(message)) {} /// Creates a JSError referring to a JavaScript Object having message and /// stack properties set to provided values. @@ -1535,17 +1488,18 @@ class JSI_EXPORT JSError : public JSIException { /// but necessary to avoid ambiguity with the above. JSError(std::string what, Runtime& rt, Value&& value); + /// Creates a JSError referring to the provided value, message and stack. This + /// constructor does not take a Runtime parameter, and therefore cannot result + /// in recursively invoking the JSError constructor. + JSError(Value&& value, std::string message, std::string stack); + JSError(const JSError&) = default; virtual ~JSError(); - const std::string& getStack() const { - return stack_; - } + const std::string& getStack() const { return stack_; } - const std::string& getMessage() const { - return message_; - } + const std::string& getMessage() const { return message_; } const jsi::Value& value() const { assert(value_); @@ -1565,7 +1519,7 @@ class JSI_EXPORT JSError : public JSIException { std::string stack_; }; -} // namespace jsi -} // namespace facebook +} // namespace jsi +} // namespace facebook -#include "jsi/jsi-inl.h" +#include "jsi/jsi-inl.h" \ No newline at end of file diff --git a/NativeScript/jsi/jsilib-posix.cpp b/NativeScript/jsi/jsilib-posix.cpp index 303ba157..42fa1a09 100644 --- a/NativeScript/jsi/jsilib-posix.cpp +++ b/NativeScript/jsi/jsilib-posix.cpp @@ -12,6 +12,7 @@ #include #include #include + #include #include #include @@ -25,9 +26,8 @@ namespace { constexpr size_t kErrorBufferSize = 512; -__attribute__((format(printf, 1, 2))) void throwFormattedError( - const char* fmt, - ...) { +__attribute__((format(printf, 1, 2))) void throwFormattedError(const char* fmt, + ...) { char logBuffer[kErrorBufferSize]; va_list va_args; @@ -36,8 +36,8 @@ __attribute__((format(printf, 1, 2))) void throwFormattedError( va_end(va_args); if (result < 0) { - throw JSINativeException( - std::string("Failed to format error message: ") + fmt); + throw JSINativeException(std::string("Failed to format error message: ") + + fmt); } throw JSINativeException(logBuffer); @@ -48,20 +48,18 @@ class ScopedFile { ScopedFile(const std::string& path) : path_(path), fd_(::open(path.c_str(), O_RDONLY)) { if (fd_ == -1) { - throwFormattedError( - "Could not open %s: %s", path.c_str(), strerror(errno)); + throwFormattedError("Could not open %s: %s", path.c_str(), + strerror(errno)); } } - ~ScopedFile() { - ::close(fd_); - } + ~ScopedFile() { ::close(fd_); } size_t size() { struct stat fileInfo; if (::fstat(fd_, &fileInfo) == -1) { - throwFormattedError( - "Could not stat %s: %s", path_.c_str(), strerror(errno)); + throwFormattedError("Could not stat %s: %s", path_.c_str(), + strerror(errno)); } return fileInfo.st_size; } @@ -69,8 +67,8 @@ class ScopedFile { uint8_t* mmap(size_t size) { void* result = ::mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd_, 0); if (result == MAP_FAILED) { - throwFormattedError( - "Could not mmap %s: %s", path_.c_str(), strerror(errno)); + throwFormattedError("Could not mmap %s: %s", path_.c_str(), + strerror(errno)); } return reinterpret_cast(result); } @@ -79,7 +77,7 @@ class ScopedFile { const int fd_; }; -} // namespace +} // namespace FileBuffer::FileBuffer(const std::string& path) { ScopedFile file(path); @@ -91,18 +89,15 @@ FileBuffer::~FileBuffer() { if (::munmap(data_, size_)) { // terminate the program with pending exception try { - throwFormattedError( - "Could not unmap memory (%p, %zu bytes): %s", - data_, - size_, - strerror(errno)); + throwFormattedError("Could not unmap memory (%p, %zu bytes): %s", data_, + size_, strerror(errno)); } catch (...) { std::terminate(); } } } -} // namespace jsi -} // namespace facebook +} // namespace jsi +} // namespace facebook -#endif // !defined(_WINDOWS) +#endif // !defined(_WINDOWS) \ No newline at end of file diff --git a/NativeScript/jsi/jsilib-windows.cpp b/NativeScript/jsi/jsilib-windows.cpp index 25da1ea0..13892382 100644 --- a/NativeScript/jsi/jsilib-windows.cpp +++ b/NativeScript/jsi/jsilib-windows.cpp @@ -21,7 +21,7 @@ FileBuffer::~FileBuffer() { assert(false && "FileBuffer is not implemented on Windows"); } -} // namespace jsi -} // namespace facebook +} // namespace jsi +} // namespace facebook -#endif //_WINDOWS +#endif //_WINDOWS \ No newline at end of file diff --git a/NativeScript/jsi/jsilib.h b/NativeScript/jsi/jsilib.h index 68f711a6..0dad2ee8 100644 --- a/NativeScript/jsi/jsilib.h +++ b/NativeScript/jsi/jsilib.h @@ -17,13 +17,9 @@ class FileBuffer : public Buffer { FileBuffer(const std::string& path); ~FileBuffer() override; - size_t size() const override { - return size_; - } + size_t size() const override { return size_; } - const uint8_t* data() const override { - return data_; - } + const uint8_t* data() const override { return data_; } private: size_t size_; @@ -38,22 +34,15 @@ class SourceJavaScriptPreparation final : public jsi::PreparedJavaScript, std::string sourceURL_; public: - SourceJavaScriptPreparation( - std::shared_ptr buf, - std::string sourceURL) + SourceJavaScriptPreparation(std::shared_ptr buf, + std::string sourceURL) : buf_(std::move(buf)), sourceURL_(std::move(sourceURL)) {} - const std::string& sourceURL() const { - return sourceURL_; - } + const std::string& sourceURL() const { return sourceURL_; } - size_t size() const override { - return buf_->size(); - } - const uint8_t* data() const override { - return buf_->data(); - } + size_t size() const override { return buf_->size(); } + const uint8_t* data() const override { return buf_->data(); } }; -} // namespace jsi -} // namespace facebook +} // namespace jsi +} // namespace facebook \ No newline at end of file diff --git a/NativeScript/jsi/threadsafe.h b/NativeScript/jsi/threadsafe.h index 4855020b..768edb4a 100644 --- a/NativeScript/jsi/threadsafe.h +++ b/NativeScript/jsi/threadsafe.h @@ -28,12 +28,8 @@ template struct WithLock { L lock; WithLock(R& r) : lock(r) {} - void before() { - lock.lock(); - } - void after() { - lock.unlock(); - } + void before() { lock.lock(); } + void after() { lock.unlock(); } }; // The actual implementation of a given ThreadSafeRuntime. It's parameterized @@ -50,9 +46,8 @@ class ThreadSafeRuntimeImpl final public: template ThreadSafeRuntimeImpl(Args&&... args) - : WithRuntimeDecorator, R, ThreadSafeRuntime>( - unsafe_, - lock_), + : WithRuntimeDecorator, R, ThreadSafeRuntime>(unsafe_, + lock_), unsafe_(std::forward(args)...), lock_(unsafe_) {} @@ -60,20 +55,16 @@ class ThreadSafeRuntimeImpl final return WithRuntimeDecorator, R, ThreadSafeRuntime>::plain(); } - void lock() const override { - lock_.before(); - } + void lock() const override { lock_.before(); } - void unlock() const override { - lock_.after(); - } + void unlock() const override { lock_.after(); } private: R unsafe_; mutable WithLock lock_; }; -} // namespace detail +} // namespace detail -} // namespace jsi -} // namespace facebook +} // namespace jsi +} // namespace facebook \ No newline at end of file diff --git a/NativeScript/v8runtime/HostProxy.cpp b/NativeScript/v8runtime/HostProxy.cpp index 584f1318..0c58c8d3 100644 --- a/NativeScript/v8runtime/HostProxy.cpp +++ b/NativeScript/v8runtime/HostProxy.cpp @@ -13,13 +13,11 @@ namespace jsi = facebook::jsi; namespace rnv8 { -HostObjectProxy::HostObjectProxy( - V8Runtime &runtime, - v8::Isolate *isolate, - std::shared_ptr hostObject) +HostObjectProxy::HostObjectProxy(V8Runtime& runtime, v8::Isolate* isolate, + std::shared_ptr hostObject) : runtime_(runtime), isolate_(isolate), hostObject_(hostObject) {} -void HostObjectProxy::BindFinalizer(const v8::Local &object) { +void HostObjectProxy::BindFinalizer(const v8::Local& object) { v8::HandleScope scopedHandle(isolate_); weakHandle_.Reset(isolate_, object); weakHandle_.SetWeak(this, Finalizer, v8::WeakCallbackType::kParameter); @@ -30,36 +28,34 @@ std::shared_ptr HostObjectProxy::GetHostObject() { } // static -void HostObjectProxy::Getter( - v8::Local property, - const v8::PropertyCallbackInfo &info) { +void HostObjectProxy::Getter(v8::Local property, + const v8::PropertyCallbackInfo& info) { v8::HandleScope scopedHandle(info.GetIsolate()); v8::Local data = - v8::Local::Cast(info.This()->GetInternalField(0)); - HostObjectProxy *hostObjectProxy = - reinterpret_cast(data->Value()); + v8::Local::Cast(info.This()->GetInternalField(1)); + HostObjectProxy* hostObjectProxy = + reinterpret_cast(data->Value()); assert(hostObjectProxy); - auto &runtime = hostObjectProxy->runtime_; + auto& runtime = hostObjectProxy->runtime_; jsi::PropNameID sym = JSIV8ValueConverter::ToJSIPropNameID(runtime, property); jsi::Value ret; try { ret = hostObjectProxy->hostObject_->get(runtime, sym); - } catch (const jsi::JSError &error) { + } catch (const jsi::JSError& error) { info.GetIsolate()->ThrowException( JSIV8ValueConverter::ToV8Value(runtime, error.value())); return; - } catch (const std::exception &ex) { + } catch (const std::exception& ex) { auto excValue = runtime.global() .getPropertyAsFunction(runtime, "Error") - .call( - runtime, - std::string("Exception in HostObject::get(property:") + - JSIV8ValueConverter::ToSTLString( - info.GetIsolate(), property) + - std::string("): ") + ex.what()); + .call(runtime, + std::string("Exception in HostObject::get(property:") + + JSIV8ValueConverter::ToSTLString(info.GetIsolate(), + property) + + std::string("): ") + ex.what()); info.GetIsolate()->ThrowException( JSIV8ValueConverter::ToV8Value(runtime, excValue)); return; @@ -67,12 +63,11 @@ void HostObjectProxy::Getter( auto excValue = runtime.global() .getPropertyAsFunction(runtime, "Error") - .call( - runtime, - std::string("Exception in HostObject::get(property:") + - JSIV8ValueConverter::ToSTLString( - info.GetIsolate(), property) + - std::string("): ")); + .call(runtime, + std::string("Exception in HostObject::get(property:") + + JSIV8ValueConverter::ToSTLString(info.GetIsolate(), + property) + + std::string("): ")); info.GetIsolate()->ThrowException( JSIV8ValueConverter::ToV8Value(runtime, excValue)); return; @@ -81,38 +76,35 @@ void HostObjectProxy::Getter( } // static -void HostObjectProxy::Setter( - v8::Local property, - v8::Local value, - const v8::PropertyCallbackInfo &info) { +void HostObjectProxy::Setter(v8::Local property, + v8::Local value, + const v8::PropertyCallbackInfo& info) { v8::HandleScope scopedHandle(info.GetIsolate()); v8::Local data = - v8::Local::Cast(info.This()->GetInternalField(0)); - HostObjectProxy *hostObjectProxy = - reinterpret_cast(data->Value()); + v8::Local::Cast(info.This()->GetInternalField(1)); + HostObjectProxy* hostObjectProxy = + reinterpret_cast(data->Value()); assert(hostObjectProxy); - auto &runtime = hostObjectProxy->runtime_; + auto& runtime = hostObjectProxy->runtime_; jsi::PropNameID sym = JSIV8ValueConverter::ToJSIPropNameID(runtime, property); try { hostObjectProxy->hostObject_->set( - runtime, - sym, + runtime, sym, JSIV8ValueConverter::ToJSIValue(info.GetIsolate(), value)); - } catch (const jsi::JSError &error) { + } catch (const jsi::JSError& error) { info.GetIsolate()->ThrowException( JSIV8ValueConverter::ToV8Value(runtime, error.value())); return; - } catch (const std::exception &ex) { + } catch (const std::exception& ex) { auto excValue = runtime.global() .getPropertyAsFunction(runtime, "Error") - .call( - runtime, - std::string("Exception in HostObject::set(property:") + - JSIV8ValueConverter::ToSTLString( - info.GetIsolate(), property) + - std::string("): ") + ex.what()); + .call(runtime, + std::string("Exception in HostObject::set(property:") + + JSIV8ValueConverter::ToSTLString(info.GetIsolate(), + property) + + std::string("): ") + ex.what()); info.GetIsolate()->ThrowException( JSIV8ValueConverter::ToV8Value(runtime, excValue)); return; @@ -120,12 +112,11 @@ void HostObjectProxy::Setter( auto excValue = runtime.global() .getPropertyAsFunction(runtime, "Error") - .call( - runtime, - std::string("Exception in HostObject::set(property:") + - JSIV8ValueConverter::ToSTLString( - info.GetIsolate(), property) + - std::string("): ")); + .call(runtime, + std::string("Exception in HostObject::set(property:") + + JSIV8ValueConverter::ToSTLString(info.GetIsolate(), + property) + + std::string("): ")); info.GetIsolate()->ThrowException( JSIV8ValueConverter::ToV8Value(runtime, excValue)); return; @@ -135,16 +126,16 @@ void HostObjectProxy::Setter( // static void HostObjectProxy::Enumerator( - const v8::PropertyCallbackInfo &info) { + const v8::PropertyCallbackInfo& info) { v8::HandleScope scopedHandle(info.GetIsolate()); v8::Local data = - v8::Local::Cast(info.This()->GetInternalField(0)); - HostObjectProxy *hostObjectProxy = - reinterpret_cast(data->Value()); + v8::Local::Cast(info.This()->GetInternalField(1)); + HostObjectProxy* hostObjectProxy = + reinterpret_cast(data->Value()); assert(hostObjectProxy); - auto &runtime = hostObjectProxy->runtime_; + auto& runtime = hostObjectProxy->runtime_; auto names = hostObjectProxy->hostObject_->getPropertyNames(runtime); @@ -165,8 +156,8 @@ void HostObjectProxy::Enumerator( // static void HostObjectProxy::Finalizer( - const v8::WeakCallbackInfo &data) { - auto *pThis = data.GetParameter(); + const v8::WeakCallbackInfo& data) { + auto* pThis = data.GetParameter(); if (pThis->hostObject_.use_count() == 1) { pThis->hostObject_.reset(); } @@ -174,57 +165,55 @@ void HostObjectProxy::Finalizer( delete pThis; } -HostFunctionProxy::HostFunctionProxy( - V8Runtime &runtime, - v8::Isolate *isolate, - jsi::HostFunctionType &&hostFunction) +HostFunctionProxy::HostFunctionProxy(V8Runtime& runtime, v8::Isolate* isolate, + jsi::HostFunctionType&& hostFunction) : runtime_(runtime), isolate_(isolate), hostFunction_(std::move(hostFunction)) {} -void HostFunctionProxy::BindFinalizer(const v8::Local &object) { +void HostFunctionProxy::BindFinalizer(const v8::Local& object) { v8::HandleScope scopedHandle(isolate_); weakHandle_.Reset(isolate_, object); weakHandle_.SetWeak(this, Finalizer, v8::WeakCallbackType::kParameter); } -jsi::HostFunctionType &HostFunctionProxy::GetHostFunction() { +jsi::HostFunctionType& HostFunctionProxy::GetHostFunction() { return hostFunction_; } // static void HostFunctionProxy::Finalizer( - const v8::WeakCallbackInfo &data) { - auto *pThis = data.GetParameter(); + const v8::WeakCallbackInfo& data) { + auto* pThis = data.GetParameter(); pThis->weakHandle_.Reset(); delete pThis; } // static void HostFunctionProxy::FunctionCallback( - const v8::FunctionCallbackInfo &info) { + const v8::FunctionCallbackInfo& info) { v8::HandleScope scopedHandle(info.GetIsolate()); v8::Local data = v8::Local::Cast(info.Data()); - auto *hostFunctionProxy = - reinterpret_cast(data->Value()); + auto* hostFunctionProxy = reinterpret_cast(data->Value()); - auto &runtime = hostFunctionProxy->runtime_; + auto& runtime = hostFunctionProxy->runtime_; int argumentCount = info.Length(); const unsigned maxStackArgCount = 8; jsi::Value stackArgs[maxStackArgCount]; std::unique_ptr heapArgs; - jsi::Value *args; + jsi::Value* args; if (argumentCount > maxStackArgCount) { heapArgs = std::make_unique(argumentCount); for (size_t i = 0; i < argumentCount; i++) { - heapArgs[i] = JSIV8ValueConverter::ToJSIValue(info.GetIsolate(), info[(int) i]); + heapArgs[i] = + JSIV8ValueConverter::ToJSIValue(info.GetIsolate(), info[(int)i]); } args = heapArgs.get(); } else { for (size_t i = 0; i < argumentCount; i++) { stackArgs[i] = - JSIV8ValueConverter::ToJSIValue(info.GetIsolate(), info[(int) i]); + JSIV8ValueConverter::ToJSIValue(info.GetIsolate(), info[(int)i]); } args = stackArgs; } @@ -234,14 +223,13 @@ void HostFunctionProxy::FunctionCallback( JSIV8ValueConverter::ToJSIValue(info.GetIsolate(), info.This())); try { result = JSIV8ValueConverter::ToV8Value( - runtime, - hostFunctionProxy->hostFunction_( - runtime, thisVal, args, argumentCount)); - } catch (const jsi::JSError &error) { + runtime, hostFunctionProxy->hostFunction_(runtime, thisVal, args, + argumentCount)); + } catch (const jsi::JSError& error) { info.GetIsolate()->ThrowException( JSIV8ValueConverter::ToV8Value(runtime, error.value())); return; - } catch (const std::exception &ex) { + } catch (const std::exception& ex) { std::string exceptionString("Exception in HostFunction: "); exceptionString += ex.what(); auto excValue = runtime.global() @@ -264,4 +252,4 @@ void HostFunctionProxy::FunctionCallback( info.GetReturnValue().Set(result); } -} // namespace rnv8 +} // namespace rnv8 \ No newline at end of file diff --git a/NativeScript/v8runtime/HostProxy.h b/NativeScript/v8runtime/HostProxy.h index ce02f69d..af10c1b3 100644 --- a/NativeScript/v8runtime/HostProxy.h +++ b/NativeScript/v8runtime/HostProxy.h @@ -15,57 +15,50 @@ namespace rnv8 { class HostObjectProxy { public: - HostObjectProxy( - V8Runtime &runtime, - v8::Isolate *isolate, - std::shared_ptr hostObject); + HostObjectProxy(V8Runtime& runtime, v8::Isolate* isolate, + std::shared_ptr hostObject); - void BindFinalizer(const v8::Local &object); + void BindFinalizer(const v8::Local& object); std::shared_ptr GetHostObject(); public: - static void Getter( - v8::Local property, - const v8::PropertyCallbackInfo &info); + static void Getter(v8::Local property, + const v8::PropertyCallbackInfo& info); - static void Setter( - v8::Local property, - v8::Local value, - const v8::PropertyCallbackInfo &info); + static void Setter(v8::Local property, v8::Local value, + const v8::PropertyCallbackInfo& info); - static void Enumerator(const v8::PropertyCallbackInfo &info); + static void Enumerator(const v8::PropertyCallbackInfo& info); - static void Finalizer(const v8::WeakCallbackInfo &data); + static void Finalizer(const v8::WeakCallbackInfo& data); private: - V8Runtime &runtime_; - v8::Isolate *isolate_; + V8Runtime& runtime_; + v8::Isolate* isolate_; std::shared_ptr hostObject_; v8::Global weakHandle_; }; class HostFunctionProxy { public: - HostFunctionProxy( - V8Runtime &runtime, - v8::Isolate *isolate, - facebook::jsi::HostFunctionType &&hostFunction); + HostFunctionProxy(V8Runtime& runtime, v8::Isolate* isolate, + facebook::jsi::HostFunctionType&& hostFunction); - void BindFinalizer(const v8::Local &object); + void BindFinalizer(const v8::Local& object); - facebook::jsi::HostFunctionType &GetHostFunction(); + facebook::jsi::HostFunctionType& GetHostFunction(); public: - static void Finalizer(const v8::WeakCallbackInfo &data); + static void Finalizer(const v8::WeakCallbackInfo& data); - static void FunctionCallback(const v8::FunctionCallbackInfo &info); + static void FunctionCallback(const v8::FunctionCallbackInfo& info); private: - V8Runtime &runtime_; - v8::Isolate *isolate_; + V8Runtime& runtime_; + v8::Isolate* isolate_; facebook::jsi::HostFunctionType hostFunction_; v8::Global weakHandle_; }; -} // namespace rnv8 +} // namespace rnv8 \ No newline at end of file diff --git a/NativeScript/v8runtime/JSIV8ValueConverter.cpp b/NativeScript/v8runtime/JSIV8ValueConverter.cpp index 3d9f0c91..e7bc9655 100644 --- a/NativeScript/v8runtime/JSIV8ValueConverter.cpp +++ b/NativeScript/v8runtime/JSIV8ValueConverter.cpp @@ -6,6 +6,7 @@ */ #include "JSIV8ValueConverter.h" + #include "V8PointerValue.h" namespace jsi = facebook::jsi; @@ -13,9 +14,8 @@ namespace jsi = facebook::jsi; namespace rnv8 { // static -jsi::Value JSIV8ValueConverter::ToJSIValue( - v8::Isolate *isolate, - const v8::Local &value) { +jsi::Value JSIV8ValueConverter::ToJSIValue(v8::Isolate* isolate, + const v8::Local& value) { v8::HandleScope scopedHandle(isolate); if (value->IsUndefined()) { return jsi::Value::undefined(); @@ -39,18 +39,13 @@ jsi::Value JSIV8ValueConverter::ToJSIValue( if (value->IsObject()) { return V8Runtime::make(new V8PointerValue(isolate, value)); } - - if (value->IsBigInt()) { - return V8Runtime::make(new V8PointerValue(isolate, value)); - } return jsi::Value::undefined(); } // static -v8::Local JSIV8ValueConverter::ToV8Value( - const V8Runtime &runtime, - const jsi::Value &value) { +v8::Local JSIV8ValueConverter::ToV8Value(const V8Runtime& runtime, + const jsi::Value& value) { v8::EscapableHandleScope scopedHandle(runtime.isolate_); if (value.isUndefined()) { @@ -65,13 +60,10 @@ v8::Local JSIV8ValueConverter::ToV8Value( v8::Number::New(runtime.isolate_, std::move(value.getNumber()))); } else if (value.isString()) { return scopedHandle.Escape(ToV8String( - runtime, std::move(value.getString(const_cast(runtime))))); + runtime, std::move(value.getString(const_cast(runtime))))); } else if (value.isObject()) { return scopedHandle.Escape(ToV8Object( - runtime, std::move(value.getObject(const_cast(runtime))))); - }else if(value.isBigInt()){ - return scopedHandle.Escape(ToV8BigInt( - runtime, std::move(value.getBigInt(const_cast(runtime))))); + runtime, std::move(value.getObject(const_cast(runtime))))); } else { // What are you? std::abort(); @@ -80,11 +72,10 @@ v8::Local JSIV8ValueConverter::ToV8Value( // static v8::Local JSIV8ValueConverter::ToV8String( - const V8Runtime &runtime, - const jsi::String &string) { + const V8Runtime& runtime, const jsi::String& string) { v8::EscapableHandleScope scopedHandle(runtime.isolate_); - const V8PointerValue *v8PointerValue = - static_cast(runtime.getPointerValue(string)); + const V8PointerValue* v8PointerValue = + static_cast(runtime.getPointerValue(string)); assert(v8PointerValue->Get(runtime.isolate_)->IsString()); return scopedHandle.Escape( v8::Local::Cast(v8PointerValue->Get(runtime.isolate_))); @@ -92,11 +83,10 @@ v8::Local JSIV8ValueConverter::ToV8String( // static v8::Local JSIV8ValueConverter::ToV8String( - const V8Runtime &runtime, - const jsi::PropNameID &propName) { + const V8Runtime& runtime, const jsi::PropNameID& propName) { v8::EscapableHandleScope scopedHandle(runtime.isolate_); - const V8PointerValue *v8PointerValue = - static_cast(runtime.getPointerValue(propName)); + const V8PointerValue* v8PointerValue = + static_cast(runtime.getPointerValue(propName)); assert(v8PointerValue->Get(runtime.isolate_)->IsString()); return scopedHandle.Escape( v8::Local::Cast(v8PointerValue->Get(runtime.isolate_))); @@ -104,24 +94,21 @@ v8::Local JSIV8ValueConverter::ToV8String( // static v8::MaybeLocal JSIV8ValueConverter::ToV8String( - const V8Runtime &runtime, - const std::shared_ptr &buffer) { + const V8Runtime& runtime, + const std::shared_ptr& buffer) { v8::EscapableHandleScope scopedHandle(runtime.isolate_); v8::MaybeLocal ret = v8::String::NewFromUtf8( - runtime.isolate_, - reinterpret_cast(buffer->data()), - v8::NewStringType::kNormal, - (int) buffer->size()); + runtime.isolate_, reinterpret_cast(buffer->data()), + v8::NewStringType::kNormal, (int)buffer->size()); return scopedHandle.EscapeMaybe(ret); } // static v8::Local JSIV8ValueConverter::ToV8Symbol( - const V8Runtime &runtime, - const jsi::Symbol &symbol) { + const V8Runtime& runtime, const jsi::Symbol& symbol) { v8::EscapableHandleScope scopedHandle(runtime.isolate_); - const V8PointerValue *v8PointerValue = - static_cast(runtime.getPointerValue(symbol)); + const V8PointerValue* v8PointerValue = + static_cast(runtime.getPointerValue(symbol)); assert(v8PointerValue->Get(runtime.isolate_)->IsSymbol()); return scopedHandle.Escape( v8::Local::Cast(v8PointerValue->Get(runtime.isolate_))); @@ -129,36 +116,21 @@ v8::Local JSIV8ValueConverter::ToV8Symbol( // static v8::Local JSIV8ValueConverter::ToV8Object( - const V8Runtime &runtime, - const jsi::Object &object) { + const V8Runtime& runtime, const jsi::Object& object) { v8::EscapableHandleScope scopedHandle(runtime.isolate_); - const V8PointerValue *v8PointerValue = - static_cast(runtime.getPointerValue(object)); + const V8PointerValue* v8PointerValue = + static_cast(runtime.getPointerValue(object)); assert(v8PointerValue->Get(runtime.isolate_)->IsObject()); return scopedHandle.Escape( v8::Local::Cast(v8PointerValue->Get(runtime.isolate_))); } // static -v8::Local JSIV8ValueConverter::ToV8BigInt( - const V8Runtime &runtime, - const jsi::BigInt &bigInt) { - v8::EscapableHandleScope scopedHandle(runtime.isolate_); - const auto *v8PointerValue = - static_cast(runtime.getPointerValue(bigInt)); - assert(v8PointerValue->Get(runtime.isolate_)->IsBigInt()); - return scopedHandle.Escape( - v8::Local::Cast(v8PointerValue->Get(runtime.isolate_))); -} - - -// static -v8::Local JSIV8ValueConverter::ToV8Array( - const V8Runtime &runtime, - const jsi::Array &array) { +v8::Local JSIV8ValueConverter::ToV8Array(const V8Runtime& runtime, + const jsi::Array& array) { v8::EscapableHandleScope scopedHandle(runtime.isolate_); - const V8PointerValue *v8PointerValue = - static_cast(runtime.getPointerValue(array)); + const V8PointerValue* v8PointerValue = + static_cast(runtime.getPointerValue(array)); assert(v8PointerValue->Get(runtime.isolate_)->IsArray()); return scopedHandle.Escape( v8::Local::Cast(v8PointerValue->Get(runtime.isolate_))); @@ -166,11 +138,10 @@ v8::Local JSIV8ValueConverter::ToV8Array( // static v8::Local JSIV8ValueConverter::ToV8Function( - const V8Runtime &runtime, - const jsi::Function &function) { + const V8Runtime& runtime, const jsi::Function& function) { v8::EscapableHandleScope scopedHandle(runtime.isolate_); - const V8PointerValue *v8PointerValue = - static_cast(runtime.getPointerValue(function)); + const V8PointerValue* v8PointerValue = + static_cast(runtime.getPointerValue(function)); assert(v8PointerValue->Get(runtime.isolate_)->IsFunction()); return scopedHandle.Escape( v8::Local::Cast(v8PointerValue->Get(runtime.isolate_))); @@ -178,8 +149,7 @@ v8::Local JSIV8ValueConverter::ToV8Function( // static jsi::PropNameID JSIV8ValueConverter::ToJSIPropNameID( - const V8Runtime &runtime, - const v8::Local &property) { + const V8Runtime& runtime, const v8::Local& property) { v8::HandleScope scopedHandle(runtime.isolate_); return runtime.make( new V8PointerValue(runtime.isolate_, property)); @@ -187,7 +157,7 @@ jsi::PropNameID JSIV8ValueConverter::ToJSIPropNameID( // static std::string JSIV8ValueConverter::ToSTLString( - const v8::String::Utf8Value &string) { + const v8::String::Utf8Value& string) { if (*string) { return std::string(*string, string.length()); } @@ -196,12 +166,11 @@ std::string JSIV8ValueConverter::ToSTLString( // static std::string JSIV8ValueConverter::ToSTLString( - v8::Isolate *isolate, - const v8::Local &string) { + v8::Isolate* isolate, const v8::Local& string) { v8::HandleScope scopedHandle(isolate); assert(string->IsString()); v8::String::Utf8Value utf8(isolate, string); return ToSTLString(utf8); } -} // namespace rnv8 +} // namespace rnv8 \ No newline at end of file diff --git a/NativeScript/v8runtime/JSIV8ValueConverter.h b/NativeScript/v8runtime/JSIV8ValueConverter.h index fd6983da..0816a5fd 100644 --- a/NativeScript/v8runtime/JSIV8ValueConverter.h +++ b/NativeScript/v8runtime/JSIV8ValueConverter.h @@ -17,58 +17,44 @@ class JSIV8ValueConverter { private: JSIV8ValueConverter() = delete; ~JSIV8ValueConverter() = delete; - JSIV8ValueConverter(JSIV8ValueConverter &&) = delete; + JSIV8ValueConverter(JSIV8ValueConverter&&) = delete; public: - static facebook::jsi::Value ToJSIValue( - v8::Isolate *isolate, - const v8::Local &value); + static facebook::jsi::Value ToJSIValue(v8::Isolate* isolate, + const v8::Local& value); - static v8::Local ToV8Value( - const V8Runtime &runtime, - const facebook::jsi::Value &value); + static v8::Local ToV8Value(const V8Runtime& runtime, + const facebook::jsi::Value& value); - static v8::Local ToV8String( - const V8Runtime &runtime, - const facebook::jsi::String &string); + static v8::Local ToV8String(const V8Runtime& runtime, + const facebook::jsi::String& string); static v8::Local ToV8String( - const V8Runtime &runtime, - const facebook::jsi::PropNameID &propName); + const V8Runtime& runtime, const facebook::jsi::PropNameID& propName); static v8::MaybeLocal ToV8String( - const V8Runtime &runtime, - const std::shared_ptr &buffer); + const V8Runtime& runtime, + const std::shared_ptr& buffer); - static v8::Local ToV8Symbol( - const V8Runtime &runtime, - const facebook::jsi::Symbol &symbol); + static v8::Local ToV8Symbol(const V8Runtime& runtime, + const facebook::jsi::Symbol& symbol); - static v8::Local ToV8Object( - const V8Runtime &runtime, - const facebook::jsi::Object &object); - - static v8::Local ToV8BigInt( - const V8Runtime &runtime, - const facebook::jsi::BigInt &bigInt); + static v8::Local ToV8Object(const V8Runtime& runtime, + const facebook::jsi::Object& object); - static v8::Local ToV8Array( - const V8Runtime &runtime, - const facebook::jsi::Array &array); + static v8::Local ToV8Array(const V8Runtime& runtime, + const facebook::jsi::Array& array); static v8::Local ToV8Function( - const V8Runtime &runtime, - const facebook::jsi::Function &function); + const V8Runtime& runtime, const facebook::jsi::Function& function); static facebook::jsi::PropNameID ToJSIPropNameID( - const V8Runtime &runtime, - const v8::Local &property); + const V8Runtime& runtime, const v8::Local& property); - static std::string ToSTLString(const v8::String::Utf8Value &string); + static std::string ToSTLString(const v8::String::Utf8Value& string); - static std::string ToSTLString( - v8::Isolate *isolate, - const v8::Local &string); + static std::string ToSTLString(v8::Isolate* isolate, + const v8::Local& string); }; -} // namespace rnv8 +} // namespace rnv8 \ No newline at end of file diff --git a/NativeScript/v8runtime/V8PointerValue.cpp b/NativeScript/v8runtime/V8PointerValue.cpp index e7b65641..d8aaa584 100644 --- a/NativeScript/v8runtime/V8PointerValue.cpp +++ b/NativeScript/v8runtime/V8PointerValue.cpp @@ -9,35 +9,35 @@ namespace rnv8 { -V8PointerValue::V8PointerValue( - v8::Isolate *isolate, - const v8::Local &value) +V8PointerValue::V8PointerValue(v8::Isolate* isolate, + const v8::Local& value) : isolate_(isolate), value_(isolate, value) {} -V8PointerValue::V8PointerValue( - v8::Isolate *isolate, - v8::Global &&value) +V8PointerValue::V8PointerValue(v8::Isolate* isolate, + v8::Global&& value) : isolate_(isolate), value_(std::move(value)) {} V8PointerValue::~V8PointerValue() {} -v8::Local V8PointerValue::Get(v8::Isolate *isolate) const { +v8::Local V8PointerValue::Get(v8::Isolate* isolate) const { v8::EscapableHandleScope scopedHandle(isolate); return scopedHandle.Escape(value_.Get(isolate)); } +void V8PointerValue::Reset(v8::Isolate* isolate, v8::Local value) { + v8::HandleScope scopedHandle(isolate); + value_.Reset(isolate, value); +} + // static -V8PointerValue *V8PointerValue::createFromOneByte( - v8::Isolate *isolate, - const char *str, - size_t length) { +V8PointerValue* V8PointerValue::createFromOneByte(v8::Isolate* isolate, + const char* str, + size_t length) { v8::HandleScope scopedHandle(isolate); v8::Local v8String; if (!v8::String::NewFromOneByte( - isolate, - reinterpret_cast(str), - v8::NewStringType::kNormal, - static_cast(length)) + isolate, reinterpret_cast(str), + v8::NewStringType::kNormal, static_cast(length)) .ToLocal(&v8String)) { return nullptr; } @@ -45,17 +45,14 @@ V8PointerValue *V8PointerValue::createFromOneByte( } // static -V8PointerValue *V8PointerValue::createFromUtf8( - v8::Isolate *isolate, - const uint8_t *str, - size_t length) { +V8PointerValue* V8PointerValue::createFromUtf8(v8::Isolate* isolate, + const uint8_t* str, + size_t length) { v8::HandleScope scopedHandle(isolate); v8::Local v8String; - if (!v8::String::NewFromUtf8( - isolate, - reinterpret_cast(str), - v8::NewStringType::kNormal, - static_cast(length)) + if (!v8::String::NewFromUtf8(isolate, reinterpret_cast(str), + v8::NewStringType::kNormal, + static_cast(length)) .ToLocal(&v8String)) { return nullptr; } @@ -71,4 +68,4 @@ void V8PointerValue::invalidate() { delete this; } -} // namespace rnv8 +} // namespace rnv8 \ No newline at end of file diff --git a/NativeScript/v8runtime/V8PointerValue.h b/NativeScript/v8runtime/V8PointerValue.h index 57d206f3..0ed63ff0 100644 --- a/NativeScript/v8runtime/V8PointerValue.h +++ b/NativeScript/v8runtime/V8PointerValue.h @@ -15,21 +15,23 @@ namespace rnv8 { class V8PointerValue final : public V8Runtime::PointerValue { public: - V8PointerValue(v8::Isolate *isolate, const v8::Local &value); + V8PointerValue(v8::Isolate* isolate, const v8::Local& value); // Passing Global value directly - V8PointerValue(v8::Isolate *isolate, v8::Global &&value); + V8PointerValue(v8::Isolate* isolate, v8::Global&& value); ~V8PointerValue() override; - v8::Local Get(v8::Isolate *isolate) const; + v8::Local Get(v8::Isolate* isolate) const; + + void Reset(v8::Isolate* isolate, v8::Local value); public: - static V8PointerValue * - createFromOneByte(v8::Isolate *isolate, const char *str, size_t length); + static V8PointerValue* createFromOneByte(v8::Isolate* isolate, + const char* str, size_t length); - static V8PointerValue * - createFromUtf8(v8::Isolate *isolate, const uint8_t *str, size_t length); + static V8PointerValue* createFromUtf8(v8::Isolate* isolate, + const uint8_t* str, size_t length); private: void invalidate() override; @@ -37,8 +39,8 @@ class V8PointerValue final : public V8Runtime::PointerValue { private: friend class JSIV8ValueConverter; friend class V8Runtime; - v8::Isolate *isolate_; + v8::Isolate* isolate_; v8::Global value_; }; -} // namespace rnv8 +} // namespace rnv8 \ No newline at end of file diff --git a/NativeScript/v8runtime/V8Runtime.cpp b/NativeScript/v8runtime/V8Runtime.cpp index ffc27de6..131fa656 100644 --- a/NativeScript/v8runtime/V8Runtime.cpp +++ b/NativeScript/v8runtime/V8Runtime.cpp @@ -4,13 +4,20 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -#include "v8.h" -#include "runtime/Runtime.h" + #include "V8Runtime.h" + +#include "runtime/Runtime.h" +#include "v8.h" + +// #include +#include #include #include + #include "HostProxy.h" #include "JSIV8ValueConverter.h" +// #include "V8Inspector.h" #include "V8PointerValue.h" #include "jsi/jsilib.h" @@ -22,56 +29,231 @@ namespace { const char kHostFunctionProxyProp[] = "__hostFunctionProxy"; -} // namespace +} // namespace // static std::unique_ptr V8Runtime::s_platform = nullptr; -std::mutex s_platform_mutex; // protects s_platform +std::mutex s_platform_mutex; // protects s_platform V8Runtime::V8Runtime() { isolate_ = tns::Runtime::GetCurrentRuntime()->GetIsolate(); + + // V8Runtime::V8Runtime( + // std::unique_ptr config, + // std::shared_ptr jsQueue) + // : config_(std::move(config)) { + // { + // const std::lock_guard lock(s_platform_mutex); + // if (!s_platform) { + // s_platform = v8::platform::NewDefaultPlatform(); + // v8::V8::InitializeICU(); + // v8::V8::InitializePlatform(s_platform.get()); + // #if TARGET_OS_IOS + // v8::V8::SetFlagsFromString("--nolazy --nofreeze_flags_after_init"); + // #else + // v8::V8::SetFlagsFromString("--nolazy"); + // #endif + // v8::V8::Initialize(); + // } + // } + + // if (config_->snapshotBlob) { + // snapshotBlob_ = std::make_unique(); + // snapshotBlob_->data = config_->snapshotBlob->c_str(); + // snapshotBlob_->raw_size = + // static_cast(config_->snapshotBlob->size()); + // createParams.snapshot_blob = snapshotBlob_.get(); + // } + v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); context_.Reset(isolate_, isolate_->GetCurrentContext()); + v8::Context::Scope scopedContext(context_.Get(isolate_)); arrayBufferAllocator_.reset( - v8::ArrayBuffer::Allocator::NewDefaultAllocator()); -} -v8::Isolate *V8Runtime::GetIsolate() { - return tns::Runtime::GetCurrentRuntime()->GetIsolate(); - -} + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + // jsQueue_ = jsQueue; + // if (config_->enableInspector) { + // inspectorClient_ = std::make_shared( + // jsQueue_, + // context_.Get(isolate_), + // config_->appName, + // config_->deviceName); + // inspectorClient_->ConnectToReactFrontend(); + // } +} + +// V8Runtime::V8Runtime(const V8Runtime* v8Runtime, +// std::unique_ptr config) +// : config_(std::move(config)) { +// arrayBufferAllocator_.reset( +// v8::ArrayBuffer::Allocator::NewDefaultAllocator()); +// v8::Isolate::CreateParams createParams; +// createParams.array_buffer_allocator = arrayBufferAllocator_.get(); +// if (v8Runtime->config_->snapshotBlob) { +// snapshotBlob_ = std::make_unique(); +// snapshotBlob_->data = v8Runtime->config_->snapshotBlob->c_str(); +// snapshotBlob_->raw_size = +// static_cast(v8Runtime->config_->snapshotBlob->size()); +// createParams.snapshot_blob = snapshotBlob_.get(); +// } +// config_->codecacheMode = V8RuntimeConfig::CodecacheMode::kNone; + +// isolate_ = v8::Isolate::New(createParams); +// #if defined(__ANDROID__) +// if (!v8Runtime->config_->timezoneId.empty()) { +// isolate_->DateTimeConfigurationChangeNotification( +// v8::Isolate::TimeZoneDetection::kCustom, +// v8Runtime->config_->timezoneId.c_str()); +// } +// #endif +// v8::Locker locker(isolate_); +// v8::Isolate::Scope scopedIsolate(isolate_); +// v8::HandleScope scopedHandle(isolate_); +// context_.Reset(isolate_, CreateGlobalContext(isolate_)); +// v8::Context::Scope scopedContext(context_.Get(isolate_)); +// // jsQueue_ = v8Runtime->jsQueue_; + +// // if (config_->enableInspector) { +// // inspectorClient_ = std::make_shared( +// // jsQueue_, +// // context_.Get(isolate_), +// // config_->appName, +// // config_->deviceName); +// // inspectorClient_->ConnectToReactFrontend(); +// // } + +// #if 0 // Experimental shared global context +// isSharedRuntime_ = true; +// isolate_ = v8Runtime->isolate_; +// // jsQueue_ = v8Runtime->jsQueue_; + +// v8::Locker locker(isolate_); +// v8::Isolate::Scope scopedIsolate(isolate_); +// v8::HandleScope scopedHandle(isolate_); +// context_.Reset(isolate_, CreateGlobalContext(isolate_)); + +// auto localContext = context_.Get(isolate_); +// localContext->SetSecurityToken( +// v8Runtime->context_.Get(isolate_)->GetSecurityToken()); + +// bool inheritProtoResult = +// localContext->Global() +// ->GetPrototype() +// .As() +// ->SetPrototype( +// localContext, +// v8Runtime->context_.Get(isolate_)->Global()->GetPrototype()) +// .FromJust(); +// if (!inheritProtoResult) { +// LOG(ERROR) << "Unable to inherit prototype from parent shared runtime."; +// } + +// // if (config_->enableInspector) { +// // inspectorClient_ = std::make_shared( +// // jsQueue_, +// // context_.Get(isolate_), +// // config_->appName, +// // config_->deviceName); +// // inspectorClient_->ConnectToReactFrontend(); +// // } +// #endif +// } V8Runtime::~V8Runtime() { { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); + if (inspectorClient_) { + inspectorClient_.reset(); + } + context_.Reset(); } - //if (!isSharedRuntime_) { - //isolate_->Dispose(); - //} + if (!isSharedRuntime_) { + isolate_->Dispose(); + } // v8::V8::Dispose(); // v8::V8::DisposePlatform(); } void V8Runtime::OnMainLoopIdle() { -// v8::Locker locker(isolate_); -// v8::Isolate::Scope scopedIsolate(isolate_); -// v8::HandleScope scopedHandle(isolate_); -// v8::Context::Scope scopedContext(context_.Get(isolate_)); -// -// while (v8::platform::PumpMessageLoop( -// s_platform.get(), -// isolate_, -// v8::platform::MessageLoopBehavior::kDoNotWait)) { -// continue; -// } -} - -void V8Runtime::ReportException(v8::Isolate *isolate, v8::TryCatch *tryCatch) -const { + // v8::Locker locker(isolate_); + // v8::Isolate::Scope scopedIsolate(isolate_); + // v8::HandleScope scopedHandle(isolate_); + // v8::Context::Scope scopedContext(context_.Get(isolate_)); + + // while (v8::platform::PumpMessageLoop( + // s_platform.get(), isolate_, + // v8::platform::MessageLoopBehavior::kDoNotWait)) { + // continue; + // } +} + +// v8::Local V8Runtime::CreateGlobalContext(v8::Isolate* isolate) { +// v8::HandleScope scopedHandle(isolate); +// v8::Local global = v8::ObjectTemplate::New(isolate_); +// global->Set( +// v8::String::NewFromUtf8(isolate, "_v8runtime", +// v8::NewStringType::kNormal) +// .ToLocalChecked(), +// v8::FunctionTemplate::New(isolate, V8Runtime::GetRuntimeInfo)); +// return v8::Context::New(isolate_, nullptr, global); +// } + +// jsi::Value V8Runtime::ExecuteScript(v8::Isolate* isolate, +// const v8::Local& script, +// const std::string& sourceURL) { +// v8::HandleScope scopedHandle(isolate); +// v8::TryCatch tryCatch(isolate); + +// v8::MaybeLocal sourceURLValue = v8::String::NewFromUtf8( +// isolate, sourceURL.c_str(), v8::NewStringType::kNormal, +// static_cast(sourceURL.length())); +// v8::ScriptOrigin origin(isolate, sourceURLValue.ToLocalChecked()); + +// v8::Local context(isolate->GetCurrentContext()); + +// auto codecache = LoadCodeCacheIfNeeded(sourceURL); +// v8::ScriptCompiler::CachedData* cachedData = codecache.release(); + +// std::unique_ptr source = +// UseFakeSourceIfNeeded(origin, cachedData); +// if (!source) { +// source = std::make_unique(script, origin, +// cachedData); +// } + +// v8::Local compiledScript; +// if (!v8::ScriptCompiler::Compile(context, source.release(), +// cachedData +// ? +// v8::ScriptCompiler::kConsumeCodeCache +// : +// v8::ScriptCompiler::kNoCompileOptions) +// .ToLocal(&compiledScript)) { +// ReportException(isolate, &tryCatch); +// return {}; +// } + +// if (cachedData && cachedData->rejected) { +// LOG(INFO) << "[rnv8] cache miss: " << sourceURL; +// } +// SaveCodeCacheIfNeeded(compiledScript, sourceURL, cachedData); + +// v8::Local result; +// if (!compiledScript->Run(context).ToLocal(&result)) { +// assert(tryCatch.HasCaught()); +// ReportException(isolate, &tryCatch); +// return {}; +// } + +// return JSIV8ValueConverter::ToJSIValue(isolate, result); +// } + +void V8Runtime::ReportException(v8::Isolate* isolate, + v8::TryCatch* tryCatch) const { v8::HandleScope scopedHandle(isolate); std::string exception = JSIV8ValueConverter::ToSTLString(isolate, tryCatch->Exception()); @@ -79,7 +261,7 @@ const { if (message.IsEmpty()) { // V8 didn't provide any extra information about this error; just // print the exception. - throw jsi::JSError(const_cast(*this), exception); + throw jsi::JSError(const_cast(*this), exception); return; } else { std::ostringstream ss; @@ -114,37 +296,145 @@ const { v8::String::Utf8Value stackTrace(isolate, stackTraceString); ss << JSIV8ValueConverter::ToSTLString(stackTrace) << std::endl; } - throw jsi::JSError(const_cast(*this), ss.str()); + + throw jsi::JSError(const_cast(*this), ss.str()); return; } } -// static -v8::Platform *V8Runtime::GetPlatform() { - return s_platform.get(); +// std::unique_ptr +// V8Runtime::LoadCodeCacheIfNeeded(const std::string& sourceURL) { +// // caching is for main runtime only +// if (isSharedRuntime_) { +// return nullptr; +// } + +// if (config_->codecacheMode == V8RuntimeConfig::CodecacheMode::kNone) { +// return nullptr; +// } + +// std::filesystem::path codecachePath(config_->codecacheDir); +// codecachePath /= std::filesystem::path(sourceURL).filename(); +// auto* file = std::fopen(codecachePath.string().c_str(), "rb"); +// if (!file) { +// LOG(INFO) << "Cannot load codecache file: " << codecachePath.string(); +// return nullptr; +// } +// std::fseek(file, 0, SEEK_END); +// size_t size = std::ftell(file); +// uint8_t* buffer = new uint8_t[size]; +// std::rewind(file); + +// std::fread(buffer, size, 1, file); +// std::fclose(file); + +// return std::make_unique( +// buffer, static_cast(size), +// v8::ScriptCompiler::CachedData::BufferPolicy::BufferOwned); +// } + +// bool V8Runtime::SaveCodeCacheIfNeeded( +// const v8::Local& script, const std::string& sourceURL, +// v8::ScriptCompiler::CachedData* cachedData) { +// // caching is for main runtime only +// if (isSharedRuntime_) { +// return false; +// } + +// if (cachedData && !cachedData->rejected) { +// return false; +// } + +// if (config_->codecacheMode == V8RuntimeConfig::CodecacheMode::kNone) { +// return false; +// } + +// v8::HandleScope scopedHandle(isolate_); + +// v8::Local unboundScript = script->GetUnboundScript(); +// std::unique_ptr newCachedData; +// newCachedData.reset(v8::ScriptCompiler::CreateCodeCache(unboundScript)); +// if (!newCachedData) { +// return false; +// } + +// std::filesystem::path codecachePath(config_->codecacheDir); +// codecachePath /= std::filesystem::path(sourceURL).filename(); +// if (auto* file = std::fopen(codecachePath.string().c_str(), "wb")) { +// std::fwrite(newCachedData->data, 1, newCachedData->length, file); +// std::fclose(file); +// return true; +// } else { +// LOG(ERROR) << "Cannot save codecache file: " << codecachePath.string(); +// return false; +// } +// } + +// std::unique_ptr V8Runtime::UseFakeSourceIfNeeded( +// const v8::ScriptOrigin& origin, +// v8::ScriptCompiler::CachedData* cachedData) { +// // caching is for main runtime only +// if (isSharedRuntime_) { +// return nullptr; +// } + +// if (!cachedData) { +// return nullptr; +// } + +// if (config_->codecacheMode == V8RuntimeConfig::CodecacheMode::kStubBundle) +// { +// uint32_t payloadSize = +// (cachedData->data[8] << 0) | (cachedData->data[9] << 8) | +// (cachedData->data[10] << 16) | (cachedData->data[11] << 24); +// std::string stubScriptString(payloadSize, ' '); +// v8::Local stubScript = +// v8::String::NewFromUtf8(isolate_, stubScriptString.c_str()) +// .ToLocalChecked(); +// return std::make_unique(stubScript, origin, +// cachedData); +// } + +// return nullptr; +// } + +V8Runtime::InternalFieldType V8Runtime::GetInternalFieldType( + v8::Local object) const { + if (object->InternalFieldCount() != 2) { + return V8Runtime::InternalFieldType::kInvalid; + } + v8::Local typeValue = object->GetInternalField(0); + assert(typeValue->IsUint32()); + return static_cast( + v8::Local::Cast(typeValue)->Value()); } +// static +v8::Platform* V8Runtime::GetPlatform() { return s_platform.get(); } +// // jsi::Runtime implementations - +// jsi::Value V8Runtime::evaluateJavaScript( - const std::shared_ptr &buffer, - const std::string &sourceURL) { + const std::shared_ptr& buffer, + const std::string& sourceURL) { return {}; } std::shared_ptr V8Runtime::prepareJavaScript( - const std::shared_ptr &buffer, - std::string sourceURL) { - + const std::shared_ptr& buffer, std::string sourceURL) { return nullptr; } jsi::Value V8Runtime::evaluatePreparedJavaScript( - const std::shared_ptr &js) { + const std::shared_ptr& js) { return evaluateJavaScript(nullptr, nullptr); } +void V8Runtime::queueMicrotask(const jsi::Function& callback) { + // TODO: add this when we revisit new architecture support +} + bool V8Runtime::drainMicrotasks(int maxMicrotasksHint) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); @@ -152,8 +442,7 @@ bool V8Runtime::drainMicrotasks(int maxMicrotasksHint) { v8::Context::Scope scopedContext(context_.Get(isolate_)); while (v8::platform::PumpMessageLoop( - s_platform.get(), - isolate_, + s_platform.get(), isolate_, v8::platform::MessageLoopBehavior::kDoNotWait)) { continue; } @@ -177,13 +466,11 @@ std::string V8Runtime::description() { return ss.str(); } -bool V8Runtime::isInspectable() { - return false; -} +bool V8Runtime::isInspectable() { return false; } // These clone methods are shallow clone -jsi::Runtime::PointerValue *V8Runtime::cloneSymbol( - const Runtime::PointerValue *pv) { +jsi::Runtime::PointerValue* V8Runtime::cloneSymbol( + const Runtime::PointerValue* pv) { if (!pv) { return nullptr; } @@ -192,15 +479,13 @@ jsi::Runtime::PointerValue *V8Runtime::cloneSymbol( v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - const V8PointerValue *v8PointerValue = - static_cast(pv); + const V8PointerValue* v8PointerValue = static_cast(pv); assert(v8PointerValue->Get(isolate_)->IsSymbol()); - return new V8PointerValue(isolate_, v8PointerValue->Get(isolate_)); } -jsi::Runtime::PointerValue *V8Runtime::cloneBigInt( - const Runtime::PointerValue *pv) { +jsi::Runtime::PointerValue* V8Runtime::cloneBigInt( + const Runtime::PointerValue* pv) { if (!pv) { return nullptr; } @@ -210,14 +495,13 @@ jsi::Runtime::PointerValue *V8Runtime::cloneBigInt( v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - const V8PointerValue *v8PointerValue = - static_cast(pv); + const V8PointerValue* v8PointerValue = static_cast(pv); assert(v8PointerValue->Get(isolate_)->IsBigInt()); return new V8PointerValue(isolate_, v8PointerValue->Get(isolate_)); } -jsi::Runtime::PointerValue *V8Runtime::cloneString( - const Runtime::PointerValue *pv) { +jsi::Runtime::PointerValue* V8Runtime::cloneString( + const Runtime::PointerValue* pv) { if (!pv) { return nullptr; } @@ -227,14 +511,13 @@ jsi::Runtime::PointerValue *V8Runtime::cloneString( v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - const V8PointerValue *v8PointerValue = - static_cast(pv); + const V8PointerValue* v8PointerValue = static_cast(pv); assert(v8PointerValue->Get(isolate_)->IsString()); return new V8PointerValue(isolate_, v8PointerValue->Get(isolate_)); } -jsi::Runtime::PointerValue *V8Runtime::cloneObject( - const Runtime::PointerValue *pv) { +jsi::Runtime::PointerValue* V8Runtime::cloneObject( + const Runtime::PointerValue* pv) { if (!pv) { return nullptr; } @@ -244,25 +527,23 @@ jsi::Runtime::PointerValue *V8Runtime::cloneObject( v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - const V8PointerValue *v8PointerValue = - static_cast(pv); + const V8PointerValue* v8PointerValue = static_cast(pv); assert(v8PointerValue->Get(isolate_)->IsObject()); return new V8PointerValue(isolate_, v8PointerValue->Get(isolate_)); } -jsi::Runtime::PointerValue *V8Runtime::clonePropNameID( - const Runtime::PointerValue *pv) { +jsi::Runtime::PointerValue* V8Runtime::clonePropNameID( + const Runtime::PointerValue* pv) { return cloneString(pv); } -jsi::PropNameID V8Runtime::createPropNameIDFromAscii( - const char *str, - size_t length) { +jsi::PropNameID V8Runtime::createPropNameIDFromAscii(const char* str, + size_t length) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - V8PointerValue *value = + V8PointerValue* value = V8PointerValue::createFromOneByte(isolate_, str, length); if (!value) { throw jsi::JSError(*this, "createFromOneByte() - string creation failed."); @@ -271,14 +552,13 @@ jsi::PropNameID V8Runtime::createPropNameIDFromAscii( return make(value); } -jsi::PropNameID V8Runtime::createPropNameIDFromUtf8( - const uint8_t *utf8, - size_t length) { +jsi::PropNameID V8Runtime::createPropNameIDFromUtf8(const uint8_t* utf8, + size_t length) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - V8PointerValue *value = + V8PointerValue* value = V8PointerValue::createFromUtf8(isolate_, utf8, length); if (!value) { throw jsi::JSError(*this, "createFromUtf8() - string creation failed."); @@ -287,59 +567,57 @@ jsi::PropNameID V8Runtime::createPropNameIDFromUtf8( return make(value); } -jsi::PropNameID V8Runtime::createPropNameIDFromString(const jsi::String &str) { +jsi::PropNameID V8Runtime::createPropNameIDFromString(const jsi::String& str) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - const V8PointerValue *v8PointerValue = - static_cast(getPointerValue(str)); + const V8PointerValue* v8PointerValue = + static_cast(getPointerValue(str)); assert(v8PointerValue->Get(isolate_)->IsString()); v8::String::Utf8Value utf8(isolate_, v8PointerValue->Get(isolate_)); - return createPropNameIDFromUtf8( - reinterpret_cast(*utf8), utf8.length()); + return createPropNameIDFromUtf8(reinterpret_cast(*utf8), + utf8.length()); } jsi::PropNameID V8Runtime::createPropNameIDFromSymbol( - const facebook::jsi::Symbol &sym) { + const facebook::jsi::Symbol& sym) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - const V8PointerValue *v8PointerValue = - static_cast(getPointerValue(sym)); - assert(v8PointerValue->Get(isolate_)->IsSymbol()); + assert(static_cast(getPointerValue(sym)) + ->Get(isolate_) + ->IsSymbol()); - return make( - const_cast(getPointerValue(sym))); + return make(const_cast(getPointerValue(sym))); } - -std::string V8Runtime::utf8(const jsi::PropNameID &sym) { +std::string V8Runtime::utf8(const jsi::PropNameID& sym) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - const V8PointerValue *v8PointerValue = - static_cast(getPointerValue(sym)); + const V8PointerValue* v8PointerValue = + static_cast(getPointerValue(sym)); v8::String::Utf8Value utf8(isolate_, v8PointerValue->Get(isolate_)); return JSIV8ValueConverter::ToSTLString(utf8); } -bool V8Runtime::compare(const jsi::PropNameID &a, const jsi::PropNameID &b) { +bool V8Runtime::compare(const jsi::PropNameID& a, const jsi::PropNameID& b) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - const V8PointerValue *v8PointerValueA = - static_cast(getPointerValue(a)); - const V8PointerValue *v8PointerValueB = - static_cast(getPointerValue(b)); + const V8PointerValue* v8PointerValueA = + static_cast(getPointerValue(a)); + const V8PointerValue* v8PointerValueB = + static_cast(getPointerValue(b)); v8::Local v8StringA = v8::Local::Cast(v8PointerValueA->Get(isolate_)); @@ -348,17 +626,123 @@ bool V8Runtime::compare(const jsi::PropNameID &a, const jsi::PropNameID &b) { return v8StringA->StringEquals(v8StringB); } -std::string V8Runtime::symbolToString(const jsi::Symbol &symbol) { +std::string V8Runtime::symbolToString(const jsi::Symbol& symbol) { return jsi::Value(*this, symbol).toString(*this).utf8(*this); } -jsi::String V8Runtime::createStringFromAscii(const char *str, size_t length) { +jsi::BigInt V8Runtime::createBigIntFromInt64(int64_t value) { + v8::Locker locker(isolate_); + v8::Isolate::Scope scopedIsolate(isolate_); + v8::HandleScope scopedHandle(isolate_); + v8::Context::Scope scopedContext(context_.Get(isolate_)); + + v8::Local v8BigInt = v8::BigInt::New(isolate_, value); + return make(new V8PointerValue(isolate_, v8BigInt)); +} + +jsi::BigInt V8Runtime::createBigIntFromUint64(uint64_t value) { + v8::Locker locker(isolate_); + v8::Isolate::Scope scopedIsolate(isolate_); + v8::HandleScope scopedHandle(isolate_); + v8::Context::Scope scopedContext(context_.Get(isolate_)); + + v8::Local v8BigInt = v8::BigInt::NewFromUnsigned(isolate_, value); + return make(new V8PointerValue(isolate_, v8BigInt)); +} + +bool V8Runtime::bigintIsInt64(const jsi::BigInt& value) { + v8::Locker locker(isolate_); + v8::Isolate::Scope scopedIsolate(isolate_); + v8::HandleScope scopedHandle(isolate_); + v8::Context::Scope scopedContext(context_.Get(isolate_)); + + const V8PointerValue* v8PointerValue = + static_cast(getPointerValue(value)); + assert(v8PointerValue->Get(isolate_)->IsBigInt()); + v8::Local v8BigInt = + v8::Local::Cast(v8PointerValue->Get(isolate_)); + bool lossless = false; + v8BigInt->Int64Value(&lossless); + return lossless == true; +} + +bool V8Runtime::bigintIsUint64(const jsi::BigInt& value) { + v8::Locker locker(isolate_); + v8::Isolate::Scope scopedIsolate(isolate_); + v8::HandleScope scopedHandle(isolate_); + v8::Context::Scope scopedContext(context_.Get(isolate_)); + + const V8PointerValue* v8PointerValue = + static_cast(getPointerValue(value)); + assert(v8PointerValue->Get(isolate_)->IsBigInt()); + v8::Local v8BigInt = + v8::Local::Cast(v8PointerValue->Get(isolate_)); + bool lossless = false; + v8BigInt->Uint64Value(&lossless); + return lossless == true; +} + +uint64_t V8Runtime::truncate(const jsi::BigInt& value) { + v8::Locker locker(isolate_); + v8::Isolate::Scope scopedIsolate(isolate_); + v8::HandleScope scopedHandle(isolate_); + v8::Context::Scope scopedContext(context_.Get(isolate_)); + + const V8PointerValue* v8PointerValue = + static_cast(getPointerValue(value)); + assert(v8PointerValue->Get(isolate_)->IsBigInt()); + v8::Local v8BigInt = + v8::Local::Cast(v8PointerValue->Get(isolate_)); + return v8BigInt->Uint64Value(); +} + +jsi::String V8Runtime::bigintToString(const jsi::BigInt& value, int radix) { + v8::Locker locker(isolate_); + v8::Isolate::Scope scopedIsolate(isolate_); + v8::HandleScope scopedHandle(isolate_); + v8::Context::Scope scopedContext(context_.Get(isolate_)); + + const V8PointerValue* v8PointerValue = + static_cast(getPointerValue(value)); + assert(v8PointerValue->Get(isolate_)->IsBigInt()); + v8::Local v8Value = + v8::Local::Cast(v8PointerValue->Get(isolate_)); + + // V8 does not expose `toString(radix)` in its API, so we have to use + // `BigInt.prototype.toString.call(value, radix)` instead. + v8::Local global = context_.Get(isolate_)->Global(); + v8::Local bigintClass = v8::Local::Cast( + global + ->Get(isolate_->GetCurrentContext(), + v8::String::NewFromUtf8Literal(isolate_, "BigInt")) + .ToLocalChecked()); + v8::Local bigintProto = v8::Local::Cast( + bigintClass + ->Get(isolate_->GetCurrentContext(), + v8::String::NewFromUtf8Literal(isolate_, "prototype")) + .ToLocalChecked()); + v8::Local bigintToStringFunction = + v8::Local::Cast( + bigintProto + ->Get(isolate_->GetCurrentContext(), + v8::String::NewFromUtf8Literal(isolate_, "toString")) + .ToLocalChecked()); + v8::Local args[] = {v8::Integer::New(isolate_, radix)}; + v8::Local result = + bigintToStringFunction + ->Call(isolate_->GetCurrentContext(), v8Value, 1, args) + .ToLocalChecked(); + assert(result->IsString()); + return V8Runtime::make(new V8PointerValue(isolate_, result)); +} + +jsi::String V8Runtime::createStringFromAscii(const char* str, size_t length) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - V8PointerValue *value = + V8PointerValue* value = V8PointerValue::createFromOneByte(isolate_, str, length); if (!value) { throw jsi::JSError(*this, "createFromOneByte() - string creation failed."); @@ -367,13 +751,13 @@ jsi::String V8Runtime::createStringFromAscii(const char *str, size_t length) { return make(value); } -jsi::String V8Runtime::createStringFromUtf8(const uint8_t *str, size_t length) { +jsi::String V8Runtime::createStringFromUtf8(const uint8_t* str, size_t length) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - V8PointerValue *value = V8PointerValue::createFromUtf8(isolate_, str, length); + V8PointerValue* value = V8PointerValue::createFromUtf8(isolate_, str, length); if (!value) { throw jsi::JSError(*this, "createFromUtf8() - string creation failed."); } @@ -381,14 +765,14 @@ jsi::String V8Runtime::createStringFromUtf8(const uint8_t *str, size_t length) { return make(value); } -std::string V8Runtime::utf8(const jsi::String &str) { +std::string V8Runtime::utf8(const jsi::String& str) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - const V8PointerValue *v8PointerValue = - static_cast(getPointerValue(str)); + const V8PointerValue* v8PointerValue = + static_cast(getPointerValue(str)); assert(v8PointerValue->Get(isolate_)->IsString()); v8::String::Utf8Value utf8(isolate_, v8PointerValue->Get(isolate_)); @@ -412,19 +796,16 @@ jsi::Object V8Runtime::createObject( v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - HostObjectProxy *hostObjectProxy = + HostObjectProxy* hostObjectProxy = new HostObjectProxy(*this, isolate_, hostObject); v8::Local v8Object; v8::Local hostObjectTemplate = v8::ObjectTemplate::New(isolate_); hostObjectTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration( - HostObjectProxy::Getter, - HostObjectProxy::Setter, - nullptr, - nullptr, + HostObjectProxy::Getter, HostObjectProxy::Setter, nullptr, nullptr, HostObjectProxy::Enumerator)); - hostObjectTemplate->SetInternalFieldCount(1); + hostObjectTemplate->SetInternalFieldCount(2); if (!hostObjectTemplate->NewInstance(isolate_->GetCurrentContext()) .ToLocal(&v8Object)) { @@ -434,14 +815,16 @@ jsi::Object V8Runtime::createObject( v8::Local wrappedHostObjectProxy = v8::External::New(isolate_, hostObjectProxy); - v8Object->SetInternalField(0, wrappedHostObjectProxy); + v8Object->SetInternalField(0, v8::Integer::NewFromUnsigned( + isolate_, InternalFieldType::kHostObject)); + v8Object->SetInternalField(1, wrappedHostObjectProxy); hostObjectProxy->BindFinalizer(v8Object); return make(new V8PointerValue(isolate_, v8Object)); } std::shared_ptr V8Runtime::getHostObject( - const jsi::Object &object) { + const jsi::Object& object) { assert(isHostObject(object)); // We are guarenteed at this point to have isHostObject(obj) == true @@ -454,15 +837,15 @@ std::shared_ptr V8Runtime::getHostObject( v8::Local v8Object = JSIV8ValueConverter::ToV8Object(*this, object); v8::Local internalField = - v8::Local::Cast(v8Object->GetInternalField(0)); - HostObjectProxy *hostObjectProxy = - reinterpret_cast(internalField->Value()); + v8::Local::Cast(v8Object->GetInternalField(1)); + HostObjectProxy* hostObjectProxy = + reinterpret_cast(internalField->Value()); assert(hostObjectProxy); return hostObjectProxy->GetHostObject(); } -jsi::HostFunctionType &V8Runtime::getHostFunction( - const jsi::Function &function) { +jsi::HostFunctionType& V8Runtime::getHostFunction( + const jsi::Function& function) { assert(isHostFunction(function)); // We know that isHostFunction(function) is true here, so its safe to proceed @@ -471,29 +854,126 @@ jsi::HostFunctionType &V8Runtime::getHostFunction( v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - const V8PointerValue *v8PointerValue = - static_cast(getPointerValue(function)); + const V8PointerValue* v8PointerValue = + static_cast(getPointerValue(function)); assert(v8PointerValue->Get(isolate_)->IsFunction()); v8::Local v8Function = v8::Local::Cast(v8PointerValue->Get(isolate_)); v8::Local prop = - v8::String::NewFromUtf8( - isolate_, kHostFunctionProxyProp, v8::NewStringType::kNormal) + v8::String::NewFromUtf8(isolate_, kHostFunctionProxyProp, + v8::NewStringType::kNormal) .ToLocalChecked(); v8::Local wrappedHostFunctionProxy = v8::Local::Cast( v8Function->Get(isolate_->GetCurrentContext(), prop) .ToLocalChecked()); - HostFunctionProxy *hostFunctionProxy = - reinterpret_cast(wrappedHostFunctionProxy->Value()); + HostFunctionProxy* hostFunctionProxy = + reinterpret_cast(wrappedHostFunctionProxy->Value()); assert(hostFunctionProxy); return hostFunctionProxy->GetHostFunction(); } -jsi::Value V8Runtime::getProperty( - const jsi::Object &object, - const jsi::PropNameID &name) { +bool V8Runtime::hasNativeState(const jsi::Object& object) { + v8::Locker locker(isolate_); + v8::Isolate::Scope scopedIsolate(isolate_); + v8::HandleScope scopedHandle(isolate_); + v8::Context::Scope scopedContext(context_.Get(isolate_)); + + v8::Local v8Object = + JSIV8ValueConverter::ToV8Object(*this, object); + return GetInternalFieldType(v8Object) == InternalFieldType::kNativeState; +} + +std::shared_ptr V8Runtime::getNativeState( + const jsi::Object& object) { + if (isHostObject(object)) { + throw jsi::JSINativeException("native state unsupported on HostObject"); + } + assert(hasNativeState(object)); + + // We are guarenteed at this point to have hasNativeState(obj) == true + // so the internal data should be a NativeState + v8::Locker locker(isolate_); + v8::Isolate::Scope scopedIsolate(isolate_); + v8::HandleScope scopedHandle(isolate_); + v8::Context::Scope scopedContext(context_.Get(isolate_)); + + v8::Local v8Object = + JSIV8ValueConverter::ToV8Object(*this, object); + auto* nativeStatePtr = reinterpret_cast*>( + v8Object->GetAlignedPointerFromInternalField(1)); + return std::shared_ptr(*nativeStatePtr); +} + +void V8Runtime::setNativeState(const jsi::Object& object, + std::shared_ptr state) { + if (isHostObject(object)) { + throw jsi::JSINativeException("native state unsupported on HostObject"); + } + + v8::Locker locker(isolate_); + v8::Isolate::Scope scopedIsolate(isolate_); + v8::HandleScope scopedHandle(isolate_); + v8::Context::Scope scopedContext(context_.Get(isolate_)); + + v8::Local v8ObjectOriginal = + JSIV8ValueConverter::ToV8Object(*this, object); + + v8::Local objectTemplate = + v8::ObjectTemplate::New(isolate_); + objectTemplate->SetInternalFieldCount(2); + v8::Local v8Object; + if (!objectTemplate->NewInstance(isolate_->GetCurrentContext()) + .ToLocal(&v8Object)) { + throw jsi::JSError(*this, "Unable to create new Object for setNativeState"); + } + V8PointerValue* v8PointerValue = static_cast( + const_cast(getPointerValue(object))); + v8PointerValue->Reset(isolate_, v8Object); + + v8Object->SetInternalField(0, v8::Integer::NewFromUnsigned( + isolate_, InternalFieldType::kNativeState)); + // Allocate a shared_ptr on the C++ heap and use it as context of NativeState. + auto* nativeStatePtr = + new std::shared_ptr(std::move(state)); + v8Object->SetAlignedPointerInInternalField( + 1, reinterpret_cast(nativeStatePtr)); + + // Clone properties to the new object created from object template with + // two internal fields. + v8::Local global = context_.Get(isolate_)->Global(); + v8::Local objectClass = v8::Local::Cast( + global + ->Get(isolate_->GetCurrentContext(), + v8::String::NewFromUtf8Literal(isolate_, "Object")) + .ToLocalChecked()); + v8::Local objectAssignFunction = v8::Local::Cast( + objectClass + ->Get(isolate_->GetCurrentContext(), + v8::String::NewFromUtf8Literal(isolate_, "assign")) + .ToLocalChecked()); + v8::Local args[] = {v8Object, v8ObjectOriginal}; + objectAssignFunction + ->Call(isolate_->GetCurrentContext(), v8::Undefined(isolate_), 2, args) + .ToLocalChecked(); + + // Bind a global handle with weak callback to cleanup the shared_ptr + // on the C++ heap. + v8::Global weakV8Object(isolate_, v8Object); + weakV8Object.SetWeak( + &weakV8Object, + [](const v8::WeakCallbackInfo>& data) { + v8::Global* weakV8ObjectPtr = data.GetParameter(); + weakV8ObjectPtr->Reset(); + delete reinterpret_cast*>( + data.GetInternalField(1)); + }, + v8::WeakCallbackType::kInternalFields); +} + +jsi::Value V8Runtime::getProperty(const jsi::Object& object, + const jsi::PropNameID& name) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -503,9 +983,9 @@ jsi::Value V8Runtime::getProperty( v8::Local v8Object = JSIV8ValueConverter::ToV8Object(*this, object); - v8::MaybeLocal result = v8Object->Get( - isolate_->GetCurrentContext(), - JSIV8ValueConverter::ToV8String(*this, name)); + v8::MaybeLocal result = + v8Object->Get(isolate_->GetCurrentContext(), + JSIV8ValueConverter::ToV8String(*this, name)); if (tryCatch.HasCaught()) { ReportException(isolate_, &tryCatch); } @@ -516,9 +996,8 @@ jsi::Value V8Runtime::getProperty( return JSIV8ValueConverter::ToJSIValue(isolate_, result.ToLocalChecked()); } -jsi::Value V8Runtime::getProperty( - const jsi::Object &object, - const jsi::String &name) { +jsi::Value V8Runtime::getProperty(const jsi::Object& object, + const jsi::String& name) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -528,9 +1007,9 @@ jsi::Value V8Runtime::getProperty( v8::Local v8Object = JSIV8ValueConverter::ToV8Object(*this, object); - v8::MaybeLocal result = v8Object->Get( - isolate_->GetCurrentContext(), - JSIV8ValueConverter::ToV8String(*this, name)); + v8::MaybeLocal result = + v8Object->Get(isolate_->GetCurrentContext(), + JSIV8ValueConverter::ToV8String(*this, name)); if (tryCatch.HasCaught()) { ReportException(isolate_, &tryCatch); } @@ -540,9 +1019,8 @@ jsi::Value V8Runtime::getProperty( return JSIV8ValueConverter::ToJSIValue(isolate_, result.ToLocalChecked()); } -bool V8Runtime::hasProperty( - const jsi::Object &object, - const jsi::PropNameID &name) { +bool V8Runtime::hasProperty(const jsi::Object& object, + const jsi::PropNameID& name) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -552,9 +1030,9 @@ bool V8Runtime::hasProperty( v8::Local v8Object = JSIV8ValueConverter::ToV8Object(*this, object); - v8::Maybe result = v8Object->Has( - isolate_->GetCurrentContext(), - JSIV8ValueConverter::ToV8String(*this, name)); + v8::Maybe result = + v8Object->Has(isolate_->GetCurrentContext(), + JSIV8ValueConverter::ToV8String(*this, name)); if (tryCatch.HasCaught()) { ReportException(isolate_, &tryCatch); } @@ -565,9 +1043,8 @@ bool V8Runtime::hasProperty( return result.FromJust(); } -bool V8Runtime::hasProperty( - const jsi::Object &object, - const jsi::String &name) { +bool V8Runtime::hasProperty(const jsi::Object& object, + const jsi::String& name) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -577,9 +1054,9 @@ bool V8Runtime::hasProperty( v8::Local v8Object = JSIV8ValueConverter::ToV8Object(*this, object); - v8::Maybe result = v8Object->Has( - isolate_->GetCurrentContext(), - JSIV8ValueConverter::ToV8String(*this, name)); + v8::Maybe result = + v8Object->Has(isolate_->GetCurrentContext(), + JSIV8ValueConverter::ToV8String(*this, name)); if (tryCatch.HasCaught()) { ReportException(isolate_, &tryCatch); } @@ -590,10 +1067,9 @@ bool V8Runtime::hasProperty( return result.FromJust(); } -void V8Runtime::setPropertyValue( - jsi::Object &object, - const jsi::PropNameID &name, - const jsi::Value &value) { +void V8Runtime::setPropertyValue(const jsi::Object& object, + const jsi::PropNameID& name, + const jsi::Value& value) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -603,19 +1079,17 @@ void V8Runtime::setPropertyValue( JSIV8ValueConverter::ToV8Object(*this, object); if (v8Object - ->Set( - isolate_->GetCurrentContext(), - JSIV8ValueConverter::ToV8String(*this, name), - JSIV8ValueConverter::ToV8Value(*this, value)) + ->Set(isolate_->GetCurrentContext(), + JSIV8ValueConverter::ToV8String(*this, name), + JSIV8ValueConverter::ToV8Value(*this, value)) .IsNothing()) { throw jsi::JSError(*this, "V8Runtime::setPropertyValue failed."); } } -void V8Runtime::setPropertyValue( - jsi::Object &object, - const jsi::String &name, - const jsi::Value &value) { +void V8Runtime::setPropertyValue(const jsi::Object& object, + const jsi::String& name, + const jsi::Value& value) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -625,67 +1099,15 @@ void V8Runtime::setPropertyValue( JSIV8ValueConverter::ToV8Object(*this, object); if (v8Object - ->Set( - isolate_->GetCurrentContext(), - JSIV8ValueConverter::ToV8String(*this, name), - JSIV8ValueConverter::ToV8Value(*this, value)) + ->Set(isolate_->GetCurrentContext(), + JSIV8ValueConverter::ToV8String(*this, name), + JSIV8ValueConverter::ToV8Value(*this, value)) .IsNothing()) { throw jsi::JSError(*this, "V8Runtime::setPropertyValue failed."); } } - - -facebook::jsi::ArrayBuffer V8Runtime::createArrayBuffer( - std::shared_ptr buffer) { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - auto size = buffer->size(); - auto *data = buffer->data(); - auto *ctx = new std::shared_ptr(std::move(buffer)); - auto finalize = [](void *, size_t, void *ctx) { - delete static_cast *>(ctx); - }; - - std::unique_ptr store = v8::ArrayBuffer::NewBackingStore(data, size, - finalize, ctx); - auto arrayBuffer = v8::ArrayBuffer::New(isolate_, std::move(store)); - - - return make(new V8PointerValue(isolate_, arrayBuffer)) - .getArrayBuffer(*this); -} - - -uint64_t V8Runtime::uint64Value(const jsi::BigInt &bigInt, bool *lossless) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::TryCatch tryCatch(isolate_); - auto v8ObjectA = JSIV8ValueConverter::ToV8BigInt(*this, bigInt); - - return v8ObjectA->Uint64Value(lossless); -} - -int64_t V8Runtime::int64Value(const jsi::BigInt &bigInt, bool *lossless) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::TryCatch tryCatch(isolate_); - auto v8ObjectA = JSIV8ValueConverter::ToV8BigInt(*this, bigInt); - - return v8ObjectA->Int64Value(lossless); -} - - -bool V8Runtime::isArray(const jsi::Object &object) const { +bool V8Runtime::isArray(const jsi::Object& object) const { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -696,7 +1118,7 @@ bool V8Runtime::isArray(const jsi::Object &object) const { return v8Object->IsArray(); } -bool V8Runtime::isArrayBuffer(const jsi::Object &object) const { +bool V8Runtime::isArrayBuffer(const jsi::Object& object) const { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -707,153 +1129,7 @@ bool V8Runtime::isArrayBuffer(const jsi::Object &object) const { return v8Object->IsArrayBuffer(); } - -bool V8Runtime::isArrayBufferView(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->IsArrayBufferView(); -} - -bool V8Runtime::isTypedArray(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - - return v8Object->IsTypedArray(); -} - -bool V8Runtime::isUint8Array(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->IsUint8Array(); -} - -bool V8Runtime::isUint8ClampedArray(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->IsUint8ClampedArray(); -} - -bool V8Runtime::isInt8Array(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->IsInt8Array(); -} - -bool V8Runtime::isUint16Array(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->IsUint16Array(); -} - -bool V8Runtime::isInt16Array(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->IsInt16Array(); -} - -bool V8Runtime::isUint32Array(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->IsUint32Array(); -} - -bool V8Runtime::isInt32Array(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->IsInt32Array(); -} - -bool V8Runtime::isFloat32Array(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->IsFloat32Array(); -} - -bool V8Runtime::isBigUint64Array(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->IsBigUint64Array(); -} - -bool V8Runtime::isBigInt64Array(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->IsBigInt64Array(); -} - -bool V8Runtime::isFloat64Array(const jsi::Object &object) const { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->IsFloat64Array(); -} - - -bool V8Runtime::isFunction(const jsi::Object &object) const { +bool V8Runtime::isFunction(const jsi::Object& object) const { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -864,7 +1140,7 @@ bool V8Runtime::isFunction(const jsi::Object &object) const { return v8Object->IsFunction(); } -bool V8Runtime::isHostObject(const jsi::Object &object) const { +bool V8Runtime::isHostObject(const jsi::Object& object) const { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -872,10 +1148,10 @@ bool V8Runtime::isHostObject(const jsi::Object &object) const { v8::Local v8Object = JSIV8ValueConverter::ToV8Object(*this, object); - return v8Object->InternalFieldCount() == 1; + return GetInternalFieldType(v8Object) == InternalFieldType::kHostObject; } -bool V8Runtime::isHostFunction(const jsi::Function &function) const { +bool V8Runtime::isHostFunction(const jsi::Function& function) const { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -885,13 +1161,13 @@ bool V8Runtime::isHostFunction(const jsi::Function &function) const { JSIV8ValueConverter::ToV8Function(*this, function); v8::Local prop = - v8::String::NewFromUtf8( - isolate_, kHostFunctionProxyProp, v8::NewStringType::kNormal) + v8::String::NewFromUtf8(isolate_, kHostFunctionProxyProp, + v8::NewStringType::kNormal) .ToLocalChecked(); return v8Function->Has(isolate_->GetCurrentContext(), prop).ToChecked(); } -jsi::Array V8Runtime::getPropertyNames(const jsi::Object &object) { +jsi::Array V8Runtime::getPropertyNames(const jsi::Object& object) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -901,13 +1177,12 @@ jsi::Array V8Runtime::getPropertyNames(const jsi::Object &object) { JSIV8ValueConverter::ToV8Object(*this, object); v8::Local propertyNames; if (!v8Object - ->GetPropertyNames( - isolate_->GetCurrentContext(), - v8::KeyCollectionMode::kIncludePrototypes, - static_cast( - v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS), - v8::IndexFilter::kIncludeIndices, - v8::KeyConversionMode::kConvertToString) + ->GetPropertyNames(isolate_->GetCurrentContext(), + v8::KeyCollectionMode::kIncludePrototypes, + static_cast( + v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS), + v8::IndexFilter::kIncludeIndices, + v8::KeyConversionMode::kConvertToString) .ToLocal(&propertyNames)) { std::abort(); } @@ -915,14 +1190,14 @@ jsi::Array V8Runtime::getPropertyNames(const jsi::Object &object) { .getArray(*this); } -jsi::WeakObject V8Runtime::createWeakObject(const jsi::Object &weakObject) { +jsi::WeakObject V8Runtime::createWeakObject(const jsi::Object& weakObject) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - const V8PointerValue *v8PointerValue = - static_cast(getPointerValue(weakObject)); + const V8PointerValue* v8PointerValue = + static_cast(getPointerValue(weakObject)); assert(v8PointerValue->Get(isolate_)->IsObject()); v8::Global weakRef = @@ -932,17 +1207,17 @@ jsi::WeakObject V8Runtime::createWeakObject(const jsi::Object &weakObject) { new V8PointerValue(isolate_, std::move(weakRef))); } -jsi::Value V8Runtime::lockWeakObject(jsi::WeakObject &weakObject) { +jsi::Value V8Runtime::lockWeakObject(const jsi::WeakObject& weakObject) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - const V8PointerValue *v8PointerValue = - static_cast(getPointerValue(weakObject)); + const V8PointerValue* v8PointerValue = + static_cast(getPointerValue(weakObject)); assert(v8PointerValue->Get(isolate_)->IsObject()); - return JSIV8ValueConverter::ToJSIValue( - isolate_, v8PointerValue->Get(isolate_)); + return JSIV8ValueConverter::ToJSIValue(isolate_, + v8PointerValue->Get(isolate_)); } jsi::Array V8Runtime::createArray(size_t length) { @@ -957,7 +1232,12 @@ jsi::Array V8Runtime::createArray(size_t length) { .getArray(*this); } -size_t V8Runtime::size(const jsi::Array &array) { +jsi::ArrayBuffer V8Runtime::createArrayBuffer( + std::shared_ptr buffer) { + throw std::logic_error("Not implemented"); +} + +size_t V8Runtime::size(const jsi::Array& array) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -967,7 +1247,7 @@ size_t V8Runtime::size(const jsi::Array &array) { return v8Array->Length(); } -size_t V8Runtime::size(const jsi::ArrayBuffer &arrayBuffer) { +size_t V8Runtime::size(const jsi::ArrayBuffer& arrayBuffer) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -976,38 +1256,11 @@ size_t V8Runtime::size(const jsi::ArrayBuffer &arrayBuffer) { v8::Local v8Object = JSIV8ValueConverter::ToV8Object(*this, arrayBuffer); assert(v8Object->IsArrayBuffer()); - v8::ArrayBuffer *v8ArrayBuffer = v8::ArrayBuffer::Cast(*v8Object); + v8::ArrayBuffer* v8ArrayBuffer = v8::ArrayBuffer::Cast(*v8Object); return v8ArrayBuffer->ByteLength(); } - -size_t V8Runtime::size(const jsi::TypedArray &typedArray) { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, typedArray); - assert(v8Object->IsTypedArray()); - v8::TypedArray *array = v8::TypedArray::Cast(*v8Object); - return array->ByteLength(); -} - -size_t V8Runtime::offset(const jsi::TypedArray &typedArray) { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, typedArray); - assert(v8Object->IsTypedArray()); - auto array = v8Object.As(); - return array->ByteOffset(); -} - -uint8_t *V8Runtime::data(const jsi::ArrayBuffer &arrayBuffer) { +uint8_t* V8Runtime::data(const jsi::ArrayBuffer& arrayBuffer) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -1016,24 +1269,11 @@ uint8_t *V8Runtime::data(const jsi::ArrayBuffer &arrayBuffer) { v8::Local v8Object = JSIV8ValueConverter::ToV8Object(*this, arrayBuffer); assert(v8Object->IsArrayBuffer()); - v8::ArrayBuffer *v8ArrayBuffer = v8::ArrayBuffer::Cast(*v8Object); - return reinterpret_cast(v8ArrayBuffer->GetBackingStore()->Data()); + v8::ArrayBuffer* v8ArrayBuffer = v8::ArrayBuffer::Cast(*v8Object); + return reinterpret_cast(v8ArrayBuffer->GetBackingStore()->Data()); } -uint8_t *V8Runtime::data(const jsi::TypedArray &typedArray) { - v8::Locker locker(isolate_); - v8::Isolate::Scope scopedIsolate(isolate_); - v8::HandleScope scopedHandle(isolate_); - v8::Context::Scope scopedContext(context_.Get(isolate_)); - - v8::Local v8Object = - JSIV8ValueConverter::ToV8Object(*this, typedArray); - assert(v8Object->IsTypedArray()); - auto array = v8Object.As(); - return reinterpret_cast(array->Buffer()->GetBackingStore()->Data()); -} - -jsi::Value V8Runtime::getValueAtIndex(const jsi::Array &array, size_t i) { +jsi::Value V8Runtime::getValueAtIndex(const jsi::Array& array, size_t i) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -1048,56 +1288,50 @@ jsi::Value V8Runtime::getValueAtIndex(const jsi::Array &array, size_t i) { return JSIV8ValueConverter::ToJSIValue(isolate_, result.ToLocalChecked()); } -void V8Runtime::setValueAtIndexImpl( - jsi::Array &array, - size_t i, - const jsi::Value &value) { +void V8Runtime::setValueAtIndexImpl(const jsi::Array& array, size_t i, + const jsi::Value& value) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); v8::Local v8Array = JSIV8ValueConverter::ToV8Array(*this, array); - v8::Maybe result = v8Array->Set( - isolate_->GetCurrentContext(), - static_cast(i), - JSIV8ValueConverter::ToV8Value(*this, value)); + v8::Maybe result = + v8Array->Set(isolate_->GetCurrentContext(), static_cast(i), + JSIV8ValueConverter::ToV8Value(*this, value)); if (result.IsNothing()) { throw jsi::JSError(*this, "V8Runtime::setValueAtIndexImpl failed."); } } jsi::Function V8Runtime::createFunctionFromHostFunction( - const jsi::PropNameID &name, - unsigned int paramCount, + const jsi::PropNameID& name, unsigned int paramCount, jsi::HostFunctionType func) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); v8::Context::Scope scopedContext(context_.Get(isolate_)); - HostFunctionProxy *hostFunctionProxy = + HostFunctionProxy* hostFunctionProxy = new HostFunctionProxy(*this, isolate_, std::move(func)); v8::Local wrappedHostFunctionProxy = v8::External::New(isolate_, hostFunctionProxy); v8::Local v8HostFunction = - v8::Function::New( - isolate_->GetCurrentContext(), - HostFunctionProxy::FunctionCallback, - wrappedHostFunctionProxy) + v8::Function::New(isolate_->GetCurrentContext(), + HostFunctionProxy::FunctionCallback, + wrappedHostFunctionProxy) .ToLocalChecked(); hostFunctionProxy->BindFinalizer(v8HostFunction); v8::Local v8FunctionContainer = - v8::Function::New( - isolate_->GetCurrentContext(), - V8Runtime::OnHostFuncionContainerCallback, - v8HostFunction) + v8::Function::New(isolate_->GetCurrentContext(), + V8Runtime::OnHostFuncionContainerCallback, + v8HostFunction) .ToLocalChecked(); v8::Local prop = - v8::String::NewFromUtf8( - isolate_, kHostFunctionProxyProp, v8::NewStringType::kNormal) + v8::String::NewFromUtf8(isolate_, kHostFunctionProxyProp, + v8::NewStringType::kNormal) .ToLocalChecked(); v8FunctionContainer ->Set(isolate_->GetCurrentContext(), prop, wrappedHostFunctionProxy) @@ -1112,11 +1346,9 @@ jsi::Function V8Runtime::createFunctionFromHostFunction( .getFunction(*this); } -jsi::Value V8Runtime::call( - const jsi::Function &function, - const jsi::Value &jsThis, - const jsi::Value *args, - size_t count) { +jsi::Value V8Runtime::call(const jsi::Function& function, + const jsi::Value& jsThis, const jsi::Value* args, + size_t count) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -1140,11 +1372,9 @@ jsi::Value V8Runtime::call( argv.push_back(v8ArgValue); } - v8::MaybeLocal result = v8Function->Call( - isolate_->GetCurrentContext(), - v8Receiver, - static_cast(count), - argv.data()); + v8::MaybeLocal result = + v8Function->Call(isolate_->GetCurrentContext(), v8Receiver, + static_cast(count), argv.data()); if (tryCatch.HasCaught()) { ReportException(isolate_, &tryCatch); @@ -1157,10 +1387,8 @@ jsi::Value V8Runtime::call( } } -jsi::Value V8Runtime::callAsConstructor( - const jsi::Function &function, - const jsi::Value *args, - size_t count) { +jsi::Value V8Runtime::callAsConstructor(const jsi::Function& function, + const jsi::Value* args, size_t count) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -1178,10 +1406,8 @@ jsi::Value V8Runtime::callAsConstructor( v8::Local v8Object; if (!v8Function - ->NewInstance( - isolate_->GetCurrentContext(), - static_cast(count), - argv.data()) + ->NewInstance(isolate_->GetCurrentContext(), static_cast(count), + argv.data()) .ToLocal(&v8Object)) { throw jsi::JSError(*this, "CallAsConstructor failed"); } @@ -1193,7 +1419,7 @@ jsi::Value V8Runtime::callAsConstructor( return JSIV8ValueConverter::ToJSIValue(isolate_, v8Object); } -bool V8Runtime::strictEquals(const jsi::Symbol &a, const jsi::Symbol &b) const { +bool V8Runtime::strictEquals(const jsi::Symbol& a, const jsi::Symbol& b) const { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -1210,7 +1436,7 @@ bool V8Runtime::strictEquals(const jsi::Symbol &a, const jsi::Symbol &b) const { return result; } -bool V8Runtime::strictEquals(const jsi::BigInt &a, const jsi::BigInt &b) const { +bool V8Runtime::strictEquals(const jsi::BigInt& a, const jsi::BigInt& b) const { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -1218,9 +1444,9 @@ bool V8Runtime::strictEquals(const jsi::BigInt &a, const jsi::BigInt &b) const { v8::TryCatch tryCatch(isolate_); v8::Local v8ValueA = - (static_cast(getPointerValue(a)))->Get(isolate_); + (static_cast(getPointerValue(a)))->Get(isolate_); v8::Local v8ValueB = - (static_cast(getPointerValue(b)))->Get(isolate_); + (static_cast(getPointerValue(b)))->Get(isolate_); bool result = v8ValueA->StrictEquals(v8ValueB); if (tryCatch.HasCaught()) { @@ -1229,8 +1455,7 @@ bool V8Runtime::strictEquals(const jsi::BigInt &a, const jsi::BigInt &b) const { return result; } - -bool V8Runtime::strictEquals(const jsi::String &a, const jsi::String &b) const { +bool V8Runtime::strictEquals(const jsi::String& a, const jsi::String& b) const { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -1247,7 +1472,7 @@ bool V8Runtime::strictEquals(const jsi::String &a, const jsi::String &b) const { return result; } -bool V8Runtime::strictEquals(const jsi::Object &a, const jsi::Object &b) const { +bool V8Runtime::strictEquals(const jsi::Object& a, const jsi::Object& b) const { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -1264,7 +1489,7 @@ bool V8Runtime::strictEquals(const jsi::Object &a, const jsi::Object &b) const { return result; } -bool V8Runtime::instanceOf(const jsi::Object &o, const jsi::Function &f) { +bool V8Runtime::instanceOf(const jsi::Object& o, const jsi::Function& f) { v8::Locker locker(isolate_); v8::Isolate::Scope scopedIsolate(isolate_); v8::HandleScope scopedHandle(isolate_); @@ -1282,14 +1507,17 @@ bool V8Runtime::instanceOf(const jsi::Object &o, const jsi::Function &f) { return result; } +void V8Runtime::setExternalMemoryPressure(const jsi::Object& obj, + size_t amount) {} + // // JS function/object handler callbacks // // static void V8Runtime::GetRuntimeInfo( - const v8::FunctionCallbackInfo &args) { - v8::Isolate *isolate = args.GetIsolate(); + const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scopedHandle(isolate); v8::Local runtimeInfo = v8::Object::New(isolate); v8::Local context(isolate->GetCurrentContext()); @@ -1298,8 +1526,8 @@ void V8Runtime::GetRuntimeInfo( v8::String::NewFromUtf8(isolate, "version", v8::NewStringType::kNormal) .ToLocalChecked(); v8::Local versionValue = - v8::String::NewFromUtf8( - args.GetIsolate(), v8::V8::GetVersion(), v8::NewStringType::kNormal) + v8::String::NewFromUtf8(args.GetIsolate(), v8::V8::GetVersion(), + v8::NewStringType::kNormal) .ToLocalChecked(); runtimeInfo->Set(context, versionKey, versionValue).Check(); @@ -1310,28 +1538,25 @@ void V8Runtime::GetRuntimeInfo( v8::HeapStatistics heapStats; isolate->GetHeapStatistics(&heapStats); memoryInfo - ->Set( - context, - v8::String::NewFromUtf8( - isolate, "jsHeapSizeLimit", v8::NewStringType::kNormal) - .ToLocalChecked(), - v8::Number::New(isolate, heapStats.heap_size_limit())) + ->Set(context, + v8::String::NewFromUtf8(isolate, "jsHeapSizeLimit", + v8::NewStringType::kNormal) + .ToLocalChecked(), + v8::Number::New(isolate, heapStats.heap_size_limit())) .Check(); memoryInfo - ->Set( - context, - v8::String::NewFromUtf8( - isolate, "totalJSHeapSize", v8::NewStringType::kNormal) - .ToLocalChecked(), - v8::Number::New(isolate, heapStats.total_heap_size())) + ->Set(context, + v8::String::NewFromUtf8(isolate, "totalJSHeapSize", + v8::NewStringType::kNormal) + .ToLocalChecked(), + v8::Number::New(isolate, heapStats.total_heap_size())) .Check(); memoryInfo - ->Set( - context, - v8::String::NewFromUtf8( - isolate, "usedJSHeapSize", v8::NewStringType::kNormal) - .ToLocalChecked(), - v8::Number::New(isolate, heapStats.used_heap_size())) + ->Set(context, + v8::String::NewFromUtf8(isolate, "usedJSHeapSize", + v8::NewStringType::kNormal) + .ToLocalChecked(), + v8::Number::New(isolate, heapStats.used_heap_size())) .Check(); runtimeInfo->Set(context, memoryKey, memoryInfo).Check(); @@ -1340,24 +1565,22 @@ void V8Runtime::GetRuntimeInfo( // static void V8Runtime::OnHostFuncionContainerCallback( - const v8::FunctionCallbackInfo &args) { + const v8::FunctionCallbackInfo& args) { v8::HandleScope scopedHandle(args.GetIsolate()); v8::Local v8HostFunction = v8::Local::Cast(args.Data()); std::vector> argv; for (size_t i = 0; i < args.Length(); ++i) { - argv.push_back(args[(int) i]); + argv.push_back(args[(int)i]); } - v8::MaybeLocal result = v8HostFunction->Call( - args.GetIsolate()->GetCurrentContext(), - args.This(), - args.Length(), - argv.data()); + v8::MaybeLocal result = + v8HostFunction->Call(args.GetIsolate()->GetCurrentContext(), args.This(), + args.Length(), argv.data()); if (!result.IsEmpty()) { args.GetReturnValue().Set(result.ToLocalChecked()); } } -} // namespace rnv8 +} // namespace rnv8 \ No newline at end of file diff --git a/NativeScript/v8runtime/V8Runtime.h b/NativeScript/v8runtime/V8Runtime.h index 96b11e9a..fe4b093a 100644 --- a/NativeScript/v8runtime/V8Runtime.h +++ b/NativeScript/v8runtime/V8Runtime.h @@ -7,6 +7,8 @@ #pragma once +// #include +#include "V8RuntimeConfig.h" #include "jsi/jsi.h" #include "libplatform/libplatform.h" #include "v8.h" @@ -15,54 +17,64 @@ namespace rnv8 { class V8Runtime; class V8PointerValue; +class InspectorClient; class V8Runtime : public facebook::jsi::Runtime { public: V8Runtime(); - - //V8Runtime(const V8Runtime *v8Runtime); - + // V8Runtime( + // std::unique_ptr config, + // std::shared_ptr jsQueue); + // V8Runtime( + // const V8Runtime *v8Runtime, + // std::unique_ptr config); ~V8Runtime(); - + // Calling this function when the platform main runloop is idle void OnMainLoopIdle(); private: - v8::Local CreateGlobalContext(v8::Isolate *isolate); - v8::Isolate *GetIsolate(); - facebook::jsi::Value ExecuteScript( - v8::Isolate *isolate, - const v8::Local &script, - const std::string &sourceURL); - void ReportException(v8::Isolate *isolate, v8::TryCatch *tryCatch) const; + v8::Local CreateGlobalContext(v8::Isolate* isolate); + facebook::jsi::Value ExecuteScript(v8::Isolate* isolate, + const v8::Local& script, + const std::string& sourceURL); + void ReportException(v8::Isolate* isolate, v8::TryCatch* tryCatch) const; std::unique_ptr LoadCodeCacheIfNeeded( - const std::string &codecachePath); - bool SaveCodeCacheIfNeeded( - const v8::Local &script, - const std::string &codecachePath, - v8::ScriptCompiler::CachedData *cachedData); + const std::string& sourceURL); + bool SaveCodeCacheIfNeeded(const v8::Local& script, + const std::string& sourceURL, + v8::ScriptCompiler::CachedData* cachedData); std::unique_ptr UseFakeSourceIfNeeded( - const v8::ScriptOrigin &origin, - v8::ScriptCompiler::CachedData *cachedData); + const v8::ScriptOrigin& origin, + v8::ScriptCompiler::CachedData* cachedData); + + enum InternalFieldType { + kInvalid = 0, + kHostObject = 1, + kNativeState = 2, + kMaxValue = kNativeState, + }; + InternalFieldType GetInternalFieldType(v8::Local object) const; - static v8::Platform *GetPlatform(); + static v8::Platform* GetPlatform(); // // facebook::jsi::Runtime implementations // public: facebook::jsi::Value evaluateJavaScript( - const std::shared_ptr &buffer, - const std::string &sourceURL) override; + const std::shared_ptr& buffer, + const std::string& sourceURL) override; std::shared_ptr prepareJavaScript( - const std::shared_ptr &buffer, + const std::shared_ptr& buffer, std::string sourceURL) override; facebook::jsi::Value evaluatePreparedJavaScript( - const std::shared_ptr &js) + const std::shared_ptr& js) override; + void queueMicrotask(const facebook::jsi::Function& callback) override; bool drainMicrotasks(int maxMicrotasksHint = -1) override; facebook::jsi::Object global() override; @@ -70,145 +82,120 @@ class V8Runtime : public facebook::jsi::Runtime { bool isInspectable() override; protected: - PointerValue *cloneSymbol(const Runtime::PointerValue *pv) override; - PointerValue *cloneBigInt(const Runtime::PointerValue *pv) override; - PointerValue *cloneString(const Runtime::PointerValue *pv) override; - PointerValue *cloneObject(const Runtime::PointerValue *pv) override; - PointerValue *clonePropNameID(const Runtime::PointerValue *pv) override; - - facebook::jsi::PropNameID createPropNameIDFromAscii( - const char *str, - size_t length) override; - facebook::jsi::PropNameID createPropNameIDFromUtf8( - const uint8_t *utf8, - size_t length) override; + PointerValue* cloneSymbol(const Runtime::PointerValue* pv) override; + PointerValue* cloneBigInt(const Runtime::PointerValue* pv) override; + PointerValue* cloneString(const Runtime::PointerValue* pv) override; + PointerValue* cloneObject(const Runtime::PointerValue* pv) override; + PointerValue* clonePropNameID(const Runtime::PointerValue* pv) override; + + facebook::jsi::PropNameID createPropNameIDFromAscii(const char* str, + size_t length) override; + facebook::jsi::PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, + size_t length) override; facebook::jsi::PropNameID createPropNameIDFromString( - const facebook::jsi::String &str) override; - + const facebook::jsi::String& str) override; facebook::jsi::PropNameID createPropNameIDFromSymbol( - const facebook::jsi::Symbol &sym) override; - - std::string utf8(const facebook::jsi::PropNameID &) override; - bool compare( - const facebook::jsi::PropNameID &, - const facebook::jsi::PropNameID &) override; - - std::string symbolToString(const facebook::jsi::Symbol &) override; - - facebook::jsi::String createStringFromAscii(const char *str, size_t length) - override; - facebook::jsi::String createStringFromUtf8(const uint8_t *utf8, size_t length) - override; - std::string utf8(const facebook::jsi::String &) override; + const facebook::jsi::Symbol& sym) override; + std::string utf8(const facebook::jsi::PropNameID&) override; + bool compare(const facebook::jsi::PropNameID&, + const facebook::jsi::PropNameID&) override; + + std::string symbolToString(const facebook::jsi::Symbol&) override; + + facebook::jsi::BigInt createBigIntFromInt64(int64_t) override; + facebook::jsi::BigInt createBigIntFromUint64(uint64_t) override; + bool bigintIsInt64(const facebook::jsi::BigInt&) override; + bool bigintIsUint64(const facebook::jsi::BigInt&) override; + uint64_t truncate(const facebook::jsi::BigInt&) override; + facebook::jsi::String bigintToString(const facebook::jsi::BigInt&, + int) override; + + facebook::jsi::String createStringFromAscii(const char* str, + size_t length) override; + facebook::jsi::String createStringFromUtf8(const uint8_t* utf8, + size_t length) override; + std::string utf8(const facebook::jsi::String&) override; facebook::jsi::Object createObject() override; facebook::jsi::Object createObject( std::shared_ptr hostObject) override; - - facebook::jsi::ArrayBuffer createArrayBuffer( - std::shared_ptr buffer) override; - std::shared_ptr getHostObject( - const facebook::jsi::Object &) override; - facebook::jsi::HostFunctionType &getHostFunction( - const facebook::jsi::Function &) override; + const facebook::jsi::Object&) override; + facebook::jsi::HostFunctionType& getHostFunction( + const facebook::jsi::Function&) override; + + bool hasNativeState(const facebook::jsi::Object&) override; + std::shared_ptr getNativeState( + const facebook::jsi::Object&) override; + void setNativeState( + const facebook::jsi::Object&, + std::shared_ptr state) override; facebook::jsi::Value getProperty( - const facebook::jsi::Object &, - const facebook::jsi::PropNameID &name) override; - facebook::jsi::Value getProperty( - const facebook::jsi::Object &, - const facebook::jsi::String &name) override; - bool hasProperty( - const facebook::jsi::Object &, - const facebook::jsi::PropNameID &name) override; - bool hasProperty( - const facebook::jsi::Object &, - const facebook::jsi::String &name) override; - void setPropertyValue( - facebook::jsi::Object &, - const facebook::jsi::PropNameID &name, - const facebook::jsi::Value &value) override; - void setPropertyValue( - facebook::jsi::Object &, - const facebook::jsi::String &name, - const facebook::jsi::Value &value) override; - - bool isArray(const facebook::jsi::Object &) const override; - bool isArrayBuffer(const facebook::jsi::Object &) const override; - bool isArrayBufferView(const facebook::jsi::Object &) const override; - bool isTypedArray(const facebook::jsi::Object &) const override; - bool isInt8Array(const facebook::jsi::Object &) const override; - bool isUint8Array(const facebook::jsi::Object &) const override; - bool isUint8ClampedArray(const facebook::jsi::Object &) const override; - bool isInt16Array(const facebook::jsi::Object &) const override; - bool isUint16Array(const facebook::jsi::Object &) const override; - bool isInt32Array(const facebook::jsi::Object &) const override; - bool isUint32Array(const facebook::jsi::Object &) const override; - bool isFloat32Array(const facebook::jsi::Object &) const override; - bool isBigInt64Array(const facebook::jsi::Object &) const override; - bool isBigUint64Array(const facebook::jsi::Object &) const override; - bool isFloat64Array(const facebook::jsi::Object &) const override; - - bool isFunction(const facebook::jsi::Object &) const override; - bool isHostObject(const facebook::jsi::Object &) const override; - bool isHostFunction(const facebook::jsi::Function &) const override; - facebook::jsi::Array getPropertyNames(const facebook::jsi::Object &) override; + const facebook::jsi::Object&, + const facebook::jsi::PropNameID& name) override; + facebook::jsi::Value getProperty(const facebook::jsi::Object&, + const facebook::jsi::String& name) override; + bool hasProperty(const facebook::jsi::Object&, + const facebook::jsi::PropNameID& name) override; + bool hasProperty(const facebook::jsi::Object&, + const facebook::jsi::String& name) override; + void setPropertyValue(const facebook::jsi::Object&, + const facebook::jsi::PropNameID& name, + const facebook::jsi::Value& value) override; + void setPropertyValue(const facebook::jsi::Object&, + const facebook::jsi::String& name, + const facebook::jsi::Value& value) override; + + bool isArray(const facebook::jsi::Object&) const override; + bool isArrayBuffer(const facebook::jsi::Object&) const override; + bool isFunction(const facebook::jsi::Object&) const override; + bool isHostObject(const facebook::jsi::Object&) const override; + bool isHostFunction(const facebook::jsi::Function&) const override; + facebook::jsi::Array getPropertyNames(const facebook::jsi::Object&) override; facebook::jsi::WeakObject createWeakObject( - const facebook::jsi::Object &) override; - facebook::jsi::Value lockWeakObject(facebook::jsi::WeakObject &) override; + const facebook::jsi::Object&) override; + facebook::jsi::Value lockWeakObject( + const facebook::jsi::WeakObject&) override; facebook::jsi::Array createArray(size_t length) override; - size_t size(const facebook::jsi::Array &) override; - size_t size(const facebook::jsi::ArrayBuffer &) override; - size_t size(const facebook::jsi::TypedArray &) override; - size_t offset(const facebook::jsi::TypedArray &) override; - uint8_t *data(const facebook::jsi::ArrayBuffer &) override; - uint8_t *data(const facebook::jsi::TypedArray &) override; - facebook::jsi::Value getValueAtIndex(const facebook::jsi::Array &, size_t i) - override; - void setValueAtIndexImpl( - facebook::jsi::Array &, - size_t i, - const facebook::jsi::Value &value) override; + facebook::jsi::ArrayBuffer createArrayBuffer( + std::shared_ptr buffer) override; + size_t size(const facebook::jsi::Array&) override; + size_t size(const facebook::jsi::ArrayBuffer&) override; + uint8_t* data(const facebook::jsi::ArrayBuffer&) override; + facebook::jsi::Value getValueAtIndex(const facebook::jsi::Array&, + size_t i) override; + void setValueAtIndexImpl(const facebook::jsi::Array&, size_t i, + const facebook::jsi::Value& value) override; facebook::jsi::Function createFunctionFromHostFunction( - const facebook::jsi::PropNameID &name, - unsigned int paramCount, + const facebook::jsi::PropNameID& name, unsigned int paramCount, facebook::jsi::HostFunctionType func) override; - facebook::jsi::Value call( - const facebook::jsi::Function &, - const facebook::jsi::Value &jsThis, - const facebook::jsi::Value *args, - size_t count) override; - facebook::jsi::Value callAsConstructor( - const facebook::jsi::Function &, - const facebook::jsi::Value *args, - size_t count) override; - - bool strictEquals( - const facebook::jsi::Symbol &a, - const facebook::jsi::Symbol &b) const override; - - bool strictEquals( - const facebook::jsi::BigInt &a, - const facebook::jsi::BigInt &b) const override; - - bool strictEquals( - const facebook::jsi::String &a, - const facebook::jsi::String &b) const override; - bool strictEquals( - const facebook::jsi::Object &a, - const facebook::jsi::Object &b) const override; - - bool instanceOf( - const facebook::jsi::Object &o, - const facebook::jsi::Function &f) override; - - uint64_t uint64Value(const facebook::jsi::BigInt&, bool* lossless = nullptr) const override; - - int64_t int64Value(const facebook::jsi::BigInt&, bool* lossless = nullptr) const override; + facebook::jsi::Value call(const facebook::jsi::Function&, + const facebook::jsi::Value& jsThis, + const facebook::jsi::Value* args, + size_t count) override; + facebook::jsi::Value callAsConstructor(const facebook::jsi::Function&, + const facebook::jsi::Value* args, + size_t count) override; + + bool strictEquals(const facebook::jsi::Symbol& a, + const facebook::jsi::Symbol& b) const override; + bool strictEquals(const facebook::jsi::BigInt& a, + const facebook::jsi::BigInt& b) const override; + + bool strictEquals(const facebook::jsi::String& a, + const facebook::jsi::String& b) const override; + bool strictEquals(const facebook::jsi::Object& a, + const facebook::jsi::Object& b) const override; + + bool instanceOf(const facebook::jsi::Object& o, + const facebook::jsi::Function& f) override; + + void setExternalMemoryPressure(const facebook::jsi::Object& obj, + size_t amount) override; private: friend class V8PointerValue; @@ -219,21 +206,24 @@ class V8Runtime : public facebook::jsi::Runtime { // private: // For `global._v8runtime()` - static void GetRuntimeInfo(const v8::FunctionCallbackInfo &args); + static void GetRuntimeInfo(const v8::FunctionCallbackInfo& args); // For `HostFunctionContainer()`, will call underlying HostFunction static void OnHostFuncionContainerCallback( - const v8::FunctionCallbackInfo &args); + const v8::FunctionCallbackInfo& args); private: static std::unique_ptr s_platform; private: + std::unique_ptr config_; std::unique_ptr arrayBufferAllocator_; - v8::Isolate *isolate_; + std::unique_ptr snapshotBlob_; + v8::Isolate* isolate_; v8::Global context_; + std::shared_ptr inspectorClient_; bool isSharedRuntime_ = false; - //std::shared_ptr jsQueue_; + // std::shared_ptr jsQueue_; }; -} // namespace rnv8 +} // namespace rnv8 \ No newline at end of file diff --git a/NativeScript/v8runtime/V8RuntimeConfig.h b/NativeScript/v8runtime/V8RuntimeConfig.h index a4301fb9..76ae3c74 100644 --- a/NativeScript/v8runtime/V8RuntimeConfig.h +++ b/NativeScript/v8runtime/V8RuntimeConfig.h @@ -16,11 +16,11 @@ struct V8RuntimeConfig { V8RuntimeConfig() {} ~V8RuntimeConfig() = default; - V8RuntimeConfig(const V8RuntimeConfig &rhs) = delete; - V8RuntimeConfig &operator=(const V8RuntimeConfig &rhs) = delete; + V8RuntimeConfig(const V8RuntimeConfig& rhs) = delete; + V8RuntimeConfig& operator=(const V8RuntimeConfig& rhs) = delete; - V8RuntimeConfig(V8RuntimeConfig &&rhs) = default; - V8RuntimeConfig &operator=(V8RuntimeConfig &&rhs) = default; + V8RuntimeConfig(V8RuntimeConfig&& rhs) = default; + V8RuntimeConfig& operator=(V8RuntimeConfig&& rhs) = default; }; -} // namespace rnv8 +} // namespace rnv8 \ No newline at end of file diff --git a/NativeScript/v8runtime/V8RuntimeFactory.cpp b/NativeScript/v8runtime/V8RuntimeFactory.cpp index dec4e38d..c067260f 100644 --- a/NativeScript/v8runtime/V8RuntimeFactory.cpp +++ b/NativeScript/v8runtime/V8RuntimeFactory.cpp @@ -6,19 +6,20 @@ */ #include "V8RuntimeFactory.h" + #include "V8Runtime.h" namespace rnv8 { std::unique_ptr createV8Runtime() { - return std::make_unique(); + return std::make_unique(); } -//std::unique_ptr createSharedV8Runtime( -// const facebook::jsi::Runtime *sharedRuntime, -// std::unique_ptr config) { -// auto *sharedV8Runtime = dynamic_cast(sharedRuntime); -// return std::make_unique(sharedV8Runtime, std::move(config)); -//} +// std::unique_ptr createSharedV8Runtime( +// const facebook::jsi::Runtime *sharedRuntime, +// std::unique_ptr config) { +// auto *sharedV8Runtime = dynamic_cast(sharedRuntime); +// return std::make_unique(sharedV8Runtime, std::move(config)); +// } -} // namespace rnv8 +} // namespace rnv8 \ No newline at end of file diff --git a/NativeScript/v8runtime/V8RuntimeFactory.h b/NativeScript/v8runtime/V8RuntimeFactory.h index 22d7bd7d..d2ec22a1 100644 --- a/NativeScript/v8runtime/V8RuntimeFactory.h +++ b/NativeScript/v8runtime/V8RuntimeFactory.h @@ -8,14 +8,15 @@ #pragma once #include + #include "jsi/jsi.h" namespace rnv8 { std::unique_ptr createV8Runtime(); -//std::unique_ptr createSharedV8Runtime( -// const facebook::jsi::Runtime *sharedRuntime, -// std::unique_ptr config); +// std::unique_ptr createSharedV8Runtime( +// const facebook::jsi::Runtime *sharedRuntime, +// std::unique_ptr config); -} // namespace rnv8 +} // namespace rnv8 \ No newline at end of file