This saves a surprising amount of memory.
Change-Id: I16f7bde8d11fe11703d4e441060fd52e9632248c
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
if (!compileState->v8BindingProgram.isEmpty()) {
Instruction::InitV8Bindings bindings;
- bindings.program = output->indexForString(compileState->v8BindingProgram);
- bindings.programIndex = compileState->v8BindingProgramIndex;
+ int index = output->programs.count();
+ output->programs.append(compileState->v8BindingProgram);
+ output->v8bindings.append(v8::Persistent<v8::Array>());
+
+ bindings.programIndex = index;
bindings.line = compileState->v8BindingProgramLine;
output->addInstruction(bindings);
}
Instruction::StoreSignal store;
store.signalIndex = prop->index;
- const QString &rewrite =
- rewriteSignalHandler(v->value, prop->name().toString());
- store.value = output->indexForString(rewrite);
+ const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
+ store.value = output->indexForByteArray(rewrite.toUtf8());
store.context = v->signalExpressionContextStack;
store.line = v->location.start.line;
store.column = v->location.start.column;
if (!compileState->v8BindingProgram.isEmpty()) {
Instruction::InitV8Bindings bindings;
- bindings.program = output->indexForString(compileState->v8BindingProgram);
- bindings.programIndex = compileState->v8BindingProgramIndex;
+ int index = output->programs.count();
+ output->programs.append(compileState->v8BindingProgram);
+ output->v8bindings.append(v8::Persistent<v8::Array>());
+
+ bindings.programIndex = index;
bindings.line = compileState->v8BindingProgramLine;
output->addInstruction(bindings);
}
}
funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
+ QByteArray utf8 = funcScript.toUtf8();
VMD::MethodData methodData = { s->parameterNames.count(), 0,
- funcScript.length(),
+ utf8.length(),
s->location.start.line };
VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
md = methodData;
md.bodyOffset = dynamicData.size();
- dynamicData.append((const char *)funcScript.constData(),
- (funcScript.length() * sizeof(QChar)));
+ dynamicData.append((const char *)utf8.constData(), utf8.length());
}
+
methodIndex++;
}
}
int startLineNumber = sharedBindings.at(0)->value->location.start.line;
int lineNumber = startLineNumber;
- QString functionArray(QLatin1String("["));
+ QByteArray functionArray("[", 1);
for (int ii = 0; ii < sharedBindings.count(); ++ii) {
+
JSBindingReference *reference = sharedBindings.at(ii);
QDeclarativeScript::Value *value = reference->value;
const QString &expression = reference->rewrittenExpression;
- if (ii != 0) functionArray += QLatin1String(",");
+ if (ii != 0) functionArray.append(",", 1);
while (lineNumber < value->location.start.line) {
lineNumber++;
- functionArray += QLatin1String("\n");
+ functionArray.append("\n", 1);
}
- functionArray += expression;
+ functionArray += expression.toUtf8();
lineNumber += expression.count(QLatin1Char('\n'));
reference->compiledIndex = ii;
}
- functionArray += QLatin1String("]");
+ functionArray.append("]", 1);
compileState->v8BindingProgram = functionArray;
compileState->v8BindingProgramLine = startLineNumber;
- compileState->v8BindingProgramIndex = output->v8bindings.count();
- output->v8bindings.append(v8::Persistent<v8::Array>());
}
if (bindingCompiler.isValid())
QDeclarativePropertyCache *rootPropertyCache;
QList<QString> primitives;
QList<QByteArray> datas;
+ QList<QByteArray> programs;
QByteArray bytecode;
QList<QDeclarativePropertyCache *> propertyCaches;
QList<QDeclarativeIntegerCache *> contextCaches;
bool nested;
QByteArray compiledBindingData;
- QString v8BindingProgram;
+ QByteArray v8BindingProgram;
int v8BindingProgramLine;
- int v8BindingProgramIndex;
DepthStack objectDepth;
DepthStack listDepth;
setScopeObject(me);
}
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QByteArray &expr,
+ bool isRewritten, QObject *me, const QString &srcUrl,
+ int lineNumber, int columnNumber)
+{
+ url = srcUrl;
+ line = lineNumber;
+ column = columnNumber;
+
+ if (isRewritten) {
+ expressionFunctionValid = true;
+ expressionFunctionRewritten = true;
+ v8function = evalFunction(ctxt, me, expr.constData(), expr.length(),
+ srcUrl, lineNumber, &v8qmlscope);
+ setUseSharedContext(false);
+
+ expressionUtf8 = expr;
+ } else {
+ expression = QString::fromUtf8(expr);
+
+ expressionFunctionValid = false;
+ expressionFunctionRewritten = isRewritten;
+ }
+
+ QDeclarativeAbstractExpression::setContext(ctxt);
+ setScopeObject(me);
+}
+
+// Callee owns the persistent handle
+v8::Persistent<v8::Function>
+QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObject *scope,
+ const char *code, int codeLength,
+ const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope)
+{
+ QDeclarativeEngine *engine = ctxt->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope ctxtscope(ep->v8engine()->context());
+
+ v8::TryCatch tc;
+ v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
+ v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, codeLength, filename, line);
+ if (tc.HasCaught()) {
+ QDeclarativeError error;
+ error.setDescription(QLatin1String("Exception occurred during function compilation"));
+ error.setLine(line);
+ error.setUrl(QUrl::fromLocalFile(filename));
+ v8::Local<v8::Message> message = tc.Message();
+ if (!message.IsEmpty())
+ QDeclarativeExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ return v8::Persistent<v8::Function>();
+ }
+ v8::Local<v8::Value> result = script->Run(scopeobject);
+ if (tc.HasCaught()) {
+ QDeclarativeError error;
+ error.setDescription(QLatin1String("Exception occurred during function evaluation"));
+ error.setLine(line);
+ error.setUrl(QUrl::fromLocalFile(filename));
+ v8::Local<v8::Message> message = tc.Message();
+ if (!message.IsEmpty())
+ QDeclarativeExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ return v8::Persistent<v8::Function>();
+ }
+ if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
+ return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
+}
+
// Callee owns the persistent handle
v8::Persistent<v8::Function>
QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObject *scope,
QDeclarativeEngine *engine = ctxt->engine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- // XXX TODO: Implement script caching, like we used to do with QScriptProgram in the
- // QtScript days
v8::HandleScope handle_scope;
v8::Context::Scope ctxtscope(ep->v8engine()->context());
return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
}
-QDeclarativeExpression *QDeclarativeExpressionPrivate::create(QDeclarativeContextData *ctxt, QObject *object, const QString &expr, bool isRewritten,
+QDeclarativeExpression *
+QDeclarativeExpressionPrivate::create(QDeclarativeContextData *ctxt, QObject *object,
+ const QString &expr, bool isRewritten,
const QString &url, int lineNumber, int columnNumber)
{
return new QDeclarativeExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber, *new QDeclarativeExpressionPrivate);
d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber);
}
+/*! \internal */
+QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt,
+ QObject *object, const QByteArray &expr,
+ bool isRewritten,
+ const QString &url, int lineNumber, int columnNumber,
+ QDeclarativeExpressionPrivate &dd)
+: QObject(dd, 0)
+{
+ Q_D(QDeclarativeExpression);
+ d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber);
+}
+
/*!
Create a QDeclarativeExpression object that is a child of \a parent.
v8::Context::Scope scope(v8engine->context());
return v8engine->toString(v8::Handle<v8::Value>(d->v8function));
+ } else if (!d->expressionUtf8.isEmpty()) {
+ return QString::fromUtf8(d->expressionUtf8);
+ } else {
+ return d->expression;
}
- return d->expression;
}
/*!
d->resetNotifyOnValueChanged();
d->expression = expression;
+ d->expressionUtf8.clear();
d->expressionFunctionValid = false;
d->expressionFunctionRewritten = false;
qPersistentDispose(d->v8function);
QDeclarativeExpressionPrivate &dd);
QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QString &, bool,
const QString &, int, int, QDeclarativeExpressionPrivate &dd);
+ QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QByteArray &, bool,
+ const QString &, int, int, QDeclarativeExpressionPrivate &dd);
private:
QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QString &);
void init(QDeclarativeContextData *, const QString &, QObject *);
void init(QDeclarativeContextData *, v8::Handle<v8::Function>, QObject *);
void init(QDeclarativeContextData *, const QString &, bool, QObject *, const QString &, int, int);
+ void init(QDeclarativeContextData *, const QByteArray &, bool, QObject *, const QString &, int, int);
QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0);
static void exceptionToError(v8::Handle<v8::Message>, QDeclarativeError &);
static v8::Persistent<v8::Function> evalFunction(QDeclarativeContextData *ctxt, QObject *scope,
- const QString &code, const QString &filename, int line,
+ const QString &code, const QString &filename,
+ int line,
v8::Persistent<v8::Object> *qmlscope = 0);
+ static v8::Persistent<v8::Function> evalFunction(QDeclarativeContextData *ctxt, QObject *scope,
+ const char *code, int codeLength,
+ const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope = 0);
+
static QDeclarativeExpression *create(QDeclarativeContextData *, QObject *, const QString &, bool,
const QString &, int, int);
inline virtual QString expressionIdentifier();
QString expression;
+ QByteArray expressionUtf8;
v8::Persistent<v8::Object> v8qmlscope;
v8::Persistent<v8::Function> v8function;
qWarning().nospace() << idx << "\t\t" << "ASSIGN_CUSTOMTYPE\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.primitive << "\t" << instr->assignCustomType.type;
break;
case QDeclarativeInstruction::InitV8Bindings:
- qWarning().nospace() << idx << "\t\t" << "INIT_V8_BINDING\t" << instr->initV8Bindings.program << "\t" << instr->initV8Bindings.programIndex << "\t" << instr->initV8Bindings.line;
+ qWarning().nospace() << idx << "\t\t" << "INIT_V8_BINDING\t" << instr->initV8Bindings.programIndex << "\t" << instr->initV8Bindings.line;
break;
case QDeclarativeInstruction::StoreBinding:
qWarning().nospace() << idx << "\t\t" << "STORE_BINDING\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
};
struct instr_initV8Bindings {
QML_INSTR_HEADER
- int program;
ushort programIndex;
ushort line;
};
m_imports.populateCache(m_scriptData->importCache, engine);
m_scriptData->pragmas = m_pragmas;
- m_scriptData->m_programSource = m_source;
+ m_scriptData->m_programSource = m_source.toUtf8();
}
QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url)
friend class QDeclarativeScriptBlob;
bool m_loaded;
- QString m_programSource;
+ QByteArray m_programSource;
v8::Persistent<v8::Script> m_program;
v8::Persistent<v8::Object> m_value;
};
#define TYPES COMP->types
#define PRIMITIVES COMP->primitives
#define DATAS COMP->datas
+#define PROGRAMS COMP->programs
#define PROPERTYCACHES COMP->propertyCaches
#define SCRIPTS COMP->scripts
#define URLS COMP->urls
QDeclarativeBoundSignal *bs = new QDeclarativeBoundSignal(target, signal, target);
QDeclarativeExpression *expr =
- new QDeclarativeExpression(CTXT, context, PRIMITIVES.at(instr.value), true, COMP->name, instr.line, instr.column, *new QDeclarativeExpressionPrivate);
+ new QDeclarativeExpression(CTXT, context, DATAS.at(instr.value), true, COMP->name, instr.line, instr.column, *new QDeclarativeExpressionPrivate);
bs->setExpression(expr);
QML_END_INSTR(StoreSignal)
QML_END_INSTR(BeginObject)
QML_BEGIN_INSTR(InitV8Bindings)
- CTXT->v8bindings = new QV8Bindings(PRIMITIVES.at(instr.program), instr.programIndex,
- instr.line, COMP, CTXT);
+ CTXT->v8bindings = new QV8Bindings(instr.programIndex, instr.line, COMP, CTXT);
QML_END_INSTR(InitV8Bindings)
QML_BEGIN_INSTR(StoreBinding)
QV8Engine *v8engine = ep->v8engine();
// If compilation throws an error, a surrounding v8::TryCatch will record it.
- v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_programSource, url.toString(), 1);
+ v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_programSource.constData(),
+ m_programSource.length(), url.toString(),
+ 1);
if (program.IsEmpty())
return;
m_program = qPersistentNew<v8::Script>(program);
+ m_programSource.clear(); // We don't need this anymore
addToEngine(engine);
if (v8methods[index].IsEmpty()) {
QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + index;
- const QChar *body =
- (const QChar *)(((const char*)metaData) + data->bodyOffset);
-
- QString code = QString::fromRawData(body, data->bodyLength);
+ const char *body = ((const char*)metaData) + data->bodyOffset;
+ int bodyLength = data->bodyLength;
// XXX We should evaluate all methods in a single big script block to
// improve the call time between dynamic methods defined on the same
// object
- v8methods[index] = QDeclarativeExpressionPrivate::evalFunction(ctxt, object, code, ctxt->url.toString(),
+ v8methods[index] = QDeclarativeExpressionPrivate::evalFunction(ctxt, object, body, bodyLength,
+ ctxt->url.toString(),
data->lineNumber);
}
parent->release();
}
-QV8Bindings::QV8Bindings(const QString &program, int index, int line,
+QV8Bindings::QV8Bindings(int index, int line,
QDeclarativeCompiledData *compiled,
QDeclarativeContextData *context)
: bindingsCount(0), bindings(0)
bool compileFailed = false;
{
v8::TryCatch try_catch;
- script = engine->qmlModeCompile(program, compiled->name, line);
+ const QByteArray &program = compiled->programs.at(index);
+ script = engine->qmlModeCompile(program.constData(), program.length(), compiled->name, line);
if (try_catch.HasCaught()) {
// The binding was not compiled. There are some exceptional cases which the
// expression rewriter does not rewrite properly (e.g., \r-terminated lines
v8::Local<v8::Value> result = script->Run(engine->contextWrapper()->sharedContext());
if (result->IsArray()) {
compiled->v8bindings[index] = qPersistentNew(v8::Local<v8::Array>::Cast(result));
+ compiled->programs[index].clear(); // We don't need the source anymore
}
}
}
public QDeclarativeRefCount
{
public:
- QV8Bindings(const QString &program, int index, int line,
+ QV8Bindings(int index, int line,
QDeclarativeCompiledData *compiled,
QDeclarativeContextData *context);
virtual ~QV8Bindings();
}
// A handle scope and context must be entered
-v8::Local<v8::Script> QV8Engine::qmlModeCompile(const QString &source, const QString &fileName, int lineNumber)
+v8::Local<v8::Script> QV8Engine::qmlModeCompile(const QString &source,
+ const QString &fileName,
+ int lineNumber)
{
v8::Local<v8::String> v8source = m_stringWrapper.toString(source);
v8::Local<v8::String> v8fileName = m_stringWrapper.toString(fileName);
return script;
}
+// A handle scope and context must be entered.
+// source can be either ascii or utf8.
+v8::Local<v8::Script> QV8Engine::qmlModeCompile(const char *source, int sourceLength,
+ const QString &fileName,
+ int lineNumber)
+{
+ if (sourceLength == -1)
+ sourceLength = strlen(source);
+
+ v8::Local<v8::String> v8source = v8::String::New(source, sourceLength);
+ v8::Local<v8::String> v8fileName = m_stringWrapper.toString(fileName);
+
+ v8::ScriptOrigin origin(v8fileName, v8::Integer::New(lineNumber - 1));
+
+ v8::Local<v8::Script> script = v8::Script::Compile(v8source, &origin, 0, v8::Handle<v8::String>(),
+ v8::Script::QmlMode);
+
+ return script;
+}
+
QNetworkAccessManager *QV8Engine::networkAccessManager()
{
return QDeclarativeEnginePrivate::get(m_engine)->getNetworkAccessManager();
v8::Local<v8::Script> qmlModeCompile(const QString &source,
const QString &fileName = QString(),
int lineNumber = 1);
+ v8::Local<v8::Script> qmlModeCompile(const char *source, int sourceLength = -1,
+ const QString &fileName = QString(),
+ int lineNumber = 1);
// Return the QML global "scope" object for the \a ctxt context and \a scope object.
inline v8::Local<v8::Object> qmlScope(QDeclarativeContextData *ctxt, QObject *scope);