aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/v4vm/qv4v8.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/v4vm/qv4v8.cpp')
-rw-r--r--src/qml/qml/v4vm/qv4v8.cpp2141
1 files changed, 2141 insertions, 0 deletions
diff --git a/src/qml/qml/v4vm/qv4v8.cpp b/src/qml/qml/v4vm/qv4v8.cpp
new file mode 100644
index 0000000000..d81f23f30f
--- /dev/null
+++ b/src/qml/qml/v4vm/qv4v8.cpp
@@ -0,0 +1,2141 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the V4VM module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4v8.h"
+
+#include "qv4engine.h"
+#include "qv4runtime.h"
+#include "qv4mm.h"
+#include "qv4managed.h"
+#include "qv4functionobject.h"
+#include "qv4value.h"
+#include "qv4isel_masm_p.h"
+#include "qv4globalobject.h"
+#include "qv4regexpobject.h"
+#include "qv4dateobject.h"
+#include "qv4numberobject.h"
+#include "qv4booleanobject.h"
+#include "qv4stringobject.h"
+#include "qv4objectproto.h"
+#include <QThreadStorage>
+
+using namespace QQmlJS;
+using namespace QQmlJS::VM;
+
+namespace v8 {
+
+#define currentEngine() Isolate::GetCurrent()->GetCurrentContext()->GetEngine()
+
+#define Q_D(obj) QQmlJS::VM::Value *d = reinterpret_cast<QQmlJS::VM::Value*>(obj)
+
+#define ValuePtr(obj) reinterpret_cast<QQmlJS::VM::Value*>(obj)
+#define ConstValuePtr(obj) reinterpret_cast<const QQmlJS::VM::Value*>(obj)
+
+void *gcProtect(void *handle)
+{
+ Q_D(handle);
+ if (VM::Managed *m = d->asManaged()) {
+ currentEngine()->memoryManager->protect(m);
+ return currentEngine()->memoryManager;
+ }
+}
+
+void gcProtect(void *memoryManager, void *handle)
+{
+ Q_D(handle);
+ if (VM::Managed *m = d->asManaged())
+ if (memoryManager)
+ static_cast<VM::MemoryManager *>(memoryManager)->protect(m);
+}
+
+void gcUnprotect(void *memoryManager, void *handle)
+{
+ Q_D(handle);
+ if (VM::Managed *m = d->asManaged())
+ if (memoryManager)
+ static_cast<VM::MemoryManager *>(memoryManager)->unprotect(m);
+}
+
+struct V8AccessorGetter: FunctionObject {
+ AccessorGetter getter;
+ Persistent<Value> data;
+ Persistent<String> name;
+
+ V8AccessorGetter(ExecutionContext *scope, const Handle<String> &name, const AccessorGetter &getter, Handle<Value> data)
+ : FunctionObject(scope)
+ {
+ vtbl = &static_vtbl;
+ this->getter = getter;
+ this->data = Persistent<Value>::New(data);
+ this->name = Persistent<String>::New(name);
+ }
+
+ using Object::construct;
+
+ static VM::Value call(Managed *that, ExecutionContext *context, const VM::Value &thisObject, VM::Value *args, int argc)
+ {
+ V8AccessorGetter *getter = static_cast<V8AccessorGetter*>(that);
+ AccessorInfo info(thisObject, getter->data);
+ VM::Value result = VM::Value::undefinedValue();
+ try {
+ result = getter->getter(Local<String>::New(getter->name), info)->vmValue();
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(context);
+ }
+ return result;
+ }
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+DEFINE_MANAGED_VTABLE(V8AccessorGetter);
+
+struct V8AccessorSetter: FunctionObject {
+ AccessorSetter setter;
+ Persistent<Value> data;
+ Persistent<String> name;
+
+ V8AccessorSetter(ExecutionContext *scope, const Handle<String> &name, const AccessorSetter &setter, Handle<Value> data)
+ : FunctionObject(scope)
+ {
+ vtbl = &static_vtbl;
+ this->setter = setter;
+ this->data = Persistent<Value>::New(data);
+ this->name = Persistent<String>::New(name);
+ }
+
+ using Object::construct;
+
+ static VM::Value call(Managed *that, ExecutionContext *context, const VM::Value &thisObject, VM::Value *args, int argc)
+ {
+ if (!argc)
+ return VM::Value::undefinedValue();
+ V8AccessorSetter *setter = static_cast<V8AccessorSetter*>(that);
+ AccessorInfo info(thisObject, setter->data);
+ try {
+ setter->setter(Local<String>::New(setter->name), Local<Value>::New(Value::fromVmValue(args[0])), info);
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(context);
+ }
+ return VM::Value::undefinedValue();
+ }
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+DEFINE_MANAGED_VTABLE(V8AccessorSetter);
+
+ScriptOrigin::ScriptOrigin(Handle<Value> resource_name, Handle<Integer> resource_line_offset, Handle<Integer> resource_column_offset)
+{
+ m_fileName = resource_name->ToString()->asQString();
+ m_lineNumber = resource_line_offset->ToInt32()->Value();
+ m_columnNumber = resource_column_offset->ToInt32()->Value();
+}
+
+Handle<Value> ScriptOrigin::ResourceName() const
+{
+ return Value::fromVmValue(VM::Value::fromString(currentEngine()->current, m_fileName));
+}
+
+Handle<Integer> ScriptOrigin::ResourceLineOffset() const
+{
+ return Integer::New(m_lineNumber);
+}
+
+Handle<Integer> ScriptOrigin::ResourceColumnOffset() const
+{
+ return Integer::New(m_columnNumber);
+}
+
+
+Local<Script> Script::New(Handle<String> source,
+ ScriptOrigin* origin,
+ ScriptData* pre_data,
+ Handle<String> script_data,
+ CompileFlags flags)
+{
+ Script *s = new Script;
+ s->m_script = source->ToString()->asQString();
+ if (origin)
+ s->m_origin = *origin;
+ s->m_flags = flags;
+ s->m_context = Handle<Context>();
+ return Local<Script>::New(Handle<Script>(s));
+}
+
+
+Local<Script> Script::New(Handle<String> source,
+ Handle<Value> file_name,
+ CompileFlags flags)
+{
+ ScriptOrigin origin(file_name);
+ return New(source, &origin, 0, Handle<String>(), flags);
+}
+
+Local<Script> Script::Compile(Handle<String> source, ScriptOrigin *origin, ScriptData *pre_data, Handle<String> script_data, Script::CompileFlags flags)
+{
+ Script *s = new Script;
+ s->m_script = source->ToString()->asQString();
+ if (origin)
+ s->m_origin = *origin;
+ s->m_flags = flags;
+ s->m_context = Context::GetCurrent();
+ return Local<Script>::New(Handle<Script>(s));
+}
+
+Local<Script> Script::Compile(Handle<String> source,
+ Handle<Value> file_name,
+ Handle<String> script_data,
+ CompileFlags flags)
+{
+ ScriptOrigin origin(file_name);
+ return Compile(source, &origin, 0, script_data, flags);
+}
+
+Local<Value> Script::Run()
+{
+ Handle<Context> context = m_context;
+ if (context.IsEmpty())
+ context = Context::GetCurrent();
+ ASSERT(context.get());
+ VM::ExecutionEngine *engine = context->GetEngine();
+ VM::ExecutionContext *ctx = engine->current;
+
+ VM::Value result = VM::Value::undefinedValue();
+ try {
+ QQmlJS::VM::Function *f = QQmlJS::VM::EvalFunction::parseSource(engine->rootContext, m_origin.m_fileName, m_script, QQmlJS::Codegen::EvalCode,
+ /*strictMode =*/ false, /*inheritContext =*/ false);
+ if (!f)
+ __qmljs_throw(engine->current, VM::Value::fromObject(engine->newSyntaxErrorObject(engine->current, 0)));
+
+ result = context->GetEngine()->run(f);
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(ctx);
+ }
+
+ return Local<Value>::New(Value::fromVmValue(result));
+}
+
+Local<Value> Script::Run(Handle<Object> qml)
+{
+ Handle<Context> context = m_context;
+ if (context.IsEmpty())
+ context = Context::GetCurrent();
+ ASSERT(context.get());
+ VM::ExecutionEngine *engine = context->GetEngine();
+ VM::ExecutionContext *ctx = engine->current;
+
+ VM::Value result = VM::Value::undefinedValue();
+
+ try {
+
+ VM::EvalFunction *eval = new (engine->memoryManager) VM::EvalFunction(engine->rootContext, qml->vmValue().asObject());
+
+ VM::Value arg = VM::Value::fromString(engine->current, m_script);
+
+ result = eval->evalCall(engine->current, VM::Value::undefinedValue(), &arg, 1, /*directCall*/ false);
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(ctx);
+ }
+ return Local<Value>::New(Value::fromVmValue(result));
+}
+
+Local<Value> Script::Id()
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+void Script::SetData(Handle<String> data)
+{
+ Q_UNIMPLEMENTED();
+}
+
+
+Local<String> Message::Get() const
+{
+ return Local<String>::New(Value::fromVmValue(VM::Value::fromString(currentEngine()->current, m_message)));
+}
+
+Handle<Value> Message::GetScriptResourceName() const
+{
+ return Value::fromVmValue(VM::Value::fromString(currentEngine()->current, m_resourceName));
+}
+
+int Message::GetLineNumber() const
+{
+ return m_lineNumber;
+}
+
+
+Local<StackFrame> StackTrace::GetFrame(uint32_t index) const
+{
+ if (index >= (uint)frames.size())
+ return Local<StackFrame>();
+ return frames.at(index);
+}
+
+int StackTrace::GetFrameCount() const
+{
+ return frames.size();
+}
+
+Local<Array> StackTrace::AsArray()
+{
+ Q_UNIMPLEMENTED();
+ return Local<Array>();
+}
+
+Local<StackTrace> StackTrace::CurrentStackTrace(int frame_limit, StackTrace::StackTraceOptions options)
+{
+ StackTrace *trace = new StackTrace;
+ VM::ExecutionEngine *engine = currentEngine();
+ VM::ExecutionContext *current = engine->current;
+ while (current && frame_limit) {
+ if (CallContext *c = current->asCallContext()) {
+ StackFrame *frame = new StackFrame(Value::fromVmValue(VM::Value::fromString(engine->id_null)),
+ Value::fromVmValue(VM::Value::fromString(c->function->name)),
+ 0, 0);
+ trace->frames.append(frame);
+ --frame_limit;
+ }
+ current = current->parent;
+ }
+
+ return Local<StackTrace>::New(Handle<StackTrace>(trace));
+}
+
+
+int StackFrame::GetLineNumber() const
+{
+ return m_lineNumber;
+}
+
+int StackFrame::GetColumn() const
+{
+ return m_columnNumber;
+}
+
+Local<String> StackFrame::GetScriptName() const
+{
+ return Local<String>::New(m_scriptName);
+}
+
+Local<String> StackFrame::GetScriptNameOrSourceURL() const
+{
+ return Local<String>::New(m_scriptName);
+}
+
+Local<String> StackFrame::GetFunctionName() const
+{
+ return Local<String>::New(m_functionName);
+}
+
+StackFrame::StackFrame(Handle<String> script, Handle<String> function, int line, int column)
+ : m_lineNumber(line)
+ , m_columnNumber(column)
+{
+ m_scriptName = Persistent<String>::New(script);
+ m_functionName = Persistent<String>::New(function);
+}
+
+
+bool Value::IsUndefined() const
+{
+ return ConstValuePtr(this)->isUndefined();
+}
+
+bool Value::IsNull() const {
+ return ConstValuePtr(this)->isNull();
+}
+
+bool Value::IsTrue() const
+{
+ return ConstValuePtr(this)->isBoolean() && ConstValuePtr(this)->booleanValue();
+}
+
+bool Value::IsFalse() const
+{
+ return !IsTrue();
+}
+
+bool Value::IsString() const
+{
+ return ConstValuePtr(this)->isString();
+}
+
+bool Value::IsFunction() const
+{
+ return ConstValuePtr(this)->asFunctionObject();
+}
+
+bool Value::IsArray() const
+{
+ return ConstValuePtr(this)->asArrayObject();
+}
+
+bool Value::IsObject() const
+{
+ return ConstValuePtr(this)->isObject();
+}
+
+bool Value::IsBoolean() const
+{
+ return ConstValuePtr(this)->isBoolean();
+}
+
+bool Value::IsNumber() const
+{
+ return ConstValuePtr(this)->isNumber();
+}
+
+bool Value::IsExternal() const
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+bool Value::IsInt32() const
+{
+ return ConstValuePtr(this)->isInteger();
+}
+
+bool Value::IsUint32() const
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+bool Value::IsDate() const
+{
+ return ConstValuePtr(this)->asDateObject();
+}
+
+bool Value::IsBooleanObject() const
+{
+ return ConstValuePtr(this)->asBooleanObject();
+}
+
+bool Value::IsNumberObject() const
+{
+ return ConstValuePtr(this)->asNumberObject();
+}
+
+bool Value::IsStringObject() const
+{
+ return ConstValuePtr(this)->asStringObject();
+}
+
+bool Value::IsRegExp() const
+{
+ return ConstValuePtr(this)->asRegExpObject();
+}
+
+bool Value::IsError() const
+{
+ return ConstValuePtr(this)->asErrorObject();
+}
+
+Local<Boolean> Value::ToBoolean() const
+{
+ return Local<Boolean>::New(Value::fromVmValue(VM::Value::fromBoolean(ConstValuePtr(this)->toBoolean())));
+}
+
+Local<Number> Value::ToNumber() const
+{
+ return Local<Number>::New(Value::fromVmValue(VM::Value::fromDouble(ConstValuePtr(this)->toNumber())));
+}
+
+Local<String> Value::ToString() const
+{
+ return Local<String>::New(Value::fromVmValue(VM::Value::fromString(ConstValuePtr(this)->toString(currentEngine()->current))));
+}
+
+Local<Object> Value::ToObject() const
+{
+ return Local<Object>::New(Value::fromVmValue(QQmlJS::VM::Value::fromObject(ConstValuePtr(this)->toObject(currentEngine()->current))));
+}
+
+Local<Integer> Value::ToInteger() const
+{
+ return Local<Integer>::New(Value::fromVmValue(QQmlJS::VM::Value::fromDouble(ConstValuePtr(this)->toInteger())));
+}
+
+Local<Uint32> Value::ToUint32() const
+{
+ return Local<Uint32>::New(Value::fromVmValue(QQmlJS::VM::Value::fromUInt32(ConstValuePtr(this)->toUInt32())));
+}
+
+Local<Int32> Value::ToInt32() const
+{
+ return Local<Int32>::New(Value::fromVmValue(QQmlJS::VM::Value::fromInt32(ConstValuePtr(this)->toInt32())));
+}
+
+Local<Uint32> Value::ToArrayIndex() const
+{
+ return Local<Uint32>::New(Value::fromVmValue(QQmlJS::VM::Value::fromUInt32(ConstValuePtr(this)->asArrayIndex())));
+}
+
+bool Value::BooleanValue() const
+{
+ return ConstValuePtr(this)->toBoolean();
+}
+
+double Value::NumberValue() const
+{
+ return ConstValuePtr(this)->asDouble();
+}
+
+int64_t Value::IntegerValue() const
+{
+ return (int64_t)ConstValuePtr(this)->toInteger();
+}
+
+uint32_t Value::Uint32Value() const
+{
+ return ConstValuePtr(this)->toUInt32();
+}
+
+int32_t Value::Int32Value() const
+{
+ return ConstValuePtr(this)->toInt32();
+}
+
+bool Value::Equals(Handle<Value> that) const
+{
+ return __qmljs_equal(*ConstValuePtr(this), *ConstValuePtr(&that));
+}
+
+bool Value::StrictEquals(Handle<Value> that) const
+{
+ return __qmljs_strict_equal(*ConstValuePtr(this), *ConstValuePtr(&that));
+}
+
+VM::Value Value::vmValue() const
+{
+ return *ConstValuePtr(this);
+}
+
+Handle<Value> Value::fromVmValue(const VM::Value &vmValue)
+{
+ Handle<Value> res;
+ res.val = vmValue.val;
+ return res;
+}
+
+
+bool Boolean::Value() const
+{
+ return BooleanValue();
+}
+
+Handle<Boolean> Boolean::New(bool value)
+{
+ return Value::fromVmValue(VM::Value::fromBoolean(value));
+}
+
+
+int String::Length() const
+{
+ return asVMString()->toQString().length();
+}
+
+uint32_t String::Hash() const
+{
+ return asVMString()->hashValue();
+}
+
+
+String::CompleteHashData String::CompleteHash() const
+{
+ VM::String *s = asVMString();
+ CompleteHashData data;
+ data.hash = s->hashValue();
+ data.length = s->toQString().length();
+ data.symbol_id = s->identifier;
+ return data;
+}
+
+uint32_t String::ComputeHash(uint16_t *string, int length)
+{
+ return VM::String::createHashValue(reinterpret_cast<const QChar *>(string), length);
+}
+
+uint32_t String::ComputeHash(char *string, int length)
+{
+ // ### unefficient
+ QString s = QString::fromLatin1((char *)string, length);
+ return VM::String::createHashValue(s.constData(), s.length());
+}
+
+bool String::Equals(uint16_t *str, int length)
+{
+ return asQString() == QString(reinterpret_cast<QChar*>(str), length);
+}
+
+bool String::Equals(char *str, int length)
+{
+ return asQString() == QString::fromLatin1(str, length);
+}
+
+uint16_t String::GetCharacter(int index)
+{
+ return asQString().at(index).unicode();
+}
+
+int String::Write(uint16_t *buffer, int start, int length, int options) const
+{
+ if (length < 0)
+ length = asQString().length();
+ if (length == 0)
+ return 0;
+ if (asQString().length() < length)
+ length = asQString().length();
+ // ### do we use options?
+ memcpy(buffer + start, asQString().constData(), length*sizeof(QChar));
+ return length;
+}
+
+v8::Local<String> String::Empty()
+{
+ return Local<String>::New(v8::Value::fromVmValue(VM::Value::fromString(currentEngine()->current, QString())));
+}
+
+bool String::IsExternal() const
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+String::ExternalStringResource *String::GetExternalStringResource() const
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+String *String::Cast(v8::Value *obj)
+{
+ return static_cast<String *>(obj);
+}
+
+
+Local<String> String::New(const char *data, int length)
+{
+ QQmlJS::VM::Value v = QQmlJS::VM::Value::fromString(currentEngine()->current, QString::fromLatin1(data, length));
+ return Local<String>::New(v8::Value::fromVmValue(v));
+}
+
+Local<String> String::New(const uint16_t *data, int length)
+{
+ QQmlJS::VM::Value v = QQmlJS::VM::Value::fromString(currentEngine()->current, QString((const QChar *)data, length));
+ return Local<String>::New(v8::Value::fromVmValue(v));
+}
+
+Local<String> String::NewSymbol(const char *data, int length)
+{
+ QString str = QString::fromLatin1(data, length);
+ VM::String *vmString = currentEngine()->newIdentifier(str);
+ return New(vmString);
+}
+
+Local<String> String::New(VM::String *s)
+{
+ return Local<String>::New(v8::Value::fromVmValue(VM::Value::fromString(s)));
+}
+
+Local<String> String::NewExternal(String::ExternalStringResource *resource)
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+QString String::asQString() const
+{
+ return asVMString()->toQString();
+}
+
+VM::String *String::asVMString() const
+{
+ const VM::Value *v = ConstValuePtr(this);
+ ASSERT(v->isString());
+ return v->stringValue();
+}
+
+String::AsciiValue::AsciiValue(Handle<v8::Value> obj)
+{
+ str = obj->ToString()->asQString().toLatin1();
+}
+
+String::Value::Value(Handle<v8::Value> obj)
+{
+ str = obj->ToString()->asQString();
+}
+
+
+double Number::Value() const
+{
+ const VM::Value *v = ConstValuePtr(this);
+ assert(v->isNumber());
+ return v->asDouble();
+}
+
+Local<Number> Number::New(double value)
+{
+ return Local<Number>::New(Value::fromVmValue(VM::Value::fromDouble(value)));
+}
+
+Number *Number::Cast(v8::Value *obj)
+{
+ return static_cast<Number *>(obj);
+}
+
+Local<Integer> Integer::New(int32_t value)
+{
+ return Local<Integer>::New(Value::fromVmValue(VM::Value::fromInt32(value)));
+}
+
+Local<Integer> Integer::NewFromUnsigned(uint32_t value)
+{
+ return Local<Integer>::New(Value::fromVmValue(VM::Value::fromUInt32(value)));
+}
+
+Local<Integer> Integer::New(int32_t value, Isolate *)
+{
+ return New(value);
+}
+
+Local<Integer> Integer::NewFromUnsigned(uint32_t value, Isolate *)
+{
+ return NewFromUnsigned(value);
+}
+
+int64_t Integer::Value() const
+{
+ const VM::Value *v = ConstValuePtr(this);
+ assert(v->isNumber());
+ return (int64_t)v->asDouble();
+}
+
+Integer *Integer::Cast(v8::Value *obj)
+{
+ return static_cast<Integer *>(obj);
+}
+
+int32_t Int32::Value() const
+{
+ const VM::Value *v = ConstValuePtr(this);
+ assert(v->isInteger());
+ return v->int_32;
+}
+
+uint32_t Uint32::Value() const
+{
+ const VM::Value *v = ConstValuePtr(this);
+ assert(v->isNumber());
+ return v->toUInt32();
+}
+
+
+struct ExternalResourceWrapper : public QQmlJS::VM::Object::ExternalResource
+{
+ ExternalResourceWrapper(v8::Object::ExternalResource *wrapped)
+ {
+ this->wrapped = wrapped;
+ }
+
+ virtual ~ExternalResourceWrapper()
+ {
+ wrapped->Dispose();
+ }
+
+ v8::Object::ExternalResource *wrapped;
+};
+
+
+bool Object::Set(Handle<Value> key, Handle<Value> value, PropertyAttribute attribs)
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+ QQmlJS::VM::ExecutionContext *ctx = currentEngine()->current;
+ bool result = true;
+ try {
+ o->put(ctx, ValuePtr(&key)->toString(ctx), *ValuePtr(&value));
+ // ### attribs
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(ctx);
+ result = false;
+ }
+ return result;
+}
+
+bool Object::Set(uint32_t index, Handle<Value> value)
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+ QQmlJS::VM::ExecutionContext *ctx = currentEngine()->current;
+ bool result = true;
+ try {
+ o->putIndexed(ctx, index, *ValuePtr(&value));
+ // ### attribs
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(ctx);
+ result = false;
+ }
+ return result;
+}
+
+Local<Value> Object::Get(Handle<Value> key)
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+ QQmlJS::VM::ExecutionContext *ctx = currentEngine()->current;
+ QQmlJS::VM::Value prop = VM::Value::undefinedValue();
+ try {
+ prop = o->get(ctx, ValuePtr(&key)->toString(ctx));
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(ctx);
+ }
+ return Local<Value>::New(Value::fromVmValue(prop));
+}
+
+Local<Value> Object::Get(uint32_t key)
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+ QQmlJS::VM::ExecutionContext *ctx = currentEngine()->current;
+ QQmlJS::VM::Value prop = VM::Value::undefinedValue();
+ try {
+ prop = o->getIndexed(ctx, key);
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(ctx);
+ }
+ return Local<Value>::New(Value::fromVmValue(prop));
+}
+
+bool Object::Has(Handle<String> key)
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+ return o->__hasProperty__(ValuePtr(&key)->asString());
+}
+
+bool Object::Delete(Handle<String> key)
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+ bool result = false;
+ ExecutionContext *ctx = currentEngine()->current;
+ try {
+ result = o->deleteProperty(ctx, ValuePtr(&key)->asString());
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(ctx);
+ }
+ return result;
+}
+
+bool Object::Has(uint32_t index)
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ if (!o)
+ return false;
+ return o->__hasProperty__(index);
+}
+
+bool Object::Delete(uint32_t index)
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+ ExecutionContext *ctx = currentEngine()->current;
+ bool result = false;
+ try {
+ result = o->deleteIndexedProperty(ctx, index);
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(ctx);
+ }
+ return result;
+}
+
+bool Object::SetAccessor(Handle<String> name, AccessorGetter getter, AccessorSetter setter, Handle<Value> data, AccessControl settings, PropertyAttribute attribute)
+{
+ VM::ExecutionEngine *engine = currentEngine();
+
+ VM::FunctionObject *wrappedGetter = 0;
+ if (getter) {
+ wrappedGetter = new (engine->memoryManager) V8AccessorGetter(engine->rootContext, name, getter, data);
+ }
+ VM::FunctionObject *wrappedSetter = 0;
+ if (setter) {
+ wrappedSetter = new (engine->memoryManager) V8AccessorSetter(engine->rootContext, name, setter, data);
+ }
+
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+ PropertyAttributes attrs = Attr_Accessor;
+ attrs.setConfigurable(!(attribute & DontDelete));
+ attrs.setEnumerable(!(attribute & DontEnum));
+ VM::Property *pd = o->insertMember(name->asVMString(), attrs);
+ pd->setGetter(wrappedGetter);
+ pd->setSetter(wrappedSetter);
+ return true;
+}
+
+Local<Array> Object::GetPropertyNames()
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+
+ VM::ArrayObject *array = currentEngine()->newArrayObject(currentEngine()->current)->asArrayObject();
+ ObjectIterator it(currentEngine()->current, o, ObjectIterator::WithProtoChain|ObjectIterator::EnumberableOnly);
+ while (1) {
+ VM::Value v = it.nextPropertyNameAsString();
+ if (v.isNull())
+ break;
+ array->push_back(v);
+ }
+ return Local<Array>::New(Value::fromVmValue(VM::Value::fromObject(array)));
+}
+
+Local<Array> Object::GetOwnPropertyNames()
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+ VM::Value arg = VM::Value::fromObject(o);
+ ArrayObject *array = currentEngine()->newArrayObject(currentEngine()->current)->asArrayObject();
+ ObjectIterator it(currentEngine()->current, o, ObjectIterator::EnumberableOnly);
+ while (1) {
+ VM::Value v = it.nextPropertyNameAsString();
+ if (v.isNull())
+ break;
+ array->push_back(v);
+ }
+ return Local<Array>::New(Value::fromVmValue(VM::Value::fromObject(array)));
+}
+
+Local<Value> Object::GetPrototype()
+{
+ Local<Value> result;
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+ return Local<Value>::New(Value::fromVmValue(QQmlJS::VM::Value::fromObject(o->prototype)));
+}
+
+bool Object::SetPrototype(Handle<Value> prototype)
+{
+ QQmlJS::VM::Object *p = ConstValuePtr(&prototype)->asObject();
+ if (!p)
+ return false;
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+ o->prototype = p;
+ return true;
+}
+
+Local<Value> Object::GetInternalField(int index)
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+void Object::SetInternalField(int index, Handle<Value> value)
+{
+ Q_UNIMPLEMENTED();
+}
+
+void Object::SetExternalResource(Object::ExternalResource *resource)
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ if (!o)
+ return;
+ o->externalResource = new ExternalResourceWrapper(resource);
+}
+
+Object::ExternalResource *Object::GetExternalResource()
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ if (!o || !o->externalResource)
+ return 0;
+ return static_cast<ExternalResourceWrapper*>(o->externalResource)->wrapped;
+}
+
+bool Object::HasOwnProperty(Handle<String> key)
+{
+ QQmlJS::VM::Object *o = ConstValuePtr(this)->asObject();
+ assert(o);
+ QQmlJS::VM::ExecutionContext *ctx = currentEngine()->current;
+ return o->__getOwnProperty__(ValuePtr(&key)->toString(ctx));
+}
+
+int Object::GetIdentityHash()
+{
+ return (quintptr)ConstValuePtr(this)->asObject() >> 2;
+}
+
+bool Object::SetHiddenValue(Handle<String> key, Handle<Value> value)
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+Local<Value> Object::GetHiddenValue(Handle<String> key)
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+Local<Object> Object::Clone()
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+bool Object::IsCallable()
+{
+ return ConstValuePtr(this)->asFunctionObject();
+}
+
+Local<Value> Object::CallAsFunction(Handle<Object> recv, int argc, Handle<Value> argv[])
+{
+ VM::FunctionObject *f = ConstValuePtr(this)->asFunctionObject();
+ if (!f)
+ return Local<Value>();
+ VM::Value retval = f->call(currentEngine()->current, recv->vmValue(),
+ reinterpret_cast<QQmlJS::VM::Value*>(argv),
+ argc);
+ return Local<Value>::New(Value::fromVmValue(retval));
+}
+
+Local<Value> Object::CallAsConstructor(int argc, Handle<Value> argv[])
+{
+ VM::FunctionObject *f = ConstValuePtr(this)->asFunctionObject();
+ if (!f)
+ return Local<Value>();
+ VM::Value retval = f->construct(currentEngine()->current,
+ reinterpret_cast<QQmlJS::VM::Value*>(argv),
+ argc);
+ return Local<Value>::New(Value::fromVmValue(retval));
+}
+
+Local<Object> Object::New()
+{
+ VM::Object *o = currentEngine()->newObject();
+ return Local<Object>::New(Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+Object *Object::Cast(Value *obj)
+{
+ return static_cast<Object *>(obj);
+}
+
+
+uint32_t Array::Length() const
+{
+ VM::ArrayObject *a = ConstValuePtr(this)->asArrayObject();
+ if (!a)
+ return 0;
+ return a->arrayLength();
+}
+
+Local<Array> Array::New(int length)
+{
+ VM::ArrayObject *a = currentEngine()->newArrayObject(currentEngine()->current);
+ if (length < 0x1000)
+ a->arrayReserve(length);
+
+ return Local<Array>::New(Value::fromVmValue(VM::Value::fromObject(a)));
+}
+
+Array *Array::Cast(Value *obj)
+{
+ return static_cast<Array *>(obj);
+}
+
+
+Local<Object> Function::NewInstance() const
+{
+ VM::FunctionObject *f = ConstValuePtr(this)->asFunctionObject();
+ assert(f);
+ VM::ExecutionContext *context = currentEngine()->current;
+ QQmlJS::VM::Value result = VM::Value::undefinedValue();
+ try {
+ result = f->construct(context, 0, 0);
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(context);
+ }
+ return Local<Object>::New(Value::fromVmValue(result));
+}
+
+Local<Object> Function::NewInstance(int argc, Handle<Value> argv[]) const
+{
+ VM::FunctionObject *f = ConstValuePtr(this)->asFunctionObject();
+ assert(f);
+ VM::ExecutionContext *context = currentEngine()->current;
+ QQmlJS::VM::Value result = VM::Value::undefinedValue();
+ try {
+ result = f->construct(context, reinterpret_cast<QQmlJS::VM::Value*>(argv), argc);
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(context);
+ }
+ return Local<Object>::New(Value::fromVmValue(result));
+}
+
+Local<Value> Function::Call(Handle<Object> thisObj, int argc, Handle<Value> argv[])
+{
+ QQmlJS::VM::FunctionObject *f = ConstValuePtr(this)->asFunctionObject();
+ if (!f)
+ return Local<Value>();
+ VM::ExecutionContext *context = currentEngine()->current;
+ QQmlJS::VM::Value result = VM::Value::undefinedValue();
+ try {
+ result = f->call(context, *ConstValuePtr(&thisObj),
+ reinterpret_cast<QQmlJS::VM::Value*>(argv), argc);
+ } catch (VM::Exception &e) {
+ Isolate::GetCurrent()->setException(e.value());
+ e.accept(context);
+ }
+ return Local<Value>::New(Value::fromVmValue(result));
+}
+
+Handle<Value> Function::GetName() const
+{
+ QQmlJS::VM::FunctionObject *f = ConstValuePtr(this)->asFunctionObject();
+ if (!f)
+ return Handle<Value>();
+ return Value::fromVmValue(VM::Value::fromString(f->name));
+}
+
+ScriptOrigin Function::GetScriptOrigin() const
+{
+ Q_UNIMPLEMENTED();
+ return ScriptOrigin();
+}
+
+Function *Function::Cast(Value *obj)
+{
+ return static_cast<Function *>(obj);
+}
+
+
+Local<Value> Date::New(double time)
+{
+ VM::Object *o = currentEngine()->newDateObject(VM::Value::fromDouble(time));
+ return Local<Value>::New(Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+double Date::NumberValue() const
+{
+ DateObject *d = ConstValuePtr(this)->asDateObject();
+ assert(d);
+ return d->value.doubleValue();
+}
+
+Date *Date::Cast(Value *obj)
+{
+ return static_cast<Date *>(obj);
+}
+
+void Date::DateTimeConfigurationChangeNotification()
+{
+ Q_UNIMPLEMENTED();
+}
+
+
+Local<Value> NumberObject::New(double value)
+{
+ VM::Object *o = currentEngine()->newNumberObject(VM::Value::fromDouble(value));
+ return Local<Value>::New(Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+double NumberObject::NumberValue() const
+{
+ VM::NumberObject *n = ConstValuePtr(this)->asNumberObject();
+ assert(n);
+ return n->value.doubleValue();
+}
+
+NumberObject *NumberObject::Cast(Value *obj)
+{
+ return static_cast<NumberObject *>(obj);
+}
+
+Local<Value> BooleanObject::New(bool value)
+{
+ VM::Object *o = currentEngine()->newBooleanObject(VM::Value::fromBoolean(value));
+ return Local<Value>::New(Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+bool BooleanObject::BooleanValue() const
+{
+ VM::BooleanObject *b = ConstValuePtr(this)->asBooleanObject();
+ assert(b);
+ return b->value.booleanValue();
+}
+
+BooleanObject *BooleanObject::Cast(Value *obj)
+{
+ return static_cast<BooleanObject *>(obj);
+}
+
+Local<Value> StringObject::New(Handle<String> value)
+{
+ VM::Object *o = currentEngine()->newStringObject(currentEngine()->current, VM::Value::fromString(value->vmValue().asString()));
+ return Local<Value>::New(Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+Local<String> StringObject::StringValue() const
+{
+ VM::StringObject *s = ConstValuePtr(this)->asStringObject();
+ assert(s);
+ return Local<String>::New(Value::fromVmValue(s->value));
+}
+
+StringObject *StringObject::Cast(Value *obj)
+{
+ return static_cast<StringObject *>(obj);
+}
+
+Local<RegExp> RegExp::New(Handle<String> pattern, RegExp::Flags flags)
+{
+ int f = 0;
+ if (flags & kGlobal)
+ f |= V4IR::RegExp::RegExp_Global;
+ if (flags & kIgnoreCase)
+ f |= V4IR::RegExp::RegExp_IgnoreCase;
+ if (flags & kMultiline)
+ f |= V4IR::RegExp::RegExp_Multiline;
+ VM::Object *o = currentEngine()->newRegExpObject(pattern->asQString(), f);
+ return Local<RegExp>::New(Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+Local<String> RegExp::GetSource() const
+{
+ RegExpObject *re = ConstValuePtr(this)->asRegExpObject();
+ assert(re);
+ return Local<String>::New(Value::fromVmValue(VM::Value::fromString(currentEngine()->current, re->value->pattern())));
+}
+
+RegExp::Flags RegExp::GetFlags() const
+{
+ RegExpObject *re = ConstValuePtr(this)->asRegExpObject();
+ assert(re);
+
+ int f = 0;
+ if (re->global)
+ f |= kGlobal;
+ if (re->value->ignoreCase())
+ f |= kIgnoreCase;
+ if (re->value->multiLine())
+ f |= kMultiline;
+
+ return (RegExp::Flags)f;
+}
+
+RegExp *RegExp::Cast(Value *obj)
+{
+ return static_cast<RegExp *>(obj);
+}
+
+struct VoidStarWrapper : public VM::Object::ExternalResource
+{
+ void *data;
+};
+
+Local<Value> External::Wrap(void *data)
+{
+ return New(data);
+}
+
+void *External::Unwrap(Handle<v8::Value> obj)
+{
+ return obj.As<External>()->Value();
+}
+
+Local<External> External::New(void *value)
+{
+ VM::Object *o = currentEngine()->newObject();
+ VoidStarWrapper *wrapper = new VoidStarWrapper;
+ wrapper->data = value;
+ o->externalResource = wrapper;
+ return Local<v8::External>::New(v8::Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+External *External::Cast(v8::Value *obj)
+{
+ return static_cast<External *>(obj);
+}
+
+void *External::Value() const
+{
+ VM::Object *o = ConstValuePtr(this)->asObject();
+ if (!o || !o->externalResource)
+ return 0;
+ return static_cast<VoidStarWrapper*>(o->externalResource)->data;
+}
+
+
+void Template::Set(Handle<String> name, Handle<Value> value, PropertyAttribute attributes)
+{
+ Property p;
+ p.name = Persistent<String>::New(name);
+ p.value = Persistent<Value>::New(value);
+ p.attributes = attributes;
+ m_properties << p;
+}
+
+void Template::Set(const char *name, Handle<Value> value)
+{
+ Set(String::New(name), value);
+}
+
+
+Arguments::Arguments(const VM::Value *args, int argc, const VM::Value &thisObject, bool isConstructor, const Persistent<Value> &data)
+{
+ for (int i = 0; i < argc; ++i)
+ m_args << Persistent<Value>::New(Value::fromVmValue(args[i]));
+ m_thisObject = Persistent<Object>::New(Value::fromVmValue(thisObject));
+ m_isConstructor = isConstructor;
+ m_data = Persistent<Value>::New(data);
+}
+
+int Arguments::Length() const
+{
+ return m_args.size();
+}
+
+Local<Value> Arguments::operator [](int i) const
+{
+ return Local<Value>::New(m_args.at(i));
+}
+
+Local<Object> Arguments::This() const
+{
+ return Local<Object>::New(m_thisObject);
+}
+
+Local<Object> Arguments::Holder() const
+{
+ // ### FIXME.
+ return Local<Object>::New(m_thisObject);
+}
+
+bool Arguments::IsConstructCall() const
+{
+ return m_isConstructor;
+}
+
+Local<Value> Arguments::Data() const
+{
+ return Local<Value>::New(m_data);
+}
+
+Isolate *Arguments::GetIsolate() const
+{
+ return Isolate::GetCurrent();
+}
+
+
+AccessorInfo::AccessorInfo(const VM::Value &thisObject, const Persistent<Value> &data)
+{
+ m_this = Persistent<Object>::New(Value::fromVmValue(thisObject));
+ m_data = data;
+}
+
+Isolate *AccessorInfo::GetIsolate() const
+{
+ return Isolate::GetCurrent();
+}
+
+Local<Value> AccessorInfo::Data() const
+{
+ return Local<Value>::New(m_data);
+}
+
+Local<Object> AccessorInfo::This() const
+{
+ return Local<Object>::New(m_this);
+}
+
+Local<Object> AccessorInfo::Holder() const
+{
+ // ### FIXME
+ return Local<Object>::New(m_this);
+}
+
+template <typename BaseClass>
+class V4V8Object : public BaseClass
+{
+public:
+ V4V8Object(VM::ExecutionEngine *engine, ObjectTemplate *tmpl)
+ : BaseClass(engine->rootContext)
+ {
+ this->vtbl = &static_vtbl;
+ m_template = Persistent<ObjectTemplate>(tmpl);
+ if (m_template.IsEmpty())
+ m_template = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
+
+ foreach (const ObjectTemplate::Accessor &acc, m_template->m_accessors) {
+ PropertyAttributes attrs = Attr_Accessor;
+ attrs.setConfigurable(!(acc.attribute & DontDelete));
+ attrs.setEnumerable(!(acc.attribute & DontEnum));
+ VM::Property *pd = this->insertMember(acc.name->asVMString(), attrs);
+ *pd = VM::Property::fromAccessor(acc.getter->vmValue().asFunctionObject(),
+ acc.setter->vmValue().asFunctionObject());
+ }
+
+ initProperties(m_template.get());
+ }
+
+ void initProperties(Template *tmpl)
+ {
+ foreach (const Template::Property &p, tmpl->m_properties) {
+ PropertyAttributes attrs = Attr_Data;
+ attrs.setConfigurable(!(p.attributes & DontDelete));
+ attrs.setEnumerable(!(p.attributes & DontEnum));
+ attrs.setWritable(!(p.attributes & ReadOnly));
+ VM::Property *pd = this->insertMember(p.name->asVMString(), attrs);
+ *pd = VM::Property::fromValue(p.value->vmValue());
+ }
+ }
+
+ Persistent<ObjectTemplate> m_template;
+
+protected:
+ AccessorInfo namedAccessorInfo()
+ {
+ // ### thisObject?
+ return AccessorInfo(VM::Value::fromObject(this), m_template->m_namedPropertyData);
+ }
+ AccessorInfo fallbackAccessorInfo()
+ {
+ // ### thisObject?
+ return AccessorInfo(VM::Value::fromObject(this), m_template->m_fallbackPropertyData);
+ }
+ AccessorInfo indexedAccessorInfo()
+ {
+ // ### thisObject?
+ return AccessorInfo(VM::Value::fromObject(this), m_template->m_namedPropertyData);
+ }
+
+ static const ManagedVTable static_vtbl;
+
+ static VM::Value get(VM::Managed *m, ExecutionContext *ctx, VM::String *name, bool *hasProperty)
+ {
+ V4V8Object *that = static_cast<V4V8Object*>(m);
+ if (that->m_template->m_namedPropertyGetter) {
+ Handle<Value> result = that->m_template->m_namedPropertyGetter(String::New(name), that->namedAccessorInfo());
+ if (!result.IsEmpty()) {
+ if (hasProperty)
+ *hasProperty = true;
+ return result->vmValue();
+ }
+ }
+
+ bool hasProp = false;
+ VM::Value result = BaseClass::get(m, ctx, name, &hasProp);
+
+ if (!hasProp && that->m_template->m_fallbackPropertyGetter) {
+ Handle<Value> fallbackResult = that->m_template->m_fallbackPropertyGetter(String::New(name), that->fallbackAccessorInfo());
+ if (!fallbackResult.IsEmpty()) {
+ if (hasProperty)
+ *hasProperty = true;
+ return fallbackResult->vmValue();
+ }
+ }
+
+ if (hasProperty)
+ *hasProperty = hasProp;
+ return result;
+ }
+
+ static VM::Value getIndexed(VM::Managed *m, ExecutionContext *ctx, uint index, bool *hasProperty)
+ {
+ V4V8Object *that = static_cast<V4V8Object*>(m);
+ if (that->m_template->m_indexedPropertyGetter) {
+ Handle<Value> result = that->m_template->m_indexedPropertyGetter(index, that->indexedAccessorInfo());
+ if (!result.IsEmpty()) {
+ if (hasProperty)
+ *hasProperty = true;
+ return result->vmValue();
+ }
+ }
+ return BaseClass::getIndexed(m, ctx, index, hasProperty);
+ }
+
+ static void put(VM::Managed *m, ExecutionContext *ctx, VM::String *name, const VM::Value &value)
+ {
+ Local<Value> v8Value = Local<Value>::New(Value::fromVmValue(value));
+ V4V8Object *that = static_cast<V4V8Object*>(m);
+ if (that->m_template->m_namedPropertySetter) {
+ Handle<Value> result = that->m_template->m_namedPropertySetter(String::New(name), v8Value, that->namedAccessorInfo());
+ if (!result.IsEmpty())
+ return;
+ }
+ PropertyAttributes attrs;
+ Property *pd = that->__getOwnProperty__(name, &attrs);
+ if (pd)
+ that->putValue(ctx, pd, attrs, value);
+ else if (that->m_template->m_fallbackPropertySetter)
+ that->m_template->m_fallbackPropertySetter(String::New(name), v8Value, that->fallbackAccessorInfo());
+ else
+ BaseClass::put(m, ctx, name, value);
+ }
+
+ static void putIndexed(VM::Managed *m, ExecutionContext *ctx, uint index, const VM::Value &value)
+ {
+ V4V8Object *that = static_cast<V4V8Object*>(m);
+ if (that->m_template->m_indexedPropertySetter) {
+ Handle<Value> result = that->m_template->m_indexedPropertySetter(index, Local<Value>::New(Value::fromVmValue(value)), that->indexedAccessorInfo());
+ if (!result.IsEmpty())
+ return;
+ }
+ BaseClass::putIndexed(m, ctx, index, value);
+ }
+
+ static PropertyAttributes propertyAttributesToFlags(const Handle<Value> &attr)
+ {
+ PropertyAttributes flags;
+ int intAttr = attr->ToInt32()->Value();
+ flags.setWritable(!(intAttr & ReadOnly));
+ flags.setEnumerable(!(intAttr & DontEnum));
+ flags.setConfigurable(!(intAttr & DontDelete));
+ return flags;
+ }
+
+ static PropertyAttributes query(VM::Managed *m, ExecutionContext *ctx, VM::String *name)
+ {
+ V4V8Object *that = static_cast<V4V8Object*>(m);
+ if (that->m_template->m_namedPropertyQuery) {
+ Handle<Value> result = that->m_template->m_namedPropertyQuery(String::New(name), that->namedAccessorInfo());
+ if (!result.IsEmpty())
+ return propertyAttributesToFlags(result);
+ }
+ PropertyAttributes flags = BaseClass::query(m, ctx, name);
+ if (flags.type() == PropertyAttributes::Generic && that->m_template->m_fallbackPropertySetter) {
+ Handle<Value> result = that->m_template->m_fallbackPropertyQuery(String::New(name), that->fallbackAccessorInfo());
+ if (!result.IsEmpty())
+ return propertyAttributesToFlags(result);
+ }
+
+ return flags;
+ }
+
+ static PropertyAttributes queryIndexed(VM::Managed *m, ExecutionContext *ctx, uint index)
+ {
+ V4V8Object *that = static_cast<V4V8Object*>(m);
+ if (that->m_template->m_indexedPropertyQuery) {
+ Handle<Value> result = that->m_template->m_indexedPropertyQuery(index, that->indexedAccessorInfo());
+ if (!result.IsEmpty())
+ return propertyAttributesToFlags(result);
+ }
+
+ return BaseClass::queryIndexed(m, ctx, index);
+ }
+
+ static bool deleteProperty(VM::Managed *m, ExecutionContext *ctx, VM::String *name)
+ {
+ V4V8Object *that = static_cast<V4V8Object*>(m);
+ if (that->m_template->m_namedPropertyDeleter) {
+ Handle<Boolean> result = that->m_template->m_namedPropertyDeleter(String::New(name), that->namedAccessorInfo());
+ if (!result.IsEmpty())
+ return result->Value();
+ }
+
+ bool result = BaseClass::deleteProperty(m, ctx, name);
+
+ if (that->m_template->m_fallbackPropertyDeleter) {
+ Handle<Boolean> interceptResult = that->m_template->m_fallbackPropertyDeleter(String::New(name), that->fallbackAccessorInfo());
+ if (!interceptResult.IsEmpty())
+ result = interceptResult->Value();
+ }
+
+ return result;
+ }
+
+ static bool deleteIndexedProperty(VM::Managed *m, ExecutionContext *ctx, uint index)
+ {
+ V4V8Object *that = static_cast<V4V8Object*>(m);
+ if (that->m_template->m_indexedPropertyDeleter) {
+ Handle<Boolean> result = that->m_template->m_indexedPropertyDeleter(index, that->indexedAccessorInfo());
+ if (!result.IsEmpty())
+ return result->Value();
+ }
+ return BaseClass::deleteIndexedProperty(m, ctx, index);
+ }
+};
+
+template<>
+DEFINE_MANAGED_VTABLE(V4V8Object<VM::Object>);
+template<>
+DEFINE_MANAGED_VTABLE(V4V8Object<VM::FunctionObject>);
+template<>
+DEFINE_MANAGED_VTABLE(V4V8Object<VM::FunctionPrototype>);
+
+struct V4V8Function : public V4V8Object<VM::FunctionObject>
+{
+ V4V8Function(VM::ExecutionEngine *engine, FunctionTemplate *functionTemplate)
+ : V4V8Object<VM::FunctionObject>(engine, 0)
+ {
+ vtbl = &static_vtbl;
+ m_functionTemplate = Persistent<FunctionTemplate>(functionTemplate);
+ initProperties(m_functionTemplate.get());
+ }
+
+protected:
+ static const ManagedVTable static_vtbl;
+
+ static VM::Value call(VM::Managed *m, ExecutionContext *context, const VM::Value &thisObject, VM::Value *args, int argc)
+ {
+ V4V8Function *that = static_cast<V4V8Function*>(m);
+ Arguments arguments(args, argc, thisObject, false, that->m_functionTemplate->m_data);
+ VM::Value result = VM::Value::undefinedValue();
+ if (that->m_functionTemplate->m_callback)
+ result = that->m_functionTemplate->m_callback(arguments)->vmValue();
+ return result;
+ }
+
+ static VM::Value construct(VM::Managed *m, ExecutionContext *context, VM::Value *args, int argc)
+ {
+ V4V8Function *that = static_cast<V4V8Function*>(m);
+ Arguments arguments(args, argc, VM::Value::undefinedValue(), true, that->m_functionTemplate->m_data);
+
+ VM::Object *obj = that->m_functionTemplate->m_instanceTemplate->NewInstance()->vmValue().asObject();
+ VM::Value proto = that->Managed::get(context, context->engine->id_prototype);
+ if (proto.isObject())
+ obj->prototype = proto.objectValue();
+
+ VM::Value result = VM::Value::undefinedValue();
+ if (that->m_functionTemplate->m_callback)
+ result = that->m_functionTemplate->m_callback(arguments)->vmValue();
+ if (result.isObject())
+ return result;
+ return VM::Value::fromObject(obj);
+
+ }
+
+ Persistent<FunctionTemplate> m_functionTemplate;
+};
+
+DEFINE_MANAGED_VTABLE(V4V8Function);
+
+FunctionTemplate::FunctionTemplate(InvocationCallback callback, Handle<Value> data)
+ : m_callback(callback)
+{
+ m_instanceTemplate = Local<ObjectTemplate>();
+ m_prototypeTemplate = Local<ObjectTemplate>();
+ m_data = Persistent<Value>::New(data);
+}
+
+Local<FunctionTemplate> FunctionTemplate::New(InvocationCallback callback, Handle<Value> data)
+{
+ FunctionTemplate *ft = new FunctionTemplate(callback, data);
+ return Local<FunctionTemplate>::New(Handle<FunctionTemplate>(ft));
+}
+
+Local<Function> FunctionTemplate::GetFunction()
+{
+ VM::ExecutionEngine *engine = currentEngine();
+ VM::Object *o = new (engine->memoryManager) V4V8Function(engine, this);
+ VM::Object *proto = new (engine->memoryManager) V4V8Object<VM::FunctionPrototype>(engine, m_prototypeTemplate.get());
+ o->put(engine->current, engine->id_prototype, VM::Value::fromObject(proto));
+ return Local<Function>::New(Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+Local<ObjectTemplate> FunctionTemplate::InstanceTemplate()
+{
+ if (m_instanceTemplate.IsEmpty())
+ m_instanceTemplate = ObjectTemplate::New();
+ return m_instanceTemplate;
+}
+
+Local<ObjectTemplate> FunctionTemplate::PrototypeTemplate()
+{
+ if (m_prototypeTemplate.IsEmpty())
+ m_prototypeTemplate = ObjectTemplate::New();
+ return m_prototypeTemplate;
+}
+
+
+Local<ObjectTemplate> ObjectTemplate::New()
+{
+ ObjectTemplate *ot = new ObjectTemplate;
+ return Local<ObjectTemplate>::New(Handle<ObjectTemplate>(ot));
+}
+
+Local<Object> ObjectTemplate::NewInstance()
+{
+ VM::ExecutionEngine *engine = currentEngine();
+ VM::Object *o = new (engine->memoryManager) V4V8Object<VM::Object>(engine, this);
+ o->prototype = engine->objectPrototype;
+ o->externalComparison = m_useUserComparison;
+
+ return Local<Object>::New(Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+void ObjectTemplate::SetAccessor(Handle<String> name, AccessorGetter getter, AccessorSetter setter, Handle<Value> data, AccessControl settings, PropertyAttribute attribute)
+{
+ VM::ExecutionEngine *engine = currentEngine();
+
+ Accessor a;
+ if (getter) {
+ VM::FunctionObject *wrappedGetter = new (engine->memoryManager) V8AccessorGetter(engine->rootContext, name, getter, data);
+ a.getter = Persistent<Value>::New(Value::fromVmValue(VM::Value::fromObject(wrappedGetter)));
+ }
+ if (setter) {
+ VM::FunctionObject *wrappedSetter = new (engine->memoryManager) V8AccessorSetter(engine->rootContext, name, setter, data);
+ a.setter = Persistent<Value>::New(Value::fromVmValue(VM::Value::fromObject(wrappedSetter)));
+ }
+ a.attribute = attribute;
+ a.name = Persistent<String>::New(name);
+ m_accessors << a;
+}
+
+void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter, NamedPropertySetter setter, NamedPropertyQuery query, NamedPropertyDeleter deleter, NamedPropertyEnumerator enumerator, Handle<Value> data)
+{
+ m_namedPropertyGetter = getter;
+ m_namedPropertySetter = setter;
+ m_namedPropertyQuery = query;
+ m_namedPropertyDeleter = deleter;
+ m_namedPropertyEnumerator = enumerator;
+ m_namedPropertyData = Persistent<Value>::New(data);
+}
+
+void ObjectTemplate::SetFallbackPropertyHandler(NamedPropertyGetter getter, NamedPropertySetter setter, NamedPropertyQuery query, NamedPropertyDeleter deleter, NamedPropertyEnumerator enumerator, Handle<Value> data)
+{
+ m_fallbackPropertyGetter = getter;
+ m_fallbackPropertySetter = setter;
+ m_fallbackPropertyQuery = query;
+ m_fallbackPropertyDeleter = deleter;
+ m_fallbackPropertyEnumerator = enumerator;
+ m_fallbackPropertyData = Persistent<Value>::New(data);
+}
+
+void ObjectTemplate::SetIndexedPropertyHandler(IndexedPropertyGetter getter, IndexedPropertySetter setter, IndexedPropertyQuery query, IndexedPropertyDeleter deleter, IndexedPropertyEnumerator enumerator, Handle<Value> data)
+{
+ m_indexedPropertyGetter = getter;
+ m_indexedPropertySetter = setter;
+ m_indexedPropertyQuery = query;
+ m_indexedPropertyDeleter = deleter;
+ m_indexedPropertyEnumerator = enumerator;
+ m_indexedPropertyData = Persistent<Value>::New(data);
+}
+
+int ObjectTemplate::InternalFieldCount()
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+void ObjectTemplate::SetInternalFieldCount(int value)
+{
+ Q_UNIMPLEMENTED();
+}
+
+bool ObjectTemplate::HasExternalResource()
+{
+ // we always reserve the space for the external resource
+ return true;
+}
+
+void ObjectTemplate::SetHasExternalResource(bool value)
+{
+ // no need for this, we always reserve the space for the external resource
+ Q_UNUSED(value);
+}
+
+void ObjectTemplate::MarkAsUseUserObjectComparison()
+{
+ m_useUserComparison = true;
+}
+
+ObjectTemplate::ObjectTemplate()
+{
+ m_namedPropertyGetter = 0;
+ m_namedPropertySetter = 0;
+ m_namedPropertyQuery = 0;
+ m_namedPropertyDeleter = 0;
+ m_namedPropertyEnumerator = 0;
+
+ m_fallbackPropertyGetter = 0;
+ m_fallbackPropertySetter = 0;
+ m_fallbackPropertyQuery = 0;
+ m_fallbackPropertyDeleter = 0;
+ m_fallbackPropertyEnumerator = 0;
+
+ m_indexedPropertyGetter = 0;
+ m_indexedPropertySetter = 0;
+ m_indexedPropertyQuery = 0;
+ m_indexedPropertyDeleter = 0;
+ m_indexedPropertyEnumerator = 0;
+
+ m_useUserComparison = false;
+}
+
+Handle<Primitive> Undefined()
+{
+ Handle<Primitive> val;
+ val.val = VM::Value::undefinedValue().val;
+ return val;
+}
+
+Handle<Primitive> Null()
+{
+ Handle<Primitive> val;
+ val.val = VM::Value::nullValue().val;
+ return val;
+}
+
+Handle<Boolean> True()
+{
+ Handle<Primitive> val;
+ val.val = VM::Value::fromBoolean(true).val;
+ return val;
+}
+
+Handle<Boolean> False()
+{
+ Handle<Primitive> val;
+ val.val = VM::Value::fromBoolean(false).val;
+ return val;
+}
+
+
+Handle<Value> ThrowException(Handle<Value> exception)
+{
+ __qmljs_throw(currentEngine()->current, exception->vmValue());
+ return Handle<Value>();
+}
+
+
+Local<Value> Exception::ReferenceError(Handle<String> message)
+{
+ Q_UNUSED(message);
+ VM::Object *o = currentEngine()->newReferenceErrorObject(currentEngine()->current, message->ToString()->asQString());
+ return Local<Value>::New(Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+Local<Value> Exception::SyntaxError(Handle<String> message)
+{
+ Q_UNUSED(message);
+ VM::Object *o = currentEngine()->newSyntaxErrorObject(currentEngine()->current, 0);
+ return Local<Value>::New(Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+Local<Value> Exception::TypeError(Handle<String> message)
+{
+ Q_UNUSED(message);
+ VM::Object *o = currentEngine()->newTypeErrorObject(currentEngine()->current, message->ToString()->asQString());
+ return Local<Value>::New(Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+Local<Value> Exception::Error(Handle<String> message)
+{
+ Q_UNUSED(message);
+ VM::Object *o = currentEngine()->newErrorObject(VM::Value::fromString(currentEngine()->current, message->ToString()->asQString()));
+ return Local<Value>::New(Value::fromVmValue(VM::Value::fromObject(o)));
+}
+
+
+static QThreadStorage<Isolate*> currentIsolate;
+
+Isolate::Isolate()
+ : m_lastIsolate(0)
+ , tryCatch(0)
+{
+}
+
+Isolate::~Isolate()
+{
+}
+
+Isolate *Isolate::New()
+{
+ assert(!"Isolate::New()");
+ Q_UNREACHABLE();
+}
+
+void Isolate::Enter()
+{
+ m_lastIsolate = currentIsolate.localData();
+ currentIsolate.localData() = this;
+}
+
+void Isolate::Exit()
+{
+ currentIsolate.localData() = m_lastIsolate;
+ m_lastIsolate = 0;
+}
+
+void Isolate::Dispose()
+{
+ Q_UNIMPLEMENTED();
+}
+
+void Isolate::SetData(void *data)
+{
+ Q_UNIMPLEMENTED();
+}
+
+void *Isolate::GetData()
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+void Isolate::setException(const VM::Value &ex)
+{
+ if (tryCatch) {
+ tryCatch->hasCaughtException = true;
+ tryCatch->exception = Local<Value>::New(Value::fromVmValue(ex));
+ }
+}
+
+Isolate *Isolate::GetCurrent()
+{
+ if (!currentIsolate.hasLocalData())
+ currentIsolate.setLocalData(new Isolate);
+ return currentIsolate.localData();
+}
+
+
+void V8::SetFlagsFromString(const char *, int)
+{
+ // we can safely ignore these
+}
+
+static UserObjectComparisonCallback userObjectComparisonCallback = 0;
+
+static bool v8ExternalResourceComparison(const VM::Value &a, const VM::Value &b)
+{
+ if (!userObjectComparisonCallback)
+ return false;
+ Local<Object> la = Local<Object>::New(Value::fromVmValue(a));
+ Local<Object> lb = Local<Object>::New(Value::fromVmValue(b));
+ return userObjectComparisonCallback(la, lb);
+}
+
+void V8::SetUserObjectComparisonCallbackFunction(UserObjectComparisonCallback callback)
+{
+ userObjectComparisonCallback = callback;
+ currentEngine()->externalResourceComparison = v8ExternalResourceComparison;
+}
+
+void V8::AddGCPrologueCallback(GCPrologueCallback, GCType)
+{
+ // not required currently as we don't have weak Persistent references.
+ // not having them will lead to some leaks in QQmlVMEMetaObejct, but shouldn't matter otherwise
+}
+
+void V8::RemoveGCPrologueCallback(GCPrologueCallback)
+{
+ assert(!"RemoveGCPrologueCallback();");
+}
+
+void V8::AddImplicitReferences(Persistent<Object> parent, Persistent<Value> *children, size_t length)
+{
+ // not required currently as we don't have weak Persistent references.
+ // not having them will lead to some leaks in QQmlVMEMetaObejct, but shouldn't matter otherwise
+ assert(!"AddImplicitReferences();");
+}
+
+bool V8::Initialize()
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+bool V8::Dispose()
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+bool V8::IdleNotification(int hint)
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+void V8::LowMemoryNotification()
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+
+TryCatch::TryCatch()
+{
+ Isolate *i = Isolate::GetCurrent();
+
+ hasCaughtException = false;
+ parent = i->tryCatch;
+ i->tryCatch = this;
+}
+
+TryCatch::~TryCatch()
+{
+ Isolate *i = Isolate::GetCurrent();
+ i->tryCatch = parent;
+}
+
+bool TryCatch::HasCaught() const
+{
+ return hasCaughtException;
+}
+
+Handle<Value> TryCatch::ReThrow()
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+Local<Value> TryCatch::Exception() const
+{
+ return exception;
+}
+
+Local<Message> TryCatch::Message() const
+{
+ Q_UNIMPLEMENTED();
+ return Local<v8::Message>::New(Handle<v8::Message>(new v8::Message(QString(), QString(), 0)));
+}
+
+void TryCatch::Reset()
+{
+ hasCaughtException = false;
+}
+
+
+
+struct Context::Private
+{
+ Private()
+ {
+ engine.reset(new QQmlJS::VM::ExecutionEngine);
+ }
+
+ QScopedPointer<QQmlJS::VM::ExecutionEngine> engine;
+};
+
+Context::Context()
+ : m_lastContext(0)
+ , d(new Private)
+{
+}
+
+Context::~Context()
+{
+ delete d;
+}
+
+Persistent<Context> Context::New(ExtensionConfiguration *extensions, Handle<ObjectTemplate> global_template, Handle<Value> global_object)
+{
+ Context *result = new Context;
+ return Persistent<Context>::New(Handle<Context>(result));
+}
+
+Local<Object> Context::Global()
+{
+ return Local<Object>::New(Value::fromVmValue(VM::Value::fromObject(d->engine->globalObject)));
+}
+
+Local<Context> Context::GetCurrent()
+{
+ return Context::Adopt(Isolate::GetCurrent()->m_contextStack.top());
+}
+
+Local<Context> Context::GetCalling()
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+Local<Object> Context::GetCallingQmlGlobal()
+{
+ VM::ExecutionEngine *engine = GetCurrent()->GetEngine();
+ VM::ExecutionContext *ctx = engine->current;
+ while (ctx && ctx->outer != engine->rootContext)
+ ctx = ctx->outer;
+
+ assert(ctx);
+ if (!ctx->type == ExecutionContext::Type_QmlContext)
+ return Local<Object>();
+
+ return Local<Object>::New(Value::fromVmValue(VM::Value::fromObject(static_cast<CallContext *>(ctx)->activation)));
+}
+
+Local<Value> Context::GetCallingScriptData()
+{
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+}
+
+void Context::Enter()
+{
+ Isolate* iso = Isolate::GetCurrent();
+ iso->m_contextStack.push(this);
+}
+
+void Context::Exit()
+{
+ Isolate::GetCurrent()->m_contextStack.pop();
+}
+
+
+QQmlJS::VM::ExecutionEngine *Context::GetEngine()
+{
+ return d->engine.data();
+}
+
+
+}