diff options
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4arrayobject.cpp | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 16 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4generatorobject.cpp | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4internalclass.cpp | 77 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4internalclass_p.h | 67 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4memberdata.cpp | 21 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qmlcontext.cpp | 19 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script.cpp | 1 |
8 files changed, 144 insertions, 65 deletions
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 8637db3dfd..b5b421fa39 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -103,7 +103,9 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) ctor->defineDefaultProperty(QStringLiteral("from"), method_from, 1); ctor->addSymbolSpecies(); - ScopedObject unscopables(scope, engine->newObject(engine->classes[EngineBase::Class_Empty]->changeVTable(QV4::Object::staticVTable()))); + Scoped<InternalClass> ic(scope, engine->classes[EngineBase::Class_Empty] + ->changeVTable(QV4::Object::staticVTable())); + ScopedObject unscopables(scope, engine->newObject(ic->d())); ScopedString name(scope); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(engine->id_toString(), method_toString, 0); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 1d0c7c13fa..bcd577c24d 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -464,11 +464,17 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) jsObjects[TypeError_Ctor] = memoryManager->allocate<TypeErrorCtor>(global); jsObjects[URIError_Ctor] = memoryManager->allocate<URIErrorCtor>(global); jsObjects[IteratorProto] = memoryManager->allocate<IteratorPrototype>(); - jsObjects[ForInIteratorProto] = memoryManager->allocObject<ForInIteratorPrototype>(newInternalClass(ForInIteratorPrototype::staticVTable(), iteratorPrototype())); - jsObjects[MapIteratorProto] = memoryManager->allocObject<MapIteratorPrototype>(newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype())); - jsObjects[SetIteratorProto] = memoryManager->allocObject<SetIteratorPrototype>(newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype())); - jsObjects[ArrayIteratorProto] = memoryManager->allocObject<ArrayIteratorPrototype>(newInternalClass(ArrayIteratorPrototype::staticVTable(), iteratorPrototype())); - jsObjects[StringIteratorProto] = memoryManager->allocObject<StringIteratorPrototype>(newInternalClass(StringIteratorPrototype::staticVTable(), iteratorPrototype())); + + ic = newInternalClass(ForInIteratorPrototype::staticVTable(), iteratorPrototype()); + jsObjects[ForInIteratorProto] = memoryManager->allocObject<ForInIteratorPrototype>(ic); + ic = newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype()); + jsObjects[MapIteratorProto] = memoryManager->allocObject<MapIteratorPrototype>(ic); + ic = newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype()); + jsObjects[SetIteratorProto] = memoryManager->allocObject<SetIteratorPrototype>(ic); + ic = newInternalClass(ArrayIteratorPrototype::staticVTable(), iteratorPrototype()); + jsObjects[ArrayIteratorProto] = memoryManager->allocObject<ArrayIteratorPrototype>(ic); + ic = newInternalClass(StringIteratorPrototype::staticVTable(), iteratorPrototype()); + jsObjects[StringIteratorProto] = memoryManager->allocObject<StringIteratorPrototype>(ic); str = newString(QStringLiteral("get [Symbol.species]")); jsObjects[GetSymbolSpecies] = FunctionObject::createBuiltinFunction(this, str, ArrayPrototype::method_get_species, 0); diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp index 566db6fd4e..14caa6953f 100644 --- a/src/qml/jsruntime/qv4generatorobject.cpp +++ b/src/qml/jsruntime/qv4generatorobject.cpp @@ -139,7 +139,9 @@ void GeneratorPrototype::init(ExecutionEngine *engine, Object *ctor) Scope scope(engine); ScopedValue v(scope); - ScopedObject ctorProto(scope, engine->newObject(engine->newInternalClass(Object::staticVTable(), engine->functionPrototype()))); + Scoped<InternalClass> ic(scope, engine->newInternalClass( + Object::staticVTable(), engine->functionPrototype())); + ScopedObject ctorProto(scope, engine->newObject(ic->d())); ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(1)); ctor->defineReadonlyProperty(engine->id_prototype(), ctorProto); diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 9906e2b1a0..a10fda79f2 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -44,6 +44,7 @@ #include "qv4object_p.h" #include "qv4identifiertable_p.h" #include "qv4value_p.h" +#include "qv4mm_p.h" QT_BEGIN_NAMESPACE @@ -144,7 +145,7 @@ SharedInternalClassDataPrivate<PropertyKey>::SharedInternalClassDataPrivate(cons data(nullptr) { if (other.alloc()) { - int s = other.size(); + const uint s = other.size(); data = MemberData::allocate(engine, other.alloc(), other.data); setSize(s); } @@ -163,8 +164,8 @@ SharedInternalClassDataPrivate<PropertyKey>::SharedInternalClassDataPrivate(cons void SharedInternalClassDataPrivate<PropertyKey>::grow() { - uint a = alloc() * 2; - int s = size(); + const uint a = alloc() * 2; + const uint s = size(); data = MemberData::allocate(engine, a, data); setSize(s); Q_ASSERT(alloc() >= a); @@ -204,7 +205,70 @@ void SharedInternalClassDataPrivate<PropertyKey>::mark(MarkStack *s) data->mark(s); } +SharedInternalClassDataPrivate<PropertyAttributes>::SharedInternalClassDataPrivate( + const SharedInternalClassDataPrivate<PropertyAttributes> &other, uint pos, + PropertyAttributes value) + : refcount(1), + m_alloc(qMin(other.m_alloc, pos + 8)), + m_size(pos + 1), + m_engine(other.m_engine) +{ + Q_ASSERT(m_size <= m_alloc); + m_engine->memoryManager->changeUnmanagedHeapSizeUsage(m_alloc * sizeof(PropertyAttributes)); + data = new PropertyAttributes[m_alloc]; + if (other.data) + memcpy(data, other.data, (m_size - 1) * sizeof(PropertyAttributes)); + data[pos] = value; +} + +SharedInternalClassDataPrivate<PropertyAttributes>::SharedInternalClassDataPrivate( + const SharedInternalClassDataPrivate<PropertyAttributes> &other) + : refcount(1), + m_alloc(other.m_alloc), + m_size(other.m_size), + m_engine(other.m_engine) +{ + if (m_alloc) { + m_engine->memoryManager->changeUnmanagedHeapSizeUsage(m_alloc * sizeof(PropertyAttributes)); + data = new PropertyAttributes[m_alloc]; + memcpy(data, other.data, m_size*sizeof(PropertyAttributes)); + } else { + data = nullptr; + } +} +SharedInternalClassDataPrivate<PropertyAttributes>::~SharedInternalClassDataPrivate() +{ + m_engine->memoryManager->changeUnmanagedHeapSizeUsage( + -qptrdiff(m_alloc * sizeof(PropertyAttributes))); + delete [] data; +} + +void SharedInternalClassDataPrivate<PropertyAttributes>::grow() { + uint alloc; + if (!m_alloc) { + alloc = 8; + m_engine->memoryManager->changeUnmanagedHeapSizeUsage(alloc * sizeof(PropertyAttributes)); + } else { + // yes, signed. We don't want to deal with stuff > 2G + const uint currentSize = m_alloc * sizeof(PropertyAttributes); + if (currentSize < uint(std::numeric_limits<int>::max() / 2)) + alloc = m_alloc * 2; + else + alloc = std::numeric_limits<int>::max() / sizeof(PropertyAttributes); + + m_engine->memoryManager->changeUnmanagedHeapSizeUsage( + (alloc - m_alloc) * sizeof(PropertyAttributes)); + } + + auto *n = new PropertyAttributes[alloc]; + if (data) { + memcpy(n, data, m_alloc*sizeof(PropertyAttributes)); + delete [] data; + } + data = n; + m_alloc = alloc; +} namespace Heap { @@ -602,11 +666,10 @@ Heap::InternalClass *InternalClass::frozen() return f; } -Heap::InternalClass *InternalClass::propertiesFrozen() const +Heap::InternalClass *InternalClass::propertiesFrozen() { Scope scope(engine); - Scoped<QV4::InternalClass> frozen(scope, engine->internalClasses(EngineBase::Class_Empty)->changeVTable(vtable)); - frozen = frozen->changePrototype(prototype); + Scoped<QV4::InternalClass> frozen(scope, this); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (!nameMap.at(i).isValid()) @@ -615,7 +678,7 @@ Heap::InternalClass *InternalClass::propertiesFrozen() const attrs.setWritable(false); attrs.setConfigurable(false); } - frozen = frozen->addMember(nameMap.at(i), attrs); + frozen = frozen->changeMember(nameMap.at(i), attrs); } return frozen->d(); } diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 681cbda5f9..42b61218a5 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -149,55 +149,31 @@ inline PropertyHash::Entry *PropertyHash::lookup(PropertyKey identifier) const } } -template<typename T> -struct SharedInternalClassDataPrivate { - SharedInternalClassDataPrivate(ExecutionEngine *) +template<class T> +struct SharedInternalClassDataPrivate {}; + +template<> +struct SharedInternalClassDataPrivate<PropertyAttributes> { + SharedInternalClassDataPrivate(ExecutionEngine *engine) : refcount(1), m_alloc(0), m_size(0), - data(nullptr) + data(nullptr), + m_engine(engine) { } - SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate &other) - : refcount(1), - m_alloc(other.m_alloc), - m_size(other.m_size) - { - if (m_alloc) { - data = new T[m_alloc]; - memcpy(data, other.data, m_size*sizeof(T)); - } - } - SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate &other, uint pos, T value) - : refcount(1), - m_alloc(pos + 8), - m_size(pos + 1) - { - data = new T[m_alloc]; - if (other.data) - memcpy(data, other.data, (m_size - 1)*sizeof(T)); - data[pos] = value; - } - ~SharedInternalClassDataPrivate() { delete [] data; } - + SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate<PropertyAttributes> &other); + SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate<PropertyAttributes> &other, + uint pos, PropertyAttributes value); + ~SharedInternalClassDataPrivate(); - void grow() { - if (!m_alloc) - m_alloc = 4; - T *n = new T[m_alloc * 2]; - if (data) { - memcpy(n, data, m_alloc*sizeof(T)); - delete [] data; - } - data = n; - m_alloc *= 2; - } + void grow(); uint alloc() const { return m_alloc; } uint size() const { return m_size; } void setSize(uint s) { m_size = s; } - T at(uint i) { Q_ASSERT(data && i < m_alloc); return data[i]; } - void set(uint i, T t) { Q_ASSERT(data && i < m_alloc); data[i] = t; } + PropertyAttributes at(uint i) { Q_ASSERT(data && i < m_alloc); return data[i]; } + void set(uint i, PropertyAttributes t) { Q_ASSERT(data && i < m_alloc); data[i] = t; } void mark(MarkStack *) {} @@ -205,7 +181,8 @@ struct SharedInternalClassDataPrivate { private: uint m_alloc; uint m_size; - T *data; + PropertyAttributes *data; + ExecutionEngine *m_engine; }; template<> @@ -270,8 +247,12 @@ struct SharedInternalClassData { Q_ASSERT(pos == d->size()); if (pos == d->alloc()) d->grow(); - d->setSize(d->size() + 1); - d->set(pos, value); + if (pos >= d->alloc()) { + qBadAlloc(); + } else { + d->setSize(d->size() + 1); + d->set(pos, value); + } } void set(uint pos, T value) { @@ -451,7 +432,7 @@ struct InternalClass : Base { Q_REQUIRED_RESULT InternalClass *sealed(); Q_REQUIRED_RESULT InternalClass *frozen(); - Q_REQUIRED_RESULT InternalClass *propertiesFrozen() const; + Q_REQUIRED_RESULT InternalClass *propertiesFrozen(); Q_REQUIRED_RESULT InternalClass *asProtoClass(); diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index 246f857643..f327c85001 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -69,12 +69,25 @@ Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberD size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value)); // round up to next power of two to avoid quadratic behaviour for very large objects alloc = nextPowerOfTwo(alloc); - Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc); - if (old) + + // The above code can overflow in a number of interesting ways. All of those are unsigned, + // and therefore defined behavior. Still, apply some sane bounds. + if (alloc > std::numeric_limits<int>::max()) + alloc = std::numeric_limits<int>::max(); + + Heap::MemberData *m; + if (old) { + const size_t oldSize = sizeof(Heap::MemberData) + (old->values.size - 1) * sizeof(Value); + if (oldSize > alloc) + alloc = oldSize; + m = e->memoryManager->allocManaged<MemberData>(alloc); // no write barrier required here - memcpy(m, old, sizeof(Heap::MemberData) + (old->values.size - 1) * sizeof(Value)); - else + memcpy(m, old, oldSize); + } else { + m = e->memoryManager->allocManaged<MemberData>(alloc); m->init(); + } + 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/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index a2c8e3916f..12ada7ee70 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -465,10 +465,23 @@ ReturnedValue QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(Lookup * return static_cast<Heap::CallContext*>(ctx.d())->locals[index].asReturnedValue(); } - Scoped<QQmlContextWrapper> qmlContext(scope, engine->qmlContext()->qml()); bool hasProperty = false; - ScopedValue result(scope, QQmlContextWrapper::getPropertyAndBase(qmlContext, name, /*receiver*/nullptr, - &hasProperty, base, l)); + ScopedValue result(scope); + + Scoped<QmlContext> callingQmlContext(scope, engine->qmlContext()); + if (callingQmlContext) { + Scoped<QQmlContextWrapper> qmlContextWrapper(scope, callingQmlContext->d()->qml()); + result = QQmlContextWrapper::getPropertyAndBase(qmlContextWrapper, name, /*receiver*/nullptr, &hasProperty, + base, l); + } else { + // Code path typical to worker scripts, compiled with lookups but no qml context. + result = l->resolveGlobalGetter(engine); + if (l->globalGetter != Lookup::globalGetterGeneric) { + hasProperty = true; + l->qmlContextGlobalLookup.getterTrampoline = l->globalGetter; + l->qmlContextPropertyGetter = QQmlContextWrapper::lookupInGlobalObject; + } + } if (!hasProperty) return engine->throwReferenceError(name.toQString()); return result->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 7bbef3335e..6cb2e95cdc 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -201,7 +201,6 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compi } Codegen cg(unitGenerator, /*strict mode*/false); - cg.setUseFastLookups(false); cg.generateFromProgram(fileName, finalUrl, source, program, module, contextType); errors = cg.qmlErrors(); if (!errors.isEmpty()) { |