Prepare MASM for better runtime string handling
authorSimon Hausmann <simon.hausmann@digia.com>
Thu, 15 Aug 2013 08:36:41 +0000 (10:36 +0200)
committerSimon Hausmann <simon.hausmann@digia.com>
Thu, 15 Aug 2013 11:56:07 +0000 (13:56 +0200)
Keep the run-time functions as-is by taking String pointers and use a little
bit of inline assembly to resolve the string ids to string pointers, by
adding a runtimeStrings array pointer next to the lookups in the context
(similar mechanism).

Change-Id: Ib5a70bdf47fef7c447d646ccfe03f3dc30d39f20
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/qml/compiler/qv4compileddata.cpp
src/qml/compiler/qv4compileddata_p.h
src/qml/compiler/qv4isel_masm.cpp
src/qml/compiler/qv4isel_masm_p.h
src/qml/compiler/qv4isel_p.h
src/qml/jsruntime/qv4context.cpp
src/qml/jsruntime/qv4context_p.h
src/qml/jsruntime/qv4runtime.cpp
src/qml/jsruntime/qv4runtime_p.h
src/qml/jsruntime/qv4script.cpp

index 2a39f62..a1a355b 100644 (file)
@@ -56,16 +56,16 @@ int Function::calculateSize(QQmlJS::V4IR::Function *f)
 CompilationUnit::~CompilationUnit()
 {
     free(data);
-    free(runtimeIdentifiers);
+    free(runtimeStrings);
 }
 
 QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
 {
-    assert(!runtimeIdentifiers);
+    assert(!runtimeStrings);
     assert(data);
-    runtimeIdentifiers = (QV4::String**)malloc(data->stringTableSize * sizeof(QV4::String*));
+    runtimeStrings = (QV4::String**)malloc(data->stringTableSize * sizeof(QV4::String*));
     for (int i = 0; i < data->stringTableSize; ++i)
-        runtimeIdentifiers[i] = engine->newIdentifier(data->stringAt(i)->qString());
+        runtimeStrings[i] = engine->newIdentifier(data->stringAt(i)->qString());
 
     return linkBackendToEngine(engine);
 }
index c70fa69..c9d5520 100644 (file)
@@ -239,7 +239,7 @@ struct CompilationUnit
     CompilationUnit()
         : refCount(0)
         , data(0)
-        , runtimeIdentifiers(0)
+        , runtimeStrings(0)
     {}
     virtual ~CompilationUnit();
 
@@ -251,7 +251,7 @@ struct CompilationUnit
 
     QString fileName() const { return data->stringAt(data->sourceFileIndex)->qString(); }
 
-    QV4::String **runtimeIdentifiers; // Array
+    QV4::String **runtimeStrings; // Array
 
     QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
 
index 29f2343..248dc78 100644 (file)
@@ -208,8 +208,8 @@ const int Assembler::calleeSavedRegisterCount = sizeof(calleeSavedRegisters) / s
 
 const Assembler::VoidType Assembler::Void;
 
-Assembler::Assembler(V4IR::Function* function, QV4::Function *vmFunction, QV4::ExecutionEngine *engine)
-    : _function(function), _vmFunction(vmFunction), _engine(engine), _nextBlock(0)
+Assembler::Assembler(InstructionSelection *isel, V4IR::Function* function, QV4::Function *vmFunction, QV4::ExecutionEngine *engine)
+    : _function(function), _vmFunction(vmFunction), _isel(isel), _engine(engine), _nextBlock(0)
 {
 }
 
@@ -281,6 +281,13 @@ Assembler::Pointer Assembler::loadTempAddress(RegisterID reg, V4IR::Temp *t)
     return Pointer(reg, offset);
 }
 
+Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &string)
+{
+    loadPtr(Address(Assembler::ContextRegister, offsetof(QV4::ExecutionContext, runtimeStrings)), reg);
+    const int id = _isel->stringId(string);
+    return Pointer(reg, id * sizeof(QV4::String*));
+}
+
 template <typename Result, typename Source>
 void Assembler::copyValue(Result result, Source source)
 {
@@ -691,7 +698,7 @@ void InstructionSelection::run(QV4::Function *vmFunction, V4IR::Function *functi
     qSwap(_lookups, lookups);
     qSwap(_reentryBlocks, reentryBlocks);
     Assembler* oldAssembler = _as;
-    _as = new Assembler(_function, _vmFunction, engine());
+    _as = new Assembler(this, _function, _vmFunction, engine());
 
     V4IR::Optimizer opt(_function);
     opt.run();
@@ -1052,8 +1059,7 @@ void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targe
 
 void InstructionSelection::loadString(const QString &str, V4IR::Temp *targetTemp)
 {
-    int id = stringId(str);
-    generateFunctionCall(Assembler::Void, __qmljs_resolve_string_as_value, Assembler::ContextRegister, Assembler::PointerToValue(targetTemp), Assembler::TrustedImm32(id));
+    generateFunctionCall(Assembler::Void, __qmljs_value_from_string, Assembler::PointerToValue(targetTemp), Assembler::PointerToString(str));
 }
 
 void InstructionSelection::loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp)
index 8c55f41..b67386d 100644 (file)
@@ -59,6 +59,8 @@ QT_BEGIN_NAMESPACE
 namespace QQmlJS {
 namespace MASM {
 
+class InstructionSelection;
+
 struct CompilationUnit : public QV4::CompiledData::CompilationUnit
 {
     virtual QV4::Function *linkBackendToEngine(QV4::ExecutionEngine *engine);
@@ -74,7 +76,7 @@ struct CompilationUnit : public QV4::CompiledData::CompilationUnit
 class Assembler : public JSC::MacroAssembler
 {
 public:
-    Assembler(V4IR::Function* function, QV4::Function *vmFunction, QV4::ExecutionEngine *engine);
+    Assembler(InstructionSelection *isel, V4IR::Function* function, QV4::Function *vmFunction, QV4::ExecutionEngine *engine);
 #if CPU(X86)
 
 #undef VALUE_FITS_IN_REGISTER
@@ -258,6 +260,10 @@ public:
         PointerToValue(V4IR::Temp *value) : value(value) {}
         V4IR::Temp *value;
     };
+    struct PointerToString {
+        explicit PointerToString(const QString &string) : string(string) {}
+        QString string;
+    };
     struct Reference {
         Reference(V4IR::Temp *value) : value(value) {}
         V4IR::Temp *value;
@@ -287,6 +293,7 @@ public:
     void addPatch(DataLabelPtr patch, V4IR::BasicBlock *target);
 
     Pointer loadTempAddress(RegisterID reg, V4IR::Temp *t);
+    Pointer loadStringAddress(RegisterID reg, const QString &string);
 
     void loadArgumentInRegister(RegisterID source, RegisterID dest)
     {
@@ -312,6 +319,11 @@ public:
             loadArgumentInRegister(addr, dest);
         }
     }
+    void loadArgumentInRegister(PointerToString temp, RegisterID dest)
+    {
+        Pointer addr = loadStringAddress(dest, temp.string);
+        loadPtr(addr, dest);
+    }
 
     void loadArgumentInRegister(Reference temp, RegisterID dest)
     {
@@ -432,6 +444,14 @@ public:
     }
 
     template <int StackSlot>
+    void loadArgumentOnStack(PointerToString temp)
+    {
+        Pointer ptr = loadStringAddress(ScratchRegister, temp.string);
+        loadPtr(ptr, ScratchRegister);
+        poke(ScratchRegister, StackSlot);
+    }
+
+    template <int StackSlot>
     void loadArgumentOnStack(Reference temp)
     {
         assert (temp.value);
@@ -780,6 +800,7 @@ private:
     V4IR::BasicBlock *_nextBlock;
 
     QV4::ExecutionEngine *_engine;
+    InstructionSelection *_isel;
 
     struct CodeLineNumerMapping
     {
index ef0cd06..1e1d72d 100644 (file)
@@ -69,14 +69,14 @@ public:
 
     void setUseFastLookups(bool b) { useFastLookups = b; }
 
+    int stringId(const QString &str) { return jsUnitGenerator.registerString(str); }
+
 protected:
     QV4::Function *createFunctionMapping(QV4::Function *outer, V4IR::Function *irFunction);
     QV4::ExecutionEngine *engine() const { return _engine; }
     virtual void run(QV4::Function *vmFunction, V4IR::Function *function) = 0;
     virtual QV4::CompiledData::CompilationUnit *backendCompileStep() { return 0; }
 
-    int stringId(const QString &str) { return jsUnitGenerator.registerString(str); }
-
 private:
     QV4::ExecutionEngine *_engine;
 protected:
index 633ad2e..f6ba986 100644 (file)
@@ -138,6 +138,7 @@ void WithContext::initWithContext(ExecutionContext *p, Object *with)
     thisObject = p->thisObject;
     outer = p;
     lookups = p->lookups;
+    runtimeStrings = p->runtimeStrings;
 
     withObject = with;
 }
@@ -149,6 +150,7 @@ void CatchContext::initCatchContext(ExecutionContext *p, String *exceptionVarNam
     thisObject = p->thisObject;
     outer = p;
     lookups = p->lookups;
+    runtimeStrings = p->runtimeStrings;
 
     this->exceptionVarName = exceptionVarName;
     this->exceptionValue = exceptionValue;
@@ -172,8 +174,10 @@ void CallContext::initCallContext(ExecutionContext *parentContext, FunctionObjec
 
     activation = 0;
 
-    if (function->function)
+    if (function->function) {
         lookups = function->function->lookups;
+        runtimeStrings = function->function->compilationUnit->runtimeStrings;
+    }
 
     uint argc = argumentCount;
 
@@ -220,6 +224,7 @@ void CallContext::initQmlContext(ExecutionContext *parentContext, Object *qml, F
     activation = qml;
 
     lookups = function->function->lookups;
+    runtimeStrings = function->function->compilationUnit->runtimeStrings;
 
     locals = (Value *)(this + 1);
     if (function->varCount)
index dfe02bd..3bae120 100644 (file)
@@ -94,6 +94,7 @@ struct Q_QML_EXPORT ExecutionContext
     ExecutionContext *parent;
     ExecutionContext *outer;
     Lookup *lookups;
+    String **runtimeStrings;
     ExecutionContext *next; // used in the GC
 
     struct EvalCode
@@ -115,6 +116,7 @@ struct Q_QML_EXPORT ExecutionContext
         parent = parentContext;
         outer = 0;
         lookups = 0;
+        runtimeStrings = 0;
         currentEvalCode = 0;
         interpreterInstructionPointer = 0;
     }
index 210a6c4..8dcf65a 100644 (file)
@@ -1221,16 +1221,9 @@ void __qmljs_decrement(Value *result, const Value &value)
     }
 }
 
-String *__qmljs_resolve_string(ExecutionContext *ctx, int stringId)
+void __qmljs_value_from_string(Value *result, String *string)
 {
-    QV4::CallContext *callCtx = ctx->asCallContext();
-    QV4::Function *fun = callCtx ? callCtx->function->function : ctx->engine->globalCode;
-    return fun->compilationUnit->runtimeIdentifiers[stringId];
-}
-
-void __qmljs_resolve_string_as_value(ExecutionContext *ctx, Value *result, int stringId)
-{
-    *result = Value::fromString(__qmljs_resolve_string(ctx, stringId));
+    *result = Value::fromString(string);
 }
 
 } // namespace QV4
index 6cac111..31ee819 100644 (file)
@@ -126,8 +126,7 @@ void __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, QV4::Value *array,
 void __qmljs_builtin_define_getter_setter(QV4::ExecutionContext *ctx, const QV4::Value &object, QV4::String *name, const QV4::Value *getter, const QV4::Value *setter);
 void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, QV4::InternalClass *klass);
 
-QV4::String *__qmljs_resolve_string(QV4::ExecutionContext *ctx, int stringId);
-void __qmljs_resolve_string_as_value(QV4::ExecutionContext *ctx, QV4::Value *result, int stringId);
+void __qmljs_value_from_string(QV4::Value *result, QV4::String *string);
 
 // constructors
 void __qmljs_init_closure(QV4::ExecutionContext *ctx, QV4::Value *result, QV4::Function *clos);
index 448d638..59b52c3 100644 (file)
@@ -201,17 +201,20 @@ Value Script::run()
         TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction);
 
         bool strict = scope->strictMode;
-        Lookup *lookups = scope->lookups;
+        Lookup *oldLookups = scope->lookups;
+        String **oldRuntimeStrings = scope->runtimeStrings;
 
         scope->strictMode = vmFunction->isStrict();
         scope->lookups = vmFunction->lookups;
+        scope->runtimeStrings = vmFunction->compilationUnit->runtimeStrings;
 
         QV4::Value result;
         try {
             result = vmFunction->code(scope, vmFunction->codeData);
         } catch (Exception &e) {
             scope->strictMode = strict;
-            scope->lookups = lookups;
+            scope->lookups = oldLookups;
+            scope->runtimeStrings = oldRuntimeStrings;
             throw;
         }