Backout changesets 7e6fb33fdf22:c85332df4320 (bug 905017) for windows bustage.

This commit is contained in:
Ms2ger 2013-08-22 10:16:30 +02:00
parent c8e2369441
commit f79ae70d10
31 changed files with 800 additions and 870 deletions

View File

@ -302,28 +302,6 @@ def module_name(name):
return name.replace('inlines.h', '').replace('-inl.h', '').replace('.h', '').replace('.cpp', '')
def is_module_header(enclosing_inclname, header_inclname):
'''Determine if an included name is the "module header", i.e. should be
first in the file.'''
module = module_name(enclosing_inclname)
# Normal case, e.g. module == "foo/Bar", header_inclname == "foo/Bar.h".
if module == module_name(header_inclname):
return True
# A public header, e.g. module == "foo/Bar", header_inclname == "js/Bar.h".
m = re.match(r'js\/(.*)\.h', header_inclname)
if m is not None and module.endswith('/' + m.group(1)):
return True
# A weird public header case.
if module == 'jsmemorymetrics' and header_inclname == 'js/MemoryMetrics.h':
return True
return False
class Include(object):
'''Important information for a single #include statement.'''
@ -335,7 +313,7 @@ class Include(object):
def isLeaf(self):
return True
def section(self, enclosing_inclname):
def section(self, module):
'''Identify which section inclname belongs to.
The section numbers are as follows.
@ -355,9 +333,11 @@ class Include(object):
if not self.inclname.endswith('.h'):
return 7
# A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need
# special handling.
if is_module_header(enclosing_inclname, self.inclname):
# A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need special
# 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':
return 0
if '/' in self.inclname:
@ -471,6 +451,8 @@ def do_file(filename, inclname, file_kind, f, all_inclnames, included_h_inclname
if inclname == include.inclname:
error(filename, include.linenum, 'the file includes itself')
module = module_name(inclname)
def check_includes_order(include1, include2):
'''Check the ordering of two #include statements.'''
@ -478,8 +460,8 @@ def do_file(filename, inclname, file_kind, f, all_inclnames, included_h_inclname
include2.inclname in oddly_ordered_inclnames:
return
section1 = include1.section(inclname)
section2 = include2.section(inclname)
section1 = include1.section(module)
section2 = include2.section(module)
if (section1 > section2) or \
((section1 == section2) and (include1.inclname.lower() > include2.inclname.lower())):
error(filename, str(include1.linenum) + ':' + str(include2.linenum),

View File

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

View File

@ -14,7 +14,6 @@
#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 "js/Value.h"
#include "jsapi.h"
class nsIDOMDOMRequest;

View File

@ -10,7 +10,7 @@
#include "nsIProgrammingLanguage.h"
#include "mozilla/Attributes.h"
#include "js/StructuredClone.h"
#include "jsapi.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"

View File

@ -11,8 +11,6 @@
#include "mozIStorageStatement.h"
#include "js/Value.h"
namespace IPC {
template <typename T> struct ParamTraits;
} // namespace IPC
@ -161,7 +159,7 @@ public:
}
nsresult SetFromJSVal(JSContext* aCx,
const JS::Value aVal)
const jsval aVal)
{
mBuffer.Truncate();
@ -211,7 +209,7 @@ public:
nsresult AppendItem(JSContext* aCx,
bool aFirstOfArray,
const JS::Value aVal)
const jsval aVal)
{
nsresult rv = EncodeJSVal(aCx, aVal, aFirstOfArray ? eMaxType : 0);
if (NS_FAILED(rv)) {
@ -305,7 +303,7 @@ private:
}
// Encoding functions. These append the encoded value to the end of mBuffer
inline nsresult EncodeJSVal(JSContext* aCx, const JS::Value aVal,
inline nsresult EncodeJSVal(JSContext* aCx, const jsval aVal,
uint8_t aTypeOffset)
{
return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0);
@ -331,7 +329,7 @@ private:
nsCString mBuffer;
private:
nsresult EncodeJSValInternal(JSContext* aCx, const JS::Value aVal,
nsresult EncodeJSValInternal(JSContext* aCx, const jsval aVal,
uint8_t aTypeOffset, uint16_t aRecursionDepth);
static nsresult DecodeJSValInternal(const unsigned char*& aPos,

View File

@ -15,7 +15,6 @@
#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 "js/StructuredClone.h"
#include "jsapi.h"
namespace mozilla {

View File

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

View File

@ -15,8 +15,6 @@
#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 "js/StructuredClone.h"
#include "jsapi.h"
#include "nsCSSProperty.h"
#ifdef _MSC_VER

View File

@ -10,7 +10,6 @@
#include "JavaScriptShared.h"
#include "mozilla/jsipc/PJavaScriptParent.h"
#include "jsclass.h"
#ifdef XP_WIN
#undef GetClassName

View File

@ -1,94 +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 js_ProfilingStack_h
#define js_ProfilingStack_h
#include "jsbytecode.h"
#include "jstypes.h"
#include "js/Utility.h"
struct JSRuntime;
class JSScript;
namespace js {
// A call stack can be specified to the JS engine such that all JS entry/exits
// to functions push/pop an entry to/from the specified stack.
//
// For more detailed information, see vm/SPSProfiler.h.
//
class ProfileEntry
{
// All fields are marked volatile to prevent the compiler from re-ordering
// instructions. Namely this sequence:
//
// entry[size] = ...;
// size++;
//
// If the size modification were somehow reordered before the stores, then
// if a sample were taken it would be examining bogus information.
//
// A ProfileEntry represents both a C++ profile entry and a JS one. Both use
// the string as a description, but JS uses the sp as NULL to indicate that
// it is a JS entry. The script_ is then only ever examined for a JS entry,
// and the idx is used by both, but with different meanings.
//
const char * volatile string; // Descriptive string of this entry
void * volatile sp; // Relevant stack pointer for the entry
JSScript * volatile script_; // if js(), non-null script which is running
int32_t volatile idx; // if js(), idx of pc, otherwise line number
public:
// All of these methods are marked with the 'volatile' keyword because SPS's
// representation of the stack is stored such that all ProfileEntry
// instances are volatile. These methods would not be available unless they
// were marked as volatile as well.
bool js() volatile {
JS_ASSERT_IF(sp == NULL, script_ != NULL);
return sp == NULL;
}
uint32_t line() volatile { JS_ASSERT(!js()); return idx; }
JSScript *script() volatile { JS_ASSERT(js()); return script_; }
void *stackAddress() volatile { return sp; }
const char *label() volatile { return string; }
void setLine(uint32_t aLine) volatile { JS_ASSERT(!js()); idx = aLine; }
void setLabel(const char *aString) volatile { string = aString; }
void setStackAddress(void *aSp) volatile { sp = aSp; }
void setScript(JSScript *aScript) volatile { script_ = aScript; }
// We can't know the layout of JSScript, so look in vm/SPSProfiler.cpp.
JS_FRIEND_API(jsbytecode *) pc() volatile;
JS_FRIEND_API(void) setPC(jsbytecode *pc) volatile;
static size_t offsetOfString() { return offsetof(ProfileEntry, string); }
static size_t offsetOfStackAddress() { return offsetof(ProfileEntry, sp); }
static size_t offsetOfPCIdx() { return offsetof(ProfileEntry, idx); }
static size_t offsetOfScript() { return offsetof(ProfileEntry, script_); }
// The index used in the entry can either be a line number or the offset of
// a pc into a script's code. To signify a NULL pc, use a -1 index. This is
// checked against in pc() and setPC() to set/get the right pc.
static const int32_t NullPCIndex = -1;
};
JS_FRIEND_API(void)
SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size,
uint32_t max);
JS_FRIEND_API(void)
EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled);
JS_FRIEND_API(jsbytecode*)
ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip);
} // namespace js
#endif /* js_ProfilingStack_h */

View File

@ -1,162 +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 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,24 +1896,6 @@ 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;
namespace JS {
extern JS_PUBLIC_DATA(const Handle<Value>) NullHandleValue;
extern JS_PUBLIC_DATA(const Handle<Value>) UndefinedHandleValue;
}
#undef JS_VALUE_IS_CONSTEXPR
#undef JS_RETURN_LAYOUT_FROM_BITS

View File

@ -302,28 +302,6 @@ def module_name(name):
return name.replace('inlines.h', '').replace('-inl.h', '').replace('.h', '').replace('.cpp', '')
def is_module_header(enclosing_inclname, header_inclname):
'''Determine if an included name is the "module header", i.e. should be
first in the file.'''
module = module_name(enclosing_inclname)
# Normal case, e.g. module == "foo/Bar", header_inclname == "foo/Bar.h".
if module == module_name(header_inclname):
return True
# A public header, e.g. module == "foo/Bar", header_inclname == "js/Bar.h".
m = re.match(r'js\/(.*)\.h', header_inclname)
if m is not None and module.endswith('/' + m.group(1)):
return True
# A weird public header case.
if module == 'jsmemorymetrics' and header_inclname == 'js/MemoryMetrics.h':
return True
return False
class Include(object):
'''Important information for a single #include statement.'''
@ -335,7 +313,7 @@ class Include(object):
def isLeaf(self):
return True
def section(self, enclosing_inclname):
def section(self, module):
'''Identify which section inclname belongs to.
The section numbers are as follows.
@ -355,9 +333,11 @@ class Include(object):
if not self.inclname.endswith('.h'):
return 7
# A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need
# special handling.
if is_module_header(enclosing_inclname, self.inclname):
# A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need special
# 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':
return 0
if '/' in self.inclname:
@ -471,6 +451,8 @@ def do_file(filename, inclname, file_kind, f, all_inclnames, included_h_inclname
if inclname == include.inclname:
error(filename, include.linenum, 'the file includes itself')
module = module_name(inclname)
def check_includes_order(include1, include2):
'''Check the ordering of two #include statements.'''
@ -478,8 +460,8 @@ def do_file(filename, inclname, file_kind, f, all_inclnames, included_h_inclname
include2.inclname in oddly_ordered_inclnames:
return
section1 = include1.section(inclname)
section2 = include2.section(inclname)
section1 = include1.section(module)
section2 = include2.section(module)
if (section1 > section2) or \
((section1 == section2) and (include1.inclname.lower() > include2.inclname.lower())):
error(filename, str(include1.linenum) + ':' + str(include2.linenum),

View File

@ -21,6 +21,7 @@
#include "jsarray.h"
#include "jsatom.h"
#include "jsbool.h"
#include "jsclone.h"
#include "jscntxt.h"
#include "jsdate.h"
#include "jsexn.h"
@ -59,7 +60,6 @@
#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"
@ -128,6 +128,17 @@ const jsid JSID_VOID = { size_t(JSID_TYPE_VOID) };
const jsid JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) };
#endif
const jsval JSVAL_NULL = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0));
const jsval JSVAL_ZERO = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32, 0));
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 jsid voidIdValue = JSID_VOID;
const jsid emptyIdValue = JSID_EMPTY;
const HandleId JS::JSID_VOIDHANDLE = HandleId::fromMarkedLocation(&voidIdValue);
@ -174,22 +185,18 @@ JS_GetEmptyString(JSRuntime *rt)
return rt->emptyString;
}
namespace js {
void
static void
AssertHeapIsIdle(JSRuntime *rt)
{
JS_ASSERT(rt->heapState == js::Idle);
}
void
static void
AssertHeapIsIdle(JSContext *cx)
{
AssertHeapIsIdle(cx->runtime());
}
}
static void
AssertHeapIsIdleOrIterating(JSRuntime *rt)
{
@ -5918,6 +5925,220 @@ 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,8 +1147,54 @@ 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)
{
@ -1830,12 +1876,6 @@ template <> struct GCMethods<jsid>
#endif
};
void
AssertHeapIsIdle(JSRuntime *rt);
void
AssertHeapIsIdle(JSContext *cx);
} /* namespace js */
class JSAutoRequest
@ -4669,6 +4709,134 @@ 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).
@ -5087,6 +5255,9 @@ JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length,
namespace JS {
extern JS_PUBLIC_DATA(const Handle<Value>) NullHandleValue;
extern JS_PUBLIC_DATA(const Handle<Value>) UndefinedHandleValue;
extern JS_PUBLIC_DATA(const Handle<jsid>) JSID_VOIDHANDLE;
extern JS_PUBLIC_DATA(const Handle<jsid>) JSID_EMPTYHANDLE;

View File

@ -27,13 +27,11 @@
* array object.
*/
#include "js/StructuredClone.h"
#include "jsclone.h"
#include "mozilla/Endian.h"
#include "mozilla/FloatingPoint.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jsdate.h"
#include "jswrapper.h"
@ -88,181 +86,6 @@ 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)
{
@ -274,12 +97,10 @@ 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
WriteStructuredClone(JSContext *cx, HandleValue v, uint64_t **bufp, size_t *nbytesp,
const JSStructuredCloneCallbacks *cb, void *cbClosure,
jsval transferable)
js::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);
@ -287,8 +108,8 @@ WriteStructuredClone(JSContext *cx, HandleValue v, uint64_t **bufp, size_t *nbyt
}
bool
ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp,
const JSStructuredCloneCallbacks *cb, void *cbClosure)
js::ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp,
const JSStructuredCloneCallbacks *cb, void *cbClosure)
{
SCInput in(cx, data, nbytes);
@ -300,7 +121,7 @@ ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp,
}
bool
ClearStructuredClone(const uint64_t *data, size_t nbytes)
js::ClearStructuredClone(const uint64_t *data, size_t nbytes)
{
const uint64_t *point = data;
const uint64_t *end = data + nbytes / 8;
@ -331,7 +152,7 @@ ClearStructuredClone(const uint64_t *data, size_t nbytes)
}
bool
StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes, bool *hasTransferable)
js::StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes, bool *hasTransferable)
{
*hasTransferable = false;
@ -346,8 +167,6 @@ StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes, bool *has
return true;
}
}
static inline uint64_t
PairToUInt64(uint32_t tag, uint32_t data)
{
@ -742,6 +561,24 @@ 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
@ -1015,6 +852,26 @@ 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)
@ -1423,257 +1280,3 @@ 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);
}

