diff options
Diffstat (limited to 'js/rust/src/jsglue.cpp')
-rw-r--r-- | js/rust/src/jsglue.cpp | 746 |
1 files changed, 746 insertions, 0 deletions
diff --git a/js/rust/src/jsglue.cpp b/js/rust/src/jsglue.cpp new file mode 100644 index 0000000000..69ed3bbca1 --- /dev/null +++ b/js/rust/src/jsglue.cpp @@ -0,0 +1,746 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define __STDC_LIMIT_MACROS +#include <stdint.h> + +#include "js-config.h" + +#ifdef JS_DEBUG +// A hack for MFBT. Guard objects need this to work. +# define DEBUG 1 +#endif + +#include "jsapi.h" +#include "jsfriendapi.h" +#include "js/Proxy.h" +#include "js/CharacterEncoding.h" +#include "js/Class.h" +#include "js/experimental/JitInfo.h" +#include "js/experimental/TypedData.h" +#include "js/friend/ErrorMessages.h" // js::GetErrorMessage +#include "js/MemoryMetrics.h" +#include "js/Principals.h" +#include "js/StructuredClone.h" +#include "js/Wrapper.h" +#include "assert.h" + +struct ProxyTraps { + bool (*enter)(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, + js::BaseProxyHandler::Action action, bool* bp); + + bool (*getOwnPropertyDescriptor)( + JSContext* cx, JS::HandleObject proxy, JS::HandleId id, + JS::MutableHandle<JS::PropertyDescriptor> desc); + bool (*defineProperty)(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, + JS::Handle<JS::PropertyDescriptor> desc, + JS::ObjectOpResult& result); + bool (*ownPropertyKeys)(JSContext* cx, JS::HandleObject proxy, + JS::MutableHandleIdVector props); + bool (*delete_)(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, + JS::ObjectOpResult& result); + + bool (*enumerate)(JSContext* cx, JS::HandleObject proxy, + JS::MutableHandleIdVector props); + + bool (*getPrototypeIfOrdinary)(JSContext* cx, JS::HandleObject proxy, + bool* isOrdinary, + JS::MutableHandleObject protop); + // getPrototype + // setPrototype + // setImmutablePrototype + + bool (*preventExtensions)(JSContext* cx, JS::HandleObject proxy, + JS::ObjectOpResult& result); + + bool (*isExtensible)(JSContext* cx, JS::HandleObject proxy, bool* succeeded); + + bool (*has)(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, bool* bp); + bool (*get)(JSContext* cx, JS::HandleObject proxy, JS::HandleValue receiver, + JS::HandleId id, JS::MutableHandleValue vp); + bool (*set)(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, + JS::HandleValue v, JS::HandleValue receiver, + JS::ObjectOpResult& result); + + bool (*call)(JSContext* cx, JS::HandleObject proxy, const JS::CallArgs& args); + bool (*construct)(JSContext* cx, JS::HandleObject proxy, + const JS::CallArgs& args); + + bool (*hasOwn)(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, + bool* bp); + bool (*getOwnEnumerablePropertyKeys)(JSContext* cx, JS::HandleObject proxy, + JS::MutableHandleIdVector props); + bool (*nativeCall)(JSContext* cx, JS::IsAcceptableThis test, + JS::NativeImpl impl, JS::CallArgs args); + bool (*hasInstance)(JSContext* cx, JS::HandleObject proxy, + JS::MutableHandleValue v, bool* bp); + bool (*objectClassIs)(JS::HandleObject obj, js::ESClass classValue, + JSContext* cx); + const char* (*className)(JSContext* cx, JS::HandleObject proxy); + JSString* (*fun_toString)(JSContext* cx, JS::HandleObject proxy, + bool isToString); + // bool (*regexp_toShared)(JSContext *cx, JS::HandleObject proxy, RegExpGuard + // *g); + bool (*boxedValue_unbox)(JSContext* cx, JS::HandleObject proxy, + JS::MutableHandleValue vp); + bool (*defaultValue)(JSContext* cx, JS::HandleObject obj, JSType hint, + JS::MutableHandleValue vp); + void (*trace)(JSTracer* trc, JSObject* proxy); + void (*finalize)(JSFreeOp* fop, JSObject* proxy); + size_t (*objectMoved)(JSObject* proxy, JSObject* old); + + bool (*isCallable)(JSObject* obj); + bool (*isConstructor)(JSObject* obj); + + // getElements + + // isScripted +}; + +static int HandlerFamily; + +#define DEFER_TO_TRAP_OR_BASE_CLASS(_base) \ + \ + /* Standard internal methods. */ \ + virtual bool enumerate(JSContext* cx, JS::HandleObject proxy, \ + JS::MutableHandleIdVector props) const override { \ + return mTraps.enumerate ? mTraps.enumerate(cx, proxy, props) \ + : _base::enumerate(cx, proxy, props); \ + } \ + \ + virtual bool has(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, \ + bool* bp) const override { \ + return mTraps.has ? mTraps.has(cx, proxy, id, bp) \ + : _base::has(cx, proxy, id, bp); \ + } \ + \ + virtual bool get(JSContext* cx, JS::HandleObject proxy, \ + JS::HandleValue receiver, JS::HandleId id, \ + JS::MutableHandleValue vp) const override { \ + return mTraps.get ? mTraps.get(cx, proxy, receiver, id, vp) \ + : _base::get(cx, proxy, receiver, id, vp); \ + } \ + \ + virtual bool set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, \ + JS::HandleValue v, JS::HandleValue receiver, \ + JS::ObjectOpResult& result) const override { \ + return mTraps.set ? mTraps.set(cx, proxy, id, v, receiver, result) \ + : _base::set(cx, proxy, id, v, receiver, result); \ + } \ + \ + virtual bool call(JSContext* cx, JS::HandleObject proxy, \ + const JS::CallArgs& args) const override { \ + return mTraps.call ? mTraps.call(cx, proxy, args) \ + : _base::call(cx, proxy, args); \ + } \ + \ + virtual bool construct(JSContext* cx, JS::HandleObject proxy, \ + const JS::CallArgs& args) const override { \ + return mTraps.construct ? mTraps.construct(cx, proxy, args) \ + : _base::construct(cx, proxy, args); \ + } \ + \ + /* Spidermonkey extensions. */ \ + virtual bool hasOwn(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, \ + bool* bp) const override { \ + return mTraps.hasOwn ? mTraps.hasOwn(cx, proxy, id, bp) \ + : _base::hasOwn(cx, proxy, id, bp); \ + } \ + \ + virtual bool getOwnEnumerablePropertyKeys( \ + JSContext* cx, JS::HandleObject proxy, JS::MutableHandleIdVector props) \ + const override { \ + return mTraps.getOwnEnumerablePropertyKeys \ + ? mTraps.getOwnEnumerablePropertyKeys(cx, proxy, props) \ + : _base::getOwnEnumerablePropertyKeys(cx, proxy, props); \ + } \ + \ + virtual bool nativeCall(JSContext* cx, JS::IsAcceptableThis test, \ + JS::NativeImpl impl, const JS::CallArgs& args) \ + const override { \ + return mTraps.nativeCall ? mTraps.nativeCall(cx, test, impl, args) \ + : _base::nativeCall(cx, test, impl, args); \ + } \ + \ + virtual bool hasInstance(JSContext* cx, JS::HandleObject proxy, \ + JS::MutableHandleValue v, bool* bp) \ + const override { \ + return mTraps.hasInstance ? mTraps.hasInstance(cx, proxy, v, bp) \ + : _base::hasInstance(cx, proxy, v, bp); \ + } \ + \ + virtual const char* className(JSContext* cx, JS::HandleObject proxy) \ + const override { \ + return mTraps.className ? mTraps.className(cx, proxy) \ + : _base::className(cx, proxy); \ + } \ + \ + virtual JSString* fun_toString(JSContext* cx, JS::HandleObject proxy, \ + bool isToString) const override { \ + return mTraps.fun_toString ? mTraps.fun_toString(cx, proxy, isToString) \ + : _base::fun_toString(cx, proxy, isToString); \ + } \ + \ + virtual bool boxedValue_unbox(JSContext* cx, JS::HandleObject proxy, \ + JS::MutableHandleValue vp) const override { \ + return mTraps.boxedValue_unbox ? mTraps.boxedValue_unbox(cx, proxy, vp) \ + : _base::boxedValue_unbox(cx, proxy, vp); \ + } \ + \ + virtual void trace(JSTracer* trc, JSObject* proxy) const override { \ + mTraps.trace ? mTraps.trace(trc, proxy) : _base::trace(trc, proxy); \ + } \ + \ + virtual void finalize(JSFreeOp* fop, JSObject* proxy) const override { \ + mTraps.finalize ? mTraps.finalize(fop, proxy) \ + : _base::finalize(fop, proxy); \ + } \ + \ + virtual size_t objectMoved(JSObject* proxy, JSObject* old) const override { \ + return mTraps.objectMoved ? mTraps.objectMoved(proxy, old) \ + : _base::objectMoved(proxy, old); \ + } \ + \ + virtual bool isCallable(JSObject* obj) const override { \ + return mTraps.isCallable ? mTraps.isCallable(obj) \ + : _base::isCallable(obj); \ + } \ + \ + virtual bool isConstructor(JSObject* obj) const override { \ + return mTraps.isConstructor ? mTraps.isConstructor(obj) \ + : _base::isConstructor(obj); \ + } + +class WrapperProxyHandler : public js::Wrapper { + ProxyTraps mTraps; + + public: + WrapperProxyHandler(const ProxyTraps& aTraps) + : js::Wrapper(0), mTraps(aTraps) {} + + virtual bool finalizeInBackground(const JS::Value& priv) const override { + return false; + } + + DEFER_TO_TRAP_OR_BASE_CLASS(js::Wrapper) + + virtual bool getOwnPropertyDescriptor( + JSContext* cx, JS::HandleObject proxy, JS::HandleId id, + JS::MutableHandle<JS::PropertyDescriptor> desc) const override { + return mTraps.getOwnPropertyDescriptor + ? mTraps.getOwnPropertyDescriptor(cx, proxy, id, desc) + : js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc); + } + + virtual bool defineProperty(JSContext* cx, JS::HandleObject proxy, + JS::HandleId id, + JS::Handle<JS::PropertyDescriptor> desc, + JS::ObjectOpResult& result) const override { + return mTraps.defineProperty + ? mTraps.defineProperty(cx, proxy, id, desc, result) + : js::Wrapper::defineProperty(cx, proxy, id, desc, result); + } + + virtual bool ownPropertyKeys(JSContext* cx, JS::HandleObject proxy, + JS::MutableHandleIdVector props) const override { + return mTraps.ownPropertyKeys + ? mTraps.ownPropertyKeys(cx, proxy, props) + : js::Wrapper::ownPropertyKeys(cx, proxy, props); + } + + virtual bool delete_(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, + JS::ObjectOpResult& result) const override { + return mTraps.delete_ ? mTraps.delete_(cx, proxy, id, result) + : js::Wrapper::delete_(cx, proxy, id, result); + } + + virtual bool preventExtensions(JSContext* cx, JS::HandleObject proxy, + JS::ObjectOpResult& result) const override { + return mTraps.preventExtensions + ? mTraps.preventExtensions(cx, proxy, result) + : js::Wrapper::preventExtensions(cx, proxy, result); + } + + virtual bool isExtensible(JSContext* cx, JS::HandleObject proxy, + bool* succeeded) const override { + return mTraps.isExtensible + ? mTraps.isExtensible(cx, proxy, succeeded) + : js::Wrapper::isExtensible(cx, proxy, succeeded); + } +}; + +class RustJSPrincipal : public JSPrincipals { + const void* origin; // box with origin in it + void (*destroyCallback)(JSPrincipals* principal); + bool (*writeCallback)(JSContext* cx, JSStructuredCloneWriter* writer); + + public: + RustJSPrincipal(const void* origin, void (*destroy)(JSPrincipals* principal), + bool (*write)(JSContext* cx, JSStructuredCloneWriter* writer)) + : JSPrincipals() { + this->origin = origin; + this->destroyCallback = destroy; + this->writeCallback = write; + } + + virtual const void* getOrigin() { return origin; } + + virtual void destroy() { + if (this->destroyCallback) this->destroyCallback(this); + } + + bool isSystemOrAddonPrincipal() { return false; } + + bool write(JSContext* cx, JSStructuredCloneWriter* writer) { + return this->writeCallback ? this->writeCallback(cx, writer) : false; + } +}; + +class ForwardingProxyHandler : public js::BaseProxyHandler { + ProxyTraps mTraps; + const void* mExtra; + + public: + ForwardingProxyHandler(const ProxyTraps& aTraps, const void* aExtra) + : js::BaseProxyHandler(&HandlerFamily), mTraps(aTraps), mExtra(aExtra) {} + + const void* getExtra() const { return mExtra; } + + virtual bool finalizeInBackground(const JS::Value& priv) const override { + return false; + } + + DEFER_TO_TRAP_OR_BASE_CLASS(BaseProxyHandler) + + virtual bool getOwnPropertyDescriptor( + JSContext* cx, JS::HandleObject proxy, JS::HandleId id, + JS::MutableHandle<JS::PropertyDescriptor> desc) const override { + return mTraps.getOwnPropertyDescriptor(cx, proxy, id, desc); + } + + virtual bool defineProperty(JSContext* cx, JS::HandleObject proxy, + JS::HandleId id, + JS::Handle<JS::PropertyDescriptor> desc, + JS::ObjectOpResult& result) const override { + return mTraps.defineProperty(cx, proxy, id, desc, result); + } + + virtual bool ownPropertyKeys(JSContext* cx, JS::HandleObject proxy, + JS::MutableHandleIdVector props) const override { + return mTraps.ownPropertyKeys(cx, proxy, props); + } + + virtual bool delete_(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, + JS::ObjectOpResult& result) const override { + return mTraps.delete_(cx, proxy, id, result); + } + + virtual bool getPrototypeIfOrdinary( + JSContext* cx, JS::HandleObject proxy, bool* isOrdinary, + JS::MutableHandleObject protop) const override { + return mTraps.getPrototypeIfOrdinary(cx, proxy, isOrdinary, protop); + } + + virtual bool preventExtensions(JSContext* cx, JS::HandleObject proxy, + JS::ObjectOpResult& result) const override { + return mTraps.preventExtensions(cx, proxy, result); + } + + virtual bool isExtensible(JSContext* cx, JS::HandleObject proxy, + bool* succeeded) const override { + return mTraps.isExtensible(cx, proxy, succeeded); + } +}; + +extern "C" { + +JSPrincipals* CreateRustJSPrincipal( + const void* origin, void (*destroy)(JSPrincipals* principal), + bool (*write)(JSContext* cx, JSStructuredCloneWriter* writer)) { + return new RustJSPrincipal(origin, destroy, write); +} + +const void* GetPrincipalOrigin(JSPrincipals* principal) { + return static_cast<RustJSPrincipal*>(principal)->getOrigin(); +} + +bool InvokeGetOwnPropertyDescriptor( + const void* handler, JSContext* cx, JS::HandleObject proxy, JS::HandleId id, + JS::MutableHandle<JS::PropertyDescriptor> desc) { + return static_cast<const ForwardingProxyHandler*>(handler) + ->getOwnPropertyDescriptor(cx, proxy, id, desc); +} + +bool InvokeHasOwn(const void* handler, JSContext* cx, JS::HandleObject proxy, + JS::HandleId id, bool* bp) { + return static_cast<const js::BaseProxyHandler*>(handler)->hasOwn(cx, proxy, + id, bp); +} + +JS::Value RUST_JS_NumberValue(double d) { return JS_NumberValue(d); } + +const JSJitInfo* RUST_FUNCTION_VALUE_TO_JITINFO(JS::Value v) { + return FUNCTION_VALUE_TO_JITINFO(v); +} + +JS::CallArgs CreateCallArgsFromVp(unsigned argc, JS::Value* vp) { + return JS::CallArgsFromVp(argc, vp); +} + +bool CallJitGetterOp(const JSJitInfo* info, JSContext* cx, + JS::HandleObject thisObj, void* specializedThis, + unsigned argc, JS::Value* vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + return info->getter(cx, thisObj, specializedThis, JSJitGetterCallArgs(args)); +} + +bool CallJitSetterOp(const JSJitInfo* info, JSContext* cx, + JS::HandleObject thisObj, void* specializedThis, + unsigned argc, JS::Value* vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + return info->setter(cx, thisObj, specializedThis, JSJitSetterCallArgs(args)); +} + +bool CallJitMethodOp(const JSJitInfo* info, JSContext* cx, + JS::HandleObject thisObj, void* specializedThis, + uint32_t argc, JS::Value* vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + return info->method(cx, thisObj, specializedThis, JSJitMethodCallArgs(args)); +} + +const void* CreateProxyHandler(const ProxyTraps* aTraps, const void* aExtra) { + return new ForwardingProxyHandler(*aTraps, aExtra); +} + +const void* CreateWrapperProxyHandler(const ProxyTraps* aTraps) { + return new WrapperProxyHandler(*aTraps); +} + +const void* GetCrossCompartmentWrapper() { + return &js::CrossCompartmentWrapper::singleton; +} + +const void* GetSecurityWrapper() { + return &js::CrossCompartmentSecurityWrapper::singleton; +} + +void DeleteCompileOptions(JS::ReadOnlyCompileOptions* aOpts) { + delete static_cast<JS::OwningCompileOptions*>(aOpts); +} + +JS::ReadOnlyCompileOptions* NewCompileOptions(JSContext* aCx, const char* aFile, + unsigned aLine) { + JS::CompileOptions opts(aCx); + opts.setFileAndLine(aFile, aLine); + + JS::OwningCompileOptions* owned = new JS::OwningCompileOptions(aCx); + if (!owned) { + return nullptr; + } + + if (!owned->copy(aCx, opts)) { + DeleteCompileOptions(owned); + return nullptr; + } + + return owned; +} + +JSObject* NewProxyObject(JSContext* aCx, const void* aHandler, + JS::HandleValue aPriv, JSObject* proto, + JSObject* parent, JSObject* call, + JSObject* construct) { + js::ProxyOptions options; + return js::NewProxyObject(aCx, (js::BaseProxyHandler*)aHandler, aPriv, proto, + options); +} + +JSObject* WrapperNew(JSContext* aCx, JS::HandleObject aObj, + const void* aHandler, const JSClass* aClass) { + js::WrapperOptions options; + if (aClass) { + options.setClass(aClass); + } + return js::Wrapper::New(aCx, aObj, (const js::Wrapper*)aHandler, options); +} + +JSObject* WrapperNewSingleton(JSContext* aCx, JS::HandleObject aObj, + const void* aHandler, const JSClass* aClass) { + js::WrapperOptions options; + if (aClass) { + options.setClass(aClass); + } + return js::Wrapper::NewSingleton(aCx, aObj, (const js::Wrapper*)aHandler, + options); +} + +const JSClass WindowProxyClass = PROXY_CLASS_DEF( + "Proxy", JSCLASS_HAS_RESERVED_SLOTS(1)); /* additional class flags */ + +const JSClass* GetWindowProxyClass() { return &WindowProxyClass; } + +JS::Value GetProxyReservedSlot(JSObject* obj, uint32_t slot) { + return js::GetProxyReservedSlot(obj, slot); +} + +void SetProxyReservedSlot(JSObject* obj, uint32_t slot, const JS::Value* val) { + js::SetProxyReservedSlot(obj, slot, *val); +} + +JSObject* NewWindowProxy(JSContext* aCx, JS::HandleObject aObj, + const void* aHandler) { + return WrapperNewSingleton(aCx, aObj, aHandler, &WindowProxyClass); +} + +JS::Value GetProxyPrivate(JSObject* obj) { return js::GetProxyPrivate(obj); } + +void SetProxyPrivate(JSObject* obj, const JS::Value* expando) { + js::SetProxyPrivate(obj, *expando); +} + +bool RUST_JSID_IS_INT(JS::HandleId id) { return JSID_IS_INT(id); } + +jsid int_to_jsid(int32_t i) { return INT_TO_JSID(i); } + +int32_t RUST_JSID_TO_INT(JS::HandleId id) { return JSID_TO_INT(id); } + +bool RUST_JSID_IS_STRING(JS::HandleId id) { return JSID_IS_STRING(id); } + +JSString* RUST_JSID_TO_STRING(JS::HandleId id) { return JSID_TO_STRING(id); } + +jsid RUST_SYMBOL_TO_JSID(JS::Symbol* sym) { return SYMBOL_TO_JSID(sym); } + +void RUST_SET_JITINFO(JSFunction* func, const JSJitInfo* info) { + SET_JITINFO(func, info); +} + +jsid RUST_INTERNED_STRING_TO_JSID(JSContext* cx, JSString* str) { + return JS::PropertyKey::fromPinnedString(str); +} + +const JSErrorFormatString* RUST_js_GetErrorMessage(void* userRef, + uint32_t errorNumber) { + return js::GetErrorMessage(userRef, errorNumber); +} + +bool IsProxyHandlerFamily(JSObject* obj) { + auto family = js::GetProxyHandler(obj)->family(); + return family == &HandlerFamily; +} + +const void* GetProxyHandlerFamily() { return &HandlerFamily; } + +const void* GetProxyHandlerExtra(JSObject* obj) { + const js::BaseProxyHandler* handler = js::GetProxyHandler(obj); + assert(handler->family() == &HandlerFamily); + return static_cast<const ForwardingProxyHandler*>(handler)->getExtra(); +} + +const void* GetProxyHandler(JSObject* obj) { + const js::BaseProxyHandler* handler = js::GetProxyHandler(obj); + assert(handler->family() == &HandlerFamily); + return handler; +} + +void ReportError(JSContext* aCx, const char* aError) { +#ifdef DEBUG + for (const char* p = aError; *p; ++p) { + assert(*p != '%'); + } +#endif + JS_ReportErrorASCII(aCx, "%s", aError); +} + +bool IsWrapper(JSObject* obj) { return js::IsWrapper(obj); } + +JSObject* UnwrapObjectStatic(JSObject* obj) { + return js::CheckedUnwrapStatic(obj); +} + +JSObject* UncheckedUnwrapObject(JSObject* obj, bool stopAtOuter) { + return js::UncheckedUnwrap(obj, stopAtOuter); +} + +JS::PersistentRootedIdVector* CreateRootedIdVector(JSContext* cx) { + return new JS::PersistentRootedIdVector(cx); +} + +bool AppendToRootedIdVector(JS::PersistentRootedIdVector* v, jsid id) { + return v->append(id); +} + +const jsid* SliceRootedIdVector(const JS::PersistentRootedIdVector* v, + size_t* length) { + *length = v->length(); + return v->begin(); +} + +void DestroyRootedIdVector(JS::PersistentRootedIdVector* v) { delete v; } + +JS::MutableHandleIdVector GetMutableHandleIdVector( + JS::PersistentRootedIdVector* v) { + return JS::MutableHandleIdVector(v); +} + +JS::PersistentRootedObjectVector* CreateRootedObjectVector(JSContext* aCx) { + JS::PersistentRootedObjectVector* vec = + new JS::PersistentRootedObjectVector(aCx); + return vec; +} + +bool AppendToRootedObjectVector(JS::PersistentRootedObjectVector* v, + JSObject* obj) { + return v->append(obj); +} + +void DeleteRootedObjectVector(JS::PersistentRootedObjectVector* v) { delete v; } + +#if defined(__linux__) +# include <malloc.h> +#elif defined(__APPLE__) +# include <malloc/malloc.h> +#elif defined(__MINGW32__) || defined(__MINGW64__) +// nothing needed here +#elif defined(_MSC_VER) +// nothing needed here +#else +# error "unsupported platform" +#endif + +// SpiderMonkey-in-Rust currently uses system malloc, not jemalloc. +static size_t MallocSizeOf(const void* aPtr) { +#if defined(__linux__) + return malloc_usable_size((void*)aPtr); +#elif defined(__APPLE__) + return malloc_size((void*)aPtr); +#elif defined(__MINGW32__) || defined(__MINGW64__) + return _msize((void*)aPtr); +#elif defined(_MSC_VER) + return _msize((void*)aPtr); +#else +# error "unsupported platform" +#endif +} + +bool CollectServoSizes(JSContext* cx, JS::ServoSizes* sizes) { + mozilla::PodZero(sizes); + return JS::AddServoSizeOf(cx, MallocSizeOf, + /* ObjectPrivateVisitor = */ nullptr, sizes); +} + +void CallValueTracer(JSTracer* trc, JS::Heap<JS::Value>* valuep, + const char* name) { + JS::TraceEdge(trc, valuep, name); +} + +void CallIdTracer(JSTracer* trc, JS::Heap<jsid>* idp, const char* name) { + JS::TraceEdge(trc, idp, name); +} + +void CallObjectTracer(JSTracer* trc, JS::Heap<JSObject*>* objp, + const char* name) { + JS::TraceEdge(trc, objp, name); +} + +void CallStringTracer(JSTracer* trc, JS::Heap<JSString*>* strp, + const char* name) { + JS::TraceEdge(trc, strp, name); +} + +void CallBigIntTracer(JSTracer* trc, JS::Heap<JS::BigInt*>* bip, + const char* name) { + JS::TraceEdge(trc, bip, name); +} + +void CallScriptTracer(JSTracer* trc, JS::Heap<JSScript*>* scriptp, + const char* name) { + JS::TraceEdge(trc, scriptp, name); +} + +void CallFunctionTracer(JSTracer* trc, JS::Heap<JSFunction*>* funp, + const char* name) { + JS::TraceEdge(trc, funp, name); +} + +void CallUnbarrieredObjectTracer(JSTracer* trc, JSObject** objp, + const char* name) { + js::UnsafeTraceManuallyBarrieredEdge(trc, objp, name); +} + +bool IsDebugBuild() { +#ifdef JS_DEBUG + return true; +#else + return false; +#endif +} + +#define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \ + void Get##Type##ArrayLengthAndData(JSObject* obj, uint32_t* length, \ + bool* isSharedMemory, type** data) { \ + js::Get##Type##ArrayLengthAndData(obj, length, isSharedMemory, data); \ + } + +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int8, int8_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8, uint8_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8Clamped, uint8_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int16, int16_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint16, uint16_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int32, int32_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint32, uint32_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float32, float) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float64, double) + +#undef JS_DEFINE_DATA_AND_LENGTH_ACCESSOR + +JSAutoStructuredCloneBuffer* NewJSAutoStructuredCloneBuffer( + JS::StructuredCloneScope scope, + const JSStructuredCloneCallbacks* callbacks) { + return js_new<JSAutoStructuredCloneBuffer>(scope, callbacks, nullptr); +} + +JSStructuredCloneData* DeleteJSAutoStructuredCloneBuffer( + JSAutoStructuredCloneBuffer* buf) { + js_delete(buf); +} + +size_t GetLengthOfJSStructuredCloneData(JSStructuredCloneData* data) { + assert(data != nullptr); + + size_t len = 0; + + data->ForEachDataChunk([&](const char* bytes, size_t size) { + len += size; + return true; + }); + + return len; +} + +void CopyJSStructuredCloneData(JSStructuredCloneData* src, uint8_t* dest) { + assert(src != nullptr); + assert(dest != nullptr); + + size_t bytes_copied = 0; + + src->ForEachDataChunk([&](const char* bytes, size_t size) { + memcpy(dest, bytes, size); + dest += size; + return true; + }); +} + +bool WriteBytesToJSStructuredCloneData(const uint8_t* src, size_t len, + JSStructuredCloneData* dest) { + assert(src != nullptr); + assert(dest != nullptr); + + return dest->AppendBytes(reinterpret_cast<const char*>(src), len); +} + +char* JSEncodeStringToUTF8(JSContext* cx, JS::HandleString string) { + return JS_EncodeStringToUTF8(cx, string).release(); +} + +} // extern "C" |