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:
Nicholas Nethercote 2013-08-19 23:43:47 -07:00
parent db501ffdf0
commit 9ce6c39a8f
21 changed files with 656 additions and 659 deletions

View File

@ -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:

View File

@ -5,6 +5,8 @@
#ifndef StructuredCloneTags_h__
#define StructuredCloneTags_h__
#include "js/StructuredClone.h"
namespace mozilla {
namespace dom {

View File

@ -14,6 +14,7 @@
#include "nsServiceManagerUtils.h"
#include "nsContentUtils.h"
#include "jsapi.h"
#include "js/StructuredClone.h"
#include "mozilla/Base64.h"

View File

@ -10,7 +10,7 @@
#include "mozilla/Attributes.h"
#include "BluetoothCommon.h"
#include "nsThreadUtils.h"
#include "jsapi.h"
#include "js/Value.h"
class nsIDOMDOMRequest;

View File

@ -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"

View File

@ -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,

View File

@ -15,6 +15,7 @@
#include "nsJSEnvironment.h"
#include "nsThreadUtils.h"
#include "StructuredCloneTags.h"
#include "jsapi.h"
using namespace mozilla::dom;

View File

@ -11,7 +11,7 @@
#include "nsTArray.h"
#include "nsIDOMFile.h"
#include "jsapi.h"
#include "js/StructuredClone.h"
namespace mozilla {

View File

@ -8,7 +8,7 @@
#include "Workers.h"
class JSAutoStructuredCloneBuffer;
#include "js/StructuredClone.h"
BEGIN_WORKERS_NAMESPACE

View File

@ -15,6 +15,8 @@
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/TypedArray.h"
#include "js/StructuredClone.h"
BEGIN_WORKERS_NAMESPACE
class Proxy;

View File

@ -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
View 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 */

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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).

View File

@ -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 &in;
// 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 */

View File

@ -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',

View File

@ -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"

View File

@ -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 &in;
// 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);
}

View File

@ -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"