mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 905017 (part 2, attempt 2) - Move structured clone stuff from jsapi.{h,cpp} and jsclone.{h,cpp} to js/StructuredClone.{h,cpp}. r=billm.
--HG-- rename : js/src/jsclone.cpp => js/src/vm/StructuredClone.cpp extra : rebase_source : 2699588c63ef58ab84bc8c63adc0487648af3834
This commit is contained in:
parent
db501ffdf0
commit
9ce6c39a8f
@ -337,7 +337,8 @@ class Include(object):
|
||||
# handling.
|
||||
if module == module_name(self.inclname) or \
|
||||
module == 'jsmemorymetrics' and self.inclname == 'js/MemoryMetrics.h' or \
|
||||
module == 'vm/PropertyKey' and self.inclname == 'js/PropertyKey.h':
|
||||
module == 'vm/PropertyKey' and self.inclname == 'js/PropertyKey.h' or \
|
||||
module == 'vm/StructuredClone' and self.inclname == 'js/StructuredClone.h':
|
||||
return 0
|
||||
|
||||
if '/' in self.inclname:
|
||||
|
@ -5,6 +5,8 @@
|
||||
#ifndef StructuredCloneTags_h__
|
||||
#define StructuredCloneTags_h__
|
||||
|
||||
#include "js/StructuredClone.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "jsapi.h"
|
||||
#include "js/StructuredClone.h"
|
||||
|
||||
#include "mozilla/Base64.h"
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "BluetoothCommon.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "jsapi.h"
|
||||
#include "js/Value.h"
|
||||
|
||||
class nsIDOMDOMRequest;
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "nsIProgrammingLanguage.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "jsapi.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDebug.h"
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include "mozIStorageStatement.h"
|
||||
|
||||
#include "js/Value.h"
|
||||
|
||||
namespace IPC {
|
||||
template <typename T> struct ParamTraits;
|
||||
} // namespace IPC
|
||||
@ -159,7 +161,7 @@ public:
|
||||
}
|
||||
|
||||
nsresult SetFromJSVal(JSContext* aCx,
|
||||
const jsval aVal)
|
||||
const JS::Value aVal)
|
||||
{
|
||||
mBuffer.Truncate();
|
||||
|
||||
@ -209,7 +211,7 @@ public:
|
||||
|
||||
nsresult AppendItem(JSContext* aCx,
|
||||
bool aFirstOfArray,
|
||||
const jsval aVal)
|
||||
const JS::Value aVal)
|
||||
{
|
||||
nsresult rv = EncodeJSVal(aCx, aVal, aFirstOfArray ? eMaxType : 0);
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -303,7 +305,7 @@ private:
|
||||
}
|
||||
|
||||
// Encoding functions. These append the encoded value to the end of mBuffer
|
||||
inline nsresult EncodeJSVal(JSContext* aCx, const jsval aVal,
|
||||
inline nsresult EncodeJSVal(JSContext* aCx, const JS::Value aVal,
|
||||
uint8_t aTypeOffset)
|
||||
{
|
||||
return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0);
|
||||
@ -329,7 +331,7 @@ private:
|
||||
nsCString mBuffer;
|
||||
|
||||
private:
|
||||
nsresult EncodeJSValInternal(JSContext* aCx, const jsval aVal,
|
||||
nsresult EncodeJSValInternal(JSContext* aCx, const JS::Value aVal,
|
||||
uint8_t aTypeOffset, uint16_t aRecursionDepth);
|
||||
|
||||
static nsresult DecodeJSValInternal(const unsigned char*& aPos,
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "StructuredCloneTags.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "nsTArray.h"
|
||||
#include "nsIDOMFile.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "js/StructuredClone.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include "Workers.h"
|
||||
|
||||
class JSAutoStructuredCloneBuffer;
|
||||
#include "js/StructuredClone.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
|
||||
#include "js/StructuredClone.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class Proxy;
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "nsMemory.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsTArray.h"
|
||||
#include "jsapi.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "nsCSSProperty.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
162
js/public/StructuredClone.h
Normal file
162
js/public/StructuredClone.h
Normal file
@ -0,0 +1,162 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
#ifndef js_StructuredClone_h
|
||||
#define js_StructuredClone_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "jstypes.h"
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
struct JSRuntime;
|
||||
struct JSStructuredCloneReader;
|
||||
struct JSStructuredCloneWriter;
|
||||
|
||||
namespace JS {
|
||||
template <typename T> class Handle;
|
||||
class Value;
|
||||
}
|
||||
|
||||
// API for the HTML5 internal structured cloning algorithm.
|
||||
|
||||
// Read structured data from the reader r. This hook is used to read a value
|
||||
// previously serialized by a call to the WriteStructuredCloneOp hook.
|
||||
//
|
||||
// tag and data are the pair of uint32_t values from the header. The callback
|
||||
// may use the JS_Read* APIs to read any other relevant parts of the object
|
||||
// from the reader r. closure is any value passed to the JS_ReadStructuredClone
|
||||
// function. Return the new object on success, NULL on error/exception.
|
||||
typedef JSObject *(*ReadStructuredCloneOp)(JSContext *cx, JSStructuredCloneReader *r,
|
||||
uint32_t tag, uint32_t data, void *closure);
|
||||
|
||||
// Structured data serialization hook. The engine can write primitive values,
|
||||
// Objects, Arrays, Dates, RegExps, TypedArrays, and ArrayBuffers. Any other
|
||||
// type of object requires application support. This callback must first use
|
||||
// the JS_WriteUint32Pair API to write an object header, passing a value
|
||||
// greater than JS_SCTAG_USER to the tag parameter. Then it can use the
|
||||
// JS_Write* APIs to write any other relevant parts of the value v to the
|
||||
// writer w. closure is any value passed to the JS_WriteStructuredCLone function.
|
||||
//
|
||||
// Return true on success, false on error/exception.
|
||||
typedef bool (*WriteStructuredCloneOp)(JSContext *cx, JSStructuredCloneWriter *w,
|
||||
JS::Handle<JSObject*> obj, void *closure);
|
||||
|
||||
// This is called when JS_WriteStructuredClone is given an invalid transferable.
|
||||
// To follow HTML5, the application must throw a DATA_CLONE_ERR DOMException
|
||||
// with error set to one of the JS_SCERR_* values.
|
||||
typedef void (*StructuredCloneErrorOp)(JSContext *cx, uint32_t errorid);
|
||||
|
||||
// The maximum supported structured-clone serialization format version.
|
||||
#define JS_STRUCTURED_CLONE_VERSION 2
|
||||
|
||||
struct JSStructuredCloneCallbacks {
|
||||
ReadStructuredCloneOp read;
|
||||
WriteStructuredCloneOp write;
|
||||
StructuredCloneErrorOp reportError;
|
||||
};
|
||||
|
||||
// Note: if the *data contains transferable objects, it can be read only once.
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, uint32_t version,
|
||||
JS::Value *vp, const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure);
|
||||
|
||||
// Note: On success, the caller is responsible for calling
|
||||
// JS_ClearStructuredClone(*datap, nbytesp).
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteStructuredClone(JSContext *cx, JS::Value v, uint64_t **datap, size_t *nbytesp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure, JS::Value transferable);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ClearStructuredClone(const uint64_t *data, size_t nbytes);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes, bool *hasTransferable);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredClone(JSContext *cx, JS::Value v, JS::Value *vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks, void *closure);
|
||||
|
||||
// RAII sugar for JS_WriteStructuredClone.
|
||||
class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
|
||||
uint64_t *data_;
|
||||
size_t nbytes_;
|
||||
uint32_t version_;
|
||||
|
||||
public:
|
||||
JSAutoStructuredCloneBuffer()
|
||||
: data_(NULL), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION) {}
|
||||
|
||||
~JSAutoStructuredCloneBuffer() { clear(); }
|
||||
|
||||
uint64_t *data() const { return data_; }
|
||||
size_t nbytes() const { return nbytes_; }
|
||||
|
||||
void clear();
|
||||
|
||||
// Copy some memory. It will be automatically freed by the destructor.
|
||||
bool copy(const uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
|
||||
|
||||
// Adopt some memory. It will be automatically freed by the destructor.
|
||||
// data must have been allocated by the JS engine (e.g., extracted via
|
||||
// JSAutoStructuredCloneBuffer::steal).
|
||||
void adopt(uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
|
||||
|
||||
// Remove the buffer so that it will not be automatically freed.
|
||||
// After this, the caller is responsible for feeding the memory back to
|
||||
// JSAutoStructuredCloneBuffer::adopt.
|
||||
void steal(uint64_t **datap, size_t *nbytesp, uint32_t *versionp=NULL);
|
||||
|
||||
bool read(JSContext *cx, JS::Value *vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks=NULL, void *closure=NULL);
|
||||
|
||||
bool write(JSContext *cx, JS::Value v,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks=NULL, void *closure=NULL);
|
||||
|
||||
bool write(JSContext *cx, JS::Value v, JS::Value transferable,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks=NULL, void *closure=NULL);
|
||||
|
||||
// Swap ownership with another JSAutoStructuredCloneBuffer.
|
||||
void swap(JSAutoStructuredCloneBuffer &other);
|
||||
|
||||
private:
|
||||
// Copy and assignment are not supported.
|
||||
JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer &other);
|
||||
JSAutoStructuredCloneBuffer &operator=(const JSAutoStructuredCloneBuffer &other);
|
||||
};
|
||||
|
||||
// The range of tag values the application may use for its own custom object types.
|
||||
#define JS_SCTAG_USER_MIN ((uint32_t) 0xFFFF8000)
|
||||
#define JS_SCTAG_USER_MAX ((uint32_t) 0xFFFFFFFF)
|
||||
|
||||
#define JS_SCERR_RECURSION 0
|
||||
#define JS_SCERR_TRANSFERABLE 1
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadTypedArray(JSStructuredCloneReader *r, JS::Value *vp);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteTypedArray(JSStructuredCloneWriter *w, JS::Value v);
|
||||
|
||||
#endif /* js_StructuredClone_h */
|
@ -1896,6 +1896,17 @@ JSVAL_TO_PRIVATE(jsval v)
|
||||
return JSVAL_TO_PRIVATE_PTR_IMPL(JSVAL_TO_IMPL(v));
|
||||
}
|
||||
|
||||
// JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and
|
||||
// constructing values from scratch (e.g. Int32Value(0)). These constants are
|
||||
// stored in memory and initialized at startup, so testing against them and
|
||||
// using them requires memory loads and will be correspondingly slow.
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID;
|
||||
|
||||
#undef JS_VALUE_IS_CONSTEXPR
|
||||
#undef JS_RETURN_LAYOUT_FROM_BITS
|
||||
|
||||
|
@ -337,7 +337,8 @@ class Include(object):
|
||||
# handling.
|
||||
if module == module_name(self.inclname) or \
|
||||
module == 'jsmemorymetrics' and self.inclname == 'js/MemoryMetrics.h' or \
|
||||
module == 'vm/PropertyKey' and self.inclname == 'js/PropertyKey.h':
|
||||
module == 'vm/PropertyKey' and self.inclname == 'js/PropertyKey.h' or \
|
||||
module == 'vm/StructuredClone' and self.inclname == 'js/StructuredClone.h':
|
||||
return 0
|
||||
|
||||
if '/' in self.inclname:
|
||||
|
230
js/src/jsapi.cpp
230
js/src/jsapi.cpp
@ -21,7 +21,6 @@
|
||||
#include "jsarray.h"
|
||||
#include "jsatom.h"
|
||||
#include "jsbool.h"
|
||||
#include "jsclone.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsdate.h"
|
||||
#include "jsexn.h"
|
||||
@ -60,6 +59,7 @@
|
||||
#include "gc/Marking.h"
|
||||
#include "jit/AsmJSLink.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#if ENABLE_INTL_API
|
||||
#include "unicode/uclean.h"
|
||||
#include "unicode/utypes.h"
|
||||
@ -134,10 +134,8 @@ const jsval JSVAL_ONE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32, 1));
|
||||
const jsval JSVAL_FALSE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_BOOLEAN, false));
|
||||
const jsval JSVAL_TRUE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_BOOLEAN, true));
|
||||
const jsval JSVAL_VOID = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0));
|
||||
const HandleValue JS::NullHandleValue =
|
||||
HandleValue::fromMarkedLocation(&JSVAL_NULL);
|
||||
const HandleValue JS::UndefinedHandleValue =
|
||||
HandleValue::fromMarkedLocation(&JSVAL_VOID);
|
||||
const HandleValue JS::NullHandleValue = HandleValue::fromMarkedLocation(&JSVAL_NULL);
|
||||
const HandleValue JS::UndefinedHandleValue = HandleValue::fromMarkedLocation(&JSVAL_VOID);
|
||||
|
||||
const jsid voidIdValue = JSID_VOID;
|
||||
const jsid emptyIdValue = JSID_EMPTY;
|
||||
@ -185,18 +183,22 @@ JS_GetEmptyString(JSRuntime *rt)
|
||||
return rt->emptyString;
|
||||
}
|
||||
|
||||
static void
|
||||
namespace js {
|
||||
|
||||
void
|
||||
AssertHeapIsIdle(JSRuntime *rt)
|
||||
{
|
||||
JS_ASSERT(rt->heapState == js::Idle);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
AssertHeapIsIdle(JSContext *cx)
|
||||
{
|
||||
AssertHeapIsIdle(cx->runtime());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
AssertHeapIsIdleOrIterating(JSRuntime *rt)
|
||||
{
|
||||
@ -5932,220 +5934,6 @@ JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, jsval
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadStructuredClone(JSContext *cx, uint64_t *buf, size_t nbytes,
|
||||
uint32_t version, jsval *vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
if (version > JS_STRUCTURED_CLONE_VERSION) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION);
|
||||
return false;
|
||||
}
|
||||
const JSStructuredCloneCallbacks *callbacks =
|
||||
optionalCallbacks ?
|
||||
optionalCallbacks :
|
||||
cx->runtime()->structuredCloneCallbacks;
|
||||
return ReadStructuredClone(cx, buf, nbytes, vp, callbacks, closure);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteStructuredClone(JSContext *cx, jsval valueArg, uint64_t **bufp, size_t *nbytesp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure, jsval transferable)
|
||||
{
|
||||
RootedValue value(cx, valueArg);
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, value);
|
||||
|
||||
const JSStructuredCloneCallbacks *callbacks =
|
||||
optionalCallbacks ?
|
||||
optionalCallbacks :
|
||||
cx->runtime()->structuredCloneCallbacks;
|
||||
return WriteStructuredClone(cx, value, (uint64_t **) bufp, nbytesp,
|
||||
callbacks, closure, transferable);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ClearStructuredClone(const uint64_t *data, size_t nbytes)
|
||||
{
|
||||
return ClearStructuredClone(data, nbytes);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes,
|
||||
bool *hasTransferable)
|
||||
{
|
||||
bool transferable;
|
||||
if (!StructuredCloneHasTransferObjects(data, nbytes, &transferable))
|
||||
return false;
|
||||
|
||||
*hasTransferable = transferable;
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredClone(JSContext *cx, jsval valueArg, jsval *vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure)
|
||||
{
|
||||
RootedValue value(cx, valueArg);
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, value);
|
||||
|
||||
const JSStructuredCloneCallbacks *callbacks =
|
||||
optionalCallbacks ?
|
||||
optionalCallbacks :
|
||||
cx->runtime()->structuredCloneCallbacks;
|
||||
JSAutoStructuredCloneBuffer buf;
|
||||
return buf.write(cx, value, callbacks, closure) &&
|
||||
buf.read(cx, vp, callbacks, closure);
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::clear()
|
||||
{
|
||||
if (data_) {
|
||||
ClearStructuredClone(data_, nbytes_);
|
||||
data_ = NULL;
|
||||
nbytes_ = 0;
|
||||
version_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::adopt(uint64_t *data, size_t nbytes, uint32_t version)
|
||||
{
|
||||
clear();
|
||||
data_ = data;
|
||||
nbytes_ = nbytes;
|
||||
version_ = version;
|
||||
}
|
||||
|
||||
bool
|
||||
JSAutoStructuredCloneBuffer::copy(const uint64_t *srcData, size_t nbytes, uint32_t version)
|
||||
{
|
||||
// transferable objects cannot be copied
|
||||
bool hasTransferable;
|
||||
if (!StructuredCloneHasTransferObjects(data_, nbytes_, &hasTransferable) ||
|
||||
hasTransferable)
|
||||
return false;
|
||||
|
||||
uint64_t *newData = static_cast<uint64_t *>(js_malloc(nbytes));
|
||||
if (!newData)
|
||||
return false;
|
||||
|
||||
js_memcpy(newData, srcData, nbytes);
|
||||
|
||||
clear();
|
||||
data_ = newData;
|
||||
nbytes_ = nbytes;
|
||||
version_ = version;
|
||||
return true;
|
||||
}
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::steal(uint64_t **datap, size_t *nbytesp, uint32_t *versionp)
|
||||
{
|
||||
*datap = data_;
|
||||
*nbytesp = nbytes_;
|
||||
if (versionp)
|
||||
*versionp = version_;
|
||||
|
||||
data_ = NULL;
|
||||
nbytes_ = 0;
|
||||
version_ = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
JSAutoStructuredCloneBuffer::read(JSContext *cx, jsval *vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure)
|
||||
{
|
||||
JS_ASSERT(cx);
|
||||
JS_ASSERT(data_);
|
||||
return !!JS_ReadStructuredClone(cx, data_, nbytes_, version_, vp,
|
||||
optionalCallbacks, closure);
|
||||
}
|
||||
|
||||
bool
|
||||
JSAutoStructuredCloneBuffer::write(JSContext *cx, jsval valueArg,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure)
|
||||
{
|
||||
jsval transferable = JSVAL_VOID;
|
||||
return write(cx, valueArg, transferable, optionalCallbacks, closure);
|
||||
}
|
||||
|
||||
bool
|
||||
JSAutoStructuredCloneBuffer::write(JSContext *cx, jsval valueArg,
|
||||
jsval transferable,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure)
|
||||
{
|
||||
RootedValue value(cx, valueArg);
|
||||
clear();
|
||||
bool ok = !!JS_WriteStructuredClone(cx, value, &data_, &nbytes_,
|
||||
optionalCallbacks, closure,
|
||||
transferable);
|
||||
if (!ok) {
|
||||
data_ = NULL;
|
||||
nbytes_ = 0;
|
||||
version_ = JS_STRUCTURED_CLONE_VERSION;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::swap(JSAutoStructuredCloneBuffer &other)
|
||||
{
|
||||
uint64_t *data = other.data_;
|
||||
size_t nbytes = other.nbytes_;
|
||||
uint32_t version = other.version_;
|
||||
|
||||
other.data_ = this->data_;
|
||||
other.nbytes_ = this->nbytes_;
|
||||
other.version_ = this->version_;
|
||||
|
||||
this->data_ = data;
|
||||
this->nbytes_ = nbytes;
|
||||
this->version_ = version;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks)
|
||||
{
|
||||
rt->structuredCloneCallbacks = callbacks;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2)
|
||||
{
|
||||
return r->input().readPair((uint32_t *) p1, (uint32_t *) p2);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len)
|
||||
{
|
||||
return r->input().readBytes(p, len);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data)
|
||||
{
|
||||
return w->output().writePair(tag, data);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len)
|
||||
{
|
||||
return w->output().writeBytes(p, len);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
180
js/src/jsapi.h
180
js/src/jsapi.h
@ -1147,54 +1147,8 @@ typedef void
|
||||
(* JSCompartmentNameCallback)(JSRuntime *rt, JSCompartment *compartment,
|
||||
char *buf, size_t bufsize);
|
||||
|
||||
/*
|
||||
* Read structured data from the reader r. This hook is used to read a value
|
||||
* previously serialized by a call to the WriteStructuredCloneOp hook.
|
||||
*
|
||||
* tag and data are the pair of uint32_t values from the header. The callback
|
||||
* may use the JS_Read* APIs to read any other relevant parts of the object
|
||||
* from the reader r. closure is any value passed to the JS_ReadStructuredClone
|
||||
* function. Return the new object on success, NULL on error/exception.
|
||||
*/
|
||||
typedef JSObject *(*ReadStructuredCloneOp)(JSContext *cx, JSStructuredCloneReader *r,
|
||||
uint32_t tag, uint32_t data, void *closure);
|
||||
|
||||
/*
|
||||
* Structured data serialization hook. The engine can write primitive values,
|
||||
* Objects, Arrays, Dates, RegExps, TypedArrays, and ArrayBuffers. Any other
|
||||
* type of object requires application support. This callback must first use
|
||||
* the JS_WriteUint32Pair API to write an object header, passing a value
|
||||
* greater than JS_SCTAG_USER to the tag parameter. Then it can use the
|
||||
* JS_Write* APIs to write any other relevant parts of the value v to the
|
||||
* writer w. closure is any value passed to the JS_WriteStructuredCLone function.
|
||||
*
|
||||
* Return true on success, false on error/exception.
|
||||
*/
|
||||
typedef bool (*WriteStructuredCloneOp)(JSContext *cx, JSStructuredCloneWriter *w,
|
||||
JS::Handle<JSObject*> obj, void *closure);
|
||||
|
||||
/*
|
||||
* This is called when JS_WriteStructuredClone is given an invalid transferable.
|
||||
* To follow HTML5, the application must throw a DATA_CLONE_ERR DOMException
|
||||
* with error set to one of the JS_SCERR_* values.
|
||||
*/
|
||||
typedef void (*StructuredCloneErrorOp)(JSContext *cx, uint32_t errorid);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and
|
||||
* constructing values from scratch (e.g. Int32Value(0)). These constants are
|
||||
* stored in memory and initialized at startup, so testing against them and
|
||||
* using them requires memory loads and will be correspondingly slow.
|
||||
*/
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID;
|
||||
|
||||
static JS_ALWAYS_INLINE jsval
|
||||
JS_NumberValue(double d)
|
||||
{
|
||||
@ -1876,6 +1830,12 @@ template <> struct GCMethods<jsid>
|
||||
#endif
|
||||
};
|
||||
|
||||
void
|
||||
AssertHeapIsIdle(JSRuntime *rt);
|
||||
|
||||
void
|
||||
AssertHeapIsIdle(JSContext *cx);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
class JSAutoRequest
|
||||
@ -4709,134 +4669,6 @@ JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, jsval
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/* API for the HTML5 internal structured cloning algorithm. */
|
||||
|
||||
/* The maximum supported structured-clone serialization format version. */
|
||||
#define JS_STRUCTURED_CLONE_VERSION 2
|
||||
|
||||
struct JSStructuredCloneCallbacks {
|
||||
ReadStructuredCloneOp read;
|
||||
WriteStructuredCloneOp write;
|
||||
StructuredCloneErrorOp reportError;
|
||||
};
|
||||
|
||||
/* Note: if the *data contains transferable objects, it can be read
|
||||
* only once */
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes,
|
||||
uint32_t version, jsval *vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure);
|
||||
|
||||
/* Note: On success, the caller is responsible for calling
|
||||
* JS_ClearStructuredClone(*datap, nbytesp). */
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteStructuredClone(JSContext *cx, jsval v, uint64_t **datap, size_t *nbytesp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure, jsval transferable);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ClearStructuredClone(const uint64_t *data, size_t nbytes);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes,
|
||||
bool *hasTransferable);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredClone(JSContext *cx, jsval v, jsval *vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure);
|
||||
|
||||
/* RAII sugar for JS_WriteStructuredClone. */
|
||||
class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
|
||||
uint64_t *data_;
|
||||
size_t nbytes_;
|
||||
uint32_t version_;
|
||||
|
||||
public:
|
||||
JSAutoStructuredCloneBuffer()
|
||||
: data_(NULL), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION) {}
|
||||
|
||||
~JSAutoStructuredCloneBuffer() { clear(); }
|
||||
|
||||
uint64_t *data() const { return data_; }
|
||||
size_t nbytes() const { return nbytes_; }
|
||||
|
||||
void clear();
|
||||
|
||||
/* Copy some memory. It will be automatically freed by the destructor. */
|
||||
bool copy(const uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
|
||||
|
||||
/*
|
||||
* Adopt some memory. It will be automatically freed by the destructor.
|
||||
* data must have been allocated by the JS engine (e.g., extracted via
|
||||
* JSAutoStructuredCloneBuffer::steal).
|
||||
*/
|
||||
void adopt(uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
|
||||
|
||||
/*
|
||||
* Remove the buffer so that it will not be automatically freed.
|
||||
* After this, the caller is responsible for feeding the memory back to
|
||||
* JSAutoStructuredCloneBuffer::adopt.
|
||||
*/
|
||||
void steal(uint64_t **datap, size_t *nbytesp, uint32_t *versionp=NULL);
|
||||
|
||||
bool read(JSContext *cx, jsval *vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks=NULL,
|
||||
void *closure=NULL);
|
||||
|
||||
bool write(JSContext *cx, jsval v,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks=NULL,
|
||||
void *closure=NULL);
|
||||
|
||||
bool write(JSContext *cx, jsval v,
|
||||
jsval transferable,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks=NULL,
|
||||
void *closure=NULL);
|
||||
|
||||
/**
|
||||
* Swap ownership with another JSAutoStructuredCloneBuffer.
|
||||
*/
|
||||
void swap(JSAutoStructuredCloneBuffer &other);
|
||||
|
||||
private:
|
||||
/* Copy and assignment are not supported. */
|
||||
JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer &other);
|
||||
JSAutoStructuredCloneBuffer &operator=(const JSAutoStructuredCloneBuffer &other);
|
||||
};
|
||||
|
||||
/* API for implementing custom serialization behavior (for ImageData, File, etc.) */
|
||||
|
||||
/* The range of tag values the application may use for its own custom object types. */
|
||||
#define JS_SCTAG_USER_MIN ((uint32_t) 0xFFFF8000)
|
||||
#define JS_SCTAG_USER_MAX ((uint32_t) 0xFFFFFFFF)
|
||||
|
||||
#define JS_SCERR_RECURSION 0
|
||||
#define JS_SCERR_TRANSFERABLE 1
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadTypedArray(JSStructuredCloneReader *r, jsval *vp);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* The default locale for the ECMAScript Internationalization API
|
||||
* (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat).
|
||||
|
206
js/src/jsclone.h
206
js/src/jsclone.h
@ -1,206 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
#ifndef jsclone_h
|
||||
#define jsclone_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "js/Vector.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
bool
|
||||
WriteStructuredClone(JSContext *cx, HandleValue v, uint64_t **bufp, size_t *nbytesp,
|
||||
const JSStructuredCloneCallbacks *cb, void *cbClosure,
|
||||
jsval transferable);
|
||||
|
||||
bool
|
||||
ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp,
|
||||
const JSStructuredCloneCallbacks *cb, void *cbClosure);
|
||||
|
||||
bool
|
||||
ClearStructuredClone(const uint64_t *data, size_t nbytes);
|
||||
|
||||
bool
|
||||
StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes,
|
||||
bool *hasTransferable);
|
||||
|
||||
struct SCOutput {
|
||||
public:
|
||||
explicit SCOutput(JSContext *cx);
|
||||
|
||||
JSContext *context() const { return cx; }
|
||||
|
||||
bool write(uint64_t u);
|
||||
bool writePair(uint32_t tag, uint32_t data);
|
||||
bool writeDouble(double d);
|
||||
bool writeBytes(const void *p, size_t nbytes);
|
||||
bool writeChars(const jschar *p, size_t nchars);
|
||||
bool writePtr(const void *);
|
||||
|
||||
template <class T>
|
||||
bool writeArray(const T *p, size_t nbytes);
|
||||
|
||||
bool extractBuffer(uint64_t **datap, size_t *sizep);
|
||||
|
||||
uint64_t count() { return buf.length(); }
|
||||
|
||||
private:
|
||||
JSContext *cx;
|
||||
js::Vector<uint64_t> buf;
|
||||
};
|
||||
|
||||
struct SCInput {
|
||||
public:
|
||||
SCInput(JSContext *cx, uint64_t *data, size_t nbytes);
|
||||
|
||||
JSContext *context() const { return cx; }
|
||||
|
||||
bool read(uint64_t *p);
|
||||
bool readPair(uint32_t *tagp, uint32_t *datap);
|
||||
bool readDouble(double *p);
|
||||
bool readBytes(void *p, size_t nbytes);
|
||||
bool readChars(jschar *p, size_t nchars);
|
||||
bool readPtr(void **);
|
||||
|
||||
bool get(uint64_t *p);
|
||||
bool getPair(uint32_t *tagp, uint32_t *datap);
|
||||
|
||||
bool replace(uint64_t u);
|
||||
bool replacePair(uint32_t tag, uint32_t data);
|
||||
|
||||
template <class T>
|
||||
bool readArray(T *p, size_t nelems);
|
||||
|
||||
private:
|
||||
bool eof();
|
||||
|
||||
void staticAssertions() {
|
||||
JS_STATIC_ASSERT(sizeof(jschar) == 2);
|
||||
JS_STATIC_ASSERT(sizeof(uint32_t) == 4);
|
||||
JS_STATIC_ASSERT(sizeof(double) == 8);
|
||||
}
|
||||
|
||||
JSContext *cx;
|
||||
uint64_t *point;
|
||||
uint64_t *end;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
struct JSStructuredCloneReader {
|
||||
public:
|
||||
explicit JSStructuredCloneReader(js::SCInput &in, const JSStructuredCloneCallbacks *cb,
|
||||
void *cbClosure)
|
||||
: in(in), objs(in.context()), allObjs(in.context()),
|
||||
callbacks(cb), closure(cbClosure) { }
|
||||
|
||||
js::SCInput &input() { return in; }
|
||||
bool read(js::Value *vp);
|
||||
|
||||
private:
|
||||
JSContext *context() { return in.context(); }
|
||||
|
||||
bool readTransferMap();
|
||||
|
||||
bool checkDouble(double d);
|
||||
JSString *readString(uint32_t nchars);
|
||||
bool readTypedArray(uint32_t arrayType, uint32_t nelems, js::Value *vp, bool v1Read = false);
|
||||
bool readArrayBuffer(uint32_t nbytes, js::Value *vp);
|
||||
bool readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems, js::Value *vp);
|
||||
bool readId(jsid *idp);
|
||||
bool startRead(js::Value *vp);
|
||||
|
||||
js::SCInput ∈
|
||||
|
||||
// Stack of objects with properties remaining to be read.
|
||||
js::AutoValueVector objs;
|
||||
|
||||
// Stack of all objects read during this deserialization
|
||||
js::AutoValueVector allObjs;
|
||||
|
||||
// The user defined callbacks that will be used for cloning.
|
||||
const JSStructuredCloneCallbacks *callbacks;
|
||||
|
||||
// Any value passed to JS_ReadStructuredClone.
|
||||
void *closure;
|
||||
|
||||
friend bool JS_ReadTypedArray(JSStructuredCloneReader *r, jsval *vp);
|
||||
};
|
||||
|
||||
struct JSStructuredCloneWriter {
|
||||
public:
|
||||
explicit JSStructuredCloneWriter(js::SCOutput &out,
|
||||
const JSStructuredCloneCallbacks *cb,
|
||||
void *cbClosure,
|
||||
jsval tVal)
|
||||
: out(out), objs(out.context()),
|
||||
counts(out.context()), ids(out.context()),
|
||||
memory(out.context()), callbacks(cb), closure(cbClosure),
|
||||
transferable(out.context(), tVal), transferableObjects(out.context()) { }
|
||||
|
||||
bool init() { return transferableObjects.init() && parseTransferable() &&
|
||||
memory.init() && writeTransferMap(); }
|
||||
|
||||
bool write(const js::Value &v);
|
||||
|
||||
js::SCOutput &output() { return out; }
|
||||
|
||||
private:
|
||||
JSContext *context() { return out.context(); }
|
||||
|
||||
bool writeTransferMap();
|
||||
|
||||
bool writeString(uint32_t tag, JSString *str);
|
||||
bool writeId(jsid id);
|
||||
bool writeArrayBuffer(JS::HandleObject obj);
|
||||
bool writeTypedArray(JS::HandleObject obj);
|
||||
bool startObject(JS::HandleObject obj, bool *backref);
|
||||
bool startWrite(const js::Value &v);
|
||||
bool traverseObject(JS::HandleObject obj);
|
||||
|
||||
bool parseTransferable();
|
||||
void reportErrorTransferable();
|
||||
|
||||
inline void checkStack();
|
||||
|
||||
js::SCOutput &out;
|
||||
|
||||
// Vector of objects with properties remaining to be written.
|
||||
//
|
||||
// NB: These can span multiple compartments, so the compartment must be
|
||||
// entered before any manipulation is performed.
|
||||
js::AutoValueVector objs;
|
||||
|
||||
// counts[i] is the number of properties of objs[i] remaining to be written.
|
||||
// counts.length() == objs.length() and sum(counts) == ids.length().
|
||||
js::Vector<size_t> counts;
|
||||
|
||||
// Ids of properties remaining to be written.
|
||||
js::AutoIdVector ids;
|
||||
|
||||
// The "memory" list described in the HTML5 internal structured cloning algorithm.
|
||||
// memory is a superset of objs; items are never removed from Memory
|
||||
// until a serialization operation is finished
|
||||
typedef js::AutoObjectUnsigned32HashMap CloneMemory;
|
||||
CloneMemory memory;
|
||||
|
||||
// The user defined callbacks that will be used for cloning.
|
||||
const JSStructuredCloneCallbacks *callbacks;
|
||||
|
||||
// Any value passed to JS_WriteStructuredClone.
|
||||
void *closure;
|
||||
|
||||
// List of transferable objects
|
||||
JS::RootedValue transferable;
|
||||
js::AutoObjectHashSet transferableObjects;
|
||||
|
||||
friend bool JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v);
|
||||
};
|
||||
|
||||
#endif /* jsclone_h */
|
@ -71,6 +71,7 @@ EXPORTS.js += [
|
||||
'../public/PropertyKey.h',
|
||||
'../public/RequiredDefines.h',
|
||||
'../public/RootingAPI.h',
|
||||
'../public/StructuredClone.h',
|
||||
'../public/Utility.h',
|
||||
'../public/Value.h',
|
||||
'../public/Vector.h',
|
||||
@ -125,6 +126,7 @@ CPP_SOURCES += [
|
||||
'StoreBuffer.cpp',
|
||||
'String.cpp',
|
||||
'StringBuffer.cpp',
|
||||
'StructuredClone.cpp',
|
||||
'TestingFunctions.cpp',
|
||||
'ThreadPool.cpp',
|
||||
'TokenStream.cpp',
|
||||
@ -143,7 +145,6 @@ CPP_SOURCES += [
|
||||
'jsarray.cpp',
|
||||
'jsatom.cpp',
|
||||
'jsbool.cpp',
|
||||
'jsclone.cpp',
|
||||
'jscntxt.cpp',
|
||||
'jscompartment.cpp',
|
||||
'jscrashreport.cpp',
|
||||
|
@ -62,6 +62,7 @@
|
||||
#include "frontend/BytecodeEmitter.h"
|
||||
#include "frontend/Parser.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "perf/jsperf.h"
|
||||
#include "shell/jsheaptools.h"
|
||||
#include "shell/jsoptparse.h"
|
||||
|
@ -27,11 +27,13 @@
|
||||
* array object.
|
||||
*/
|
||||
|
||||
#include "jsclone.h"
|
||||
#include "js/StructuredClone.h"
|
||||
|
||||
#include "mozilla/Endian.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsdate.h"
|
||||
#include "jswrapper.h"
|
||||
|
||||
@ -86,6 +88,181 @@ enum TransferableMapHeader {
|
||||
SCTAG_TM_MARKED
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
||||
struct SCOutput {
|
||||
public:
|
||||
explicit SCOutput(JSContext *cx);
|
||||
|
||||
JSContext *context() const { return cx; }
|
||||
|
||||
bool write(uint64_t u);
|
||||
bool writePair(uint32_t tag, uint32_t data);
|
||||
bool writeDouble(double d);
|
||||
bool writeBytes(const void *p, size_t nbytes);
|
||||
bool writeChars(const jschar *p, size_t nchars);
|
||||
bool writePtr(const void *);
|
||||
|
||||
template <class T>
|
||||
bool writeArray(const T *p, size_t nbytes);
|
||||
|
||||
bool extractBuffer(uint64_t **datap, size_t *sizep);
|
||||
|
||||
uint64_t count() { return buf.length(); }
|
||||
|
||||
private:
|
||||
JSContext *cx;
|
||||
js::Vector<uint64_t> buf;
|
||||
};
|
||||
|
||||
struct SCInput {
|
||||
public:
|
||||
SCInput(JSContext *cx, uint64_t *data, size_t nbytes);
|
||||
|
||||
JSContext *context() const { return cx; }
|
||||
|
||||
bool read(uint64_t *p);
|
||||
bool readPair(uint32_t *tagp, uint32_t *datap);
|
||||
bool readDouble(double *p);
|
||||
bool readBytes(void *p, size_t nbytes);
|
||||
bool readChars(jschar *p, size_t nchars);
|
||||
bool readPtr(void **);
|
||||
|
||||
bool get(uint64_t *p);
|
||||
bool getPair(uint32_t *tagp, uint32_t *datap);
|
||||
|
||||
bool replace(uint64_t u);
|
||||
bool replacePair(uint32_t tag, uint32_t data);
|
||||
|
||||
template <class T>
|
||||
bool readArray(T *p, size_t nelems);
|
||||
|
||||
private:
|
||||
bool eof();
|
||||
|
||||
void staticAssertions() {
|
||||
JS_STATIC_ASSERT(sizeof(jschar) == 2);
|
||||
JS_STATIC_ASSERT(sizeof(uint32_t) == 4);
|
||||
JS_STATIC_ASSERT(sizeof(double) == 8);
|
||||
}
|
||||
|
||||
JSContext *cx;
|
||||
uint64_t *point;
|
||||
uint64_t *end;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
struct JSStructuredCloneReader {
|
||||
public:
|
||||
explicit JSStructuredCloneReader(js::SCInput &in, const JSStructuredCloneCallbacks *cb,
|
||||
void *cbClosure)
|
||||
: in(in), objs(in.context()), allObjs(in.context()),
|
||||
callbacks(cb), closure(cbClosure) { }
|
||||
|
||||
js::SCInput &input() { return in; }
|
||||
bool read(js::Value *vp);
|
||||
|
||||
private:
|
||||
JSContext *context() { return in.context(); }
|
||||
|
||||
bool readTransferMap();
|
||||
|
||||
bool checkDouble(double d);
|
||||
JSString *readString(uint32_t nchars);
|
||||
bool readTypedArray(uint32_t arrayType, uint32_t nelems, js::Value *vp, bool v1Read = false);
|
||||
bool readArrayBuffer(uint32_t nbytes, js::Value *vp);
|
||||
bool readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems, js::Value *vp);
|
||||
bool readId(jsid *idp);
|
||||
bool startRead(js::Value *vp);
|
||||
|
||||
js::SCInput ∈
|
||||
|
||||
// Stack of objects with properties remaining to be read.
|
||||
js::AutoValueVector objs;
|
||||
|
||||
// Stack of all objects read during this deserialization
|
||||
js::AutoValueVector allObjs;
|
||||
|
||||
// The user defined callbacks that will be used for cloning.
|
||||
const JSStructuredCloneCallbacks *callbacks;
|
||||
|
||||
// Any value passed to JS_ReadStructuredClone.
|
||||
void *closure;
|
||||
|
||||
friend bool JS_ReadTypedArray(JSStructuredCloneReader *r, JS::Value *vp);
|
||||
};
|
||||
|
||||
struct JSStructuredCloneWriter {
|
||||
public:
|
||||
explicit JSStructuredCloneWriter(js::SCOutput &out,
|
||||
const JSStructuredCloneCallbacks *cb,
|
||||
void *cbClosure,
|
||||
jsval tVal)
|
||||
: out(out), objs(out.context()),
|
||||
counts(out.context()), ids(out.context()),
|
||||
memory(out.context()), callbacks(cb), closure(cbClosure),
|
||||
transferable(out.context(), tVal), transferableObjects(out.context()) { }
|
||||
|
||||
bool init() { return transferableObjects.init() && parseTransferable() &&
|
||||
memory.init() && writeTransferMap(); }
|
||||
|
||||
bool write(const js::Value &v);
|
||||
|
||||
js::SCOutput &output() { return out; }
|
||||
|
||||
private:
|
||||
JSContext *context() { return out.context(); }
|
||||
|
||||
bool writeTransferMap();
|
||||
|
||||
bool writeString(uint32_t tag, JSString *str);
|
||||
bool writeId(jsid id);
|
||||
bool writeArrayBuffer(JS::HandleObject obj);
|
||||
bool writeTypedArray(JS::HandleObject obj);
|
||||
bool startObject(JS::HandleObject obj, bool *backref);
|
||||
bool startWrite(const js::Value &v);
|
||||
bool traverseObject(JS::HandleObject obj);
|
||||
|
||||
bool parseTransferable();
|
||||
void reportErrorTransferable();
|
||||
|
||||
inline void checkStack();
|
||||
|
||||
js::SCOutput &out;
|
||||
|
||||
// Vector of objects with properties remaining to be written.
|
||||
//
|
||||
// NB: These can span multiple compartments, so the compartment must be
|
||||
// entered before any manipulation is performed.
|
||||
js::AutoValueVector objs;
|
||||
|
||||
// counts[i] is the number of properties of objs[i] remaining to be written.
|
||||
// counts.length() == objs.length() and sum(counts) == ids.length().
|
||||
js::Vector<size_t> counts;
|
||||
|
||||
// Ids of properties remaining to be written.
|
||||
js::AutoIdVector ids;
|
||||
|
||||
// The "memory" list described in the HTML5 internal structured cloning algorithm.
|
||||
// memory is a superset of objs; items are never removed from Memory
|
||||
// until a serialization operation is finished
|
||||
typedef js::AutoObjectUnsigned32HashMap CloneMemory;
|
||||
CloneMemory memory;
|
||||
|
||||
// The user defined callbacks that will be used for cloning.
|
||||
const JSStructuredCloneCallbacks *callbacks;
|
||||
|
||||
// Any value passed to JS_WriteStructuredClone.
|
||||
void *closure;
|
||||
|
||||
// List of transferable objects
|
||||
JS::RootedValue transferable;
|
||||
js::AutoObjectHashSet transferableObjects;
|
||||
|
||||
friend bool JS_WriteTypedArray(JSStructuredCloneWriter *w, JS::Value v);
|
||||
};
|
||||
|
||||
JS_FRIEND_API(uint64_t)
|
||||
js_GetSCOffset(JSStructuredCloneWriter* writer)
|
||||
{
|
||||
@ -97,10 +274,12 @@ JS_STATIC_ASSERT(SCTAG_END_OF_BUILTIN_TYPES <= JS_SCTAG_USER_MIN);
|
||||
JS_STATIC_ASSERT(JS_SCTAG_USER_MIN <= JS_SCTAG_USER_MAX);
|
||||
JS_STATIC_ASSERT(TypedArrayObject::TYPE_INT8 == 0);
|
||||
|
||||
namespace js {
|
||||
|
||||
bool
|
||||
js::WriteStructuredClone(JSContext *cx, HandleValue v, uint64_t **bufp, size_t *nbytesp,
|
||||
const JSStructuredCloneCallbacks *cb, void *cbClosure,
|
||||
jsval transferable)
|
||||
WriteStructuredClone(JSContext *cx, HandleValue v, uint64_t **bufp, size_t *nbytesp,
|
||||
const JSStructuredCloneCallbacks *cb, void *cbClosure,
|
||||
jsval transferable)
|
||||
{
|
||||
SCOutput out(cx);
|
||||
JSStructuredCloneWriter w(out, cb, cbClosure, transferable);
|
||||
@ -108,8 +287,8 @@ js::WriteStructuredClone(JSContext *cx, HandleValue v, uint64_t **bufp, size_t *
|
||||
}
|
||||
|
||||
bool
|
||||
js::ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp,
|
||||
const JSStructuredCloneCallbacks *cb, void *cbClosure)
|
||||
ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp,
|
||||
const JSStructuredCloneCallbacks *cb, void *cbClosure)
|
||||
{
|
||||
SCInput in(cx, data, nbytes);
|
||||
|
||||
@ -121,7 +300,7 @@ js::ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp,
|
||||
}
|
||||
|
||||
bool
|
||||
js::ClearStructuredClone(const uint64_t *data, size_t nbytes)
|
||||
ClearStructuredClone(const uint64_t *data, size_t nbytes)
|
||||
{
|
||||
const uint64_t *point = data;
|
||||
const uint64_t *end = data + nbytes / 8;
|
||||
@ -152,7 +331,7 @@ js::ClearStructuredClone(const uint64_t *data, size_t nbytes)
|
||||
}
|
||||
|
||||
bool
|
||||
js::StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes, bool *hasTransferable)
|
||||
StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes, bool *hasTransferable)
|
||||
{
|
||||
*hasTransferable = false;
|
||||
|
||||
@ -167,6 +346,8 @@ js::StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes, bool
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
PairToUInt64(uint32_t tag, uint32_t data)
|
||||
{
|
||||
@ -561,24 +742,6 @@ JSStructuredCloneWriter::checkStack()
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v)
|
||||
{
|
||||
JS_ASSERT(v.isObject());
|
||||
assertSameCompartment(w->context(), v);
|
||||
RootedObject obj(w->context(), &v.toObject());
|
||||
|
||||
// If the object is a security wrapper, see if we're allowed to unwrap it.
|
||||
// If we aren't, throw.
|
||||
if (obj->is<WrapperObject>())
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj) {
|
||||
JS_ReportError(w->context(), "Permission denied to access object");
|
||||
return false;
|
||||
}
|
||||
return w->writeTypedArray(obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out a typed array. Note that post-v1 structured clone buffers do not
|
||||
* perform endianness conversion on stored data, so multibyte typed arrays
|
||||
@ -852,26 +1015,6 @@ TagToV1ArrayType(uint32_t tag)
|
||||
return tag - SCTAG_TYPED_ARRAY_V1_MIN;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadTypedArray(JSStructuredCloneReader *r, jsval *vp)
|
||||
{
|
||||
uint32_t tag, nelems;
|
||||
if (!r->input().readPair(&tag, &nelems))
|
||||
return false;
|
||||
if (tag >= SCTAG_TYPED_ARRAY_V1_MIN && tag <= SCTAG_TYPED_ARRAY_V1_MAX) {
|
||||
return r->readTypedArray(TagToV1ArrayType(tag), nelems, vp, true);
|
||||
} else if (tag == SCTAG_TYPED_ARRAY_OBJECT) {
|
||||
uint64_t arrayType;
|
||||
if (!r->input().read(&arrayType))
|
||||
return false;
|
||||
return r->readTypedArray(arrayType, nelems, vp);
|
||||
} else {
|
||||
JS_ReportErrorNumber(r->context(), js_GetErrorMessage, NULL,
|
||||
JSMSG_SC_BAD_SERIALIZED_DATA, "expected type array");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneReader::readTypedArray(uint32_t arrayType, uint32_t nelems, Value *vp,
|
||||
bool v1Read)
|
||||
@ -1280,3 +1423,257 @@ JSStructuredCloneReader::read(Value *vp)
|
||||
|
||||
return true;
|
||||
}
|
||||
using namespace js;
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadStructuredClone(JSContext *cx, uint64_t *buf, size_t nbytes,
|
||||
uint32_t version, JS::Value *vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
if (version > JS_STRUCTURED_CLONE_VERSION) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION);
|
||||
return false;
|
||||
}
|
||||
const JSStructuredCloneCallbacks *callbacks =
|
||||
optionalCallbacks ?
|
||||
optionalCallbacks :
|
||||
cx->runtime()->structuredCloneCallbacks;
|
||||
return ReadStructuredClone(cx, buf, nbytes, vp, callbacks, closure);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteStructuredClone(JSContext *cx, JS::Value valueArg, uint64_t **bufp, size_t *nbytesp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure, JS::Value transferable)
|
||||
{
|
||||
RootedValue value(cx, valueArg);
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, value);
|
||||
|
||||
const JSStructuredCloneCallbacks *callbacks =
|
||||
optionalCallbacks ?
|
||||
optionalCallbacks :
|
||||
cx->runtime()->structuredCloneCallbacks;
|
||||
return WriteStructuredClone(cx, value, bufp, nbytesp, callbacks, closure, transferable);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ClearStructuredClone(const uint64_t *data, size_t nbytes)
|
||||
{
|
||||
return ClearStructuredClone(data, nbytes);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes,
|
||||
bool *hasTransferable)
|
||||
{
|
||||
bool transferable;
|
||||
if (!StructuredCloneHasTransferObjects(data, nbytes, &transferable))
|
||||
return false;
|
||||
|
||||
*hasTransferable = transferable;
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredClone(JSContext *cx, JS::Value valueArg, JS::Value *vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure)
|
||||
{
|
||||
RootedValue value(cx, valueArg);
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, value);
|
||||
|
||||
const JSStructuredCloneCallbacks *callbacks =
|
||||
optionalCallbacks ?
|
||||
optionalCallbacks :
|
||||
cx->runtime()->structuredCloneCallbacks;
|
||||
JSAutoStructuredCloneBuffer buf;
|
||||
return buf.write(cx, value, callbacks, closure) &&
|
||||
buf.read(cx, vp, callbacks, closure);
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::clear()
|
||||
{
|
||||
if (data_) {
|
||||
ClearStructuredClone(data_, nbytes_);
|
||||
data_ = NULL;
|
||||
nbytes_ = 0;
|
||||
version_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JSAutoStructuredCloneBuffer::copy(const uint64_t *srcData, size_t nbytes, uint32_t version)
|
||||
{
|
||||
// transferable objects cannot be copied
|
||||
bool hasTransferable;
|
||||
if (!StructuredCloneHasTransferObjects(data_, nbytes_, &hasTransferable) ||
|
||||
hasTransferable)
|
||||
return false;
|
||||
|
||||
uint64_t *newData = static_cast<uint64_t *>(js_malloc(nbytes));
|
||||
if (!newData)
|
||||
return false;
|
||||
|
||||
js_memcpy(newData, srcData, nbytes);
|
||||
|
||||
clear();
|
||||
data_ = newData;
|
||||
nbytes_ = nbytes;
|
||||
version_ = version;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::adopt(uint64_t *data, size_t nbytes, uint32_t version)
|
||||
{
|
||||
clear();
|
||||
data_ = data;
|
||||
nbytes_ = nbytes;
|
||||
version_ = version;
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::steal(uint64_t **datap, size_t *nbytesp, uint32_t *versionp)
|
||||
{
|
||||
*datap = data_;
|
||||
*nbytesp = nbytes_;
|
||||
if (versionp)
|
||||
*versionp = version_;
|
||||
|
||||
data_ = NULL;
|
||||
nbytes_ = 0;
|
||||
version_ = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
JSAutoStructuredCloneBuffer::read(JSContext *cx, JS::Value *vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure)
|
||||
{
|
||||
JS_ASSERT(cx);
|
||||
JS_ASSERT(data_);
|
||||
return !!JS_ReadStructuredClone(cx, data_, nbytes_, version_, vp,
|
||||
optionalCallbacks, closure);
|
||||
}
|
||||
|
||||
bool
|
||||
JSAutoStructuredCloneBuffer::write(JSContext *cx, JS::Value valueArg,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure)
|
||||
{
|
||||
JS::Value transferable = JSVAL_VOID;
|
||||
return write(cx, valueArg, transferable, optionalCallbacks, closure);
|
||||
}
|
||||
|
||||
bool
|
||||
JSAutoStructuredCloneBuffer::write(JSContext *cx, JS::Value valueArg,
|
||||
JS::Value transferable,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks,
|
||||
void *closure)
|
||||
{
|
||||
RootedValue value(cx, valueArg);
|
||||
clear();
|
||||
bool ok = !!JS_WriteStructuredClone(cx, value, &data_, &nbytes_,
|
||||
optionalCallbacks, closure,
|
||||
transferable);
|
||||
if (!ok) {
|
||||
data_ = NULL;
|
||||
nbytes_ = 0;
|
||||
version_ = JS_STRUCTURED_CLONE_VERSION;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::swap(JSAutoStructuredCloneBuffer &other)
|
||||
{
|
||||
uint64_t *data = other.data_;
|
||||
size_t nbytes = other.nbytes_;
|
||||
uint32_t version = other.version_;
|
||||
|
||||
other.data_ = this->data_;
|
||||
other.nbytes_ = this->nbytes_;
|
||||
other.version_ = this->version_;
|
||||
|
||||
this->data_ = data;
|
||||
this->nbytes_ = nbytes;
|
||||
this->version_ = version;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks)
|
||||
{
|
||||
rt->structuredCloneCallbacks = callbacks;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2)
|
||||
{
|
||||
return r->input().readPair((uint32_t *) p1, (uint32_t *) p2);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len)
|
||||
{
|
||||
return r->input().readBytes(p, len);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadTypedArray(JSStructuredCloneReader *r, JS::Value *vp)
|
||||
{
|
||||
uint32_t tag, nelems;
|
||||
if (!r->input().readPair(&tag, &nelems))
|
||||
return false;
|
||||
if (tag >= SCTAG_TYPED_ARRAY_V1_MIN && tag <= SCTAG_TYPED_ARRAY_V1_MAX) {
|
||||
return r->readTypedArray(TagToV1ArrayType(tag), nelems, vp, true);
|
||||
} else if (tag == SCTAG_TYPED_ARRAY_OBJECT) {
|
||||
uint64_t arrayType;
|
||||
if (!r->input().read(&arrayType))
|
||||
return false;
|
||||
return r->readTypedArray(arrayType, nelems, vp);
|
||||
} else {
|
||||
JS_ReportErrorNumber(r->context(), js_GetErrorMessage, NULL,
|
||||
JSMSG_SC_BAD_SERIALIZED_DATA, "expected type array");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data)
|
||||
{
|
||||
return w->output().writePair(tag, data);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len)
|
||||
{
|
||||
return w->output().writeBytes(p, len);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteTypedArray(JSStructuredCloneWriter *w, JS::Value v)
|
||||
{
|
||||
JS_ASSERT(v.isObject());
|
||||
assertSameCompartment(w->context(), v);
|
||||
RootedObject obj(w->context(), &v.toObject());
|
||||
|
||||
// If the object is a security wrapper, see if we're allowed to unwrap it.
|
||||
// If we aren't, throw.
|
||||
if (obj->is<WrapperObject>())
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj) {
|
||||
JS_ReportError(w->context(), "Permission denied to access object");
|
||||
return false;
|
||||
}
|
||||
return w->writeTypedArray(obj);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "jsdbgapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsproxy.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
|
Loading…
Reference in New Issue
Block a user