Allow only the ExecutionEngine's StringPool to create Strings.
authorErik Verbruggen <erik.verbruggen@digia.com>
Tue, 4 Dec 2012 11:00:23 +0000 (12:00 +0100)
committerLars Knoll <lars.knoll@digia.com>
Tue, 4 Dec 2012 17:56:56 +0000 (18:56 +0100)
Strings are the only non-Object Values living on the heap. So by
tracking creation, we can help the future GC a lot.

Change-Id: I5d5044f9ff10da42aeb75dd4a556d6ab3d839b1a
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
main.cpp
qmljs_environment.cpp
qmljs_environment.h
qmljs_objects.cpp
qmljs_objects.h
qv4codegen.cpp
qv4codegen_p.h
qv4ecmaobjects.cpp

index 9090cd2..a516953 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -186,7 +186,7 @@ int compile(const QString &fileName, const QString &source, QQmlJS::LLVMOutputTy
 
     Codegen cg(0);
     // FIXME: if the program is empty, we should we generate an empty %entry, or give an error?
-    /*IR::Function *globalCode =*/ cg(program, &module);
+    /*IR::Function *globalCode =*/ cg(fileName, program, &module);
 
     int (*exec)(void *) = outputType == LLVMOutputJit ? executeLLVMCode : 0;
     return compileWithLLVM(&module, fileName, outputType, exec);
index ce1bf9d..94a8775 100644 (file)
@@ -39,6 +39,7 @@
 **
 ****************************************************************************/
 
+#include <QString>
 #include "debugging.h"
 #include <qmljs_environment.h>
 #include <qmljs_objects.h>
@@ -48,27 +49,30 @@ namespace QQmlJS {
 namespace VM {
 
 DiagnosticMessage::DiagnosticMessage()
-    : fileName(0)
-    , offset(0)
+    : offset(0)
     , length(0)
     , startLine(0)
     , startColumn(0)
     , type(0)
-    , message(0)
     , next(0)
 {}
 
+DiagnosticMessage::~DiagnosticMessage()
+{
+    delete next;
+}
+
 String *DiagnosticMessage::buildFullMessage(ExecutionContext *ctx) const
 {
     QString msg;
-    if (fileName)
-        msg = fileName->toQString() + QLatin1Char(':');
+    if (!fileName.isEmpty())
+        msg = fileName + QLatin1Char(':');
     msg += QString::number(startLine) + QLatin1Char(':') + QString::number(startColumn) + QLatin1String(": ");
     if (type == QQmlJS::VM::DiagnosticMessage::Error)
         msg += QLatin1String("error");
     else
         msg += QLatin1String("warning");
-    msg += ": " + message->toQString();
+    msg += ": " + message;
 
     return ctx->engine->newString(msg);
 }
index 3457771..eb10b66 100644 (file)
@@ -56,16 +56,17 @@ struct DiagnosticMessage
 {
     enum { Error, Warning };
 
-    String *fileName;
+    QString fileName;
     quint32 offset;
     quint32 length;
     quint32 startLine;
     unsigned startColumn: 31;
     unsigned type: 1;
-    String *message;
+    QString message;
     DiagnosticMessage *next;
 
     DiagnosticMessage();
+    ~DiagnosticMessage();
     String *buildFullMessage(ExecutionContext *ctx) const;
 };
 
index e2cb5cf..f12999b 100644 (file)
@@ -543,14 +543,14 @@ QQmlJS::IR::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ct
         VM::DiagnosticMessage *error = 0, **errIt = &error;
         foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
             if (m.isError()) {
-                *errIt = new VM::DiagnosticMessage; // FIXME: should we ask the engine to create this object?
-                (*errIt)->fileName = ctx->engine->newString(fileName);
+                *errIt = new VM::DiagnosticMessage;
+                (*errIt)->fileName = fileName;
                 (*errIt)->offset = m.loc.offset;
                 (*errIt)->length = m.loc.length;
                 (*errIt)->startLine = m.loc.startLine;
                 (*errIt)->startColumn = m.loc.startColumn;
                 (*errIt)->type = VM::DiagnosticMessage::Error;
-                (*errIt)->message = ctx->engine->newString(m.message);
+                (*errIt)->message = m.message;
                 errIt = &(*errIt)->next;
             } else {
                 std::cerr << qPrintable(fileName) << ':' << m.loc.startLine << ':' << m.loc.startColumn
@@ -570,7 +570,7 @@ QQmlJS::IR::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ct
             }
 
             Codegen cg(ctx);
-            globalCode = cg(program, &module, mode);
+            globalCode = cg(fileName, program, &module, mode);
             if (globalCode) {
                 // only generate other functions if global code generation succeeded.
                 foreach (IR::Function *function, module.functions) {
index cd9c243..2590b01 100644 (file)
@@ -94,9 +94,6 @@ struct TypeErrorPrototype;
 struct URIErrorPrototype;
 
 struct String {
-    String(const QString &text)
-        : _text(text), _hashValue(0) {}
-
     inline bool isEqualTo(const String *other) const {
         if (this == other)
             return true;
@@ -117,6 +114,11 @@ struct String {
     }
 
 private:
+    friend struct StringPool;
+    String(const QString &text)
+        : _text(text), _hashValue(0) {}
+
+private:
     QString _text;
     mutable unsigned _hashValue;
 };
@@ -613,6 +615,7 @@ struct ReferenceErrorObject: ErrorObject {
 
 struct SyntaxErrorObject: ErrorObject {
     SyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *msg);
+    ~SyntaxErrorObject() { delete msg; }
     virtual QString className() { return QStringLiteral("SyntaxError"); }
 
     virtual SyntaxErrorObject *asSyntaxError() { return this; }
index 893bbb1..34c785d 100644 (file)
@@ -371,10 +371,11 @@ Codegen::Codegen(VM::ExecutionContext *context)
 {
 }
 
-IR::Function *Codegen::operator()(Program *node, IR::Module *module, Mode mode)
+IR::Function *Codegen::operator()(const QString &fileName, Program *node, IR::Module *module, Mode mode)
 {
     assert(node);
 
+    _fileName = fileName;
     _module = module;
     _env = 0;
 
@@ -399,8 +400,9 @@ IR::Function *Codegen::operator()(Program *node, IR::Module *module, Mode mode)
     return globalCode;
 }
 
-IR::Function *Codegen::operator()(AST::FunctionExpression *ast, IR::Module *module)
+IR::Function *Codegen::operator()(const QString &fileName, AST::FunctionExpression *ast, IR::Module *module)
 {
+    _fileName = fileName;
     _module = module;
     _env = 0;
 
@@ -2270,9 +2272,10 @@ bool Codegen::visit(UiSourceElement *)
 void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
 {
     VM::DiagnosticMessage *msg = new VM::DiagnosticMessage;
+    msg->fileName = _fileName;
     msg->offset = loc.begin();
     msg->startLine = loc.startLine;
     msg->startColumn = loc.startColumn;
-    msg->message = new VM::String(detail);
+    msg->message = detail;
     _context->throwSyntaxError(msg);
 }
index f1dca06..474e558 100644 (file)
@@ -69,8 +69,8 @@ public:
         FunctionCode
     };
 
-    IR::Function *operator()(AST::Program *ast, IR::Module *module, Mode mode = GlobalCode);
-    IR::Function *operator()(AST::FunctionExpression *ast, IR::Module *module);
+    IR::Function *operator()(const QString &fileName, AST::Program *ast, IR::Module *module, Mode mode = GlobalCode);
+    IR::Function *operator()(const QString &fileName, AST::FunctionExpression *ast, IR::Module *module);
 
 protected:
     enum Format { ex, cx, nx };
@@ -336,6 +336,7 @@ protected:
     void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail);
 
 private:
+    QString _fileName;
     Result _expr;
     QString _property;
     UiMember _uiMember;
index 99375d2..607c1f1 100644 (file)
@@ -1893,7 +1893,7 @@ Value FunctionCtor::construct(ExecutionContext *ctx)
     IR::Module module;
 
     Codegen cg(ctx);
-    IR::Function *irf = cg(fe, &module);
+    IR::Function *irf = cg(QString(), fe, &module);
 
     EvalInstructionSelection *isel = ctx->engine->iselFactory->create(ctx->engine);
     isel->run(irf);
@@ -2779,16 +2779,14 @@ Value ErrorPrototype::method_toString(ExecutionContext *ctx)
     if (!o)
         __qmljs_throw_type_error(ctx);
 
-    String n(QString::fromLatin1("name"));
-    Value name = o->__get__(ctx, &n);
+    Value name = o->__get__(ctx, ctx->engine->newString(QString::fromLatin1("name")));
     QString qname;
     if (name.isUndefined())
         qname = QString::fromLatin1("Error");
     else
         qname = __qmljs_to_string(name, ctx).stringValue()->toQString();
 
-    String m(QString::fromLatin1("message"));
-    Value message = o->__get__(ctx, &m);
+    Value message = o->__get__(ctx, ctx->engine->newString(QString::fromLatin1("message")));
     QString qmessage;
     if (!message.isUndefined())
         qmessage = __qmljs_to_string(message, ctx).stringValue()->toQString();