206
js/src/jsclone.h Normal file
View File

@ -0,0 +1,206 @@
/* -*- 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

@ -991,6 +991,24 @@ js::GetEnterCompartmentDepth(JSContext *cx)
}
#endif
JS_FRIEND_API(void)
js::SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size, uint32_t max)
{
rt->spsProfiler.setProfilingStack(stack, size, max);
}
JS_FRIEND_API(void)
js::EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled)
{
rt->spsProfiler.enable(enabled);
}
JS_FRIEND_API(jsbytecode*)
js::ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip)
{
return rt->spsProfiler.ipToPC(script, size_t(ip));
}
JS_FRIEND_API(void)
js::SetDOMCallbacks(JSRuntime *rt, const DOMCallbacks *callbacks)
{

View File

@ -669,6 +669,84 @@ GetPCCountScriptSummary(JSContext *cx, size_t script);
JS_FRIEND_API(JSString *)
GetPCCountScriptContents(JSContext *cx, size_t script);
/*
* A call stack can be specified to the JS engine such that all JS entry/exits
* to functions push/pop an entry to/from the specified stack.
*
* For more detailed information, see vm/SPSProfiler.h
*/
class ProfileEntry
{
/*
* All fields are marked volatile to prevent the compiler from re-ordering
* instructions. Namely this sequence:
*
* entry[size] = ...;
* size++;
*
* If the size modification were somehow reordered before the stores, then
* if a sample were taken it would be examining bogus information.
*
* A ProfileEntry represents both a C++ profile entry and a JS one. Both use
* the string as a description, but JS uses the sp as NULL to indicate that
* it is a JS entry. The script_ is then only ever examined for a JS entry,
* and the idx is used by both, but with different meanings.
*/
const char * volatile string; // Descriptive string of this entry
void * volatile sp; // Relevant stack pointer for the entry
JSScript * volatile script_; // if js(), non-null script which is running
int32_t volatile idx; // if js(), idx of pc, otherwise line number
public:
/*
* All of these methods are marked with the 'volatile' keyword because SPS's
* representation of the stack is stored such that all ProfileEntry
* instances are volatile. These methods would not be available unless they
* were marked as volatile as well
*/
bool js() volatile {
JS_ASSERT_IF(sp == NULL, script_ != NULL);
return sp == NULL;
}
uint32_t line() volatile { JS_ASSERT(!js()); return idx; }
JSScript *script() volatile { JS_ASSERT(js()); return script_; }
void *stackAddress() volatile { return sp; }
const char *label() volatile { return string; }
void setLine(uint32_t aLine) volatile { JS_ASSERT(!js()); idx = aLine; }
void setLabel(const char *aString) volatile { string = aString; }
void setStackAddress(void *aSp) volatile { sp = aSp; }
void setScript(JSScript *aScript) volatile { script_ = aScript; }
/* we can't know the layout of JSScript, so look in vm/SPSProfiler.cpp */
JS_FRIEND_API(jsbytecode *) pc() volatile;
JS_FRIEND_API(void) setPC(jsbytecode *pc) volatile;
static size_t offsetOfString() { return offsetof(ProfileEntry, string); }
static size_t offsetOfStackAddress() { return offsetof(ProfileEntry, sp); }
static size_t offsetOfPCIdx() { return offsetof(ProfileEntry, idx); }
static size_t offsetOfScript() { return offsetof(ProfileEntry, script_); }
/*
* The index used in the entry can either be a line number or the offset of
* a pc into a script's code. To signify a NULL pc, use a -1 index. This is
* checked against in pc() and setPC() to set/get the right pc.
*/
static const int32_t NullPCIndex = -1;
};
JS_FRIEND_API(void)
SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size,
uint32_t max);
JS_FRIEND_API(void)
EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled);
JS_FRIEND_API(jsbytecode*)
ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip);
#ifdef JS_THREADSAFE
JS_FRIEND_API(bool)
ContextHasOutstandingRequests(const JSContext *cx);

