[SCM] WebKit Debian packaging branch, debian/unstable, updated. debian/1.1.18-1-697-g2f78b87
eric at webkit.org
eric at webkit.org
Wed Jan 20 22:26:07 UTC 2010
The following commit has been merged in the debian/unstable branch:
commit 5792212ec9bc73b2f48dc098561a0630dabe0e11
Author: eric at webkit.org <eric at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Fri Jan 15 21:28:47 2010 +0000
2010-01-15 Vitaly Repeshko <vitalyr at chromium.org>
Reviewed by David Levin.
[V8] Support SerializedScriptValue.
https://bugs.webkit.org/show_bug.cgi?id=32920
http://crbug.com/30620
Initial implementation of SerializedScriptValue which is used to
to create a serialized representation of JavaScript objects. This
representation is needed for structured clones and worker messages.
* WebCore.gypi: Added SerializedScriptValue.cpp.
* bindings/scripts/CodeGeneratorV8.pm: Removed conversion to string before using SerializedScriptValue.
* bindings/v8/SerializedScriptValue.cpp: Added.
(WebCore::):
(WebCore::ZigZag::encode):
(WebCore::ZigZag::decode):
(WebCore::Writer::Writer):
(WebCore::Writer::writeUndefined):
(WebCore::Writer::writeNull):
(WebCore::Writer::writeTrue):
(WebCore::Writer::writeFalse):
(WebCore::Writer::writeString):
(WebCore::Writer::writeInt32):
(WebCore::Writer::writeNumber):
(WebCore::Writer::endComposite):
(WebCore::Writer::data):
(WebCore::Writer::doWriteUint32):
(WebCore::Writer::append):
(WebCore::Writer::ensureSpace):
(WebCore::Writer::fillHole):
(WebCore::Writer::charAt):
(WebCore::Serializer::Serializer):
(WebCore::Serializer::serialize):
(WebCore::Serializer::StateBase::~StateBase):
(WebCore::Serializer::StateBase::nextState):
(WebCore::Serializer::StateBase::setNextState):
(WebCore::Serializer::StateBase::composite):
(WebCore::Serializer::StateBase::StateBase):
(WebCore::Serializer::State::composite):
(WebCore::Serializer::State::tag):
(WebCore::Serializer::State::State):
(WebCore::Serializer::StackCleaner::StackCleaner):
(WebCore::Serializer::StackCleaner::~StackCleaner):
(WebCore::Serializer::ArrayState::ArrayState):
(WebCore::Serializer::ArrayState::done):
(WebCore::Serializer::ArrayState::advance):
(WebCore::Serializer::ObjectState::ObjectState):
(WebCore::Serializer::ObjectState::done):
(WebCore::Serializer::ObjectState::advance):
(WebCore::Serializer::ObjectState::nextProperty):
(WebCore::Serializer::doSerialize):
(WebCore::Serializer::push):
(WebCore::Serializer::top):
(WebCore::Serializer::pop):
(WebCore::Serializer::checkComposite):
(WebCore::Reader::Reader):
(WebCore::Reader::isEof):
(WebCore::Reader::read):
(WebCore::Reader::readTag):
(WebCore::Reader::readString):
(WebCore::Reader::readInt32):
(WebCore::Reader::readNumber):
(WebCore::Reader::doReadUint32):
(WebCore::Deserializer::Deserializer):
(WebCore::Deserializer::deserialize):
(WebCore::Deserializer::doDeserialize):
(WebCore::Deserializer::push):
(WebCore::Deserializer::pop):
(WebCore::Deserializer::stackDepth):
(WebCore::Deserializer::element):
(WebCore::SerializedScriptValue::SerializedScriptValue):
(WebCore::SerializedScriptValue::deserialize):
* bindings/v8/SerializedScriptValue.h:
(WebCore::SerializedScriptValue::create):
(WebCore::SerializedScriptValue::createFromWire):
(WebCore::SerializedScriptValue::release):
(WebCore::SerializedScriptValue::toWireString):
Updated uses of SerializedScriptValue:
* bindings/v8/custom/V8DOMWindowCustom.cpp:
(WebCore::V8DOMWindow::postMessageCallback):
* bindings/v8/custom/V8DedicatedWorkerContextCustom.cpp:
(WebCore::V8DedicatedWorkerContext::postMessageCallback):
* bindings/v8/custom/V8HistoryCustom.cpp:
(WebCore::V8History::pushStateCallback):
(WebCore::V8History::replaceStateCallback):
* bindings/v8/custom/V8MessageEventCustom.cpp:
(WebCore::V8MessageEvent::initMessageEventCallback):
* bindings/v8/custom/V8MessagePortCustom.cpp:
(WebCore::V8MessagePort::postMessageCallback):
* bindings/v8/custom/V8WorkerCustom.cpp:
(WebCore::V8Worker::postMessageCallback):
2010-01-15 Vitaly Repeshko <vitalyr at chromium.org>
Reviewed by David Levin.
[V8] Support SerializedScriptValue.
https://bugs.webkit.org/show_bug.cgi?id=32920
http://crbug.com/30620
Updated uses of SerializedScriptValue:
* src/PlatformMessagePortChannel.cpp:
(WebCore::PlatformMessagePortChannel::postMessageToRemote):
(WebCore::PlatformMessagePortChannel::tryGetMessageFromRemote):
* src/WebWorkerBase.cpp:
(WebKit::WebWorkerBase::postMessageToWorkerObject):
* src/WebWorkerClientImpl.cpp:
(WebKit::WebWorkerClientImpl::postMessageToWorkerContext):
(WebKit::WebWorkerClientImpl::postMessageToWorkerObjectTask):
* src/WebWorkerImpl.cpp:
(WebKit::WebWorkerImpl::postMessageToWorkerContextTask):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@53344 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index eff6f0e..01bf65e 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,98 @@
+2010-01-15 Vitaly Repeshko <vitalyr at chromium.org>
+
+ Reviewed by David Levin.
+
+ [V8] Support SerializedScriptValue.
+ https://bugs.webkit.org/show_bug.cgi?id=32920
+ http://crbug.com/30620
+
+ Initial implementation of SerializedScriptValue which is used to
+ to create a serialized representation of JavaScript objects. This
+ representation is needed for structured clones and worker messages.
+
+ * WebCore.gypi: Added SerializedScriptValue.cpp.
+ * bindings/scripts/CodeGeneratorV8.pm: Removed conversion to string before using SerializedScriptValue.
+ * bindings/v8/SerializedScriptValue.cpp: Added.
+ (WebCore::):
+ (WebCore::ZigZag::encode):
+ (WebCore::ZigZag::decode):
+ (WebCore::Writer::Writer):
+ (WebCore::Writer::writeUndefined):
+ (WebCore::Writer::writeNull):
+ (WebCore::Writer::writeTrue):
+ (WebCore::Writer::writeFalse):
+ (WebCore::Writer::writeString):
+ (WebCore::Writer::writeInt32):
+ (WebCore::Writer::writeNumber):
+ (WebCore::Writer::endComposite):
+ (WebCore::Writer::data):
+ (WebCore::Writer::doWriteUint32):
+ (WebCore::Writer::append):
+ (WebCore::Writer::ensureSpace):
+ (WebCore::Writer::fillHole):
+ (WebCore::Writer::charAt):
+ (WebCore::Serializer::Serializer):
+ (WebCore::Serializer::serialize):
+ (WebCore::Serializer::StateBase::~StateBase):
+ (WebCore::Serializer::StateBase::nextState):
+ (WebCore::Serializer::StateBase::setNextState):
+ (WebCore::Serializer::StateBase::composite):
+ (WebCore::Serializer::StateBase::StateBase):
+ (WebCore::Serializer::State::composite):
+ (WebCore::Serializer::State::tag):
+ (WebCore::Serializer::State::State):
+ (WebCore::Serializer::StackCleaner::StackCleaner):
+ (WebCore::Serializer::StackCleaner::~StackCleaner):
+ (WebCore::Serializer::ArrayState::ArrayState):
+ (WebCore::Serializer::ArrayState::done):
+ (WebCore::Serializer::ArrayState::advance):
+ (WebCore::Serializer::ObjectState::ObjectState):
+ (WebCore::Serializer::ObjectState::done):
+ (WebCore::Serializer::ObjectState::advance):
+ (WebCore::Serializer::ObjectState::nextProperty):
+ (WebCore::Serializer::doSerialize):
+ (WebCore::Serializer::push):
+ (WebCore::Serializer::top):
+ (WebCore::Serializer::pop):
+ (WebCore::Serializer::checkComposite):
+ (WebCore::Reader::Reader):
+ (WebCore::Reader::isEof):
+ (WebCore::Reader::read):
+ (WebCore::Reader::readTag):
+ (WebCore::Reader::readString):
+ (WebCore::Reader::readInt32):
+ (WebCore::Reader::readNumber):
+ (WebCore::Reader::doReadUint32):
+ (WebCore::Deserializer::Deserializer):
+ (WebCore::Deserializer::deserialize):
+ (WebCore::Deserializer::doDeserialize):
+ (WebCore::Deserializer::push):
+ (WebCore::Deserializer::pop):
+ (WebCore::Deserializer::stackDepth):
+ (WebCore::Deserializer::element):
+ (WebCore::SerializedScriptValue::SerializedScriptValue):
+ (WebCore::SerializedScriptValue::deserialize):
+ * bindings/v8/SerializedScriptValue.h:
+ (WebCore::SerializedScriptValue::create):
+ (WebCore::SerializedScriptValue::createFromWire):
+ (WebCore::SerializedScriptValue::release):
+ (WebCore::SerializedScriptValue::toWireString):
+
+ Updated uses of SerializedScriptValue:
+ * bindings/v8/custom/V8DOMWindowCustom.cpp:
+ (WebCore::V8DOMWindow::postMessageCallback):
+ * bindings/v8/custom/V8DedicatedWorkerContextCustom.cpp:
+ (WebCore::V8DedicatedWorkerContext::postMessageCallback):
+ * bindings/v8/custom/V8HistoryCustom.cpp:
+ (WebCore::V8History::pushStateCallback):
+ (WebCore::V8History::replaceStateCallback):
+ * bindings/v8/custom/V8MessageEventCustom.cpp:
+ (WebCore::V8MessageEvent::initMessageEventCallback):
+ * bindings/v8/custom/V8MessagePortCustom.cpp:
+ (WebCore::V8MessagePort::postMessageCallback):
+ * bindings/v8/custom/V8WorkerCustom.cpp:
+ (WebCore::V8Worker::postMessageCallback):
+
2010-01-15 Oliver Hunt <oliver at apple.com>
Reviewed by Dirk Schulze.
diff --git a/WebCore/WebCore.gypi b/WebCore/WebCore.gypi
index 1a7a4df..7b8df1f 100644
--- a/WebCore/WebCore.gypi
+++ b/WebCore/WebCore.gypi
@@ -795,6 +795,7 @@
'bindings/v8/ScriptStringImpl.h',
'bindings/v8/ScriptValue.cpp',
'bindings/v8/ScriptValue.h',
+ 'bindings/v8/SerializedScriptValue.cpp',
'bindings/v8/SerializedScriptValue.h',
'bindings/v8/specialization/V8BindingDOMWindow.h',
'bindings/v8/specialization/V8BindingState.cpp',
diff --git a/WebCore/bindings/scripts/CodeGeneratorV8.pm b/WebCore/bindings/scripts/CodeGeneratorV8.pm
index 6a90bb4..d6786b8 100644
--- a/WebCore/bindings/scripts/CodeGeneratorV8.pm
+++ b/WebCore/bindings/scripts/CodeGeneratorV8.pm
@@ -2564,7 +2564,7 @@ sub ReturnNativeToJSValue
if ($type eq "SerializedScriptValue") {
$implIncludes{"$type.h"} = 1;
- return "return v8String($value->toString())";
+ return "return $value->deserialize()";
}
if ($type eq "DedicatedWorkerContext" or $type eq "WorkerContext" or $type eq "SharedWorkerContext") {
diff --git a/WebCore/bindings/v8/SerializedScriptValue.cpp b/WebCore/bindings/v8/SerializedScriptValue.cpp
new file mode 100644
index 0000000..3af1f42
--- /dev/null
+++ b/WebCore/bindings/v8/SerializedScriptValue.cpp
@@ -0,0 +1,698 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SerializedScriptValue.h"
+
+#include "SharedBuffer.h"
+
+#include <v8.h>
+#include <wtf/Assertions.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+// FIXME:
+// - catch V8 exceptions
+// - be ready to get empty handles
+// - consider crashing in debug mode on deserialization errors
+
+namespace WebCore {
+
+namespace {
+
+typedef UChar BufferValueType;
+
+// Serialization format is a sequence of (tag, optional data)
+// pairs. Tag always takes exactly one byte.
+enum SerializationTag {
+ InvalidTag = '!',
+ PaddingTag = '\0',
+ UndefinedTag = '_',
+ NullTag = '0',
+ TrueTag = 'T',
+ FalseTag = 'F',
+ StringTag = 'S',
+ Int32Tag = 'I',
+ NumberTag = 'N',
+ ObjectTag = '{',
+ ArrayTag = '[',
+};
+
+// Helpers to do verbose handle casts.
+
+template <typename T, typename U>
+static v8::Handle<T> handleCast(v8::Handle<U> handle) { return v8::Handle<T>::Cast(handle); }
+
+template <typename T, typename U>
+static v8::Local<T> handleCast(v8::Local<U> handle) { return v8::Local<T>::Cast(handle); }
+
+static bool shouldCheckForCycles(int depth)
+{
+ ASSERT(depth >= 0);
+ // Since we are not required to spot the cycle as soon as it
+ // happens we can check for cycles only when the current depth
+ // is a power of two.
+ return !(depth & (depth - 1));
+}
+
+static const int maxDepth = 20000;
+
+// VarInt encoding constants.
+static const int varIntShift = 7;
+static const int varIntMask = (1 << varIntShift) - 1;
+
+// ZigZag encoding helps VarInt encoding stay small for negative
+// numbers with small absolute values.
+class ZigZag {
+public:
+ static uint32_t encode(uint32_t value)
+ {
+ if (value & (1U << 31))
+ value = ((~value) << 1) + 1;
+ else
+ value <<= 1;
+ return value;
+ }
+
+ static uint32_t decode(uint32_t value)
+ {
+ if (value & 1)
+ value = ~(value >> 1);
+ else
+ value >>= 1;
+ return value;
+ }
+
+private:
+ ZigZag();
+};
+
+// Writer is responsible for serializing primitive types and storing
+// information used to reconstruct composite types.
+class Writer : Noncopyable {
+public:
+ Writer() : m_position(0)
+ {
+ }
+
+ // Write functions for primitive types.
+
+ void writeUndefined() { append(UndefinedTag); }
+
+ void writeNull() { append(NullTag); }
+
+ void writeTrue() { append(TrueTag); }
+
+ void writeFalse() { append(FalseTag); }
+
+ void writeString(const char* data, int length)
+ {
+ append(StringTag);
+ doWriteUint32(static_cast<uint32_t>(length));
+ append(data, length);
+ }
+
+ void writeInt32(int32_t value)
+ {
+ append(Int32Tag);
+ doWriteUint32(ZigZag::encode(static_cast<uint32_t>(value)));
+ }
+
+ void writeNumber(double number)
+ {
+ append(NumberTag);
+ append(reinterpret_cast<char*>(&number), sizeof(number));
+ }
+
+ // Records that a composite object can be constructed by using
+ // |length| previously stored values.
+ void endComposite(SerializationTag tag, int32_t length)
+ {
+ ASSERT(tag == ObjectTag || tag == ArrayTag);
+ append(tag);
+ doWriteUint32(static_cast<uint32_t>(length));
+ }
+
+ Vector<BufferValueType>& data()
+ {
+ fillHole();
+ return m_buffer;
+ }
+
+private:
+ void doWriteUint32(uint32_t value)
+ {
+ while (true) {
+ char b = (value & varIntMask);
+ value >>= varIntShift;
+ if (!value) {
+ append(b);
+ break;
+ }
+ append(b | (1 << varIntShift));
+ }
+ }
+
+ void append(SerializationTag tag)
+ {
+ append(static_cast<char>(tag));
+ }
+
+ void append(char b)
+ {
+ ensureSpace(1);
+ *charAt(m_position++) = b;
+ }
+
+ void append(const char* data, int length)
+ {
+ ensureSpace(length);
+ memcpy(charAt(m_position), data, length);
+ m_position += length;
+ }
+
+ void ensureSpace(int extra)
+ {
+ COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
+ m_buffer.grow((m_position + extra + 1) / 2); // "+ 1" to round up.
+ }
+
+ void fillHole()
+ {
+ COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
+ // If the writer is at odd position in the buffer, then one of
+ // the bytes in the last UChar is not initialized.
+ if (m_position % 2)
+ *charAt(m_position) = static_cast<char>(PaddingTag);
+ }
+
+ char* charAt(int position) { return reinterpret_cast<char*>(m_buffer.data()) + position; }
+
+ Vector<BufferValueType> m_buffer;
+ int m_position;
+};
+
+class Serializer {
+public:
+ explicit Serializer(Writer& writer)
+ : m_writer(writer)
+ , m_state(0)
+ , m_depth(0)
+ {
+ }
+
+ bool serialize(v8::Handle<v8::Value> value)
+ {
+ v8::HandleScope scope;
+ StackCleaner cleaner(&m_state);
+ if (!doSerialize(value))
+ return false;
+ while (top()) {
+ int length;
+ while (!top()->isDone(&length)) {
+ // Note that doSerialize() can change current top().
+ if (!doSerialize(top()->advance()))
+ return false;
+ }
+ m_writer.endComposite(top()->tag(), length);
+ pop();
+ }
+ return true;
+ }
+
+private:
+ class StateBase : public Noncopyable {
+ public:
+ virtual ~StateBase() { }
+
+ // Link to the next state to form a stack.
+ StateBase* nextState() { return m_next; }
+ void setNextState(StateBase* next) { m_next = next; }
+
+ // Composite object we're processing in this state.
+ v8::Handle<v8::Value> composite() { return m_composite; }
+
+ // Serialization tag for the current composite.
+ virtual SerializationTag tag() const = 0;
+
+ // Returns whether iteration over subobjects of the current
+ // composite object is done. If yes, |*length| is set to the
+ // number of subobjects.
+ virtual bool isDone(int* length) = 0;
+
+ // Advances to the next subobject.
+ // Requires: !this->isDone().
+ virtual v8::Local<v8::Value> advance() = 0;
+
+ protected:
+ StateBase(v8::Handle<v8::Value> composite)
+ : m_next(0)
+ , m_composite(composite)
+ {
+ }
+
+ private:
+ StateBase* m_next;
+ v8::Handle<v8::Value> m_composite;
+ };
+
+ template <typename T, SerializationTag compositeTag>
+ class State : public StateBase {
+ public:
+ v8::Handle<T> composite() { return handleCast<T>(StateBase::composite()); }
+
+ virtual SerializationTag tag() const { return compositeTag; }
+
+ protected:
+ explicit State(v8::Handle<T> composite) : StateBase(composite)
+ {
+ }
+ };
+
+ // Helper to clean up the state stack in case of errors.
+ class StackCleaner : Noncopyable {
+ public:
+ explicit StackCleaner(StateBase** stack) : m_stack(stack)
+ {
+ }
+
+ ~StackCleaner()
+ {
+ StateBase* state = *m_stack;
+ while (state) {
+ StateBase* tmp = state->nextState();
+ delete state;
+ state = tmp;
+ }
+ *m_stack = 0;
+ }
+
+ private:
+ StateBase** m_stack;
+ };
+
+ class ArrayState : public State<v8::Array, ArrayTag> {
+ public:
+ ArrayState(v8::Handle<v8::Array> array)
+ : State<v8::Array, ArrayTag>(array)
+ , m_index(0)
+ {
+ }
+
+ virtual bool isDone(int* length)
+ {
+ *length = composite()->Length();
+ return m_index >= *length;
+ }
+
+ virtual v8::Local<v8::Value> advance()
+ {
+ ASSERT(m_index < composite()->Length());
+ v8::HandleScope scope;
+ return scope.Close(composite()->Get(v8::Integer::New(m_index++)));
+ }
+
+ private:
+ int m_index;
+ };
+
+ class ObjectState : public State<v8::Object, ObjectTag> {
+ public:
+ ObjectState(v8::Handle<v8::Object> object)
+ : State<v8::Object, ObjectTag>(object)
+ , m_propertyNames(object->GetPropertyNames())
+ , m_index(-1)
+ , m_length(0)
+ {
+ nextProperty();
+ }
+
+ virtual bool isDone(int* length)
+ {
+ *length = m_length;
+ return m_index >= 2 * m_propertyNames->Length();
+ }
+
+ virtual v8::Local<v8::Value> advance()
+ {
+ ASSERT(m_index < 2 * m_propertyNames->Length());
+ if (!(m_index % 2)) {
+ ++m_index;
+ return m_propertyName;
+ }
+ v8::Local<v8::Value> result = composite()->Get(m_propertyName);
+ nextProperty();
+ return result;
+ }
+
+ private:
+ void nextProperty()
+ {
+ v8::HandleScope scope;
+ ++m_index;
+ ASSERT(!(m_index % 2));
+ for (; m_index < 2 * m_propertyNames->Length(); m_index += 2) {
+ v8::Local<v8::Value> propertyName = m_propertyNames->Get(v8::Integer::New(m_index / 2));
+ if ((propertyName->IsString() && composite()->HasRealNamedProperty(handleCast<v8::String>(propertyName)))
+ || (propertyName->IsInt32() && composite()->HasRealIndexedProperty(propertyName->Uint32Value()))) {
+ m_propertyName = scope.Close(propertyName);
+ m_length += 2;
+ return;
+ }
+ }
+ }
+
+ v8::Local<v8::Array> m_propertyNames;
+ v8::Local<v8::Value> m_propertyName;
+ int m_index;
+ int m_length;
+ };
+
+ bool doSerialize(v8::Handle<v8::Value> value)
+ {
+ if (value->IsUndefined())
+ m_writer.writeUndefined();
+ else if (value->IsNull())
+ m_writer.writeNull();
+ else if (value->IsTrue())
+ m_writer.writeTrue();
+ else if (value->IsFalse())
+ m_writer.writeFalse();
+ else if (value->IsInt32())
+ m_writer.writeInt32(value->Int32Value());
+ else if (value->IsNumber())
+ m_writer.writeNumber(handleCast<v8::Number>(value)->Value());
+ else if (value->IsString()) {
+ v8::String::Utf8Value stringValue(value);
+ m_writer.writeString(*stringValue, stringValue.length());
+ } else if (value->IsArray()) {
+ if (!checkComposite(value))
+ return false;
+ push(new ArrayState(handleCast<v8::Array>(value)));
+ } else if (value->IsObject()) {
+ if (!checkComposite(value))
+ return false;
+ push(new ObjectState(handleCast<v8::Object>(value)));
+ // FIXME:
+ // - check not a wrapper
+ // - support File, ImageData, etc.
+ }
+ return true;
+ }
+
+ void push(StateBase* state)
+ {
+ state->setNextState(m_state);
+ m_state = state;
+ ++m_depth;
+ }
+
+ StateBase* top() { return m_state; }
+
+ void pop()
+ {
+ if (!m_state)
+ return;
+ StateBase* top = m_state;
+ m_state = top->nextState();
+ delete top;
+ --m_depth;
+ }
+
+ bool checkComposite(v8::Handle<v8::Value> composite)
+ {
+ if (m_depth > maxDepth)
+ return false;
+ if (!shouldCheckForCycles(m_depth))
+ return true;
+ for (StateBase* state = top(); state; state = state->nextState()) {
+ if (state->composite() == composite)
+ return false;
+ }
+ return true;
+ }
+
+ Writer& m_writer;
+ StateBase* m_state;
+ int m_depth;
+};
+
+// Reader is responsible for deserializing primitive types and
+// restoring information about saved objects of composite types.
+class Reader {
+public:
+ Reader(const char* buffer, int length)
+ : m_buffer(buffer)
+ , m_length(length)
+ , m_position(0)
+ {
+ }
+
+ bool isEof() const { return m_position >= m_length; }
+
+ bool read(SerializationTag* tag, v8::Handle<v8::Value>* value, int* length)
+ {
+ uint32_t rawLength;
+ if (!readTag(tag))
+ return false;
+ switch (*tag) {
+ case PaddingTag:
+ break;
+ case UndefinedTag:
+ *value = v8::Undefined();
+ break;
+ case NullTag:
+ *value = v8::Null();
+ break;
+ case TrueTag:
+ *value = v8::True();
+ break;
+ case FalseTag:
+ *value = v8::False();
+ break;
+ case StringTag:
+ if (!readString(value))
+ return false;
+ break;
+ case Int32Tag:
+ if (!readInt32(value))
+ return false;
+ break;
+ case NumberTag:
+ if (!readNumber(value))
+ return false;
+ break;
+ case ObjectTag:
+ case ArrayTag:
+ if (!doReadUint32(&rawLength))
+ return false;
+ *length = rawLength;
+ break;
+ }
+ return true;
+ }
+
+private:
+ bool readTag(SerializationTag* tag)
+ {
+ if (m_position >= m_length)
+ return false;
+ *tag = static_cast<SerializationTag>(m_buffer[m_position++]);
+ return true;
+ }
+
+ bool readString(v8::Handle<v8::Value>* value)
+ {
+ uint32_t length;
+ if (!doReadUint32(&length))
+ return false;
+ if (m_position + length > m_length)
+ return false;
+ *value = v8::String::New(m_buffer + m_position, length);
+ m_position += length;
+ return true;
+ }
+
+ bool readInt32(v8::Handle<v8::Value>* value)
+ {
+ uint32_t rawValue;
+ if (!doReadUint32(&rawValue))
+ return false;
+ *value = v8::Integer::New(static_cast<int32_t>(ZigZag::decode(rawValue)));
+ return true;
+ }
+
+ bool readNumber(v8::Handle<v8::Value>* value)
+ {
+ if (m_position + sizeof(double) > m_length)
+ return false;
+ double number;
+ char* numberAsByteArray = reinterpret_cast<char*>(&number);
+ for (int i = 0; i < sizeof(double); ++i)
+ numberAsByteArray[i] = m_buffer[m_position++];
+ *value = v8::Number::New(number);
+ return true;
+ }
+
+ bool doReadUint32(uint32_t* value)
+ {
+ *value = 0;
+ char currentByte;
+ int shift = 0;
+ do {
+ if (m_position >= m_length)
+ return false;
+ currentByte = m_buffer[m_position++];
+ *value |= ((currentByte & varIntMask) << shift);
+ shift += varIntShift;
+ } while (currentByte & (1 << varIntShift));
+ return true;
+ }
+
+ const char* m_buffer;
+ const int m_length;
+ int m_position;
+};
+
+class Deserializer {
+public:
+ explicit Deserializer(Reader& reader) : m_reader(reader)
+ {
+ }
+
+ v8::Local<v8::Value> deserialize()
+ {
+ v8::HandleScope scope;
+ while (!m_reader.isEof()) {
+ if (!doDeserialize())
+ return v8::Local<v8::Value>();
+ }
+ if (stackDepth() != 1)
+ return v8::Local<v8::Value>();
+ return scope.Close(element(0));
+ }
+
+private:
+ bool doDeserialize()
+ {
+ SerializationTag tag;
+ v8::Local<v8::Value> value;
+ int length;
+ if (!m_reader.read(&tag, &value, &length))
+ return false;
+ if (!value.IsEmpty()) {
+ push(value);
+ } else if (tag == ObjectTag) {
+ if (length > stackDepth())
+ return false;
+ v8::Local<v8::Object> object = v8::Object::New();
+ for (int i = stackDepth() - length; i < stackDepth(); i += 2) {
+ v8::Local<v8::Value> propertyName = element(i);
+ v8::Local<v8::Value> propertyValue = element(i + 1);
+ object->Set(propertyName, propertyValue);
+ }
+ pop(length);
+ push(object);
+ } else if (tag == ArrayTag) {
+ if (length > stackDepth())
+ return false;
+ v8::Local<v8::Array> array = v8::Array::New(length);
+ const int depth = stackDepth() - length;
+ {
+ v8::HandleScope scope;
+ for (int i = 0; i < length; ++i)
+ array->Set(v8::Integer::New(i), element(depth + i));
+ }
+ pop(length);
+ push(array);
+ } else if (tag != PaddingTag)
+ return false;
+ return true;
+ }
+
+ void push(v8::Local<v8::Value> value) { m_stack.append(value); }
+
+ void pop(int length)
+ {
+ ASSERT(length >= 0);
+ ASSERT(length <= m_stack.size());
+ m_stack.shrink(m_stack.size() - length);
+ }
+
+ int stackDepth() const { return m_stack.size(); }
+
+ v8::Local<v8::Value> element(int index)
+ {
+ ASSERT(index >= 0);
+ ASSERT(index < m_stack.size());
+ return m_stack[index];
+ }
+
+ Reader& m_reader;
+ Vector<v8::Local<v8::Value> > m_stack;
+};
+
+} // namespace
+
+SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value)
+{
+ Writer writer;
+ Serializer serializer(writer);
+ if (!serializer.serialize(value)) {
+ // FIXME: throw exception
+ return;
+ }
+ m_data = StringImpl::adopt(writer.data());
+}
+
+SerializedScriptValue::SerializedScriptValue(String data, StringDataMode mode)
+{
+ if (mode == WireData)
+ m_data = data;
+ else {
+ ASSERT(mode == StringValue);
+ RefPtr<SharedBuffer> buffer = utf8Buffer(data);
+ Writer writer;
+ writer.writeString(buffer->data(), buffer->size());
+ m_data = StringImpl::adopt(writer.data());
+ }
+}
+
+v8::Local<v8::Value> SerializedScriptValue::deserialize()
+{
+ if (!m_data.impl())
+ return v8::Local<v8::Value>();
+ COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
+ Reader reader(reinterpret_cast<const char*>(m_data.impl()->characters()), 2 * m_data.length());
+ Deserializer deserializer(reader);
+ return deserializer.deserialize();
+}
+
+} // namespace WebCore
diff --git a/WebCore/bindings/v8/SerializedScriptValue.h b/WebCore/bindings/v8/SerializedScriptValue.h
index 26a4199..7eb8935 100644
--- a/WebCore/bindings/v8/SerializedScriptValue.h
+++ b/WebCore/bindings/v8/SerializedScriptValue.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -40,11 +40,26 @@ namespace WebCore {
class SerializedScriptValue : public RefCounted<SerializedScriptValue> {
public:
- static PassRefPtr<SerializedScriptValue> create(String string)
+ // Creates a serialized representation of the given V8 value.
+ static PassRefPtr<SerializedScriptValue> create(v8::Handle<v8::Value> value)
{
- return adoptRef(new SerializedScriptValue(string));
+ return adoptRef(new SerializedScriptValue(value));
}
+ // Creates a serialized value with the given data obtained from a
+ // prior call to toWireString().
+ static PassRefPtr<SerializedScriptValue> createFromWire(String data)
+ {
+ return adoptRef(new SerializedScriptValue(data, WireData));
+ }
+
+ // Creates a serialized representation of WebCore string.
+ static PassRefPtr<SerializedScriptValue> create(String data)
+ {
+ return adoptRef(new SerializedScriptValue(data, StringValue));
+ }
+
+ // Creates an empty serialized value.
static PassRefPtr<SerializedScriptValue> create()
{
return adoptRef(new SerializedScriptValue());
@@ -52,23 +67,29 @@ public:
PassRefPtr<SerializedScriptValue> release()
{
- RefPtr<SerializedScriptValue> result = adoptRef(new SerializedScriptValue(m_data));
+ RefPtr<SerializedScriptValue> result = adoptRef(new SerializedScriptValue(m_data, WireData));
m_data = String();
return result.release();
}
- String toString()
- {
- return m_data;
- }
+ String toWireString() const { return m_data; }
+
+ // Deserializes the value (in the current context). Returns an
+ // empty handle in case of failure.
+ v8::Local<v8::Value> deserialize();
private:
- SerializedScriptValue(String string)
- : m_data(string)
- {
- }
+ enum StringDataMode {
+ StringValue,
+ WireData
+ };
SerializedScriptValue() { }
+
+ explicit SerializedScriptValue(v8::Handle<v8::Value>);
+
+ SerializedScriptValue(String data, StringDataMode mode);
+
String m_data;
};
diff --git a/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp b/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp
index dacd4f6..b594518 100644
--- a/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp
+++ b/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp
@@ -411,7 +411,7 @@ v8::Handle<v8::Value> V8DOMWindow::postMessageCallback(const v8::Arguments& args
ASSERT(source->frame());
v8::TryCatch tryCatch;
- RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(toWebCoreString(args[0]));
+ RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(args[0]);
MessagePortArray portArray;
String targetOrigin;
diff --git a/WebCore/bindings/v8/custom/V8DedicatedWorkerContextCustom.cpp b/WebCore/bindings/v8/custom/V8DedicatedWorkerContextCustom.cpp
index 5ab6218..4486dbe 100644
--- a/WebCore/bindings/v8/custom/V8DedicatedWorkerContextCustom.cpp
+++ b/WebCore/bindings/v8/custom/V8DedicatedWorkerContextCustom.cpp
@@ -46,7 +46,7 @@ v8::Handle<v8::Value> V8DedicatedWorkerContext::postMessageCallback(const v8::Ar
{
INC_STATS(L"DOM.DedicatedWorkerContext.postMessage");
DedicatedWorkerContext* workerContext = V8DedicatedWorkerContext::toNative(args.Holder());
- RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(v8ValueToWebCoreString(args[0]));
+ RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(args[0]);
MessagePortArray portArray;
if (args.Length() > 1) {
if (!getMessagePortArray(args[1], portArray))
diff --git a/WebCore/bindings/v8/custom/V8HistoryCustom.cpp b/WebCore/bindings/v8/custom/V8HistoryCustom.cpp
index 6aa0806..b857d6e 100644
--- a/WebCore/bindings/v8/custom/V8HistoryCustom.cpp
+++ b/WebCore/bindings/v8/custom/V8HistoryCustom.cpp
@@ -43,7 +43,7 @@ namespace WebCore {
v8::Handle<v8::Value> V8History::pushStateCallback(const v8::Arguments& args)
{
- RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(toWebCoreString(args[0]));
+ RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(args[0]);
v8::TryCatch tryCatch;
String title = toWebCoreStringWithNullOrUndefinedCheck(args[1]);
@@ -64,7 +64,7 @@ v8::Handle<v8::Value> V8History::pushStateCallback(const v8::Arguments& args)
v8::Handle<v8::Value> V8History::replaceStateCallback(const v8::Arguments& args)
{
- RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(toWebCoreString(args[0]));
+ RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(args[0]);
v8::TryCatch tryCatch;
String title = toWebCoreStringWithNullOrUndefinedCheck(args[1]);
diff --git a/WebCore/bindings/v8/custom/V8MessageEventCustom.cpp b/WebCore/bindings/v8/custom/V8MessageEventCustom.cpp
index b291d1a..2b027dc 100644
--- a/WebCore/bindings/v8/custom/V8MessageEventCustom.cpp
+++ b/WebCore/bindings/v8/custom/V8MessageEventCustom.cpp
@@ -65,7 +65,7 @@ v8::Handle<v8::Value> V8MessageEvent::initMessageEventCallback(const v8::Argumen
String typeArg = v8ValueToWebCoreString(args[0]);
bool canBubbleArg = args[1]->BooleanValue();
bool cancelableArg = args[2]->BooleanValue();
- RefPtr<SerializedScriptValue> dataArg = SerializedScriptValue::create(v8ValueToWebCoreString(args[3]));
+ RefPtr<SerializedScriptValue> dataArg = SerializedScriptValue::create(args[3]);
String originArg = v8ValueToWebCoreString(args[4]);
String lastEventIdArg = v8ValueToWebCoreString(args[5]);
DOMWindow* sourceArg = V8DOMWindow::HasInstance(args[6]) ? V8DOMWindow::toNative(v8::Handle<v8::Object>::Cast(args[6])) : 0;
diff --git a/WebCore/bindings/v8/custom/V8MessagePortCustom.cpp b/WebCore/bindings/v8/custom/V8MessagePortCustom.cpp
index 071b1ac..cc70bc5 100644
--- a/WebCore/bindings/v8/custom/V8MessagePortCustom.cpp
+++ b/WebCore/bindings/v8/custom/V8MessagePortCustom.cpp
@@ -78,7 +78,7 @@ v8::Handle<v8::Value> V8MessagePort::postMessageCallback(const v8::Arguments& ar
{
INC_STATS("DOM.MessagePort.postMessage");
MessagePort* messagePort = V8MessagePort::toNative(args.Holder());
- RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(toWebCoreString(args[0]));
+ RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(args[0]);
MessagePortArray portArray;
if (args.Length() > 1) {
if (!getMessagePortArray(args[1], portArray))
diff --git a/WebCore/bindings/v8/custom/V8PopStateEventCustom.cpp b/WebCore/bindings/v8/custom/V8PopStateEventCustom.cpp
index 99cc2d1..46e9929 100644
--- a/WebCore/bindings/v8/custom/V8PopStateEventCustom.cpp
+++ b/WebCore/bindings/v8/custom/V8PopStateEventCustom.cpp
@@ -44,7 +44,7 @@ v8::Handle<v8::Value> V8PopStateEvent::initPopStateEventCallback(const v8::Argum
String typeArg = v8ValueToWebCoreString(args[0]);
bool canBubbleArg = args[1]->BooleanValue();
bool cancelableArg = args[2]->BooleanValue();
- RefPtr<SerializedScriptValue> stateArg = SerializedScriptValue::create(v8ValueToWebCoreString(args[3]));
+ RefPtr<SerializedScriptValue> stateArg = SerializedScriptValue::create(args[3]);
PopStateEvent* event = V8PopStateEvent::toNative(args.Holder());
event->initPopStateEvent(typeArg, canBubbleArg, cancelableArg, stateArg.release());
@@ -61,7 +61,7 @@ v8::Handle<v8::Value> V8PopStateEvent::stateAccessorGetter(v8::Local<v8::String>
if (!state)
return v8::Null();
- return v8StringOrNull(state->toString());
+ return state->deserialize();
}
} // namespace WebCore
diff --git a/WebCore/bindings/v8/custom/V8WorkerCustom.cpp b/WebCore/bindings/v8/custom/V8WorkerCustom.cpp
index 6dec7af..4291f6d 100644
--- a/WebCore/bindings/v8/custom/V8WorkerCustom.cpp
+++ b/WebCore/bindings/v8/custom/V8WorkerCustom.cpp
@@ -92,7 +92,7 @@ v8::Handle<v8::Value> V8Worker::postMessageCallback(const v8::Arguments& args)
{
INC_STATS("DOM.Worker.postMessage");
Worker* worker = V8Worker::toNative(args.Holder());
- RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(toWebCoreString(args[0]));
+ RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(args[0]);
MessagePortArray portArray;
if (args.Length() > 1) {
if (!getMessagePortArray(args[1], portArray))
diff --git a/WebKit/chromium/ChangeLog b/WebKit/chromium/ChangeLog
index 00a8c32..4013ef2 100644
--- a/WebKit/chromium/ChangeLog
+++ b/WebKit/chromium/ChangeLog
@@ -1,3 +1,23 @@
+2010-01-15 Vitaly Repeshko <vitalyr at chromium.org>
+
+ Reviewed by David Levin.
+
+ [V8] Support SerializedScriptValue.
+ https://bugs.webkit.org/show_bug.cgi?id=32920
+ http://crbug.com/30620
+
+ Updated uses of SerializedScriptValue:
+ * src/PlatformMessagePortChannel.cpp:
+ (WebCore::PlatformMessagePortChannel::postMessageToRemote):
+ (WebCore::PlatformMessagePortChannel::tryGetMessageFromRemote):
+ * src/WebWorkerBase.cpp:
+ (WebKit::WebWorkerBase::postMessageToWorkerObject):
+ * src/WebWorkerClientImpl.cpp:
+ (WebKit::WebWorkerClientImpl::postMessageToWorkerContext):
+ (WebKit::WebWorkerClientImpl::postMessageToWorkerObjectTask):
+ * src/WebWorkerImpl.cpp:
+ (WebKit::WebWorkerImpl::postMessageToWorkerContextTask):
+
2010-01-14 Jeremy Orlow <jorlow at chromium.org>
Reviewed by Oliver Hunt.
diff --git a/WebKit/chromium/src/PlatformMessagePortChannel.cpp b/WebKit/chromium/src/PlatformMessagePortChannel.cpp
index f8c41d3..aa42a10 100644
--- a/WebKit/chromium/src/PlatformMessagePortChannel.cpp
+++ b/WebKit/chromium/src/PlatformMessagePortChannel.cpp
@@ -179,7 +179,7 @@ void PlatformMessagePortChannel::postMessageToRemote(PassOwnPtr<MessagePortChann
if (!m_localPort || !m_webChannel)
return;
- WebString messageString = message->message()->toString();
+ WebString messageString = message->message()->toWireString();
OwnPtr<WebCore::MessagePortChannelArray> channels = message->channels();
WebMessagePortChannelArray* webChannels = 0;
if (channels.get() && channels->size()) {
@@ -211,7 +211,7 @@ bool PlatformMessagePortChannel::tryGetMessageFromRemote(OwnPtr<MessagePortChann
(*channels)[i] = MessagePortChannel::create(platformChannel);
}
}
- RefPtr<SerializedScriptValue> serializedMessage = SerializedScriptValue::create(message);
+ RefPtr<SerializedScriptValue> serializedMessage = SerializedScriptValue::createFromWire(message);
result = MessagePortChannel::EventData::create(serializedMessage.release(), channels.release());
}
diff --git a/WebKit/chromium/src/WebWorkerBase.cpp b/WebKit/chromium/src/WebWorkerBase.cpp
index 0e3aa4e..7fd3749 100644
--- a/WebKit/chromium/src/WebWorkerBase.cpp
+++ b/WebKit/chromium/src/WebWorkerBase.cpp
@@ -157,7 +157,7 @@ void WebWorkerBase::postMessageToWorkerObject(PassRefPtr<SerializedScriptValue>
PassOwnPtr<MessagePortChannelArray> channels)
{
dispatchTaskToMainThread(createCallbackTask(&postMessageTask, this,
- message->toString(), channels));
+ message->toWireString(), channels));
}
void WebWorkerBase::postMessageTask(ScriptExecutionContext* context,
diff --git a/WebKit/chromium/src/WebWorkerClientImpl.cpp b/WebKit/chromium/src/WebWorkerClientImpl.cpp
index 6be03a7..598a078 100644
--- a/WebKit/chromium/src/WebWorkerClientImpl.cpp
+++ b/WebKit/chromium/src/WebWorkerClientImpl.cpp
@@ -173,7 +173,7 @@ void WebWorkerClientImpl::postMessageToWorkerContext(
if (!isMainThread()) {
WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&postMessageToWorkerContextTask,
this,
- message->toString(),
+ message->toWireString(),
channels));
return;
}
@@ -184,7 +184,7 @@ void WebWorkerClientImpl::postMessageToWorkerContext(
webchannel->setClient(0);
webChannels[i] = webchannel;
}
- m_webWorker->postMessageToWorkerContext(message->toString(), webChannels);
+ m_webWorker->postMessageToWorkerContext(message->toWireString(), webChannels);
}
bool WebWorkerClientImpl::hasPendingActivity() const
@@ -356,7 +356,7 @@ void WebWorkerClientImpl::postMessageToWorkerObjectTask(
OwnPtr<MessagePortArray> ports =
MessagePort::entanglePorts(*context, channels.release());
RefPtr<SerializedScriptValue> serializedMessage =
- SerializedScriptValue::create(message);
+ SerializedScriptValue::createFromWire(message);
thisPtr->m_worker->dispatchEvent(MessageEvent::create(ports.release(),
serializedMessage.release()));
}
diff --git a/WebKit/chromium/src/WebWorkerImpl.cpp b/WebKit/chromium/src/WebWorkerImpl.cpp
index 744be30..5b5e053 100644
--- a/WebKit/chromium/src/WebWorkerImpl.cpp
+++ b/WebKit/chromium/src/WebWorkerImpl.cpp
@@ -88,7 +88,7 @@ void WebWorkerImpl::postMessageToWorkerContextTask(WebCore::ScriptExecutionConte
OwnPtr<MessagePortArray> ports =
MessagePort::entanglePorts(*context, channels.release());
RefPtr<SerializedScriptValue> serializedMessage =
- SerializedScriptValue::create(message);
+ SerializedScriptValue::createFromWire(message);
workerContext->dispatchEvent(MessageEvent::create(
ports.release(), serializedMessage.release()));
thisPtr->confirmMessageFromWorkerObject(workerContext->hasPendingActivity());
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list