aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp60
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h28
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp193
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h161
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4context.cpp224
-rw-r--r--src/qml/jsruntime/qv4context_p.h161
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp9
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h13
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp51
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp95
-rw-r--r--src/qml/jsruntime/qv4engine_p.h47
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h6
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp44
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h14
-rw-r--r--src/qml/jsruntime/qv4function.cpp13
-rw-r--r--src/qml/jsruntime/qv4function_p.h6
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp66
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h28
-rw-r--r--src/qml/jsruntime/qv4global_p.h5
-rw-r--r--src/qml/jsruntime/qv4identifiertable_p.h4
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp58
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h3
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp76
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h18
-rw-r--r--src/qml/jsruntime/qv4managed.cpp1
-rw-r--r--src/qml/jsruntime/qv4managed_p.h7
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp14
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp15
-rw-r--r--src/qml/jsruntime/qv4memberdata_p.h35
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp56
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4object.cpp228
-rw-r--r--src/qml/jsruntime/qv4object_p.h141
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp8
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h2
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp128
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h1
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp21
-rw-r--r--src/qml/jsruntime/qv4persistent_p.h4
-rw-r--r--src/qml/jsruntime/qv4property_p.h15
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp61
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h19
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp299
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h29
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp6
-rw-r--r--src/qml/jsruntime/qv4regexp_p.h2
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp64
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h41
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp14
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp106
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4string.cpp6
-rw-r--r--src/qml/jsruntime/qv4string_p.h2
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp33
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h10
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp29
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h21
-rw-r--r--src/qml/jsruntime/qv4value_p.h3
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4variantobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp44
64 files changed, 1567 insertions, 1300 deletions
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 6ab838c387..0905c2828a 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -48,32 +48,33 @@ DEFINE_OBJECT_VTABLE(ArgumentsObject);
void Heap::ArgumentsObject::init(QV4::CallContext *context)
{
+ ExecutionEngine *v4 = internalClass->engine;
+
Object::init();
fullyCreated = false;
- this->context = context->d();
+ this->context.set(v4, context->d());
Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable());
- ExecutionEngine *v4 = context->engine();
Scope scope(v4);
Scoped<QV4::ArgumentsObject> args(scope, this);
if (context->d()->strictMode) {
Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(v4->id_callee()));
Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(v4->id_caller()));
- *args->propertyData(CalleePropertyIndex + QV4::Object::GetterOffset) = v4->thrower();
- *args->propertyData(CalleePropertyIndex + QV4::Object::SetterOffset) = v4->thrower();
- *args->propertyData(CallerPropertyIndex + QV4::Object::GetterOffset) = v4->thrower();
- *args->propertyData(CallerPropertyIndex + QV4::Object::SetterOffset) = v4->thrower();
+ args->setProperty(CalleePropertyIndex + QV4::Object::GetterOffset, *v4->thrower());
+ args->setProperty(CalleePropertyIndex + QV4::Object::SetterOffset, *v4->thrower());
+ args->setProperty(CallerPropertyIndex + QV4::Object::GetterOffset, *v4->thrower());
+ args->setProperty(CallerPropertyIndex + QV4::Object::SetterOffset, *v4->thrower());
args->arrayReserve(context->argc());
args->arrayPut(0, context->args(), context->argc());
args->d()->fullyCreated = true;
} else {
Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(v4->id_callee()));
- *args->propertyData(CalleePropertyIndex) = context->d()->function->asReturnedValue();
+ args->setProperty(CalleePropertyIndex, context->d()->function);
}
Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(v4->id_length()));
- *args->propertyData(LengthPropertyIndex) = Primitive::fromInt32(context->d()->callData->argc);
+ args->setProperty(LengthPropertyIndex, Primitive::fromInt32(context->d()->callData->argc));
}
void ArgumentsObject::fullyCreate()
@@ -90,9 +91,9 @@ void ArgumentsObject::fullyCreate()
Scoped<MemberData> md(scope, d()->mappedArguments);
if (numAccessors) {
- d()->mappedArguments = md->allocate(scope.engine, numAccessors);
+ d()->mappedArguments.set(scope.engine, md->allocate(scope.engine, numAccessors));
for (uint i = 0; i < numAccessors; ++i) {
- d()->mappedArguments->data[i] = context()->callData->args[i];
+ d()->mappedArguments->values.set(scope.engine, i, context()->callData->args[i]);
arraySet(i, scope.engine->argumentsAccessors + i, Attr_Accessor);
}
}
@@ -108,22 +109,22 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
fullyCreate();
Scope scope(engine);
- Property *pd = arrayData() ? arrayData()->getProperty(index) : 0;
ScopedProperty map(scope);
PropertyAttributes mapAttrs;
+ uint numAccessors = qMin(context()->formalParameterCount(), static_cast<uint>(context()->callData->argc));
bool isMapped = false;
- uint numAccessors = qMin((int)context()->formalParameterCount(), context()->callData->argc);
- if (pd && index < (uint)numAccessors)
- isMapped = arrayData()->attributes(index).isAccessor() &&
- pd->getter() == scope.engine->argumentsAccessors[index].getter();
+ if (arrayData() && index < numAccessors &&
+ arrayData()->attributes(index).isAccessor() &&
+ arrayData()->get(index) == scope.engine->argumentsAccessors[index].getter()->asReturnedValue())
+ isMapped = true;
if (isMapped) {
Q_ASSERT(arrayData());
mapAttrs = arrayData()->attributes(index);
- map->copy(pd, mapAttrs);
+ arrayData()->getProperty(index, map, &mapAttrs);
setArrayAttributes(index, Attr_Data);
- pd = arrayData()->getProperty(index);
- pd->value = d()->mappedArguments->data[index];
+ ArrayData::Index arrayIndex{ arrayData(), arrayData()->mappedIndex(index) };
+ arrayIndex.set(scope.engine, d()->mappedArguments->values[index]);
}
bool strict = engine->current->strictMode;
@@ -141,8 +142,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
if (attrs.isWritable()) {
setArrayAttributes(index, mapAttrs);
- pd = arrayData()->getProperty(index);
- pd->copy(map, mapAttrs);
+ arrayData()->setProperty(engine, index, map);
}
}
@@ -167,18 +167,17 @@ ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *ha
return Encode::undefined();
}
-void ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value)
+bool ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value)
{
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
if (!args->fullyCreated() && index >= static_cast<uint>(args->context()->callData->argc))
args->fullyCreate();
- if (args->fullyCreated()) {
- Object::putIndexed(m, index, value);
- return;
- }
+ if (args->fullyCreated())
+ return Object::putIndexed(m, index, value);
args->context()->callData->args[index] = value;
+ return true;
}
bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index)
@@ -237,17 +236,6 @@ void ArgumentsSetterFunction::call(const Managed *setter, Scope &scope, CallData
scope.result = Encode::undefined();
}
-void ArgumentsObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- ArgumentsObject::Data *o = static_cast<ArgumentsObject::Data *>(that);
- if (o->context)
- o->context->mark(e);
- if (o->mappedArguments)
- o->mappedArguments->mark(e);
-
- Object::markObjects(that, e);
-}
-
uint ArgumentsObject::getLength(const Managed *m)
{
const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m);
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index 0a2ea3b42a..46e1f884e8 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -59,26 +59,35 @@ namespace QV4 {
namespace Heap {
-struct ArgumentsGetterFunction : FunctionObject {
+#define ArgumentsGetterFunctionMembers(class, Member) \
+ Member(class, NoMark, uint, index)
+
+DECLARE_HEAP_OBJECT(ArgumentsGetterFunction, FunctionObject) {
+ DECLARE_MARK_TABLE(ArgumentsGetterFunction);
inline void init(QV4::ExecutionContext *scope, uint index);
- uint index;
};
-struct ArgumentsSetterFunction : FunctionObject {
+#define ArgumentsSetterFunctionMembers(class, Member) \
+ Member(class, NoMark, uint, index)
+
+DECLARE_HEAP_OBJECT(ArgumentsSetterFunction, FunctionObject) {
+ DECLARE_MARK_TABLE(ArgumentsSetterFunction);
inline void init(QV4::ExecutionContext *scope, uint index);
- uint index;
};
-struct ArgumentsObject : Object {
+#define ArgumentsObjectMembers(class, Member) \
+ Member(class, Pointer, CallContext *, context) \
+ Member(class, Pointer, MemberData *, mappedArguments) \
+ Member(class, NoMark, bool, fullyCreated)
+
+DECLARE_HEAP_OBJECT(ArgumentsObject, Object) {
+ DECLARE_MARK_TABLE(ArgumentsObject);
enum {
LengthPropertyIndex = 0,
CalleePropertyIndex = 1,
CallerPropertyIndex = 3
};
void init(QV4::CallContext *context);
- Pointer<CallContext> context;
- bool fullyCreated;
- Pointer<MemberData> mappedArguments;
};
}
@@ -128,10 +137,9 @@ struct ArgumentsObject: Object {
bool defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void putIndexed(Managed *m, uint index, const Value &value);
+ static bool putIndexed(Managed *m, uint index, const Value &value);
static bool deleteIndexedProperty(Managed *m, uint index);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
static uint getLength(const Managed *m);
void fullyCreate();
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 6d1fb62e0a..df9884d84a 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -52,6 +52,7 @@ const QV4::VTable QV4::ArrayData::static_vtbl = {
0,
0,
0,
+ 0,
QV4::ArrayData::IsExecutionContext,
QV4::ArrayData::IsString,
QV4::ArrayData::IsObject,
@@ -130,7 +131,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
if (d->type() < Heap::ArrayData::Sparse) {
offset = d->d()->offset;
- toCopy = d->d()->len;
+ toCopy = d->d()->values.size;
} else {
toCopy = d->alloc();
}
@@ -151,7 +152,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
Heap::SimpleArrayData *n = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
n->init();
n->offset = 0;
- n->len = d ? d->d()->len : 0;
+ n->values.size = d ? d->d()->values.size : 0;
newData = n;
} else {
Heap::SparseArrayData *n = scope.engine->memoryManager->allocManaged<SparseArrayData>(size);
@@ -160,7 +161,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
}
newData->setAlloc(alloc);
newData->setType(newType);
- newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->arrayData + alloc) : 0);
+ newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->values.values + alloc) : 0);
o->setArrayData(newData);
if (d) {
@@ -172,12 +173,14 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
newData->attrs()[i] = Attr_Data;
}
- if (toCopy > d->d()->alloc - offset) {
- uint copyFromStart = toCopy - (d->d()->alloc - offset);
- memcpy(newData->d()->arrayData + toCopy - copyFromStart, d->d()->arrayData, sizeof(Value)*copyFromStart);
+ if (toCopy > d->d()->values.alloc - offset) {
+ uint copyFromStart = toCopy - (d->d()->values.alloc - offset);
+ // no write barrier required here
+ memcpy(newData->d()->values.values + toCopy - copyFromStart, d->d()->values.values, sizeof(Value)*copyFromStart);
toCopy -= copyFromStart;
}
- memcpy(newData->d()->arrayData, d->d()->arrayData + offset, sizeof(Value)*toCopy);
+ // no write barrier required here
+ memcpy(newData->d()->values.values, d->d()->values.values + offset, sizeof(Value)*toCopy);
}
if (newType != Heap::ArrayData::Sparse)
@@ -197,22 +200,22 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
lastFree = &sparse->freeList;
storeValue(lastFree, 0);
for (uint i = 0; i < toCopy; ++i) {
- if (!sparse->arrayData[i].isEmpty()) {
+ if (!sparse->values[i].isEmpty()) {
SparseArrayNode *n = sparse->sparse->insert(i);
n->value = i;
} else {
storeValue(lastFree, i);
- sparse->arrayData[i].setEmpty();
- lastFree = &sparse->arrayData[i].rawValueRef();
+ sparse->values.values[i].setEmpty();
+ lastFree = &sparse->values.values[i].rawValueRef();
}
}
}
- if (toCopy < sparse->alloc) {
- for (uint i = toCopy; i < sparse->alloc; ++i) {
+ if (toCopy < sparse->values.alloc) {
+ for (uint i = toCopy; i < sparse->values.alloc; ++i) {
storeValue(lastFree, i);
- sparse->arrayData[i].setEmpty();
- lastFree = &sparse->arrayData[i].rawValueRef();
+ sparse->values.values[i].setEmpty();
+ lastFree = &sparse->values.values[i].rawValueRef();
}
storeValue(lastFree, UINT_MAX);
}
@@ -235,24 +238,10 @@ void ArrayData::ensureAttributes(Object *o)
ArrayData::realloc(o, Heap::ArrayData::Simple, 0, true);
}
-
-void SimpleArrayData::markObjects(Heap::Base *d, ExecutionEngine *e)
-{
- Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(d);
- uint end = dd->offset + dd->len;
- if (end > dd->alloc) {
- for (uint i = 0; i < end - dd->alloc; ++i)
- dd->arrayData[i].mark(e);
- end = dd->alloc;
- }
- for (uint i = dd->offset; i < end; ++i)
- dd->arrayData[i].mark(e);
-}
-
ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index)
{
const Heap::SimpleArrayData *dd = static_cast<const Heap::SimpleArrayData *>(d);
- if (index >= dd->len)
+ if (index >= dd->values.size)
return Primitive::emptyValue().asReturnedValue();
return dd->data(index).asReturnedValue();
}
@@ -260,13 +249,13 @@ ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index)
bool SimpleArrayData::put(Object *o, uint index, const Value &value)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- Q_ASSERT(index >= dd->len || !dd->attrs || !dd->attrs[index].isAccessor());
+ Q_ASSERT(index >= dd->values.size || !dd->attrs || !dd->attrs[index].isAccessor());
// ### honour attributes
- dd->data(index) = value;
- if (index >= dd->len) {
+ dd->setData(o->engine(), index, value);
+ if (index >= dd->values.size) {
if (dd->attrs)
dd->attrs[index] = Attr_Data;
- dd->len = index + 1;
+ dd->values.size = index + 1;
}
return true;
}
@@ -274,11 +263,11 @@ bool SimpleArrayData::put(Object *o, uint index, const Value &value)
bool SimpleArrayData::del(Object *o, uint index)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (index >= dd->len)
+ if (index >= dd->values.size)
return true;
if (!dd->attrs || dd->attrs[index].isConfigurable()) {
- dd->data(index) = Primitive::emptyValue();
+ dd->setData(o->engine(), index, Primitive::emptyValue());
if (dd->attrs)
dd->attrs[index] = Attr_Data;
return true;
@@ -297,8 +286,8 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
Q_ASSERT(!dd->attrs);
- if (dd->len + n > dd->alloc) {
- realloc(o, Heap::ArrayData::Simple, dd->len + n, false);
+ if (dd->values.size + n > dd->values.alloc) {
+ realloc(o, Heap::ArrayData::Simple, dd->values.size + n, false);
Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Simple);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
@@ -306,70 +295,71 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n)
dd->offset -= n; // there is enough space left in front
} else {
// we need to wrap around, so:
- dd->offset = dd->alloc - // start at the back, but subtract:
+ dd->offset = dd->values.alloc - // start at the back, but subtract:
(n - dd->offset); // the number of items we can put in the free space at the start of the allocated array
}
- dd->len += n;
+ dd->values.size += n;
for (uint i = 0; i < n; ++i)
- dd->data(i) = values[i].asReturnedValue();
+ dd->setData(o->engine(), i, values[i]);
}
ReturnedValue SimpleArrayData::pop_front(Object *o)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
Q_ASSERT(!dd->attrs);
- if (!dd->len)
+ if (!dd->values.size)
return Encode::undefined();
ReturnedValue v = dd->data(0).isEmpty() ? Encode::undefined() : dd->data(0).asReturnedValue();
- dd->offset = (dd->offset + 1) % dd->alloc;
- --dd->len;
+ dd->offset = (dd->offset + 1) % dd->values.alloc;
+ --dd->values.size;
return v;
}
uint SimpleArrayData::truncate(Object *o, uint newLen)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (dd->len < newLen)
+ if (dd->values.size < newLen)
return newLen;
if (!dd->attrs) {
- dd->len = newLen;
+ dd->values.size = newLen;
return newLen;
}
- while (dd->len > newLen) {
- if (!dd->data(dd->len - 1).isEmpty() && !dd->attrs[dd->len - 1].isConfigurable())
- return dd->len;
- --dd->len;
+ while (dd->values.size > newLen) {
+ if (!dd->data(dd->values.size - 1).isEmpty() && !dd->attrs[dd->values.size - 1].isConfigurable())
+ return dd->values.size;
+ --dd->values.size;
}
- return dd->len;
+ return dd->values.size;
}
uint SimpleArrayData::length(const Heap::ArrayData *d)
{
- return d->len;
+ return d->values.size;
}
bool SimpleArrayData::putArray(Object *o, uint index, const Value *values, uint n)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (index + n > dd->alloc) {
+ if (index + n > dd->values.alloc) {
reallocate(o, index + n + 1, false);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
- for (uint i = dd->len; i < index; ++i)
- dd->data(i) = Primitive::emptyValue();
+ QV4::ExecutionEngine *e = o->engine();
+ for (uint i = dd->values.size; i < index; ++i)
+ dd->setData(e, i, Primitive::emptyValue());
for (uint i = 0; i < n; ++i)
- dd->data(index + i) = values[i];
- dd->len = qMax(dd->len, index + n);
+ dd->setData(e, index + i, values[i]);
+ dd->values.size = qMax(dd->values.size, index + n);
return true;
}
void SparseArrayData::free(Heap::ArrayData *d, uint idx)
{
Q_ASSERT(d && d->type == Heap::ArrayData::Sparse);
- Value *v = d->arrayData + idx;
+ Value *v = d->values.values + idx;
if (d->attrs && d->attrs[idx].isAccessor()) {
// double slot, free both. Order is important, so we have a double slot for allocation again afterwards.
v[1].setEmpty(Value::fromReturnedValue(d->freeList).emptyValue());
@@ -382,15 +372,6 @@ void SparseArrayData::free(Heap::ArrayData *d, uint idx)
d->attrs[idx].clear();
}
-
-void SparseArrayData::markObjects(Heap::Base *d, ExecutionEngine *e)
-{
- Heap::SparseArrayData *dd = static_cast<Heap::SparseArrayData *>(d);
- uint l = dd->alloc;
- for (uint i = 0; i < l; ++i)
- dd->arrayData[i].mark(e);
-}
-
Heap::ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttributes)
{
realloc(o, Heap::ArrayData::Sparse, n, enforceAttributes);
@@ -406,32 +387,32 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot)
ReturnedValue *last = &dd->freeList;
while (1) {
if (Value::fromReturnedValue(*last).value() == UINT_MAX) {
- reallocate(o, dd->alloc + 2, true);
+ reallocate(o, dd->values.alloc + 2, true);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
last = &dd->freeList;
Q_ASSERT(Value::fromReturnedValue(*last).value() != UINT_MAX);
}
- Q_ASSERT(dd->arrayData[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value());
- if (dd->arrayData[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) {
+ Q_ASSERT(dd->values[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value());
+ if (dd->values[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) {
// found two slots in a row
uint idx = Value::fromReturnedValue(*last).emptyValue();
Value lastV = Value::fromReturnedValue(*last);
- lastV.setEmpty(dd->arrayData[lastV.emptyValue() + 1].value());
+ lastV.setEmpty(dd->values[lastV.emptyValue() + 1].value());
*last = lastV.rawValue();
dd->attrs[idx] = Attr_Accessor;
return idx;
}
- last = &dd->arrayData[Value::fromReturnedValue(*last).value()].rawValueRef();
+ last = &dd->values.values[Value::fromReturnedValue(*last).value()].rawValueRef();
}
} else {
if (Value::fromReturnedValue(dd->freeList).value() == UINT_MAX) {
- reallocate(o, dd->alloc + 1, false);
+ reallocate(o, dd->values.alloc + 1, false);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
uint idx = Value::fromReturnedValue(dd->freeList).value();
Q_ASSERT(idx != UINT_MAX);
- dd->freeList = dd->arrayData[idx].asReturnedValue();
+ dd->freeList = dd->values[idx].asReturnedValue();
Q_ASSERT(Value::fromReturnedValue(dd->freeList).isEmpty());
if (dd->attrs)
dd->attrs[idx] = Attr_Data;
@@ -445,7 +426,7 @@ ReturnedValue SparseArrayData::get(const Heap::ArrayData *d, uint index)
index = s->mappedIndex(index);
if (index == UINT_MAX)
return Primitive::emptyValue().asReturnedValue();
- return s->arrayData[index].asReturnedValue();
+ return s->values[index].asReturnedValue();
}
bool SparseArrayData::put(Object *o, uint index, const Value &value)
@@ -459,7 +440,7 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value)
if (n->value == UINT_MAX)
n->value = allocate(o);
s = o->d()->arrayData.cast<Heap::SparseArrayData>();
- s->arrayData[n->value] = value;
+ s->setArrayData(o->engine(), n->value, value);
if (s->attrs)
s->attrs[n->value] = Attr_Data;
return true;
@@ -474,7 +455,7 @@ bool SparseArrayData::del(Object *o, uint index)
return true;
uint pidx = n->value;
- Q_ASSERT(!dd->arrayData[pidx].isEmpty());
+ Q_ASSERT(!dd->values[pidx].isEmpty());
bool isAccessor = false;
if (dd->attrs) {
@@ -487,11 +468,11 @@ bool SparseArrayData::del(Object *o, uint index)
if (isAccessor) {
// free up both indices
- dd->arrayData[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
- dd->arrayData[pidx].setEmpty(pidx + 1);
+ dd->values.values[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
+ dd->values.values[pidx].setEmpty(pidx + 1);
} else {
Q_ASSERT(dd->type == Heap::ArrayData::Sparse);
- dd->arrayData[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
+ dd->values.values[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
}
dd->freeList = Primitive::emptyValue(pidx).asReturnedValue();
@@ -520,10 +501,10 @@ void SparseArrayData::push_front(Object *o, const Value *values, uint n)
{
Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>();
Q_ASSERT(!d->attrs);
- for (int i = n - 1; i >= 0; --i) {
+ for (int i = static_cast<int>(n) - 1; i >= 0; --i) {
uint idx = allocate(o);
d = o->d()->arrayData.cast<Heap::SparseArrayData>();
- d->arrayData[idx] = values[i];
+ d->setArrayData(o->engine(), idx, values[i]);
d->sparse->push_front(idx);
}
}
@@ -535,7 +516,7 @@ ReturnedValue SparseArrayData::pop_front(Object *o)
uint idx = d->sparse->pop_front();
ReturnedValue v;
if (idx != UINT_MAX) {
- v = d->arrayData[idx].asReturnedValue();
+ v = d->values[idx].asReturnedValue();
free(o->arrayData(), idx);
} else {
v = Encode::undefined();
@@ -613,24 +594,24 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n)
ScopedValue v(scope);
for (const SparseArrayNode *it = os->sparse->begin();
it != os->sparse->end(); it = it->nextNode()) {
- v = otherObj->getValue(os->arrayData[it->value], other->d()->attrs[it->value]);
+ v = otherObj->getValue(os->values[it->value], other->d()->attrs[it->value]);
obj->arraySet(oldSize + it->key(), v);
}
} else {
for (const SparseArrayNode *it = other->d()->sparse->begin();
it != os->sparse->end(); it = it->nextNode())
- obj->arraySet(oldSize + it->key(), os->arrayData[it->value]);
+ obj->arraySet(oldSize + it->key(), os->values[it->value]);
}
} else {
Heap::SimpleArrayData *os = static_cast<Heap::SimpleArrayData *>(other->d());
uint toCopy = n;
uint chunk = toCopy;
- if (chunk > os->alloc - os->offset)
- chunk -= os->alloc - os->offset;
- obj->arrayPut(oldSize, os->arrayData + os->offset, chunk);
+ if (chunk > os->values.alloc - os->offset)
+ chunk -= os->values.alloc - os->offset;
+ obj->arrayPut(oldSize, os->values.data() + os->offset, chunk);
toCopy -= chunk;
if (toCopy)
- obj->arrayPut(oldSize + chunk, os->arrayData, toCopy);
+ obj->arrayPut(oldSize + chunk, os->values.data(), toCopy);
}
return oldSize + n;
@@ -640,18 +621,18 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor)
{
if (!isAccessor && o->d()->arrayData->type != Heap::ArrayData::Sparse) {
Heap::SimpleArrayData *d = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (index < 0x1000 || index < d->len + (d->len >> 2)) {
- if (index >= d->alloc) {
+ if (index < 0x1000 || index < d->values.size + (d->values.size >> 2)) {
+ if (index >= d->values.alloc) {
o->arrayReserve(index + 1);
d = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
- if (index >= d->len) {
+ if (index >= d->values.size) {
// mark possible hole in the array
- for (uint i = d->len; i < index; ++i)
- d->data(i) = Primitive::emptyValue();
- d->len = index + 1;
+ for (uint i = d->values.size; i < index; ++i)
+ d->setData(o->engine(), i, Primitive::emptyValue());
+ d->values.size = index + 1;
}
- d->arrayData[d->mappedIndex(index)] = *v;
+ d->setData(o->engine(), index, *v);
return;
}
}
@@ -662,9 +643,9 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor)
if (n->value == UINT_MAX)
n->value = SparseArrayData::allocate(o, isAccessor);
s = o->d()->arrayData.cast<Heap::SparseArrayData>();
- s->arrayData[n->value] = *v;
+ s->setArrayData(o->engine(), n->value, *v);
if (isAccessor)
- s->arrayData[n->value + Object::SetterOffset] = v[Object::SetterOffset];
+ s->setArrayData(o->engine(), n->value + Object::SetterOffset, v[Object::SetterOffset]);
}
@@ -801,7 +782,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
break;
PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data;
- d->data(i) = thisObject->getValue(sparse->arrayData()[n->value], a);
+ d->setData(engine, i, Value::fromReturnedValue(thisObject->getValue(sparse->arrayData()[n->value], a)));
d->attrs[i] = a.isAccessor() ? Attr_Data : a;
n = n->nextNode();
@@ -811,12 +792,12 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
while (n != sparse->sparse()->end()) {
if (n->value >= len)
break;
- d->data(i) = sparse->arrayData()[n->value];
+ d->setData(engine, i, sparse->arrayData()[n->value]);
n = n->nextNode();
++i;
}
}
- d->len = i;
+ d->values.size = i;
if (len > i)
len = i;
if (n != sparse->sparse()->end()) {
@@ -824,7 +805,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
thisObject->initSparseArray();
while (n != sparse->sparse()->end()) {
PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data;
- thisObject->arraySet(n->value, reinterpret_cast<Property *>(sparse->arrayData() + n->value), a);
+ thisObject->arraySet(n->value, reinterpret_cast<const Property *>(sparse->arrayData() + n->value), a);
n = n->nextNode();
}
@@ -832,8 +813,8 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
}
} else {
Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (len > d->len)
- len = d->len;
+ if (len > d->values.size)
+ len = d->values.size;
// sort empty values to the end
for (uint i = 0; i < len; i++) {
@@ -842,8 +823,8 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
if (!d->data(len).isEmpty())
break;
Q_ASSERT(!d->attrs || !d->attrs[len].isAccessor());
- d->data(i) = d->data(len);
- d->data(len) = Primitive::emptyValue();
+ d->setData(engine, i, d->data(len));
+ d->setData(engine, len, Primitive::emptyValue());
}
}
@@ -854,7 +835,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
ArrayElementLessThan lessThan(engine, thisObject, comparefn);
- Value *begin = thisObject->arrayData()->arrayData;
+ Value *begin = thisObject->arrayData()->values.values;
sortHelper(begin, begin + len, *begin, lessThan);
#ifdef CHECK_SPARSE_ARRAYS
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index daf8c36814..e1de2e82e6 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -90,27 +90,31 @@ struct ArrayVTable
namespace Heap {
-struct ArrayData : public Base {
- enum Type {
- Simple = 0,
- Complex = 1,
- Sparse = 2,
- Custom = 3
+#define ArrayDataMembers(class, Member) \
+ Member(class, NoMark, uint, type) \
+ Member(class, NoMark, uint, offset) \
+ Member(class, NoMark, PropertyAttributes *, attrs) \
+ Member(class, NoMark, ReturnedValue, freeList) \
+ Member(class, NoMark, SparseArray *, sparse) \
+ Member(class, ValueArray, ValueArray, values)
+
+DECLARE_HEAP_OBJECT(ArrayData, Base) {
+ DECLARE_MARK_TABLE(ArrayData);
+
+ enum Type { Simple = 0, Complex = 1, Sparse = 2, Custom = 3 };
+
+ struct Index {
+ Heap::ArrayData *arrayData;
+ uint index;
+
+ void set(EngineBase *e, Value newVal) {
+ arrayData->values.set(e, index, newVal);
+ }
+ const Value *operator->() const { return &arrayData->values[index]; }
+ const Value &operator*() const { return arrayData->values[index]; }
+ bool isNull() const { return !arrayData; }
};
- uint alloc;
- Type type;
- PropertyAttributes *attrs;
- union {
- uint len;
- ReturnedValue freeList;
- };
- union {
- uint offset;
- SparseArray *sparse;
- };
- Value arrayData[1];
-
bool isSparse() const { return type == Sparse; }
const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(Base::vtable()); }
@@ -118,35 +122,32 @@ struct ArrayData : public Base {
inline ReturnedValue get(uint i) const {
return vtable()->get(this, i);
}
- inline void getProperty(uint index, Property *p, PropertyAttributes *attrs);
- inline void setProperty(uint index, const Property *p);
- inline Property *getProperty(uint index);
- inline Value *getValueOrSetter(uint index, PropertyAttributes *attrs);
+ inline bool getProperty(uint index, Property *p, PropertyAttributes *attrs);
+ inline void setProperty(EngineBase *e, uint index, const Property *p);
+ inline Index getValueOrSetter(uint index, PropertyAttributes *attrs);
inline PropertyAttributes attributes(uint i) const;
bool isEmpty(uint i) const {
return get(i) == Primitive::emptyValue().asReturnedValue();
}
- inline ReturnedValue length() const {
+ inline uint length() const {
return vtable()->length(this);
}
+ void setArrayData(EngineBase *e, uint index, Value newVal) {
+ values.set(e, index, newVal);
+ }
+
+ uint mappedIndex(uint index) const;
};
V4_ASSERT_IS_TRIVIAL(ArrayData)
struct SimpleArrayData : public ArrayData {
- uint mappedIndex(uint index) const { return (index + offset) % alloc; }
- Value data(uint index) const { return arrayData[mappedIndex(index)]; }
- Value &data(uint index) { return arrayData[mappedIndex(index)]; }
-
- Property *getProperty(uint index) {
- if (index >= len)
- return 0;
- index = mappedIndex(index);
- if (arrayData[index].isEmpty())
- return 0;
- return reinterpret_cast<Property *>(arrayData + index);
+ uint mappedIndex(uint index) const { return (index + offset) % values.alloc; }
+ const Value &data(uint index) const { return values[mappedIndex(index)]; }
+ void setData(EngineBase *e, uint index, Value newVal) {
+ values.set(e, mappedIndex(index), newVal);
}
PropertyAttributes attributes(uint i) const {
@@ -168,13 +169,6 @@ struct SparseArrayData : public ArrayData {
return n->value;
}
- Property *getProperty(uint index) {
- SparseArrayNode *n = sparse->findNode(index);
- if (!n)
- return 0;
- return reinterpret_cast<Property *>(arrayData + n->value);
- }
-
PropertyAttributes attributes(uint i) const {
if (!attrs)
return Attr_Data;
@@ -189,16 +183,23 @@ struct Q_QML_EXPORT ArrayData : public Managed
{
typedef Heap::ArrayData::Type Type;
V4_MANAGED(ArrayData, Managed)
+ enum {
+ IsArrayData = true
+ };
- uint alloc() const { return d()->alloc; }
- uint &alloc() { return d()->alloc; }
- void setAlloc(uint a) { d()->alloc = a; }
- Type type() const { return d()->type; }
+ typedef Heap::ArrayData::Index Index;
+
+ uint alloc() const { return d()->values.alloc; }
+ uint &alloc() { return d()->values.alloc; }
+ void setAlloc(uint a) { d()->values.alloc = a; }
+ Type type() const { return static_cast<Type>(d()->type); }
void setType(Type t) { d()->type = t; }
PropertyAttributes *attrs() const { return d()->attrs; }
void setAttrs(PropertyAttributes *a) { d()->attrs = a; }
- const Value *arrayData() const { return &d()->arrayData[0]; }
- Value *arrayData() { return &d()->arrayData[0]; }
+ const Value *arrayData() const { return d()->values.data(); }
+ void setArrayData(EngineBase *e, uint index, Value newVal) {
+ d()->setArrayData(e, index, newVal);
+ }
const ArrayVTable *vtable() const { return d()->vtable(); }
bool isSparse() const { return type() == Heap::ArrayData::Sparse; }
@@ -221,9 +222,6 @@ struct Q_QML_EXPORT ArrayData : public Managed
ReturnedValue get(uint i) const {
return d()->get(i);
}
- inline Property *getProperty(uint index) {
- return d()->getProperty(index);
- }
static void ensureAttributes(Object *o);
static void realloc(Object *o, Type newType, uint alloc, bool enforceAttributes);
@@ -240,15 +238,12 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData
uint mappedIndex(uint index) const { return d()->mappedIndex(index); }
Value data(uint index) const { return d()->data(index); }
- Value &data(uint index) { return d()->data(index); }
- uint &len() { return d()->len; }
- uint len() const { return d()->len; }
+ uint &len() { return d()->values.size; }
+ uint len() const { return d()->values.size; }
static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
- static void markObjects(Heap::Base *d, ExecutionEngine *e);
-
static ReturnedValue get(const Heap::ArrayData *d, uint index);
static bool put(Object *o, uint index, const Value &value);
static bool putArray(Object *o, uint index, const Value *values, uint n);
@@ -276,8 +271,6 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData
uint mappedIndex(uint index) const { return d()->mappedIndex(index); }
- static void markObjects(Heap::Base *d, ExecutionEngine *e);
-
static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
static ReturnedValue get(const Heap::ArrayData *d, uint index);
static bool put(Object *o, uint index, const Value &value);
@@ -292,30 +285,38 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData
namespace Heap {
-void ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs)
+inline uint ArrayData::mappedIndex(uint index) const
{
- Property *pd = getProperty(index);
- Q_ASSERT(pd);
- *attrs = attributes(index);
- p->value = pd->value;
- if (attrs->isAccessor())
- p->set = pd->set;
+ if (isSparse())
+ return static_cast<const SparseArrayData *>(this)->mappedIndex(index);
+ if (index >= values.size)
+ return UINT_MAX;
+ uint idx = static_cast<const SimpleArrayData *>(this)->mappedIndex(index);
+ return values[idx].isEmpty() ? UINT_MAX : idx;
}
-void ArrayData::setProperty(uint index, const Property *p)
+bool ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs)
{
- Property *pd = getProperty(index);
- Q_ASSERT(pd);
- pd->value = p->value;
- if (attributes(index).isAccessor())
- pd->set = p->set;
+ uint mapped = mappedIndex(index);
+ if (mapped == UINT_MAX) {
+ *attrs = Attr_Invalid;
+ return false;
+ }
+
+ *attrs = attributes(index);
+ p->value = *(Index{ this, mapped });
+ if (attrs->isAccessor())
+ p->set = *(Index{ this, mapped + 1 /*Object::SetterOffset*/ });
+ return true;
}
-inline Property *ArrayData::getProperty(uint index)
+void ArrayData::setProperty(QV4::EngineBase *e, uint index, const Property *p)
{
- if (isSparse())
- return static_cast<SparseArrayData *>(this)->getProperty(index);
- return static_cast<SimpleArrayData *>(this)->getProperty(index);
+ uint mapped = mappedIndex(index);
+ Q_ASSERT(mapped != UINT_MAX);
+ values.set(e, mapped, p->value);
+ if (attributes(index).isAccessor())
+ values.set(e, mapped + 1 /*QV4::Object::SetterOffset*/, p->set);
}
inline PropertyAttributes ArrayData::attributes(uint i) const
@@ -325,16 +326,16 @@ inline PropertyAttributes ArrayData::attributes(uint i) const
return static_cast<const SimpleArrayData *>(this)->attributes(i);
}
-Value *ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs)
+ArrayData::Index ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs)
{
- Property *p = getProperty(index);
- if (!p) {
+ uint idx = mappedIndex(index);
+ if (idx == UINT_MAX) {
*attrs = Attr_Invalid;
- return 0;
+ return { 0, 0 };
}
*attrs = attributes(index);
- return attrs->isAccessor() ? &p->set : &p->value;
+ return { this, attrs->isAccessor() ? idx + 1 /* QV4::Object::SetterOffset*/ : idx };
}
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 759354f4e2..a2c19e1f2d 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -690,8 +690,8 @@ void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallD
} else {
Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex);
Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (len > sa->len)
- len = sa->len;
+ if (len > sa->values.size)
+ len = sa->values.size;
uint idx = fromIndex;
while (idx < len) {
value = sa->data(idx);
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 3ff864d7b9..6807c835b0 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -54,41 +54,44 @@
using namespace QV4;
DEFINE_MANAGED_VTABLE(ExecutionContext);
+DEFINE_MANAGED_VTABLE(SimpleCallContext);
DEFINE_MANAGED_VTABLE(CallContext);
DEFINE_MANAGED_VTABLE(WithContext);
DEFINE_MANAGED_VTABLE(CatchContext);
DEFINE_MANAGED_VTABLE(GlobalContext);
-/* Function *f, int argc */
-#define requiredMemoryForExecutionContect(f, argc) \
- ((sizeof(CallContext::Data) + 7) & ~7) + \
- sizeof(Value) * (f->compiledFunction->nLocals + qMax((uint)argc, f->nFormals)) + sizeof(CallData)
-
Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData)
{
- Heap::CallContext *c = engine()->memoryManager->allocManaged<CallContext>(
- requiredMemoryForExecutionContect(function, callData->argc));
+ uint localsAndFormals = function->compiledFunction->nLocals + sizeof(CallData)/sizeof(Value) - 1 + qMax(static_cast<uint>(callData->argc), function->nFormals);
+ size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * (localsAndFormals);
+
+ ExecutionEngine *v4 = engine();
+ Heap::CallContext *c = v4->memoryManager->allocManaged<CallContext>(requiredMemory);
c->init(Heap::ExecutionContext::Type_CallContext);
c->v4Function = function;
c->strictMode = function->isStrict();
- c->outer = this->d();
-
- c->activation = 0;
+ c->outer.set(v4, this->d());
c->compilationUnit = function->compilationUnit;
c->lookups = function->compilationUnit->runtimeLookups;
c->constantTable = function->compilationUnit->constants;
- c->locals = (Value *)((quintptr(c + 1) + 7) & ~7);
const CompiledData::Function *compiledFunction = function->compiledFunction;
- int nLocals = compiledFunction->nLocals;
+ uint nLocals = compiledFunction->nLocals;
+ c->locals.size = nLocals;
+ c->locals.alloc = localsAndFormals;
+#if QT_POINTER_SIZE == 8
+ // memory allocated from the JS heap is 0 initialized, so skip the std::fill() below
+ Q_ASSERT(Primitive::undefinedValue().asReturnedValue() == 0);
+#else
if (nLocals)
- std::fill(c->locals, c->locals + nLocals, Primitive::undefinedValue());
+ std::fill(c->locals.values, c->locals.values + nLocals, Primitive::undefinedValue());
+#endif
- c->callData = reinterpret_cast<CallData *>(c->locals + nLocals);
- ::memcpy(c->callData, callData, sizeof(CallData) + (callData->argc - 1) * sizeof(Value));
+ c->callData = reinterpret_cast<CallData *>(c->locals.values + nLocals);
+ ::memcpy(c->callData, callData, sizeof(CallData) - sizeof(Value) + static_cast<uint>(callData->argc) * sizeof(Value));
if (callData->argc < static_cast<int>(compiledFunction->nFormals))
std::fill(c->callData->args + c->callData->argc, c->callData->args + compiledFunction->nFormals, Primitive::undefinedValue());
@@ -118,10 +121,10 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
switch (ctx->d()->type) {
case Heap::ExecutionContext::Type_CallContext:
case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
if (!activation) {
if (!c->activation)
- c->activation = scope.engine->newObject();
+ c->activation.set(scope.engine, scope.engine->newObject());
activation = c->activation;
}
break;
@@ -144,7 +147,7 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
ctx = ctx->d()->outer;
}
- if (activation->hasProperty(name))
+ if (activation->hasOwnProperty(name))
return;
ScopedProperty desc(scope);
PropertyAttributes attrs(Attr_Data);
@@ -155,41 +158,52 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
void Heap::GlobalContext::init(ExecutionEngine *eng)
{
Heap::ExecutionContext::init(Heap::ExecutionContext::Type_GlobalContext);
- global = eng->globalObject->d();
+ global.set(eng, eng->globalObject->d());
}
void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionVarName,
const Value &exceptionValue)
{
Heap::ExecutionContext::init(Heap::ExecutionContext::Type_CatchContext);
- outer = outerContext;
+ outer.set(internalClass->engine, outerContext);
strictMode = outer->strictMode;
callData = outer->callData;
lookups = outer->lookups;
constantTable = outer->constantTable;
compilationUnit = outer->compilationUnit;
- this->exceptionVarName = exceptionVarName;
- this->exceptionValue = exceptionValue;
+ this->exceptionVarName.set(internalClass->engine, exceptionVarName);
+ this->exceptionValue.set(internalClass->engine, exceptionValue);
}
+void Heap::WithContext::init(ExecutionContext *outerContext, Object *with)
+{
+ Heap::ExecutionContext::init(Heap::ExecutionContext::Type_WithContext);
+ outer.set(internalClass->engine, outerContext);
+ callData = outer->callData;
+ lookups = outer->lookups;
+ constantTable = outer->constantTable;
+ compilationUnit = outer->compilationUnit;
-Identifier * const *CallContext::formals() const
+ withObject.set(internalClass->engine, with);
+}
+
+Identifier * const *SimpleCallContext::formals() const
{
return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() : 0;
}
-unsigned int CallContext::formalCount() const
+unsigned int SimpleCallContext::formalCount() const
{
return d()->v4Function ? d()->v4Function->nFormals : 0;
}
-Identifier * const *CallContext::variables() const
+Identifier * const *SimpleCallContext::variables() const
{
return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() + d()->v4Function->nFormals : 0;
}
-unsigned int CallContext::variableCount() const
+unsigned int SimpleCallContext::variableCount() const
{
return d()->v4Function ? d()->v4Function->compiledFunction->nLocals : 0;
}
@@ -202,7 +216,6 @@ bool ExecutionContext::deleteProperty(String *name)
Identifier *id = name->identifier();
Scope scope(this);
- bool hasWith = false;
ScopedContext ctx(scope, this);
for (; ctx; ctx = ctx->d()->outer) {
switch (ctx->d()->type) {
@@ -213,7 +226,6 @@ bool ExecutionContext::deleteProperty(String *name)
break;
}
case Heap::ExecutionContext::Type_WithContext: {
- hasWith = true;
ScopedObject withObject(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
if (withObject->hasProperty(name))
return withObject->deleteProperty(name);
@@ -226,14 +238,13 @@ bool ExecutionContext::deleteProperty(String *name)
break;
}
case Heap::ExecutionContext::Type_CallContext:
+ Q_FALLTHROUGH();
case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- if (c->v4Function && (c->v4Function->needsActivation() || hasWith)) {
- uint index = c->v4Function->internalClass->find(id);
- if (index < UINT_MAX)
- // ### throw in strict mode?
- return false;
- }
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
+ uint index = c->v4Function->internalClass->find(id);
+ if (index < UINT_MAX)
+ // ### throw in strict mode?
+ return false;
ScopedObject qml(scope, c->activation);
if (qml && qml->hasProperty(name))
return qml->deleteProperty(name);
@@ -250,61 +261,6 @@ bool ExecutionContext::deleteProperty(String *name)
return true;
}
-bool CallContext::needsOwnArguments() const
-{
- QV4::Function *f = d()->v4Function;
- return (f && f->needsActivation()) || (argc() < (f ? static_cast<int>(f->nFormals) : 0));
-}
-
-void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine)
-{
- ExecutionContext::Data *ctx = static_cast<ExecutionContext::Data *>(m);
-
- if (ctx->outer)
- ctx->outer->mark(engine);
-
- switch (ctx->type) {
- case Heap::ExecutionContext::Type_CatchContext: {
- CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx);
- c->exceptionVarName->mark(engine);
- c->exceptionValue.mark(engine);
- break;
- }
- case Heap::ExecutionContext::Type_WithContext: {
- WithContext::Data *w = static_cast<WithContext::Data *>(ctx);
- if (w->withObject)
- w->withObject->mark(engine);
- break;
- }
- case Heap::ExecutionContext::Type_GlobalContext: {
- GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx);
- g->global->mark(engine);
- break;
- }
- case Heap::ExecutionContext::Type_SimpleCallContext:
- break;
- case Heap::ExecutionContext::Type_CallContext: {
- QV4::Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
- Q_ASSERT(c->v4Function);
- ctx->callData->thisObject.mark(engine);
- for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->v4Function->nFormals); ++arg)
- ctx->callData->args[arg].mark(engine);
- for (unsigned local = 0, lastLocal = c->v4Function->compiledFunction->nLocals; local < lastLocal; ++local)
- c->locals[local].mark(engine);
- if (c->activation)
- c->activation->mark(engine);
- if (c->function)
- c->function->mark(engine);
- break;
- }
- case Heap::ExecutionContext::Type_QmlContext: {
- QmlContext::Data *g = static_cast<QmlContext::Data *>(ctx);
- g->qml->mark(engine);
- break;
- }
- }
-}
-
// Do a standard call with this execution context as the outer scope
void ExecutionContext::call(Scope &scope, CallData *callData, Function *function, const FunctionObject *f)
{
@@ -312,7 +268,7 @@ void ExecutionContext::call(Scope &scope, CallData *callData, Function *function
Scoped<CallContext> ctx(scope, newCallContext(function, callData));
if (f)
- ctx->d()->function = f->d();
+ ctx->d()->function.set(scope.engine, f->d());
scope.engine->pushContext(ctx);
scope.result = Q_V4_PROFILE(scope.engine, function);
@@ -328,7 +284,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext();
+ SimpleCallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext();
ctx->strictMode = function->isStrict();
ctx->callData = callData;
@@ -336,8 +292,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio
ctx->compilationUnit = function->compilationUnit;
ctx->lookups = function->compilationUnit->runtimeLookups;
ctx->constantTable = function->compilationUnit->constants;
- ctx->outer = this->d();
- ctx->locals = scope.alloc(function->compiledFunction->nLocals);
+ ctx->outer.set(scope.engine, this->d());
for (int i = callData->argc; i < (int)function->nFormals; ++i)
callData->args[i] = Encode::undefined();
@@ -366,7 +321,7 @@ void ExecutionContext::setProperty(String *name, const Value &value)
case Heap::ExecutionContext::Type_CatchContext: {
Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
if (c->exceptionVarName->isEqualTo(name->d())) {
- c->exceptionValue = value;
+ c->exceptionValue.set(scope.engine, value);
return;
}
break;
@@ -385,15 +340,16 @@ void ExecutionContext::setProperty(String *name, const Value &value)
}
case Heap::ExecutionContext::Type_CallContext:
case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
if (c->v4Function) {
uint index = c->v4Function->internalClass->find(id);
if (index < UINT_MAX) {
if (index < c->v4Function->nFormals) {
c->callData->args[c->v4Function->nFormals - index - 1] = value;
} else {
+ Q_ASSERT(c->type == Heap::ExecutionContext::Type_CallContext);
index -= c->v4Function->nFormals;
- c->locals[index] = value;
+ static_cast<Heap::CallContext *>(c)->locals.set(scope.engine, index, value);
}
return;
}
@@ -434,13 +390,10 @@ ReturnedValue ExecutionContext::getProperty(String *name)
if (name->equals(engine()->id_this()))
return thisObject().asReturnedValue();
- bool hasWith = false;
- bool hasCatchScope = false;
ScopedContext ctx(scope, this);
for (; ctx; ctx = ctx->d()->outer) {
switch (ctx->d()->type) {
case Heap::ExecutionContext::Type_CatchContext: {
- hasCatchScope = true;
Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
if (c->exceptionVarName->isEqualTo(name->d()))
return c->exceptionValue.asReturnedValue();
@@ -448,7 +401,6 @@ ReturnedValue ExecutionContext::getProperty(String *name)
}
case Heap::ExecutionContext::Type_WithContext: {
ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
- hasWith = true;
bool hasProperty = false;
v = w->get(name, &hasProperty);
if (hasProperty) {
@@ -465,19 +417,20 @@ ReturnedValue ExecutionContext::getProperty(String *name)
break;
}
case Heap::ExecutionContext::Type_CallContext:
+ Q_FALLTHROUGH();
case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) {
- name->makeIdentifier();
- Identifier *id = name->identifier();
-
- uint index = c->v4Function->internalClass->find(id);
- if (index < UINT_MAX) {
- if (index < c->v4Function->nFormals)
- return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
- return c->locals[index - c->v4Function->nFormals].asReturnedValue();
- }
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
+
+ name->makeIdentifier();
+ Identifier *id = name->identifier();
+ uint index = c->v4Function->internalClass->find(id);
+ if (index < UINT_MAX) {
+ if (index < c->v4Function->nFormals)
+ return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
+ if (c->type == Heap::ExecutionContext::Type_CallContext)
+ return static_cast<Heap::CallContext *>(c)->locals[index - c->v4Function->nFormals].asReturnedValue();
}
+
ScopedObject activation(scope, c->activation);
if (activation) {
bool hasProperty = false;
@@ -485,9 +438,12 @@ ReturnedValue ExecutionContext::getProperty(String *name)
if (hasProperty)
return v->asReturnedValue();
}
- if (c->function && c->v4Function->isNamedExpression()
- && name->equals(ScopedString(scope, c->v4Function->name())))
- return c->function->asReturnedValue();
+
+ if (c->v4Function->isNamedExpression() && c->type == Heap::ExecutionContext::Type_CallContext) {
+ if (name->equals(ScopedString(scope, c->v4Function->name())))
+ if (auto func = static_cast<Heap::CallContext *>(c)->function)
+ return func->asReturnedValue();
+ }
break;
}
case Heap::ExecutionContext::Type_QmlContext: {
@@ -514,13 +470,10 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
if (name->equals(engine()->id_this()))
return thisObject().asReturnedValue();
- bool hasWith = false;
- bool hasCatchScope = false;
ScopedContext ctx(scope, this);
for (; ctx; ctx = ctx->d()->outer) {
switch (ctx->d()->type) {
case Heap::ExecutionContext::Type_CatchContext: {
- hasCatchScope = true;
Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
if (c->exceptionVarName->isEqualTo(name->d()))
return c->exceptionValue.asReturnedValue();
@@ -528,7 +481,6 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
}
case Heap::ExecutionContext::Type_WithContext: {
ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
- hasWith = true;
bool hasProperty = false;
v = w->get(name, &hasProperty);
if (hasProperty) {
@@ -546,19 +498,20 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
break;
}
case Heap::ExecutionContext::Type_CallContext:
+ Q_FALLTHROUGH();
case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) {
- name->makeIdentifier();
- Identifier *id = name->identifier();
-
- uint index = c->v4Function->internalClass->find(id);
- if (index < UINT_MAX) {
- if (index < c->v4Function->nFormals)
- return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
- return c->locals[index - c->v4Function->nFormals].asReturnedValue();
- }
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
+
+ name->makeIdentifier();
+ Identifier *id = name->identifier();
+ uint index = c->v4Function->internalClass->find(id);
+ if (index < UINT_MAX) {
+ if (index < c->v4Function->nFormals)
+ return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
+ if (c->type == Heap::ExecutionContext::Type_CallContext)
+ return static_cast<Heap::CallContext *>(c)->locals[index - c->v4Function->nFormals].asReturnedValue();
}
+
ScopedObject activation(scope, c->activation);
if (activation) {
bool hasProperty = false;
@@ -566,9 +519,12 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
if (hasProperty)
return v->asReturnedValue();
}
- if (c->function && c->v4Function->isNamedExpression()
- && name->equals(ScopedString(scope, c->v4Function->name())))
- return c->function->asReturnedValue();
+
+ if (c->v4Function->isNamedExpression() && c->type == Heap::ExecutionContext::Type_CallContext) {
+ if (name->equals(ScopedString(scope, c->v4Function->name())))
+ if (auto func = static_cast<Heap::CallContext *>(c)->function)
+ return func->asReturnedValue();
+ }
break;
}
case Heap::ExecutionContext::Type_QmlContext: {
@@ -592,7 +548,7 @@ Function *ExecutionContext::getFunction() const
Scope scope(engine());
ScopedContext it(scope, this->d());
for (; it; it = it->d()->outer) {
- if (const CallContext *callCtx = it->asCallContext())
+ if (const SimpleCallContext *callCtx = it->asSimpleCallContext())
return callCtx->d()->v4Function;
else if (it->asCatchContext() || it->asWithContext())
continue; // look in the parent context for a FunctionObject
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 0b63922a4b..a854c324d0 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -68,10 +68,11 @@ struct Function;
struct Function;
struct Identifier;
struct CallContext;
+struct SimpleCallContext;
struct CatchContext;
struct WithContext;
struct QmlContext;
-struct QmlContextWrapper;
+struct QQmlContextWrapper;
// Attention: Make sure that this structure is the same size on 32-bit and 64-bit
// architecture or you'll have to change the JIT code.
@@ -101,34 +102,17 @@ namespace Heap {
struct QmlContext;
-// ### Temporary arrangment until this code hits the dev branch and
-// can use the Members macro
-struct ExecutionContextData {
- CallData *callData;
- ExecutionContext *outer;
- Lookup *lookups;
- const QV4::Value *constantTable;
- CompiledData::CompilationUnitBase *compilationUnit;
- // as member of non-pointer size this has to come last to preserve the ability to
- // translate offsetof of it between 64-bit and 32-bit.
- int lineNumber;
-#if QT_POINTER_SIZE == 8
- uint padding_;
-#endif
-};
-
-Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::value);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, callData) == 0);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == offsetof(ExecutionContextData, callData) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, lookups) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, constantTable) == offsetof(ExecutionContextData, lookups) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, compilationUnit) == offsetof(ExecutionContextData, constantTable) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, lineNumber) == offsetof(ExecutionContextData, compilationUnit) + QT_POINTER_SIZE);
+#define ExecutionContextMembers(class, Member) \
+ Member(class, NoMark, CallData *, callData) \
+ Member(class, Pointer, ExecutionContext *, outer) \
+ Member(class, NoMark, Lookup *, lookups) \
+ Member(class, NoMark, const QV4::Value *, constantTable) \
+ Member(class, NoMark, CompiledData::CompilationUnitBase *, compilationUnit) \
+ Member(class, NoMark, int, lineNumber) // as member of non-pointer size this has to come last to preserve the ability to
+ // translate offsetof of it between 64-bit and 32-bit.
-struct ExecutionContextSizeStruct : public Base, public ExecutionContextData {};
-
-struct ExecutionContext : Base, public ExecutionContextData {
- static Q_CONSTEXPR size_t baseOffset = sizeof(ExecutionContextSizeStruct) - sizeof(ExecutionContextData);
+DECLARE_HEAP_OBJECT(ExecutionContext, Base) {
+ DECLARE_MARK_TABLE(ExecutionContext);
enum ContextType {
Type_GlobalContext = 0x1,
@@ -158,17 +142,20 @@ struct ExecutionContext : Base, public ExecutionContextData {
V4_ASSERT_IS_TRIVIAL(ExecutionContext)
Q_STATIC_ASSERT(sizeof(ExecutionContext) == sizeof(Base) + sizeof(ExecutionContextData) + QT_POINTER_SIZE);
-struct CallContextData {
- Value *locals;
-};
-
-Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value);
-Q_STATIC_ASSERT(offsetof(CallContextData, locals) == 0);
+Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::value);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, callData) == 0);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == offsetof(ExecutionContextData, callData) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, lookups) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, constantTable) == offsetof(ExecutionContextData, lookups) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, compilationUnit) == offsetof(ExecutionContextData, constantTable) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, lineNumber) == offsetof(ExecutionContextData, compilationUnit) + QT_POINTER_SIZE);
-struct CallContextSizeStruct : public ExecutionContext, public CallContextData {};
+#define SimpleCallContextMembers(class, Member) \
+ Member(class, Pointer, Object *, activation) \
+ Member(class, NoMark, QV4::Function *, v4Function)
-struct CallContext : ExecutionContext, public CallContextData {
- static Q_CONSTEXPR size_t baseOffset = sizeof(CallContextSizeStruct) - sizeof(CallContextData);
+DECLARE_HEAP_OBJECT(SimpleCallContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(SimpleCallContext);
void init(ContextType t = Type_SimpleCallContext)
{
@@ -177,39 +164,66 @@ struct CallContext : ExecutionContext, public CallContextData {
inline unsigned int formalParameterCount() const;
- Pointer<FunctionObject> function;
- QV4::Function *v4Function;
- Pointer<Object> activation;
};
-V4_ASSERT_IS_TRIVIAL(CallContext)
+V4_ASSERT_IS_TRIVIAL(SimpleCallContext)
+Q_STATIC_ASSERT(std::is_standard_layout<SimpleCallContextData>::value);
+Q_STATIC_ASSERT(offsetof(SimpleCallContextData, activation) == 0);
+Q_STATIC_ASSERT(offsetof(SimpleCallContextData, v4Function) == offsetof(SimpleCallContextData, activation) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(sizeof(SimpleCallContextData) == 2 * QT_POINTER_SIZE);
+Q_STATIC_ASSERT(sizeof(SimpleCallContext) == sizeof(ExecutionContext) + sizeof(SimpleCallContextData));
+
+#if QT_POINTER_SIZE == 8
+#define CallContextMembers(class, Member) \
+ Member(class, Pointer, FunctionObject *, function) \
+ Member(class, ValueArray, ValueArray, locals)
+#else
+#define CallContextMembers(class, Member) \
+ Member(class, Pointer, FunctionObject *, function) \
+ Member(class, NoMark, void *, padding) \
+ Member(class, ValueArray, ValueArray, locals)
+#endif
+
+DECLARE_HEAP_OBJECT(CallContext, SimpleCallContext) {
+ DECLARE_MARK_TABLE(CallContext);
+
+ using SimpleCallContext::formalParameterCount;
+};
+
+Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value);
+Q_STATIC_ASSERT(offsetof(CallContextData, function) == 0);
+// IMPORTANT: we cannot do offsetof(CallContextData, locals) in the JIT as the offset does not scale with
+// the pointer size. On 32-bit ARM the offset of the ValueArray is aligned to 8 bytes, on 32-bit x86 for
+// example it is not. Therefore we have a padding in place and always have a distance of 8 bytes.
+Q_STATIC_ASSERT(offsetof(CallContextData, locals) == offsetof(CallContextData, function) + 8);
+
+#define GlobalContextMembers(class, Member) \
+ Member(class, Pointer, Object *, global)
+
+DECLARE_HEAP_OBJECT(GlobalContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(GlobalContext);
-struct GlobalContext : ExecutionContext {
void init(ExecutionEngine *engine);
- Pointer<Object> global;
};
V4_ASSERT_IS_TRIVIAL(GlobalContext)
-struct CatchContext : ExecutionContext {
+#define CatchContextMembers(class, Member) \
+ Member(class, Pointer, String *, exceptionVarName) \
+ Member(class, HeapValue, HeapValue, exceptionValue)
+
+DECLARE_HEAP_OBJECT(CatchContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(CatchContext);
+
void init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue);
- Pointer<String> exceptionVarName;
- Value exceptionValue;
};
V4_ASSERT_IS_TRIVIAL(CatchContext)
-struct WithContext : ExecutionContext {
- void init(ExecutionContext *outerContext, Object *with)
- {
- Heap::ExecutionContext::init(Heap::ExecutionContext::Type_WithContext);
- outer = outerContext;
- callData = outer->callData;
- lookups = outer->lookups;
- constantTable = outer->constantTable;
- compilationUnit = outer->compilationUnit;
-
- withObject = with;
- }
+#define WithContextMembers(class, Member) \
+ Member(class, Pointer, Object *, withObject)
+
+DECLARE_HEAP_OBJECT(WithContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(WithContext);
- Pointer<Object> withObject;
+ void init(ExecutionContext *outerContext, Object *with);
};
V4_ASSERT_IS_TRIVIAL(WithContext)
@@ -236,15 +250,13 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
ReturnedValue getPropertyAndBase(String *name, Value *base);
bool deleteProperty(String *name);
- inline CallContext *asCallContext();
- inline const CallContext *asCallContext() const;
+ inline SimpleCallContext *asSimpleCallContext();
+ inline const SimpleCallContext *asSimpleCallContext() const;
inline const CatchContext *asCatchContext() const;
inline const WithContext *asWithContext() const;
Function *getFunction() const;
- static void markObjects(Heap::Base *m, ExecutionEngine *e);
-
Value &thisObject() const {
return d()->callData->thisObject;
}
@@ -262,10 +274,10 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
void simpleCall(Scope &scope, CallData *callData, QV4::Function *function);
};
-struct Q_QML_EXPORT CallContext : public ExecutionContext
+struct Q_QML_EXPORT SimpleCallContext : public ExecutionContext
{
- V4_MANAGED(CallContext, ExecutionContext)
- V4_INTERNALCLASS(CallContext)
+ V4_MANAGED(SimpleCallContext, ExecutionContext)
+ V4_INTERNALCLASS(SimpleCallContext)
// formals are in reverse order
Identifier * const *formals() const;
@@ -274,14 +286,17 @@ struct Q_QML_EXPORT CallContext : public ExecutionContext
unsigned int variableCount() const;
inline ReturnedValue argument(int i) const;
- bool needsOwnArguments() const;
-
};
-inline ReturnedValue CallContext::argument(int i) const {
+inline ReturnedValue SimpleCallContext::argument(int i) const {
return i < argc() ? args()[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue();
}
+struct Q_QML_EXPORT CallContext : public SimpleCallContext
+{
+ V4_MANAGED(CallContext, SimpleCallContext)
+};
+
struct GlobalContext : public ExecutionContext
{
V4_MANAGED(GlobalContext, ExecutionContext)
@@ -298,14 +313,14 @@ struct WithContext : public ExecutionContext
V4_MANAGED(WithContext, ExecutionContext)
};
-inline CallContext *ExecutionContext::asCallContext()
+inline SimpleCallContext *ExecutionContext::asSimpleCallContext()
{
- return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0;
+ return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<SimpleCallContext *>(this) : 0;
}
-inline const CallContext *ExecutionContext::asCallContext() const
+inline const SimpleCallContext *ExecutionContext::asSimpleCallContext() const
{
- return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0;
+ return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<const SimpleCallContext *>(this) : 0;
}
inline const CatchContext *ExecutionContext::asCatchContext() const
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index a810b38f24..f1405e08ee 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -73,7 +73,7 @@ void DataViewCtor::construct(const Managed *, Scope &scope, CallData *callData)
}
Scoped<DataView> a(scope, scope.engine->memoryManager->allocObject<DataView>());
- a->d()->buffer = buffer->d();
+ a->d()->buffer.set(scope.engine, buffer->d());
a->d()->byteLength = byteLength;
a->d()->byteOffset = byteOffset;
scope.result = a.asReturnedValue();
@@ -84,13 +84,6 @@ void DataViewCtor::call(const Managed *that, Scope &scope, CallData *callData)
construct(that, scope, callData);
}
-
-void DataView::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- DataView::Data *v = static_cast<DataView::Data *>(that);
- v->buffer->mark(e);
-}
-
void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index 11cc0a6bd9..5c50df4655 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -63,11 +63,14 @@ struct DataViewCtor : FunctionObject {
void init(QV4::ExecutionContext *scope);
};
-struct DataView : Object {
+#define DataViewMembers(class, Member) \
+ Member(class, Pointer, ArrayBuffer *, buffer) \
+ Member(class, NoMark, uint, byteLength) \
+ Member(class, NoMark, uint, byteOffset)
+
+DECLARE_HEAP_OBJECT(DataView, Object) {
+ DECLARE_MARK_TABLE(DataView);
void init() { Object::init(); }
- Pointer<ArrayBuffer> buffer;
- uint byteLength;
- uint byteOffset;
};
}
@@ -84,8 +87,6 @@ struct DataView : Object
{
V4_OBJECT2(DataView, Object)
V4_PROTOTYPE(dataViewPrototype)
-
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
struct DataViewPrototype: Object
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index b90c335b1c..c56d007028 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -340,7 +340,9 @@ static inline double TimeClip(double t)
{
if (! qt_is_finite(t) || fabs(t) > 8.64e15)
return qt_qnan();
- return Primitive::toInteger(t);
+
+ // +0 looks weird, but is correct. See ES6 20.3.1.15. We must not return -0.
+ return Primitive::toInteger(t) + 0;
}
static inline double ParseString(const QString &s)
@@ -724,7 +726,7 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
Scope scope(engine);
ScopedObject o(scope);
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(7));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(7));
LocalTZA = getLocalTZA();
ctor->defineDefaultProperty(QStringLiteral("parse"), method_parse, 1);
@@ -774,8 +776,21 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("setYear"), method_setYear, 1);
defineDefaultProperty(QStringLiteral("setFullYear"), method_setFullYear, 3);
defineDefaultProperty(QStringLiteral("setUTCFullYear"), method_setUTCFullYear, 3);
- defineDefaultProperty(QStringLiteral("toUTCString"), method_toUTCString, 0);
- defineDefaultProperty(QStringLiteral("toGMTString"), method_toUTCString, 0);
+
+ // ES6: B.2.4.3 & 20.3.4.43:
+ // We have to use the *same object* for toUTCString and toGMTString
+ {
+ QString toUtcString(QStringLiteral("toUTCString"));
+ QString toGmtString(QStringLiteral("toGMTString"));
+ ScopedString us(scope, engine->newIdentifier(toUtcString));
+ ScopedString gs(scope, engine->newIdentifier(toGmtString));
+ ExecutionContext *global = engine->rootContext();
+ ScopedFunctionObject toUtcGmtStringFn(scope, BuiltinFunction::create(global, us, method_toUTCString));
+ toUtcGmtStringFn->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
+ defineDefaultProperty(us, toUtcGmtStringFn);
+ defineDefaultProperty(gs, toUtcGmtStringFn);
+ }
+
defineDefaultProperty(QStringLiteral("toISOString"), method_toISOString, 0);
defineDefaultProperty(QStringLiteral("toJSON"), method_toJSON, 1);
}
@@ -1025,6 +1040,7 @@ void DatePrototype::method_setTime(const BuiltinFunction *, Scope &scope, CallDa
THROW_TYPE_ERROR();
double t = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
self->setDate(TimeClip(t));
scope.result = Encode(self->date());
}
@@ -1036,7 +1052,9 @@ void DatePrototype::method_setMilliseconds(const BuiltinFunction *, Scope &scope
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
scope.result = Encode(self->date());
}
@@ -1048,7 +1066,9 @@ void DatePrototype::method_setUTCMilliseconds(const BuiltinFunction *, Scope &sc
THROW_TYPE_ERROR();
double t = self->date();
+ CHECK_EXCEPTION();
double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))));
scope.result = Encode(self->date());
}
@@ -1060,8 +1080,11 @@ void DatePrototype::method_setSeconds(const BuiltinFunction *, Scope &scope, Cal
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1088,9 +1111,13 @@ void DatePrototype::method_setMinutes(const BuiltinFunction *, Scope &scope, Cal
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double min = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1118,10 +1145,15 @@ void DatePrototype::method_setHours(const BuiltinFunction *, Scope &scope, CallD
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber();
+ CHECK_EXCEPTION();
double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1150,7 +1182,9 @@ void DatePrototype::method_setDate(const BuiltinFunction *, Scope &scope, CallDa
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1163,7 +1197,9 @@ void DatePrototype::method_setUTCDate(const BuiltinFunction *, Scope &scope, Cal
THROW_TYPE_ERROR();
double t = self->date();
+ CHECK_EXCEPTION();
double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1176,8 +1212,11 @@ void DatePrototype::method_setMonth(const BuiltinFunction *, Scope &scope, CallD
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double month = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1245,11 +1284,15 @@ void DatePrototype::method_setFullYear(const BuiltinFunction *, Scope &scope, Ca
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
if (std::isnan(t))
t = 0;
double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
self->setDate(t);
scope.result = Encode(self->date());
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index ecd57bcd8d..b0373884dd 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -112,7 +112,7 @@ struct DateCtor: FunctionObject
static void call(const Managed *that, Scope &scope, CallData *);
};
-struct DatePrototype: DateObject
+struct DatePrototype: Object
{
V4_PROTOTYPE(objectPrototype)
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 0d3f29d089..f19f134c53 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -134,6 +134,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
, regExpAllocator(new QV4::ExecutableAllocator)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
, jsStack(new WTF::PageAllocation)
+ , gcStack(new WTF::PageAllocation)
, globalCode(0)
, v8Engine(0)
, argumentsAccessors(0)
@@ -182,18 +183,22 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
iselFactory.reset(factory);
// reserve space for the JS stack
- // we allow it to grow to 2 times JSStackLimit, as we can overshoot due to garbage collection
- // and ScopedValues allocated outside of JIT'ed methods.
- *jsStack = WTF::PageAllocation::allocate(2 * JSStackLimit, WTF::OSAllocator::JSVMStackPages,
+ // we allow it to grow to a bit more than JSStackLimit, as we can overshoot due to ScopedValues
+ // allocated outside of JIT'ed methods.
+ *jsStack = WTF::PageAllocation::allocate(JSStackLimit + 256*1024, WTF::OSAllocator::JSVMStackPages,
/* writable */ true, /* executable */ false,
/* includesGuardPages */ true);
jsStackBase = (Value *)jsStack->base();
#ifdef V4_USE_VALGRIND
- VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, 2*JSStackLimit);
+ VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, JSStackLimit + 256*1024);
#endif
jsStackTop = jsStackBase;
+ *gcStack = WTF::PageAllocation::allocate(GCStackLimit, WTF::OSAllocator::JSVMStackPages,
+ /* writable */ true, /* executable */ false,
+ /* includesGuardPages */ true);
+
exceptionValue = jsAlloca(1);
globalObject = static_cast<Object *>(jsAlloca(1));
jsObjects = jsAlloca(NJSObjects);
@@ -215,7 +220,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable());
internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable());
internalClasses[EngineBase::Class_QmlContext] = internalClasses[EngineBase::Class_ExecutionContext]->changeVTable(QV4::QmlContext::staticVTable());
- internalClasses[Class_CallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
+ internalClasses[Class_SimpleCallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
jsStrings[String_Empty] = newIdentifier(QString());
jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined"));
@@ -257,7 +262,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
InternalClass *ic = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable());
jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic);
internalClasses[Class_Object] = ic->changePrototype(objectPrototype()->d());
- internalClasses[EngineBase::Class_QmlContextWrapper] = internalClasses[Class_Object]->changeVTable(QV4::QmlContextWrapper::staticVTable());
+ internalClasses[EngineBase::Class_QmlContextWrapper] = internalClasses[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable());
ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype());
Q_ASSERT(ic->prototype);
@@ -422,13 +427,14 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
//
// set up the global object
//
- rootContext()->d()->global = globalObject->d();
+ rootContext()->d()->global.set(scope.engine, globalObject->d());
rootContext()->d()->callData->thisObject = globalObject;
Q_ASSERT(globalObject->d()->vtable());
globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor());
globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor());
- globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberCtor());
+ FunctionObject *numberObject = numberCtor();
+ globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberObject);
globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor());
globalObject->defineDefaultProperty(QStringLiteral("Array"), *arrayCtor());
globalObject->defineDefaultProperty(QStringLiteral("Function"), *functionCtor());
@@ -458,8 +464,26 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
jsObjects[Eval_Function] = memoryManager->allocObject<EvalFunction>(global);
globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction());
- globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2);
- globalObject->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1);
+ // ES6: 20.1.2.12 & 20.1.2.13:
+ // parseInt and parseFloat must be the same FunctionObject on the global &
+ // Number object.
+ {
+ QString piString(QStringLiteral("parseInt"));
+ QString pfString(QStringLiteral("parseFloat"));
+ Scope scope(this);
+ ScopedString pi(scope, newIdentifier(piString));
+ ScopedString pf(scope, newIdentifier(pfString));
+ ExecutionContext *global = rootContext();
+ ScopedFunctionObject parseIntFn(scope, BuiltinFunction::create(global, pi, GlobalFunctions::method_parseInt));
+ ScopedFunctionObject parseFloatFn(scope, BuiltinFunction::create(global, pf, GlobalFunctions::method_parseFloat));
+ parseIntFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(2));
+ parseFloatFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(1));
+ globalObject->defineDefaultProperty(piString, parseIntFn);
+ globalObject->defineDefaultProperty(pfString, parseFloatFn);
+ numberObject->defineDefaultProperty(piString, parseIntFn);
+ numberObject->defineDefaultProperty(pfString, parseFloatFn);
+ }
+
globalObject->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1);
globalObject->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1);
globalObject->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1);
@@ -491,6 +515,8 @@ ExecutionEngine::~ExecutionEngine()
delete executableAllocator;
jsStack->deallocate();
delete jsStack;
+ gcStack->deallocate();
+ delete gcStack;
delete [] argumentsAccessors;
}
@@ -602,12 +628,14 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int leng
size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value);
Heap::SimpleArrayData *d = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
d->init();
- d->alloc = length;
d->type = Heap::ArrayData::Simple;
d->offset = 0;
- d->len = length;
- memcpy(&d->arrayData, values, length*sizeof(Value));
- a->d()->arrayData = d;
+ d->values.alloc = length;
+ d->values.size = length;
+ // this doesn't require a write barrier, things will be ok, when the new array data gets inserted into
+ // the parent object
+ memcpy(&d->values.values, values, length*sizeof(Value));
+ a->d()->arrayData.set(this, d);
a->setArrayLengthUnchecked(length);
}
return a->d();
@@ -884,7 +912,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
QUrl base;
ExecutionContext *c = currentContext;
while (c) {
- CallContext *callCtx = c->asCallContext();
+ SimpleCallContext *callCtx = c->asSimpleCallContext();
if (callCtx && callCtx->d()->v4Function) {
base = callCtx->d()->v4Function->finalUrl();
break;
@@ -927,35 +955,24 @@ void ExecutionEngine::requireArgumentsAccessors(int n)
}
}
-static void drainMarkStack(ExecutionEngine *engine, QV4::Value *markBase)
+void ExecutionEngine::markObjects(MarkStack *markStack)
{
- while (engine->jsStackTop > markBase) {
- Heap::Base *h = engine->popForGC();
- Q_ASSERT (h->vtable()->markObjects);
- h->vtable()->markObjects(h, engine);
- }
-}
-
-void ExecutionEngine::markObjects()
-{
- Value *markBase = jsStackTop;
- identifierTable->mark(this);
+ identifierTable->mark(markStack);
for (int i = 0; i < nArgumentsAccessors; ++i) {
const Property &pd = argumentsAccessors[i];
if (Heap::FunctionObject *getter = pd.getter())
- getter->mark(this);
+ getter->mark(markStack);
if (Heap::FunctionObject *setter = pd.setter())
- setter->mark(this);
+ setter->mark(markStack);
}
- classPool->markObjects(this);
-
- drainMarkStack(this, markBase);
+ classPool->markObjects(markStack);
+ markStack->drain();
for (auto compilationUnit: compilationUnits) {
- compilationUnit->markObjects(this);
- drainMarkStack(this, markBase);
+ compilationUnit->markObjects(markStack);
+ markStack->drain();
}
}
@@ -1150,9 +1167,9 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return QVariant::fromValue(QV4::JsonObject::toJsonObject(object));
} else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) {
return qVariantFromValue<QObject *>(wrapper->object());
- } else if (object->as<QV4::QmlContextWrapper>()) {
+ } else if (object->as<QV4::QQmlContextWrapper>()) {
return QVariant();
- } else if (QV4::QmlTypeWrapper *w = object->as<QV4::QmlTypeWrapper>()) {
+ } else if (QV4::QQmlTypeWrapper *w = object->as<QV4::QQmlTypeWrapper>()) {
return w->toVariant();
} else if (QV4::QQmlValueTypeWrapper *v = object->as<QV4::QQmlValueTypeWrapper>()) {
return v->toVariant();
@@ -1574,12 +1591,6 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
return 0;
}
-void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject)
-{
- Q_ASSERT(!baseObject.vtable()->isObject || static_cast<const Heap::Object&>(baseObject).internalClass->engine == this);
- Q_UNUSED(baseObject);
-}
-
void ExecutionEngine::failStackLimitCheck(Scope &scope)
{
scope.result = throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index fee06ebc58..4549cda5b9 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -104,17 +104,13 @@ public:
WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
- enum { JSStackLimit = 4*1024*1024 };
+ enum {
+ JSStackLimit = 4*1024*1024,
+ GCStackLimit = 2*1024*1024
+ };
WTF::PageAllocation *jsStack;
- void pushForGC(Heap::Base *m) {
- *jsStackTop = m;
- ++jsStackTop;
- }
- Heap::Base *popForGC() {
- --jsStackTop;
- return jsStackTop->heapObject();
- }
+ WTF::PageAllocation *gcStack;
QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) {
Value *ptr = jsStackTop;
@@ -422,7 +418,7 @@ public:
void requireArgumentsAccessors(int n);
- void markObjects();
+ void markObjects(MarkStack *markStack);
void initRootContext();
@@ -459,8 +455,6 @@ public:
bool metaTypeFromJS(const Value *value, int type, void *data);
QV4::ReturnedValue metaTypeToJS(int type, const void *data);
- void assertObjectBelongsToEngine(const Heap::Base &baseObject);
-
bool checkStackLimits(Scope &scope);
private:
@@ -519,23 +513,32 @@ inline ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *contex
}
inline
-void Heap::Base::mark(QV4::ExecutionEngine *engine)
+void Heap::Base::mark(QV4::MarkStack *markStack)
{
Q_ASSERT(inUse());
- if (isMarked())
- return;
-#ifndef QT_NO_DEBUG
- engine->assertObjectBelongsToEngine(*this);
-#endif
- setMarkBit();
- engine->pushForGC(this);
+ const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
+ Chunk *c = h->chunk();
+ size_t index = h - c->realBase();
+ Q_ASSERT(!Chunk::testBit(c->extendsBitmap, index));
+ quintptr *bitmap = c->blackBitmap + Chunk::bitmapIndex(index);
+ quintptr bit = Chunk::bitForIndex(index);
+ if (!(*bitmap & bit)) {
+ *bitmap |= bit;
+ markStack->push(this);
+ }
}
-inline void Value::mark(ExecutionEngine *e)
+inline void Value::mark(MarkStack *markStack)
{
Heap::Base *o = heapObject();
if (o)
- o->mark(e);
+ o->mark(markStack);
+}
+
+inline void Managed::mark(MarkStack *markStack)
+{
+ Q_ASSERT(m());
+ m()->mark(markStack);
}
#define CHECK_STACK_LIMITS(v4, scope) if ((v4)->checkStackLimits(scope)) return; \
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index 38b5ed8909..8258d644ff 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -66,7 +66,9 @@ struct EngineBase {
Heap::ExecutionContext *current = 0;
Value *jsStackTop = 0;
- quint32 hasException = false;
+ quint8 hasException = false;
+ quint8 writeBarrierActive = false;
+ quint16 unused = 0;
#if QT_POINTER_SIZE == 8
quint8 padding[4];
#endif
@@ -88,7 +90,7 @@ struct EngineBase {
Class_SimpleArrayData,
Class_SparseArrayData,
Class_ExecutionContext,
- Class_CallContext,
+ Class_SimpleCallContext,
Class_Object,
Class_ArrayObject,
Class_FunctionObject,
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 6811438915..b3bd28e18b 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -78,10 +78,10 @@ void Heap::ErrorObject::init()
if (internalClass == scope.engine->internalClasses[EngineBase::Class_ErrorProto])
return;
- *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction();
- *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined();
- *propertyData(QV4::ErrorObject::Index_FileName) = Encode::undefined();
- *propertyData(QV4::ErrorObject::Index_LineNumber) = Encode::undefined();
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue());
+ setProperty(scope.engine, QV4::ErrorObject::Index_FileName, Primitive::undefinedValue());
+ setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::undefinedValue());
}
void Heap::ErrorObject::init(const Value &message, ErrorType t)
@@ -92,17 +92,17 @@ void Heap::ErrorObject::init(const Value &message, ErrorType t)
Scope scope(internalClass->engine);
Scoped<QV4::ErrorObject> e(scope, this);
- *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction();
- *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined();
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue());
e->d()->stackTrace = new StackTrace(scope.engine->stackTrace());
if (!e->d()->stackTrace->isEmpty()) {
- *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace->at(0).source);
- *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace->at(0).line);
+ setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source));
+ setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::fromInt32(e->d()->stackTrace->at(0).line));
}
if (!message.isUndefined())
- *propertyData(QV4::ErrorObject::Index_Message) = message;
+ setProperty(scope.engine, QV4::ErrorObject::Index_Message, message);
}
void Heap::ErrorObject::init(const Value &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t)
@@ -113,8 +113,8 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int
Scope scope(internalClass->engine);
Scoped<QV4::ErrorObject> e(scope, this);
- *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction();
- *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined();
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue());
e->d()->stackTrace = new StackTrace(scope.engine->stackTrace());
StackFrame frame;
@@ -124,12 +124,12 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int
e->d()->stackTrace->prepend(frame);
if (!e->d()->stackTrace->isEmpty()) {
- *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace->at(0).source);
- *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace->at(0).line);
+ setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source));
+ setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::fromInt32(e->d()->stackTrace->at(0).line));
}
if (!message.isUndefined())
- *propertyData(QV4::ErrorObject::Index_Message) = message;
+ setProperty(scope.engine, QV4::ErrorObject::Index_Message, message);
}
const char *ErrorObject::className(Heap::ErrorObject::ErrorType t)
@@ -168,19 +168,11 @@ void ErrorObject::method_get_stack(const BuiltinFunction *, Scope &scope, CallDa
if (frame.line >= 0)
trace += QLatin1Char(':') + QString::number(frame.line);
}
- This->d()->stack = scope.engine->newString(trace);
+ This->d()->stack.set(scope.engine, scope.engine->newString(trace));
}
scope.result = This->d()->stack;
}
-void ErrorObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- ErrorObject::Data *This = static_cast<ErrorObject::Data *>(that);
- if (This->stack)
- This->stack->mark(e);
- Object::markObjects(that, e);
-}
-
DEFINE_OBJECT_VTABLE(ErrorObject);
void Heap::SyntaxErrorObject::init(const Value &msg)
@@ -325,9 +317,9 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He
ScopedObject o(scope);
ctor->defineReadonlyProperty(engine->id_prototype(), (o = obj));
ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
- *obj->propertyData(Index_Constructor) = ctor;
- *obj->propertyData(Index_Message) = engine->id_empty();
- *obj->propertyData(Index_Name) = engine->newString(QString::fromLatin1(ErrorObject::className(t)));
+ obj->setProperty(Index_Constructor, ctor->d());
+ obj->setProperty(Index_Message, engine->id_empty()->d());
+ obj->setProperty(Index_Name, engine->newString(QString::fromLatin1(ErrorObject::className(t))));
obj->defineDefaultProperty(engine->id_toString(), method_toString, 0);
}
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 12531c9309..d556617b48 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -62,7 +62,12 @@ struct SyntaxErrorObject;
namespace Heap {
-struct ErrorObject : Object {
+
+#define ErrorObjectMembers(class, Member) \
+ Member(class, Pointer, String *, stack)
+
+DECLARE_HEAP_OBJECT(ErrorObject, Object) {
+ DECLARE_MARK_TABLE(ErrorObject);
enum ErrorType {
Error,
EvalError,
@@ -72,6 +77,8 @@ struct ErrorObject : Object {
TypeError,
URIError
};
+ StackTrace *stackTrace;
+ ErrorType errorType;
void init();
void init(const Value &message, ErrorType t = Error);
@@ -80,10 +87,6 @@ struct ErrorObject : Object {
delete stackTrace;
Object::destroy();
}
-
- ErrorType errorType;
- StackTrace *stackTrace;
- Pointer<String> stack;
};
struct EvalErrorObject : ErrorObject {
@@ -173,7 +176,6 @@ struct ErrorObject: Object {
static const char *className(Heap::ErrorObject::ErrorType t);
static void method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
template<>
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index f78555dbda..4b88d85e68 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -59,7 +59,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
, hasQmlDependencies(function->hasQmlDependencies())
{
internalClass = engine->internalClasses[EngineBase::Class_Empty];
- const CompiledData::LEUInt32 *formalsIndices = compiledFunction->formalsTable();
+ const quint32_le *formalsIndices = compiledFunction->formalsTable();
// iterate backwards, so we get the right ordering for duplicate names
Scope scope(engine);
ScopedString arg(scope);
@@ -78,14 +78,11 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
}
nFormals = compiledFunction->nFormals;
- const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable();
+ const quint32_le *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
- activationRequired = compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject));
-
- canUseSimpleCall = !needsActivation() && !(compiledFunction->flags & CompiledData::Function::HasCatchOrWith) &&
- !(compiledFunction->nFormals > QV4::Global::ReservedArgumentCount) && !isNamedExpression();
+ canUseSimpleCall = compiledFunction->flags & CompiledData::Function::CanUseSimpleCall;
}
Function::~Function()
@@ -113,11 +110,11 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
}
nFormals = parameters.size();
- const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable();
+ const quint32_le *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
- activationRequired = true;
+ canUseSimpleCall = false;
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index b212b3d027..8b2d14a0cf 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -69,7 +69,6 @@ struct Q_QML_EXPORT Function {
// first nArguments names in internalClass are the actual arguments
InternalClass *internalClass;
uint nFormals;
- bool activationRequired;
bool hasQmlDependencies;
bool canUseSimpleCall;
@@ -90,9 +89,6 @@ struct Q_QML_EXPORT Function {
inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; }
inline bool isNamedExpression() const { return compiledFunction->flags & CompiledData::Function::IsNamedExpression; }
- inline bool needsActivation() const
- { return activationRequired; }
-
inline bool canUseSimpleFunction() const { return canUseSimpleCall; }
QQmlSourceLocation sourceLocation() const
@@ -103,7 +99,7 @@ struct Q_QML_EXPORT Function {
};
-inline unsigned int Heap::CallContext::formalParameterCount() const
+inline unsigned int Heap::SimpleCallContext::formalParameterCount() const
{
return v4Function ? v4Function->nFormals : 0;
}
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 63396998fa..2375aae92b 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -69,11 +69,13 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(FunctionObject);
+Q_STATIC_ASSERT((Heap::FunctionObject::markTable & Heap::Object::markTable) == Heap::Object::markTable);
+
void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, bool createProto)
{
Object::init();
function = nullptr;
- this->scope = scope->d();
+ this->scope.set(scope->engine(), scope->d());
Scope s(scope->engine());
ScopedFunctionObject f(s, this);
f->init(name, createProto);
@@ -84,7 +86,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function
Object::init();
this->function = function;
function->compilationUnit->addref();
- this->scope = scope->d();
+ this->scope.set(scope->engine(), scope->d());
Scope s(scope->engine());
ScopedString name(s, function->name());
ScopedFunctionObject f(s, this);
@@ -102,9 +104,9 @@ void Heap::FunctionObject::init()
{
Object::init();
function = nullptr;
- this->scope = internalClass->engine->rootContext()->d();
+ this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d());
Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype);
- *propertyData(Index_Prototype) = Encode::undefined();
+ setProperty(internalClass->engine, Index_Prototype, Primitive::undefinedValue());
}
@@ -124,14 +126,14 @@ void FunctionObject::init(String *n, bool createProto)
if (createProto) {
ScopedObject proto(s, s.engine->newObject(s.engine->internalClasses[EngineBase::Class_ObjectProto], s.engine->objectPrototype()));
Q_ASSERT(s.engine->internalClasses[EngineBase::Class_ObjectProto]->find(s.engine->id_constructor()) == Heap::FunctionObject::Index_ProtoConstructor);
- *proto->propertyData(Heap::FunctionObject::Index_ProtoConstructor) = this->asReturnedValue();
- *propertyData(Heap::FunctionObject::Index_Prototype) = proto.asReturnedValue();
+ proto->setProperty(Heap::FunctionObject::Index_ProtoConstructor, d());
+ setProperty(Heap::FunctionObject::Index_Prototype, proto);
} else {
- *propertyData(Heap::FunctionObject::Index_Prototype) = Encode::undefined();
+ setProperty(Heap::FunctionObject::Index_Prototype, Primitive::undefinedValue());
}
if (n)
- defineReadonlyProperty(s.engine->id_name(), *n);
+ defineReadonlyConfigurableProperty(s.engine->id_name(), *n);
}
ReturnedValue FunctionObject::name() const
@@ -149,15 +151,6 @@ void FunctionObject::call(const Managed *, Scope &scope, CallData *)
scope.result = Encode::undefined();
}
-void FunctionObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- Heap::FunctionObject *o = static_cast<Heap::FunctionObject *>(that);
- if (o->scope)
- o->scope->mark(e);
-
- Object::markObjects(that, e);
-}
-
Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function)
{
return scope->engine()->memoryManager->allocObject<ScriptFunction>(scope, function);
@@ -258,10 +251,10 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
Scope scope(engine);
ScopedObject o(scope);
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
- defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(0));
+ defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
defineDefaultProperty(engine->id_toString(), method_toString, 0);
defineDefaultProperty(QStringLiteral("apply"), method_apply, 2);
@@ -309,7 +302,7 @@ void FunctionPrototype::method_apply(const BuiltinFunction *, Scope &scope, Call
cData->args[i] = Primitive::undefinedValue();
} else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) {
auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData());
- uint alen = sad ? sad->len : 0;
+ uint alen = sad ? sad->values.size : 0;
if (alen > len)
alen = len;
for (uint i = 0; i < alen; ++i)
@@ -352,8 +345,9 @@ void FunctionPrototype::method_bind(const BuiltinFunction *, Scope &scope, CallD
Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0);
if (callData->argc > 1) {
boundArgs = MemberData::allocate(scope.engine, callData->argc - 1);
- boundArgs->d()->size = callData->argc - 1;
- memcpy(boundArgs->data(), callData->args + 1, (callData->argc - 1)*sizeof(Value));
+ boundArgs->d()->values.size = callData->argc - 1;
+ for (uint i = 0; i < static_cast<uint>(callData->argc - 1); ++i)
+ boundArgs->set(scope.engine, i, callData->args[i + 1]);
}
ExecutionContext *global = scope.engine->rootContext();
@@ -420,7 +414,7 @@ void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData)
void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function)
{
FunctionObject::init();
- this->scope = scope->d();
+ this->scope.set(scope->engine(), scope->d());
this->function = function;
function->compilationUnit->addref();
@@ -433,7 +427,7 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function
ScopedString name(s, function->name());
f->init(name, true);
Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length);
- *propertyData(Index_Length) = Primitive::fromInt32(f->formalParameterCount());
+ setProperty(s.engine, Index_Length, Primitive::fromInt32(f->formalParameterCount()));
if (scope->d()->strictMode) {
ScopedProperty pd(s);
@@ -459,7 +453,6 @@ InternalClass *ScriptFunction::classForConstructor() const
return ic;
}
-
DEFINE_OBJECT_VTABLE(BuiltinFunction);
void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *))
@@ -497,7 +490,7 @@ void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *c
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext();
+ SimpleCallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext();
ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
ctx->callData = callData;
v4->pushContext(ctx);
@@ -514,12 +507,12 @@ DEFINE_OBJECT_VTABLE(BoundFunction);
void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject *target,
const Value &boundThis, QV4::MemberData *boundArgs)
{
+ Scope s(scope);
Heap::FunctionObject::init(scope, QStringLiteral("__bound function__"));
- this->target = target->d();
- this->boundArgs = boundArgs ? boundArgs->d() : 0;
- this->boundThis = boundThis;
+ this->target.set(s.engine, target->d());
+ this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : 0);
+ this->boundThis.set(scope->engine(), boundThis);
- Scope s(scope);
ScopedObject f(s, this);
ScopedValue l(s, target->get(s.engine->id_length()));
@@ -528,7 +521,7 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject
len -= boundArgs->size();
if (len < 0)
len = 0;
- f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(len));
+ f->defineReadonlyConfigurableProperty(s.engine->id_length(), Primitive::fromInt32(len));
ScopedProperty pd(s);
pd->value = s.engine->thrower();
@@ -577,14 +570,3 @@ void BoundFunction::construct(const Managed *that, Scope &scope, CallData *dd)
ScopedFunctionObject t(scope, f->target());
t->construct(scope, callData);
}
-
-void BoundFunction::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- BoundFunction::Data *o = static_cast<BoundFunction::Data *>(that);
- if (o->target)
- o->target->mark(e);
- o->boundThis.mark(e);
- if (o->boundArgs)
- o->boundArgs->mark(e);
- FunctionObject::markObjects(that, e);
-}
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index d691b869fe..6ce5734b6d 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -65,7 +65,12 @@ struct BuiltinFunction;
namespace Heap {
-struct Q_QML_PRIVATE_EXPORT FunctionObject : Object {
+#define FunctionObjectMembers(class, Member) \
+ Member(class, Pointer, ExecutionContext *, scope) \
+ Member(class, NoMark, Function *, function)
+
+DECLARE_HEAP_OBJECT(FunctionObject, Object) {
+ DECLARE_MARK_TABLE(FunctionObject);
enum {
Index_Prototype = 0,
Index_ProtoConstructor = 0
@@ -79,12 +84,8 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object {
unsigned int formalParameterCount() { return function ? function->nFormals : 0; }
unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; }
- bool needsActivation() const { return function ? function->needsActivation() : false; }
const QV4::Object *protoProperty() const { return propertyData(Index_Prototype)->as<QV4::Object>(); }
-
- Pointer<ExecutionContext> scope;
- Function *function;
};
struct FunctionCtor : FunctionObject {
@@ -121,11 +122,15 @@ struct ScriptFunction : FunctionObject {
QV4::InternalClass *cachedClassForConstructor;
};
-struct BoundFunction : FunctionObject {
+#define BoundFunctionMembers(class, Member) \
+ Member(class, Pointer, FunctionObject *, target) \
+ Member(class, HeapValue, HeapValue, boundThis) \
+ Member(class, Pointer, MemberData *, boundArgs)
+
+DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) {
+ DECLARE_MARK_TABLE(BoundFunction);
+
void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs);
- Pointer<FunctionObject> target;
- Value boundThis;
- Pointer<MemberData> boundArgs;
};
}
@@ -156,14 +161,11 @@ struct Q_QML_EXPORT FunctionObject: Object {
static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function);
- bool needsActivation() const { return d()->needsActivation(); }
bool strictMode() const { return d()->function ? d()->function->isStrict() : false; }
bool isBinding() const;
bool isBoundFunction() const;
QQmlSourceLocation sourceLocation() const;
-
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
template<>
@@ -251,8 +253,6 @@ struct BoundFunction: FunctionObject {
static void construct(const Managed *, Scope &scope, CallData *d);
static void call(const Managed *that, Scope &scope, CallData *dd);
-
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
}
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index a3ef395076..5cddf2eaa6 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -178,6 +178,7 @@ namespace Heap {
struct DataView;
struct TypedArray;
+ template <typename T, size_t> struct Pointer;
}
class MemoryManager;
@@ -192,9 +193,12 @@ struct ScriptFunction;
struct InternalClass;
struct Property;
struct Value;
+template<size_t> struct HeapValue;
+template<size_t> struct ValueArray;
struct Lookup;
struct ArrayData;
struct VTable;
+struct Function;
struct BooleanObject;
struct NumberObject;
@@ -252,6 +256,7 @@ enum PropertyFlag {
Attr_NotEnumerable = 0x4,
Attr_NotConfigurable = 0x8,
Attr_ReadOnly = Attr_NotWritable|Attr_NotEnumerable|Attr_NotConfigurable,
+ Attr_ReadOnly_ButConfigurable = Attr_NotWritable|Attr_NotEnumerable,
Attr_Invalid = 0xff
};
diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h
index 89af5db731..b0b08f1e54 100644
--- a/src/qml/jsruntime/qv4identifiertable_p.h
+++ b/src/qml/jsruntime/qv4identifiertable_p.h
@@ -93,14 +93,14 @@ public:
Heap::String *stringFromIdentifier(Identifier *i);
- void mark(ExecutionEngine *e) {
+ void mark(MarkStack *markStack) {
for (int i = 0; i < alloc; ++i) {
Heap::String *entry = entries[i];
if (!entry || entry->isMarked())
continue;
entry->setMarkBit();
Q_ASSERT(entry->vtable()->markObjects);
- entry->vtable()->markObjects(entry, e);
+ entry->vtable()->markObjects(entry, markStack);
}
}
};
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 0bcd510541..603da1df7b 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -133,48 +133,20 @@ InternalClass::InternalClass(const QV4::InternalClass &other)
static void insertHoleIntoPropertyData(Object *object, int idx)
{
- int inlineSize = object->d()->vtable()->nInlineProperties;
- int icSize = object->internalClass()->size;
- int from = qMax(idx, inlineSize);
- int to = from + 1;
- if (from < icSize) {
- memmove(object->propertyData(to), object->propertyData(from),
- (icSize - from - 1) * sizeof(Value));
- }
- if (from == idx)
- return;
- if (inlineSize < icSize)
- *object->propertyData(inlineSize) = *object->propertyData(inlineSize - 1);
- from = idx;
- to = from + 1;
- if (from < inlineSize - 1) {
- memmove(object->propertyData(to), object->propertyData(from),
- (inlineSize - from - 1) * sizeof(Value));
- }
+ Heap::Object *o = object->d();
+ ExecutionEngine *v4 = o->internalClass->engine;
+ int size = o->internalClass->size;
+ for (int i = size - 1; i > idx; --i)
+ o->setProperty(v4, i, *o->propertyData(i - 1));
}
static void removeFromPropertyData(Object *object, int idx, bool accessor = false)
{
- int inlineSize = object->d()->vtable()->nInlineProperties;
- int delta = (accessor ? 2 : 1);
- int oldSize = object->internalClass()->size + delta;
- int to = idx;
- int from = to + delta;
- if (from < inlineSize) {
- memmove(object->propertyData(to), object->d()->propertyData(from), (inlineSize - from)*sizeof(Value));
- to = inlineSize - delta;
- from = inlineSize;
- }
- if (to < inlineSize && from < oldSize) {
- Q_ASSERT(from >= inlineSize);
- memcpy(object->propertyData(to), object->d()->propertyData(from), (inlineSize - to)*sizeof(Value));
- to = inlineSize;
- from = inlineSize + delta;
- }
- if (from < oldSize) {
- Q_ASSERT(to >= inlineSize && from > to);
- memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value));
- }
+ Heap::Object *o = object->d();
+ ExecutionEngine *v4 = o->internalClass->engine;
+ int size = o->internalClass->size;
+ for (int i = idx; i < size; ++i)
+ o->setProperty(v4, i, *o->propertyData(i + (accessor ? 2 : 1)));
}
void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index)
@@ -188,7 +160,7 @@ void InternalClass::changeMember(Object *object, String *string, PropertyAttribu
object->setInternalClass(newClass);
if (newClass->size > oldClass->size) {
Q_ASSERT(newClass->size == oldClass->size + 1);
- insertHoleIntoPropertyData(object, idx + 1);
+ insertHoleIntoPropertyData(object, idx);
} else if (newClass->size < oldClass->size) {
Q_ASSERT(newClass->size == oldClass->size - 1);
removeFromPropertyData(object, idx + 1);
@@ -506,9 +478,9 @@ void InternalClass::destroy()
}
}
-void InternalClassPool::markObjects(ExecutionEngine *engine)
+void InternalClassPool::markObjects(MarkStack *markStack)
{
- InternalClass *ic = engine->internalClasses[EngineBase::Class_Empty];
+ InternalClass *ic = markStack->engine->internalClasses[EngineBase::Class_Empty];
Q_ASSERT(!ic->prototype);
// only need to go two levels into the IC hierarchy, as prototype changes
@@ -519,10 +491,10 @@ void InternalClassPool::markObjects(ExecutionEngine *engine)
InternalClass *ic2 = t.lookup;
for (auto &t2 : ic2->transitions) {
if (t2.flags == InternalClassTransition::PrototypeChange)
- t2.lookup->prototype->mark(engine);
+ t2.lookup->prototype->mark(markStack);
}
} else if (t.flags == InternalClassTransition::PrototypeChange) {
- t.lookup->prototype->mark(engine);
+ t.lookup->prototype->mark(markStack);
}
}
}
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 9e8ab9e73e..df17074e72 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -64,6 +64,7 @@ struct String;
struct Object;
struct Identifier;
struct VTable;
+struct MarkStack;
struct PropertyHashData;
struct PropertyHash
@@ -305,7 +306,7 @@ private:
struct InternalClassPool : public QQmlJS::MemoryPool
{
- void markObjects(ExecutionEngine *engine);
+ void markObjects(MarkStack *markStack);
};
}
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 1d571f53f3..0f021c8bd0 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -705,7 +705,7 @@ QString Stringify::Str(const QString &key, const Value &v)
if (replacerFunction) {
ScopedObject holder(scope, v4->newObject());
- holder->put(scope.engine, QString(), scope.result);
+ holder->put(scope.engine->id_empty(), scope.result);
ScopedCallData callData(scope, 2);
callData->args[0] = v4->newString(key);
callData->args[1] = scope.result;
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 7a158ece35..afadf59bd5 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -60,7 +60,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu
if (index != UINT_MAX) {
level = i;
*attrs = obj->internalClass->propertyData.at(index);
- Value *v = obj->propertyData(index);
+ const Value *v = obj->propertyData(index);
return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs);
}
@@ -73,7 +73,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu
index = obj->internalClass->find(name);
if (index != UINT_MAX) {
*attrs = obj->internalClass->propertyData.at(index);
- Value *v = obj->propertyData(index);
+ const Value *v = obj->propertyData(index);
return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs);
}
@@ -95,7 +95,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
if (index != UINT_MAX) {
level = i;
*attrs = obj->internalClass->propertyData.at(index);
- Value *v = obj->propertyData(index);
+ const Value *v = obj->propertyData(index);
return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs);
}
@@ -108,7 +108,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
index = obj->internalClass->find(name);
if (index != UINT_MAX) {
*attrs = obj->internalClass->propertyData.at(index);
- Value *v = obj->propertyData(index);
+ const Value *v = obj->propertyData(index);
return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs);
}
@@ -117,20 +117,20 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
return Primitive::emptyValue().asReturnedValue();
}
-ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, const Value &object, const Value &index)
+ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index)
{
uint idx;
if (object.isObject() && index.asArrayIndex(idx)) {
l->indexedGetter = indexedGetterObjectInt;
- return indexedGetterObjectInt(l, object, index);
+ return indexedGetterObjectInt(l, engine, object, index);
}
- return indexedGetterFallback(l, object, index);
+ return indexedGetterFallback(l, engine, object, index);
}
-ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, const Value &index)
+ReturnedValue Lookup::indexedGetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index)
{
Q_UNUSED(l);
- Scope scope(l->engine);
+ Scope scope(engine);
uint idx = 0;
bool isInt = index.asArrayIndex(idx);
@@ -148,7 +148,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons
if (object.isNullOrUndefined()) {
QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow());
- return l->engine->throwTypeError(message);
+ return engine->throwTypeError(message);
}
o = RuntimeHelpers::convertToObject(scope.engine, object);
@@ -174,7 +174,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons
}
-ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, const Value &index)
+ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index)
{
uint idx;
if (index.asArrayIndex(idx)) {
@@ -183,7 +183,7 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con
Heap::Object *o = static_cast<Heap::Object *>(b);
if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len)
+ if (idx < s->values.size)
if (!s->data(idx).isEmpty())
return s->data(idx).asReturnedValue();
}
@@ -191,25 +191,25 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con
}
}
- return indexedGetterFallback(l, object, index);
+ return indexedGetterFallback(l, engine, object, index);
}
-void Lookup::indexedSetterGeneric(Lookup *l, const Value &object, const Value &index, const Value &v)
+void Lookup::indexedSetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v)
{
if (Object *o = object.objectValue()) {
uint idx;
if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple && index.asArrayIndex(idx)) {
l->indexedSetter = indexedSetterObjectInt;
- indexedSetterObjectInt(l, object, index, v);
+ indexedSetterObjectInt(l, engine, object, index, v);
return;
}
}
- indexedSetterFallback(l, object, index, v);
+ indexedSetterFallback(l, engine, object, index, v);
}
-void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value &index, const Value &value)
+void Lookup::indexedSetterFallback(Lookup *, ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
- Scope scope(l->engine);
+ Scope scope(engine);
ScopedObject o(scope, object.toObject(scope.engine));
if (scope.engine->hasException)
return;
@@ -218,8 +218,8 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value &
if (index.asArrayIndex(idx)) {
if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len) {
- s->data(idx) = value;
+ if (idx < s->values.size) {
+ s->setData(engine, idx, value);
return;
}
}
@@ -231,7 +231,7 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value &
o->put(name, value);
}
-void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value &index, const Value &v)
+void Lookup::indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v)
{
uint idx;
if (index.asArrayIndex(idx)) {
@@ -240,15 +240,15 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value
Heap::Object *o = static_cast<Heap::Object *>(b);
if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len) {
- s->data(idx) = v;
+ if (idx < s->values.size) {
+ s->setData(engine, idx, v);
return;
}
}
}
}
}
- indexedSetterFallback(l, object, index, v);
+ indexedSetterFallback(l, engine, object, index, v);
}
ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object)
@@ -380,7 +380,7 @@ ReturnedValue Lookup::getter0MemberData(Lookup *l, ExecutionEngine *engine, cons
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass)
- return o->memberData->data[l->index].asReturnedValue();
+ return o->memberData->values.data()[l->index].asReturnedValue();
}
return getterTwoClasses(l, engine, object);
}
@@ -452,7 +452,7 @@ ReturnedValue Lookup::getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine
if (l->classList[0] == o->internalClass)
return o->inlinePropertyData(l->index)->asReturnedValue();
if (l->classList[2] == o->internalClass)
- return o->memberData->data[l->index2].asReturnedValue();
+ return o->memberData->values.data()[l->index2].asReturnedValue();
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
@@ -465,9 +465,9 @@ ReturnedValue Lookup::getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEng
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass)
- return o->memberData->data[l->index].asReturnedValue();
+ return o->memberData->values.data()[l->index].asReturnedValue();
if (l->classList[2] == o->internalClass)
- return o->memberData->data[l->index2].asReturnedValue();
+ return o->memberData->values.data()[l->index2].asReturnedValue();
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
@@ -495,7 +495,7 @@ ReturnedValue Lookup::getter0MemberDatagetter1(Lookup *l, ExecutionEngine *engin
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass)
- return o->memberData->data[l->index].asReturnedValue();
+ return o->memberData->values.data()[l->index].asReturnedValue();
if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype()->internalClass)
return o->prototype()->propertyData(l->index2)->asReturnedValue();
}
@@ -611,7 +611,7 @@ ReturnedValue Lookup::primitiveGetter0MemberData(Lookup *l, ExecutionEngine *eng
if (object.type() == l->type) {
Heap::Object *o = l->proto;
if (l->classList[0] == o->internalClass)
- return o->memberData->data[l->index].asReturnedValue();
+ return o->memberData->values.data()[l->index].asReturnedValue();
}
l->getter = getterGeneric;
return getterGeneric(l, engine, object);
@@ -738,7 +738,7 @@ ReturnedValue Lookup::globalGetter0MemberData(Lookup *l, ExecutionEngine *engine
{
Object *o = engine->globalObject;
if (l->classList[0] == o->internalClass())
- return o->d()->memberData->data[l->index].asReturnedValue();
+ return o->d()->memberData->values.data()[l->index].asReturnedValue();
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
@@ -880,7 +880,7 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va
{
Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
- *o->propertyData(l->index) = value;
+ o->setProperty(engine, l->index, value);
return;
}
@@ -891,7 +891,7 @@ void Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, co
{
Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
- *o->d()->inlinePropertyData(l->index) = value;
+ o->d()->setInlineProperty(engine, l->index, value);
return;
}
@@ -904,7 +904,7 @@ void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, co
if (o && o->internalClass() == l->classList[0]) {
Q_ASSERT(!o->prototype());
o->setInternalClass(l->classList[3]);
- *o->propertyData(l->index) = value;
+ o->setProperty(l->index, value);
return;
}
@@ -921,7 +921,7 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, co
if (p->internalClass == l->classList[1]) {
Q_ASSERT(!p->prototype());
o->setInternalClass(l->classList[3]);
- *o->propertyData(l->index) = value;
+ o->setProperty(l->index, value);
return;
}
}
@@ -942,7 +942,7 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co
if (p->internalClass == l->classList[2]) {
Q_ASSERT(!p->prototype());
o->setInternalClass(l->classList[3]);
- *o->propertyData(l->index) = value;
+ o->setProperty(l->index, value);
return;
}
}
@@ -957,11 +957,11 @@ void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, c
Object *o = static_cast<Object *>(object.managed());
if (o) {
if (o->internalClass() == l->classList[0]) {
- *o->propertyData(l->index) = value;
+ o->setProperty(l->index, value);
return;
}
if (o->internalClass() == l->classList[1]) {
- *o->propertyData(l->index2) = value;
+ o->setProperty(l->index2, value);
return;
}
}
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 151231991f..ce5189a780 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -67,14 +67,13 @@ namespace QV4 {
struct Lookup {
enum { Size = 4 };
union {
- ReturnedValue (*indexedGetter)(Lookup *l, const Value &object, const Value &index);
- void (*indexedSetter)(Lookup *l, const Value &object, const Value &index, const Value &v);
+ ReturnedValue (*indexedGetter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
+ void (*indexedSetter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v);
ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine);
void (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v);
};
union {
- ExecutionEngine *engine;
InternalClass *classList[Size];
struct {
void *dummy0;
@@ -91,13 +90,13 @@ struct Lookup {
uint index;
uint nameIndex;
- static ReturnedValue indexedGetterGeneric(Lookup *l, const Value &object, const Value &index);
- static ReturnedValue indexedGetterFallback(Lookup *l, const Value &object, const Value &index);
- static ReturnedValue indexedGetterObjectInt(Lookup *l, const Value &object, const Value &index);
+ static ReturnedValue indexedGetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
+ static ReturnedValue indexedGetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
+ static ReturnedValue indexedGetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
- static void indexedSetterGeneric(Lookup *l, const Value &object, const Value &index, const Value &v);
- static void indexedSetterFallback(Lookup *l, const Value &object, const Value &index, const Value &value);
- static void indexedSetterObjectInt(Lookup *l, const Value &object, const Value &index, const Value &v);
+ static void indexedSetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v);
+ static void indexedSetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &value);
+ static void indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v);
static ReturnedValue getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -154,7 +153,6 @@ Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value);
// across 32-bit and 64-bit (matters when cross-compiling).
Q_STATIC_ASSERT(offsetof(Lookup, indexedGetter) == 0);
Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0);
-Q_STATIC_ASSERT(offsetof(Lookup, engine) == offsetof(Lookup, getter) + QT_POINTER_SIZE);
}
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 200380eda0..e00eaa0d9b 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -49,6 +49,7 @@ const VTable Managed::static_vtbl =
0,
0,
0,
+ 0,
Managed::IsExecutionContext,
Managed::IsString,
Managed::IsObject,
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 6859334797..40dfc244ea 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -54,6 +54,7 @@
#include "qv4value_p.h"
#include "qv4enginebase_p.h"
#include <private/qv4heap_p.h>
+#include <private/qv4writebarrier_p.h>
QT_BEGIN_NAMESPACE
@@ -92,6 +93,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
dptr->_checkIsInitialized(); \
return dptr; \
} \
+ static Q_CONSTEXPR quint64 markTable = QV4::Heap::DataClass::markTable; \
V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass)
#define V4_MANAGED(DataClass, superClass) \
@@ -130,6 +132,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
#define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \
{ \
parentVTable, \
+ markTable, \
(sizeof(classname::Data) + sizeof(QV4::Value) - 1)/sizeof(QV4::Value), \
(sizeof(classname::Data) + (std::is_same<classname, Object>::value ? 2*sizeof(QV4::Value) : 0) + QV4::Chunk::SlotSize - 1)/QV4::Chunk::SlotSize*QV4::Chunk::SlotSize/sizeof(QV4::Value) \
- (sizeof(classname::Data) + sizeof(QV4::Value) - 1)/sizeof(QV4::Value), \
@@ -143,7 +146,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
classname::MyType, \
#classname, \
Q_VTABLE_FUNCTION(classname, destroy), \
- markObjects, \
+ Q_VTABLE_FUNCTION(classname, markObjects), \
isEqualTo \
}
@@ -215,8 +218,10 @@ public:
bool inUse() const { return d()->inUse(); }
bool markBit() const { return d()->isMarked(); }
+ inline void mark(MarkStack *markStack);
static void destroy(Heap::Base *) {}
+ static void markObjects(Heap::Base *, MarkStack *) {}
Q_ALWAYS_INLINE Heap::Base *heapObject() const {
return m();
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index 109d6c38b5..8782e6deae 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -42,6 +42,7 @@
#include <QtCore/qdatetime.h>
#include <QtCore/qmath.h>
+#include <QtCore/qrandom.h>
#include <QtCore/private/qnumeric_p.h>
#include <QtCore/qthreadstorage.h>
@@ -272,20 +273,9 @@ void MathObject::method_pow(const BuiltinFunction *, Scope &scope, CallData *cal
RETURN_RESULT(Encode(qt_qnan()));
}
-Q_GLOBAL_STATIC(QThreadStorage<bool *>, seedCreatedStorage);
-
void MathObject::method_random(const BuiltinFunction *, Scope &scope, CallData *)
{
- if (!seedCreatedStorage()->hasLocalData()) {
- int msecs = QTime(0,0,0).msecsTo(QTime::currentTime());
- Q_ASSERT(msecs >= 0);
- qsrand(uint(uint(msecs) ^ reinterpret_cast<quintptr>(scope.engine)));
- seedCreatedStorage()->setLocalData(new bool(true));
- }
- // rand()/qrand() return a value where the upperbound is RAND_MAX inclusive. So, instead of
- // dividing by RAND_MAX (which would return 0..RAND_MAX inclusive), we divide by RAND_MAX + 1.
- qint64 upperLimit = qint64(RAND_MAX) + 1;
- RETURN_RESULT(Encode(qrand() / double(upperLimit)));
+ RETURN_RESULT(Encode(QRandomGenerator::global()->generateDouble()));
}
void MathObject::method_round(const BuiltinFunction *, Scope &scope, CallData *callData)
diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp
index db45c77472..8f862d63e9 100644
--- a/src/qml/jsruntime/qv4memberdata.cpp
+++ b/src/qml/jsruntime/qv4memberdata.cpp
@@ -45,24 +45,19 @@ using namespace QV4;
DEFINE_MANAGED_VTABLE(MemberData);
-void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- Heap::MemberData *m = static_cast<Heap::MemberData *>(that);
- for (uint i = 0; i < m->size; ++i)
- m->data[i].mark(e);
-}
-
Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old)
{
- Q_ASSERT(!old || old->size < n);
+ Q_ASSERT(!old || old->values.size < n);
Q_ASSERT(n);
size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value));
Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc);
if (old)
- memcpy(m, old, sizeof(Heap::MemberData) + (old->size - 1)* sizeof(Value));
+ // no write barrier required here
+ memcpy(m, old, sizeof(Heap::MemberData) + (old->values.size - 1) * sizeof(Value));
else
m->init();
- m->size = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
+ m->values.alloc = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
+ m->values.size = m->values.alloc;
return m;
}
diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h
index e239458849..bae524d088 100644
--- a/src/qml/jsruntime/qv4memberdata_p.h
+++ b/src/qml/jsruntime/qv4memberdata_p.h
@@ -59,12 +59,11 @@ namespace QV4 {
namespace Heap {
-struct MemberData : Base {
- union {
- uint size;
- double _dummy;
- };
- Value data[1];
+#define MemberDataMembers(class, Member) \
+ Member(class, ValueArray, ValueArray, values)
+
+DECLARE_HEAP_OBJECT(MemberData, Base) {
+ DECLARE_MARK_TABLE(MemberData);
};
V4_ASSERT_IS_TRIVIAL(MemberData)
@@ -75,14 +74,26 @@ struct MemberData : Managed
V4_MANAGED(MemberData, Managed)
V4_INTERNALCLASS(MemberData)
- Value &operator[] (uint idx) { return d()->data[idx]; }
- const Value *data() const { return d()->data; }
- Value *data() { return d()->data; }
- inline uint size() const { return d()->size; }
+ struct Index {
+ Heap::Base *base;
+ Value *slot;
- static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0);
+ void set(EngineBase *e, Value newVal) {
+ WriteBarrier::write(e, base, slot, newVal);
+ }
+ const Value *operator->() const { return slot; }
+ const Value &operator*() const { return *slot; }
+ bool isNull() const { return !slot; }
+ };
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
+ const Value &operator[] (uint idx) const { return d()->values[idx]; }
+ const Value *data() const { return d()->values.data(); }
+ void set(EngineBase *e, uint index, Value v) { d()->values.set(e, index, v); }
+ void set(EngineBase *e, uint index, Heap::Base *b) { d()->values.set(e, index, b); }
+
+ inline uint size() const { return d()->values.size; }
+
+ static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0);
};
}
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index 255d0212c1..d5c80dbf80 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -102,6 +102,8 @@ void NumberPrototype::init(ExecutionEngine *engine, Object *ctor)
ctor->defineReadonlyProperty(QStringLiteral("POSITIVE_INFINITY"), Primitive::fromDouble(qInf()));
ctor->defineReadonlyProperty(QStringLiteral("MAX_VALUE"), Primitive::fromDouble(1.7976931348623158e+308));
ctor->defineReadonlyProperty(QStringLiteral("EPSILON"), Primitive::fromDouble(std::numeric_limits<double>::epsilon()));
+ ctor->defineReadonlyProperty(QStringLiteral("MAX_SAFE_INTEGER"), Primitive::fromDouble(9007199254740991));
+ ctor->defineReadonlyProperty(QStringLiteral("MIN_SAFE_INTEGER"), Primitive::fromDouble(-9007199254740991));
QT_WARNING_PUSH
QT_WARNING_DISABLE_INTEL(239)
@@ -109,15 +111,17 @@ QT_WARNING_DISABLE_INTEL(239)
QT_WARNING_POP
ctor->defineDefaultProperty(QStringLiteral("isFinite"), method_isFinite, 1);
+ ctor->defineDefaultProperty(QStringLiteral("isInteger"), method_isInteger, 1);
+ ctor->defineDefaultProperty(QStringLiteral("isSafeInteger"), method_isSafeInteger, 1);
ctor->defineDefaultProperty(QStringLiteral("isNaN"), method_isNaN, 1);
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
- defineDefaultProperty(engine->id_toString(), method_toString);
+ defineDefaultProperty(engine->id_toString(), method_toString, 1);
defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString);
defineDefaultProperty(engine->id_valueOf(), method_valueOf);
defineDefaultProperty(QStringLiteral("toFixed"), method_toFixed, 1);
- defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential);
- defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision);
+ defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential, 1);
+ defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision, 1);
}
inline ReturnedValue thisNumberValue(Scope &scope, CallData *callData)
@@ -155,6 +159,52 @@ void NumberPrototype::method_isFinite(const BuiltinFunction *, Scope &scope, Cal
scope.result = Encode(!std::isnan(v) && !qt_is_inf(v));
}
+void NumberPrototype::method_isInteger(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ if (!callData->argc) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ const Value &v = callData->args[0];
+ if (!v.isNumber()) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double dv = v.toNumber();
+ if (std::isnan(dv) || qt_is_inf(dv)) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double iv = v.toInteger();
+ scope.result = Encode(dv == iv);
+}
+
+void NumberPrototype::method_isSafeInteger(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ if (!callData->argc) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ const Value &v = callData->args[0];
+ if (!v.isNumber()) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double dv = v.toNumber();
+ if (std::isnan(dv) || qt_is_inf(dv)) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double iv = v.toInteger();
+ scope.result = Encode(dv == iv && std::fabs(iv) <= (2^53)-1);
+}
+
void NumberPrototype::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData)
{
if (!callData->argc) {
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index 85d306020c..0bc2cd8c65 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -89,6 +89,8 @@ struct NumberPrototype: NumberObject
void init(ExecutionEngine *engine, Object *ctor);
static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isInteger(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isSafeInteger(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 98f5c7464f..94d5a74fe5 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -67,8 +67,8 @@ void Object::setInternalClass(InternalClass *ic)
return;
bool hasMD = d()->memberData != nullptr;
uint requiredSize = ic->size - nInline;
- if (!hasMD || (hasMD && d()->memberData->size < requiredSize))
- d()->memberData = MemberData::allocate(ic->engine, requiredSize, d()->memberData);
+ if (!(hasMD && requiredSize) || (hasMD && d()->memberData->values.size < requiredSize))
+ d()->memberData.set(ic->engine, MemberData::allocate(ic->engine, requiredSize, d()->memberData));
}
void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const
@@ -81,9 +81,9 @@ void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) con
void Object::setProperty(uint index, const Property *p)
{
- *propertyData(index) = p->value;
+ setProperty(index, p->value);
if (internalClass()->propertyData.at(index).isAccessor())
- *propertyData(index + SetterOffset) = p->set;
+ setProperty(index + SetterOffset, p->set);
}
bool Object::setPrototype(Object *proto)
@@ -99,13 +99,6 @@ bool Object::setPrototype(Object *proto)
return true;
}
-void Object::put(ExecutionEngine *engine, const QString &name, const Value &value)
-{
- Scope scope(engine);
- ScopedString n(scope, engine->newString(name));
- put(n, value);
-}
-
ReturnedValue Object::getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs)
{
if (!attrs.isAccessor())
@@ -121,16 +114,16 @@ ReturnedValue Object::getValue(const Value &thisObject, const Value &v, Property
return scope.result.asReturnedValue();
}
-void Object::putValue(uint memberIndex, const Value &value)
+bool Object::putValue(uint memberIndex, const Value &value)
{
QV4::InternalClass *ic = internalClass();
if (ic->engine->hasException)
- return;
+ return false;
PropertyAttributes attrs = ic->propertyData[memberIndex];
if (attrs.isAccessor()) {
- FunctionObject *set = propertyData(memberIndex + SetterOffset)->as<FunctionObject>();
+ const FunctionObject *set = propertyData(memberIndex + SetterOffset)->as<FunctionObject>();
if (set) {
Scope scope(ic->engine);
ScopedFunctionObject setter(scope, set);
@@ -138,7 +131,7 @@ void Object::putValue(uint memberIndex, const Value &value)
callData->args[0] = value;
callData->thisObject = this;
setter->call(scope, callData);
- return;
+ return !ic->engine->hasException;
}
goto reject;
}
@@ -146,12 +139,13 @@ void Object::putValue(uint memberIndex, const Value &value)
if (!attrs.isWritable())
goto reject;
- *propertyData(memberIndex) = value;
- return;
+ setProperty(memberIndex, value);
+ return true;
reject:
if (engine()->current->strictMode)
engine()->throwTypeError();
+ return false;
}
void Object::defineDefaultProperty(const QString &name, const Value &value)
@@ -169,7 +163,7 @@ void Object::defineDefaultProperty(const QString &name, void (*code)(const Built
ScopedString s(scope, e->newIdentifier(name));
ExecutionContext *global = e->rootContext();
ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code));
- function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
defineDefaultProperty(s, function);
}
@@ -179,7 +173,7 @@ void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunct
Scope scope(e);
ExecutionContext *global = e->rootContext();
ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code));
- function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
defineDefaultProperty(name, function);
}
@@ -217,19 +211,27 @@ void Object::defineReadonlyProperty(String *name, const Value &value)
insertMember(name, value, Attr_ReadOnly);
}
-void Object::markObjects(Heap::Base *that, ExecutionEngine *e)
+void Object::defineReadonlyConfigurableProperty(const QString &name, const Value &value)
{
- Heap::Object *o = static_cast<Heap::Object *>(that);
+ QV4::ExecutionEngine *e = engine();
+ Scope scope(e);
+ ScopedString s(scope, e->newIdentifier(name));
+ defineReadonlyConfigurableProperty(s, value);
+}
- if (o->memberData)
- o->memberData->mark(e);
- if (o->arrayData)
- o->arrayData->mark(e);
+void Object::defineReadonlyConfigurableProperty(String *name, const Value &value)
+{
+ insertMember(name, value, Attr_ReadOnly_ButConfigurable);
+}
+
+void Object::markObjects(Heap::Base *b, MarkStack *stack)
+{
+ Heap::Object *o = static_cast<Heap::Object *>(b);
uint nInline = o->vtable()->nInlineProperties;
Value *v = reinterpret_cast<Value *>(o) + o->vtable()->inlinePropertyOffset;
const Value *end = v + nInline;
while (v < end) {
- v->mark(e);
+ v->mark(stack);
++v;
}
}
@@ -240,10 +242,10 @@ void Object::insertMember(String *s, const Property *p, PropertyAttributes attri
InternalClass::addMember(this, s, attributes, &idx);
if (attributes.isAccessor()) {
- *propertyData(idx + GetterOffset) = p->value;
- *propertyData(idx + SetterOffset) = p->set;
+ setProperty(idx + GetterOffset, p->value);
+ setProperty(idx + SetterOffset, p->set);
} else {
- *propertyData(idx) = p->value;
+ setProperty(idx, p->value);
}
}
@@ -275,12 +277,9 @@ void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p
void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p)
{
- Property *pd = arrayData() ? arrayData()->getProperty(index) : 0;
- if (pd) {
- *attrs = arrayData()->attributes(index);
- if (p)
- p->copy(pd, *attrs);
- return;
+ if (arrayData()) {
+ if (arrayData()->getProperty(index, p, attrs))
+ return;
}
if (isStringObject()) {
*attrs = Attr_NotConfigurable|Attr_NotWritable;
@@ -295,7 +294,7 @@ void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p)
}
// Section 8.12.2
-Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs)
+MemberData::Index Object::getValueOrSetter(String *name, PropertyAttributes *attrs)
{
Q_ASSERT(name->asArrayIndex() == UINT_MAX);
@@ -307,36 +306,38 @@ Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs)
uint idx = o->internalClass->find(id);
if (idx < UINT_MAX) {
*attrs = o->internalClass->propertyData[idx];
- return o->propertyData(attrs->isAccessor() ? idx + SetterOffset : idx);
+ return o->writablePropertyData(attrs->isAccessor() ? idx + SetterOffset : idx );
}
o = o->prototype();
}
*attrs = Attr_Invalid;
- return 0;
+ return { 0, 0 };
}
-Value *Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
+ArrayData::Index Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
{
Heap::Object *o = d();
while (o) {
- Property *p = o->arrayData ? o->arrayData->getProperty(index) : 0;
- if (p) {
- *attrs = o->arrayData->attributes(index);
- return attrs->isAccessor() ? &p->set : &p->value;
+ if (o->arrayData) {
+ uint idx = o->arrayData->mappedIndex(index);
+ if (idx != UINT_MAX) {
+ *attrs = o->arrayData->attributes(index);
+ return { o->arrayData , attrs->isAccessor() ? idx + SetterOffset : idx };
+ }
}
if (o->vtable()->type == Type_StringObject) {
if (index < static_cast<const Heap::StringObject *>(o)->length()) {
// this is an evil hack, but it works, as the method is only ever called from putIndexed,
// where we don't use the returned pointer there for non writable attributes
*attrs = (Attr_NotWritable|Attr_NotConfigurable);
- return reinterpret_cast<Value *>(0x1);
+ return { reinterpret_cast<Heap::ArrayData *>(0x1), 0 };
}
}
o = o->prototype();
}
*attrs = Attr_Invalid;
- return 0;
+ return { 0, 0 };
}
bool Object::hasProperty(String *name) const
@@ -421,14 +422,14 @@ ReturnedValue Object::getIndexed(const Managed *m, uint index, bool *hasProperty
return static_cast<const Object *>(m)->internalGetIndexed(index, hasProperty);
}
-void Object::put(Managed *m, String *name, const Value &value)
+bool Object::put(Managed *m, String *name, const Value &value)
{
- static_cast<Object *>(m)->internalPut(name, value);
+ return static_cast<Object *>(m)->internalPut(name, value);
}
-void Object::putIndexed(Managed *m, uint index, const Value &value)
+bool Object::putIndexed(Managed *m, uint index, const Value &value)
{
- static_cast<Object *>(m)->internalPutIndexed(index, value);
+ return static_cast<Object *>(m)->internalPutIndexed(index, value);
}
PropertyAttributes Object::query(const Managed *m, String *name)
@@ -524,7 +525,7 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value)
l->classList[0] = o->internalClass();
l->index = idx;
l->setter = idx < o->d()->vtable()->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0;
- *o->propertyData(idx) = value;
+ o->setProperty(idx, value);
return;
}
@@ -579,7 +580,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *
int k = it->arrayNode->key();
uint pidx = it->arrayNode->value;
Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>();
- Property *p = reinterpret_cast<Property *>(sa->arrayData + pidx);
+ const Property *p = reinterpret_cast<const Property *>(sa->values.data() + pidx);
it->arrayNode = it->arrayNode->nextNode();
PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data;
if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
@@ -594,9 +595,9 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *
it->arrayIndex = UINT_MAX;
}
// dense arrays
- while (it->arrayIndex < o->d()->arrayData->len) {
+ while (it->arrayIndex < o->d()->arrayData->values.size) {
Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- Value &val = sa->data(it->arrayIndex);
+ const Value &val = sa->data(it->arrayIndex);
PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex);
++it->arrayIndex;
if (!val.isEmpty()
@@ -663,15 +664,14 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) const
ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
{
- Property *pd = 0;
PropertyAttributes attrs;
Scope scope(engine());
ScopedObject o(scope, this);
+ ScopedProperty pd(scope);
+ bool exists = false;
while (o) {
- Property *p = o->arrayData() ? o->arrayData()->getProperty(index) : 0;
- if (p) {
- pd = p;
- attrs = o->arrayData()->attributes(index);
+ if (o->arrayData() && o->arrayData()->getProperty(index, pd, &attrs)) {
+ exists = true;
break;
}
if (o->isStringObject()) {
@@ -686,7 +686,7 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
o = o->prototype();
}
- if (pd) {
+ if (exists) {
if (hasProperty)
*hasProperty = true;
return getValue(pd->value, attrs);
@@ -699,10 +699,11 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
// Section 8.12.5
-void Object::internalPut(String *name, const Value &value)
+bool Object::internalPut(String *name, const Value &value)
{
- if (internalClass()->engine->hasException)
- return;
+ ExecutionEngine *engine = this->engine();
+ if (engine->hasException)
+ return false;
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
@@ -711,45 +712,46 @@ void Object::internalPut(String *name, const Value &value)
name->makeIdentifier();
Identifier *id = name->identifier();
+ MemberData::Index memberIndex{0, 0};
uint member = internalClass()->find(id);
- Value *v = 0;
PropertyAttributes attrs;
if (member < UINT_MAX) {
attrs = internalClass()->propertyData[member];
- v = propertyData(attrs.isAccessor() ? member + SetterOffset : member);
+ memberIndex = d()->writablePropertyData(attrs.isAccessor() ? member + SetterOffset : member);
}
// clause 1
- if (v) {
+ if (!memberIndex.isNull()) {
if (attrs.isAccessor()) {
- if (v->as<FunctionObject>())
+ if (memberIndex->as<FunctionObject>())
goto cont;
goto reject;
} else if (!attrs.isWritable())
goto reject;
- else if (isArrayObject() && name->equals(engine()->id_length())) {
+ else if (isArrayObject() && name->equals(engine->id_length())) {
bool ok;
uint l = value.asArrayLength(&ok);
if (!ok) {
- engine()->throwRangeError(value);
- return;
+ engine->throwRangeError(value);
+ return false;
}
ok = setArrayLength(l);
if (!ok)
goto reject;
} else {
- *v = value;
+ memberIndex.set(engine, value);
}
- return;
+ return true;
} else if (!prototype()) {
if (!isExtensible())
goto reject;
} else {
// clause 4
- Scope scope(engine());
- if ((v = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs))) {
+ Scope scope(engine);
+ memberIndex = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs);
+ if (!memberIndex.isNull()) {
if (attrs.isAccessor()) {
- if (!v->as<FunctionObject>())
+ if (!memberIndex->as<FunctionObject>())
goto reject;
} else if (!isExtensible() || !attrs.isWritable()) {
goto reject;
@@ -762,64 +764,68 @@ void Object::internalPut(String *name, const Value &value)
cont:
// Clause 5
- if (v && attrs.isAccessor()) {
- Q_ASSERT(v->as<FunctionObject>());
+ if (!memberIndex.isNull() && attrs.isAccessor()) {
+ Q_ASSERT(memberIndex->as<FunctionObject>());
- Scope scope(engine());
- ScopedFunctionObject setter(scope, *v);
+ Scope scope(engine);
+ ScopedFunctionObject setter(scope, *memberIndex);
ScopedCallData callData(scope, 1);
callData->args[0] = value;
callData->thisObject = this;
setter->call(scope, callData);
- return;
+ return !internalClass()->engine->hasException;
}
insertMember(name, value);
- return;
+ return true;
reject:
- if (engine()->current->strictMode) {
+ // ### this should be removed once everything is ported to use Object::set()
+ if (engine->current->strictMode) {
QString message = QLatin1String("Cannot assign to read-only property \"") +
name->toQString() + QLatin1Char('\"');
- engine()->throwTypeError(message);
+ engine->throwTypeError(message);
}
+ return false;
}
-void Object::internalPutIndexed(uint index, const Value &value)
+bool Object::internalPutIndexed(uint index, const Value &value)
{
- if (internalClass()->engine->hasException)
- return;
+ ExecutionEngine *engine = this->engine();
+ if (engine->hasException)
+ return false;
PropertyAttributes attrs;
- Value *v = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : 0;
+ ArrayData::Index arrayIndex = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : ArrayData::Index{ 0, 0 };
- if (!v && isStringObject()) {
+ if (arrayIndex.isNull() && isStringObject()) {
if (index < static_cast<StringObject *>(this)->length())
// not writable
goto reject;
}
// clause 1
- if (v) {
+ if (!arrayIndex.isNull()) {
if (attrs.isAccessor()) {
- if (v->as<FunctionObject>())
+ if (arrayIndex->as<FunctionObject>())
goto cont;
goto reject;
} else if (!attrs.isWritable())
goto reject;
- else
- *v = value;
- return;
+
+ arrayIndex.set(engine, value);
+ return true;
} else if (!prototype()) {
if (!isExtensible())
goto reject;
} else {
// clause 4
- Scope scope(engine());
- if ((v = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs))) {
+ Scope scope(engine);
+ arrayIndex = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs);
+ if (!arrayIndex.isNull()) {
if (attrs.isAccessor()) {
- if (!v->as<FunctionObject>())
+ if (!arrayIndex->as<FunctionObject>())
goto reject;
} else if (!isExtensible() || !attrs.isWritable()) {
goto reject;
@@ -832,24 +838,26 @@ void Object::internalPutIndexed(uint index, const Value &value)
cont:
// Clause 5
- if (v && attrs.isAccessor()) {
- Q_ASSERT(v->as<FunctionObject>());
+ if (!arrayIndex.isNull() && attrs.isAccessor()) {
+ Q_ASSERT(arrayIndex->as<FunctionObject>());
- Scope scope(engine());
- ScopedFunctionObject setter(scope, *v);
+ Scope scope(engine);
+ ScopedFunctionObject setter(scope, *arrayIndex);
ScopedCallData callData(scope, 1);
callData->args[0] = value;
callData->thisObject = this;
setter->call(scope, callData);
- return;
+ return !internalClass()->engine->hasException;
}
arraySet(index, value);
- return;
+ return true;
reject:
- if (engine()->current->strictMode)
- engine()->throwTypeError();
+ // ### this should be removed once everything is ported to use Object::setIndexed()
+ if (engine->current->strictMode)
+ engine->throwTypeError();
+ return false;
}
// Section 8.12.7
@@ -978,8 +986,8 @@ bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Prope
// Clause 1
if (arrayData()) {
- hasProperty = arrayData()->getProperty(index);
- if (!hasProperty && isStringObject())
+ hasProperty = arrayData()->mappedIndex(index) != UINT_MAX;
+ if (!hasProperty && isStringObject())
hasProperty = (index < static_cast<StringObject *>(this)->length());
}
@@ -1091,7 +1099,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *
setProperty(index, current);
} else {
setArrayAttributes(index, cattrs);
- arrayData()->setProperty(index, current);
+ arrayData()->setProperty(scope.engine, index, current);
}
return true;
reject:
@@ -1127,7 +1135,8 @@ void Object::copyArrayData(Object *other)
;
} else {
Q_ASSERT(!arrayData() && other->arrayData());
- ArrayData::realloc(this, other->d()->arrayData->type, other->d()->arrayData->alloc, false);
+ ArrayData::realloc(this, static_cast<ArrayData::Type>(other->d()->arrayData->type),
+ other->d()->arrayData->values.alloc, false);
if (other->arrayType() == Heap::ArrayData::Sparse) {
Heap::ArrayData *od = other->d()->arrayData;
Heap::ArrayData *dd = d()->arrayData;
@@ -1135,10 +1144,11 @@ void Object::copyArrayData(Object *other)
dd->freeList = od->freeList;
} else {
Heap::ArrayData *dd = d()->arrayData;
- dd->len = other->d()->arrayData->len;
+ dd->values.size = other->d()->arrayData->values.size;
dd->offset = other->d()->arrayData->offset;
}
- memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, other->d()->arrayData->alloc*sizeof(Value));
+ // ### need a write barrier
+ memcpy(d()->arrayData->values.values, other->d()->arrayData->values.values, other->d()->arrayData->values.alloc*sizeof(Value));
}
setArrayLengthUnchecked(other->getLength());
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 9592ff5d1b..066a93cc61 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -67,7 +67,12 @@ struct BuiltinFunction;
namespace Heap {
-struct Object : Base {
+#define ObjectMembers(class, Member) \
+ Member(class, Pointer, MemberData *, memberData) \
+ Member(class, Pointer, ArrayData *, arrayData)
+
+DECLARE_HEAP_OBJECT(Object, Base) {
+ DECLARE_MARK_TABLE(Object);
void init() { Base::init(); }
void destroy() { Base::destroy(); }
@@ -75,9 +80,23 @@ struct Object : Base {
Q_ASSERT(index < vtable()->nInlineProperties);
return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index;
}
- Value *inlinePropertyData(uint index) {
+ void setInlineProperty(ExecutionEngine *e, uint index, Value v) {
+ Q_ASSERT(index < vtable()->nInlineProperties);
+ Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
+ WriteBarrier::write(e, this, prop, v);
+ }
+ void setInlineProperty(ExecutionEngine *e, uint index, Heap::Base *b) {
Q_ASSERT(index < vtable()->nInlineProperties);
- return reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
+ Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
+ WriteBarrier::write(e, this, prop, b);
+ }
+
+ QV4::MemberData::Index writablePropertyData(uint index) {
+ uint nInline = vtable()->nInlineProperties;
+ if (index < nInline)
+ return { this, reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index};
+ index -= nInline;
+ return { memberData, memberData->values.values + index };
}
const Value *propertyData(uint index) const {
@@ -85,21 +104,32 @@ struct Object : Base {
if (index < nInline)
return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index;
index -= nInline;
- return memberData->data + index;
+ return memberData->values.data() + index;
}
- Value *propertyData(uint index) {
+ void setProperty(ExecutionEngine *e, uint index, Value v) {
uint nInline = vtable()->nInlineProperties;
- if (index < nInline)
- return reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
+ if (index < nInline) {
+ setInlineProperty(e, index, v);
+ return;
+ }
+ index -= nInline;
+ memberData->values.set(e, index, v);
+ }
+ void setProperty(ExecutionEngine *e, uint index, Heap::Base *b) {
+ uint nInline = vtable()->nInlineProperties;
+ if (index < nInline) {
+ setInlineProperty(e, index, b);
+ return;
+ }
index -= nInline;
- return memberData->data + index;
+ memberData->values.set(e, index, b);
}
Heap::Object *prototype() const { return internalClass->prototype; }
- Pointer<MemberData> memberData;
- Pointer<ArrayData> arrayData;
};
+Q_STATIC_ASSERT(Object::markTable == ((2 << 2) | (2 << 4)));
+
}
#define V4_OBJECT(superClass) \
@@ -134,7 +164,8 @@ struct Object : Base {
dptr->_checkIsInitialized(); \
return dptr; \
} \
- V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass);
+ V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); \
+ static Q_CONSTEXPR quint64 markTable = QV4::Heap::DataClass::markTable;
#define V4_PROTOTYPE(p) \
static QV4::Object *defaultPrototype(QV4::ExecutionEngine *e) \
@@ -147,8 +178,8 @@ struct ObjectVTable
void (*construct)(const Managed *, Scope &scope, CallData *data);
ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty);
ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty);
- void (*put)(Managed *, String *name, const Value &value);
- void (*putIndexed)(Managed *, uint index, const Value &value);
+ bool (*put)(Managed *, String *name, const Value &value);
+ bool (*putIndexed)(Managed *, uint index, const Value &value);
PropertyAttributes (*query)(const Managed *, String *name);
PropertyAttributes (*queryIndexed)(const Managed *, uint index);
bool (*deleteProperty)(Managed *m, String *name);
@@ -206,13 +237,16 @@ struct Q_QML_EXPORT Object: Managed {
void setInternalClass(InternalClass *ic);
const Value *propertyData(uint index) const { return d()->propertyData(index); }
- Value *propertyData(uint index) { return d()->propertyData(index); }
Heap::ArrayData *arrayData() const { return d()->arrayData; }
- void setArrayData(ArrayData *a) { d()->arrayData = a->d(); }
+ void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a->d()); }
void getProperty(uint index, Property *p, PropertyAttributes *attrs) const;
void setProperty(uint index, const Property *p);
+ void setProperty(uint index, Value v) const { d()->setProperty(engine(), index, v); }
+ void setProperty(uint index, Heap::Base *b) const { d()->setProperty(engine(), index, b); }
+ void setProperty(ExecutionEngine *engine, uint index, Value v) const { d()->setProperty(engine, index, v); }
+ void setProperty(ExecutionEngine *engine, uint index, Heap::Base *b) const { d()->setProperty(engine, index, b); }
const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(d()->vtable()); }
Heap::Object *prototype() const { return d()->prototype(); }
@@ -221,8 +255,8 @@ struct Q_QML_EXPORT Object: Managed {
void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0);
void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0);
- Value *getValueOrSetter(String *name, PropertyAttributes *attrs);
- Value *getValueOrSetter(uint index, PropertyAttributes *attrs);
+ MemberData::Index getValueOrSetter(String *name, PropertyAttributes *attrs);
+ ArrayData::Index getValueOrSetter(uint index, PropertyAttributes *attrs);
bool hasProperty(String *name) const;
bool hasProperty(uint index) const;
@@ -239,8 +273,6 @@ struct Q_QML_EXPORT Object: Managed {
//
// helpers
//
- void put(ExecutionEngine *engine, const QString &name, const Value &value);
-
static ReturnedValue getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs);
ReturnedValue getValue(const Value &v, PropertyAttributes attrs) const {
Scope scope(this->engine());
@@ -248,7 +280,7 @@ struct Q_QML_EXPORT Object: Managed {
return getValue(t, v, attrs);
}
- void putValue(uint memberIndex, const Value &value);
+ bool putValue(uint memberIndex, const Value &value);
/* The spec default: Writable: true, Enumerable: false, Configurable: true */
void defineDefaultProperty(String *name, const Value &value) {
@@ -265,6 +297,10 @@ struct Q_QML_EXPORT Object: Managed {
void defineReadonlyProperty(const QString &name, const Value &value);
void defineReadonlyProperty(String *name, const Value &value);
+ /* Fixed: Writable: false, Enumerable: false, Configurable: true */
+ void defineReadonlyConfigurableProperty(const QString &name, const Value &value);
+ void defineReadonlyConfigurableProperty(String *name, const Value &value);
+
void insertMember(String *s, const Value &v, PropertyAttributes attributes = Attr_Data) {
Scope scope(engine());
ScopedProperty p(scope);
@@ -304,7 +340,7 @@ public:
void push_back(const Value &v);
ArrayData::Type arrayType() const {
- return arrayData() ? d()->arrayData->type : Heap::ArrayData::Simple;
+ return arrayData() ? static_cast<ArrayData::Type>(d()->arrayData->type) : Heap::ArrayData::Simple;
}
// ### remove me
void setArrayType(ArrayData::Type t) {
@@ -344,10 +380,47 @@ public:
{ return vtable()->get(this, name, hasProperty); }
inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) const
{ return vtable()->getIndexed(this, idx, hasProperty); }
- inline void put(String *name, const Value &v)
- { vtable()->put(this, name, v); }
- inline void putIndexed(uint idx, const Value &v)
- { vtable()->putIndexed(this, idx, v); }
+
+ // use the set variants instead, to customize throw behavior
+ inline bool put(String *name, const Value &v)
+ { return vtable()->put(this, name, v); }
+ inline bool putIndexed(uint idx, const Value &v)
+ { return vtable()->putIndexed(this, idx, v); }
+
+ enum ThrowOnFailure {
+ DoThrowOnRejection,
+ DoNotThrow
+ };
+
+ // ES6: 7.3.3 Set (O, P, V, Throw)
+ inline bool set(String *name, const Value &v, ThrowOnFailure shouldThrow)
+ {
+ bool ret = vtable()->put(this, name, v);
+ // ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception.
+ if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) {
+ ExecutionEngine *e = engine();
+ if (!e->hasException) { // allow a custom set impl to throw itself
+ QString message = QLatin1String("Cannot assign to read-only property \"") +
+ name->toQString() + QLatin1Char('\"');
+ e->throwTypeError(message);
+ }
+ }
+ return ret;
+ }
+
+ inline bool setIndexed(uint idx, const Value &v, ThrowOnFailure shouldThrow)
+ {
+ bool ret = vtable()->putIndexed(this, idx, v);
+ if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) {
+ ExecutionEngine *e = engine();
+ if (!e->hasException) { // allow a custom set impl to throw itself
+ e->throwTypeError();
+ }
+ }
+ return ret;
+ }
+
+
PropertyAttributes query(String *name) const
{ return vtable()->query(this, name); }
PropertyAttributes queryIndexed(uint index) const
@@ -371,13 +444,12 @@ public:
inline void call(Scope &scope, CallData *d) const
{ vtable()->call(this, scope, d); }
protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
static void construct(const Managed *m, Scope &scope, CallData *);
static void call(const Managed *m, Scope &scope, CallData *);
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
- static void putIndexed(Managed *m, uint index, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
+ static bool putIndexed(Managed *m, uint index, const Value &value);
static PropertyAttributes query(const Managed *m, String *name);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
static bool deleteProperty(Managed *m, String *name);
@@ -387,12 +459,13 @@ protected:
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static uint getLength(const Managed *m);
static ReturnedValue instanceOf(const Object *typeObject, const Value &var);
+ static void markObjects(Heap::Base *, MarkStack *);
private:
ReturnedValue internalGet(String *name, bool *hasProperty) const;
ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const;
- void internalPut(String *name, const Value &value);
- void internalPutIndexed(uint index, const Value &value);
+ bool internalPut(String *name, const Value &value);
+ bool internalPutIndexed(uint index, const Value &value);
bool internalDeleteProperty(String *name);
bool internalDeleteIndexedProperty(uint index);
@@ -436,7 +509,7 @@ struct ArrayObject : Object {
private:
void commonInit()
- { *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); }
+ { setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(0)); }
};
}
@@ -476,7 +549,7 @@ struct ArrayObject: Object {
inline void Object::setArrayLengthUnchecked(uint l)
{
if (isArrayObject())
- *propertyData(Heap::ArrayObject::LengthPropertyIndex) = Primitive::fromUInt32(l);
+ setProperty(Heap::ArrayObject::LengthPropertyIndex, Primitive::fromUInt32(l));
}
inline void Object::push_back(const Value &v)
@@ -493,7 +566,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a
{
// ### Clean up
arrayCreate();
- if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->alloc)) {
+ if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->values.alloc)) {
initSparseArray();
} else {
arrayData()->vtable()->reallocate(this, index + 1, false);
@@ -508,7 +581,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a
inline void Object::arraySet(uint index, const Value &value)
{
arrayCreate();
- if (index > 0x1000 && index > 2*d()->arrayData->alloc) {
+ if (index > 0x1000 && index > 2*d()->arrayData->values.alloc) {
initSparseArray();
}
ArrayData::insert(this, index, &value);
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index 59115dfe21..3427ee89fe 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -177,10 +177,10 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString()
DEFINE_OBJECT_VTABLE(ForEachIteratorObject);
-void ForEachIteratorObject::markObjects(Heap::Base *that, ExecutionEngine *e)
+void ForEachIteratorObject::markObjects(Heap::Base *that, MarkStack *markStack)
{
ForEachIteratorObject::Data *o = static_cast<ForEachIteratorObject::Data *>(that);
- o->workArea[0].mark(e);
- o->workArea[1].mark(e);
- Object::markObjects(that, e);
+ o->workArea[0].mark(markStack);
+ o->workArea[1].mark(markStack);
+ Object::markObjects(that, markStack);
}
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index 98e94a95ea..6168d59914 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -129,7 +129,7 @@ struct ForEachIteratorObject: Object {
ReturnedValue nextPropertyName() { return d()->it().nextPropertyNameAsString(); }
protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
+ static void markObjects(Heap::Base *that, MarkStack *markStack);
};
inline
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 97dbe24339..2e72c0f13f 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -89,10 +90,11 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
ScopedObject o(scope, this);
ctor->defineReadonlyProperty(v4->id_prototype(), o);
- ctor->defineReadonlyProperty(v4->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyConfigurableProperty(v4->id_length(), Primitive::fromInt32(1));
ctor->defineDefaultProperty(QStringLiteral("getPrototypeOf"), method_getPrototypeOf, 1);
ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), method_getOwnPropertyDescriptor, 2);
ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyNames"), method_getOwnPropertyNames, 1);
+ ctor->defineDefaultProperty(QStringLiteral("assign"), method_assign, 2);
ctor->defineDefaultProperty(QStringLiteral("create"), method_create, 2);
ctor->defineDefaultProperty(QStringLiteral("defineProperty"), method_defineProperty, 3);
ctor->defineDefaultProperty(QStringLiteral("defineProperties"), method_defineProperties, 2);
@@ -123,9 +125,8 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
ScopedObject p(scope, o->prototype());
scope.result = !!p ? p->asReturnedValue() : Encode::null();
@@ -133,11 +134,8 @@ void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scop
void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject O(scope, callData->argument(0));
- if (!O) {
- scope.result = scope.engine->throwTypeError();
- return;
- }
+ ScopedObject O(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
if (ArgumentsObject::isNonStrictArgumentsObject(O))
static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate();
@@ -154,13 +152,54 @@ void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, S
void ObjectPrototype::method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject O(scope, callData->argument(0));
- if (!O) {
- scope.result = scope.engine->throwTypeError();
+ ScopedObject O(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
+
+ scope.result = getOwnPropertyNames(scope.engine, callData->args[0]);
+}
+
+// 19.1.2.1
+void ObjectPrototype::method_assign(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ ScopedObject to(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
+
+ if (callData->argc == 1) {
+ scope.result = to;
return;
}
- scope.result = getOwnPropertyNames(scope.engine, callData->args[0]);
+ for (int i = 1; i < callData->argc; ++i) {
+ if (callData->args[i].isUndefined() || callData->args[i].isNull())
+ continue;
+
+ ScopedObject from(scope, callData->args[i].toObject(scope.engine));
+ CHECK_EXCEPTION();
+ QV4::ScopedArrayObject keys(scope, QV4::ObjectPrototype::getOwnPropertyNames(scope.engine, from));
+ quint32 length = keys->getLength();
+
+ ScopedString nextKey(scope);
+ ScopedValue propValue(scope);
+ for (quint32 i = 0; i < length; ++i) {
+ nextKey = Value::fromReturnedValue(keys->getIndexed(i)).toString(scope.engine);
+
+ PropertyAttributes attrs;
+ ScopedProperty prop(scope);
+ from->getOwnProperty(nextKey, &attrs, prop);
+
+ if (attrs == PropertyFlag::Attr_Invalid)
+ continue;
+
+ if (!attrs.isEnumerable())
+ continue;
+
+ propValue = from->get(nextKey);
+ to->set(nextKey, propValue, Object::DoThrowOnRejection);
+ CHECK_EXCEPTION();
+ }
+ }
+
+ scope.result = to;
}
void ObjectPrototype::method_create(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
@@ -246,14 +285,17 @@ void ObjectPrototype::method_defineProperties(const BuiltinFunction *, Scope &sc
void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallData *callData)
{
ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ if (!o) {
+ // 19.1.2.17, 1
+ scope.result = callData->argument(0);
+ return;
+ }
o->setInternalClass(o->internalClass()->sealed());
if (o->arrayData()) {
ArrayData::ensureAttributes(o);
- for (uint i = 0; i < o->d()->arrayData->alloc; ++i) {
+ for (uint i = 0; i < o->d()->arrayData->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
o->d()->arrayData->attrs[i].setConfigurable(false);
}
@@ -265,8 +307,11 @@ void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallDat
void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData)
{
ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ if (!o) {
+ // 19.1.2.5, 1
+ scope.result = callData->argument(0);
+ return;
+ }
if (ArgumentsObject::isNonStrictArgumentsObject(o))
static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate();
@@ -275,7 +320,7 @@ void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallD
if (o->arrayData()) {
ArrayData::ensureAttributes(o);
- for (uint i = 0; i < o->arrayData()->alloc; ++i) {
+ for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
o->arrayData()->attrs[i].setConfigurable(false);
if (o->arrayData()->attrs[i].isData())
@@ -287,9 +332,11 @@ void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallD
void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = callData->argument(0);
+ return;
+ }
o->setInternalClass(o->internalClass()->nonExtensible());
scope.result = o;
@@ -297,9 +344,11 @@ void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &s
void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = Encode(true);
+ return;
+ }
if (o->isExtensible()) {
scope.result = Encode(false);
@@ -322,7 +371,7 @@ void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, Cal
return;
}
- for (uint i = 0; i < o->arrayData()->alloc; ++i) {
+ for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
if (o->arrayData()->attributes(i).isConfigurable()) {
scope.result = Encode(false);
@@ -335,9 +384,11 @@ void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, Cal
void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = Encode(true);
+ return;
+ }
if (o->isExtensible()) {
scope.result = Encode(false);
@@ -360,7 +411,7 @@ void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, Cal
return;
}
- for (uint i = 0; i < o->arrayData()->alloc; ++i) {
+ for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) {
scope.result = Encode(false);
@@ -373,18 +424,19 @@ void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, Cal
void ObjectPrototype::method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = Encode(false);
+ return;
+ }
scope.result = Encode((bool)o->isExtensible());
}
void ObjectPrototype::method_keys(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
ScopedArrayObject a(scope, scope.engine->newArrayObject());
@@ -670,12 +722,12 @@ ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionEngine *engine, c
return o.asReturnedValue();
}
-
+// es6: GetOwnPropertyKeys
Heap::ArrayObject *ObjectPrototype::getOwnPropertyNames(ExecutionEngine *v4, const Value &o)
{
Scope scope(v4);
ScopedArrayObject array(scope, v4->newArrayObject());
- ScopedObject O(scope, o);
+ ScopedObject O(scope, o.toObject(v4));
if (O) {
ObjectIterator it(scope, O, ObjectIterator::NoFlags);
ScopedValue name(scope);
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index 1db8615511..44b54267f3 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -81,6 +81,7 @@ struct ObjectPrototype: Object
static void method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_assign(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_create(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp
index 75f7c95dde..973541553a 100644
--- a/src/qml/jsruntime/qv4persistent.cpp
+++ b/src/qml/jsruntime/qv4persistent.cpp
@@ -232,26 +232,15 @@ void PersistentValueStorage::free(Value *v)
freePage(p);
}
-static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
+void PersistentValueStorage::mark(MarkStack *markStack)
{
- while (engine->jsStackTop > markBase) {
- Heap::Base *h = engine->popForGC();
- Q_ASSERT (h->vtable()->markObjects);
- h->vtable()->markObjects(h, engine);
- }
-}
-
-void PersistentValueStorage::mark(ExecutionEngine *e)
-{
- Value *markBase = e->jsStackTop;
-
Page *p = static_cast<Page *>(firstPage);
while (p) {
for (int i = 0; i < kEntriesPerPage; ++i) {
if (Managed *m = p->values[i].as<Managed>())
- m->mark(e);
+ m->mark(markStack);
}
- drainMarkStack(e, markBase);
+ markStack->drain();
p = p->header.next;
}
@@ -407,11 +396,11 @@ void WeakValue::allocVal(ExecutionEngine *engine)
val = engine->memoryManager->m_weakValues->allocate();
}
-void WeakValue::markOnce(ExecutionEngine *e)
+void WeakValue::markOnce(MarkStack *markStack)
{
if (!val)
return;
- val->mark(e);
+ val->mark(markStack);
}
void WeakValue::free()
diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h
index c1cd1f34df..1f838f5531 100644
--- a/src/qml/jsruntime/qv4persistent_p.h
+++ b/src/qml/jsruntime/qv4persistent_p.h
@@ -65,7 +65,7 @@ struct Q_QML_EXPORT PersistentValueStorage
Value *allocate();
static void free(Value *e);
- void mark(ExecutionEngine *e);
+ void mark(MarkStack *markStack);
struct Iterator {
Iterator(void *p, int idx);
@@ -203,7 +203,7 @@ public:
bool isNullOrUndefined() const { return !val || val->isNullOrUndefined(); }
void clear() { free(); }
- void markOnce(ExecutionEngine *e);
+ void markOnce(MarkStack *markStack);
private:
Value *val;
diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h
index 5069d7690b..2a5b6f7f74 100644
--- a/src/qml/jsruntime/qv4property_p.h
+++ b/src/qml/jsruntime/qv4property_p.h
@@ -78,12 +78,6 @@ struct Property {
attrs->resolve();
}
- static Property genericDescriptor() {
- Property pd;
- pd.value = Primitive::emptyValue();
- return pd;
- }
-
inline bool isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const;
inline void merge(PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs);
@@ -99,19 +93,12 @@ struct Property {
}
explicit Property() { value = Encode::undefined(); set = Value::fromHeapObject(0); }
- explicit Property(Value v) : value(v) { set = Value::fromHeapObject(0); }
- Property(FunctionObject *getter, FunctionObject *setter) {
- value = reinterpret_cast<Managed *>(getter);
- set = reinterpret_cast<Managed *>(setter);
- }
Property(Heap::FunctionObject *getter, Heap::FunctionObject *setter) {
value.setM(reinterpret_cast<Heap::Base *>(getter));
set.setM(reinterpret_cast<Heap::Base *>(setter));
}
- Property &operator=(Value v) { value = v; return *this; }
private:
- Property(const Property &);
- Property &operator=(const Property &);
+ Q_DISABLE_COPY(Property)
};
inline bool Property::isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index d97d44379d..8b9ef149d6 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -59,10 +59,10 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
-DEFINE_OBJECT_VTABLE(QmlContextWrapper);
+DEFINE_OBJECT_VTABLE(QQmlContextWrapper);
DEFINE_MANAGED_VTABLE(QmlContext);
-void Heap::QmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject)
+void Heap::QQmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject)
{
Object::init();
readOnly = true;
@@ -71,17 +71,17 @@ void Heap::QmlContextWrapper::init(QQmlContextData *context, QObject *scopeObjec
this->scopeObject.init(scopeObject);
}
-void Heap::QmlContextWrapper::destroy()
+void Heap::QQmlContextWrapper::destroy()
{
delete context;
scopeObject.destroy();
Object::destroy();
}
-ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue QQmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty)
{
- Q_ASSERT(m->as<QmlContextWrapper>());
- const QmlContextWrapper *resource = static_cast<const QmlContextWrapper *>(m);
+ Q_ASSERT(m->as<QQmlContextWrapper>());
+ const QQmlContextWrapper *resource = static_cast<const QQmlContextWrapper *>(m);
QV4::ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
@@ -131,7 +131,7 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr
if (context->imports && name->startsWithUpper()) {
// Search for attached properties, enums and imported scripts
- QQmlTypeNameCache::Result r = context->imports->query(name);
+ QQmlTypeNameCache::Result r = context->imports->query(name, QQmlImport::AllowRecursion);
if (r.isValid()) {
if (hasProperty)
@@ -140,9 +140,9 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr
QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
return scripts->getIndexed(r.scriptIndex);
} else if (r.type.isValid()) {
- return QmlTypeWrapper::create(v4, scopeObject, r.type);
+ return QQmlTypeWrapper::create(v4, scopeObject, r.type);
} else if (r.importNamespace) {
- return QmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace);
+ return QQmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace);
}
Q_ASSERT(!"Unreachable");
}
@@ -222,21 +222,19 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr
return Encode::undefined();
}
-void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
+bool QQmlContextWrapper::put(Managed *m, String *name, const Value &value)
{
- Q_ASSERT(m->as<QmlContextWrapper>());
- QmlContextWrapper *resource = static_cast<QmlContextWrapper *>(m);
+ Q_ASSERT(m->as<QQmlContextWrapper>());
+ QQmlContextWrapper *resource = static_cast<QQmlContextWrapper *>(m);
ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
if (scope.hasException())
- return;
- QV4::Scoped<QmlContextWrapper> wrapper(scope, resource);
+ return false;
+ QV4::Scoped<QQmlContextWrapper> wrapper(scope, resource);
uint member = wrapper->internalClass()->find(name);
- if (member < UINT_MAX) {
- wrapper->putValue(member, value);
- return;
- }
+ if (member < UINT_MAX)
+ return wrapper->putValue(member, value);
if (wrapper->d()->isNullWrapper) {
if (wrapper && wrapper->d()->readOnly) {
@@ -244,11 +242,10 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
QLatin1Char('"');
ScopedString e(scope, v4->newString(error));
v4->throwError(e);
- return;
+ return false;
}
- Object::put(m, name, value);
- return;
+ return Object::put(m, name, value);
}
// Its possible we could delay the calculation of the "actual" context (in the case
@@ -257,7 +254,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
QQmlContextData *expressionContext = context;
if (!context)
- return;
+ return false;
// See QV8ContextWrapper::Getter for resolution order
@@ -267,18 +264,18 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
const QV4::IdentifierHash<int> &properties = context->propertyNames();
// Search context properties
if (properties.count() && properties.value(name) != -1)
- return;
+ return false;
// Search scope object
if (scopeObject &&
QV4::QObjectWrapper::setQmlProperty(v4, context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, value))
- return;
+ return true;
scopeObject = 0;
// Search context object
if (context->contextObject &&
QV4::QObjectWrapper::setQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, value))
- return;
+ return true;
context = context->parent;
}
@@ -289,23 +286,23 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
QLatin1Char('"');
v4->throwError(error);
- return;
+ return false;
}
- Object::put(m, name, value);
+ return Object::put(m, name, value);
}
-void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml)
+void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml)
{
Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext);
- outer = outerContext->d();
+ outer.set(internalClass->engine, outerContext->d());
strictMode = false;
callData = outer->callData;
lookups = outer->lookups;
constantTable = outer->constantTable;
compilationUnit = outer->compilationUnit;
- this->qml = qml->d();
+ this->qml.set(internalClass->engine, qml->d());
}
Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, const QUrl &source, Value *sendFunction)
@@ -318,7 +315,7 @@ Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, cons
context->isInternal = true;
context->isJSContext = true;
- Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, (QObject*)0));
+ Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, (QObject*)0));
qml->d()->isNullWrapper = true;
qml->setReadOnly(false);
@@ -336,7 +333,7 @@ Heap::QmlContext *QmlContext::create(ExecutionContext *parent, QQmlContextData *
{
Scope scope(parent);
- Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, scopeObject));
+ Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, scopeObject));
Heap::QmlContext *c = scope.engine->memoryManager->alloc<QmlContext>(parent, qml);
Q_ASSERT(c->vtable() == staticVTable());
return c;
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index 8ef7356f4c..65bf4c60ce 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -62,11 +62,11 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-struct QmlContextWrapper;
+struct QQmlContextWrapper;
namespace Heap {
-struct QmlContextWrapper : Object {
+struct QQmlContextWrapper : Object {
void init(QQmlContextData *context, QObject *scopeObject);
void destroy();
bool readOnly;
@@ -76,17 +76,20 @@ struct QmlContextWrapper : Object {
QQmlQPointer<QObject> scopeObject;
};
-struct QmlContext : ExecutionContext {
- void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml);
+#define QmlContextMembers(class, Member) \
+ Member(class, Pointer, QQmlContextWrapper *, qml)
- Pointer<QmlContextWrapper> qml;
+DECLARE_HEAP_OBJECT(QmlContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(QmlContext);
+
+ void init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml);
};
}
-struct Q_QML_EXPORT QmlContextWrapper : Object
+struct Q_QML_EXPORT QQmlContextWrapper : Object
{
- V4_OBJECT2(QmlContextWrapper, Object)
+ V4_OBJECT2(QQmlContextWrapper, Object)
V4_NEEDS_DESTROY
V4_INTERNALCLASS(QmlContextWrapper)
@@ -96,7 +99,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
void setReadOnly(bool b) { d()->readOnly = b; }
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
};
struct Q_QML_EXPORT QmlContext : public ExecutionContext
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 89c10e0995..51a957acc9 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -74,9 +74,14 @@
#include <QtCore/qtimer.h>
#include <QtCore/qatomic.h>
#include <QtCore/qmetaobject.h>
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qloggingcategory.h>
+#include <vector>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
+
// The code in this file does not violate strict aliasing, but GCC thinks it does
// so turn off the warnings for us to have a clean build
QT_WARNING_DISABLE_GCC("-Wstrict-aliasing")
@@ -202,19 +207,61 @@ void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const
{
+ QObject *o = d()->object();
+ return findProperty(engine, o, qmlContext, name, revisionMode, local);
+}
+
+QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QObject *o, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local)
+{
Q_UNUSED(revisionMode);
- QQmlData *ddata = QQmlData::get(d()->object(), false);
- if (!ddata)
- return 0;
+ QQmlData *ddata = QQmlData::get(o, false);
QQmlPropertyData *result = 0;
if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(name, d()->object(), qmlContext);
+ result = ddata->propertyCache->property(name, o, qmlContext);
else
- result = QQmlPropertyCache::property(engine->jsEngine(), d()->object(), name, qmlContext, *local);
+ result = QQmlPropertyCache::property(engine->jsEngine(), o, name, qmlContext, *local);
return result;
}
+ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired)
+{
+ QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex()));
+
+ if (property->isFunction() && !property->isVarProperty()) {
+ if (property->isVMEFunction()) {
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
+ Q_ASSERT(vmemo);
+ return vmemo->vmeMethod(property->coreIndex());
+ } else if (property->isV4Function()) {
+ Scope scope(engine);
+ ScopedContext global(scope, engine->qmlContext());
+ if (!global)
+ global = engine->rootContext();
+ return QV4::QObjectMethod::create(global, object, property->coreIndex());
+ } else if (property->isSignalHandler()) {
+ QmlSignalHandler::initProto(engine);
+ return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex())->asReturnedValue();
+ } else {
+ ExecutionContext *global = engine->rootContext();
+ return QV4::QObjectMethod::create(global, object, property->coreIndex());
+ }
+ }
+
+ QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0;
+
+ if (captureRequired && ep && ep->propertyCapture && !property->isConstant())
+ ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
+
+ if (property->isVarProperty()) {
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
+ Q_ASSERT(vmemo);
+ return vmemo->vmeProperty(property->coreIndex());
+ } else {
+ return loadProperty(engine, object, *property);
+ }
+}
+
ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode,
bool *hasProperty, bool includeImports) const
{
@@ -250,11 +297,11 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
if (r.scriptIndex != -1) {
return QV4::Encode::undefined();
} else if (r.type.isValid()) {
- return QmlTypeWrapper::create(v4, d()->object(),
- r.type, Heap::QmlTypeWrapper::ExcludeEnums);
+ return QQmlTypeWrapper::create(v4, d()->object(),
+ r.type, Heap::QQmlTypeWrapper::ExcludeEnums);
} else if (r.importNamespace) {
- return QmlTypeWrapper::create(v4, d()->object(),
- qmlContext->imports, r.importNamespace, Heap::QmlTypeWrapper::ExcludeEnums);
+ return QQmlTypeWrapper::create(v4, d()->object(),
+ qmlContext->imports, r.importNamespace, Heap::QQmlTypeWrapper::ExcludeEnums);
}
Q_ASSERT(!"Unreachable");
}
@@ -279,42 +326,19 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
return getProperty(v4, d()->object(), result);
}
-ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired)
+ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired)
{
- QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex()));
-
- if (property->isFunction() && !property->isVarProperty()) {
- if (property->isVMEFunction()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
- Q_ASSERT(vmemo);
- return vmemo->vmeMethod(property->coreIndex());
- } else if (property->isV4Function()) {
- Scope scope(engine);
- ScopedContext global(scope, engine->qmlContext());
- if (!global)
- global = engine->rootContext();
- return QV4::QObjectMethod::create(global, object, property->coreIndex());
- } else if (property->isSignalHandler()) {
- QmlSignalHandler::initProto(engine);
- return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex())->asReturnedValue();
- } else {
- ExecutionContext *global = engine->rootContext();
- return QV4::QObjectMethod::create(global, object, property->coreIndex());
- }
- }
-
- QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0;
-
- if (captureRequired && ep && ep->propertyCapture && !property->isConstant())
- ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
+ if (QQmlData::wasDeleted(object))
+ return QV4::Encode::null();
+ QQmlData *ddata = QQmlData::get(object, /*create*/false);
+ if (!ddata)
+ return QV4::Encode::undefined();
- if (property->isVarProperty()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
- Q_ASSERT(vmemo);
- return vmemo->vmeProperty(property->coreIndex());
- } else {
- return loadProperty(engine, object, *property);
- }
+ QQmlPropertyCache *cache = ddata->propertyCache;
+ Q_ASSERT(cache);
+ QQmlPropertyData *property = cache->property(propertyIndex);
+ Q_ASSERT(property); // We resolved this property earlier, so it better exist!
+ return getProperty(engine, object, property, captureRequired);
}
ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty)
@@ -325,12 +349,49 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
return QV4::Encode::null();
}
- if (!QQmlData::get(object, true)) {
+ if (name->equals(engine->id_destroy()) || name->equals(engine->id_toString())) {
+ int index = name->equals(engine->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod;
if (hasProperty)
- *hasProperty = false;
- return QV4::Encode::null();
+ *hasProperty = true;
+ ExecutionContext *global = engine->rootContext();
+ return QV4::QObjectMethod::create(global, object, index);
+ }
+
+ QQmlData *ddata = QQmlData::get(object, false);
+ QQmlPropertyData local;
+ QQmlPropertyData *result = findProperty(engine, object, qmlContext, name, revisionMode, &local);
+
+ if (result) {
+ if (revisionMode == QV4::QObjectWrapper::CheckRevision && result->hasRevision()) {
+ if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result)) {
+ if (hasProperty)
+ *hasProperty = false;
+ return QV4::Encode::undefined();
+ }
+ }
+
+ if (hasProperty)
+ *hasProperty = true;
+
+ return getProperty(engine, object, result);
+ } else {
+ // Check if this object is already wrapped.
+ if (!ddata || (ddata->jsWrapper.isUndefined() &&
+ (ddata->jsEngineId == 0 || // Nobody owns the QObject
+ !ddata->hasTaintedV4Object))) { // Someone else has used the QObject, but it isn't tainted
+
+ // Not wrapped. Last chance: try query QObjectWrapper's prototype.
+ // If it can't handle this, then there is no point
+ // to wrap the QObject just to look at an empty set of JS props.
+ QV4::Object *proto = QObjectWrapper::defaultPrototype(engine);
+ return proto->get(name, hasProperty);
+ }
}
+ // If we get here, we must already be wrapped (which implies a ddata).
+ // There's no point wrapping again, as there wouldn't be any new props.
+ Q_ASSERT(ddata);
+
QV4::Scope scope(engine);
QV4::Scoped<QObjectWrapper> wrapper(scope, wrap(engine, object));
if (!wrapper) {
@@ -341,6 +402,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
return wrapper->getQmlProperty(qmlContext, name, revisionMode, hasProperty);
}
+
bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name,
QObjectWrapper::RevisionMode revisionMode, const Value &value)
{
@@ -399,10 +461,23 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
}
}
- if (newBinding)
+ if (newBinding) {
QQmlPropertyPrivate::setBinding(newBinding);
- else
+ } else {
+ if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (auto binding = QQmlPropertyPrivate::binding(object, QQmlPropertyIndex(property->coreIndex()))) {
+ Q_ASSERT(!binding->isValueTypeProxy());
+ const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
+ const auto stackFrame = engine->currentStackFrame();
+ qCInfo(lcBindingRemoval,
+ "Overwriting binding on %s::%s at %s:%d that was initially bound at %s",
+ object->metaObject()->className(), qPrintable(property->name(object)),
+ qPrintable(stackFrame.source), stackFrame.line,
+ qPrintable(qmlBinding->expressionIdentifier()));
+ }
+ }
QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
+ }
if (!newBinding && property->isVarProperty()) {
// allow assignment of "special" values (null, undefined, function) to var properties
@@ -539,7 +614,7 @@ ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *ob
}
}
-void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine)
+void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack)
{
if (QQmlData::wasDeleted(object))
return;
@@ -548,25 +623,10 @@ void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine)
if (!ddata)
return;
- if (ddata->jsEngineId == engine->m_engineId)
- ddata->jsWrapper.markOnce(engine);
- else if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
- engine->m_multiplyWrappedQObjects->mark(object, engine);
-}
-
-ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired)
-{
- if (QQmlData::wasDeleted(object))
- return QV4::Encode::null();
- QQmlData *ddata = QQmlData::get(object, /*create*/false);
- if (!ddata)
- return QV4::Encode::undefined();
-
- QQmlPropertyCache *cache = ddata->propertyCache;
- Q_ASSERT(cache);
- QQmlPropertyData *property = cache->property(propertyIndex);
- Q_ASSERT(property); // We resolved this property earlier, so it better exist!
- return getProperty(engine, object, property, captureRequired);
+ if (ddata->jsEngineId == markStack->engine->m_engineId)
+ ddata->jsWrapper.markOnce(markStack);
+ else if (markStack->engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
+ markStack->engine->m_multiplyWrappedQObjects->mark(object, markStack);
}
void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value)
@@ -598,7 +658,7 @@ bool QObjectWrapper::isEqualTo(Managed *a, Managed *b)
QV4::QObjectWrapper *qobjectWrapper = static_cast<QV4::QObjectWrapper *>(a);
QV4::Object *o = b->as<Object>();
if (o) {
- if (QV4::QmlTypeWrapper *qmlTypeWrapper = o->as<QV4::QmlTypeWrapper>())
+ if (QV4::QQmlTypeWrapper *qmlTypeWrapper = o->as<QV4::QQmlTypeWrapper>())
return qmlTypeWrapper->toVariant().value<QObject*>() == qobjectWrapper->object();
}
@@ -625,13 +685,13 @@ QV4::ReturnedValue QObjectWrapper::get(const Managed *m, String *name, bool *has
return that->getQmlProperty(qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true);
}
-void QObjectWrapper::put(Managed *m, String *name, const Value &value)
+bool QObjectWrapper::put(Managed *m, String *name, const Value &value)
{
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ExecutionEngine *v4 = that->engine();
if (v4->hasException || QQmlData::wasDeleted(that->d()->object()))
- return;
+ return false;
QQmlContextData *qmlContext = v4->callingQmlContext();
if (!setQmlProperty(v4, qmlContext, that->d()->object(), name, QV4::QObjectWrapper::IgnoreRevision, value)) {
@@ -642,10 +702,13 @@ void QObjectWrapper::put(Managed *m, String *name, const Value &value)
QString error = QLatin1String("Cannot assign to non-existent property \"") +
name->toQString() + QLatin1Char('\"');
v4->throwError(error);
+ return false;
} else {
- QV4::Object::put(m, name, value);
+ return QV4::Object::put(m, name, value);
}
}
+
+ return true;
}
PropertyAttributes QObjectWrapper::query(const Managed *m, String *name)
@@ -939,36 +1002,36 @@ void QObjectWrapper::method_disconnect(const BuiltinFunction *, Scope &scope, Ca
RETURN_UNDEFINED();
}
-static void markChildQObjectsRecursively(QObject *parent, QV4::ExecutionEngine *e)
+static void markChildQObjectsRecursively(QObject *parent, QV4::MarkStack *markStack)
{
const QObjectList &children = parent->children();
for (int i = 0; i < children.count(); ++i) {
QObject *child = children.at(i);
if (!child)
continue;
- QObjectWrapper::markWrapper(child, e);
- markChildQObjectsRecursively(child, e);
+ QObjectWrapper::markWrapper(child, markStack);
+ markChildQObjectsRecursively(child, markStack);
}
}
-void QObjectWrapper::markObjects(Heap::Base *that, QV4::ExecutionEngine *e)
+void QObjectWrapper::markObjects(Heap::Base *that, QV4::MarkStack *markStack)
{
QObjectWrapper::Data *This = static_cast<QObjectWrapper::Data *>(that);
if (QObject *o = This->object()) {
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
if (vme)
- vme->mark(e);
+ vme->mark(markStack);
// Children usually don't need to be marked, the gc keeps them alive.
// But in the rare case of a "floating" QObject without a parent that
// _gets_ marked (we've been called here!) then we also need to
// propagate the marking down to the children recursively.
if (!o->parent())
- markChildQObjectsRecursively(o, e);
+ markChildQObjectsRecursively(o, markStack);
}
- QV4::Object::markObjects(that, e);
+ QV4::Object::markObjects(that, markStack);
}
void QObjectWrapper::destroyObject(bool lastCall)
@@ -1038,12 +1101,21 @@ private:
inline void cleanup();
+ template <class T, class M>
+ void fromContainerValue(const QV4::Object *object, int type, M CallArgument::*member, bool &queryEngine);
+
union {
float floatValue;
double doubleValue;
quint32 intValue;
bool boolValue;
QObject *qobjectPtr;
+ std::vector<int> *stdVectorIntPtr;
+ std::vector<qreal> *stdVectorRealPtr;
+ std::vector<bool> *stdVectorBoolPtr;
+ std::vector<QString> *stdVectorQStringPtr;
+ std::vector<QUrl> *stdVectorQUrlPtr;
+ std::vector<QModelIndex> *stdVectorQModelIndexPtr;
char allocData[MaxSizeOf8<QVariant,
QString,
@@ -1473,6 +1545,18 @@ void *CallArgument::dataPtr()
{
if (type == -1)
return qvariantPtr->data();
+ else if (type == qMetaTypeId<std::vector<int>>())
+ return stdVectorIntPtr;
+ else if (type == qMetaTypeId<std::vector<qreal>>())
+ return stdVectorRealPtr;
+ else if (type == qMetaTypeId<std::vector<bool>>())
+ return stdVectorBoolPtr;
+ else if (type == qMetaTypeId<std::vector<QString>>())
+ return stdVectorQStringPtr;
+ else if (type == qMetaTypeId<std::vector<QUrl>>())
+ return stdVectorQUrlPtr;
+ else if (type == qMetaTypeId<std::vector<QModelIndex>>())
+ return stdVectorQModelIndexPtr;
else if (type != 0)
return (void *)&allocData;
return 0;
@@ -1522,6 +1606,19 @@ void CallArgument::initAsType(int callType)
}
}
+template <class T, class M>
+void CallArgument::fromContainerValue(const QV4::Object *object, int callType, M CallArgument::*member, bool &queryEngine)
+{
+ if (object && object->isListType()) {
+ T* ptr = static_cast<T*>(QV4::SequencePrototype::getRawContainerPtr(object, callType));
+ if (ptr) {
+ (this->*member) = ptr;
+ type = callType;
+ queryEngine = false;
+ }
+ }
+}
+
void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const QV4::Value &value)
{
if (type != 0) {
@@ -1560,7 +1657,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
qobjectPtr = 0;
if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>())
qobjectPtr = qobjectWrapper->object();
- else if (const QV4::QmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QmlTypeWrapper>())
+ else if (const QV4::QQmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QQmlTypeWrapper>())
queryEngine = qmlTypeWrapper->isSingleton();
type = callType;
} else if (callType == qMetaTypeId<QVariant>()) {
@@ -1603,6 +1700,33 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
type = callType;
} else if (callType == QMetaType::Void) {
*qvariantPtr = QVariant();
+ } else if (callType == qMetaTypeId<std::vector<int>>()
+ || callType == qMetaTypeId<std::vector<qreal>>()
+ || callType == qMetaTypeId<std::vector<bool>>()
+ || callType == qMetaTypeId<std::vector<QString>>()
+ || callType == qMetaTypeId<std::vector<QUrl>>()
+ || callType == qMetaTypeId<std::vector<QModelIndex>>()) {
+ queryEngine = true;
+ const QV4::Object* object = value.as<Object>();
+ if (callType == qMetaTypeId<std::vector<int>>()) {
+ stdVectorIntPtr = nullptr;
+ fromContainerValue<std::vector<int>>(object, callType, &CallArgument::stdVectorIntPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<qreal>>()) {
+ stdVectorRealPtr = nullptr;
+ fromContainerValue<std::vector<qreal>>(object, callType, &CallArgument::stdVectorRealPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<bool>>()) {
+ stdVectorBoolPtr = nullptr;
+ fromContainerValue<std::vector<bool>>(object, callType, &CallArgument::stdVectorBoolPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<QString>>()) {
+ stdVectorQStringPtr = nullptr;
+ fromContainerValue<std::vector<QString>>(object, callType, &CallArgument::stdVectorQStringPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<QUrl>>()) {
+ stdVectorQUrlPtr = nullptr;
+ fromContainerValue<std::vector<QUrl>>(object, callType, &CallArgument::stdVectorQUrlPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<QModelIndex>>()) {
+ stdVectorQModelIndexPtr = nullptr;
+ fromContainerValue<std::vector<QModelIndex>>(object, callType, &CallArgument::stdVectorQModelIndexPtr, queryEngine);
+ }
} else {
queryEngine = true;
}
@@ -1712,7 +1836,7 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueType
Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocObject<QObjectMethod>(scope));
method->d()->setPropertyCache(valueType->d()->propertyCache());
method->d()->index = index;
- method->d()->valueTypeWrapper = valueType->d();
+ method->d()->valueTypeWrapper.set(valueScope.engine, valueType->d());
return method.asReturnedValue();
}
@@ -1849,15 +1973,6 @@ void QObjectMethod::callInternal(CallData *callData, Scope &scope) const
}
}
-void QObjectMethod::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- QObjectMethod::Data *This = static_cast<QObjectMethod::Data*>(that);
- if (This->valueTypeWrapper)
- This->valueTypeWrapper->mark(e);
-
- FunctionObject::markObjects(that, e);
-}
-
DEFINE_OBJECT_VTABLE(QObjectMethod);
@@ -2083,12 +2198,12 @@ void MultiplyWrappedQObjectMap::remove(QObject *key)
erase(it);
}
-void MultiplyWrappedQObjectMap::mark(QObject *key, ExecutionEngine *engine)
+void MultiplyWrappedQObjectMap::mark(QObject *key, MarkStack *markStack)
{
Iterator it = find(key);
if (it == end())
return;
- it->markOnce(engine);
+ it->markOnce(markStack);
}
void MultiplyWrappedQObjectMap::removeDestroyedObject(QObject *object)
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 6494c20bd2..018e444f7c 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -95,7 +95,15 @@ private:
QQmlQPointer<QObject> qObj;
};
-struct QObjectMethod : FunctionObject {
+#define QObjectMethodMembers(class, Member) \
+ Member(class, Pointer, QQmlValueTypeWrapper *, valueTypeWrapper) \
+ Member(class, NoMark, QQmlQPointer<QObject>, qObj) \
+ Member(class, NoMark, QQmlPropertyCache *, _propertyCache) \
+ Member(class, NoMark, int, index)
+
+DECLARE_HEAP_OBJECT(QObjectMethod, FunctionObject) {
+ DECLARE_MARK_TABLE(QObjectMethod);
+
void init(QV4::ExecutionContext *scope);
void destroy()
{
@@ -113,18 +121,10 @@ struct QObjectMethod : FunctionObject {
_propertyCache = c;
}
- Pointer<QQmlValueTypeWrapper> valueTypeWrapper;
-
const QMetaObject *metaObject();
QObject *object() const { return qObj.data(); }
void setObject(QObject *o) { qObj = o; }
-private:
- QQmlQPointer<QObject> qObj;
- QQmlPropertyCache *_propertyCache;
-
-public:
- int index;
};
struct QMetaObjectWrapper : FunctionObject {
@@ -171,7 +171,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value);
static ReturnedValue wrap(ExecutionEngine *engine, QObject *object);
- static void markWrapper(QObject *object, ExecutionEngine *engine);
+ static void markWrapper(QObject *object, MarkStack *markStack);
using Object::get;
@@ -189,13 +189,14 @@ protected:
static ReturnedValue create(ExecutionEngine *engine, QObject *object);
+ static QQmlPropertyData *findProperty(ExecutionEngine *engine, QObject *o, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local);
QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const;
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
static PropertyAttributes query(const Managed *, String *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
- static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
+ static void markObjects(Heap::Base *that, QV4::MarkStack *markStack);
static void method_connect(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData);
@@ -240,8 +241,6 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
void callInternal(CallData *callData, Scope &scope) const;
- static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
-
static QPair<QObject *, int> extractQtMethod(const QV4::FunctionObject *function);
};
@@ -294,7 +293,7 @@ public:
ReturnedValue value(QObject *key) const { return QHash<QObject*, QV4::WeakValue>::value(key).value(); }
Iterator erase(Iterator it);
void remove(QObject *key);
- void mark(QObject *key, ExecutionEngine *engine);
+ void mark(QObject *key, MarkStack *markStack);
private Q_SLOTS:
void removeDestroyedObject(QObject*);
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index 8cb15b9d7e..162f0fba57 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -127,9 +127,3 @@ void Heap::RegExp::destroy()
delete pattern;
Base::destroy();
}
-
-void RegExp::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- Q_UNUSED(that);
- Q_UNUSED(e);
-}
diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h
index d9b536406c..998f6e3da3 100644
--- a/src/qml/jsruntime/qv4regexp_p.h
+++ b/src/qml/jsruntime/qv4regexp_p.h
@@ -122,8 +122,6 @@ struct RegExp : public Managed
int captureCount() const { return subPatternCount() + 1; }
- static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
-
friend class RegExpCache;
};
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 82b0f67075..83bfe21c67 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -74,15 +74,15 @@ void Heap::RegExpObject::init()
Object::init();
Scope scope(internalClass->engine);
Scoped<QV4::RegExpObject> o(scope, this);
- o->d()->value = QV4::RegExp::create(scope.engine, QString(), false, false, false);
+ value.set(scope.engine, QV4::RegExp::create(scope.engine, QString(), false, false));
o->initProperties();
}
void Heap::RegExpObject::init(QV4::RegExp *value)
{
Object::init();
- this->value = value->d();
Scope scope(internalClass->engine);
+ this->value.set(scope.engine, value->d());
Scoped<QV4::RegExpObject> o(scope, this);
o->initProperties();
}
@@ -134,14 +134,15 @@ void Heap::RegExpObject::init(const QRegExp &re)
Scope scope(internalClass->engine);
Scoped<QV4::RegExpObject> o(scope, this);
- o->d()->value = QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false);
+ o->d()->value.set(scope.engine,
+ QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false));
o->initProperties();
}
void RegExpObject::initProperties()
{
- *propertyData(Index_LastIndex) = Primitive::fromInt32(0);
+ setProperty(Index_LastIndex, Primitive::fromInt32(0));
Q_ASSERT(value());
@@ -153,25 +154,10 @@ void RegExpObject::initProperties()
p.replace('/', QLatin1String("\\/"));
}
- *propertyData(Index_Source) = engine()->newString(p);
- *propertyData(Index_Global) = Primitive::fromBoolean(global());
- *propertyData(Index_IgnoreCase) = Primitive::fromBoolean(value()->ignoreCase);
- *propertyData(Index_Multiline) = Primitive::fromBoolean(value()->multiLine);
-}
-
-
-void RegExpObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- RegExpObject::Data *re = static_cast<RegExpObject::Data *>(that);
- if (re->value)
- re->value->mark(e);
- Object::markObjects(that, e);
-}
-
-Value *RegExpObject::lastIndexProperty()
-{
- Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex()));
- return propertyData(0);
+ setProperty(Index_Source, engine()->newString(p));
+ setProperty(Index_Global, Primitive::fromBoolean(global()));
+ setProperty(Index_IgnoreCase, Primitive::fromBoolean(value()->ignoreCase));
+ setProperty(Index_Multiline, Primitive::fromBoolean(value()->multiLine));
}
// Converts a JS RegExp to a QRegExp.
@@ -225,8 +211,8 @@ void Heap::RegExpCtor::init(QV4::ExecutionContext *scope)
void Heap::RegExpCtor::clearLastMatch()
{
- lastMatch = Primitive::nullValue();
- lastInput = internalClass->engine->id_empty()->d();
+ lastMatch.set(internalClass->engine, Primitive::nullValue());
+ lastInput.set(internalClass->engine, internalClass->engine->id_empty()->d());
lastMatchStart = 0;
lastMatchEnd = 0;
}
@@ -300,15 +286,6 @@ void RegExpCtor::call(const Managed *that, Scope &scope, CallData *callData)
construct(that, scope, callData);
}
-void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- RegExpCtor::Data *This = static_cast<RegExpCtor::Data *>(that);
- This->lastMatch.mark(e);
- if (This->lastInput)
- This->lastInput->mark(e);
- FunctionObject::markObjects(that, e);
-}
-
void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor)
{
Scope scope(engine);
@@ -358,9 +335,9 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
RETURN_UNDEFINED();
QString s = str->toQString();
- int offset = r->global() ? r->lastIndexProperty()->toInt32() : 0;
+ int offset = r->global() ? r->lastIndex() : 0;
if (offset < 0 || offset > s.length()) {
- *r->lastIndexProperty() = Primitive::fromInt32(0);
+ r->setLastIndex(0);
RETURN_RESULT(Encode::null());
}
@@ -371,7 +348,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
regExpCtor->d()->clearLastMatch();
if (result == -1) {
- *r->lastIndexProperty() = Primitive::fromInt32(0);
+ r->setLastIndex(0);
RETURN_RESULT(Encode::null());
}
@@ -387,17 +364,17 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
array->arrayPut(i, v);
}
array->setArrayLengthUnchecked(len);
- *array->propertyData(Index_ArrayIndex) = Primitive::fromInt32(result);
- *array->propertyData(Index_ArrayInput) = str;
+ array->setProperty(Index_ArrayIndex, Primitive::fromInt32(result));
+ array->setProperty(Index_ArrayInput, str);
RegExpCtor::Data *dd = regExpCtor->d();
- dd->lastMatch = array;
- dd->lastInput = str->d();
+ dd->lastMatch.set(scope.engine, array);
+ dd->lastInput.set(scope.engine, str->d());
dd->lastMatchStart = matchOffsets[0];
dd->lastMatchEnd = matchOffsets[1];
if (r->global())
- *r->lastIndexProperty() = Primitive::fromInt32(matchOffsets[1]);
+ r->setLastIndex(matchOffsets[1]);
scope.result = array;
}
@@ -429,8 +406,7 @@ void RegExpPrototype::method_compile(const BuiltinFunction *, Scope &scope, Call
scope.engine->regExpCtor()->as<FunctionObject>()->construct(scope, cData);
Scoped<RegExpObject> re(scope, scope.result.asReturnedValue());
- r->d()->value = re->value();
- RETURN_UNDEFINED();
+ r->d()->value.set(scope.engine, re->value());
}
template <int index>
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index af49a1bf5e..65055ccc81 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -55,8 +55,8 @@
#include "qv4context_p.h"
#include "qv4functionobject_p.h"
#include "qv4string_p.h"
-#include "qv4codegen_p.h"
-#include "qv4isel_p.h"
+#include <qv4codegen_p.h>
+#include <qv4isel_p.h>
#include "qv4managed_p.h"
#include "qv4property_p.h"
#include "qv4objectiterator_p.h"
@@ -74,20 +74,27 @@ namespace QV4 {
namespace Heap {
-struct RegExpObject : Object {
+#define RegExpObjectMembers(class, Member) \
+ Member(class, Pointer, RegExp *, value)
+
+DECLARE_HEAP_OBJECT(RegExpObject, Object) {
+ DECLARE_MARK_TABLE(RegExpObject);
+
void init();
void init(QV4::RegExp *value);
void init(const QRegExp &re);
-
- Pointer<RegExp> value;
};
-struct RegExpCtor : FunctionObject {
+#define RegExpCtorMembers(class, Member) \
+ Member(class, HeapValue, HeapValue, lastMatch) \
+ Member(class, Pointer, String *, lastInput) \
+ Member(class, NoMark, int, lastMatchStart) \
+ Member(class, NoMark, int, lastMatchEnd)
+
+DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) {
+ DECLARE_MARK_TABLE(RegExpCtor);
+
void init(QV4::ExecutionContext *scope);
- Value lastMatch;
- Pointer<String> lastInput;
- int lastMatchStart;
- int lastMatchEnd;
void clearLastMatch();
};
@@ -121,14 +128,19 @@ struct RegExpObject: Object {
void initProperties();
- Value *lastIndexProperty();
+ int lastIndex() const {
+ Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex()));
+ return propertyData(Index_LastIndex)->toInt32();
+ }
+ void setLastIndex(int index) {
+ Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex()));
+ return setProperty(Index_LastIndex, Primitive::fromInt32(index));
+ }
+
QRegExp toQRegExp() const;
QString toString() const;
QString source() const;
uint flags() const;
-
-protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
struct RegExpCtor: FunctionObject
@@ -142,7 +154,6 @@ struct RegExpCtor: FunctionObject
static void construct(const Managed *m, Scope &scope, CallData *callData);
static void call(const Managed *that, Scope &scope, CallData *callData);
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
struct RegExpPrototype: RegExpObject
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 28b344d154..4b952bcbbc 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -665,7 +665,7 @@ ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &o
Heap::Object *o = static_cast<Heap::Object *>(b);
if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len)
+ if (idx < s->values.size)
if (!s->data(idx).isEmpty())
return s->data(idx).asReturnedValue();
}
@@ -688,8 +688,8 @@ static Q_NEVER_INLINE void setElementFallback(ExecutionEngine *engine, const Val
if (index.asArrayIndex(idx)) {
if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len) {
- s->data(idx) = value;
+ if (idx < s->values.size) {
+ s->setData(engine, idx, value);
return;
}
}
@@ -710,8 +710,8 @@ void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, co
Heap::Object *o = static_cast<Heap::Object *>(b);
if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len) {
- s->data(idx) = value;
+ if (idx < s->values.size) {
+ s->setData(engine, idx, value);
return;
}
}
@@ -1377,7 +1377,7 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::
}
for (uint i = 0; i < klass->size; ++i)
- *o->propertyData(i) = *args++;
+ o->setProperty(i, *args++);
if (arrayValueCount > 0) {
ScopedValue entry(scope);
@@ -1521,7 +1521,7 @@ ReturnedValue Runtime::method_getQmlContextObjectProperty(ExecutionEngine *engin
ReturnedValue Runtime::method_getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)
{
Scope scope(engine);
- QV4::Scoped<QmlTypeWrapper> wrapper(scope, object);
+ QV4::Scoped<QQmlTypeWrapper> wrapper(scope, object);
if (!wrapper) {
scope.engine->throwTypeError(QStringLiteral("Cannot read property of null"));
return Encode::undefined();
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 8ce10e326d..8afc672aa2 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -78,13 +78,22 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
F(int, IntVector, QVector<int>, 0) \
F(qreal, RealVector, QVector<qreal>, 0.0) \
F(bool, BoolVector, QVector<bool>, false) \
+ F(int, IntStdVector, std::vector<int>, 0) \
+ F(qreal, RealStdVector, std::vector<qreal>, 0.0) \
+ F(bool, BoolStdVector, std::vector<bool>, false) \
F(int, Int, QList<int>, 0) \
F(qreal, Real, QList<qreal>, 0.0) \
F(bool, Bool, QList<bool>, false) \
F(QString, String, QList<QString>, QString()) \
F(QString, QString, QStringList, QString()) \
+ F(QString, StringVector, QVector<QString>, QString()) \
+ F(QString, StringStdVector, std::vector<QString>, QString()) \
F(QUrl, Url, QList<QUrl>, QUrl()) \
+ F(QUrl, UrlVector, QVector<QUrl>, QUrl()) \
+ F(QUrl, UrlStdVector, std::vector<QUrl>, QUrl()) \
F(QModelIndex, QModelIndex, QModelIndexList, QModelIndex()) \
+ F(QModelIndex, QModelIndexVector, QVector<QModelIndex>, QModelIndex()) \
+ F(QModelIndex, QModelIndexStdVector, std::vector<QModelIndex>, QModelIndex()) \
F(QItemSelectionRange, QItemSelectionRange, QItemSelection, QItemSelectionRange())
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QString &element)
@@ -263,56 +272,54 @@ public:
}
loadReference();
}
- qint32 signedIdx = static_cast<qint32>(index);
- if (signedIdx < d()->container->count()) {
+ if (index < size_t(d()->container->size())) {
if (hasProperty)
*hasProperty = true;
- return convertElementToValue(engine(), d()->container->at(signedIdx));
+ return convertElementToValue(engine(), qAsConst(*(d()->container))[index]);
}
if (hasProperty)
*hasProperty = false;
return Encode::undefined();
}
- void containerPutIndexed(uint index, const QV4::Value &value)
+ bool containerPutIndexed(uint index, const QV4::Value &value)
{
if (internalClass()->engine->hasException)
- return;
+ return false;
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX) {
generateWarning(engine(), QLatin1String("Index out of range during indexed set"));
- return;
+ return false;
}
if (d()->isReference) {
if (!d()->object)
- return;
+ return false;
loadReference();
}
- qint32 signedIdx = static_cast<qint32>(index);
-
- int count = d()->container->count();
+ size_t count = size_t(d()->container->size());
typename Container::value_type element = convertValueToElement<typename Container::value_type>(value);
- if (signedIdx == count) {
- d()->container->append(element);
- } else if (signedIdx < count) {
- (*d()->container)[signedIdx] = element;
+ if (index == count) {
+ d()->container->push_back(element);
+ } else if (index < count) {
+ (*d()->container)[index] = element;
} else {
/* according to ECMA262r3 we need to insert */
/* the value at the given index, increasing length to index+1. */
- d()->container->reserve(signedIdx + 1);
- while (signedIdx > count++) {
- d()->container->append(typename Container::value_type());
+ d()->container->reserve(index + 1);
+ while (index > count++) {
+ d()->container->push_back(typename Container::value_type());
}
- d()->container->append(element);
+ d()->container->push_back(element);
}
if (d()->isReference)
storeReference();
+ return true;
}
QV4::PropertyAttributes containerQueryIndexed(uint index) const
@@ -327,8 +334,7 @@ public:
return QV4::Attr_Invalid;
loadReference();
}
- qint32 signedIdx = static_cast<qint32>(index);
- return (signedIdx < d()->container->count()) ? QV4::Attr_Data : QV4::Attr_Invalid;
+ return (index < size_t(d()->container->size())) ? QV4::Attr_Data : QV4::Attr_Invalid;
}
void containerAdvanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs)
@@ -344,7 +350,7 @@ public:
loadReference();
}
- if (it->arrayIndex < static_cast<uint>(d()->container->count())) {
+ if (it->arrayIndex < static_cast<uint>(d()->container->size())) {
*index = it->arrayIndex;
++it->arrayIndex;
*attrs = QV4::Attr_Data;
@@ -364,14 +370,13 @@ public:
return false;
loadReference();
}
- qint32 signedIdx = static_cast<qint32>(index);
- if (signedIdx >= d()->container->count())
+ if (index >= size_t(d()->container->size()))
return false;
/* according to ECMA262r3 it should be Undefined, */
/* but we cannot, so we insert a default-value instead. */
- d()->container->replace(signedIdx, typename Container::value_type());
+ (*d()->container)[index] = typename Container::value_type();
if (d()->isReference)
storeReference();
@@ -456,7 +461,7 @@ public:
RETURN_RESULT(Encode(0));
This->loadReference();
}
- RETURN_RESULT(Encode(This->d()->container->count()));
+ RETURN_RESULT(Encode(qint32(This->d()->container->size())));
}
static void method_set_length(const BuiltinFunction *, Scope &scope, CallData *callData)
@@ -478,8 +483,8 @@ public:
This->loadReference();
}
/* Determine whether we need to modify the sequence */
- qint32 newCount = static_cast<qint32>(newLength);
- qint32 count = This->d()->container->count();
+ quint32 newCount = static_cast<quint32>(newLength);
+ quint32 count = static_cast<quint32>(This->d()->container->size());
if (newCount == count) {
RETURN_UNDEFINED();
} else if (newCount > count) {
@@ -488,14 +493,13 @@ public:
/* We cannot, so we insert default-values instead. */
This->d()->container->reserve(newCount);
while (newCount > count++) {
- This->d()->container->append(typename Container::value_type());
+ This->d()->container->push_back(typename Container::value_type());
}
} else {
/* according to ECMA262r3 we need to remove */
/* elements until the sequence is the required length. */
- while (newCount < count) {
- count--;
- This->d()->container->removeAt(count);
+ if (newCount < count) {
+ This->d()->container->erase(This->d()->container->begin() + newCount, This->d()->container->end());
}
}
/* write back if required. */
@@ -516,10 +520,13 @@ public:
quint32 length = array->getLength();
QV4::ScopedValue v(scope);
for (quint32 i = 0; i < length; ++i)
- result << convertValueToElement<typename Container::value_type>((v = array->getIndexed(i)));
+ result.push_back(convertValueToElement<typename Container::value_type>((v = array->getIndexed(i))));
return QVariant::fromValue(result);
}
+ void* getRawContainerPtr() const
+ { return d()->container; }
+
void loadReference() const
{
Q_ASSERT(d()->object);
@@ -540,8 +547,8 @@ public:
static QV4::ReturnedValue getIndexed(const QV4::Managed *that, uint index, bool *hasProperty)
{ return static_cast<const QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); }
- static void putIndexed(Managed *that, uint index, const QV4::Value &value)
- { static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); }
+ static bool putIndexed(Managed *that, uint index, const QV4::Value &value)
+ { return static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); }
static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index)
{ return static_cast<const QQmlSequence<Container> *>(that)->containerQueryIndexed(index); }
static bool deleteIndexedProperty(QV4::Managed *that, uint index)
@@ -594,16 +601,34 @@ typedef QQmlSequence<QVector<qreal> > QQmlRealVectorList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealVectorList);
typedef QQmlSequence<QVector<bool> > QQmlBoolVectorList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolVectorList);
+typedef QQmlSequence<std::vector<int> > QQmlIntStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntStdVectorList);
+typedef QQmlSequence<std::vector<qreal> > QQmlRealStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealStdVectorList);
+typedef QQmlSequence<std::vector<bool> > QQmlBoolStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolStdVectorList);
typedef QQmlSequence<QStringList> QQmlQStringList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQStringList);
typedef QQmlSequence<QList<QString> > QQmlStringList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringList);
+typedef QQmlSequence<QVector<QString> > QQmlStringVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringVectorList);
+typedef QQmlSequence<std::vector<QString> > QQmlStringStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringStdVectorList);
typedef QQmlSequence<QList<int> > QQmlIntList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntList);
typedef QQmlSequence<QList<QUrl> > QQmlUrlList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlList);
+typedef QQmlSequence<QVector<QUrl> > QQmlUrlVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlVectorList);
+typedef QQmlSequence<std::vector<QUrl> > QQmlUrlStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlStdVectorList);
typedef QQmlSequence<QModelIndexList> QQmlQModelIndexList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexList);
+typedef QQmlSequence<QVector<QModelIndex> > QQmlQModelIndexVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexVectorList);
+typedef QQmlSequence<std::vector<QModelIndex> > QQmlQModelIndexStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexStdVectorList);
typedef QQmlSequence<QItemSelection> QQmlQItemSelectionRangeList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQItemSelectionRangeList);
typedef QQmlSequence<QList<bool> > QQmlBoolList;
@@ -724,6 +749,19 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, boo
#undef SEQUENCE_TO_VARIANT
+#define SEQUENCE_GET_RAWCONTAINERPTR(ElementType, ElementTypeName, SequenceType, unused) \
+ if (const QQml##ElementTypeName##List *list = [&]() -> const QQml##ElementTypeName##List* \
+ { if (typeHint == qMetaTypeId<SequenceType>()) return object->as<QQml##ElementTypeName##List>(); return nullptr;}()) \
+ return list->getRawContainerPtr(); \
+ else
+
+void* SequencePrototype::getRawContainerPtr(const Object *object, int typeHint)
+{
+ FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_GET_RAWCONTAINERPTR) { /* else */ return nullptr; }
+}
+
+#undef SEQUENCE_GET_RAWCONTAINERPTR
+
#define MAP_META_TYPE(ElementType, ElementTypeName, SequenceType, unused) \
if (object->as<QQml##ElementTypeName##List>()) { \
return qMetaTypeId<SequenceType>(); \
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 0879f149fa..2b8d1ea716 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -81,6 +81,7 @@ struct SequencePrototype : public QV4::Object
static int metaTypeForSequence(const Object *object);
static QVariant toVariant(Object *object);
static QVariant toVariant(const Value &array, int typeHint, bool *succeeded);
+ static void* getRawContainerPtr(const Object *object, int typeHint);
};
}
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index 515d61c8e4..c0183a46a7 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -54,12 +54,12 @@ using namespace QV4;
DEFINE_MANAGED_VTABLE(String);
-void String::markObjects(Heap::Base *that, ExecutionEngine *e)
+void String::markObjects(Heap::Base *that, MarkStack *markStack)
{
String::Data *s = static_cast<String::Data *>(that);
if (s->largestSubLength) {
- s->left->mark(e);
- s->right->mark(e);
+ s->left->mark(markStack);
+ s->right->mark(markStack);
}
}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index f5311ae5d4..2f34dd6139 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -205,7 +205,7 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
Identifier *identifier() const { return d()->identifier; }
protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
+ static void markObjects(Heap::Base *that, MarkStack *markStack);
static bool isEqualTo(Managed *that, Managed *o);
static uint getLength(const Managed *m);
#endif
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 7ccb7a762f..7c65c97d73 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -77,15 +77,15 @@ void Heap::StringObject::init()
{
Object::init();
Q_ASSERT(vtable() == QV4::StringObject::staticVTable());
- string = internalClass->engine->id_empty()->d();
- *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0);
+ string.set(internalClass->engine, internalClass->engine->id_empty()->d());
+ setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(0));
}
void Heap::StringObject::init(const QV4::String *str)
{
Object::init();
- string = str->d();
- *propertyData(LengthPropertyIndex) = Primitive::fromInt32(length());
+ string.set(internalClass->engine, str->d());
+ setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(length()));
}
Heap::String *Heap::StringObject::getIndex(uint index) const
@@ -145,13 +145,6 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name,
return Object::advanceIterator(m, it, name, index, p, attrs);
}
-void StringObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- StringObject::Data *o = static_cast<StringObject::Data *>(that);
- o->string->mark(e);
- Object::markObjects(that, e);
-}
-
DEFINE_OBJECT_VTABLE(StringCtor);
void Heap::StringCtor::init(QV4::ExecutionContext *scope)
@@ -200,6 +193,7 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare, 1);
defineDefaultProperty(QStringLiteral("match"), method_match, 1);
+ defineDefaultProperty(QStringLiteral("repeat"), method_repeat, 1);
defineDefaultProperty(QStringLiteral("replace"), method_replace, 2);
defineDefaultProperty(QStringLiteral("search"), method_search, 1);
defineDefaultProperty(QStringLiteral("slice"), method_slice, 2);
@@ -458,6 +452,21 @@ void StringPrototype::method_match(const BuiltinFunction *, Scope &scope, CallDa
scope.result = a;
}
+void StringPrototype::method_repeat(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
+
+ double repeats = callData->args[0].toInteger();
+
+ if (repeats < 0 || qIsInf(repeats)) {
+ scope.result = scope.engine->throwRangeError(QLatin1String("Invalid count value"));
+ return;
+ }
+
+ scope.result = scope.engine->newString(value.repeated(int(repeats)));
+}
+
static void appendReplacementString(QString *result, const QString &input, const QString& replaceValue, uint* matchOffsets, int captureCount)
{
result->reserve(result->length() + replaceValue.length());
@@ -547,7 +556,7 @@ void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, Call
offset = qMax(offset + 1, matchOffsets[oldSize + 1]);
}
if (regExp->global())
- *regExp->lastIndexProperty() = Primitive::fromUInt32(0);
+ regExp->setLastIndex(0);
numStringMatches = nMatchOffsets / (regExp->value()->captureCount() * 2);
numCaptures = regExp->value()->captureCount();
} else {
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 2e64364f9f..ce046f4844 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -60,14 +60,18 @@ namespace QV4 {
namespace Heap {
-struct StringObject : Object {
+#define StringObjectMembers(class, Member) \
+ Member(class, Pointer, String *, string)
+
+DECLARE_HEAP_OBJECT(StringObject, Object) {
+ DECLARE_MARK_TABLE(StringObject);
+
enum {
LengthPropertyIndex = 0
};
void init();
void init(const QV4::String *string);
- String *string;
Heap::String *getIndex(uint index) const;
uint length() const;
@@ -96,7 +100,6 @@ struct StringObject: Object {
protected:
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs);
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
struct StringCtor: FunctionObject
@@ -122,6 +125,7 @@ struct StringPrototype: StringObject
static void method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_match(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_repeat(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_replace(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_search(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index 80655aded6..fe27d7c2d2 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -229,8 +229,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
return;
}
- Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
- array->d()->buffer = buffer->d();
+ Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
+ array->d()->buffer.set(scope.engine, buffer->d());
array->d()->byteLength = byteLength;
array->d()->byteOffset = 0;
@@ -252,8 +252,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
return;
}
- Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
- array->d()->buffer = newBuffer->d();
+ Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
+ array->d()->buffer.set(scope.engine, newBuffer->d());
array->d()->byteLength = destByteLength;
array->d()->byteOffset = 0;
@@ -311,8 +311,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
byteLength = (uint)l;
}
- Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
- array->d()->buffer = buffer->d();
+ Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
+ array->d()->buffer.set(scope.engine, buffer->d());
array->d()->byteLength = byteLength;
array->d()->byteOffset = byteOffset;
scope.result = array.asReturnedValue();
@@ -335,8 +335,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
return;
}
- Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
- array->d()->buffer = newBuffer->d();
+ Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
+ array->d()->buffer.set(scope.engine, newBuffer->d());
array->d()->byteLength = l * elementSize;
array->d()->byteOffset = 0;
@@ -377,12 +377,6 @@ Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type
return e->memoryManager->allocObject<TypedArray>(ic, e->typedArrayPrototype + t, t);
}
-void TypedArray::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- static_cast<TypedArray::Data *>(that)->buffer->mark(e);
- Object::markObjects(that, e);
-}
-
ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty)
{
Scope scope(static_cast<const Object *>(m)->engine());
@@ -400,11 +394,11 @@ ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProp
return a->d()->type->read(a->d()->buffer->data->data(), byteOffset);
}
-void TypedArray::putIndexed(Managed *m, uint index, const Value &value)
+bool TypedArray::putIndexed(Managed *m, uint index, const Value &value)
{
ExecutionEngine *v4 = static_cast<Object *>(m)->engine();
if (v4->hasException)
- return;
+ return false;
Scope scope(v4);
Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m));
@@ -415,11 +409,12 @@ void TypedArray::putIndexed(Managed *m, uint index, const Value &value)
goto reject;
a->d()->type->write(scope.engine, a->d()->buffer->data->data(), byteOffset, value);
- return;
+ return true;
reject:
if (scope.engine->current->strictMode)
scope.engine->throwTypeError();
+ return false;
}
void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor)
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index a6a74e4b9b..a472dfa607 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -72,7 +72,15 @@ struct TypedArrayOperations {
namespace Heap {
-struct TypedArray : Object {
+#define TypedArrayMembers(class, Member) \
+ Member(class, Pointer, ArrayBuffer *, buffer) \
+ Member(class, NoMark, const TypedArrayOperations *, type) \
+ Member(class, NoMark, uint, byteLength) \
+ Member(class, NoMark, uint, byteOffset) \
+ Member(class, NoMark, uint, arrayType)
+
+DECLARE_HEAP_OBJECT(TypedArray, Object) {
+ DECLARE_MARK_TABLE(TypedArray);
enum Type {
Int8Array,
UInt8Array,
@@ -87,12 +95,6 @@ struct TypedArray : Object {
};
void init(Type t);
-
- const TypedArrayOperations *type;
- Pointer<ArrayBuffer> buffer;
- uint byteLength;
- uint byteOffset;
- Type arrayType;
};
struct TypedArrayCtor : FunctionObject {
@@ -128,12 +130,11 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object
}
Heap::TypedArray::Type arrayType() const {
- return d()->arrayType;
+ return static_cast<Heap::TypedArray::Type>(d()->arrayType);
}
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void putIndexed(Managed *m, uint index, const Value &value);
+ static bool putIndexed(Managed *m, uint index, const Value &value);
};
struct TypedArrayCtor: FunctionObject
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 94233d4ddb..1158b82318 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -491,7 +491,7 @@ public:
// Section 9.12
bool sameValue(Value other) const;
- inline void mark(ExecutionEngine *e);
+ inline void mark(MarkStack *markStack);
Value &operator =(const ScopedValue &v);
Value &operator=(ReturnedValue v) { _val = v; return *this; }
@@ -722,7 +722,6 @@ inline unsigned int Value::toUInt32() const
return (unsigned int)toInt32();
}
-
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index 5cab4c5386..f2ff5d307e 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -84,7 +84,7 @@ bool VariantObject::isEqualTo(Managed *m, Managed *other)
return false;
}
-void VariantObject::addVmePropertyReference()
+void VariantObject::addVmePropertyReference() const
{
if (d()->isScarce() && ++d()->vmePropertyReferenceCount == 1) {
// remove from the ep->scarceResources list
@@ -94,7 +94,7 @@ void VariantObject::addVmePropertyReference()
}
}
-void VariantObject::removeVmePropertyReference()
+void VariantObject::removeVmePropertyReference() const
{
if (d()->isScarce() && --d()->vmePropertyReferenceCount == 0) {
// and add to the ep->scarceResources list
diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h
index dba14b13fb..a7c6fa320c 100644
--- a/src/qml/jsruntime/qv4variantobject_p.h
+++ b/src/qml/jsruntime/qv4variantobject_p.h
@@ -96,8 +96,8 @@ struct VariantObject : Object
V4_PROTOTYPE(variantPrototype)
V4_NEEDS_DESTROY
- void addVmePropertyReference();
- void removeVmePropertyReference();
+ void addVmePropertyReference() const;
+ void removeVmePropertyReference() const;
static bool isEqualTo(Managed *m, Managed *other);
};
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 3d95353fc0..5749d0aef3 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -338,18 +338,24 @@ Param traceParam(const Param &param)
return param;
}
# define VALUE(param) (*VALUEPTR(param))
-# define VALUEPTR(param) (scopes[traceParam(param).scope] + param.index)
+# define VALUEPTR(param) (scopes[traceParam(param).scope].values + param.index)
#else
# define VALUE(param) (*VALUEPTR(param))
-# define VALUEPTR(param) (scopes[param.scope] + param.index)
+# define VALUEPTR(param) (scopes[param.scope].values + param.index)
#endif
+// ### add write barrier here
#define STOREVALUE(param, value) { \
QV4::ReturnedValue tmp = (value); \
if (engine->hasException) \
goto catchException; \
- VALUE(param) = tmp; \
- }
+ if (Q_LIKELY(!engine->writeBarrierActive || !scopes[param.scope].base)) { \
+ VALUE(param) = tmp; \
+ } else { \
+ QV4::WriteBarrier::write(engine, scopes[param.scope].base, VALUEPTR(param), QV4::Value::fromReturnedValue(tmp)); \
+ } \
+}
+
// qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro
#ifdef CHECK_EXCEPTION
#undef CHECK_EXCEPTION
@@ -396,21 +402,29 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
}
}
- Q_ALLOCA_VAR(QV4::Value*, scopes, sizeof(QV4::Value *)*(2 + 2*scopeDepth));
+ struct Scopes {
+ QV4::Value *values;
+ QV4::Heap::Base *base; // non 0 if a write barrier is required
+ };
+ Q_ALLOCA_VAR(Scopes, scopes, sizeof(Scopes)*(2 + 2*scopeDepth));
{
- scopes[0] = const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->constants);
+ scopes[0] = { const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->constants), 0 };
// stack gets setup in push instruction
- scopes[1] = 0;
+ scopes[1] = { 0, 0 };
QV4::Heap::ExecutionContext *scope = engine->current;
int i = 0;
while (scope) {
- if (scope->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext) {
+ if (scope->type == QV4::Heap::ExecutionContext::Type_SimpleCallContext) {
+ QV4::Heap::SimpleCallContext *cc = static_cast<QV4::Heap::SimpleCallContext *>(scope);
+ scopes[2*i + 2] = { cc->callData->args, 0 };
+ scopes[2*i + 3] = { 0, 0 };
+ } else if (scope->type == QV4::Heap::ExecutionContext::Type_CallContext) {
QV4::Heap::CallContext *cc = static_cast<QV4::Heap::CallContext *>(scope);
- scopes[2*i + 2] = cc->callData->args;
- scopes[2*i + 3] = cc->locals;
+ scopes[2*i + 2] = { cc->callData->args, cc };
+ scopes[2*i + 3] = { cc->locals.values, cc };
} else {
- scopes[2*i + 2] = 0;
- scopes[2*i + 3] = 0;
+ scopes[2*i + 2] = { 0, 0 };
+ scopes[2*i + 3] = { 0, 0 };
}
++i;
scope = scope->outer;
@@ -477,7 +491,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
MOTH_BEGIN_INSTR(LoadElementLookup)
QV4::Lookup *l = engine->current->lookups + instr.lookup;
- STOREVALUE(instr.result, l->indexedGetter(l, VALUE(instr.base), VALUE(instr.index)));
+ STOREVALUE(instr.result, l->indexedGetter(l, engine, VALUE(instr.base), VALUE(instr.index)));
MOTH_END_INSTR(LoadElementLookup)
MOTH_BEGIN_INSTR(StoreElement)
@@ -487,7 +501,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
MOTH_BEGIN_INSTR(StoreElementLookup)
QV4::Lookup *l = engine->current->lookups + instr.lookup;
- l->indexedSetter(l, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
+ l->indexedSetter(l, engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElementLookup)
@@ -554,7 +568,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
TRACE(inline, "stack size: %u", instr.value);
stackSize = instr.value;
stack = scope.alloc(stackSize);
- scopes[1] = stack;
+ scopes[1].values = stack;
MOTH_END_INSTR(Push)
MOTH_BEGIN_INSTR(CallValue)