2013-08-14 08:17:31 +00:00
/****************************************************************************
* *
2016-01-19 09:38:36 +00:00
* * Copyright ( C ) 2016 The Qt Company Ltd .
* * Contact : https : //www.qt.io/licensing/
2013-08-14 08:17:31 +00:00
* *
* * This file is part of the QtQml module of the Qt Toolkit .
* *
2016-01-19 09:38:36 +00:00
* * $ QT_BEGIN_LICENSE : LGPL $
2013-08-14 08:17:31 +00:00
* * 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
2015-01-28 11:55:39 +00:00
* * a written agreement between you and The Qt Company . For licensing terms
2016-01-19 09:38:36 +00:00
* * and conditions see https : //www.qt.io/terms-conditions. For further
* * information use the contact form at https : //www.qt.io/contact-us.
2013-08-14 08:17:31 +00:00
* *
* * GNU Lesser General Public License Usage
* * Alternatively , this file may be used under the terms of the GNU Lesser
2016-01-19 09:38:36 +00:00
* * 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.
2013-08-14 08:17:31 +00:00
* *
2016-01-19 09:38:36 +00:00
* * 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.
2013-08-14 08:17:31 +00:00
* *
* * $ QT_END_LICENSE $
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "qv4compileddata_p.h"
# include "qv4jsir_p.h"
2015-02-14 21:46:41 +00:00
# include <private/qv4value_p.h>
2014-03-12 15:55:06 +00:00
# ifndef V4_BOOTSTRAP
2013-08-14 08:17:37 +00:00
# include <private/qv4engine_p.h>
2013-08-14 13:44:53 +00:00
# include <private/qv4function_p.h>
2013-08-29 12:31:32 +00:00
# include <private/qv4objectproto_p.h>
2013-08-15 10:48:05 +00:00
# include <private/qv4lookup_p.h>
2013-08-15 13:54:36 +00:00
# include <private/qv4regexpobject_p.h>
2015-04-09 08:23:17 +00:00
# include <private/qqmlpropertycache_p.h>
2016-05-29 17:05:27 +00:00
# include <private/qqmltypeloader_p.h>
2016-05-29 17:21:54 +00:00
# include <private/qqmlengine_p.h>
2016-08-09 08:30:26 +00:00
# include "qv4compilationunitmapper_p.h"
2016-05-29 17:21:54 +00:00
# include <QQmlPropertyMap>
2016-07-21 15:12:52 +00:00
# include <QDateTime>
2016-06-06 14:19:47 +00:00
# include <QFile>
# include <QFileInfo>
# include <QScopedValueRollback>
2016-08-07 12:53:57 +00:00
# include <QStandardPaths>
# include <QDir>
2014-03-12 15:55:06 +00:00
# endif
2014-03-27 16:07:06 +00:00
# include <private/qqmlirbuilder_p.h>
2014-03-06 15:19:42 +00:00
# include <QCoreApplication>
2016-08-03 13:15:51 +00:00
# include <QCryptographicHash>
2016-12-29 09:20:53 +00:00
# include <QSaveFile>
2013-08-14 08:17:31 +00:00
2013-09-12 09:06:59 +00:00
# include <algorithm>
2016-08-31 12:31:29 +00:00
# if defined(QT_BUILD_INTERNAL)
# if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST)
# include <dlfcn.h>
# endif
# endif
2013-08-18 13:35:02 +00:00
QT_BEGIN_NAMESPACE
2013-08-14 08:17:31 +00:00
namespace QV4 {
namespace CompiledData {
2016-12-29 09:20:53 +00:00
# ifdef V4_BOOTSTRAP
static QString cacheFilePath ( const QString & localSourcePath )
{
const QString localCachePath = localSourcePath + QLatin1Char ( ' c ' ) ;
return localCachePath ;
}
# else
static QString cacheFilePath ( const QUrl & url )
{
const QString localSourcePath = QQmlFile : : urlToLocalFileOrQrc ( url ) ;
const QString localCachePath = localSourcePath + QLatin1Char ( ' c ' ) ;
if ( QFileInfo ( QFileInfo ( localSourcePath ) . dir ( ) . absolutePath ( ) ) . isWritable ( ) )
return localCachePath ;
QCryptographicHash fileNameHash ( QCryptographicHash : : Sha1 ) ;
fileNameHash . addData ( localSourcePath . toUtf8 ( ) ) ;
QString directory = QStandardPaths : : writableLocation ( QStandardPaths : : CacheLocation ) + QLatin1String ( " /qmlcache/ " ) ;
QDir : : root ( ) . mkpath ( directory ) ;
return directory + QString : : fromUtf8 ( fileNameHash . result ( ) . toHex ( ) ) + QLatin1Char ( ' . ' ) + QFileInfo ( localCachePath ) . completeSuffix ( ) ;
}
# endif
2014-03-12 15:55:06 +00:00
# ifndef V4_BOOTSTRAP
2015-04-09 08:23:17 +00:00
CompilationUnit : : CompilationUnit ( )
: data ( 0 )
, engine ( 0 )
, runtimeStrings ( 0 )
, runtimeLookups ( 0 )
, runtimeRegularExpressions ( 0 )
, runtimeClasses ( 0 )
2016-05-29 16:47:57 +00:00
, totalBindingsCount ( 0 )
, totalParserStatusCount ( 0 )
, totalObjectCount ( 0 )
2016-05-29 16:58:07 +00:00
, metaTypeId ( - 1 )
, listMetaTypeId ( - 1 )
, isRegisteredWithEngine ( false )
2015-04-09 08:23:17 +00:00
{ }
2013-08-14 08:17:37 +00:00
CompilationUnit : : ~ CompilationUnit ( )
{
2013-09-19 07:32:42 +00:00
unlink ( ) ;
2016-05-20 13:22:31 +00:00
if ( data & & ! ( data - > flags & QV4 : : CompiledData : : Unit : : StaticData ) )
2016-06-03 09:23:25 +00:00
free ( const_cast < Unit * > ( data ) ) ;
2016-05-20 13:22:31 +00:00
data = 0 ;
2013-08-14 08:17:37 +00:00
}
QV4 : : Function * CompilationUnit : : linkToEngine ( ExecutionEngine * engine )
{
2013-08-15 12:11:19 +00:00
this - > engine = engine ;
engine - > compilationUnits . insert ( this ) ;
2014-03-18 08:20:45 +00:00
Q_ASSERT ( ! runtimeStrings ) ;
Q_ASSERT ( data ) ;
2014-11-12 15:07:56 +00:00
runtimeStrings = ( QV4 : : Heap : : String * * ) malloc ( data - > stringTableSize * sizeof ( QV4 : : Heap : : String * ) ) ;
2013-09-20 13:13:14 +00:00
// memset the strings to 0 in case a GC run happens while we're within the loop below
2014-11-12 15:07:56 +00:00
memset ( runtimeStrings , 0 , data - > stringTableSize * sizeof ( QV4 : : Heap : : String * ) ) ;
for ( uint i = 0 ; i < data - > stringTableSize ; + + i )
runtimeStrings [ i ] = engine - > newIdentifier ( data - > stringAt ( i ) ) ;
2013-08-14 08:17:37 +00:00
2014-01-24 21:55:39 +00:00
runtimeRegularExpressions = new QV4 : : Value [ data - > regexpTableSize ] ;
2013-09-20 13:13:14 +00:00
// memset the regexps to 0 in case a GC run happens while we're within the loop below
2014-01-24 21:55:39 +00:00
memset ( runtimeRegularExpressions , 0 , data - > regexpTableSize * sizeof ( QV4 : : Value ) ) ;
2013-11-01 11:38:32 +00:00
for ( uint i = 0 ; i < data - > regexpTableSize ; + + i ) {
2013-08-15 13:54:36 +00:00
const CompiledData : : RegExp * re = data - > regexpAt ( i ) ;
int flags = 0 ;
if ( re - > flags & CompiledData : : RegExp : : RegExp_Global )
2014-02-14 12:58:40 +00:00
flags | = IR : : RegExp : : RegExp_Global ;
2013-08-15 13:54:36 +00:00
if ( re - > flags & CompiledData : : RegExp : : RegExp_IgnoreCase )
2014-02-14 12:58:40 +00:00
flags | = IR : : RegExp : : RegExp_IgnoreCase ;
2013-08-15 13:54:36 +00:00
if ( re - > flags & CompiledData : : RegExp : : RegExp_Multiline )
2014-02-14 12:58:40 +00:00
flags | = IR : : RegExp : : RegExp_Multiline ;
2014-11-12 15:07:56 +00:00
runtimeRegularExpressions [ i ] = engine - > newRegExpObject ( data - > stringAt ( re - > stringIndex ) , flags ) ;
2013-08-15 13:54:36 +00:00
}
2013-08-15 10:48:05 +00:00
if ( data - > lookupTableSize ) {
runtimeLookups = new QV4 : : Lookup [ data - > lookupTableSize ] ;
2013-10-11 12:58:45 +00:00
memset ( runtimeLookups , 0 , data - > lookupTableSize * sizeof ( QV4 : : Lookup ) ) ;
2013-08-15 10:48:05 +00:00
const CompiledData : : Lookup * compiledLookups = data - > lookupTable ( ) ;
for ( uint i = 0 ; i < data - > lookupTableSize ; + + i ) {
QV4 : : Lookup * l = runtimeLookups + i ;
2016-07-12 12:19:09 +00:00
Lookup : : Type type = Lookup : : Type ( uint ( compiledLookups [ i ] . type_and_flags ) ) ;
2014-01-24 12:16:55 +00:00
if ( type = = CompiledData : : Lookup : : Type_Getter )
2013-08-15 10:48:05 +00:00
l - > getter = QV4 : : Lookup : : getterGeneric ;
2014-01-24 12:16:55 +00:00
else if ( type = = CompiledData : : Lookup : : Type_Setter )
2013-08-15 10:48:05 +00:00
l - > setter = QV4 : : Lookup : : setterGeneric ;
2014-01-24 12:16:55 +00:00
else if ( type = = CompiledData : : Lookup : : Type_GlobalGetter )
2013-08-15 10:48:05 +00:00
l - > globalGetter = QV4 : : Lookup : : globalGetterGeneric ;
2014-01-24 12:16:55 +00:00
else if ( type = = CompiledData : : Lookup : : Type_IndexedGetter )
2014-01-17 11:19:34 +00:00
l - > indexedGetter = QV4 : : Lookup : : indexedGetterGeneric ;
2014-01-24 12:16:55 +00:00
else if ( type = = CompiledData : : Lookup : : Type_IndexedSetter )
l - > indexedSetter = QV4 : : Lookup : : indexedSetterGeneric ;
2013-08-15 10:48:05 +00:00
2013-11-01 11:38:32 +00:00
for ( int j = 0 ; j < QV4 : : Lookup : : Size ; + + j )
l - > classList [ j ] = 0 ;
2013-08-15 10:48:05 +00:00
l - > level = - 1 ;
l - > index = UINT_MAX ;
2014-11-12 15:07:56 +00:00
l - > nameIndex = compiledLookups [ i ] . nameIndex ;
2014-01-24 12:16:55 +00:00
if ( type = = CompiledData : : Lookup : : Type_IndexedGetter | | type = = CompiledData : : Lookup : : Type_IndexedSetter )
2014-01-17 11:19:34 +00:00
l - > engine = engine ;
2013-08-15 10:48:05 +00:00
}
}
2013-08-16 11:21:31 +00:00
if ( data - > jsClassTableSize ) {
runtimeClasses = ( QV4 : : InternalClass * * ) malloc ( data - > jsClassTableSize * sizeof ( QV4 : : InternalClass * ) ) ;
2013-11-01 11:38:32 +00:00
for ( uint i = 0 ; i < data - > jsClassTableSize ; + + i ) {
2013-08-16 11:21:31 +00:00
int memberCount = 0 ;
const CompiledData : : JSClassMember * member = data - > jsClassAt ( i , & memberCount ) ;
2015-01-10 19:35:18 +00:00
QV4 : : InternalClass * klass = engine - > emptyClass ;
2013-08-16 11:21:31 +00:00
for ( int j = 0 ; j < memberCount ; + + j , + + member )
2014-11-12 19:07:27 +00:00
klass = klass - > addMember ( runtimeStrings [ member - > nameOffset ] - > identifier , member - > isAccessor ? QV4 : : Attr_Accessor : QV4 : : Attr_Data ) ;
2013-08-16 11:21:31 +00:00
runtimeClasses [ i ] = klass ;
}
}
2016-07-14 18:39:58 +00:00
# if Q_BYTE_ORDER == Q_BIG_ENDIAN
Value * bigEndianConstants = new Value [ data - > constantTableSize ] ;
const LEUInt64 * littleEndianConstants = data - > constants ( ) ;
for ( uint i = 0 ; i < data - > constantTableSize ; + + i )
bigEndianConstants [ i ] = Value : : fromReturnedValue ( littleEndianConstants [ i ] ) ;
constants = bigEndianConstants ;
# else
constants = reinterpret_cast < const Value * > ( data - > constants ( ) ) ;
# endif
2013-08-19 06:31:35 +00:00
linkBackendToEngine ( engine ) ;
2013-08-16 16:35:29 +00:00
2013-10-18 13:36:40 +00:00
if ( data - > indexOfRootFunction ! = - 1 )
return runtimeFunctions [ data - > indexOfRootFunction ] ;
else
return 0 ;
2013-08-14 08:17:37 +00:00
}
2013-09-19 07:32:42 +00:00
void CompilationUnit : : unlink ( )
{
if ( engine )
engine - > compilationUnits . erase ( engine - > compilationUnits . find ( this ) ) ;
2016-05-29 07:33:26 +00:00
2016-05-29 16:58:07 +00:00
if ( isRegisteredWithEngine ) {
2016-06-14 13:44:09 +00:00
Q_ASSERT ( data & & quint32 ( propertyCaches . count ( ) ) > data - > indexOfRootObject & & propertyCaches . at ( data - > indexOfRootObject ) ) ;
2016-05-29 16:58:07 +00:00
QQmlEnginePrivate * qmlEngine = QQmlEnginePrivate : : get ( propertyCaches . at ( data - > indexOfRootObject ) - > engine ) ;
qmlEngine - > unregisterInternalCompositeType ( this ) ;
isRegisteredWithEngine = false ;
}
2016-05-29 07:33:26 +00:00
propertyCaches . clear ( ) ;
2016-05-29 17:05:27 +00:00
for ( int ii = 0 ; ii < dependentScripts . count ( ) ; + + ii )
dependentScripts . at ( ii ) - > release ( ) ;
dependentScripts . clear ( ) ;
2017-01-25 14:56:09 +00:00
typeNameCache = nullptr ;
2016-05-29 16:42:28 +00:00
2016-05-29 17:21:54 +00:00
qDeleteAll ( resolvedTypes ) ;
resolvedTypes . clear ( ) ;
2013-09-19 07:32:42 +00:00
engine = 0 ;
free ( runtimeStrings ) ;
runtimeStrings = 0 ;
delete [ ] runtimeLookups ;
runtimeLookups = 0 ;
delete [ ] runtimeRegularExpressions ;
runtimeRegularExpressions = 0 ;
free ( runtimeClasses ) ;
runtimeClasses = 0 ;
qDeleteAll ( runtimeFunctions ) ;
runtimeFunctions . clear ( ) ;
2016-07-14 18:39:58 +00:00
# if Q_BYTE_ORDER == Q_BIG_ENDIAN
delete [ ] constants ;
# endif
2013-09-19 07:32:42 +00:00
}
2013-11-02 15:30:26 +00:00
void CompilationUnit : : markObjects ( QV4 : : ExecutionEngine * e )
2013-08-15 12:11:19 +00:00
{
2013-11-01 11:38:32 +00:00
for ( uint i = 0 ; i < data - > stringTableSize ; + + i )
2014-07-23 11:56:43 +00:00
if ( runtimeStrings [ i ] )
runtimeStrings [ i ] - > mark ( e ) ;
2013-10-11 12:58:45 +00:00
if ( runtimeRegularExpressions ) {
2013-11-01 11:38:32 +00:00
for ( uint i = 0 ; i < data - > regexpTableSize ; + + i )
2013-11-02 15:30:26 +00:00
runtimeRegularExpressions [ i ] . mark ( e ) ;
2013-10-11 12:58:45 +00:00
}
2013-08-15 12:11:19 +00:00
}
2016-06-01 08:55:45 +00:00
void CompilationUnit : : destroy ( )
{
QQmlEngine * qmlEngine = 0 ;
2016-07-13 10:03:20 +00:00
if ( engine & & engine - > v8Engine )
qmlEngine = engine - > v8Engine - > engine ( ) ;
2016-06-01 08:55:45 +00:00
if ( qmlEngine )
QQmlEnginePrivate : : deleteInEngineThread ( qmlEngine , this ) ;
else
delete this ;
}
2016-05-25 12:55:44 +00:00
IdentifierHash < int > CompilationUnit : : namedObjectsPerComponent ( int componentObjectIndex )
{
auto it = namedObjectsPerComponentCache . find ( componentObjectIndex ) ;
if ( it = = namedObjectsPerComponentCache . end ( ) ) {
IdentifierHash < int > namedObjectCache ( engine ) ;
const CompiledData : : Object * component = data - > objectAt ( componentObjectIndex ) ;
2016-07-12 12:19:09 +00:00
const LEUInt32 * namedObjectIndexPtr = component - > namedObjectsInComponentTable ( ) ;
2016-05-25 12:55:44 +00:00
for ( quint32 i = 0 ; i < component - > nNamedObjectsInComponent ; + + i , + + namedObjectIndexPtr ) {
const CompiledData : : Object * namedObject = data - > objectAt ( * namedObjectIndexPtr ) ;
namedObjectCache . add ( runtimeStrings [ namedObject - > idNameIndex ] , namedObject - > id ) ;
}
it = namedObjectsPerComponentCache . insert ( componentObjectIndex , namedObjectCache ) ;
}
return * it ;
}
2016-06-20 06:32:21 +00:00
void CompilationUnit : : finalize ( QQmlEnginePrivate * engine )
2016-06-16 11:29:36 +00:00
{
2016-06-20 06:32:21 +00:00
// Add to type registry of composites
if ( propertyCaches . needsVMEMetaObject ( data - > indexOfRootObject ) )
engine - > registerInternalCompositeType ( this ) ;
else {
const QV4 : : CompiledData : : Object * obj = objectAt ( data - > indexOfRootObject ) ;
auto * typeRef = resolvedTypes . value ( obj - > inheritedTypeNameIndex ) ;
Q_ASSERT ( typeRef ) ;
if ( typeRef - > compilationUnit ) {
metaTypeId = typeRef - > compilationUnit - > metaTypeId ;
listMetaTypeId = typeRef - > compilationUnit - > listMetaTypeId ;
} else {
metaTypeId = typeRef - > type - > typeId ( ) ;
listMetaTypeId = typeRef - > type - > qListTypeId ( ) ;
}
}
2016-06-16 11:29:36 +00:00
// Collect some data for instantiation later.
int bindingCount = 0 ;
int parserStatusCount = 0 ;
int objectCount = 0 ;
for ( quint32 i = 0 ; i < data - > nObjects ; + + i ) {
const QV4 : : CompiledData : : Object * obj = data - > objectAt ( i ) ;
bindingCount + = obj - > nBindings ;
if ( auto * typeRef = resolvedTypes . value ( obj - > inheritedTypeNameIndex ) ) {
if ( QQmlType * qmlType = typeRef - > type ) {
if ( qmlType - > parserStatusCast ( ) ! = - 1 )
+ + parserStatusCount ;
}
+ + objectCount ;
if ( typeRef - > compilationUnit ) {
bindingCount + = typeRef - > compilationUnit - > totalBindingsCount ;
parserStatusCount + = typeRef - > compilationUnit - > totalParserStatusCount ;
objectCount + = typeRef - > compilationUnit - > totalObjectCount ;
}
}
}
totalBindingsCount = bindingCount ;
totalParserStatusCount = parserStatusCount ;
totalObjectCount = objectCount ;
}
2016-06-06 09:46:01 +00:00
2016-07-28 15:40:36 +00:00
bool CompilationUnit : : verifyChecksum ( QQmlEngine * engine ,
const ResolvedTypeReferenceMap & dependentTypes ) const
{
if ( dependentTypes . isEmpty ( ) ) {
for ( size_t i = 0 ; i < sizeof ( data - > dependencyMD5Checksum ) ; + + i ) {
if ( data - > dependencyMD5Checksum [ i ] ! = 0 )
return false ;
}
return true ;
}
QCryptographicHash hash ( QCryptographicHash : : Md5 ) ;
if ( ! dependentTypes . addToHash ( & hash , engine ) )
return false ;
QByteArray checksum = hash . result ( ) ;
Q_ASSERT ( checksum . size ( ) = = sizeof ( data - > dependencyMD5Checksum ) ) ;
return memcmp ( data - > dependencyMD5Checksum , checksum . constData ( ) ,
sizeof ( data - > dependencyMD5Checksum ) ) = = 0 ;
}
2016-12-29 09:20:53 +00:00
bool CompilationUnit : : loadFromDisk ( const QUrl & url , EvalISelFactory * iselFactory , QString * errorString )
2016-08-07 12:53:57 +00:00
{
2016-12-29 09:20:53 +00:00
if ( ! QQmlFile : : isLocalFile ( url ) ) {
* errorString = QStringLiteral ( " File has to be a local file. " ) ;
return false ;
}
const QString sourcePath = QQmlFile : : urlToLocalFileOrQrc ( url ) ;
QScopedPointer < CompilationUnitMapper > cacheFile ( new CompilationUnitMapper ( ) ) ;
CompiledData : : Unit * mappedUnit = cacheFile - > open ( cacheFilePath ( url ) , sourcePath , errorString ) ;
if ( ! mappedUnit )
return false ;
const Unit * const oldDataPtr = ( data & & ! ( data - > flags & QV4 : : CompiledData : : Unit : : StaticData ) ) ? data : nullptr ;
QScopedValueRollback < const Unit * > dataPtrChange ( data , mappedUnit ) ;
if ( sourcePath ! = QQmlFile : : urlToLocalFileOrQrc ( stringAt ( data - > sourceFileIndex ) ) ) {
* errorString = QStringLiteral ( " QML source file has moved to a different location. " ) ;
return false ;
}
{
const QString foundArchitecture = stringAt ( data - > architectureIndex ) ;
const QString expectedArchitecture = QSysInfo : : buildAbi ( ) ;
if ( foundArchitecture ! = expectedArchitecture ) {
* errorString = QString : : fromUtf8 ( " Architecture mismatch. Found %1 expected %2 " ) . arg ( foundArchitecture ) . arg ( expectedArchitecture ) ;
return false ;
}
}
{
const QString foundCodeGenerator = stringAt ( data - > codeGeneratorIndex ) ;
const QString expectedCodeGenerator = iselFactory - > codeGeneratorName ;
if ( foundCodeGenerator ! = expectedCodeGenerator ) {
* errorString = QString : : fromUtf8 ( " Code generator mismatch. Found code generated by %1 but expected %2 " ) . arg ( foundCodeGenerator ) . arg ( expectedCodeGenerator ) ;
return false ;
}
}
if ( ! memoryMapCode ( errorString ) )
return false ;
dataPtrChange . commit ( ) ;
free ( const_cast < Unit * > ( oldDataPtr ) ) ;
backingFile . reset ( cacheFile . take ( ) ) ;
return true ;
}
bool CompilationUnit : : memoryMapCode ( QString * errorString )
{
* errorString = QStringLiteral ( " Missing code mapping backend " ) ;
return false ;
2016-08-07 12:53:57 +00:00
}
2016-12-29 09:20:53 +00:00
# endif // V4_BOOTSTRAP
# if defined(V4_BOOTSTRAP)
bool CompilationUnit : : saveToDisk ( const QString & unitUrl , QString * errorString )
# else
2016-08-01 13:57:53 +00:00
bool CompilationUnit : : saveToDisk ( const QUrl & unitUrl , QString * errorString )
2016-12-29 09:20:53 +00:00
# endif
2016-06-06 09:46:01 +00:00
{
errorString - > clear ( ) ;
2016-07-29 14:20:19 +00:00
if ( data - > sourceTimeStamp = = 0 ) {
* errorString = QStringLiteral ( " Missing time stamp for source file " ) ;
return false ;
}
2016-12-29 09:20:53 +00:00
# if !defined(V4_BOOTSTRAP)
2016-08-07 12:53:57 +00:00
if ( ! QQmlFile : : isLocalFile ( unitUrl ) ) {
2016-06-06 09:46:01 +00:00
* errorString = QStringLiteral ( " File has to be a local file. " ) ;
return false ;
}
2016-12-29 09:20:53 +00:00
# endif
2016-06-06 09:46:01 +00:00
2017-01-20 15:37:35 +00:00
# if QT_CONFIG(temporaryfile)
2016-06-06 09:46:01 +00:00
// Foo.qml -> Foo.qmlc
2016-08-07 12:53:57 +00:00
QSaveFile cacheFile ( cacheFilePath ( unitUrl ) ) ;
2016-06-06 09:46:01 +00:00
if ( ! cacheFile . open ( QIODevice : : WriteOnly | QIODevice : : Truncate ) ) {
* errorString = cacheFile . errorString ( ) ;
return false ;
}
QByteArray modifiedUnit ;
modifiedUnit . resize ( data - > unitSize ) ;
memcpy ( modifiedUnit . data ( ) , data , data - > unitSize ) ;
const char * dataPtr = modifiedUnit . data ( ) ;
Unit * unitPtr ;
memcpy ( & unitPtr , & dataPtr , sizeof ( unitPtr ) ) ;
unitPtr - > flags | = Unit : : StaticData ;
prepareCodeOffsetsForDiskStorage ( unitPtr ) ;
qint64 headerWritten = cacheFile . write ( modifiedUnit ) ;
if ( headerWritten ! = modifiedUnit . size ( ) ) {
* errorString = cacheFile . errorString ( ) ;
return false ;
}
if ( ! saveCodeToDisk ( & cacheFile , unitPtr , errorString ) )
return false ;
if ( ! cacheFile . commit ( ) ) {
* errorString = cacheFile . errorString ( ) ;
return false ;
}
return true ;
2017-01-20 15:37:35 +00:00
# else
* errorString = QStringLiteral ( " features.temporaryfile is disabled. " ) ;
return false ;
# endif // QT_CONFIG(temporaryfile)
2016-06-06 09:46:01 +00:00
}
void CompilationUnit : : prepareCodeOffsetsForDiskStorage ( Unit * unit )
{
Q_UNUSED ( unit ) ;
}
bool CompilationUnit : : saveCodeToDisk ( QIODevice * device , const Unit * unit , QString * errorString )
{
Q_UNUSED ( device ) ;
Q_UNUSED ( unit ) ;
* errorString = QStringLiteral ( " Saving code to disk is not supported in this configuration " ) ;
return false ;
}
2016-06-06 14:19:47 +00:00
2014-03-27 16:07:06 +00:00
Unit * CompilationUnit : : createUnitData ( QmlIR : : Document * irDocument )
{
2017-01-03 12:19:15 +00:00
if ( ! irDocument - > javaScriptCompilationUnit - > data )
return irDocument - > jsGenerator . generateUnit ( QV4 : : Compiler : : JSUnitGenerator : : GenerateWithoutStringTable ) ;
QQmlRefPointer < QV4 : : CompiledData : : CompilationUnit > compilationUnit = irDocument - > javaScriptCompilationUnit ;
QV4 : : CompiledData : : Unit * jsUnit = const_cast < QV4 : : CompiledData : : Unit * > ( irDocument - > javaScriptCompilationUnit - > data ) ;
QV4 : : Compiler : : StringTableGenerator & stringTable = irDocument - > jsGenerator . stringTable ;
// Collect signals that have had a change in signature (from onClicked to onClicked(mouse) for example)
// and now need fixing in the QV4::CompiledData. Also register strings at the same time, to finalize
// the string table.
QVector < quint32 > changedSignals ;
QVector < QQmlJS : : AST : : FormalParameterList * > changedSignalParameters ;
for ( QmlIR : : Object * o : qAsConst ( irDocument - > objects ) ) {
for ( QmlIR : : Binding * binding = o - > firstBinding ( ) ; binding ; binding = binding - > next ) {
if ( ! ( binding - > flags & QV4 : : CompiledData : : Binding : : IsSignalHandlerExpression ) )
continue ;
quint32 functionIndex = binding - > value . compiledScriptIndex ;
QmlIR : : CompiledFunctionOrExpression * foe = o - > functionsAndExpressions - > slowAt ( functionIndex ) ;
if ( ! foe )
continue ;
// save absolute index
changedSignals < < o - > runtimeFunctionIndices . at ( functionIndex ) ;
Q_ASSERT ( foe - > node ) ;
Q_ASSERT ( QQmlJS : : AST : : cast < QQmlJS : : AST : : FunctionDeclaration * > ( foe - > node ) ) ;
QQmlJS : : AST : : FormalParameterList * parameters = QQmlJS : : AST : : cast < QQmlJS : : AST : : FunctionDeclaration * > ( foe - > node ) - > formals ;
changedSignalParameters < < parameters ;
for ( ; parameters ; parameters = parameters - > next )
stringTable . registerString ( parameters - > name . toString ( ) ) ;
}
}
QVector < quint32 > signalParameterNameTable ;
quint32 signalParameterNameTableOffset = jsUnit - > unitSize ;
// Update signal signatures
if ( ! changedSignals . isEmpty ( ) ) {
if ( jsUnit = = compilationUnit - > data ) {
char * unitCopy = ( char * ) malloc ( jsUnit - > unitSize ) ;
memcpy ( unitCopy , jsUnit , jsUnit - > unitSize ) ;
jsUnit = reinterpret_cast < QV4 : : CompiledData : : Unit * > ( unitCopy ) ;
}
for ( int i = 0 ; i < changedSignals . count ( ) ; + + i ) {
const uint functionIndex = changedSignals . at ( i ) ;
// The data is now read-write due to the copy above, so the const_cast is ok.
QV4 : : CompiledData : : Function * function = const_cast < QV4 : : CompiledData : : Function * > ( jsUnit - > functionAt ( functionIndex ) ) ;
Q_ASSERT ( function - > nFormals = = quint32 ( 0 ) ) ;
function - > formalsOffset = signalParameterNameTableOffset - jsUnit - > functionOffsetTable ( ) [ functionIndex ] ;
for ( QQmlJS : : AST : : FormalParameterList * parameters = changedSignalParameters . at ( i ) ;
parameters ; parameters = parameters - > next ) {
signalParameterNameTable . append ( stringTable . getStringId ( parameters - > name . toString ( ) ) ) ;
function - > nFormals = function - > nFormals + 1 ;
}
// Hack to ensure an activation is created.
function - > flags | = QV4 : : CompiledData : : Function : : HasCatchOrWith | QV4 : : CompiledData : : Function : : HasDirectEval ;
signalParameterNameTableOffset + = function - > nFormals * sizeof ( quint32 ) ;
}
}
if ( ! signalParameterNameTable . isEmpty ( ) ) {
Q_ASSERT ( jsUnit ! = compilationUnit - > data ) ;
const uint signalParameterTableSize = signalParameterNameTable . count ( ) * sizeof ( quint32 ) ;
uint newSize = jsUnit - > unitSize + signalParameterTableSize ;
const uint oldSize = jsUnit - > unitSize ;
char * unitWithSignalParameters = ( char * ) realloc ( jsUnit , newSize ) ;
memcpy ( unitWithSignalParameters + oldSize , signalParameterNameTable . constData ( ) , signalParameterTableSize ) ;
jsUnit = reinterpret_cast < QV4 : : CompiledData : : Unit * > ( unitWithSignalParameters ) ;
jsUnit - > unitSize = newSize ;
}
if ( jsUnit ! = compilationUnit - > data )
jsUnit - > flags & = ~ QV4 : : CompiledData : : Unit : : StaticData ;
return jsUnit ;
2014-03-27 16:07:06 +00:00
}
2013-09-13 07:08:41 +00:00
QString Binding : : valueAsString ( const Unit * unit ) const
{
switch ( type ) {
case Type_Script :
case Type_String :
return unit - > stringAt ( stringIndex ) ;
case Type_Boolean :
return value . b ? QStringLiteral ( " true " ) : QStringLiteral ( " false " ) ;
case Type_Number :
2016-07-12 12:19:09 +00:00
return QString : : number ( valueAsNumber ( ) ) ;
2013-09-13 07:08:41 +00:00
case Type_Invalid :
return QString ( ) ;
2016-11-16 13:22:36 +00:00
# if !QT_CONFIG(translation)
2014-03-12 15:55:06 +00:00
case Type_TranslationById :
case Type_Translation :
return unit - > stringAt ( stringIndex ) ;
# else
2014-03-06 15:19:42 +00:00
case Type_TranslationById : {
QByteArray id = unit - > stringAt ( stringIndex ) . toUtf8 ( ) ;
return qtTrId ( id . constData ( ) , value . translationData . number ) ;
}
case Type_Translation : {
// This code must match that in the qsTr() implementation
const QString & path = unit - > stringAt ( unit - > sourceFileIndex ) ;
int lastSlash = path . lastIndexOf ( QLatin1Char ( ' / ' ) ) ;
2016-04-06 12:23:58 +00:00
QStringRef context = ( lastSlash > - 1 ) ? path . midRef ( lastSlash + 1 , path . length ( ) - lastSlash - 5 )
: QStringRef ( ) ;
2014-03-06 15:19:42 +00:00
QByteArray contextUtf8 = context . toUtf8 ( ) ;
QByteArray comment = unit - > stringAt ( value . translationData . commentIndex ) . toUtf8 ( ) ;
QByteArray text = unit - > stringAt ( stringIndex ) . toUtf8 ( ) ;
return QCoreApplication : : translate ( contextUtf8 . constData ( ) , text . constData ( ) ,
comment . constData ( ) , value . translationData . number ) ;
}
2014-03-12 15:55:06 +00:00
# endif
2013-09-13 07:08:41 +00:00
default :
break ;
}
return QString ( ) ;
}
2014-01-10 13:46:33 +00:00
//reverse of Lexer::singleEscape()
2014-08-12 11:52:50 +00:00
QString Binding : : escapedString ( const QString & string )
2014-01-10 13:46:33 +00:00
{
QString tmp = QLatin1String ( " \" " ) ;
for ( int i = 0 ; i < string . length ( ) ; + + i ) {
const QChar & c = string . at ( i ) ;
switch ( c . unicode ( ) ) {
case 0x08 :
tmp + = QLatin1String ( " \\ b " ) ;
break ;
case 0x09 :
tmp + = QLatin1String ( " \\ t " ) ;
break ;
case 0x0A :
tmp + = QLatin1String ( " \\ n " ) ;
break ;
case 0x0B :
tmp + = QLatin1String ( " \\ v " ) ;
break ;
case 0x0C :
tmp + = QLatin1String ( " \\ f " ) ;
break ;
case 0x0D :
tmp + = QLatin1String ( " \\ r " ) ;
break ;
case 0x22 :
tmp + = QLatin1String ( " \\ \" " ) ;
break ;
case 0x27 :
tmp + = QLatin1String ( " \\ \' " ) ;
break ;
case 0x5C :
tmp + = QLatin1String ( " \\ \\ " ) ;
break ;
default :
tmp + = c ;
break ;
}
}
tmp + = QLatin1Char ( ' \" ' ) ;
return tmp ;
}
QString Binding : : valueAsScriptString ( const Unit * unit ) const
{
if ( type = = Type_String )
return escapedString ( unit - > stringAt ( stringIndex ) ) ;
else
return valueAsString ( unit ) ;
}
2016-05-29 17:21:54 +00:00
# ifndef V4_BOOTSTRAP
/*!
Returns the property cache , if one alread exists . The cache is not referenced .
*/
2016-07-28 15:40:29 +00:00
QQmlPropertyCache * ResolvedTypeReference : : propertyCache ( ) const
2016-05-29 17:21:54 +00:00
{
if ( type )
return typePropertyCache ;
else
2016-06-01 10:22:11 +00:00
return compilationUnit - > rootPropertyCache ( ) ;
2016-05-29 17:21:54 +00:00
}
/*!
Returns the property cache , creating one if it doesn ' t already exist . The cache is not referenced .
*/
2016-07-28 15:40:29 +00:00
QQmlPropertyCache * ResolvedTypeReference : : createPropertyCache ( QQmlEngine * engine )
2016-05-29 17:21:54 +00:00
{
if ( typePropertyCache ) {
return typePropertyCache ;
} else if ( type ) {
typePropertyCache = QQmlEnginePrivate : : get ( engine ) - > cache ( type - > metaObject ( ) ) ;
return typePropertyCache ;
} else {
2016-06-01 10:22:11 +00:00
return compilationUnit - > rootPropertyCache ( ) ;
2016-05-29 17:21:54 +00:00
}
}
2016-10-16 15:54:59 +00:00
bool ResolvedTypeReference : : addToHash ( QCryptographicHash * hash , QQmlEngine * engine )
{
if ( type ) {
bool ok = false ;
hash - > addData ( createPropertyCache ( engine ) - > checksum ( & ok ) ) ;
return ok ;
}
hash - > addData ( compilationUnit - > data - > md5Checksum , sizeof ( compilationUnit - > data - > md5Checksum ) ) ;
return true ;
}
2016-05-29 17:21:54 +00:00
template < typename T >
bool qtTypeInherits ( const QMetaObject * mo ) {
while ( mo ) {
if ( mo = = & T : : staticMetaObject )
return true ;
mo = mo - > superClass ( ) ;
}
return false ;
}
2016-07-28 15:40:29 +00:00
void ResolvedTypeReference : : doDynamicTypeCheck ( )
2016-05-29 17:21:54 +00:00
{
const QMetaObject * mo = 0 ;
if ( typePropertyCache )
mo = typePropertyCache - > firstCppMetaObject ( ) ;
else if ( type )
mo = type - > metaObject ( ) ;
2016-06-01 10:22:11 +00:00
else if ( compilationUnit )
mo = compilationUnit - > rootPropertyCache ( ) - > firstCppMetaObject ( ) ;
2016-05-29 17:21:54 +00:00
isFullyDynamicType = qtTypeInherits < QQmlPropertyMap > ( mo ) ;
}
2016-07-28 15:40:32 +00:00
2016-08-31 12:31:29 +00:00
# if defined(QT_BUILD_INTERNAL)
static QByteArray ownLibraryChecksum ( )
{
static QByteArray libraryChecksum ;
static bool checksumInitialized = false ;
if ( checksumInitialized )
return libraryChecksum ;
checksumInitialized = true ;
2017-01-26 10:46:16 +00:00
# if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST) && !defined(Q_OS_INTEGRITY)
2016-08-31 12:31:29 +00:00
Dl_info libInfo ;
if ( dladdr ( reinterpret_cast < const void * > ( & ownLibraryChecksum ) , & libInfo ) ! = 0 ) {
QFile library ( QFile : : decodeName ( libInfo . dli_fname ) ) ;
if ( library . open ( QIODevice : : ReadOnly ) ) {
QCryptographicHash hash ( QCryptographicHash : : Sha1 ) ;
hash . addData ( & library ) ;
libraryChecksum = hash . result ( ) ;
}
}
# else
// Not implemented.
# endif
return libraryChecksum ;
}
# endif
2016-07-28 15:40:32 +00:00
bool ResolvedTypeReferenceMap : : addToHash ( QCryptographicHash * hash , QQmlEngine * engine ) const
{
for ( auto it = constBegin ( ) , end = constEnd ( ) ; it ! = end ; + + it ) {
2016-10-16 15:54:59 +00:00
if ( ! it . value ( ) - > addToHash ( hash , engine ) )
2016-07-28 15:40:32 +00:00
return false ;
}
2016-08-31 12:31:29 +00:00
// This is a bit of a hack to make development easier. When hacking on the code generator
// the cache files may end up being re-used. To avoid that we also add the checksum of
// the QtQml library.
# if defined(QT_BUILD_INTERNAL)
hash - > addData ( ownLibraryChecksum ( ) ) ;
# endif
2016-07-28 15:40:32 +00:00
return true ;
}
2016-10-21 12:15:52 +00:00
# endif
2016-10-16 15:54:59 +00:00
void Unit : : generateChecksum ( )
{
2016-10-21 12:15:52 +00:00
# ifndef V4_BOOTSTRAP
2016-10-16 15:54:59 +00:00
QCryptographicHash hash ( QCryptographicHash : : Md5 ) ;
const int checksummableDataOffset = qOffsetOf ( QV4 : : CompiledData : : Unit , md5Checksum ) + sizeof ( md5Checksum ) ;
const char * dataPtr = reinterpret_cast < const char * > ( this ) + checksummableDataOffset ;
hash . addData ( dataPtr , unitSize - checksummableDataOffset ) ;
QByteArray checksum = hash . result ( ) ;
Q_ASSERT ( checksum . size ( ) = = sizeof ( md5Checksum ) ) ;
memcpy ( md5Checksum , checksum . constData ( ) , sizeof ( md5Checksum ) ) ;
2016-10-21 12:15:52 +00:00
# else
memset ( md5Checksum , 0 , sizeof ( md5Checksum ) ) ;
2016-05-29 17:21:54 +00:00
# endif
2016-10-21 12:15:52 +00:00
}
2016-05-29 17:21:54 +00:00
2013-08-14 08:17:31 +00:00
}
}
2013-08-18 13:35:02 +00:00
QT_END_NAMESPACE