aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2019-05-20 15:24:51 +0200
committerUlf Hermann <ulf.hermann@qt.io>2019-05-31 15:03:33 +0200
commitc8c2db3f5b157131542025ce556d248c7a916a00 (patch)
tree4c91465c8935b880c6dd42cb427fa3b173d52157
parent0f035c0ad79ca41a1473b64a4c0077e7085d3700 (diff)
Split QV4::Value into a static and a dynamic part
The static part can be used for compilation and won't resolve managed objects. This allows us to remove all the remaining V4_BOOTSTRAP. Change-Id: Id2f6feb64c48beb2a407697881aea8c0d791a532 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp2
-rw-r--r--src/qml/compiler/qv4codegen.cpp57
-rw-r--r--src/qml/compiler/qv4codegen_p.h3
-rw-r--r--src/qml/compiler/qv4compileddata.cpp8
-rw-r--r--src/qml/compiler/qv4compileddata_p.h7
-rw-r--r--src/qml/compiler/qv4compiler.cpp2
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp2
-rw-r--r--src/qml/compiler/qv4executablecompilationunit.cpp10
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp8
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h2
-rw-r--r--src/qml/jit/qv4baselinejit.cpp2
-rw-r--r--src/qml/jsruntime/jsruntime.pri16
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp3
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4calldata_p.h44
-rw-r--r--src/qml/jsruntime/qv4context.cpp6
-rw-r--r--src/qml/jsruntime/qv4global_p.h4
-rw-r--r--src/qml/jsruntime/qv4math_p.h13
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp15
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp89
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h2
-rw-r--r--src/qml/jsruntime/qv4staticvalue_p.h548
-rw-r--r--src/qml/jsruntime/qv4value.cpp23
-rw-r--r--src/qml/jsruntime/qv4value_p.h582
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp4
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp5
-rw-r--r--tools/qmlimportscanner/main.cpp2
-rw-r--r--tools/qmllint/main.cpp2
28 files changed, 824 insertions, 639 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 6f46648572..3e5798ba8b 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -39,7 +39,7 @@
#include "qqmlirbuilder_p.h"
-#include <private/qv4value_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qv4compileddata_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljslexer_p.h>
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index b145ceb51e..b7e3e20fd0 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -48,7 +48,7 @@
#include <private/qqmljslexer_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qv4stringtoarrayindex_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qv4compilercontext_p.h>
#include <private/qv4compilercontrolflow_p.h>
#include <private/qv4bytecodegenerator_p.h>
@@ -267,13 +267,26 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
return exprResult();
if (expr.isConstant()) {
- auto v = Value::fromReturnedValue(expr.constant);
+ auto v = StaticValue::fromReturnedValue(expr.constant);
if (v.isNumber()) {
switch (op) {
case Not:
return Reference::fromConst(this, Encode(!v.toBoolean()));
case UMinus:
- return Reference::fromConst(this, Runtime::UMinus::call(v));
+ // This duplicates some of the logic from Runtime::UMinus::call()
+ ReturnedValue r;
+ if (v.isInteger()) {
+ int intVal = v.integerValue();
+ if (intVal && intVal != std::numeric_limits<int>::min())
+ r = QV4::Encode(-intVal);
+ else
+ r = QV4::Encode(-double(intVal));
+ } else if (v.isDouble()) {
+ r = QV4::Encode(-v.doubleValue());
+ } else {
+ r = QV4::Encode(-v.int_32());
+ }
+ return Reference::fromConst(this, r);
case UPlus:
return expr;
case Compl:
@@ -1006,7 +1019,7 @@ bool Codegen::visit(ClassExpression *ast)
return false;
r.storeOnStack(heritage.stackSlot());
} else {
- Reference::fromConst(this, Value::emptyValue().asReturnedValue()).loadInAccumulator();
+ Reference::fromConst(this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
heritage.storeConsumeAccumulator();
}
@@ -1083,7 +1096,7 @@ bool Codegen::visit(ArrayPattern *ast)
if (args == -1)
args = temp;
if (!arg) {
- auto c = Reference::fromConst(this, Value::emptyValue().asReturnedValue());
+ auto c = Reference::fromConst(this, StaticValue::emptyValue().asReturnedValue());
(void) c.storeOnStack(temp);
} else {
RegisterScope scope(this);
@@ -1144,7 +1157,8 @@ bool Codegen::visit(ArrayPattern *ast)
while (it) {
for (Elision *elision = it->elision; elision; elision = elision->next) {
- Reference::fromConst(this, Value::emptyValue().asReturnedValue()).loadInAccumulator();
+ Reference::fromConst(
+ this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
pushAccumulator();
}
@@ -1538,9 +1552,9 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
}
case QSOperator::BitAnd:
if (right.isConstant()) {
- int rightAsInt = Value::fromReturnedValue(right.constant).toInt32();
+ int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
if (left.isConstant()) {
- int result = Value::fromReturnedValue(left.constant).toInt32() & rightAsInt;
+ int result = StaticValue::fromReturnedValue(left.constant).toInt32() & rightAsInt;
return Reference::fromConst(this, Encode(result));
}
left.loadInAccumulator();
@@ -1556,9 +1570,9 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
break;
case QSOperator::BitOr:
if (right.isConstant()) {
- int rightAsInt = Value::fromReturnedValue(right.constant).toInt32();
+ int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
if (left.isConstant()) {
- int result = Value::fromReturnedValue(left.constant).toInt32() | rightAsInt;
+ int result = StaticValue::fromReturnedValue(left.constant).toInt32() | rightAsInt;
return Reference::fromConst(this, Encode(result));
}
left.loadInAccumulator();
@@ -1574,9 +1588,9 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
break;
case QSOperator::BitXor:
if (right.isConstant()) {
- int rightAsInt = Value::fromReturnedValue(right.constant).toInt32();
+ int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
if (left.isConstant()) {
- int result = Value::fromReturnedValue(left.constant).toInt32() ^ rightAsInt;
+ int result = StaticValue::fromReturnedValue(left.constant).toInt32() ^ rightAsInt;
return Reference::fromConst(this, Encode(result));
}
left.loadInAccumulator();
@@ -1594,7 +1608,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
if (right.isConstant()) {
left.loadInAccumulator();
Instruction::UShrConst ushr;
- ushr.rhs = Value::fromReturnedValue(right.constant).toInt32() & 0x1f;
+ ushr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
bytecodeGenerator->addInstruction(ushr);
} else {
right.loadInAccumulator();
@@ -1607,7 +1621,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
if (right.isConstant()) {
left.loadInAccumulator();
Instruction::ShrConst shr;
- shr.rhs = Value::fromReturnedValue(right.constant).toInt32() & 0x1f;
+ shr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
bytecodeGenerator->addInstruction(shr);
} else {
right.loadInAccumulator();
@@ -1620,7 +1634,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
if (right.isConstant()) {
left.loadInAccumulator();
Instruction::ShlConst shl;
- shl.rhs = Value::fromReturnedValue(right.constant).toInt32() & 0x1f;
+ shl.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
bytecodeGenerator->addInstruction(shl);
} else {
right.loadInAccumulator();
@@ -1748,7 +1762,7 @@ Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Refe
qSwap(left, right); // null==a -> a==null
if (right.isConstant()) {
- Value c = Value::fromReturnedValue(right.constant);
+ StaticValue c = StaticValue::fromReturnedValue(right.constant);
if (c.isNull() || c.isUndefined()) {
left.loadInAccumulator();
if (oper == QSOperator::Equal) {
@@ -2022,7 +2036,9 @@ Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
argc = 0;
for (ArgumentList *it = args; it; it = it->next) {
if (it->isSpreadElement) {
- Reference::fromConst(this, Value::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
+ Reference::fromConst(
+ this,
+ StaticValue::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
++argc;
}
RegisterScope scope(this);
@@ -2999,7 +3015,8 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
functionEndsWithReturn = endsWithReturn(_module, body);
// reserve the js stack frame (Context & js Function & accumulator)
- bytecodeGenerator->newRegisterArray(sizeof(CallData)/sizeof(Value) - 1 + _context->arguments.size());
+ bytecodeGenerator->newRegisterArray(
+ sizeof(CallData) / sizeof(StaticValue) - 1 + _context->arguments.size());
bool _inFormalParameterList = false;
qSwap(_inFormalParameterList, inFormalParameterList);
@@ -4314,7 +4331,7 @@ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // the loads below are empty str
Instruction::LoadUndefined load;
codegen->bytecodeGenerator->addInstruction(load);
} else {
- Value p = Value::fromReturnedValue(constant);
+ StaticValue p = StaticValue::fromReturnedValue(constant);
if (p.isNumber()) {
double d = p.asDouble();
int i = static_cast<int>(d);
@@ -4325,7 +4342,7 @@ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // the loads below are empty str
return;
}
Instruction::LoadInt load;
- load.value = Value::fromReturnedValue(constant).toInt32();
+ load.value = StaticValue::fromReturnedValue(constant).toInt32();
codegen->bytecodeGenerator->addInstruction(load);
return;
}
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index e519da0142..6d5f8c0951 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -258,7 +258,8 @@ public:
}
static Reference fromArgument(Codegen *cg, int index, bool isVolatile) {
Reference r(cg, StackSlot);
- r.theStackSlot = Moth::StackSlot::createRegister(index + sizeof(CallData)/sizeof(Value) - 1);
+ r.theStackSlot = Moth::StackSlot::createRegister(
+ index + sizeof(CallData) / sizeof(StaticValue) - 1);
r.stackSlotIsLocalOrArgument = true;
r.isVolatile = isVolatile;
return r;
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 0fed0a03b2..813868b0ae 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qv4compileddata_p.h"
-#include <private/qv4value_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qqmlirbuilder_p.h>
#include <QCoreApplication>
#include <QCryptographicHash>
@@ -144,13 +144,13 @@ void CompilationUnit::setUnitData(const Unit *unitData, const QmlUnit *qmlUnit,
qmlData = qmlUnit ? qmlUnit : data->qmlUnit();
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- Value *bigEndianConstants = new Value[data->constantTableSize];
+ StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize];
const quint64_le *littleEndianConstants = data->constants();
for (uint i = 0; i < data->constantTableSize; ++i)
- bigEndianConstants[i] = Value::fromReturnedValue(littleEndianConstants[i]);
+ bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]);
constants = bigEndianConstants;
#else
- constants = reinterpret_cast<const Value*>(data->constants());
+ constants = reinterpret_cast<const StaticValue*>(data->constants());
#endif
m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex);
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 94b64694ae..63738d6002 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -88,6 +88,7 @@ struct Document;
}
namespace QV4 {
+struct StaticValue;
namespace Heap {
struct Module;
@@ -1070,10 +1071,10 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnitBase
// pointers either to data->constants() or little-endian memory copy.
QV4::Heap::String **runtimeStrings = nullptr; // Array
- const Value* constants = nullptr;
- QV4::Value *runtimeRegularExpressions = nullptr;
+ const StaticValue* constants = nullptr;
+ QV4::StaticValue *runtimeRegularExpressions = nullptr;
QV4::Heap::InternalClass **runtimeClasses = nullptr;
- const Value** imports = nullptr;
+ const StaticValue** imports = nullptr;
};
Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 4a54e5a44b..8722263b04 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -40,7 +40,7 @@
#include <qv4compiler_p.h>
#include <qv4compileddata_p.h>
#include <qv4codegen_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qv4alloca_p.h>
#include <private/qqmljslexer_p.h>
#include <private/qqmljsast_p.h>
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index d1a5fee92b..88837b0feb 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -156,7 +156,7 @@ Context::ResolvedName Context::resolveName(const QString &name, const QQmlJS::AS
result.isConst = false;
return result;
} else {
- result.index = argIdx + sizeof(CallData)/sizeof(Value) - 1;
+ result.index = argIdx + sizeof(CallData) / sizeof(StaticValue) - 1;
result.scope = 0;
result.type = ResolvedName::Stack;
result.isConst = false;
diff --git a/src/qml/compiler/qv4executablecompilationunit.cpp b/src/qml/compiler/qv4executablecompilationunit.cpp
index 97c828d4d8..c68f6a7cbf 100644
--- a/src/qml/compiler/qv4executablecompilationunit.cpp
+++ b/src/qml/compiler/qv4executablecompilationunit.cpp
@@ -102,7 +102,7 @@ static QString toString(QV4::ReturnedValue v)
return result;
}
-static void dumpConstantTable(const Value *constants, uint count)
+static void dumpConstantTable(const StaticValue *constants, uint count)
{
QDebug d = qDebug();
d.nospace() << right;
@@ -320,7 +320,7 @@ void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack)
}
if (runtimeRegularExpressions) {
for (uint i = 0; i < data->regexpTableSize; ++i)
- runtimeRegularExpressions[i].mark(markStack);
+ Value::fromStaticValue(runtimeRegularExpressions[i]).mark(markStack);
}
if (runtimeClasses) {
for (uint i = 0; i < data->jsClassTableSize; ++i)
@@ -458,8 +458,8 @@ Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine)
const uint importCount = data->importEntryTableSize;
if (importCount > 0) {
- imports = new const Value *[importCount];
- memset(imports, 0, importCount * sizeof(Value *));
+ imports = new const StaticValue *[importCount];
+ memset(imports, 0, importCount * sizeof(StaticValue *));
}
for (uint i = 0; i < importCount; ++i) {
const CompiledData::ImportEntry &entry = data->importEntryTable()[i];
@@ -517,7 +517,7 @@ const Value *ExecutableCompilationUnit::resolveExportRecursively(
if (index == UINT_MAX)
return nullptr;
if (index >= module()->scope->locals.size)
- return imports[index - module()->scope->locals.size];
+ return &(imports[index - module()->scope->locals.size]->asValue<Value>());
return &module()->scope->locals[index];
}
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 8a9bd66103..640a908dd3 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -41,6 +41,8 @@
#include <private/qv4compileddata_p.h>
#include <private/qv4calldata_p.h>
+#include <QtCore/qdebug.h>
+
using namespace QV4;
using namespace QV4::Moth;
@@ -110,9 +112,9 @@ const int InstrInfo::argumentCount[] = {
QString dumpRegister(int reg, int nFormals)
{
Q_STATIC_ASSERT(offsetof(CallData, function) == 0);
- Q_STATIC_ASSERT(offsetof(CallData, context) == sizeof(Value));
- Q_STATIC_ASSERT(offsetof(CallData, accumulator) == 2*sizeof(Value));
- Q_STATIC_ASSERT(offsetof(CallData, thisObject) == 3*sizeof(Value));
+ Q_STATIC_ASSERT(offsetof(CallData, context) == sizeof(StaticValue));
+ Q_STATIC_ASSERT(offsetof(CallData, accumulator) == 2*sizeof(StaticValue));
+ Q_STATIC_ASSERT(offsetof(CallData, thisObject) == 3*sizeof(StaticValue));
if (reg == CallData::Function)
return QStringLiteral("(function)");
else if (reg == CallData::Context)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 5338583164..ec81701160 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
#include <private/qv4global_p.h>
-#include <private/qv4runtime_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qv4compileddata_p.h> // for CompiledData::CodeOffsetToLine used by the dumper
#include <qendian.h>
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index f4807f1917..9dd2cdc43b 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -49,7 +49,7 @@ using namespace QV4::Moth;
BaselineJIT::BaselineJIT(Function *function)
: function(function)
- , as(new BaselineAssembler(function->compilationUnit->constants))
+ , as(new BaselineAssembler(&(function->compilationUnit->constants->asValue<Value>())))
{}
BaselineJIT::~BaselineJIT()
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index e6f1079aa7..74e893e570 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -58,7 +58,9 @@ SOURCES += \
$$PWD/qv4mapiterator.cpp \
$$PWD/qv4estable.cpp \
$$PWD/qv4module.cpp \
- $$PWD/qv4promiseobject.cpp
+ $$PWD/qv4promiseobject.cpp \
+ $$PWD/qv4runtime.cpp \
+ $$PWD/qv4value.cpp
qtConfig(qml-debug): SOURCES += $$PWD/qv4profiling.cpp
@@ -129,7 +131,9 @@ HEADERS += \
$$PWD/qv4estable_p.h \
$$PWD/qv4vtable_p.h \
$$PWD/qv4module_p.h \
- $$PWD/qv4promiseobject_p.h
+ $$PWD/qv4promiseobject_p.h \
+ $$PWD/qv4runtime_p.h \
+ $$PWD/qv4value_p.h
qtConfig(qml-sequence-object) {
HEADERS += \
@@ -144,17 +148,13 @@ qtConfig(qml-sequence-object) {
HEADERS += \
$$PWD/qv4calldata_p.h \
- $$PWD/qv4runtime_p.h \
$$PWD/qv4runtimeapi_p.h \
- $$PWD/qv4value_p.h \
$$PWD/qv4stringtoarrayindex_p.h \
$$PWD/qv4util_p.h \
- $$PWD/qv4value_p.h \
- $$PWD/qv4functiontable_p.h
+ $$PWD/qv4functiontable_p.h \
+ $$PWD/qv4staticvalue_p.h
SOURCES += \
- $$PWD/qv4runtime.cpp \
- $$PWD/qv4value.cpp \
$$PWD/qv4executableallocator.cpp
qmldevtools_build {
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index b3e607d74a..af1a2d1de0 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -175,7 +175,8 @@ static ScopedObject createObjectFromCtorOrArray(Scope &scope, ScopedFunctionObje
// this isn't completely kosher. for instance:
// Array.from.call(Object, []).constructor == Object
// is expected by the tests, but naturally, we get Number.
- ScopedValue argument(scope, useLen ? QV4::Encode(len) : Value::undefinedValue());
+ ScopedValue argument(scope, useLen ? Value::fromReturnedValue(QV4::Encode(len))
+ : Value::undefinedValue());
a = ctor->callAsConstructor(argument, useLen ? 1 : 0);
} else {
a = scope.engine->newArrayObject(len);
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index 3e5f51c302..a9b4ecb607 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -103,7 +103,7 @@ ReturnedValue BooleanPrototype::method_toString(const FunctionObject *b, const V
if (exception)
return v4->throwTypeError();
- return Encode(result ? v4->id_true() : v4->id_false());
+ return (result ? v4->id_true() : v4->id_false())->asReturnedValue();
}
ReturnedValue BooleanPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int)
diff --git a/src/qml/jsruntime/qv4calldata_p.h b/src/qml/jsruntime/qv4calldata_p.h
index 8487872bf5..5a5280cb86 100644
--- a/src/qml/jsruntime/qv4calldata_p.h
+++ b/src/qml/jsruntime/qv4calldata_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include <private/qv4value_p.h>
+#include <private/qv4staticvalue_p.h>
QT_BEGIN_NAMESPACE
@@ -71,12 +71,12 @@ struct CallData
OffsetCount = LastOffset + 1
};
- Value function;
- Value context;
- Value accumulator;
- Value thisObject;
- Value newTarget;
- Value _argc;
+ StaticValue function;
+ StaticValue context;
+ StaticValue accumulator;
+ StaticValue thisObject;
+ StaticValue newTarget;
+ StaticValue _argc;
int argc() const {
Q_ASSERT(_argc.isInteger());
@@ -89,22 +89,32 @@ struct CallData
}
inline ReturnedValue argument(int i) const {
- return i < argc() ? args[i].asReturnedValue() : Value::undefinedValue().asReturnedValue();
+ return i < argc() ? args[i].asReturnedValue()
+ : StaticValue::undefinedValue().asReturnedValue();
}
- Value args[1];
+ StaticValue args[1];
- static Q_DECL_CONSTEXPR int HeaderSize() { return offsetof(CallData, args) / sizeof(QV4::Value); }
+ static Q_DECL_CONSTEXPR int HeaderSize()
+ {
+ return offsetof(CallData, args) / sizeof(QV4::StaticValue);
+ }
+
+ template<typename Value>
+ Value *argValues();
+
+ template<typename Value>
+ const Value *argValues() const;
};
Q_STATIC_ASSERT(std::is_standard_layout<CallData>::value);
-Q_STATIC_ASSERT(offsetof(CallData, function ) == CallData::Function * sizeof(Value));
-Q_STATIC_ASSERT(offsetof(CallData, context ) == CallData::Context * sizeof(Value));
-Q_STATIC_ASSERT(offsetof(CallData, accumulator) == CallData::Accumulator * sizeof(Value));
-Q_STATIC_ASSERT(offsetof(CallData, thisObject ) == CallData::This * sizeof(Value));
-Q_STATIC_ASSERT(offsetof(CallData, newTarget ) == CallData::NewTarget * sizeof(Value));
-Q_STATIC_ASSERT(offsetof(CallData, _argc ) == CallData::Argc * sizeof(Value));
-Q_STATIC_ASSERT(offsetof(CallData, args ) == 6 * sizeof(Value));
+Q_STATIC_ASSERT(offsetof(CallData, function ) == CallData::Function * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, context ) == CallData::Context * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, accumulator) == CallData::Accumulator * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, thisObject ) == CallData::This * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, newTarget ) == CallData::NewTarget * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, _argc ) == CallData::Argc * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, args ) == 6 * sizeof(StaticValue));
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 130727378d..018571e325 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -71,7 +71,8 @@ Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int b
Heap::ExecutionContext *outer = static_cast<Heap::ExecutionContext *>(frame->context()->m());
c->outer.set(v4, outer);
- c->function.set(v4, static_cast<Heap::FunctionObject *>(frame->jsFrame->function.m()));
+ c->function.set(v4, static_cast<Heap::FunctionObject *>(
+ Value::fromStaticValue(frame->jsFrame->function).m()));
c->locals.size = nLocals;
c->locals.alloc = nLocals;
@@ -108,7 +109,8 @@ Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame)
c->init();
c->outer.set(v4, outer);
- c->function.set(v4, static_cast<Heap::FunctionObject *>(frame->jsFrame->function.m()));
+ c->function.set(v4, static_cast<Heap::FunctionObject *>(
+ Value::fromStaticValue(frame->jsFrame->function).m()));
const CompiledData::Function *compiledFunction = function->compiledFunction;
uint nLocals = compiledFunction->nLocals;
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 42b6edb6e2..ebd21b3543 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -63,10 +63,6 @@
#include <qtqmlglobal.h>
#include <private/qtqmlglobal_p.h>
-#ifdef QT_QML_BOOTSTRAPPED
-#define V4_BOOTSTRAP
-#endif
-
#if defined(Q_CC_MSVC)
#include <float.h>
#include <math.h>
diff --git a/src/qml/jsruntime/qv4math_p.h b/src/qml/jsruntime/qv4math_p.h
index 90246c4229..bca4c2ef66 100644
--- a/src/qml/jsruntime/qv4math_p.h
+++ b/src/qml/jsruntime/qv4math_p.h
@@ -52,6 +52,7 @@
#include <qglobal.h>
+#include <QtQml/private/qv4staticvalue_p.h>
#include <QtCore/qnumeric.h>
#include <QtCore/private/qnumeric_p.h>
#include <cmath>
@@ -70,24 +71,24 @@ static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b)
{
int result;
if (Q_UNLIKELY(add_overflow(a, b, &result)))
- return Value::fromDouble(static_cast<double>(a) + b).asReturnedValue();
- return Value::fromInt32(result).asReturnedValue();
+ return StaticValue::fromDouble(static_cast<double>(a) + b).asReturnedValue();
+ return StaticValue::fromInt32(result).asReturnedValue();
}
static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b)
{
int result;
if (Q_UNLIKELY(sub_overflow(a, b, &result)))
- return Value::fromDouble(static_cast<double>(a) - b).asReturnedValue();
- return Value::fromInt32(result).asReturnedValue();
+ return StaticValue::fromDouble(static_cast<double>(a) - b).asReturnedValue();
+ return StaticValue::fromInt32(result).asReturnedValue();
}
static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b)
{
int result;
if (Q_UNLIKELY(mul_overflow(a, b, &result)))
- return Value::fromDouble(static_cast<double>(a) * b).asReturnedValue();
- return Value::fromInt32(result).asReturnedValue();
+ return StaticValue::fromDouble(static_cast<double>(a) * b).asReturnedValue();
+ return StaticValue::fromInt32(result).asReturnedValue();
}
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 095f27279f..8b7de89d5b 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1271,7 +1271,8 @@ static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index
QVarLengthArray<CallArgument, 9> args(argCount + 1);
args[0].initAsType(returnType);
for (int ii = 0; ii < argCount; ++ii) {
- if (!args[ii + 1].fromValue(argTypes[ii], engine, callArgs->args[ii])) {
+ if (!args[ii + 1].fromValue(argTypes[ii], engine,
+ callArgs->args[ii].asValue<QV4::Value>())) {
qWarning() << QString::fromLatin1("Could not convert argument %1 at").arg(ii);
const StackTrace stack = engine->stackTrace();
for (const StackFrame &frame : stack) {
@@ -1616,8 +1617,10 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const
continue; // We already have a better option
int methodMatchScore = 0;
- for (int ii = 0; ii < methodArgumentCount; ++ii)
- methodMatchScore += MatchScore((v = callArgs->args[ii]), methodArgTypes[ii]);
+ for (int ii = 0; ii < methodArgumentCount; ++ii) {
+ methodMatchScore += MatchScore((v = Value::fromStaticValue(callArgs->args[ii])),
+ methodArgTypes[ii]);
+ }
if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
best = *attempt;
@@ -2253,8 +2256,10 @@ ReturnedValue QMetaObjectWrapper::callOverloadedConstructor(QV4::ExecutionEngine
continue; // We already have a better option
int methodMatchScore = 0;
- for (int ii = 0; ii < methodArgumentCount; ++ii)
- methodMatchScore += MatchScore((v = callArgs->args[ii]), methodArgTypes[ii]);
+ for (int ii = 0; ii < methodArgumentCount; ++ii) {
+ methodMatchScore += MatchScore((v = Value::fromStaticValue(callArgs->args[ii])),
+ methodArgTypes[ii]);
+ }
if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
best = attempt;
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 478114a38a..38cce2a7a9 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -39,7 +39,6 @@
#include "qv4global_p.h"
#include "qv4runtime_p.h"
-#ifndef V4_BOOTSTRAP
#include "qv4engine_p.h"
#include "qv4object_p.h"
#include "qv4objectproto_p.h"
@@ -63,7 +62,6 @@
#include "qv4qobjectwrapper_p.h"
#include "qv4symbol_p.h"
#include "qv4generatorobject_p.h"
-#endif
#include <QtCore/QDebug>
#include <cassert>
@@ -222,8 +220,6 @@ void RuntimeCounters::count(const char *func, uint tag1, uint tag2)
#endif // QV4_COUNT_RUNTIME_FUNCTIONS
-#ifndef V4_BOOTSTRAP
-
static QV4::Lookup *runtimeLookup(Function *f, uint i)
{
return f->executableCompilationUnit()->runtimeLookups + i;
@@ -1026,7 +1022,8 @@ static Object *getSuperBase(Scope &scope)
return nullptr;
}
- ScopedFunctionObject f(scope, scope.engine->currentStackFrame->jsFrame->function);
+ ScopedFunctionObject f(
+ scope, Value::fromStaticValue(scope.engine->currentStackFrame->jsFrame->function));
ScopedObject homeObject(scope, f->getHomeObject());
if (!homeObject) {
ScopedContext ctx(scope, static_cast<ExecutionContext *>(&scope.engine->currentStackFrame->jsFrame->context));
@@ -1064,7 +1061,8 @@ ReturnedValue Runtime::LoadSuperProperty::call(ExecutionEngine *engine, const Va
ScopedPropertyKey key(scope, property.toPropertyKey(engine));
if (engine->hasException)
return Encode::undefined();
- return base->get(key, &engine->currentStackFrame->jsFrame->thisObject);
+ return base->get(
+ key, &(engine->currentStackFrame->jsFrame->thisObject.asValue<Value>()));
}
void Runtime::StoreSuperProperty::call(ExecutionEngine *engine, const Value &property, const Value &value)
@@ -1076,7 +1074,8 @@ void Runtime::StoreSuperProperty::call(ExecutionEngine *engine, const Value &pro
ScopedPropertyKey key(scope, property.toPropertyKey(engine));
if (engine->hasException)
return;
- bool result = base->put(key, value, &engine->currentStackFrame->jsFrame->thisObject);
+ bool result = base->put(
+ key, value, &(engine->currentStackFrame->jsFrame->thisObject.asValue<Value>()));
if (!result && engine->currentStackFrame->v4Function->isStrict())
engine->throwTypeError();
}
@@ -1128,8 +1127,6 @@ ReturnedValue Runtime::LoadSuperConstructor::call(ExecutionEngine *engine, const
return c->asReturnedValue();
}
-#endif // V4_BOOTSTRAP
-
uint RuntimeHelpers::equalHelper(const Value &x, const Value &y)
{
Q_ASSERT(x.type() != y.type() || (x.isManaged() && (x.isString() != y.isString())));
@@ -1151,9 +1148,6 @@ uint RuntimeHelpers::equalHelper(const Value &x, const Value &y)
} else if (y.isBoolean()) {
return Runtime::CompareEqual::call(x, Value::fromDouble((double) y.booleanValue()));
} else {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
-#else
Object *xo = x.objectValue();
Object *yo = y.objectValue();
if (yo && (x.isNumber() || x.isString())) {
@@ -1165,7 +1159,6 @@ uint RuntimeHelpers::equalHelper(const Value &x, const Value &y)
ScopedValue px(scope, RuntimeHelpers::objectDefaultValue(xo, PREFERREDTYPE_HINT));
return Runtime::CompareEqual::call(px, y);
}
-#endif
}
return false;
@@ -1182,12 +1175,7 @@ Bool RuntimeHelpers::strictEqual(const Value &x, const Value &y)
if (x.isNumber())
return y.isNumber() && x.asDouble() == y.asDouble();
if (x.isManaged()) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
- return false;
-#else
return y.isManaged() && x.cast<Managed>()->isEqualTo(y.cast<Managed>());
-#endif
}
return false;
}
@@ -1202,26 +1190,17 @@ QV4::Bool Runtime::CompareGreaterThan::call(const Value &l, const Value &r)
String *sl = l.stringValue();
String *sr = r.stringValue();
if (sl && sr) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
- return false;
-#else
return sr->lessThan(sl);
-#endif
}
Object *ro = r.objectValue();
Object *lo = l.objectValue();
if (ro || lo) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
-#else
QV4::ExecutionEngine *e = (lo ? lo : ro)->engine();
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue());
QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue());
return Runtime::CompareGreaterThan::call(pl, pr);
-#endif
}
double dl = RuntimeHelpers::toNumber(l);
@@ -1239,26 +1218,17 @@ QV4::Bool Runtime::CompareLessThan::call(const Value &l, const Value &r)
String *sl = l.stringValue();
String *sr = r.stringValue();
if (sl && sr) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
- return false;
-#else
return sl->lessThan(sr);
-#endif
}
Object *ro = r.objectValue();
Object *lo = l.objectValue();
if (ro || lo) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
-#else
QV4::ExecutionEngine *e = (lo ? lo : ro)->engine();
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue());
QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue());
return Runtime::CompareLessThan::call(pl, pr);
-#endif
}
double dl = RuntimeHelpers::toNumber(l);
@@ -1276,26 +1246,17 @@ QV4::Bool Runtime::CompareGreaterEqual::call(const Value &l, const Value &r)
String *sl = l.stringValue();
String *sr = r.stringValue();
if (sl && sr) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
- return false;
-#else
return !sl->lessThan(sr);
-#endif
}
Object *ro = r.objectValue();
Object *lo = l.objectValue();
if (ro || lo) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
-#else
QV4::ExecutionEngine *e = (lo ? lo : ro)->engine();
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue());
QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue());
return Runtime::CompareGreaterEqual::call(pl, pr);
-#endif
}
double dl = RuntimeHelpers::toNumber(l);
@@ -1313,26 +1274,17 @@ QV4::Bool Runtime::CompareLessEqual::call(const Value &l, const Value &r)
String *sl = l.stringValue();
String *sr = r.stringValue();
if (sl && sr) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
- return false;
-#else
return !sr->lessThan(sl);
-#endif
}
Object *ro = r.objectValue();
Object *lo = l.objectValue();
if (ro || lo) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
-#else
QV4::ExecutionEngine *e = (lo ? lo : ro)->engine();
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue());
QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue());
return Runtime::CompareLessEqual::call(pl, pr);
-#endif
}
double dl = RuntimeHelpers::toNumber(l);
@@ -1340,7 +1292,6 @@ QV4::Bool Runtime::CompareLessEqual::call(const Value &l, const Value &r)
return dl <= dr;
}
-#ifndef V4_BOOTSTRAP
Bool Runtime::CompareInstanceof::call(ExecutionEngine *engine, const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -1623,7 +1574,8 @@ ReturnedValue Runtime::TailCall::call(CppStackFrame *frame, ExecutionEngine *eng
}
memcpy(frame->jsFrame->args, argv, argc * sizeof(Value));
- frame->init(engine, fo.function(), frame->jsFrame->args, argc, frame->callerCanHandleTailCall);
+ frame->init(engine, fo.function(), frame->jsFrame->argValues<Value>(), argc,
+ frame->callerCanHandleTailCall);
frame->setupJSFrame(frame->savedStackTop, fo, fo.scope(), thisObject, Primitive::undefinedValue());
engine->jsStackTop = frame->savedStackTop + frame->requiredJSStackFrameSize();
frame->pendingTailCall = true;
@@ -1685,12 +1637,12 @@ void Runtime::PushCallContext::call(CppStackFrame *frame)
ReturnedValue Runtime::PushWithContext::call(ExecutionEngine *engine, const Value &acc)
{
CallData *jsFrame = engine->currentStackFrame->jsFrame;
- Value &newAcc = jsFrame->accumulator;
+ Value &newAcc = jsFrame->accumulator.asValue<Value>();
newAcc = Value::fromHeapObject(acc.toObject(engine));
if (!engine->hasException) {
Q_ASSERT(newAcc.isObject());
const Object &obj = static_cast<const Object &>(newAcc);
- Value &context = jsFrame->context;
+ Value &context = jsFrame->context.asValue<Value>();
auto ec = static_cast<const ExecutionContext *>(&context);
context = ec->newWithContext(obj.d())->asReturnedValue();
}
@@ -1711,7 +1663,8 @@ void Runtime::PushBlockContext::call(ExecutionEngine *engine, int index)
void Runtime::CloneBlockContext::call(ExecutionEngine *engine)
{
auto frame = engine->currentStackFrame;
- auto context = static_cast<Heap::CallContext *>(frame->jsFrame->context.m());
+ auto context = static_cast<Heap::CallContext *>(
+ Value::fromStaticValue(frame->jsFrame->context).m());
frame->jsFrame->context =
ExecutionContext::cloneBlockContext(engine, context)->asReturnedValue();
}
@@ -1971,7 +1924,9 @@ QV4::ReturnedValue Runtime::CreateRestParameter::call(ExecutionEngine *engine, i
ReturnedValue Runtime::RegexpLiteral::call(ExecutionEngine *engine, int id)
{
- Heap::RegExpObject *ro = engine->newRegExpObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeRegularExpressions[id].as<RegExp>());
+ const auto val
+ = engine->currentStackFrame->v4Function->compilationUnit->runtimeRegularExpressions[id];
+ Heap::RegExpObject *ro = engine->newRegExpObject(Value::fromStaticValue(val).as<RegExp>());
return ro->asReturnedValue();
}
@@ -1992,7 +1947,6 @@ ReturnedValue Runtime::ToNumber::call(ExecutionEngine *, const Value &v)
{
return Encode(v.toNumber());
}
-#endif // V4_BOOTSTRAP
ReturnedValue Runtime::UMinus::call(const Value &value)
{
@@ -2010,7 +1964,6 @@ ReturnedValue Runtime::UMinus::call(const Value &value)
// binary operators
-#ifndef V4_BOOTSTRAP
ReturnedValue Runtime::Add::call(ExecutionEngine *engine, const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -2156,8 +2109,6 @@ ReturnedValue Runtime::UShr::call(const Value &left, const Value &right)
return Encode(res);
}
-#endif // V4_BOOTSTRAP
-
ReturnedValue Runtime::GreaterThan::call(const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -2190,7 +2141,6 @@ ReturnedValue Runtime::LessEqual::call(const Value &left, const Value &right)
return Encode(r);
}
-#ifndef V4_BOOTSTRAP
struct LazyScope
{
ExecutionEngine *engine = nullptr;
@@ -2210,7 +2160,6 @@ struct LazyScope
**scopedValue = value;
}
};
-#endif
Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
{
@@ -2219,11 +2168,9 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
Value lhs = left;
Value rhs = right;
-#ifndef V4_BOOTSTRAP
LazyScope scope;
Value *lhsGuard = nullptr;
Value *rhsGuard = nullptr;
-#endif
redo:
if (lhs.asReturnedValue() == rhs.asReturnedValue())
@@ -2253,7 +2200,6 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
case QV4::Value::QT_ManagedOrUndefined1:
case QV4::Value::QT_ManagedOrUndefined2:
case QV4::Value::QT_ManagedOrUndefined3: {
-#ifndef V4_BOOTSTRAP
// RHS: Managed
Heap::Base *l = lhs.m();
Heap::Base *r = rhs.m();
@@ -2271,7 +2217,6 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
lhs = lhsGuard->asReturnedValue();
break;
}
-#endif
return false;
}
case QV4::Value::QT_Empty:
@@ -2283,16 +2228,12 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
rhs = Value::fromDouble(rhs.int_32());
// fall through
default: // double
-#ifndef V4_BOOTSTRAP
if (lhs.m()->internalClass->vtable->isStringOrSymbol) {
return lhs.m()->internalClass->vtable->isString ? (RuntimeHelpers::toNumber(lhs) == rhs.doubleValue()) : false;
} else {
scope.set(&lhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT), lhs.m()->internalClass->engine);
lhs = lhsGuard->asReturnedValue();
}
-#else
- Q_UNIMPLEMENTED();
-#endif
}
goto redo;
case QV4::Value::QT_Empty:
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index 349099f8d5..cb89b7e6c0 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -116,14 +116,12 @@ struct Q_QML_PRIVATE_EXPORT RuntimeHelpers {
// type conversion and testing
-#ifndef V4_BOOTSTRAP
inline ReturnedValue RuntimeHelpers::toPrimitive(const Value &value, TypeHint typeHint)
{
if (!value.isObject())
return value.asReturnedValue();
return RuntimeHelpers::objectDefaultValue(&reinterpret_cast<const Object &>(value), typeHint);
}
-#endif
inline double RuntimeHelpers::toNumber(const Value &value)
{
diff --git a/src/qml/jsruntime/qv4staticvalue_p.h b/src/qml/jsruntime/qv4staticvalue_p.h
new file mode 100644
index 0000000000..c6b4bdb158
--- /dev/null
+++ b/src/qml/jsruntime/qv4staticvalue_p.h
@@ -0,0 +1,548 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4STATICVALUE_P_H
+#define QV4STATICVALUE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/private/qtqmlglobal_p.h>
+#include <QtQml/private/qv4global_p.h>
+#include <QtCore/private/qnumeric_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct Double {
+ quint64 d;
+
+ Double(double dbl) {
+ memcpy(&d, &dbl, sizeof(double));
+ }
+
+ int sign() const {
+ return (d >> 63) ? -1 : 1;
+ }
+
+ bool isDenormal() const {
+ return static_cast<int>((d << 1) >> 53) == 0;
+ }
+
+ int exponent() const {
+ return static_cast<int>((d << 1) >> 53) - 1023;
+ }
+
+ quint64 significant() const {
+ quint64 m = (d << 12) >> 12;
+ if (!isDenormal())
+ m |= (static_cast<quint64>(1) << 52);
+ return m;
+ }
+
+ static int toInt32(double d) {
+ int i = static_cast<int>(d);
+ if (i == d)
+ return i;
+ return Double(d).toInt32();
+ }
+
+ int toInt32() {
+ int e = exponent() - 52;
+ if (e < 0) {
+ if (e <= -53)
+ return 0;
+ return sign() * static_cast<int>(significant() >> -e);
+ } else {
+ if (e > 31)
+ return 0;
+ return sign() * (static_cast<int>(significant()) << e);
+ }
+ }
+};
+
+struct Q_QML_PRIVATE_EXPORT StaticValue
+{
+ StaticValue() = default;
+ constexpr StaticValue(quint64 val) : _val(val) {}
+
+ StaticValue &operator=(ReturnedValue v)
+ {
+ _val = v;
+ return *this;
+ }
+
+ template<typename Value>
+ StaticValue &operator=(const Value &);
+
+ template<typename Value>
+ const Value &asValue() const;
+
+ template<typename Value>
+ Value &asValue();
+
+ /*
+ We use 8 bytes for a value and a different variant of NaN boxing. A Double
+ NaN (actually -qNaN) is indicated by a number that has the top 13 bits set, and for a
+ signalling NaN it is the top 14 bits. The other values are usually set to 0 by the
+ processor, and are thus free for us to store other data. We keep pointers in there for
+ managed objects, and encode the other types using the free space given to use by the unused
+ bits for NaN values. This also works for pointers on 64 bit systems, as they all currently
+ only have 48 bits of addressable memory. (Note: we do leave the lower 49 bits available for
+ pointers.)
+
+ We xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will
+ get encoded with bits 63-49 all set to 0. We then use bit 48 to distinguish between
+ managed/undefined (0), or Null/Int/Bool/Empty (1). So, storing a 49 bit pointer will leave
+ the top 15 bits 0, which is exactly the 'natural' representation of pointers. If bit 49 is
+ set, bit 48 indicates Empty (0) or integer-convertible (1). Then the 3 bit below that are
+ used to encode Null/Int/Bool.
+
+ Undefined is encoded as a managed pointer with value 0. This is the same as a nullptr.
+
+ Specific bit-sequences:
+ 0 = always 0
+ 1 = always 1
+ x = stored value
+ a,b,c,d = specific bit values, see notes
+
+ 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 |
+ 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value
+ ------------------------------------------------------------------------+--------------
+ 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | Undefined
+ 00000000 0000000x xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Managed (heap pointer)
+ a0000000 0000bc00 00000000 00000000 00000000 00000000 00000000 00000000 | NaN/Inf
+ dddddddd ddddddxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double
+ 00000000 00000010 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole)
+ 00000000 00000010 10000000 00000000 00000000 00000000 00000000 00000000 | Null
+ 00000000 00000011 00000000 00000000 00000000 00000000 00000000 0000000x | Bool
+ 00000000 00000011 10000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int
+
+ Notes:
+ - a: xor-ed signbit, always 1 for NaN
+ - bc, xor-ed values: 11 = inf, 10 = sNaN, 01 = qNaN, 00 = boxed value
+ - d: xor-ed bits, where at least one bit is set, so: (val >> (64-14)) > 0
+ - Undefined maps to C++ nullptr, so the "default" initialization is the same for both C++
+ and JS
+ - Managed has the left 15 bits set to 0, so: (val >> (64-15)) == 0
+ - empty, Null, Bool, and Int have the left 14 bits set to 0, and bit 49 set to 1,
+ so: (val >> (64-15)) == 1
+ - Null, Bool, and Int have bit 48 set, indicating integer-convertible
+ - xoring _val with NaNEncodeMask will convert to a double in "natural" representation, where
+ any non double results in a NaN
+ - on 32bit we can use the fact that addresses are 32bits wide, so the tag part (bits 32 to
+ 63) are zero. No need to shift.
+ */
+
+ quint64 _val;
+
+ QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 &rawValueRef() { return _val; }
+ QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 rawValue() const { return _val; }
+ QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setRawValue(quint64 raw) { _val = raw; }
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ static inline int valueOffset() { return 0; }
+ static inline int tagOffset() { return 4; }
+#else // !Q_LITTLE_ENDIAN
+ static inline int valueOffset() { return 4; }
+ static inline int tagOffset() { return 0; }
+#endif
+ static inline constexpr quint64 tagValue(quint32 tag, quint32 value) { return quint64(tag) << 32 | value; }
+ QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
+ QML_NEARLY_ALWAYS_INLINE constexpr quint32 value() const { return _val & quint64(~quint32(0)); }
+ QML_NEARLY_ALWAYS_INLINE constexpr quint32 tag() const { return _val >> 32; }
+ QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTag(quint32 tag) { setTagValue(tag, value()); }
+
+ QML_NEARLY_ALWAYS_INLINE constexpr int int_32() const
+ {
+ return int(value());
+ }
+ QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setInt_32(int i)
+ {
+ setTagValue(quint32(ValueTypeInternal::Integer), quint32(i));
+ }
+ QML_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); }
+
+ QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setEmpty()
+ {
+ setTagValue(quint32(ValueTypeInternal::Empty), 0);
+ }
+
+ // ### Fix for 32 bit (easiest solution is to set highest bit to 1 for mananged/undefined/integercompatible
+ // and use negative numbers here
+ enum QuickType {
+ QT_ManagedOrUndefined = 0,
+ QT_ManagedOrUndefined1 = 1,
+ QT_ManagedOrUndefined2 = 2,
+ QT_ManagedOrUndefined3 = 3,
+ QT_Empty = 4,
+ QT_Null = 5,
+ QT_Bool = 6,
+ QT_Int = 7
+ // all other values are doubles
+ };
+
+ enum Type {
+ Undefined_Type = 0,
+ Managed_Type = 1,
+ Empty_Type = 4,
+ Null_Type = 5,
+ Boolean_Type = 6,
+ Integer_Type = 7,
+ Double_Type = 8
+ };
+
+ inline Type type() const {
+ int t = quickType();
+ if (t < QT_Empty)
+ return _val ? Managed_Type : Undefined_Type;
+ if (t > QT_Int)
+ return Double_Type;
+ return static_cast<Type>(t);
+ }
+
+ // Shared between 32-bit and 64-bit encoding
+ enum {
+ Tag_Shift = 32
+ };
+
+ // Used only by 64-bit encoding
+ static const quint64 NaNEncodeMask = 0xfffc000000000000ull;
+ enum {
+ IsDouble_Shift = 64-14,
+ IsManagedOrUndefined_Shift = 64-15,
+ IsIntegerConvertible_Shift = 64-15,
+ IsIntegerOrBool_Shift = 64-16,
+ QuickType_Shift = 64 - 17,
+ IsPositiveIntShift = 31
+ };
+
+ static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
+
+ enum class ValueTypeInternal_64 {
+ Empty = Immediate_Mask_64 | 0,
+ Null = Immediate_Mask_64 | 0x08000u,
+ Boolean = Immediate_Mask_64 | 0x10000u,
+ Integer = Immediate_Mask_64 | 0x18000u
+ };
+
+ // Used only by 32-bit encoding
+ enum Masks {
+ SilentNaNBit = 0x00040000,
+ NotDouble_Mask = 0x7ffa0000,
+ };
+ static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
+
+ enum class ValueTypeInternal_32 {
+ Empty = Immediate_Mask_32 | 0,
+ Null = Immediate_Mask_32 | 0x08000u,
+ Boolean = Immediate_Mask_32 | 0x10000u,
+ Integer = Immediate_Mask_32 | 0x18000u
+ };
+
+ enum {
+ Managed_Type_Internal = 0
+ };
+
+ using ValueTypeInternal = ValueTypeInternal_64;
+
+ enum {
+ NaN_Mask = 0x7ff80000,
+ };
+
+ inline quint64 quickType() const { return (_val >> QuickType_Shift); }
+
+ // used internally in property
+ inline bool isEmpty() const { return tag() == quint32(ValueTypeInternal::Empty); }
+ inline bool isNull() const { return tag() == quint32(ValueTypeInternal::Null); }
+ inline bool isBoolean() const { return tag() == quint32(ValueTypeInternal::Boolean); }
+ inline bool isInteger() const { return tag() == quint32(ValueTypeInternal::Integer); }
+ inline bool isNullOrUndefined() const { return isNull() || isUndefined(); }
+ inline bool isNumber() const { return quickType() >= QT_Int; }
+
+ inline bool isUndefined() const { return _val == 0; }
+ inline bool isDouble() const { return (_val >> IsDouble_Shift); }
+ inline bool isManaged() const
+ {
+#if QT_POINTER_SIZE == 4
+ return value() && tag() == Managed_Type_Internal;
+#else
+ return _val && ((_val >> IsManagedOrUndefined_Shift) == 0);
+#endif
+ }
+ inline bool isManagedOrUndefined() const
+ {
+#if QT_POINTER_SIZE == 4
+ return tag() == Managed_Type_Internal;
+#else
+ return ((_val >> IsManagedOrUndefined_Shift) == 0);
+#endif
+ }
+
+ inline bool isIntOrBool() const {
+ return (_val >> IsIntegerOrBool_Shift) == 3;
+ }
+
+ inline bool integerCompatible() const {
+ Q_ASSERT(!isEmpty());
+ return (_val >> IsIntegerConvertible_Shift) == 1;
+ }
+
+ static inline bool integerCompatible(StaticValue a, StaticValue b) {
+ return a.integerCompatible() && b.integerCompatible();
+ }
+
+ static inline bool bothDouble(StaticValue a, StaticValue b) {
+ return a.isDouble() && b.isDouble();
+ }
+
+ inline bool isNaN() const
+ {
+ return (tag() & 0x7ffc0000 ) == 0x00040000;
+ }
+
+ inline bool isPositiveInt() const {
+#if QT_POINTER_SIZE == 4
+ return isInteger() && int_32() >= 0;
+#else
+ return (_val >> IsPositiveIntShift) == (quint64(ValueTypeInternal::Integer) << 1);
+#endif
+ }
+
+ QML_NEARLY_ALWAYS_INLINE double doubleValue() const {
+ Q_ASSERT(isDouble());
+ double d;
+ StaticValue v = *this;
+ v._val ^= NaNEncodeMask;
+ memcpy(&d, &v._val, 8);
+ return d;
+ }
+
+ QML_NEARLY_ALWAYS_INLINE void setDouble(double d) {
+ if (qt_is_nan(d))
+ d = qt_qnan();
+ memcpy(&_val, &d, 8);
+ _val ^= NaNEncodeMask;
+ Q_ASSERT(isDouble());
+ }
+
+ inline bool isInt32() {
+ if (tag() == quint32(ValueTypeInternal::Integer))
+ return true;
+ if (isDouble()) {
+ double d = doubleValue();
+ if (isInt32(d)) {
+ setInt_32(int(d));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ QML_NEARLY_ALWAYS_INLINE static bool isInt32(double d) {
+ int i = int(d);
+ return (i == d && !(d == 0 && std::signbit(d)));
+ }
+
+ double asDouble() const {
+ if (tag() == quint32(ValueTypeInternal::Integer))
+ return int_32();
+ return doubleValue();
+ }
+
+ bool booleanValue() const {
+ return int_32();
+ }
+
+ int integerValue() const {
+ return int_32();
+ }
+
+ inline bool tryIntegerConversion() {
+ bool b = integerCompatible();
+ if (b)
+ setTagValue(quint32(ValueTypeInternal::Integer), value());
+ return b;
+ }
+
+ bool toBoolean() const {
+ if (integerCompatible())
+ return static_cast<bool>(int_32());
+
+ if (isManagedOrUndefined())
+ return false;
+
+ // double
+ const double d = doubleValue();
+ return d && !std::isnan(d);
+ }
+
+ inline int toInt32() const
+ {
+ switch (type()) {
+ case Null_Type:
+ case Boolean_Type:
+ case Integer_Type:
+ return int_32();
+ case Double_Type:
+ return Double::toInt32(doubleValue());
+ case Empty_Type:
+ case Undefined_Type:
+ case Managed_Type:
+ break;
+ }
+ return Double::toInt32(std::numeric_limits<double>::quiet_NaN());
+ }
+
+ ReturnedValue *data_ptr() { return &_val; }
+ constexpr ReturnedValue asReturnedValue() const { return _val; }
+ constexpr static StaticValue fromReturnedValue(ReturnedValue val) { return {val}; }
+
+ inline static constexpr StaticValue emptyValue() { return { tagValue(quint32(ValueTypeInternal::Empty), 0) }; }
+ static inline constexpr StaticValue fromBoolean(bool b) { return { tagValue(quint32(ValueTypeInternal::Boolean), b) }; }
+ static inline constexpr StaticValue fromInt32(int i) { return { tagValue(quint32(ValueTypeInternal::Integer), quint32(i)) }; }
+ inline static constexpr StaticValue undefinedValue() { return { 0 }; }
+ static inline constexpr StaticValue nullValue() { return { tagValue(quint32(ValueTypeInternal::Null), 0) }; }
+
+ static inline StaticValue fromDouble(double d)
+ {
+ StaticValue v;
+ v.setDouble(d);
+ return v;
+ }
+
+ static inline StaticValue fromUInt32(uint i)
+ {
+ StaticValue v;
+ if (i < uint(std::numeric_limits<int>::max())) {
+ v.setTagValue(quint32(ValueTypeInternal::Integer), i);
+ } else {
+ v.setDouble(i);
+ }
+ return v;
+ }
+
+ static double toInteger(double d)
+ {
+ if (std::isnan(d))
+ return +0;
+ if (!d || std::isinf(d))
+ return d;
+ return d >= 0 ? std::floor(d) : std::ceil(d);
+ }
+
+ static int toInt32(double d)
+ {
+ return Double::toInt32(d);
+ }
+
+ static unsigned int toUInt32(double d)
+ {
+ return static_cast<uint>(toInt32(d));
+ }
+};
+Q_STATIC_ASSERT(std::is_trivial<StaticValue>::value);
+
+struct Encode {
+ static constexpr ReturnedValue undefined() {
+ return StaticValue::undefinedValue().asReturnedValue();
+ }
+ static constexpr ReturnedValue null() {
+ return StaticValue::nullValue().asReturnedValue();
+ }
+
+ explicit constexpr Encode(bool b)
+ : val(StaticValue::fromBoolean(b).asReturnedValue())
+ {
+ }
+ explicit Encode(double d) {
+ val = StaticValue::fromDouble(d).asReturnedValue();
+ }
+ explicit constexpr Encode(int i)
+ : val(StaticValue::fromInt32(i).asReturnedValue())
+ {
+ }
+ explicit Encode(uint i) {
+ val = StaticValue::fromUInt32(i).asReturnedValue();
+ }
+ explicit constexpr Encode(ReturnedValue v)
+ : val(v)
+ {
+ }
+ constexpr Encode(StaticValue v)
+ : val(v.asReturnedValue())
+ {
+ }
+
+ template<typename HeapBase>
+ explicit Encode(HeapBase *o);
+
+ explicit Encode(StaticValue *o) {
+ Q_ASSERT(o);
+ val = o->asReturnedValue();
+ }
+
+ static ReturnedValue smallestNumber(double d) {
+ if (StaticValue::isInt32(d))
+ return Encode(static_cast<int>(d));
+ else
+ return Encode(d);
+ }
+
+ constexpr operator ReturnedValue() const {
+ return val;
+ }
+ quint64 val;
+private:
+ explicit Encode(void *);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4STATICVALUE_P_H
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index 82cf11f148..d29b060b9e 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -39,13 +39,11 @@
#include <qv4runtime_p.h>
#include <qv4propertykey_p.h>
-#ifndef V4_BOOTSTRAP
#include <qv4string_p.h>
#include <qv4symbol_p.h>
#include <qv4object_p.h>
#include <qv4objectproto_p.h>
#include <private/qv4mm_p.h>
-#endif
#include <wtf/MathExtras.h>
@@ -83,12 +81,8 @@ bool Value::toBooleanImpl(Value val)
Heap::Base *b = val.m();
if (!b)
return false;
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
-#else
if (b->internalClass->vtable->isString)
return static_cast<Heap::String *>(b)->length() > 0;
-#endif
return true;
}
@@ -103,10 +97,6 @@ double Value::toNumberImpl(Value val)
case QV4::Value::Undefined_Type:
return std::numeric_limits<double>::quiet_NaN();
case QV4::Value::Managed_Type:
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
- Q_FALLTHROUGH();
-#else
if (String *s = val.stringValue())
return RuntimeHelpers::stringToNumber(s->toQString());
if (val.isSymbol()) {
@@ -114,16 +104,15 @@ double Value::toNumberImpl(Value val)
m.engine()->throwTypeError();
return 0;
}
- {
- Q_ASSERT(val.isObject());
- Scope scope(val.objectValue()->engine());
- ScopedValue protectThis(scope, val);
- ScopedValue prim(scope, RuntimeHelpers::toPrimitive(val, NUMBER_HINT));
+ {
+ Q_ASSERT(val.isObject());
+ Scope scope(val.objectValue()->engine());
+ ScopedValue protectThis(scope, val);
+ ScopedValue prim(scope, RuntimeHelpers::toPrimitive(val, NUMBER_HINT));
if (scope.engine->hasException)
return 0;
return prim->toNumber();
}
-#endif
case QV4::Value::Null_Type:
case QV4::Value::Boolean_Type:
case QV4::Value::Integer_Type:
@@ -133,7 +122,6 @@ double Value::toNumberImpl(Value val)
}
}
-#ifndef V4_BOOTSTRAP
QString Value::toQStringNoThrow() const
{
switch (type()) {
@@ -325,4 +313,3 @@ uint Value::asArrayLength(bool *ok) const
}
return idx;
}
-#endif // V4_BOOTSTRAP
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index da08841026..a9c8ac66bd 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -57,8 +57,10 @@
#include "qv4global_p.h"
#include <private/qv4heap_p.h>
#include <private/qv4internalclass_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qnumeric_p.h>
+#include <private/qv4calldata_p.h>
QT_BEGIN_NAMESPACE
@@ -68,101 +70,40 @@ namespace Heap {
struct Base;
}
-struct Q_QML_PRIVATE_EXPORT Value
+struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
{
- /*
- We use 8 bytes for a value and a different variant of NaN boxing. A Double
- NaN (actually -qNaN) is indicated by a number that has the top 13 bits set, and for a
- signalling NaN it is the top 14 bits. The other values are usually set to 0 by the
- processor, and are thus free for us to store other data. We keep pointers in there for
- managed objects, and encode the other types using the free space given to use by the unused
- bits for NaN values. This also works for pointers on 64 bit systems, as they all currently
- only have 48 bits of addressable memory. (Note: we do leave the lower 49 bits available for
- pointers.)
-
- We xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will
- get encoded with bits 63-49 all set to 0. We then use bit 48 to distinguish between
- managed/undefined (0), or Null/Int/Bool/Empty (1). So, storing a 49 bit pointer will leave
- the top 15 bits 0, which is exactly the 'natural' representation of pointers. If bit 49 is
- set, bit 48 indicates Empty (0) or integer-convertible (1). Then the 3 bit below that are
- used to encode Null/Int/Bool.
-
- Undefined is encoded as a managed pointer with value 0. This is the same as a nullptr.
-
- Specific bit-sequences:
- 0 = always 0
- 1 = always 1
- x = stored value
- a,b,c,d = specific bit values, see notes
-
- 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 |
- 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value
- ------------------------------------------------------------------------+--------------
- 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | Undefined
- 00000000 0000000x xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Managed (heap pointer)
- a0000000 0000bc00 00000000 00000000 00000000 00000000 00000000 00000000 | NaN/Inf
- dddddddd ddddddxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double
- 00000000 00000010 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole)
- 00000000 00000010 10000000 00000000 00000000 00000000 00000000 00000000 | Null
- 00000000 00000011 00000000 00000000 00000000 00000000 00000000 0000000x | Bool
- 00000000 00000011 10000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int
-
- Notes:
- - a: xor-ed signbit, always 1 for NaN
- - bc, xor-ed values: 11 = inf, 10 = sNaN, 01 = qNaN, 00 = boxed value
- - d: xor-ed bits, where at least one bit is set, so: (val >> (64-14)) > 0
- - Undefined maps to C++ nullptr, so the "default" initialization is the same for both C++
- and JS
- - Managed has the left 15 bits set to 0, so: (val >> (64-15)) == 0
- - empty, Null, Bool, and Int have the left 14 bits set to 0, and bit 49 set to 1,
- so: (val >> (64-15)) == 1
- - Null, Bool, and Int have bit 48 set, indicating integer-convertible
- - xoring _val with NaNEncodeMask will convert to a double in "natural" representation, where
- any non double results in a NaN
- - on 32bit we can use the fact that addresses are 32bits wide, so the tag part (bits 32 to
- 63) are zero. No need to shift.
- */
-
- quint64 _val;
-
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 &rawValueRef() { return _val; }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 rawValue() const { return _val; }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setRawValue(quint64 raw) { _val = raw; }
-
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- static inline int valueOffset() { return 0; }
- static inline int tagOffset() { return 4; }
-#else // !Q_LITTLE_ENDIAN
- static inline int valueOffset() { return 4; }
- static inline int tagOffset() { return 0; }
-#endif
- static inline constexpr quint64 tagValue(quint32 tag, quint32 value) { return quint64(tag) << 32 | value; }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
- QML_NEARLY_ALWAYS_INLINE constexpr quint32 value() const { return _val & quint64(~quint32(0)); }
- QML_NEARLY_ALWAYS_INLINE constexpr quint32 tag() const { return _val >> 32; }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTag(quint32 tag) { setTagValue(tag, value()); }
+ using HeapBasePtr = Heap::Base *;
+ using ManagedPtr = Managed *;
+
+ Value() = default;
+ constexpr Value(quint64 val) : StaticValue(val) {}
+
+ static constexpr Value fromStaticValue(StaticValue staticValue)
+ {
+ return {staticValue._val};
+ }
#if QT_POINTER_SIZE == 8
- QML_NEARLY_ALWAYS_INLINE Heap::Base *m() const
+ QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
{
- Heap::Base *b;
+ HeapBasePtr b;
memcpy(&b, &_val, 8);
return b;
}
- QML_NEARLY_ALWAYS_INLINE void setM(Heap::Base *b)
+ QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
{
memcpy(&_val, &b, 8);
}
#elif QT_POINTER_SIZE == 4
- QML_NEARLY_ALWAYS_INLINE Heap::Base *m() const
+ QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
{
- Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32));
- Heap::Base *b;
+ Q_STATIC_ASSERT(sizeof(HeapBasePtr) == sizeof(quint32));
+ HeapBasePtr b;
quint32 v = value();
memcpy(&b, &v, 4);
return b;
}
- QML_NEARLY_ALWAYS_INLINE void setM(Heap::Base *b)
+ QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
{
quint32 v;
memcpy(&v, &b, 4);
@@ -172,204 +113,11 @@ struct Q_QML_PRIVATE_EXPORT Value
# error "unsupported pointer size"
#endif
- QML_NEARLY_ALWAYS_INLINE constexpr int int_32() const
- {
- return int(value());
- }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setInt_32(int i)
- {
- setTagValue(quint32(ValueTypeInternal::Integer), quint32(i));
- }
- QML_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); }
-
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setEmpty()
- {
- setTagValue(quint32(ValueTypeInternal::Empty), 0);
- }
-
- // ### Fix for 32 bit (easiest solution is to set highest bit to 1 for mananged/undefined/integercompatible
- // and use negative numbers here
- enum QuickType {
- QT_ManagedOrUndefined = 0,
- QT_ManagedOrUndefined1 = 1,
- QT_ManagedOrUndefined2 = 2,
- QT_ManagedOrUndefined3 = 3,
- QT_Empty = 4,
- QT_Null = 5,
- QT_Bool = 6,
- QT_Int = 7
- // all other values are doubles
- };
-
- enum Type {
- Undefined_Type = 0,
- Managed_Type = 1,
- Empty_Type = 4,
- Null_Type = 5,
- Boolean_Type = 6,
- Integer_Type = 7,
- Double_Type = 8
- };
-
- inline Type type() const {
- int t = quickType();
- if (t < QT_Empty)
- return _val ? Managed_Type : Undefined_Type;
- if (t > QT_Int)
- return Double_Type;
- return static_cast<Type>(t);
- }
-
- // Shared between 32-bit and 64-bit encoding
- enum {
- Tag_Shift = 32
- };
-
- // Used only by 64-bit encoding
- static const quint64 NaNEncodeMask = 0xfffc000000000000ull;
- enum {
- IsDouble_Shift = 64-14,
- IsManagedOrUndefined_Shift = 64-15,
- IsIntegerConvertible_Shift = 64-15,
- IsIntegerOrBool_Shift = 64-16,
- QuickType_Shift = 64 - 17,
- IsPositiveIntShift = 31
- };
-
- static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
-
- enum class ValueTypeInternal_64 {
- Empty = Immediate_Mask_64 | 0,
- Null = Immediate_Mask_64 | 0x08000u,
- Boolean = Immediate_Mask_64 | 0x10000u,
- Integer = Immediate_Mask_64 | 0x18000u
- };
-
- // Used only by 32-bit encoding
- enum Masks {
- SilentNaNBit = 0x00040000,
- NotDouble_Mask = 0x7ffa0000,
- };
- static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
-
- enum class ValueTypeInternal_32 {
- Empty = Immediate_Mask_32 | 0,
- Null = Immediate_Mask_32 | 0x08000u,
- Boolean = Immediate_Mask_32 | 0x10000u,
- Integer = Immediate_Mask_32 | 0x18000u
- };
-
- enum {
- Managed_Type_Internal = 0
- };
-
- using ValueTypeInternal = ValueTypeInternal_64;
-
- enum {
- NaN_Mask = 0x7ff80000,
- };
-
- inline quint64 quickType() const { return (_val >> QuickType_Shift); }
-
- // used internally in property
- inline bool isEmpty() const { return tag() == quint32(ValueTypeInternal::Empty); }
- inline bool isNull() const { return tag() == quint32(ValueTypeInternal::Null); }
- inline bool isBoolean() const { return tag() == quint32(ValueTypeInternal::Boolean); }
- inline bool isInteger() const { return tag() == quint32(ValueTypeInternal::Integer); }
- inline bool isNullOrUndefined() const { return isNull() || isUndefined(); }
- inline bool isNumber() const { return quickType() >= QT_Int; }
-
- inline bool isUndefined() const { return _val == 0; }
- inline bool isDouble() const { return (_val >> IsDouble_Shift); }
- inline bool isManaged() const
- {
-#if QT_POINTER_SIZE == 4
- return value() && tag() == Managed_Type_Internal;
-#else
- return _val && ((_val >> IsManagedOrUndefined_Shift) == 0);
-#endif
- }
- inline bool isManagedOrUndefined() const
- {
-#if QT_POINTER_SIZE == 4
- return tag() == Managed_Type_Internal;
-#else
- return ((_val >> IsManagedOrUndefined_Shift) == 0);
-#endif
- }
-
- inline bool isIntOrBool() const {
- return (_val >> IsIntegerOrBool_Shift) == 3;
- }
-
- inline bool integerCompatible() const {
- Q_ASSERT(!isEmpty());
- return (_val >> IsIntegerConvertible_Shift) == 1;
- }
- static inline bool integerCompatible(Value a, Value b) {
- return a.integerCompatible() && b.integerCompatible();
- }
- static inline bool bothDouble(Value a, Value b) {
- return a.isDouble() && b.isDouble();
- }
- inline bool isNaN() const { return (tag() & 0x7ffc0000 ) == 0x00040000; }
-
- inline bool isPositiveInt() const {
-#if QT_POINTER_SIZE == 4
- return isInteger() && int_32() >= 0;
-#else
- return (_val >> IsPositiveIntShift) == (quint64(ValueTypeInternal::Integer) << 1);
-#endif
- }
-
- QML_NEARLY_ALWAYS_INLINE double doubleValue() const {
- Q_ASSERT(isDouble());
- double d;
- Value v = *this;
- v._val ^= NaNEncodeMask;
- memcpy(&d, &v._val, 8);
- return d;
- }
- QML_NEARLY_ALWAYS_INLINE void setDouble(double d) {
- if (qt_is_nan(d))
- d = qt_qnan();
- memcpy(&_val, &d, 8);
- _val ^= NaNEncodeMask;
- Q_ASSERT(isDouble());
- }
inline bool isString() const;
inline bool isStringOrSymbol() const;
inline bool isSymbol() const;
inline bool isObject() const;
inline bool isFunctionObject() const;
- inline bool isInt32() {
- if (tag() == quint32(ValueTypeInternal::Integer))
- return true;
- if (isDouble()) {
- double d = doubleValue();
- if (isInt32(d)) {
- setInt_32(int(d));
- return true;
- }
- }
- return false;
- }
- QML_NEARLY_ALWAYS_INLINE static bool isInt32(double d) {
- int i = int(d);
- return (i == d && !(d == 0 && std::signbit(d)));
- }
- double asDouble() const {
- if (tag() == quint32(ValueTypeInternal::Integer))
- return int_32();
- return doubleValue();
- }
-
- bool booleanValue() const {
- return int_32();
- }
- int integerValue() const {
- return int_32();
- }
QML_NEARLY_ALWAYS_INLINE String *stringValue() const {
if (!isString())
@@ -391,16 +139,16 @@ struct Q_QML_PRIVATE_EXPORT Value
return nullptr;
return reinterpret_cast<Object*>(const_cast<Value *>(this));
}
- QML_NEARLY_ALWAYS_INLINE Managed *managed() const {
+ QML_NEARLY_ALWAYS_INLINE ManagedPtr managed() const {
if (!isManaged())
return nullptr;
return reinterpret_cast<Managed*>(const_cast<Value *>(this));
}
- QML_NEARLY_ALWAYS_INLINE Heap::Base *heapObject() const {
+ QML_NEARLY_ALWAYS_INLINE Value::HeapBasePtr heapObject() const {
return isManagedOrUndefined() ? m() : nullptr;
}
- static inline Value fromHeapObject(Heap::Base *m)
+ static inline Value fromHeapObject(HeapBasePtr m)
{
Value v;
v.setM(m);
@@ -443,12 +191,6 @@ struct Q_QML_PRIVATE_EXPORT Value
static Heap::Object *toObject(ExecutionEngine *e, Value val);
inline bool isPrimitive() const;
- inline bool tryIntegerConversion() {
- bool b = integerCompatible();
- if (b)
- setTagValue(quint32(ValueTypeInternal::Integer), value());
- return b;
- }
template <typename T>
const T *as() const {
@@ -482,13 +224,12 @@ struct Q_QML_PRIVATE_EXPORT Value
return static_cast<const T *>(managed());
}
-#ifndef V4_BOOTSTRAP
uint asArrayLength(bool *ok) const;
-#endif
- ReturnedValue *data_ptr() { return &_val; }
- constexpr ReturnedValue asReturnedValue() const { return _val; }
- static Value fromReturnedValue(ReturnedValue val) { Value v; v._val = val; return v; }
+ static constexpr Value fromReturnedValue(ReturnedValue val)
+ {
+ return fromStaticValue(StaticValue::fromReturnedValue(val));
+ }
// As per ES specs
bool sameValue(Value other) const;
@@ -496,21 +237,45 @@ struct Q_QML_PRIVATE_EXPORT Value
inline void mark(MarkStack *markStack);
- inline static constexpr Value emptyValue() { return { tagValue(quint32(ValueTypeInternal::Empty), 0) }; }
- static inline constexpr Value fromBoolean(bool b) { return { tagValue(quint32(ValueTypeInternal::Boolean), b) }; }
- static inline constexpr Value fromInt32(int i) { return { tagValue(quint32(ValueTypeInternal::Integer), quint32(i)) }; }
- inline static constexpr Value undefinedValue() { return { 0 }; }
- static inline constexpr Value nullValue() { return { tagValue(quint32(ValueTypeInternal::Null), 0) }; }
- static inline Value fromDouble(double d);
- static inline Value fromUInt32(uint i);
-
- static double toInteger(double d);
- static int toInt32(double d);
- static unsigned int toUInt32(double d);
+ static double toInteger(double d) { return StaticValue::toInteger(d); }
+ static int toInt32(double d) { return StaticValue::toInt32(d); }
+ static unsigned int toUInt32(double d) { return StaticValue::toUInt32(d); }
+ inline static constexpr Value emptyValue()
+ {
+ return fromStaticValue(StaticValue::emptyValue());
+ }
+ static inline constexpr Value fromBoolean(bool b)
+ {
+ return fromStaticValue(StaticValue::fromBoolean(b));
+ }
+ static inline constexpr Value fromInt32(int i)
+ {
+ return fromStaticValue(StaticValue::fromInt32(i));
+ }
+ inline static constexpr Value undefinedValue()
+ {
+ return fromStaticValue(StaticValue::undefinedValue());
+ }
+ static inline constexpr Value nullValue()
+ {
+ return fromStaticValue(StaticValue::nullValue());
+ }
+ static inline Value fromDouble(double d)
+ {
+ return fromStaticValue(StaticValue::fromDouble(d));
+ }
+ static inline Value fromUInt32(uint i)
+ {
+ return fromStaticValue(StaticValue::fromUInt32(i));
+ }
Value &operator =(const ScopedValue &v);
- Value &operator=(ReturnedValue v) { _val = v; return *this; }
- Value &operator=(Managed *m) {
+ Value &operator=(ReturnedValue v)
+ {
+ StaticValue::operator=(v);
+ return *this;
+ }
+ Value &operator=(ManagedPtr m) {
if (!m) {
setM(nullptr);
} else {
@@ -518,7 +283,7 @@ struct Q_QML_PRIVATE_EXPORT Value
}
return *this;
}
- Value &operator=(Heap::Base *o) {
+ Value &operator=(HeapBasePtr o) {
setM(o);
return *this;
}
@@ -526,43 +291,88 @@ struct Q_QML_PRIVATE_EXPORT Value
template<typename T>
Value &operator=(const Scoped<T> &t);
};
-Q_STATIC_ASSERT(std::is_trivial< Value >::value);
+Q_STATIC_ASSERT(std::is_trivial<Value>::value);
+Q_STATIC_ASSERT(sizeof(Value) == sizeof(StaticValue));
+
+template<>
+inline StaticValue &StaticValue::operator=<Value>(const Value &value)
+{
+ _val = value._val;
+ return *this;
+}
+
+template<typename Managed>
+inline StaticValue &StaticValue::operator=(const Managed &m)
+{
+ *static_cast<Value *>(this) = m;
+ return *this;
+}
+
+template<>
+inline Value &StaticValue::asValue<Value>()
+{
+ return *static_cast<Value *>(this);
+}
+
+template<>
+inline const Value &StaticValue::asValue<Value>() const
+{
+ return *static_cast<const Value *>(this);
+}
+
+template<>
+inline Value *CallData::argValues<Value>()
+{
+ return static_cast<Value *>(static_cast<StaticValue *>(args));
+}
+
+template<>
+inline const Value *CallData::argValues<Value>() const
+{
+ return static_cast<const Value *>(static_cast<const StaticValue *>(args));
+}
+
+template<typename HeapBase>
+inline Encode::Encode(HeapBase *o)
+{
+ val = Value::fromHeapObject(o).asReturnedValue();
+}
inline void Value::mark(MarkStack *markStack)
{
- Heap::Base *o = heapObject();
+ HeapBasePtr o = heapObject();
if (o)
o->mark(markStack);
}
inline bool Value::isString() const
{
- Heap::Base *b = heapObject();
+ HeapBasePtr b = heapObject();
return b && b->internalClass->vtable->isString;
}
bool Value::isStringOrSymbol() const
{
- Heap::Base *b = heapObject();
+ HeapBasePtr b = heapObject();
return b && b->internalClass->vtable->isStringOrSymbol;
}
bool Value::isSymbol() const
{
- Heap::Base *b = heapObject();
+ HeapBasePtr b = heapObject();
return b && b->internalClass->vtable->isStringOrSymbol && !b->internalClass->vtable->isString;
}
inline bool Value::isObject() const
{
- Heap::Base *b = heapObject();
+ HeapBasePtr b = heapObject();
return b && b->internalClass->vtable->isObject;
}
inline bool Value::isFunctionObject() const
{
- Heap::Base *b = heapObject();
+ HeapBasePtr b = heapObject();
return b && b->internalClass->vtable->isFunctionObject;
}
@@ -592,151 +402,12 @@ inline ReturnedValue Value::convertedToNumber() const
inline
ReturnedValue Heap::Base::asReturnedValue() const
{
- return Value::fromHeapObject(const_cast<Heap::Base *>(this)).asReturnedValue();
-}
-
-inline Value Value::fromDouble(double d)
-{
- Value v;
- v.setDouble(d);
- return v;
-}
-
-inline Value Value::fromUInt32(uint i)
-{
- Value v;
- if (i < INT_MAX) {
- v.setTagValue(quint32(ValueTypeInternal::Integer), i);
- } else {
- v.setDouble(i);
- }
- return v;
-}
-
-struct Double {
- quint64 d;
-
- Double(double dbl) {
- memcpy(&d, &dbl, sizeof(double));
- }
-
- int sign() const {
- return (d >> 63) ? -1 : 1;
- }
-
- bool isDenormal() const {
- return static_cast<int>((d << 1) >> 53) == 0;
- }
-
- int exponent() const {
- return static_cast<int>((d << 1) >> 53) - 1023;
- }
-
- quint64 significant() const {
- quint64 m = (d << 12) >> 12;
- if (!isDenormal())
- m |= (static_cast<quint64>(1) << 52);
- return m;
- }
-
- static int toInt32(double d) {
- int i = static_cast<int>(d);
- if (i == d)
- return i;
- return Double(d).toInt32();
- }
-
- int toInt32() {
- int e = exponent() - 52;
- if (e < 0) {
- if (e <= -53)
- return 0;
- return sign() * static_cast<int>(significant() >> -e);
- } else {
- if (e > 31)
- return 0;
- return sign() * (static_cast<int>(significant()) << e);
- }
- }
-};
-
-inline double Value::toInteger(double d)
-{
- if (std::isnan(d))
- return +0;
- else if (!d || std::isinf(d))
- return d;
- return d >= 0 ? std::floor(d) : std::ceil(d);
-}
-
-inline int Value::toInt32(double value)
-{
- return Double::toInt32(value);
-}
-
-inline unsigned int Value::toUInt32(double d)
-{
- return static_cast<uint>(toInt32(d));
+ return Value::fromHeapObject(const_cast<Value::HeapBasePtr>(this)).asReturnedValue();
}
// For source compat with older code in other modules
using Primitive = Value;
-struct Encode {
- static constexpr ReturnedValue undefined() {
- return Value::undefinedValue().asReturnedValue();
- }
- static constexpr ReturnedValue null() {
- return Value::nullValue().asReturnedValue();
- }
-
- explicit constexpr Encode(bool b)
- : val(Value::fromBoolean(b).asReturnedValue())
- {
- }
- explicit Encode(double d) {
- val = Value::fromDouble(d).asReturnedValue();
- }
- explicit constexpr Encode(int i)
- : val(Value::fromInt32(i).asReturnedValue())
- {
- }
- explicit Encode(uint i) {
- val = Value::fromUInt32(i).asReturnedValue();
- }
- explicit constexpr Encode(ReturnedValue v)
- : val(v)
- {
- }
- constexpr Encode(Value v)
- : val(v.asReturnedValue())
- {
- }
-
- explicit Encode(Heap::Base *o) {
- val = Value::fromHeapObject(o).asReturnedValue();
- }
-
- explicit Encode(Value *o) {
- Q_ASSERT(o);
- val = o->asReturnedValue();
- }
-
- static ReturnedValue smallestNumber(double d) {
- if (Value::isInt32(d))
- return Encode(static_cast<int>(d));
- else
- return Encode(d);
- }
-
- constexpr operator ReturnedValue() const {
- return val;
- }
- quint64 val;
-private:
- explicit Encode(void *);
-};
-
template<typename T>
ReturnedValue value_convert(ExecutionEngine *e, const Value &v);
@@ -793,8 +464,8 @@ inline double Value::toInteger() const
template <size_t o>
struct HeapValue : Value {
static Q_CONSTEXPR size_t offset = o;
- Heap::Base *base() {
- Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ HeapBasePtr base() {
+ HeapBasePtr base = reinterpret_cast<HeapBasePtr>(this) - (offset/sizeof(Heap::Base));
Q_ASSERT(base->inUse());
return base;
}
@@ -802,7 +473,7 @@ struct HeapValue : Value {
void set(EngineBase *e, const Value &newVal) {
WriteBarrier::write(e, base(), data_ptr(), newVal.asReturnedValue());
}
- void set(EngineBase *e, Heap::Base *b) {
+ void set(EngineBase *e, HeapBasePtr b) {
WriteBarrier::write(e, base(), data_ptr(), b->asReturnedValue());
}
};
@@ -814,8 +485,9 @@ struct ValueArray {
uint alloc;
Value values[1];
- Heap::Base *base() {
- Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ Value::HeapBasePtr base() {
+ Value::HeapBasePtr base = reinterpret_cast<Value::HeapBasePtr>(this)
+ - (offset/sizeof(Heap::Base));
Q_ASSERT(base->inUse());
return base;
}
@@ -823,7 +495,7 @@ struct ValueArray {
void set(EngineBase *e, uint index, Value v) {
WriteBarrier::write(e, base(), values[index].data_ptr(), v.asReturnedValue());
}
- void set(EngineBase *e, uint index, Heap::Base *b) {
+ void set(EngineBase *e, uint index, Value::HeapBasePtr b) {
WriteBarrier::write(e, base(), values[index].data_ptr(), Value::fromHeapObject(b).asReturnedValue());
}
inline const Value &operator[] (uint index) const {
@@ -852,12 +524,12 @@ struct ValueArray {
const Value *end = v + alloc;
if (alloc > 32*1024) {
// drain from time to time to avoid overflows in the js stack
- Heap::Base **currentBase = markStack->top;
+ Value::HeapBasePtr *currentBase = markStack->top;
while (v < end) {
v->mark(markStack);
++v;
if (markStack->top >= currentBase + 32*1024) {
- Heap::Base **oldBase = markStack->base;
+ Value::HeapBasePtr *oldBase = markStack->base;
markStack->base = currentBase;
markStack->drain();
markStack->base = oldBase;
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index c6322fb504..5b68725bcf 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -365,7 +365,7 @@ static inline Heap::CallContext *getScope(QV4::Value *stack, int level)
static inline const QV4::Value &constant(Function *function, int index)
{
- return function->compilationUnit->constants[index];
+ return function->compilationUnit->constants[index].asValue<Value>();
}
static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs)
@@ -463,7 +463,7 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, const char *code)
{
QV4::Function *function = frame->v4Function;
- QV4::Value &accumulator = frame->jsFrame->accumulator;
+ QV4::Value &accumulator = frame->jsFrame->accumulator.asValue<Value>();
QV4::ReturnedValue acc = accumulator.asReturnedValue();
Value *stack = reinterpret_cast<Value *>(frame->jsFrame);
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index e799267769..8661ebcc13 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -208,7 +208,10 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
}
Q_ASSERT(m_qmlScope.valueRef());
- QV4::ReturnedValue res = v4Function->call(&callData->thisObject, callData->args, callData->argc(), static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef()));
+ QV4::ReturnedValue res = v4Function->call(
+ &(callData->thisObject.asValue<QV4::Value>()),
+ callData->argValues<QV4::Value>(), callData->argc(),
+ static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef()));
QV4::Scope scope(v4);
QV4::ScopedValue result(scope, res);
diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp
index 616de9e80d..57aeeee0a9 100644
--- a/tools/qmlimportscanner/main.cpp
+++ b/tools/qmlimportscanner/main.cpp
@@ -30,7 +30,7 @@
#include <private/qqmljsparser_p.h>
#include <private/qqmljsast_p.h>
#include <private/qv4codegen_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qqmlirbuilder_p.h>
#include <QtCore/QCoreApplication>
diff --git a/tools/qmllint/main.cpp b/tools/qmllint/main.cpp
index 791fb71685..0fdc3e0130 100644
--- a/tools/qmllint/main.cpp
+++ b/tools/qmllint/main.cpp
@@ -34,7 +34,7 @@
#endif
#include <QCoreApplication>
-#include <private/qv4value_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qqmljslexer_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljsengine_p.h>