View File

@ -68,11 +68,9 @@ EXPORTS.js += [
'../public/HeapAPI.h',
'../public/LegacyIntTypes.h',
'../public/MemoryMetrics.h',
'../public/ProfilingStack.h',
'../public/PropertyKey.h',
'../public/RequiredDefines.h',
'../public/RootingAPI.h',
'../public/StructuredClone.h',
'../public/Utility.h',
'../public/Value.h',
'../public/Vector.h',
@ -127,13 +125,11 @@ CPP_SOURCES += [
'StoreBuffer.cpp',
'String.cpp',
'StringBuffer.cpp',
'StructuredClone.cpp',
'TestingFunctions.cpp',
'ThreadPool.cpp',
'TokenStream.cpp',
'TypedArrayObject.cpp',
'Unicode.cpp',
'Value.cpp',
'Verifier.cpp',
'Xdr.cpp',
'YarrCanonicalizeUCS2.cpp',
@ -147,6 +143,7 @@ CPP_SOURCES += [
'jsarray.cpp',
'jsatom.cpp',
'jsbool.cpp',
'jsclone.cpp',
'jscntxt.cpp',
'jscompartment.cpp',
'jscrashreport.cpp',

View File

@ -62,7 +62,6 @@
#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

@ -4,11 +4,11 @@
* 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/. */
#include "js/CharacterEncoding.h"
#include "jscntxt.h"
#include "jsprf.h"
#include "js/CharacterEncoding.h"
using namespace JS;
Latin1CharsZ

View File

@ -265,33 +265,14 @@ SPSEntryMarker::~SPSEntryMarker()
}
JS_FRIEND_API(jsbytecode*)
ProfileEntry::pc() volatile
{
ProfileEntry::pc() volatile {
JS_ASSERT_IF(idx != NullPCIndex, idx >= 0 && uint32_t(idx) < script()->length);
return idx == NullPCIndex ? NULL : script()->code + idx;
}
JS_FRIEND_API(void)
ProfileEntry::setPC(jsbytecode *pc) volatile
{
JS_ASSERT_IF(pc != NULL, script()->code <= pc && pc < script()->code + script()->length);
ProfileEntry::setPC(jsbytecode *pc) volatile {
JS_ASSERT_IF(pc != NULL, script()->code <= pc &&
pc < script()->code + script()->length);
idx = pc == NULL ? NullPCIndex : pc - script()->code;
}
JS_FRIEND_API(void)
js::SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size, uint32_t max)
{
rt->spsProfiler.setProfilingStack(stack, size, max);
}
JS_FRIEND_API(void)
js::EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled)
{
rt->spsProfiler.enable(enabled);
}
JS_FRIEND_API(jsbytecode*)
js::ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip)
{
return rt->spsProfiler.ipToPC(script, size_t(ip));
}

View File

@ -14,8 +14,6 @@
#include "jsscript.h"
#include "js/ProfilingStack.h"
/*
* SPS Profiler integration with the JS Engine
* https://developer.mozilla.org/en/Performance/Profiling_with_the_Built-in_Profiler

View File

@ -1,21 +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/. */
#include "js/Value.h"
const jsval JSVAL_NULL = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0));
const jsval JSVAL_ZERO = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32, 0));
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));
namespace JS {
const HandleValue NullHandleValue = HandleValue::fromMarkedLocation(&JSVAL_NULL);
const HandleValue UndefinedHandleValue = HandleValue::fromMarkedLocation(&JSVAL_VOID);
} // namespace JS

