aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h5
-rw-r--r--src/qml/jsruntime/qv4arrayiterator_p.h2
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper.cpp11
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper_p.h1
-rw-r--r--src/qml/jsruntime/qv4context_p.h4
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h2
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp65
-rw-r--r--src/qml/jsruntime/qv4engine_p.h13
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4executableallocator.cpp2
-rw-r--r--src/qml/jsruntime/qv4executableallocator_p.h4
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp22
-rw-r--r--src/qml/jsruntime/qv4function.cpp4
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp23
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4generatorobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp14
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp8
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp43
-rw-r--r--src/qml/jsruntime/qv4mapiterator_p.h2
-rw-r--r--src/qml/jsruntime/qv4memberdata_p.h2
-rw-r--r--src/qml/jsruntime/qv4module.cpp2
-rw-r--r--src/qml/jsruntime/qv4object.cpp2
-rw-r--r--src/qml/jsruntime/qv4persistent_p.h2
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp2
-rw-r--r--src/qml/jsruntime/qv4promiseobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4propertykey.cpp2
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h4
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp110
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h62
-rw-r--r--src/qml/jsruntime/qv4reflect.cpp5
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp12
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp18
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp17
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h6
-rw-r--r--src/qml/jsruntime/qv4setiterator_p.h2
-rw-r--r--src/qml/jsruntime/qv4stringiterator.cpp2
-rw-r--r--src/qml/jsruntime/qv4stringiterator_p.h2
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp58
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4symbol_p.h2
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h2
-rw-r--r--src/qml/jsruntime/qv4urlobject.cpp16
-rw-r--r--src/qml/jsruntime/qv4urlobject_p.h4
48 files changed, 353 insertions, 226 deletions
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index 4edfe2a763..dc17ea4e54 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -30,7 +30,7 @@ namespace Heap {
Member(class, NoMark, quint64, mapped)
DECLARE_HEAP_OBJECT(ArgumentsObject, Object) {
- DECLARE_MARKOBJECTS(ArgumentsObject);
+ DECLARE_MARKOBJECTS(ArgumentsObject)
enum {
LengthPropertyIndex = 0,
SymbolIteratorPropertyIndex = 1,
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index cc322b3f01..b955618cbe 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -60,7 +60,10 @@ private:
return *reinterpret_cast<QArrayDataPointer<char> *>(&arrayDataPointerStorage);
}
- std::aligned_storage_t<sizeof(QArrayDataPointer<char>), alignof(QArrayDataPointer<char>)>
+ template <typename T>
+ struct storage_t { alignas(T) unsigned char data[sizeof(T)]; };
+
+ storage_t<QArrayDataPointer<char>>
arrayDataPointerStorage;
bool isShared;
};
diff --git a/src/qml/jsruntime/qv4arrayiterator_p.h b/src/qml/jsruntime/qv4arrayiterator_p.h
index 2682dc79d0..ff00f99bea 100644
--- a/src/qml/jsruntime/qv4arrayiterator_p.h
+++ b/src/qml/jsruntime/qv4arrayiterator_p.h
@@ -33,7 +33,7 @@ namespace Heap {
Member(class, NoMark, quint32, nextIndex)
DECLARE_HEAP_OBJECT(ArrayIteratorObject, Object) {
- DECLARE_MARKOBJECTS(ArrayIteratorObject);
+ DECLARE_MARKOBJECTS(ArrayIteratorObject)
void init(Object *obj, QV4::ExecutionEngine *engine)
{
Object::init();
diff --git a/src/qml/jsruntime/qv4compilationunitmapper.cpp b/src/qml/jsruntime/qv4compilationunitmapper.cpp
index 0479b8b8f1..61b0f1d497 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper.cpp
+++ b/src/qml/jsruntime/qv4compilationunitmapper.cpp
@@ -29,6 +29,11 @@ public:
s_staticUnits.insert(file, staticUnit);
}
+ void remove(const QString &file)
+ {
+ s_staticUnits.remove(file);
+ }
+
private:
QMutexLocker<QMutex> m_lock;
@@ -69,4 +74,10 @@ CompiledData::Unit *CompilationUnitMapper::get(
return data;
}
+void CompilationUnitMapper::invalidate(const QString &cacheFilePath)
+{
+ StaticUnitCache cache;
+ cache.remove(cacheFilePath);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4compilationunitmapper_p.h b/src/qml/jsruntime/qv4compilationunitmapper_p.h
index 0d3ec4eeee..07952be62c 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper_p.h
+++ b/src/qml/jsruntime/qv4compilationunitmapper_p.h
@@ -33,6 +33,7 @@ public:
CompiledData::Unit *get(
const QString &cacheFilePath, const QDateTime &sourceTimeStamp, QString *errorString);
+ static void invalidate(const QString &cacheFilePath);
private:
CompiledData::Unit *open(
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 66f06ff96a..82a9472223 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -29,7 +29,7 @@ namespace Heap {
Member(class, Pointer, Object *, activation)
DECLARE_HEAP_OBJECT(ExecutionContext, Base) {
- DECLARE_MARKOBJECTS(ExecutionContext);
+ DECLARE_MARKOBJECTS(ExecutionContext)
enum ContextType {
Type_GlobalContext = 0x1,
@@ -68,7 +68,7 @@ Q_STATIC_ASSERT(offsetof(ExecutionContextData, activation) == offsetof(Execution
Member(class, ValueArray, ValueArray, locals)
DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) {
- DECLARE_MARKOBJECTS(CallContext);
+ DECLARE_MARKOBJECTS(CallContext)
void init()
{
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index 73f31d8f8c..ab2e1e589a 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -33,7 +33,7 @@ struct DataViewCtor : FunctionObject {
Member(class, NoMark, uint, byteOffset)
DECLARE_HEAP_OBJECT(DataView, Object) {
- DECLARE_MARKOBJECTS(DataView);
+ DECLARE_MARKOBJECTS(DataView)
void init() { Object::init(); }
};
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 769b8c161a..1fb6d92183 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -343,7 +343,7 @@ static inline double ParseString(const QString &s, double localTZA)
};
const QChar *ch = s.constData();
- const QChar *end = ch + s.length();
+ const QChar *end = ch + s.size();
uint format = Year;
int current = 0;
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 17cea99fd8..30924dd76d 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -324,6 +324,9 @@ void ExecutionEngine::initializeStaticMembers()
#elif defined(Q_OS_ANDROID)
// In experiments, it started crashing at 1059.
s_maxCallDepth = 1000;
+#elif defined(Q_OS_WIN)
+ // We've seen crashes around 750.
+ s_maxCallDepth = 640;
#else
s_maxCallDepth = 1234;
#endif
@@ -391,12 +394,15 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
}
}
+ // We allocate guard pages around our stacks.
+ const size_t guardPages = 2 * WTF::pageSize();
+
memoryManager = new QV4::MemoryManager(this);
// reserve space for the JS stack
// we allow it to grow to a bit more than m_maxJSStackSize, as we can overshoot due to ScopedValues
// allocated outside of JIT'ed methods.
*jsStack = WTF::PageAllocation::allocate(
- s_maxJSStackSize + 256*1024, WTF::OSAllocator::JSVMStackPages,
+ s_maxJSStackSize + 256*1024 + guardPages, WTF::OSAllocator::JSVMStackPages,
/* writable */ true, /* executable */ false, /* includesGuardPages */ true);
jsStackBase = (Value *)jsStack->base();
#ifdef V4_USE_VALGRIND
@@ -405,9 +411,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsStackTop = jsStackBase;
- *gcStack = WTF::PageAllocation::allocate(s_maxGCStackSize, WTF::OSAllocator::JSVMStackPages,
- /* writable */ true, /* executable */ false,
- /* includesGuardPages */ true);
+ *gcStack = WTF::PageAllocation::allocate(
+ s_maxGCStackSize + guardPages, WTF::OSAllocator::JSVMStackPages,
+ /* writable */ true, /* executable */ false, /* includesGuardPages */ true);
exceptionValue = jsAlloca(1);
*exceptionValue = Encode::undefined();
@@ -949,13 +955,13 @@ Heap::Object *ExecutionEngine::newObject(Heap::InternalClass *internalClass)
Heap::String *ExecutionEngine::newString(const QString &s)
{
- return memoryManager->allocWithStringData<String>(s.length() * sizeof(QChar), s);
+ return memoryManager->allocWithStringData<String>(s.size() * sizeof(QChar), s);
}
Heap::String *ExecutionEngine::newIdentifier(const QString &text)
{
Scope scope(this);
- ScopedString s(scope, memoryManager->allocWithStringData<String>(text.length() * sizeof(QChar), text));
+ ScopedString s(scope, memoryManager->allocWithStringData<String>(text.size() * sizeof(QChar), text));
s->toPropertyKey();
return s->d();
}
@@ -1511,6 +1517,12 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, QMet
if (metaType == QMetaType::fromType<bool>())
return QVariant(value.toBoolean());
+ if (metaType == QMetaType::fromType<double>())
+ return QVariant(value.toNumber());
+
+ if (metaType == QMetaType::fromType<float>())
+ return QVariant(float(value.toNumber()));
+
if (metaType == QMetaType::fromType<QJsonValue>())
return QVariant::fromValue(QV4::JsonObject::toJsonValue(value));
@@ -1842,23 +1854,17 @@ QV4::ReturnedValue ExecutionEngine::fromData(
// directly against QList<QObject*>?
const QList<QObject *> &list = *(const QList<QObject *>*)ptr;
QV4::ScopedArrayObject a(scope, newArrayObject());
- a->arrayReserve(list.count());
+ a->arrayReserve(list.size());
QV4::ScopedValue v(scope);
- for (int ii = 0; ii < list.count(); ++ii)
+ for (int ii = 0; ii < list.size(); ++ii)
a->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(this, list.at(ii))));
- a->setArrayLengthUnchecked(list.count());
+ a->setArrayLengthUnchecked(list.size());
return a.asReturnedValue();
} else if (auto flags = metaType.flags(); flags & QMetaType::PointerToQObject) {
- QV4::ReturnedValue ret = QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
- if (!flags.testFlag(QMetaType::IsConst))
- return ret;
- QV4::ScopedValue v(scope, ret);
- if (auto obj = v->as<Object>()) {
- obj->setInternalClass(obj->internalClass()->cryopreserved());
- return obj->asReturnedValue();
- } else {
- return ret;
- }
+ if (flags.testFlag(QMetaType::IsConst))
+ return QV4::QObjectWrapper::wrapConst(this, *reinterpret_cast<QObject* const *>(ptr));
+ else
+ return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
}
bool succeeded = false;
@@ -1981,6 +1987,25 @@ int ExecutionEngine::maxGCStackSize() const
return s_maxGCStackSize;
}
+/*!
+ \internal
+ Returns \a length converted to int if its safe to
+ pass to \c Scope::alloc.
+ Otherwise it throws a RangeError, and returns 0.
+ */
+int ExecutionEngine::safeForAllocLength(qint64 len64)
+{
+ if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max())) {
+ throwRangeError(QStringLiteral("Invalid array length."));
+ return 0;
+ }
+ if (len64 > qint64(this->jsStackLimit - this->jsStackTop)) {
+ throwRangeError(QStringLiteral("Array too large for apply()."));
+ return 0;
+ }
+ return len64;
+}
+
ReturnedValue ExecutionEngine::global()
{
return globalObject->asReturnedValue();
@@ -2252,7 +2277,7 @@ int ExecutionEngine::consoleCountHelper(const QString &file, quint16 line, quint
void ExecutionEngine::setExtensionData(int index, Deletable *data)
{
- if (m_extensionData.count() <= index)
+ if (m_extensionData.size() <= index)
m_extensionData.resize(index + 1);
if (m_extensionData.at(index))
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index d00495eff0..c6b97273e3 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -650,6 +650,7 @@ public:
int maxGCStackSize() const;
bool checkStackLimits();
+ int safeForAllocLength(qint64 len64);
bool canJIT(Function *f = nullptr)
{
@@ -702,7 +703,7 @@ public:
void setExtensionData(int, Deletable *);
Deletable *extensionData(int index) const
{
- if (index < m_extensionData.count())
+ if (index < m_extensionData.size())
return m_extensionData[index];
else
return nullptr;
@@ -736,6 +737,9 @@ public:
QV4::ExecutionContext *ctxt, int argc, const QV4::Value *argv);
private:
+ template<int Frames>
+ friend struct ExecutionEngineCallDepthRecorder;
+
QV4::ReturnedValue fromData(QMetaType type, const void *ptr, const QVariant *variant = nullptr);
static void initializeStaticMembers();
@@ -772,12 +776,15 @@ private:
#define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \
ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
+template<int Frames = 1>
struct ExecutionEngineCallDepthRecorder
{
ExecutionEngine *ee;
- ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ++ee->callDepth; }
- ~ExecutionEngineCallDepthRecorder() { --ee->callDepth; }
+ ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ee->callDepth += Frames; }
+ ~ExecutionEngineCallDepthRecorder() { ee->callDepth -= Frames; }
+
+ bool hasOverflow() const { return ee->callDepth >= ExecutionEngine::s_maxCallDepth; }
};
inline bool ExecutionEngine::checkStackLimits()
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index f3adadc887..eb449ba293 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -120,7 +120,7 @@ ReturnedValue ErrorObject::method_get_stack(const FunctionObject *b, const Value
return v4->throwTypeError();
if (!This->d()->stack) {
QString trace;
- for (int i = 0; i < This->d()->stackTrace->count(); ++i) {
+ for (int i = 0; i < This->d()->stackTrace->size(); ++i) {
if (i > 0)
trace += QLatin1Char('\n');
const StackFrame &frame = This->d()->stackTrace->at(i);
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index c8ebe11f30..3d9069b587 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -31,7 +31,7 @@ namespace Heap {
Member(class, Pointer, String *, stack)
DECLARE_HEAP_OBJECT(ErrorObject, Object) {
- DECLARE_MARKOBJECTS(ErrorObject);
+ DECLARE_MARKOBJECTS(ErrorObject)
enum ErrorType {
Error,
EvalError,
diff --git a/src/qml/jsruntime/qv4executableallocator.cpp b/src/qml/jsruntime/qv4executableallocator.cpp
index f8b005e914..5a63230858 100644
--- a/src/qml/jsruntime/qv4executableallocator.cpp
+++ b/src/qml/jsruntime/qv4executableallocator.cpp
@@ -125,7 +125,7 @@ ExecutableAllocator::ExecutableAllocator()
ExecutableAllocator::~ExecutableAllocator()
{
- for (ChunkOfPages *chunk : qAsConst(chunks)) {
+ for (ChunkOfPages *chunk : std::as_const(chunks)) {
for (Allocation *allocation = chunk->firstAllocation; allocation; allocation = allocation->next)
if (!allocation->free)
allocation->invalidate();
diff --git a/src/qml/jsruntime/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h
index d6551599e7..7fd8a10cdb 100644
--- a/src/qml/jsruntime/qv4executableallocator_p.h
+++ b/src/qml/jsruntime/qv4executableallocator_p.h
@@ -79,8 +79,8 @@ public:
};
// for debugging / unit-testing
- int freeAllocationCount() const { return freeAllocations.count(); }
- int chunkCount() const { return chunks.count(); }
+ int freeAllocationCount() const { return freeAllocations.size(); }
+ int chunkCount() const { return chunks.size(); }
struct ChunkOfPages
{
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index 3fe031501f..2affa4f6dd 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -297,7 +297,7 @@ void ExecutableCompilationUnit::unlink()
delete [] runtimeLookups;
runtimeLookups = nullptr;
- for (QV4::Function *f : qAsConst(runtimeFunctions))
+ for (QV4::Function *f : std::as_const(runtimeFunctions))
f->destroy();
runtimeFunctions.clear();
@@ -325,14 +325,14 @@ void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack)
if (runtimeClasses[i])
runtimeClasses[i]->mark(markStack);
}
- for (QV4::Function *f : qAsConst(runtimeFunctions))
+ for (QV4::Function *f : std::as_const(runtimeFunctions))
if (f && f->internalClass)
f->internalClass->mark(markStack);
- for (QV4::Heap::InternalClass *c : qAsConst(runtimeBlocks))
+ for (QV4::Heap::InternalClass *c : std::as_const(runtimeBlocks))
if (c)
c->mark(markStack);
- for (QV4::Heap::Object *o : qAsConst(templateObjects))
+ for (QV4::Heap::Object *o : std::as_const(templateObjects))
if (o)
o->mark(markStack);
@@ -819,8 +819,14 @@ bool ExecutableCompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorSt
return CompiledData::SaveableUnitPointer(unitData()).saveToDisk<char>(
[&unitUrl, errorString](const char *data, quint32 size) {
- return CompiledData::SaveableUnitPointer::writeDataToFile(localCacheFilePath(unitUrl), data,
- size, errorString);
+ const QString cachePath = localCacheFilePath(unitUrl);
+ if (CompiledData::SaveableUnitPointer::writeDataToFile(
+ cachePath, data, size, errorString)) {
+ CompilationUnitMapper::invalidate(cachePath);
+ return true;
+ }
+
+ return false;
});
}
@@ -832,7 +838,7 @@ bool ExecutableCompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorSt
bool ResolvedTypeReferenceMap::addToHash(
QCryptographicHash *hash, QHash<quintptr, QByteArray> *checksums) const
{
- std::vector<int> keys (count());
+ std::vector<int> keys (size());
int i = 0;
for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
keys[i] = it.key();
@@ -864,7 +870,7 @@ QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Bind
// This code must match that in the qsTr() implementation
const QString &path = fileName();
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- QStringView context = (lastSlash > -1) ? QStringView{path}.mid(lastSlash + 1, path.length() - lastSlash - 5)
+ QStringView context = (lastSlash > -1) ? QStringView{path}.mid(lastSlash + 1, path.size() - lastSlash - 5)
: QStringView();
QByteArray contextUtf8 = context.toUtf8();
QByteArray comment = stringAt(translation.commentIndex).toUtf8();
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 1be093f0a4..f756575ea8 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -111,7 +111,7 @@ Function::Function(ExecutionEngine *engine, const QQmlPrivate::AOTCompiledFuncti
, aotFunction(aotFunction)
{
internalClass = engine->internalClasses(EngineBase::Class_CallContext);
- nFormals = aotFunction->argumentTypes.length();
+ nFormals = aotFunction->argumentTypes.size();
}
Function::~Function()
@@ -127,7 +127,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
QStringList parameterNames;
// Resolve duplicate parameter names:
- for (int i = 0, ei = parameters.count(); i != ei; ++i) {
+ for (int i = 0, ei = parameters.size(); i != ei; ++i) {
const QByteArray &param = parameters.at(i);
int duplicate = -1;
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 186535cb82..b38c29a6c5 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -351,36 +351,31 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons
if (!arr)
return v4->throwTypeError();
- const qint64 len64 = arr->getLength();
- if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max()))
- return v4->throwRangeError(QStringLiteral("Invalid array length."));
- if (len64 > qint64(v4->jsStackLimit - v4->jsStackTop))
- return v4->throwRangeError(QStringLiteral("Array too large for apply()."));
-
- const uint len = uint(len64);
-
Scope scope(v4);
+ const int len = v4->safeForAllocLength(arr->getLength());
+ CHECK_EXCEPTION();
+
Value *arguments = scope.alloc<Scope::Uninitialized>(len);
if (len) {
if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
QV4::ArgumentsObject *a = arr->cast<ArgumentsObject>();
- int l = qMin(len, (uint)a->d()->context->argc());
+ int l = qMin(len, a->d()->context->argc());
memcpy(arguments, a->d()->context->args(), l*sizeof(Value));
- for (quint32 i = l; i < len; ++i)
+ for (int i = l; i < len; ++i)
arguments[i] = Value::undefinedValue();
} else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) {
auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData());
- uint alen = sad ? sad->values.size : 0;
+ int alen = sad ? sad->values.size : 0;
if (alen > len)
alen = len;
- for (uint i = 0; i < alen; ++i)
+ for (int i = 0; i < alen; ++i)
arguments[i] = sad->data(i);
- for (quint32 i = alen; i < len; ++i)
+ for (int i = alen; i < len; ++i)
arguments[i] = Value::undefinedValue();
} else {
// need to init the arguments array, as the get() calls below can have side effects
memset(arguments, 0, len*sizeof(Value));
- for (quint32 i = 0; i < len; ++i)
+ for (int i = 0; i < len; ++i)
arguments[i] = arr->get(i);
}
}
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index b42c55f5a8..e32fce28ba 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -40,7 +40,7 @@ namespace Heap {
Member(class, NoMark, bool, canBeTailCalled)
DECLARE_HEAP_OBJECT(FunctionObject, Object) {
- DECLARE_MARKOBJECTS(FunctionObject);
+ DECLARE_MARKOBJECTS(FunctionObject)
enum {
Index_ProtoConstructor = 0,
Index_Prototype = 0,
@@ -125,7 +125,7 @@ struct DefaultClassConstructorFunction : FunctionObject
Member(class, Pointer, MemberData *, boundArgs)
DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) {
- DECLARE_MARKOBJECTS(BoundFunction);
+ DECLARE_MARKOBJECTS(BoundFunction)
void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs);
};
diff --git a/src/qml/jsruntime/qv4generatorobject_p.h b/src/qml/jsruntime/qv4generatorobject_p.h
index 4a84bec748..55ccc133aa 100644
--- a/src/qml/jsruntime/qv4generatorobject_p.h
+++ b/src/qml/jsruntime/qv4generatorobject_p.h
@@ -57,7 +57,7 @@ struct GeneratorPrototype : FunctionObject {
Member(class, Pointer, ArrayObject *, jsFrame)
DECLARE_HEAP_OBJECT(GeneratorObject, Object) {
- DECLARE_MARKOBJECTS(GeneratorObject);
+ DECLARE_MARKOBJECTS(GeneratorObject)
};
}
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 0112347053..7ea90a2ddd 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -32,7 +32,7 @@ static QString escape(const QString &input)
{
QString output;
output.reserve(input.size() * 3);
- const int length = input.length();
+ const int length = input.size();
for (int i = 0; i < length; ++i) {
ushort uc = input.at(i).unicode();
if (uc < 0x100) {
@@ -63,9 +63,9 @@ static QString escape(const QString &input)
static QString unescape(const QString &input)
{
QString result;
- result.reserve(input.length());
+ result.reserve(input.size());
int i = 0;
- const int length = input.length();
+ const int length = input.size();
while (i < length) {
QChar c = input.at(i++);
if ((c == u'%') && (i + 1 < length)) {
@@ -113,7 +113,7 @@ static QString encode(const QString &input, const char *unescapedSet, bool *ok)
{
*ok = true;
QString output;
- const int length = input.length();
+ const int length = input.size();
int i = 0;
while (i < length) {
const QChar c = input.at(i);
@@ -187,8 +187,8 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok)
{
*ok = true;
QString output;
- output.reserve(input.length());
- const int length = input.length();
+ output.reserve(input.size());
+ const int length = input.size();
int i = 0;
const QChar percent = QLatin1Char('%');
while (i < length) {
@@ -381,7 +381,7 @@ ReturnedValue GlobalFunctions::method_parseInt(const FunctionObject *b, const Va
CHECK_EXCEPTION();
const QChar *pos = trimmed.constData();
- const QChar *end = pos + trimmed.length();
+ const QChar *end = pos + trimmed.size();
int sign = 1; // 3
if (pos != end) {
diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp
index 5b0c2f25ee..96aa54018b 100644
--- a/src/qml/jsruntime/qv4identifiertable.cpp
+++ b/src/qml/jsruntime/qv4identifiertable.cpp
@@ -25,7 +25,7 @@ IdentifierTable::~IdentifierTable()
{
free(entriesByHash);
free(entriesById);
- for (const auto &h : qAsConst(idHashes))
+ for (const auto &h : std::as_const(idHashes))
h->identifierTable = nullptr;
}
@@ -100,7 +100,7 @@ void IdentifierTable::addEntry(Heap::StringOrSymbol *str)
Heap::String *IdentifierTable::insertString(const QString &s)
{
uint subtype;
- uint hash = String::createHashValue(s.constData(), s.length(), &subtype);
+ uint hash = String::createHashValue(s.constData(), s.size(), &subtype);
if (subtype == Heap::String::StringType_ArrayIndex) {
Heap::String *str = engine->newString(s);
str->stringHash = hash;
@@ -133,7 +133,7 @@ Heap::Symbol *IdentifierTable::insertSymbol(const QString &s)
Q_ASSERT(s.at(0) == QLatin1Char('@'));
uint subtype;
- uint hash = String::createHashValue(s.constData(), s.length(), &subtype);
+ uint hash = String::createHashValue(s.constData(), s.size(), &subtype);
uint idx = hash % alloc;
while (Heap::StringOrSymbol *e = entriesByHash[idx]) {
if (e->stringHash == hash && e->toQString() == s)
@@ -252,7 +252,7 @@ void IdentifierTable::sweep()
PropertyKey IdentifierTable::asPropertyKey(const QString &s)
{
uint subtype;
- const uint hash = String::createHashValue(s.constData(), s.length(), &subtype);
+ const uint hash = String::createHashValue(s.constData(), s.size(), &subtype);
if (subtype == Heap::String::StringType_ArrayIndex)
return PropertyKey::fromArrayIndex(hash);
return resolveStringEntry(s, hash, subtype)->identifier;
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 693cc436ef..57ff8c44ec 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -610,10 +610,32 @@ struct Stringify
QString makeMember(const QString &key, const Value &v);
};
+class [[nodiscard]] CallDepthAndCycleChecker
+{
+ Q_DISABLE_COPY_MOVE(CallDepthAndCycleChecker);
+
+public:
+ CallDepthAndCycleChecker(Stringify *stringify, Object *o)
+ : m_callDepthRecorder(stringify->v4)
+ {
+ if (stringify->stackContains(o)) {
+ stringify->v4->throwTypeError(
+ QStringLiteral("Cannot convert circular structure to JSON"));
+ }
+
+ stringify->v4->checkStackLimits();
+ }
+
+ bool foundProblem() const { return m_callDepthRecorder.ee->hasException; }
+
+private:
+ ExecutionEngineCallDepthRecorder<1> m_callDepthRecorder;
+};
+
static QString quote(const QString &str)
{
QString product;
- const int length = str.length();
+ const int length = str.size();
product.reserve(length + 2);
product += u'"';
for (int i = 0; i < length; ++i) {
@@ -740,10 +762,9 @@ QString Stringify::makeMember(const QString &key, const Value &v)
QString Stringify::JO(Object *o)
{
- if (stackContains(o)) {
- v4->throwTypeError();
+ CallDepthAndCycleChecker check(this, o);
+ if (check.foundProblem())
return QString();
- }
Scope scope(v4);
@@ -800,10 +821,9 @@ QString Stringify::JO(Object *o)
QString Stringify::JA(Object *a)
{
- if (stackContains(a)) {
- v4->throwTypeError();
+ CallDepthAndCycleChecker check(this, a);
+ if (check.foundProblem())
return QString();
- }
Scope scope(a->engine());
@@ -865,7 +885,7 @@ ReturnedValue JsonObject::method_parse(const FunctionObject *b, const Value *, c
jtext = argv[0].toQString();
DEBUG << "parsing source = " << jtext;
- JsonParser parser(v4, jtext.constData(), jtext.length());
+ JsonParser parser(v4, jtext.constData(), jtext.size());
QJsonParseError error;
ReturnedValue result = parser.parse(&error);
if (error.error != QJsonParseError::NoError) {
@@ -885,9 +905,10 @@ ReturnedValue JsonObject::method_stringify(const FunctionObject *b, const Value
if (o) {
stringify.replacerFunction = o->as<FunctionObject>();
if (o->isArrayObject()) {
- uint arrayLen = o->getLength();
+ int arrayLen = scope.engine->safeForAllocLength(o->getLength());
+ CHECK_EXCEPTION();
stringify.propertyList = static_cast<QV4::String *>(scope.alloc(arrayLen));
- for (uint i = 0; i < arrayLen; ++i) {
+ for (int i = 0; i < arrayLen; ++i) {
Value *v = stringify.propertyList + i;
*v = o->get(i);
if (v->as<NumberObject>() || v->as<StringObject>() || v->isNumber())
@@ -895,7 +916,7 @@ ReturnedValue JsonObject::method_stringify(const FunctionObject *b, const Value
if (!v->isString()) {
v->setM(nullptr);
} else {
- for (uint j = 0; j <i; ++j) {
+ for (int j = 0; j <i; ++j) {
if (stringify.propertyList[j].m() == v->m()) {
v->setM(nullptr);
break;
diff --git a/src/qml/jsruntime/qv4mapiterator_p.h b/src/qml/jsruntime/qv4mapiterator_p.h
index 2269473d4c..97a72db85c 100644
--- a/src/qml/jsruntime/qv4mapiterator_p.h
+++ b/src/qml/jsruntime/qv4mapiterator_p.h
@@ -30,7 +30,7 @@ namespace Heap {
Member(class, NoMark, quint32, mapNextIndex)
DECLARE_HEAP_OBJECT(MapIteratorObject, Object) {
- DECLARE_MARKOBJECTS(MapIteratorObject);
+ DECLARE_MARKOBJECTS(MapIteratorObject)
void init(Object *obj, QV4::ExecutionEngine *engine)
{
Object::init();
diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h
index adcd1e8cf9..672b058fef 100644
--- a/src/qml/jsruntime/qv4memberdata_p.h
+++ b/src/qml/jsruntime/qv4memberdata_p.h
@@ -27,7 +27,7 @@ namespace Heap {
Member(class, ValueArray, ValueArray, values)
DECLARE_HEAP_OBJECT(MemberData, Base) {
- DECLARE_MARKOBJECTS(MemberData);
+ DECLARE_MARKOBJECTS(MemberData)
};
Q_STATIC_ASSERT(std::is_trivial_v<MemberData>);
diff --git a/src/qml/jsruntime/qv4module.cpp b/src/qml/jsruntime/qv4module.cpp
index 779eb77a36..1e1a059dfa 100644
--- a/src/qml/jsruntime/qv4module.cpp
+++ b/src/qml/jsruntime/qv4module.cpp
@@ -195,7 +195,7 @@ struct ModuleNamespaceIterator : ObjectOwnPropertyKeyIterator
PropertyKey ModuleNamespaceIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs)
{
const Module *module = static_cast<const Module *>(o);
- if (exportIndex < exportedNames.count()) {
+ if (exportIndex < exportedNames.size()) {
if (attrs)
*attrs = Attr_Data;
Scope scope(module->engine());
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index aec04b167d..6a39b9e27f 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -1104,7 +1104,7 @@ void Heap::ArrayObject::init(const QStringList &list)
// The result is a new Array object with length equal to the length
// of the QStringList, and the elements being the QStringList's
// elements converted to JS Strings.
- int len = list.count();
+ int len = list.size();
a->arrayReserve(len);
ScopedValue v(scope);
for (int ii = 0; ii < len; ++ii)
diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h
index e7b653b6f6..7e208bd4fd 100644
--- a/src/qml/jsruntime/qv4persistent_p.h
+++ b/src/qml/jsruntime/qv4persistent_p.h
@@ -69,7 +69,7 @@ public:
PersistentValue(PersistentValue &&other) noexcept : val(std::exchange(other.val, nullptr)) {}
void swap(PersistentValue &other) noexcept { qt_ptr_swap(val, other.val); }
- QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(PersistentValue);
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(PersistentValue)
~PersistentValue() { PersistentValueStorage::free(val); }
PersistentValue &operator=(const WeakValue &other);
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index 19da26989f..db33cd27f9 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -60,7 +60,7 @@ void Profiler::reportData()
FunctionLocationHash locations;
properties.reserve(m_data.size());
- for (const FunctionCall &call : qAsConst(m_data)) {
+ for (const FunctionCall &call : std::as_const(m_data)) {
properties.append(call.properties());
Function *function = call.function();
SentMarker &marker = m_sentLocations[reinterpret_cast<quintptr>(function)];
diff --git a/src/qml/jsruntime/qv4promiseobject_p.h b/src/qml/jsruntime/qv4promiseobject_p.h
index c0599987e5..1c11ebbfd6 100644
--- a/src/qml/jsruntime/qv4promiseobject_p.h
+++ b/src/qml/jsruntime/qv4promiseobject_p.h
@@ -34,7 +34,7 @@ class ReactionHandler : public QObject
public:
ReactionHandler(QObject *parent = nullptr);
- virtual ~ReactionHandler() override;
+ ~ReactionHandler() override;
void addReaction(ExecutionEngine *e, const Value *reaction, const Value *value);
void addResolveThenable(ExecutionEngine *e, const PromiseObject *promise, const Object *thenable, const FunctionObject *then);
diff --git a/src/qml/jsruntime/qv4propertykey.cpp b/src/qml/jsruntime/qv4propertykey.cpp
index 8a3e1adc65..e07df07543 100644
--- a/src/qml/jsruntime/qv4propertykey.cpp
+++ b/src/qml/jsruntime/qv4propertykey.cpp
@@ -66,7 +66,7 @@ QV4::Heap::String *QV4::PropertyKey::asFunctionName(ExecutionEngine *engine, Fun
QString str = s->toQString();
if (s->internalClass->vtable->isString)
n += s->toQString();
- else if (str.length() > 1)
+ else if (str.size() > 1)
n += QChar::fromLatin1('[') + QStringView{str}.mid(1) + QChar::fromLatin1(']');
}
return engine->newString(n);
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index a89e7f6f2f..bd4b5c2585 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -34,7 +34,7 @@ namespace Heap {
Member(class, Pointer, Module *, module)
DECLARE_HEAP_OBJECT(QQmlContextWrapper, Object) {
- DECLARE_MARKOBJECTS(QQmlContextWrapper);
+ DECLARE_MARKOBJECTS(QQmlContextWrapper)
void init(QQmlRefPointer<QQmlContextData> context, QObject *scopeObject);
void destroy();
@@ -47,7 +47,7 @@ DECLARE_HEAP_OBJECT(QQmlContextWrapper, Object) {
#define QmlContextMembers(class, Member)
DECLARE_HEAP_OBJECT(QmlContext, ExecutionContext) {
- DECLARE_MARKOBJECTS(QmlContext);
+ DECLARE_MARKOBJECTS(QmlContext)
QQmlContextWrapper *qml() { return static_cast<QQmlContextWrapper *>(activation.get()); }
void init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index d5e6c1b84a..b9b552576c 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -99,15 +99,10 @@ static ReturnedValue loadProperty(ExecutionEngine *v4, QObject *object,
if (property.isQObject()) {
QObject *rv = nullptr;
property.readProperty(object, &rv);
- ReturnedValue ret = QObjectWrapper::wrap(v4, rv);
- if (propMetaType.flags().testFlag(QMetaType::IsConst)) {
- ScopedValue v(scope, ret);
- if (auto obj = v->as<Object>()) {
- obj->setInternalClass(obj->internalClass()->cryopreserved());
- return obj->asReturnedValue();
- }
- }
- return ret;
+ if (propMetaType.flags().testFlag(QMetaType::IsConst))
+ return QObjectWrapper::wrapConst(v4, rv);
+ else
+ return QObjectWrapper::wrap(v4, rv);
}
if (property.isQList() && propMetaType.flags().testFlag(QMetaType::IsQmlList))
@@ -669,6 +664,29 @@ ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *ob
}
}
+ReturnedValue QObjectWrapper::wrapConst_slowPath(ExecutionEngine *engine, QObject *object)
+{
+ const QObject *constObject = object;
+
+ QQmlData *ddata = QQmlData::get(object, true);
+
+ Scope scope(engine);
+ ScopedObject constWrapper(scope);
+ if (engine->m_multiplyWrappedQObjects && ddata->hasConstWrapper)
+ constWrapper = engine->m_multiplyWrappedQObjects->value(constObject);
+
+ if (!constWrapper) {
+ constWrapper = create(engine, object);
+ constWrapper->setInternalClass(constWrapper->internalClass()->cryopreserved());
+ if (!engine->m_multiplyWrappedQObjects)
+ engine->m_multiplyWrappedQObjects = new MultiplyWrappedQObjectMap;
+ engine->m_multiplyWrappedQObjects->insert(constObject, constWrapper->d());
+ ddata->hasConstWrapper = true;
+ }
+
+ return constWrapper.asReturnedValue();
+}
+
void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack)
{
if (QQmlData::wasDeleted(object))
@@ -683,6 +701,8 @@ void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack)
ddata->jsWrapper.markOnce(markStack);
else if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
engine->m_multiplyWrappedQObjects->mark(object, markStack);
+ if (ddata->hasConstWrapper)
+ engine->m_multiplyWrappedQObjects->mark(static_cast<const QObject *>(object), markStack);
}
void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value)
@@ -710,14 +730,13 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, int p
bool QObjectWrapper::virtualIsEqualTo(Managed *a, Managed *b)
{
Q_ASSERT(a->as<QObjectWrapper>());
- QObjectWrapper *qobjectWrapper = static_cast<QObjectWrapper *>(a);
- Object *o = b->as<Object>();
- if (o) {
- if (QQmlTypeWrapper *qmlTypeWrapper = o->as<QQmlTypeWrapper>())
- return qmlTypeWrapper->toVariant().value<QObject*>() == qobjectWrapper->object();
- }
+ const QObjectWrapper *aobjectWrapper = static_cast<QObjectWrapper *>(a);
+ if (const QQmlTypeWrapper *qmlTypeWrapper = b->as<QQmlTypeWrapper>())
+ return qmlTypeWrapper->object() == aobjectWrapper->object();
- return false;
+ // We can have a const and a non-const wrapper for the same object.
+ const QObjectWrapper *bobjectWrapper = b->as<QObjectWrapper>();
+ return bobjectWrapper && aobjectWrapper->object() == bobjectWrapper->object();
}
ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object)
@@ -1176,7 +1195,7 @@ ReturnedValue QObjectWrapper::method_disconnect(const FunctionObject *b, const V
static void markChildQObjectsRecursively(QObject *parent, MarkStack *markStack)
{
const QObjectList &children = parent->children();
- for (int i = 0; i < children.count(); ++i) {
+ for (int i = 0; i < children.size(); ++i) {
QObject *child = children.at(i);
if (!child)
continue;
@@ -1350,8 +1369,8 @@ static ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index, QMe
}
}
}
- QVarLengthArray<void *, 9> argData(args.count());
- for (int ii = 0; ii < args.count(); ++ii)
+ QVarLengthArray<void *, 9> argData(args.size());
+ for (int ii = 0; ii < args.size(); ++ii)
argData[ii] = args[ii].dataPtr();
object.metacall(callType, index, argData.data());
@@ -1903,14 +1922,16 @@ bool CallArgument::fromValue(QMetaType metaType, ExecutionEngine *engine, const
// Convert via QVariant below.
// TODO: Can't we just do qobjectPtr = qmlTypeWrapper->object() instead?
break;
+ } else if (QObject *obj = qmlTypeWrapper->object()) {
+ // attached object case
+ qobjectPtr = obj;
+ return true;
}
// If this is a plain type wrapper without an instance,
- // then indeed it's an undefined parameter.
- // (although we might interpret that as const QMetaObject *).
- // TODO: But what if it's an attached object?
+ // then we got a namespace, and that's a type error
type = QMetaType::UnknownType;
- return true;
+ return false;
}
qobjectPtr = nullptr;
@@ -2025,7 +2046,7 @@ bool CallArgument::fromValue(QMetaType metaType, ExecutionEngine *engine, const
}
const QQmlMetaObject mo = QQmlMetaType::rawMetaObjectForType(metaType);
- if (!mo.isNull()) {
+ if (!mo.isNull() && v.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
QObject *obj = QQmlMetaType::toQObject(v);
if (obj != nullptr && !QQmlMetaObject::canConvert(obj, mo)) {
@@ -2095,11 +2116,11 @@ ReturnedValue CallArgument::toValue(ExecutionEngine *engine)
QList<QObject *> &list = *qlistPtr;
Scope scope(engine);
ScopedArrayObject array(scope, engine->newArrayObject());
- array->arrayReserve(list.count());
+ array->arrayReserve(list.size());
ScopedValue v(scope);
- for (int ii = 0; ii < list.count(); ++ii)
+ for (int ii = 0; ii < list.size(); ++ii)
array->arrayPut(ii, (v = QObjectWrapper::wrap(engine, list.at(ii))));
- array->setArrayLengthUnchecked(list.count());
+ array->setArrayLengthUnchecked(list.size());
return array.asReturnedValue();
}
@@ -2429,39 +2450,20 @@ void QmlSignalHandler::initProto(ExecutionEngine *engine)
engine->jsObjects[ExecutionEngine::SignalHandlerProto] = o->d();
}
-void MultiplyWrappedQObjectMap::insert(QObject *key, Heap::Object *value)
-{
- QHash<QObject*, WeakValue>::operator[](key).set(value->internalClass->engine, value);
- connect(key, SIGNAL(destroyed(QObject*)), this, SLOT(removeDestroyedObject(QObject*)));
-}
-
-
-MultiplyWrappedQObjectMap::Iterator MultiplyWrappedQObjectMap::erase(MultiplyWrappedQObjectMap::Iterator it)
+MultiplyWrappedQObjectMap::Iterator MultiplyWrappedQObjectMap::erase(
+ MultiplyWrappedQObjectMap::Iterator it)
{
- disconnect(it.key(), SIGNAL(destroyed(QObject*)), this, SLOT(removeDestroyedObject(QObject*)));
- return QHash<QObject*, WeakValue>::erase(it);
-}
-
-void MultiplyWrappedQObjectMap::remove(QObject *key)
-{
- Iterator it = find(key);
- if (it == end())
- return;
- erase(it);
-}
-
-void MultiplyWrappedQObjectMap::mark(QObject *key, MarkStack *markStack)
-{
- Iterator it = find(key);
- if (it == end())
- return;
- it->markOnce(markStack);
+ const QObjectBiPointer key = it.key();
+ const QObject *obj = key.isT1() ? key.asT1() : key.asT2();
+ disconnect(obj, &QObject::destroyed, this, &MultiplyWrappedQObjectMap::removeDestroyedObject);
+ return QHash<QObjectBiPointer, WeakValue>::erase(it);
}
void MultiplyWrappedQObjectMap::removeDestroyedObject(QObject *object)
{
- QHash<QObject*, WeakValue>::remove(object);
+ QHash<QObjectBiPointer, WeakValue>::remove(object);
+ QHash<QObjectBiPointer, WeakValue>::remove(static_cast<const QObject *>(object));
}
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 4477c3c836..5a0d837746 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -65,7 +65,7 @@ private:
Member(class, NoMark, int, index)
DECLARE_HEAP_OBJECT(QObjectMethod, FunctionObject) {
- DECLARE_MARKOBJECTS(QObjectMethod);
+ DECLARE_MARKOBJECTS(QObjectMethod)
QQmlPropertyData *methods;
int methodCount;
@@ -140,6 +140,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
QObject *object, String *name, RevisionMode revisionMode, const Value &value);
static ReturnedValue wrap(ExecutionEngine *engine, QObject *object);
+ static ReturnedValue wrapConst(ExecutionEngine *engine, QObject *object);
static void markWrapper(QObject *object, MarkStack *markStack);
using Object::get;
@@ -181,6 +182,7 @@ protected:
private:
Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object);
+ Q_NEVER_INLINE static ReturnedValue wrapConst_slowPath(ExecutionEngine *engine, QObject *object);
};
inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
@@ -197,6 +199,15 @@ inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *obje
return wrap_slowPath(engine, object);
}
+// Unfortunately we still need a non-const QObject* here because QQmlData needs to register itself in QObjectPrivate.
+inline ReturnedValue QObjectWrapper::wrapConst(ExecutionEngine *engine, QObject *object)
+{
+ if (Q_UNLIKELY(QQmlData::wasDeleted(object)))
+ return QV4::Encode::null();
+
+ return wrapConst_slowPath(engine, object);
+}
+
template <typename ReversalFunctor>
inline ReturnedValue QObjectWrapper::lookupGetterImpl(Lookup *lookup, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revertLookup)
{
@@ -292,23 +303,32 @@ struct Q_QML_EXPORT QmlSignalHandler : public QV4::Object
static void initProto(ExecutionEngine *v4);
};
+using QObjectBiPointer = QBiPointer<QObject, const QObject>;
+
class MultiplyWrappedQObjectMap : public QObject,
- private QHash<QObject*, QV4::WeakValue>
+ private QHash<QObjectBiPointer, QV4::WeakValue>
{
Q_OBJECT
public:
- typedef QHash<QObject*, QV4::WeakValue>::ConstIterator ConstIterator;
- typedef QHash<QObject*, QV4::WeakValue>::Iterator Iterator;
+ typedef QHash<QObjectBiPointer, QV4::WeakValue>::ConstIterator ConstIterator;
+ typedef QHash<QObjectBiPointer, QV4::WeakValue>::Iterator Iterator;
+
+ using value_type = QHash<QObjectBiPointer, QV4::WeakValue>::value_type;
- using value_type = QHash<QObject*, QV4::WeakValue>::value_type;
+ ConstIterator begin() const { return QHash<QObjectBiPointer, QV4::WeakValue>::constBegin(); }
+ Iterator begin() { return QHash<QObjectBiPointer, QV4::WeakValue>::begin(); }
+ ConstIterator end() const { return QHash<QObjectBiPointer, QV4::WeakValue>::constEnd(); }
+ Iterator end() { return QHash<QObjectBiPointer, QV4::WeakValue>::end(); }
- ConstIterator begin() const { return QHash<QObject*, QV4::WeakValue>::constBegin(); }
- Iterator begin() { return QHash<QObject*, QV4::WeakValue>::begin(); }
- ConstIterator end() const { return QHash<QObject*, QV4::WeakValue>::constEnd(); }
- Iterator end() { return QHash<QObject*, QV4::WeakValue>::end(); }
+ template<typename Pointer>
+ void insert(Pointer key, Heap::Object *value)
+ {
+ QHash<QObjectBiPointer, WeakValue>::operator[](key).set(value->internalClass->engine, value);
+ connect(key, SIGNAL(destroyed(QObject*)), this, SLOT(removeDestroyedObject(QObject*)));
+ }
- void insert(QObject *key, Heap::Object *value);
- ReturnedValue value(QObject *key) const
+ template<typename Pointer>
+ ReturnedValue value(Pointer key) const
{
ConstIterator it = find(key);
return it == end()
@@ -317,8 +337,24 @@ public:
}
Iterator erase(Iterator it);
- void remove(QObject *key);
- void mark(QObject *key, MarkStack *markStack);
+
+ template<typename Pointer>
+ void remove(Pointer key)
+ {
+ Iterator it = find(key);
+ if (it == end())
+ return;
+ erase(it);
+ }
+
+ template<typename Pointer>
+ void mark(Pointer key, MarkStack *markStack)
+ {
+ Iterator it = find(key);
+ if (it == end())
+ return;
+ it->markOnce(markStack);
+ }
private Q_SLOTS:
void removeDestroyedObject(QObject*);
diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp
index abcc60726a..179663a0e1 100644
--- a/src/qml/jsruntime/qv4reflect.cpp
+++ b/src/qml/jsruntime/qv4reflect.cpp
@@ -40,7 +40,10 @@ struct CallArgs {
static CallArgs createListFromArrayLike(Scope &scope, const Object *o)
{
- int len = o->getLength();
+ int len = scope.engine->safeForAllocLength(o->getLength());
+ if (scope.engine->hasException)
+ return {nullptr, 0};
+
Value *arguments = scope.alloc(len);
for (int i = 0; i < len; ++i) {
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index 0c039967ba..be7ff77603 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -49,7 +49,7 @@ uint RegExp::match(const QString &string, int start, uint *matchOffsets)
uint ret = JSC::Yarr::offsetNoMatch;
#if ENABLE(YARR_JIT_ALL_PARENS_EXPRESSIONS)
char buffer[8192];
- ret = uint(priv->jitCode->execute(s.characters16(), start, s.length(),
+ ret = uint(priv->jitCode->execute(s.characters16(), start, s.size(),
(int*)matchOffsets, buffer, 8192).start);
#else
ret = uint(priv->jitCode->execute(s.characters16(), start, s.length(),
@@ -74,18 +74,18 @@ uint RegExp::match(const QString &string, int start, uint *matchOffsets)
}
#endif // ENABLE(YARR_JIT)
- return JSC::Yarr::interpret(byteCode(), s.characters16(), string.length(), start, matchOffsets);
+ return JSC::Yarr::interpret(byteCode(), s.characters16(), string.size(), start, matchOffsets);
}
QString RegExp::getSubstitution(const QString &matched, const QString &str, int position, const Value *captures, int nCaptures, const QString &replacement)
{
QString result;
- int matchedLength = matched.length();
- Q_ASSERT(position >= 0 && position <= str.length());
+ int matchedLength = matched.size();
+ Q_ASSERT(position >= 0 && position <= str.size());
int tailPos = position + matchedLength;
int seenDollar = -1;
- for (int i = 0; i < replacement.length(); ++i) {
+ for (int i = 0; i < replacement.size(); ++i) {
QChar ch = replacement.at(i);
if (seenDollar >= 0) {
if (ch.unicode() == '$') {
@@ -98,7 +98,7 @@ QString RegExp::getSubstitution(const QString &matched, const QString &str, int
result += str.mid(tailPos);
} else if (ch.unicode() >= '0' && ch.unicode() <= '9') {
int n = ch.unicode() - '0';
- if (i + 1 < replacement.length()) {
+ if (i + 1 < replacement.size()) {
ch = replacement.at(i + 1);
if (ch.unicode() >= '0' && ch.unicode() <= '9') {
n = n*10 + (ch.unicode() - '0');
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 365593e207..0fab40a281 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -48,7 +48,7 @@ void Heap::RegExpObject::init(QV4::RegExp *value)
static QString minimalPattern(const QString &pattern)
{
QString ecmaPattern;
- int len = pattern.length();
+ int len = pattern.size();
ecmaPattern.reserve(len);
int i = 0;
const QChar *wc = pattern.unicode();
@@ -146,7 +146,7 @@ ReturnedValue RegExpObject::builtinExec(ExecutionEngine *engine, const String *s
Scope scope(engine);
int offset = (global() || sticky()) ? lastIndex() : 0;
- if (offset < 0 || offset > s.length()) {
+ if (offset < 0 || offset > s.size()) {
setLastIndex(0);
RETURN_RESULT(Encode::null());
}
@@ -170,7 +170,7 @@ ReturnedValue RegExpObject::builtinExec(ExecutionEngine *engine, const String *s
int len = value()->captureCount();
array->arrayReserve(len);
ScopedValue v(scope);
- int strlen = s.length();
+ int strlen = s.size();
for (int i = 0; i < len; ++i) {
int start = matchOffsets[i * 2];
int end = matchOffsets[i * 2 + 1];
@@ -232,7 +232,7 @@ uint parseFlags(Scope &scope, const QV4::Value *f)
if (scope.hasException())
return flags;
QString str = s->toQString();
- for (int i = 0; i < str.length(); ++i) {
+ for (int i = 0; i < str.size(); ++i) {
if (str.at(i) == QLatin1Char('g') && !(flags & CompiledData::RegExp::RegExp_Global)) {
flags |= CompiledData::RegExp::RegExp_Global;
} else if (str.at(i) == QLatin1Char('i') && !(flags & CompiledData::RegExp::RegExp_IgnoreCase)) {
@@ -382,7 +382,7 @@ ReturnedValue RegExpPrototype::execFirstMatch(const FunctionObject *b, const Val
QString s = str->toQString();
int offset = r->lastIndex();
- if (offset < 0 || offset > s.length()) {
+ if (offset < 0 || offset > s.size()) {
r->setLastIndex(0);
RETURN_RESULT(Encode::null());
}
@@ -518,7 +518,7 @@ ReturnedValue RegExpPrototype::method_get_ignoreCase(const FunctionObject *f, co
static int advanceStringIndex(int index, const QString &str, bool unicode)
{
if (unicode) {
- if (index < str.length() - 1 &&
+ if (index < str.size() - 1 &&
str.at(index).isHighSurrogate() &&
str.at(index + 1).isLowSurrogate())
++index;
@@ -607,7 +607,7 @@ ReturnedValue RegExpPrototype::method_replace(const FunctionObject *f, const Val
if (scope.hasException())
return Encode::undefined();
- int lengthS = s->toQString().length();
+ int lengthS = s->toQString().size();
ScopedString replaceValue(scope);
ScopedFunctionObject replaceFunction(scope, (argc > 1 ? argv[1] : Value::undefinedValue()));
@@ -659,7 +659,7 @@ ReturnedValue RegExpPrototype::method_replace(const FunctionObject *f, const Val
if (scope.hasException())
return Encode::undefined();
QString m = matchString->toQString();
- int matchLength = m.length();
+ int matchLength = m.size();
v = resultObject->get(scope.engine->id_index());
int position = v->toInt32();
position = qMax(qMin(position, lengthS), 0);
@@ -786,7 +786,7 @@ ReturnedValue RegExpPrototype::method_split(const FunctionObject *f, const Value
return A->asReturnedValue();
QString S = s->toQString();
- int size = S.length();
+ int size = S.size();
if (size == 0) {
ScopedValue z(scope, exec(scope.engine, splitter, s));
if (z->isNull())
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 2f278f70a7..3171367351 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -56,7 +56,7 @@ DECLARE_HEAP_OBJECT(RegExpObject, Object) {
Member(class, NoMark, int, lastMatchEnd)
DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) {
- DECLARE_MARKOBJECTS(RegExpCtor);
+ DECLARE_MARKOBJECTS(RegExpCtor)
void init(QV4::ExecutionContext *scope);
void clearLastMatch();
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index bd81c56bbd..f07f7e38a1 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -144,7 +144,7 @@ struct RuntimeCounters::Data {
}
std::sort(lines.begin(), lines.end(), Line::less);
outs << lines.size() << " counters:" << endl;
- for (const Line &line : qAsConst(lines))
+ for (const Line &line : std::as_const(lines))
outs << qSetFieldWidth(10) << line.count << qSetFieldWidth(0)
<< " | " << line.func
<< " | " << pretty(line.tag1)
@@ -217,7 +217,7 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
*result = qdtoa(num, &decpt, &sign);
if (decpt <= ecma_shortest_low || decpt > ecma_shortest_high) {
- if (result->length() > 1)
+ if (result->size() > 1)
result->insert(1, dot);
result->append(QLatin1Char('e'));
if (decpt > 0)
@@ -225,10 +225,10 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
result->append(QString::number(decpt - 1));
} else if (decpt <= 0) {
result->prepend(QLatin1String("0.") + QString(-decpt, zero));
- } else if (decpt < result->length()) {
+ } else if (decpt < result->size()) {
result->insert(decpt, dot);
} else {
- result->append(QString(decpt - result->length(), zero));
+ result->append(QString(decpt - result->size(), zero));
}
if (sign && num)
@@ -392,7 +392,7 @@ double RuntimeHelpers::stringToNumber(const QString &string)
// libdoubleconversion sources. The same maximum value would be represented by roughly 3.5 times
// as many binary digits.
const int excessiveLength = 16 * 1024;
- if (string.length() > excessiveLength)
+ if (string.size() > excessiveLength)
return qQNaN();
const QStringView s = QStringView(string).trimmed();
@@ -642,7 +642,7 @@ static Q_NEVER_INLINE ReturnedValue getElementIntFallback(ExecutionEngine *engin
ScopedObject o(scope, object);
if (!o) {
if (const String *str = object.as<String>()) {
- if (idx >= (uint)str->toQString().length()) {
+ if (idx >= (uint)str->toQString().size()) {
return Encode::undefined();
}
const QString s = str->toQString().mid(idx, 1);
@@ -1561,6 +1561,11 @@ static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc)
if (done->booleanValue())
break;
++argCount;
+ constexpr auto safetyMargin = 100; // leave some space on the stack for actual work with the elements
+ if (qint64(scope.engine->jsStackLimit - scope.engine->jsStackTop) < safetyMargin) {
+ scope.engine->throwRangeError(QLatin1String("Too many elements in array to use it with the spread operator"));
+ return { nullptr, 0 };
+ }
v = scope.alloc<Scope::Uninitialized>();
}
}
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index 09e8b60c91..eee7fd8414 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -88,6 +88,10 @@ struct Scope {
/* Be careful when using Uninitialized, the stack has to be fully initialized before calling into the memory manager again */
Uninitialized
};
+
+ template <AllocMode mode = Undefined>
+ Value *alloc(qint64 nValues) const = delete; // use safeForAllocLength
+
template <AllocMode mode = Undefined>
QML_NEARLY_ALWAYS_INLINE Value *alloc(int nValues) const
{
@@ -408,7 +412,7 @@ struct ScopedProperty
{
ScopedProperty(Scope &scope)
{
- property = reinterpret_cast<Property*>(scope.alloc(sizeof(Property) / sizeof(Value)));
+ property = reinterpret_cast<Property*>(scope.alloc(int(sizeof(Property) / sizeof(Value))));
}
Property *operator->() { return property; }
diff --git a/src/qml/jsruntime/qv4setiterator_p.h b/src/qml/jsruntime/qv4setiterator_p.h
index e7ab85accb..37f912e01a 100644
--- a/src/qml/jsruntime/qv4setiterator_p.h
+++ b/src/qml/jsruntime/qv4setiterator_p.h
@@ -30,7 +30,7 @@ namespace Heap {
Member(class, NoMark, quint32, setNextIndex)
DECLARE_HEAP_OBJECT(SetIteratorObject, Object) {
- DECLARE_MARKOBJECTS(SetIteratorObject);
+ DECLARE_MARKOBJECTS(SetIteratorObject)
void init(Object *obj, QV4::ExecutionEngine *engine)
{
Object::init();
diff --git a/src/qml/jsruntime/qv4stringiterator.cpp b/src/qml/jsruntime/qv4stringiterator.cpp
index 99f10c55b4..9cb2711efb 100644
--- a/src/qml/jsruntime/qv4stringiterator.cpp
+++ b/src/qml/jsruntime/qv4stringiterator.cpp
@@ -35,7 +35,7 @@ ReturnedValue StringIteratorPrototype::method_next(const FunctionObject *b, cons
quint32 index = thisObject->d()->nextIndex;
QString str = s->toQString();
- quint32 len = str.length();
+ quint32 len = str.size();
if (index >= len) {
thisObject->d()->iteratedString.set(scope.engine, nullptr);
diff --git a/src/qml/jsruntime/qv4stringiterator_p.h b/src/qml/jsruntime/qv4stringiterator_p.h
index a445381ba6..742b8a895d 100644
--- a/src/qml/jsruntime/qv4stringiterator_p.h
+++ b/src/qml/jsruntime/qv4stringiterator_p.h
@@ -30,7 +30,7 @@ namespace Heap {
Member(class, NoMark, quint32, nextIndex)
DECLARE_HEAP_OBJECT(StringIteratorObject, Object) {
- DECLARE_MARKOBJECTS(StringIteratorObject);
+ DECLARE_MARKOBJECTS(StringIteratorObject)
void init(String *str, QV4::ExecutionEngine *engine)
{
Object::init();
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 5e1d764aed..bec4132b5f 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -51,7 +51,7 @@ void Heap::StringObject::init(const QV4::String *str)
Heap::String *Heap::StringObject::getIndex(uint index) const
{
QString str = string->toQString();
- if (index >= (uint)str.length())
+ if (index >= (uint)str.size())
return nullptr;
return internalClass->engine->newString(str.mid(index, 1));
}
@@ -67,7 +67,7 @@ bool StringObject::virtualDeleteProperty(Managed *m, PropertyKey id)
if (id.isArrayIndex()) {
StringObject *o = static_cast<StringObject *>(m);
uint index = id.asArrayIndex();
- if (index < static_cast<uint>(o->d()->string->toQString().length()))
+ if (index < static_cast<uint>(o->d()->string->toQString().size()))
return false;
}
return Object::virtualDeleteProperty(m, id);
@@ -83,7 +83,7 @@ struct StringObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
PropertyKey StringObjectOwnPropertyKeyIterator::next(const QV4::Object *o, Property *pd, PropertyAttributes *attrs)
{
const StringObject *s = static_cast<const StringObject *>(o);
- uint slen = s->d()->string->toQString().length();
+ uint slen = s->d()->string->toQString().size();
if (arrayIndex < slen) {
uint index = arrayIndex;
++arrayIndex;
@@ -119,7 +119,7 @@ PropertyAttributes StringObject::virtualGetOwnProperty(const Managed *m, Propert
if (id.isArrayIndex()) {
const uint index = id.asArrayIndex();
const auto s = static_cast<const StringObject *>(m);
- if (index < uint(s->d()->string->toQString().length())) {
+ if (index < uint(s->d()->string->toQString().size())) {
if (p)
p->value = s->getIndex(index);
return Attr_NotConfigurable|Attr_NotWritable;
@@ -338,7 +338,7 @@ ReturnedValue StringPrototype::method_charAt(const FunctionObject *b, const Valu
pos = (int) argv[0].toInteger();
QString result;
- if (pos >= 0 && pos < str.length())
+ if (pos >= 0 && pos < str.size())
result += str.at(pos);
return Encode(v4->newString(result));
@@ -356,7 +356,7 @@ ReturnedValue StringPrototype::method_charCodeAt(const FunctionObject *b, const
pos = (int) argv[0].toInteger();
- if (pos >= 0 && pos < str.length())
+ if (pos >= 0 && pos < str.size())
RETURN_RESULT(Encode(str.at(pos).unicode()));
return Encode(qt_qnan());
@@ -419,11 +419,11 @@ ReturnedValue StringPrototype::method_endsWith(const FunctionObject *b, const Va
if (v4->hasException)
return Encode::undefined();
- int pos = value.length();
+ int pos = value.size();
if (argc > 1)
pos = (int) argv[1].toInteger();
- if (pos == value.length())
+ if (pos == value.size())
RETURN_RESULT(Encode(value.endsWith(searchString)));
QStringView stringToSearch = QStringView{value}.left(pos);
@@ -447,7 +447,7 @@ ReturnedValue StringPrototype::method_indexOf(const FunctionObject *b, const Val
int index = -1;
if (! value.isEmpty())
- index = value.indexOf(searchString, qMin(qMax(pos, 0), value.length()));
+ index = value.indexOf(searchString, qMin(qMax(pos, 0), value.size()));
return Encode(index);
}
@@ -470,7 +470,7 @@ ReturnedValue StringPrototype::method_includes(const FunctionObject *b, const Va
const Value &posArg = argv[1];
pos = (int) posArg.toInteger();
if (!posArg.isInteger() && posArg.isNumber() && qIsInf(posArg.toNumber()))
- pos = value.length();
+ pos = value.size();
}
if (pos == 0)
@@ -497,8 +497,8 @@ ReturnedValue StringPrototype::method_lastIndexOf(const FunctionObject *b, const
else
position = std::trunc(position);
- int pos = std::trunc(qMin(qMax(position, 0.0), double(value.length())));
- if (!searchString.isEmpty() && pos == value.length())
+ int pos = std::trunc(qMin(qMax(position, 0.0), double(value.size())));
+ if (!searchString.isEmpty() && pos == value.size())
--pos;
if (searchString.isNull() && pos == 0)
RETURN_RESULT(Encode(-1));
@@ -607,12 +607,12 @@ ReturnedValue StringPrototype::method_padEnd(const FunctionObject *f, const Valu
return s->asReturnedValue();
QString padded = s->toQString();
- int oldLength = padded.length();
+ int oldLength = padded.size();
int toFill = maxLen - oldLength;
padded.resize(maxLen);
QChar *ch = padded.data() + oldLength;
while (toFill) {
- int copy = qMin(fillString.length(), toFill);
+ int copy = qMin(fillString.size(), toFill);
memcpy(ch, fillString.constData(), copy*sizeof(QChar));
toFill -= copy;
ch += copy;
@@ -646,13 +646,13 @@ ReturnedValue StringPrototype::method_padStart(const FunctionObject *f, const Va
return s->asReturnedValue();
QString original = s->toQString();
- int oldLength = original.length();
+ int oldLength = original.size();
int toFill = maxLen - oldLength;
QString padded;
padded.resize(maxLen);
QChar *ch = padded.data();
while (toFill) {
- int copy = qMin(fillString.length(), toFill);
+ int copy = qMin(fillString.size(), toFill);
memcpy(ch, fillString.constData(), copy*sizeof(QChar));
toFill -= copy;
ch += copy;
@@ -682,9 +682,9 @@ ReturnedValue StringPrototype::method_repeat(const FunctionObject *b, const Valu
static void appendReplacementString(QString *result, const QString &input, const QString& replaceValue, uint* matchOffsets, int captureCount)
{
- result->reserve(result->length() + replaceValue.length());
- for (int i = 0; i < replaceValue.length(); ++i) {
- if (replaceValue.at(i) == QLatin1Char('$') && i < replaceValue.length() - 1) {
+ result->reserve(result->size() + replaceValue.size());
+ for (int i = 0; i < replaceValue.size(); ++i) {
+ if (replaceValue.at(i) == QLatin1Char('$') && i < replaceValue.size() - 1) {
ushort ch = replaceValue.at(i + 1).unicode();
uint substStart = JSC::Yarr::offsetNoMatch;
uint substEnd = JSC::Yarr::offsetNoMatch;
@@ -703,12 +703,12 @@ static void appendReplacementString(QString *result, const QString &input, const
skip = 1;
} else if (ch == '\'') {
substStart = matchOffsets[1];
- substEnd = input.length();
+ substEnd = input.size();
skip = 1;
} else if (ch >= '0' && ch <= '9') {
uint capture = ch - '0';
skip = 1;
- if (i < replaceValue.length() - 2) {
+ if (i < replaceValue.size() - 2) {
ch = replaceValue.at(i + 2).unicode();
if (ch >= '0' && ch <= '9') {
uint c = capture*10 + ch - '0';
@@ -793,7 +793,7 @@ ReturnedValue StringPrototype::method_replace(const FunctionObject *b, const Val
if (idx != -1) {
numStringMatches = 1;
matchOffsets[0] = idx;
- matchOffsets[1] = idx + searchString.length();
+ matchOffsets[1] = idx + searchString.size();
}
}
@@ -802,7 +802,7 @@ ReturnedValue StringPrototype::method_replace(const FunctionObject *b, const Val
ScopedValue replaceValue(scope, argc > 1 ? argv[1] : Value::undefinedValue());
ScopedFunctionObject searchCallback(scope, replaceValue);
if (!!searchCallback) {
- result.reserve(string.length() + 10*numStringMatches);
+ result.reserve(string.size() + 10*numStringMatches);
ScopedValue entry(scope);
Value *arguments = scope.alloc(numCaptures + 2);
int lastEnd = 0;
@@ -832,7 +832,7 @@ ReturnedValue StringPrototype::method_replace(const FunctionObject *b, const Val
result += QStringView{string}.mid(lastEnd);
} else {
QString newString = replaceValue->toQString();
- result.reserve(string.length() + numStringMatches*newString.size());
+ result.reserve(string.size() + numStringMatches*newString.size());
int lastEnd = 0;
for (int i = 0; i < numStringMatches; ++i) {
@@ -975,7 +975,7 @@ ReturnedValue StringPrototype::method_split(const FunctionObject *b, const Value
} else {
QString separator = separatorValue->toQString();
if (separator.isEmpty()) {
- for (uint i = 0; i < qMin(limit, uint(text.length())); ++i)
+ for (uint i = 0; i < qMin(limit, uint(text.size())); ++i)
array->push_back((s = scope.engine->newString(text.mid(i, 1))));
return array.asReturnedValue();
}
@@ -1033,7 +1033,7 @@ ReturnedValue StringPrototype::method_substr(const FunctionObject *b, const Valu
if (argc > 1)
length = argv[1].toInteger();
- double count = value.length();
+ double count = value.size();
if (start < 0)
start = qMax(count + start, 0.0);
@@ -1051,7 +1051,7 @@ ReturnedValue StringPrototype::method_substring(const FunctionObject *b, const V
if (v4->hasException)
return QV4::Encode::undefined();
- int length = value.length();
+ int length = value.size();
double start = 0;
double end = length;
@@ -1124,11 +1124,11 @@ ReturnedValue StringPrototype::method_trim(const FunctionObject *b, const Value
const QChar *chars = s.constData();
int start, end;
- for (start = 0; start < s.length(); ++start) {
+ for (start = 0; start < s.size(); ++start) {
if (!chars[start].isSpace() && chars[start].unicode() != 0xfeff)
break;
}
- for (end = s.length() - 1; end >= start; --end) {
+ for (end = s.size() - 1; end >= start; --end) {
if (!chars[end].isSpace() && chars[end].unicode() != 0xfeff)
break;
}
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index e0c0e37815..451a989ef4 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -28,7 +28,7 @@ namespace Heap {
Member(class, Pointer, String *, string)
DECLARE_HEAP_OBJECT(StringObject, Object) {
- DECLARE_MARKOBJECTS(StringObject);
+ DECLARE_MARKOBJECTS(StringObject)
enum {
LengthPropertyIndex = 0
diff --git a/src/qml/jsruntime/qv4symbol_p.h b/src/qml/jsruntime/qv4symbol_p.h
index b85ddb3b36..e56510bd69 100644
--- a/src/qml/jsruntime/qv4symbol_p.h
+++ b/src/qml/jsruntime/qv4symbol_p.h
@@ -36,7 +36,7 @@ struct Symbol : StringOrSymbol {
Member(class, Pointer, Symbol *, symbol)
DECLARE_HEAP_OBJECT(SymbolObject, Object) {
- DECLARE_MARKOBJECTS(SymbolObject);
+ DECLARE_MARKOBJECTS(SymbolObject)
void init(const QV4::Symbol *s);
};
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index d7e9d7466c..0284dceb7b 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -80,7 +80,7 @@ namespace Heap {
Member(class, NoMark, uint, arrayType)
DECLARE_HEAP_OBJECT(TypedArray, Object) {
- DECLARE_MARKOBJECTS(TypedArray);
+ DECLARE_MARKOBJECTS(TypedArray)
using Type = TypedArrayType;
void init(Type t);
diff --git a/src/qml/jsruntime/qv4urlobject.cpp b/src/qml/jsruntime/qv4urlobject.cpp
index bc59b7a839..7f4a078d13 100644
--- a/src/qml/jsruntime/qv4urlobject.cpp
+++ b/src/qml/jsruntime/qv4urlobject.cpp
@@ -131,7 +131,7 @@ void UrlObject::setUrl(const QUrl &url)
d()->port.set(engine(),
engine()->newString(url.port() == -1 ? QLatin1String("")
: QString::number(url.port())));
- d()->protocol.set(engine(), engine()->newString(url.scheme()));
+ d()->protocol.set(engine(), engine()->newString(url.scheme() + QLatin1Char(':')));
d()->search.set(engine(), engine()->newString(url.query()));
d()->username.set(engine(), engine()->newString(url.userName()));
@@ -186,15 +186,23 @@ bool UrlObject::setPort(QString port)
return true;
}
-bool UrlObject::setProtocol(QString protocol)
+bool UrlObject::setProtocol(QString protocolOrScheme)
{
QUrl url = toQUrl();
- url.setScheme(protocol);
+ // If there is one or several ':' in the protocolOrScheme,
+ // everything from the first colon is removed.
+
+ qsizetype firstColonPos = protocolOrScheme.indexOf(QLatin1Char(':'));
+
+ if (firstColonPos != -1)
+ protocolOrScheme.truncate(firstColonPos);
+
+ url.setScheme(protocolOrScheme);
if (!url.isValid())
return false;
- d()->protocol.set(engine(), engine()->newString(url.scheme()));
+ d()->protocol.set(engine(), engine()->newString(url.scheme() + QLatin1Char(':')));
d()->href.set(engine(), engine()->newString(url.toString()));
updateOrigin();
diff --git a/src/qml/jsruntime/qv4urlobject_p.h b/src/qml/jsruntime/qv4urlobject_p.h
index 3b210547b3..e4a3ba073b 100644
--- a/src/qml/jsruntime/qv4urlobject_p.h
+++ b/src/qml/jsruntime/qv4urlobject_p.h
@@ -41,7 +41,7 @@ namespace Heap {
DECLARE_HEAP_OBJECT(UrlObject, Object)
{
- DECLARE_MARKOBJECTS(UrlObject);
+ DECLARE_MARKOBJECTS(UrlObject)
void init() { Object::init(); }
};
@@ -59,7 +59,7 @@ struct UrlCtor : FunctionObject
DECLARE_HEAP_OBJECT(UrlSearchParamsObject, Object)
{
- DECLARE_MARKOBJECTS(UrlSearchParamsObject);
+ DECLARE_MARKOBJECTS(UrlSearchParamsObject)
void init() { Object::init(); }
};