aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
Commit message (Collapse)AuthorAgeFilesLines
* Get rid of different macros for vtable specializationsLars Knoll2014-07-2222-99/+46
| | | | | | | Detect existence of a a vtable entry at compile time. Change-Id: Ieed5d34b063184bc4435b22c6685ac0e3fabf493 Reviewed-by: Simon Hausmann <[email protected]>
* Use Members for storing the bound arguments in BoundFunctionLars Knoll2014-07-225-12/+18
| | | | | | | | Cleans up the code, and allows us to remove the destructor for bound function objects. Change-Id: Id32ac69171f7975ec7679d07d25c0eb6b4ca6fb5 Reviewed-by: Simon Hausmann <[email protected]>
* Avoid calling destroy() on most objectsLars Knoll2014-07-2226-89/+76
| | | | | | | | | The method is now optional, and we can simply avoid calling it if all members an object has are themselves garbage collected. Change-Id: If560fce051908bcc10409ead1a7d8a5bd5fa71d2 Reviewed-by: Simon Hausmann <[email protected]>
* Fix Scoped<T> constructors/assignment operators that take a T*Simon Hausmann2014-07-222-3/+12
| | | | | | | | When assigning a null T*, we would not always set m correctly to zero but to undefinedValue() instead. Change-Id: Ia2a439f4a9946664d9835230869161a8499b1659 Reviewed-by: Lars Knoll <[email protected]>
* v4: Delay creating the ScopedValue/ScopedProperty in objectLiteralHolger Hans Peter Freyther2014-07-201-15/+19
| | | | | | | | | | | | | | | | Creating a ScopedValue/ScopedProperty is not free. It will use the ExecutionEngine directly to reserve memory from the JS Stack. In tests/manual/v4/v8-bench.js and bench-allocate-nonretained.js a lot of objects are created and the arrayValueCount and the arrayGetterSetterCount are 0. We can delay the creation for a small gain. When generating the code we already know the various sizes and could already call specialized versions of the creation code. The gain is not so clear though. Change-Id: Ic99b241f5506457e57611ad4eba143c56be1f657 Reviewed-by: Simon Hausmann <[email protected]>
* v4: Remove dead code ScriptFunction constructorHolger Hans Peter Freyther2014-07-201-6/+1
| | | | | | | | | Creating a Scope/ScopedValue will immediately access ExecutionEngine of the ExecutionContext so the null check is not needed here. Move the v4 variable into the scope that is using it. Change-Id: I9189ee9d1a63997119e49c12182dffefadc916f1 Reviewed-by: Simon Hausmann <[email protected]>
* v4: Manually inline the access to the execution engineHolger Hans Peter Freyther2014-07-202-14/+7
| | | | | | | | | | | | | | | | | | | | | | Executing an allocation heavy testcase of JavaScriptCore on my i7 Sandy Bridge notebook 6.85% is spent inside the ::engine() call as gcc 4.8.2 of Debian didn't inline the call. Inline the call sites by hand. I removed the protected ::engine() as it is now unused. $ time qmljs JavaScriptCore/tests/perf/bench-allocate-nonretained.js before (best run of three) real 0m2.234s user 0m2.228s sys 0m0.008s after (worse run of three) real 0m2.097s user 0m2.088s sys 0m0.008s Change-Id: I20b73b3b3dac630eb1d5e7d66bcb50c839630567 Reviewed-by: Simon Hausmann <[email protected]>
* Make sure JIT architectures lists are in syncDmitry Shachnev2014-07-071-2/+4
| | | | | | | | | We have two lists: in qv4global_p.h and qv4targetplatform_p.h. This commit blacklists OSes on x86 and x86_64 where JIT is not supported, improves support for FreeBSD and adds cross-references between these two files. Change-Id: Id3715a2ab717186e510a54e5a548dfa22120cd87 Reviewed-by: Erik Verbruggen <[email protected]>
* Profiler: Fix MSVC warning about signed integers.Friedemann Kleint2014-07-031-1/+1
| | | | | | | | | src\qml\jsruntime\qv4profiling_p.h(144) : warning C4146: unary minus operator applied to unsigned type, result still unsigned Introduced by ac56e7cda724aa7463ef6ffe5f0e93bd3208cb51 . Change-Id: Ib77234d663bfafd9d55ae2dd551b0aabd6561d6d Reviewed-by: Ulf Hermann <[email protected]>
* Merge remote-tracking branch 'origin/5.3' into devFrederik Gladhorn2014-07-021-0/+2
|\ | | | | | | | | | | | | | | | | | | Conflicts: .qmake.conf examples/quick/scenegraph/openglunderqml/squircle.h src/quick/doc/src/qmltypereference.qdoc src/quick/scenegraph/qsgthreadedrenderloop.cpp Change-Id: Ife4f4b897044a7ffcd0710493c6aed1d87cf1ef9
| * Fix crash in QObjectWrapperOleg Shparber2014-06-191-0/+2
| | | | | | | | | | | | | | | | | | | | | | This can happen during QObject destruction, when QObjectPrivate::deleteChildren() itself sets entries in the children list to zero when deleting. These zeros cause crash in markChildQObjectsRecursively(). Task-number: QTBUG-38635 Change-Id: I29ad9e793b78ca4e8d73fbb125f46db1b8292f20 Reviewed-by: Alan Alpert <[email protected]>
* | Remove redundant sse2 math flagsAllan Sandfeld Jensen2014-07-011-7/+0
| | | | | | | | | | | | | | | | | | Qtbase already enables sse2 math by default now. This version is no longer needed and may actually hurt performance by triggering scheduling for pentium4. Change-Id: Ib3b6781fb0b92c1351344cc2d2f13101fa2b632b Reviewed-by: Thiago Macieira <[email protected]>
* | Exclude private methods and QObject::deleteLater from enumerable propertiesSimon Hausmann2014-06-241-2/+11
| | | | | | | | | | | | | | | | | | | | | | This is a regression from Qt 5.1/5.0 introduced with 5.2. Private slots/methods such as QObject::_q_reRegisterTimers() as well as QObject::deleteLater() are not suitable for calls from JavaScript. deleteLater() in particular is covered by the destroy() replacement slot. Task-number: QTBUG-39744 Change-Id: I9b25f3c0d4095ba8e2e8e5ee47e37903b5def1f9 Reviewed-by: Michael Brasser <[email protected]>
* | Fix compiler warningLars Knoll2014-06-181-1/+2
| | | | | | | | | | Change-Id: I26df4f1b8417c6b075d81eaf118669a4103503e2 Reviewed-by: Simon Hausmann <[email protected]>
* | Merge remote-tracking branch 'origin/5.3' into devSimon Hausmann2014-06-131-4/+4
|\| | | | | | | | | | | | | Conflicts: src/quickwidgets/qquickwidget.cpp Change-Id: Id4b080aea713df68608847bb82570231e37ce536
| * Fix method overload calling of Qt slots from JavaScriptkh12014-06-041-4/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | After commit ac57f185d1a2203cd4b585df7bd7af01c3ec33ed we succeed in selecting the correct overload based on the supplied arguments. However when calling slots on objects without a property cache, we end up using the local "dummy" variable to store the synthetic propert data. We also store the currently best patch in the "best" variable, which is a _pointer_ to the property data of the match. Suppose we have 5 overloads to choose from, we find that the 3rd is the best. Then we try the fourth but find it unsufficient and break out of the loop. Unfortunately the "dummy" property data at this point contains the data of the fourth (wrong) overload, and our best match variable points to it. So then when we finally call the method, we do it based on the wrong property data. The easy patch is to simply copy the few bytes of property data, so "best" is stored by value instead of pointer. Change-Id: Ie2ebbdb88a117770b6c7b9490e1c634077020e9d Reviewed-by: Karsten Heimrich <[email protected]>
* | Properly initialize heap profiler when starting profilingUlf Hermann2014-06-125-10/+45
| | | | | | | | | | Change-Id: Ia994464b2150dc9a9185280ae0e2f8c615393310 Reviewed-by: Simon Hausmann <[email protected]>
* | Javascript heap profilerUlf Hermann2014-06-064-6/+60
| | | | | | | | | | | | | | | | | | This profiler tracks every memory allocation and deallocation, by the MemoryManager as well as the V4 VM, and exposes them as a stream of events to the profiler service. Change-Id: I85297d498f0a7eb55df5d7829c4b7307de980519 Reviewed-by: Simon Hausmann <[email protected]>
* | Rework custom parser integrationSimon Hausmann2014-06-041-1/+1
|/ | | | | | | | | | | | | | | | | | | | | | | The custom parser design used to be so that the custom parser operates on the "AST", creates its own binary representation of the data it needs, stores it in a QByteArray and gets that at object instantiation time. That meant serializing everything necessary. With the introduction of the "binary" QML data structure, that process of serialization becomes obsolete and would require extra work in the custom parsers for example for QQuickStates to store the translation parameters. The clean solution is to eliminate this unnecessary serialization process and instead let the custom parsers do a verification pass at type compile time and then simply operate directly on the QV4::CompiledData::Bindings at object instantiation time. That simplifies the code, and allows for support of translations throughout all list model properties. Additionally this speeds up the creation of state objects and reduces memory consumption. Previously a text: qsTr("foo") binding in states would result in an actual java script binding. After this patch it is merely stored as a string and translated at object instantiation time. Change-Id: I7550274513f54abb09a0ab4de51c4c0bcdb23cae Reviewed-by: Lars Knoll <[email protected]>
* Fix failing assertion inside MSVC STL in debug buildsSimon Hausmann2014-05-211-2/+2
| | | | | | | | | | | | | | | When using FunctionObject's call() method, we use std::copy to copy the arguments over to the new call context. Unfortunately std::copy has an assertion in there to check that we're not copying out of bounds. What the STL doesn't know is that the Value args[1] array is dynamically allocated and easily expands beyond just one entry. Fall back to copying by hand to work around this issue. Task-number: QTBUG-38195 Change-Id: I6e254b1c893ccf5cad2358179cda1b07b00228e0 Reviewed-by: Friedemann Kleint <[email protected]> Reviewed-by: Lars Knoll <[email protected]>
* Fix Number.toExponential with parameterSimon Hausmann2014-05-211-1/+1
| | | | | | | | | | The fractionDigits parameter was unfortunately ignored, due to an accidental double variable declaration, the latter in a narrower scope shadowing the former in the correct scope. Task-number: QTBUG-38577 Change-Id: I28f35466d2d744e84b86a3ca6b3371eb86869b55 Reviewed-by: Lars Knoll <[email protected]>
* Merge remote-tracking branch 'origin/release' into stableIikka Eklund2014-05-201-4/+7
|\ | | | | | | Change-Id: I939d6b9d10b3f50d9024b80d7a215b8fd04e8d56
| * Android: Fix crash in String.replace() in release buildsv5.3.0-rc1Eskil Abrahamsen Blomfeldt2014-05-051-4/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When enabling optimizations in the compiler, it produces bogus code for the regExp->value deref in the line nMatchOffsets += regExp->value->captureCount() * 2 This is a random refactoring to work around the compiler bug. The only line that actually needs to be touched is the one mentioned above, but I replaced all uses of regExp->value so that it wouldn't look too weird. Task-number: QTBUG-38692 Change-Id: Ib33a523a86ce51ebc6c7095a803fedaebcaa8e63 Reviewed-by: Lars Knoll <[email protected]> Reviewed-by: Simon Hausmann <[email protected]>
* | Merge remote-tracking branch 'origin/release' into stableFrederik Gladhorn2014-05-0116-68/+201
|\| | | | | | | Change-Id: I996a85744753598bb48c7e0d7954049202f4f037
| * v4: ignore quiet bit for NaNs in 32 bit value encodingFawzi Mohamed2014-04-301-10/+11
| | | | | | | | | | | | | | | | | | | | | | on iOS x % 0 generates a NaN with the silent bit set, i.e. 0x7ffc_0000_0000_0000 which was interpreted as a null managed object which crashed the interpreter. Task-number: QTBUG-36859 Change-Id: Idf31ad9f0454f83d321b49b2f76bdbc2ee906189 Reviewed-by: Simon Hausmann <[email protected]> Reviewed-by: Lars Knoll <[email protected]>
| * v4: assert when an unsupported double value is stored in a valueFawzi Mohamed2014-04-301-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | we assume that just few NaN values can be generated by the HW (currently 0x7ff800..00 and 0x7ffc00..00), and we use the other values to encode js values. If uninitialized memory is interpreted as double or another NaN is explicitly constructed and feed to the interpreter, it might crash (later when actually accessing that value). Adding an assertion to catch those values when assertions are active for the 32 bit encoding (64 bit already has it). Task-number: QTBUG-36859 Change-Id: I7ac7b2619f286ba19066729836af718014a515a6 Reviewed-by: Johannes Matokic <[email protected]> Reviewed-by: Simon Hausmann <[email protected]> Reviewed-by: Lars Knoll <[email protected]>
| * Fix marking of prototype objects in internal class poolSimon Hausmann2014-04-284-17/+34
| | | | | | | | | | | | | | | | | | | | As per reported bug, we have to protect ourselves against potential loops and can mark the internal classes much simpler by just walking through the memory pool they were allocated in. Task-number: QTBUG-38299 Change-Id: I3ae96e8082e76d06f4321c5aa6d2e9645d2830a0 Reviewed-by: Lars Knoll <[email protected]>
| * Extend the QML bootstrap library by the IR buildersSimon Hausmann2014-04-2312-39/+154
| | | | | | | | | | | | | | | | | | | | | | | | | | This is among other things needed to fix the qml import scanner to detect dependencies from .js files correctly. The patch also fixes the use of Q_QML_EXPORT towards Q_QML_PRIVATE_EXPORT where appropriate and corrects the wrong include path for the double conversion code to actually be relative to the file it is included from. This worked by accident because of other include paths present in the build. Change-Id: I338583dad2f76300819af8ab0dae8e5724c84430 Reviewed-by: Lars Knoll <[email protected]>
* | Remove unneeded ;Albert Astals Cid2014-04-253-4/+4
| | | | | | | | | | | | | | Warnings returned by pedantic Change-Id: Ic2caba475db9064bf302790299d92a217436d0ee Reviewed-by: Simon Hausmann <[email protected]>
* | Merge "Merge remote-tracking branch 'origin/release' into stable" into ↵Tony Sarajärvi2014-04-241-1/+1
|\| | | | | | | refs/staging/stable
| * Refine fix for dynamic properties on QObjects wrapped in JavaScriptSimon Hausmann2014-04-171-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | This is an ammendment to commit 60730cbb5e5475b5db6a15641211aa6958a93197 to further restrict the ability to set dynamic properties on JS wrapped QObjects only on those that are associated with a qml context. Only one such association comes with the static property lookup rules of QML and therefore only those should be prohibited from dynamic properties. The previous implementation on using the "compiledData" field to detect QML association or not is not strong and reliable enough. Change-Id: I10c0e6e58a2727c01a6cb56fdf912bf250333e1f Reviewed-by: Jędrzej Nowacki <[email protected]>
* | Fix time zone calculationFabian Bumberger2014-04-241-1/+1
|/ | | | | | | | | | | | The result of local time minus global time might be negative. On QNX time_t is defined as unsigned int and thus the subtraction will not produce the expected result. This patch converts the local time and the global time to double before subtracting them. Task-number: QTBUG-35693 Change-Id: Ifa442b242a4aa23c59fa427015346150b89c9343 Reviewed-by: Simon Hausmann <[email protected]>
* Reduce memory pressure on JS stack when garbage collectingSimon Hausmann2014-04-091-3/+8
| | | | | | | | | | | | As the identifier table grows with long running programs, we may end up allocating more identifiers than we have space left on the JS stack for them alongside all the other objects in the environment. To mitigate this, we can simply treat the identifiers as roots, mark them manually and only end up putting sub-strings onto the JS stack if necessary. Task-number: QTBUG-36183 Change-Id: Ie6994555305c84b007860792d066a8df60089847 Reviewed-by: Lars Knoll <[email protected]>
* Fix unreliable behavior of array methods on qml list propertiesSimon Hausmann2014-04-091-0/+2
| | | | | | | | | | | Array methods such as forEach rely on the hasProperty boolean of getIndexed to be set appropriately. Some getIndexed implementation - such as the QQmlListProperty one - didn't initialize it correctly and therefore the behavior was undefined. Task-number: QTBUG-38088 Change-Id: I34bc3136d8cc2bc280397d0c4d5051e7d72269e8 Reviewed-by: Lars Knoll <[email protected]>
* Add support for dynamic properties for QObjects in JavaScriptSimon Hausmann2014-04-091-3/+10
| | | | | | | | | | | | | | | | | In QtScript you could add properties to a JS object that wraps a QObject. Depending on the wrap option the property was either stored on the JavaScript side or as dynamic QObject property. In QJSEngine/QJSValue, neither was supported - properties could not be added. For QObjects wrapped in JavaScript that weren't created by QML, we can restore the behavior of storing dynamically added properties as JavaScript properties. This makes porting from QtScript to QJS* much easier. Task-number: QTBUG-37408 Change-Id: I5ef1f379c08c3d84de9bdcac9b6a9397238064de Reviewed-by: Jędrzej Nowacki <[email protected]> Reviewed-by: Lars Knoll <[email protected]>
* Fix marking of prototype objects in chainSimon Hausmann2014-04-071-9/+6
| | | | | | | | | | | | | | | | With a real prototype chain it can happen that an internal class' prototype's class itself has a prototype. Therefore the first transition on the empty class is a PrototypeChange one, but the class the transition leads to may have PrototypeChange transitions itself, which weren't marked. There are multiple solutions to this, but this patch is the minimal fix by recursing fully through the internal class tree. That way it's easier to back-port the fix also into 5.2.x based branches. Task-number: QTBUG-37834 Change-Id: I901b13a2663fbad5844003ca5752f2f304de320c Reviewed-by: Lars Knoll <[email protected]>
* Make the destroy method optionalLars Knoll2014-04-041-4/+5
| | | | | | | | | | | | This allows us to avoid calling a destructor on objects that don't require one. After the memberData change this should be most objects. Also fix a bug where we didn't call the destroy() method on large objects, potentially leaking memory. Change-Id: I1708055d568d85b0a3876899d35e8c3eb92dd222 Reviewed-by: Simon Hausmann <[email protected]>
* Garbage collect member dataLars Knoll2014-04-0412-43/+207
| | | | | | | | Move the allocated member data into the garbage collected area, so that we can avoid using malloc/free for it. Change-Id: I20625efa67ecd60238568742b74854b0c8cb2e3e Reviewed-by: Simon Hausmann <[email protected]>
* Fix 'missing header' compilation error (shadow build)Kai Koehne2014-04-031-1/+1
| | | | | | | | Change the private header path to the canonical one. This fixes shadow builds for me on Windows. Change-Id: I7c18ec2d9f0769a51d296deac16c78ae41894c36 Reviewed-by: Simon Hausmann <[email protected]>
* Avoid recompiling of signal handlers defined in QtQuick state changes and ↵Simon Hausmann2014-04-022-2/+25
| | | | | | | | | | Connection objects We can re-use the expression we've compiled at QML type compilation time, as long as we "inject" the signal parameters in the dynamic qml lookup chain. Change-Id: Icc417531c41dea06ff5d033011179af49b03f542 Reviewed-by: Lars Knoll <[email protected]>
* Fix compilation of script stringsSimon Hausmann2014-04-022-3/+19
| | | | | | | | | | | | | | | | | | | | | | | | | The right hand side of script string properties can be evaluated in entirely dynamic scopes, due to QQmlExpressions' public API of allowing construction from a QQmlScriptString and a variable scope/context. Nevertheless we should compile these bindings at type compile time, as long as we make sure that the compiled code doesn't try to do any compile time determined property lookups and type resolution. This is implemented using a separate compilation pass that ensures the disableAcceleratedLookups flag is set. A few minor cleanups come with this patch: * Ensure that the property caches array is always symmetric to the list of compiled QML objects, as that allows the use of at() instead of value(). * The code for creating a QML callable function object for a given run-time function is now centralized in a static function QmlBindingWrapper, used for script strings and bindings from custom parsers. The provided unit test verifies the successful execution of the same script string with two different scope objects. Change-Id: Ica2cea46dd9e47263b4d494d922d3cc9664b08ae Reviewed-by: Michael Brasser <[email protected]> Reviewed-by: Lars Knoll <[email protected]>
* Move inline function Bool Runtime::compareEqual() above usage.Friedemann Kleint2014-04-011-19/+19
| | | | | | | | | | Fix MinGW-warnings: src/qml/jsruntime/qv4runtime_p.h:496:13: warning: 'static QV4::Bool QV4::Runtime::compareEqual(QV4::ValueRef, QV4::ValueRef)' redeclared without dllimport attribute after being referenced with dll linkage Change-Id: Ieb212ed6aba2a0deeeddd033126ae7e9737bb38e Reviewed-by: Simon Hausmann <[email protected]>
* Making the CHUNKSIZE setable via environment variableKarim Pinter2014-04-011-4/+8
| | | | | | | | | With this modification the CHUNKSIZE is setable by QV4_MM_MAX_CHUNK_SIZE environment variable so the memory usage which is important for embedded devices can be finetuned. Change-Id: I3cd75158f2255651edd341873de035c1222e3c92 Reviewed-by: Lars Knoll <[email protected]>
* Fix typoSimon Hausmann2014-04-014-5/+5
| | | | | | | creatScriptFunction -> createScriptFunction Change-Id: Icdb9214b1ae067fa2b8693d50cdac0be9fe6d390 Reviewed-by: Michael Brasser <[email protected]>
* Fix crash in sparse array handlingSimon Hausmann2014-03-281-12/+13
| | | | | | | | | | | | When re-allocating the sparse array data, make sure to initialize the free list correctly. Previously this was only done for the first allocation. Test cases uses an object literal, as that's a reliable way to ensure a sparse array is created. Task-number: QTBUG-37892 Change-Id: Ib38cfce50104904af0c980f022c9dbb7461ae5f8 Reviewed-by: Lars Knoll <[email protected]>
* Fix interpreter math routines.Erik Verbruggen2014-03-281-6/+9
| | | | | | | | | | | | | | | | This: qint64 result = a + b; is not equal to: qint64 result = static_cast<qint64>(a) + b; So checking if the former will overflow, and then doing the "double case", will get thrown out by an optimizing compiler. While we're in the area, optimize the X86 case a bit too. Change-Id: Idfb69b16dbaaa0ae9f013a430ff060ca789526ba Reviewed-by: Simon Hausmann <[email protected]> Reviewed-by: Lars Knoll <[email protected]>
* Fix double deletionSimon Hausmann2014-03-281-1/+1
| | | | | | | | | | | | | | Small regression from commit 7ae796cb141b73a1b215b2b0fd64b7ffbbd1e510. Processing the deletables might result in the onDestruction emission, which in turn may end up in GC allocation and thus GC runs. That in turn may result in m_deletables processing, which at this point is nested then. For that to work we need to set m_deletables back to zero _before_ beginning with the iteration. Fixes tst_qqmlecmascript with aggressive gc. Change-Id: Ibb310b30cd496644557f4c1bb23318b18ee8f36c Reviewed-by: Lars Knoll <[email protected]>
* Fix QtSharedPointer::ExternalRefCountData object leak in v4 engineLiang Jian2014-03-281-4/+5
| | | | | | | | | | | | Always call ~QObjectWrapper() to the wrapper object in QObjectWrapper::destroy(), otherwise the m_object member of QObjectWrapper may still hold a QtSharedPointer::ExternalRefCountData object which will never been deleted. I don't know why this will not cause leak in the past, but it seems that the leak was introduced in 7ae796cb141b73a1b215b2b0fd64b7ffbbd1e510 Change-Id: I24b49bb11f95b7e3060c7adba1ab80b615da2942 Reviewed-by: Simon Hausmann <[email protected]>
* Be a bit more conservative with allocating memoryLars Knoll2014-03-271-2/+2
| | | | | | | | | | Cap the max chunk size at 2MB. This value still still doesn't affect the v8 benchmark noticably, but should avoid extreme memory usage in some corner cases Task-number: QTBUG-37134 Change-Id: If2050374c4a7df7ff74194d64880e2d660ea26fd Reviewed-by: Simon Hausmann <[email protected]>
* Remove the scribble option from the memory managerLars Knoll2014-03-271-7/+0
| | | | | | | | This option doesn't make sense anymore, as we memset the object to 0 on destruction anyway. Change-Id: Ie40563394f9cacda1b35fde114c9a6043f53d460 Reviewed-by: Simon Hausmann <[email protected]>