View File

@ -7,10 +7,9 @@
#define __NSAUTOJSVALHOLDER_H__
#include "nsDebug.h"
#include "jsapi.h"
/**
* Simple class that looks and acts like a JS::Value except that it unroots
* Simple class that looks and acts like a jsval except that it unroots
* itself automatically if Root() is ever called. Designed to be rooted on the
* context or runtime (but not both!).
*/
@ -45,7 +44,7 @@ public:
else {
this->Release();
}
*this = static_cast<JS::Value>(aOther);
*this = static_cast<jsval>(aOther);
}
return *this;
}
@ -77,10 +76,10 @@ public:
/**
* Manually release, nullifying mVal, and mRt, but returning
* the original JS::Value.
* the original jsval.
*/
JS::Value Release() {
JS::Value oldval = mVal;
jsval Release() {
jsval oldval = mVal;
if (mRt) {
JS_RemoveValueRootRT(mRt, &mVal); // infallible
@ -108,20 +107,20 @@ public:
: nullptr;
}
JS::Value* ToJSValPtr() {
jsval* ToJSValPtr() {
return &mVal;
}
/**
* Pretend to be a JS::Value.
* Pretend to be a jsval.
*/
operator JS::Value() const { return mVal; }
operator jsval() const { return mVal; }
nsAutoJSValHolder &operator=(JSObject* aOther) {
return *this = OBJECT_TO_JSVAL(aOther);
}
nsAutoJSValHolder &operator=(JS::Value aOther) {
nsAutoJSValHolder &operator=(jsval aOther) {
#ifdef DEBUG
if (JSVAL_IS_GCTHING(aOther) && !JSVAL_IS_NULL(aOther)) {
MOZ_ASSERT(IsHeld(), "Not rooted!");
@ -132,7 +131,7 @@ public:
}
private:
JS::Value mVal;
jsval mVal;
JSRuntime* mRt;
};

View File

@ -7,7 +7,6 @@
#include "nsNSSComponent.h"
#include "nsNSSIOLayer.h"
#include "mozilla/Casting.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Telemetry.h"

View File

@ -8,7 +8,7 @@
#include "mozilla/NullPtr.h"
#include <stdint.h>
#include "js/ProfilingStack.h"
#include "jsfriendapi.h"
#include <stdlib.h>
#include <algorithm>