1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtScript module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QSCRIPTENGINE_P_H
41#define QSCRIPTENGINE_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include "private/qobject_p.h"
55
56#include <QtCore/qdatetime.h>
57#include <QtCore/qhash.h>
58#include <QtCore/qnumeric.h>
59#include <QtCore/qregexp.h>
60#include <QtCore/qset.h>
61#include <QtCore/qstringlist.h>
62#include "qscriptvalue_p.h"
63#include "qscriptstring_p.h"
64#include "bridge/qscriptclassobject_p.h"
65#include "bridge/qscriptdeclarativeclass_p.h"
66#include "bridge/qscriptdeclarativeobject_p.h"
67#include "bridge/qscriptobject_p.h"
68#include "bridge/qscriptqobject_p.h"
69#include "bridge/qscriptvariant_p.h"
70#include "bridge/qscriptactivationobject_p.h"
71
72#include "DateConstructor.h"
73#include "DateInstance.h"
74#include "Debugger.h"
75#include "ErrorInstance.h"
76#include "JSArray.h"
77#include "Executable.h"
78#include "Lexer.h"
79#include "RefPtr.h"
80#include "RegExpConstructor.h"
81#include "RegExpObject.h"
82#include "SourceProvider.h"
83#include "Structure.h"
84#include "UString.h"
85#include "JSGlobalObject.h"
86#include "JSValue.h"
87
88#include <stdlib.h>
89
90namespace JSC
91{
92 class EvalExecutable;
93 class ExecState;
94 typedef ExecState CallFrame;
95 class JSCell;
96 class JSGlobalObject;
97}
98
99
100QT_BEGIN_NAMESPACE
101
102class QString;
103class QStringList;
104class QScriptContext;
105class QScriptValue;
106class QScriptTypeInfo;
107class QScriptEngineAgent;
108class QScriptEnginePrivate;
109class QScriptSyntaxCheckResult;
110class QScriptEngine;
111class QScriptProgramPrivate;
112
113namespace QScript
114{
115 class QObjectPrototype;
116 class QMetaObjectPrototype;
117 class QVariantPrototype;
118#ifndef QT_NO_QOBJECT
119 class QObjectData;
120#endif
121 class TimeoutCheckerProxy;
122
123 qint32 ToInt32(qsreal);
124 quint32 ToUInt32(qsreal);
125 quint16 ToUInt16(qsreal);
126 qsreal ToInteger(qsreal);
127
128 inline bool ToBool(qsreal);
129 inline bool ToBool(const QString &);
130 inline qint32 ToInt32(const QString &);
131 inline quint32 ToUInt32(const QString &);
132 inline quint16 ToUInt16(const QString &);
133 inline qsreal ToInteger(const QString &);
134#ifdef Q_CC_MSVC
135 // MSVC2008 crashes if these are inlined.
136 qsreal ToNumber(const QString &);
137 QString ToString(qsreal);
138#else
139 inline qsreal ToNumber(const QString &);
140 inline QString ToString(qsreal);
141#endif
142
143 QDateTime MsToDateTime(JSC::ExecState *, qsreal);
144 qsreal DateTimeToMs(JSC::ExecState *, const QDateTime &);
145
146 //some conversion helper functions
147 inline QScriptEnginePrivate *scriptEngineFromExec(const JSC::ExecState *exec);
148 bool isFunction(JSC::JSValue value);
149
150 inline void convertToLatin1_helper(const UChar *i, int length, char *s);
151 inline QByteArray convertToLatin1(const JSC::UString &str);
152
153 class UStringSourceProviderWithFeedback;
154
155struct GlobalClientData : public JSC::JSGlobalData::ClientData
156{
157 GlobalClientData(QScriptEnginePrivate *e)
158 : engine(e) {}
159 virtual ~GlobalClientData() {}
160 virtual void mark(JSC::MarkStack& markStack);
161 virtual void uncaughtException(JSC::ExecState*, unsigned bytecodeOffset,
162 JSC::JSValue);
163
164 QScriptEnginePrivate *engine;
165};
166
167} // namespace QScript
168
169class QScriptEnginePrivate
170#ifndef QT_NO_QOBJECT
171 : public QObjectPrivate
172#endif
173{
174 Q_DECLARE_PUBLIC(QScriptEngine)
175public:
176 QScriptEnginePrivate();
177 virtual ~QScriptEnginePrivate();
178
179 static QScriptEnginePrivate *get(QScriptEngine *q) { return q ? q->d_func() : 0; }
180 static QScriptEngine *get(QScriptEnginePrivate *d) { return d ? d->q_func() : 0; }
181
182 static inline bool isArray(JSC::JSValue);
183 static inline bool isDate(JSC::JSValue);
184 static inline bool isError(JSC::JSValue);
185 static inline bool isObject(JSC::JSValue);
186 static inline bool isRegExp(JSC::JSValue);
187 static inline bool isVariant(JSC::JSValue);
188 static inline bool isQObject(JSC::JSValue);
189 static inline bool isQMetaObject(JSC::JSValue);
190
191 static inline bool toBool(JSC::ExecState *, JSC::JSValue);
192 static inline qsreal toInteger(JSC::ExecState *, JSC::JSValue);
193 static inline qsreal toNumber(JSC::ExecState *, JSC::JSValue);
194 static inline qint32 toInt32(JSC::ExecState *, JSC::JSValue);
195 static inline quint32 toUInt32(JSC::ExecState *, JSC::JSValue);
196 static inline quint16 toUInt16(JSC::ExecState *, JSC::JSValue);
197 static inline JSC::UString toString(JSC::ExecState *, JSC::JSValue);
198
199 static inline QDateTime toDateTime(JSC::ExecState *, JSC::JSValue);
200#ifndef QT_NO_REGEXP
201 static QRegExp toRegExp(JSC::ExecState*, JSC::JSValue);
202#endif
203 static QVariant toVariant(JSC::ExecState *, JSC::JSValue);
204 static inline QObject *toQObject(JSC::ExecState *, JSC::JSValue);
205 static inline const QMetaObject *toQMetaObject(JSC::ExecState *, JSC::JSValue);
206
207 static inline JSC::JSValue property(JSC::ExecState*, JSC::JSValue, const JSC::Identifier &id,
208 int resolveMode = QScriptValue::ResolvePrototype);
209 static JSC::JSValue propertyHelper(JSC::ExecState*, JSC::JSValue, const JSC::Identifier &id, int resolveMode);
210 static inline JSC::JSValue property(JSC::ExecState*, JSC::JSValue, quint32 index,
211 int resolveMode = QScriptValue::ResolvePrototype);
212 static JSC::JSValue propertyHelper(JSC::ExecState*, JSC::JSValue, quint32, int resolveMode);
213 static inline JSC::JSValue property(JSC::ExecState*, JSC::JSValue, const JSC::UString &, int resolveMode);
214 static inline void setProperty(JSC::ExecState*, JSC::JSValue object, const JSC::UString &name, JSC::JSValue,
215 const QScriptValue::PropertyFlags &flags = QScriptValue::KeepExistingFlags);
216 static void setProperty(JSC::ExecState*, JSC::JSValue object, const JSC::Identifier &id, JSC::JSValue,
217 const QScriptValue::PropertyFlags &flags = QScriptValue::KeepExistingFlags);
218 static void setProperty(JSC::ExecState*, JSC::JSValue object, quint32 index, JSC::JSValue,
219 const QScriptValue::PropertyFlags &flags = QScriptValue::KeepExistingFlags);
220 static QScriptValue::PropertyFlags propertyFlags(JSC::ExecState*, JSC::JSValue value,
221 const JSC::Identifier &id, const QScriptValue::ResolveFlags &mode);
222 static inline QScriptValue::PropertyFlags propertyFlags(JSC::ExecState*, JSC::JSValue value,
223 const JSC::UString &name, const QScriptValue::ResolveFlags &mode);
224
225 static bool convertValue(JSC::ExecState*, JSC::JSValue value,
226 int type, void *ptr);
227 static bool convertNumber(qsreal, int type, void *ptr);
228 static bool convertString(const QString &, int type, void *ptr);
229 static JSC::JSValue create(JSC::ExecState*, int type, const void *ptr);
230 bool hasDemarshalFunction(int type) const;
231
232 inline QScriptValue scriptValueFromJSCValue(JSC::JSValue value);
233 inline JSC::JSValue scriptValueToJSCValue(const QScriptValue &value);
234 static inline unsigned propertyFlagsToJSCAttributes(const QScriptValue::PropertyFlags &flags);
235
236 static inline JSC::JSValue jscValueFromVariant(JSC::ExecState*, const QVariant &value);
237 static QVariant jscValueToVariant(JSC::ExecState*, JSC::JSValue value, int targetType);
238 static inline QVariant &variantValue(JSC::JSValue value);
239 static inline void setVariantValue(JSC::JSValue objectValue, const QVariant &value);
240
241 static JSC::JSValue arrayFromStringList(JSC::ExecState*, const QStringList &lst);
242 static QStringList stringListFromArray(JSC::ExecState*, JSC::JSValue arr);
243
244 static JSC::JSValue arrayFromVariantList(JSC::ExecState*, const QVariantList &lst);
245 static QVariantList variantListFromArray(JSC::ExecState*, JSC::JSArray *arr);
246
247 static JSC::JSValue objectFromVariantMap(JSC::ExecState*, const QVariantMap &vmap);
248 static QVariantMap variantMapFromObject(JSC::ExecState*, JSC::JSObject *obj);
249
250 JSC::JSValue defaultPrototype(int metaTypeId) const;
251 void setDefaultPrototype(int metaTypeId, JSC::JSValue prototype);
252
253 static inline QScriptContext *contextForFrame(JSC::ExecState *frame);
254 static inline JSC::ExecState *frameForContext(QScriptContext *context);
255 static inline const JSC::ExecState *frameForContext(const QScriptContext *context);
256
257 static inline bool hasValidCodeBlockRegister(JSC::ExecState *frame);
258
259 JSC::JSGlobalObject *originalGlobalObject() const;
260 JSC::JSObject *getOriginalGlobalObjectProxy();
261 JSC::JSObject *customGlobalObject() const;
262 JSC::JSObject *globalObject() const;
263 void setGlobalObject(JSC::JSObject *object);
264 inline JSC::ExecState *globalExec() const;
265 JSC::JSValue toUsableValue(JSC::JSValue value);
266 static JSC::JSValue thisForContext(JSC::ExecState *frame);
267 static JSC::Register *thisRegisterForFrame(JSC::ExecState *frame);
268
269 JSC::CallFrame *pushContext(JSC::CallFrame *exec, JSC::JSValue thisObject, const JSC::ArgList& args,
270 JSC::JSObject *callee, bool calledAsConstructor = false);
271 void popContext();
272
273 void mark(JSC::MarkStack& markStack);
274 bool isCollecting() const;
275 void collectGarbage();
276 void reportAdditionalMemoryCost(int size);
277
278 //flags that we set on the return value register for native function. (ie when codeBlock is 0)
279 enum ContextFlags {
280 NativeContext = 1,
281 CalledAsConstructorContext = 2,
282 HasScopeContext = 4, // Specifies that the is a QScriptActivationObject
283 ShouldRestoreCallFrame = 8
284 };
285 static uint contextFlags(JSC::ExecState *);
286 static void setContextFlags(JSC::ExecState *, uint);
287
288 QScript::TimeoutCheckerProxy *timeoutChecker() const;
289
290 void agentDeleted(QScriptEngineAgent *agent);
291
292 static bool isLikelyStackOverflowError(JSC::ExecState *, JSC::JSValue);
293 void uncaughtException(JSC::ExecState *, unsigned bytecodeOffset, JSC::JSValue);
294
295 static inline void saveException(JSC::ExecState *, JSC::JSValue *);
296 static inline void restoreException(JSC::ExecState *, JSC::JSValue);
297
298 void setCurrentException(QScriptValue exception) { m_currentException = exception; }
299 QScriptValue currentException() const { return m_currentException; }
300 void clearCurrentException()
301 {
302 m_currentException.d_ptr.reset();
303 uncaughtExceptionBacktrace.clear();
304 uncaughtExceptionLineNumber = -1;
305 }
306
307 static QScriptSyntaxCheckResult checkSyntax(const QString &program);
308 static bool canEvaluate(const QString &program);
309
310 inline void registerScriptProgram(QScriptProgramPrivate *program);
311 inline void unregisterScriptProgram(QScriptProgramPrivate *program);
312 void detachAllRegisteredScriptPrograms();
313
314 inline QScriptValuePrivate *allocateScriptValuePrivate(size_t);
315 inline void freeScriptValuePrivate(QScriptValuePrivate *p);
316
317 inline void registerScriptValue(QScriptValuePrivate *value);
318 inline void unregisterScriptValue(QScriptValuePrivate *value);
319 void detachAllRegisteredScriptValues();
320
321 inline void registerScriptString(QScriptStringPrivate *value);
322 inline void unregisterScriptString(QScriptStringPrivate *value);
323 void detachAllRegisteredScriptStrings();
324 QScriptString toStringHandle(const JSC::Identifier &name);
325
326 static inline JSC::JSValue newArray(JSC::ExecState *, uint length);
327 static inline JSC::JSValue newDate(JSC::ExecState *, qsreal value);
328 static inline JSC::JSValue newDate(JSC::ExecState *, const QDateTime &);
329 inline JSC::JSValue newObject();
330
331#ifndef QT_NO_REGEXP
332 static JSC::JSValue newRegExp(JSC::ExecState *, const QRegExp &);
333#endif
334
335 static JSC::JSValue newRegExp(JSC::ExecState *, const QString &pattern, const QString &flags);
336 JSC::JSValue newVariant(const QVariant &);
337 JSC::JSValue newVariant(JSC::JSValue objectValue, const QVariant &);
338
339 static inline QScriptDeclarativeClass *declarativeClass(JSC::JSValue);
340 static inline QScriptDeclarativeClass::Object *declarativeObject(JSC::JSValue);
341
342 JSC::UString translationContextFromUrl(const JSC::UString &);
343
344#ifndef QT_NO_QOBJECT
345 void markQObjectData(JSC::MarkStack&);
346 JSC::JSValue newQObject(QObject *object,
347 QScriptEngine::ValueOwnership ownership = QScriptEngine::QtOwnership,
348 const QScriptEngine:: QObjectWrapOptions &options = {});
349 JSC::JSValue newQMetaObject(const QMetaObject *metaObject,
350 JSC::JSValue ctor);
351
352 static bool convertToNativeQObject(JSC::ExecState*, JSC::JSValue,
353 const QByteArray &targetType,
354 void **result);
355
356 JSC::JSValue evaluateHelper(JSC::ExecState *exec, intptr_t sourceId,
357 JSC::EvalExecutable *executable,
358 bool &compile);
359
360 QScript::QObjectData *qobjectData(QObject *object);
361 void disposeQObject(QObject *object);
362 void emitSignalHandlerException();
363
364 bool scriptConnect(QObject *sender, const char *signal,
365 JSC::JSValue receiver, JSC::JSValue function,
366 Qt::ConnectionType type);
367 bool scriptDisconnect(QObject *sender, const char *signal,
368 JSC::JSValue receiver, JSC::JSValue function);
369
370 bool scriptConnect(QObject *sender, int index,
371 JSC::JSValue receiver, JSC::JSValue function,
372 JSC::JSValue senderWrapper,
373 Qt::ConnectionType type);
374 bool scriptDisconnect(QObject *sender, int index,
375 JSC::JSValue receiver, JSC::JSValue function);
376
377 bool scriptConnect(JSC::JSValue signal, JSC::JSValue receiver,
378 JSC::JSValue function, Qt::ConnectionType type);
379 bool scriptDisconnect(JSC::JSValue signal, JSC::JSValue receiver,
380 JSC::JSValue function);
381
382 // private slots
383 void _q_objectDestroyed(QObject *);
384#endif
385
386 JSC::JSGlobalData *globalData;
387 JSC::JSObject *originalGlobalObjectProxy;
388 JSC::ExecState *currentFrame;
389
390 WTF::RefPtr<JSC::Structure> scriptObjectStructure;
391 WTF::RefPtr<JSC::Structure> staticScopeObjectStructure;
392
393 QScript::QObjectPrototype *qobjectPrototype;
394 WTF::RefPtr<JSC::Structure> qobjectWrapperObjectStructure;
395
396 QScript::QMetaObjectPrototype *qmetaobjectPrototype;
397 WTF::RefPtr<JSC::Structure> qmetaobjectWrapperObjectStructure;
398
399 QScript::QVariantPrototype *variantPrototype;
400 WTF::RefPtr<JSC::Structure> variantWrapperObjectStructure;
401
402 QList<QScriptEngineAgent*> ownedAgents;
403 QScriptEngineAgent *activeAgent;
404 int agentLineNumber;
405 QScriptValuePrivate *registeredScriptValues;
406 QScriptValuePrivate *freeScriptValues;
407 static const int maxFreeScriptValues = 256;
408 int freeScriptValuesCount;
409 QScriptStringPrivate *registeredScriptStrings;
410 QSet<QScriptProgramPrivate*> registeredScriptPrograms;
411 QHash<int, QScriptTypeInfo*> m_typeInfos;
412 int processEventsInterval;
413 QScriptValue abortResult;
414 bool inEval;
415
416 JSC::UString cachedTranslationUrl;
417 JSC::UString cachedTranslationContext;
418
419 QSet<QString> importedExtensions;
420 QSet<QString> extensionsBeingImported;
421
422 QHash<intptr_t, QScript::UStringSourceProviderWithFeedback*> loadedScripts;
423 QScriptValue m_currentException;
424 QStringList uncaughtExceptionBacktrace;
425 int uncaughtExceptionLineNumber;
426
427 QSet<JSC::JSObject*> visitedConversionObjects;
428
429#ifndef QT_NO_QOBJECT
430 QHash<QObject*, QScript::QObjectData*> m_qobjectData;
431#endif
432
433#ifdef QT_NO_QOBJECT
434 QScriptEngine *q_ptr;
435#endif
436};
437
438namespace QScript
439{
440
441class APIShim
442{
443public:
444 APIShim(QScriptEnginePrivate *engine)
445 : m_engine(engine), m_oldTable(JSC::setCurrentIdentifierTable(engine->globalData->identifierTable))
446 {
447 }
448 ~APIShim()
449 {
450 JSC::setCurrentIdentifierTable(m_oldTable);
451 }
452
453private:
454 QScriptEnginePrivate *m_engine;
455 JSC::IdentifierTable *m_oldTable;
456};
457
458/*Helper class. Main purpose is to give debugger feedback about unloading and loading scripts.
459 It keeps pointer to JSGlobalObject assuming that it is always the same - there is no way to update
460 this data. Class is internal and used as an implementation detail in and only in QScriptEngine::evaluate.*/
461class UStringSourceProviderWithFeedback: public JSC::UStringSourceProvider
462{
463public:
464 static PassRefPtr<UStringSourceProviderWithFeedback> create(
465 const JSC::UString& source, const JSC::UString& url,
466 int lineNumber, QScriptEnginePrivate* engine)
467 {
468 return adoptRef(p: new UStringSourceProviderWithFeedback(source, url, lineNumber, engine));
469 }
470
471 /* Destruction means that there is no more copies of script so create scriptUnload event
472 and unregister script in QScriptEnginePrivate::loadedScripts */
473 virtual ~UStringSourceProviderWithFeedback()
474 {
475 if (m_ptr) {
476 if (JSC::Debugger* debugger = this->debugger())
477 debugger->scriptUnload(id: asID());
478 m_ptr->loadedScripts.remove(akey: asID());
479 }
480 }
481
482 /* set internal QScriptEnginePrivate pointer to null and create unloadScript event, should be called
483 only if QScriptEnginePrivate is about to be destroyed.*/
484 void disconnectFromEngine()
485 {
486 if (JSC::Debugger* debugger = this->debugger())
487 debugger->scriptUnload(id: asID());
488 m_ptr = 0;
489 }
490
491 int columnNumberFromOffset(int offset) const
492 {
493 for (const UChar *c = m_source.data() + offset; c >= m_source.data(); --c) {
494 if (JSC::Lexer::isLineTerminator(ch: *c))
495 return offset - static_cast<int>(c - data());
496 }
497 return offset + 1;
498 }
499
500protected:
501 UStringSourceProviderWithFeedback(const JSC::UString& source, const JSC::UString& url,
502 int lineNumber, QScriptEnginePrivate* engine)
503 : UStringSourceProvider(source, url),
504 m_ptr(engine)
505 {
506 if (JSC::Debugger* debugger = this->debugger())
507 debugger->scriptLoad(id: asID(), program: source, fileName: url, baseLineNumber: lineNumber);
508 if (m_ptr)
509 m_ptr->loadedScripts.insert(akey: asID(), avalue: this);
510 }
511
512 JSC::Debugger* debugger()
513 {
514 //if m_ptr is null it mean that QScriptEnginePrivate was destroyed and scriptUnload was called
515 //else m_ptr is stable and we can use it as normal pointer without hesitation
516 if(!m_ptr)
517 return 0; //we are in ~QScriptEnginePrivate
518 else
519 return m_ptr->originalGlobalObject()->debugger(); //QScriptEnginePrivate is still alive
520 }
521
522 //trace global object and debugger instance
523 QScriptEnginePrivate* m_ptr;
524};
525
526class SaveFrameHelper
527{
528public:
529 SaveFrameHelper(QScriptEnginePrivate *eng,
530 JSC::ExecState *newFrame)
531 : engine(eng), oldFrame(eng->currentFrame)
532 {
533 eng->currentFrame = newFrame;
534 }
535 ~SaveFrameHelper()
536 {
537 engine->currentFrame = oldFrame;
538 }
539private:
540 QScriptEnginePrivate *engine;
541 JSC::ExecState *oldFrame;
542};
543
544inline QScriptEnginePrivate *scriptEngineFromExec(const JSC::ExecState *exec)
545{
546 return static_cast<GlobalClientData*>(exec->globalData().clientData)->engine;
547}
548
549#ifndef Q_CC_MSVC
550// MSVC2008 crashes if these are inlined.
551
552inline QString ToString(qsreal value)
553{
554 return JSC::UString::from(value);
555}
556
557inline qsreal ToNumber(const QString &value)
558{
559 return ((JSC::UString)value).toDouble();
560}
561
562#endif
563
564inline qint32 ToInt32(const QString &value)
565{
566 return ToInt32(ToNumber(value));
567}
568
569inline quint32 ToUInt32(const QString &value)
570{
571 return ToUInt32(ToNumber(value));
572}
573
574inline quint16 ToUInt16(const QString &value)
575{
576 return ToUInt16(ToNumber(value));
577}
578
579inline qsreal ToInteger(const QString &value)
580{
581 return ToInteger(ToNumber(value));
582}
583
584inline bool ToBool(qsreal value)
585{
586 return (value != 0) && !qIsNaN(d: value);
587}
588
589inline bool ToBool(const QString &value)
590{
591 return !value.isEmpty();
592}
593
594inline void convertToLatin1_helper(const UChar *i, int length, char *s)
595{
596 const UChar *e = i + length;
597 while (i != e)
598 *(s++) = (uchar) *(i++);
599 *s = '\0';
600}
601
602inline QByteArray convertToLatin1(const JSC::UString &str)
603{
604 QByteArray ba(str.size(), Qt::Uninitialized);
605 convertToLatin1_helper(i: str.data(), length: str.size(), s: ba.data());
606 return ba;
607}
608
609} // namespace QScript
610
611inline void QScriptEnginePrivate::registerScriptProgram(QScriptProgramPrivate *program)
612{
613 Q_ASSERT(!registeredScriptPrograms.contains(program));
614 registeredScriptPrograms.insert(value: program);
615}
616
617inline void QScriptEnginePrivate::unregisterScriptProgram(QScriptProgramPrivate *program)
618{
619 Q_ASSERT(registeredScriptPrograms.contains(program));
620 registeredScriptPrograms.remove(value: program);
621}
622
623inline QScriptValuePrivate *QScriptEnginePrivate::allocateScriptValuePrivate(size_t size)
624{
625 if (freeScriptValues) {
626 QScriptValuePrivate *p = freeScriptValues;
627 freeScriptValues = p->next;
628 --freeScriptValuesCount;
629 return p;
630 }
631 return reinterpret_cast<QScriptValuePrivate*>(malloc(size: size));
632}
633
634inline void QScriptEnginePrivate::freeScriptValuePrivate(QScriptValuePrivate *p)
635{
636 if (freeScriptValuesCount < maxFreeScriptValues) {
637 p->next = freeScriptValues;
638 freeScriptValues = p;
639 ++freeScriptValuesCount;
640 } else {
641 free(ptr: p);
642 }
643}
644
645inline void QScriptEnginePrivate::registerScriptValue(QScriptValuePrivate *value)
646{
647 value->prev = 0;
648 value->next = registeredScriptValues;
649 if (registeredScriptValues)
650 registeredScriptValues->prev = value;
651 registeredScriptValues = value;
652}
653
654inline void QScriptEnginePrivate::unregisterScriptValue(QScriptValuePrivate *value)
655{
656 if (value->prev)
657 value->prev->next = value->next;
658 if (value->next)
659 value->next->prev = value->prev;
660 if (value == registeredScriptValues)
661 registeredScriptValues = value->next;
662 value->prev = 0;
663 value->next = 0;
664}
665
666inline JSC::JSValue QScriptEnginePrivate::jscValueFromVariant(JSC::ExecState *exec, const QVariant &v)
667{
668 JSC::JSValue result = create(exec, type: v.userType(), ptr: v.data());
669 Q_ASSERT(result);
670 return result;
671}
672
673inline QScriptValue QScriptEnginePrivate::scriptValueFromJSCValue(JSC::JSValue value)
674{
675 if (!value)
676 return QScriptValue();
677
678 QScriptValuePrivate *p_value = new (this)QScriptValuePrivate(this);
679 p_value->initFrom(value);
680 return QScriptValuePrivate::toPublic(d: p_value);
681}
682
683inline JSC::JSValue QScriptEnginePrivate::scriptValueToJSCValue(const QScriptValue &value)
684{
685 QScriptValuePrivate *vv = QScriptValuePrivate::get(q: value);
686 if (!vv)
687 return JSC::JSValue();
688 if (vv->type != QScriptValuePrivate::JavaScriptCore) {
689 Q_ASSERT(!vv->engine || vv->engine == this);
690 vv->engine = this;
691 if (vv->type == QScriptValuePrivate::Number) {
692 vv->initFrom(JSC::jsNumber(exec: currentFrame, d: vv->numberValue));
693 } else { //QScriptValuePrivate::String
694 vv->initFrom(JSC::jsString(exec: currentFrame, s: vv->stringValue));
695 }
696 }
697 return vv->jscValue;
698}
699
700inline unsigned QScriptEnginePrivate::propertyFlagsToJSCAttributes(const QScriptValue::PropertyFlags &flags)
701{
702 unsigned attribs = 0;
703 if (flags & QScriptValue::ReadOnly)
704 attribs |= JSC::ReadOnly;
705 if (flags & QScriptValue::SkipInEnumeration)
706 attribs |= JSC::DontEnum;
707 if (flags & QScriptValue::Undeletable)
708 attribs |= JSC::DontDelete;
709 attribs |= flags & QScriptValue::UserRange;
710 return attribs;
711}
712
713inline QScriptValuePrivate::~QScriptValuePrivate()
714{
715 if (engine)
716 engine->unregisterScriptValue(value: this);
717}
718
719inline void QScriptValuePrivate::initFrom(JSC::JSValue value)
720{
721 if (value.isCell()) {
722 Q_ASSERT(engine != 0);
723 value = engine->toUsableValue(value);
724 }
725 type = JavaScriptCore;
726 jscValue = value;
727 if (engine)
728 engine->registerScriptValue(value: this);
729}
730
731inline void QScriptValuePrivate::initFrom(qsreal value)
732{
733 type = Number;
734 numberValue = value;
735 if (engine)
736 engine->registerScriptValue(value: this);
737}
738
739inline void QScriptValuePrivate::initFrom(const QString &value)
740{
741 type = String;
742 stringValue = value;
743 if (engine)
744 engine->registerScriptValue(value: this);
745}
746
747inline JSC::JSValue QScriptEnginePrivate::property(JSC::ExecState *exec, JSC::JSValue value, const JSC::UString &name, int resolveMode)
748{
749 return property(exec, value, JSC::Identifier(exec, name), resolveMode);
750}
751
752inline JSC::JSValue QScriptEnginePrivate::property(JSC::ExecState *exec, JSC::JSValue value, const JSC::Identifier &id, int resolveMode)
753{
754 Q_ASSERT(isObject(value));
755 JSC::JSObject *object = JSC::asObject(value);
756 JSC::PropertySlot slot(object);
757 if ((resolveMode & QScriptValue::ResolvePrototype) && object->getPropertySlot(exec, propertyName: id, slot))
758 return slot.getValue(exec, propertyName: id);
759 return propertyHelper(exec, value, id, resolveMode);
760}
761
762inline JSC::JSValue QScriptEnginePrivate::property(JSC::ExecState *exec, JSC::JSValue value, quint32 index, int resolveMode)
763{
764 Q_ASSERT(isObject(value));
765 JSC::JSObject *object = JSC::asObject(value);
766 JSC::PropertySlot slot(object);
767 if ((resolveMode & QScriptValue::ResolvePrototype) && object->getPropertySlot(exec, propertyName: index, slot))
768 return slot.getValue(exec, propertyName: index);
769 return propertyHelper(exec, value, index, resolveMode);
770}
771
772inline QScriptValue::PropertyFlags QScriptEnginePrivate::propertyFlags(JSC::ExecState *exec, JSC::JSValue value,
773 const JSC::UString &name,
774 const QScriptValue::ResolveFlags &mode)
775{
776 return propertyFlags(exec, value, JSC::Identifier(exec, name), mode);
777}
778
779inline void QScriptEnginePrivate::setProperty(JSC::ExecState *exec, JSC::JSValue objectValue, const JSC::UString &name,
780 JSC::JSValue value, const QScriptValue::PropertyFlags &flags)
781{
782 setProperty(exec, object: objectValue, JSC::Identifier(exec, name), value, flags);
783}
784
785inline JSC::JSValue QScriptValuePrivate::property(const JSC::Identifier &id, const QScriptValue::ResolveFlags &resolveMode) const
786{
787 return QScriptEnginePrivate::property(exec: engine->currentFrame, value: jscValue, id, resolveMode);
788}
789
790inline JSC::JSValue QScriptValuePrivate::property(quint32 index, const QScriptValue::ResolveFlags &resolveMode) const
791{
792 return QScriptEnginePrivate::property(exec: engine->currentFrame, value: jscValue, index, resolveMode);
793}
794
795inline JSC::JSValue QScriptValuePrivate::property(const JSC::UString &name, const QScriptValue::ResolveFlags &resolveMode) const
796{
797 JSC::ExecState *exec = engine->currentFrame;
798 return QScriptEnginePrivate::property(exec, value: jscValue, JSC::Identifier(exec, name), resolveMode);
799}
800
801inline QScriptValue::PropertyFlags QScriptValuePrivate::propertyFlags(
802 const JSC::Identifier &id, const QScriptValue::ResolveFlags &mode) const
803{
804 return QScriptEnginePrivate::propertyFlags(engine->currentFrame, value: jscValue, id, mode);
805}
806
807inline void QScriptValuePrivate::setProperty(const JSC::Identifier &id, const JSC::JSValue &value,
808 const QScriptValue::PropertyFlags &flags)
809{
810 QScriptEnginePrivate::setProperty(engine->currentFrame, object: jscValue, id, value, flags);
811}
812
813inline void QScriptValuePrivate::setProperty(quint32 index, const JSC::JSValue &value,
814 const QScriptValue::PropertyFlags &flags)
815{
816 QScriptEnginePrivate::setProperty(engine->currentFrame, object: jscValue, index, value, flags);
817}
818
819inline void QScriptValuePrivate::setProperty(const JSC::UString &name, const JSC::JSValue &value,
820 const QScriptValue::PropertyFlags &flags)
821{
822 JSC::ExecState *exec = engine->currentFrame;
823 QScriptEnginePrivate::setProperty(exec, object: jscValue, JSC::Identifier(exec, name), value, flags);
824}
825
826inline void* QScriptValuePrivate::operator new(size_t size, QScriptEnginePrivate *engine)
827{
828 if (engine)
829 return engine->allocateScriptValuePrivate(size);
830 return malloc(size: size);
831}
832
833inline void QScriptValuePrivate::operator delete(void *ptr)
834{
835 QScriptValuePrivate *d = reinterpret_cast<QScriptValuePrivate*>(ptr);
836 if (d->engine)
837 d->engine->freeScriptValuePrivate(p: d);
838 else
839 free(ptr: d);
840}
841
842inline void QScriptEnginePrivate::saveException(JSC::ExecState *exec, JSC::JSValue *val)
843{
844 if (exec) {
845 *val = exec->exception();
846 exec->clearException();
847 } else {
848 *val = JSC::JSValue();
849 }
850}
851
852inline void QScriptEnginePrivate::restoreException(JSC::ExecState *exec, JSC::JSValue val)
853{
854 if (exec && val)
855 exec->setException(val);
856}
857
858inline void QScriptEnginePrivate::registerScriptString(QScriptStringPrivate *value)
859{
860 Q_ASSERT(value->type == QScriptStringPrivate::HeapAllocated);
861 value->prev = 0;
862 value->next = registeredScriptStrings;
863 if (registeredScriptStrings)
864 registeredScriptStrings->prev = value;
865 registeredScriptStrings = value;
866}
867
868inline void QScriptEnginePrivate::unregisterScriptString(QScriptStringPrivate *value)
869{
870 Q_ASSERT(value->type == QScriptStringPrivate::HeapAllocated);
871 if (value->prev)
872 value->prev->next = value->next;
873 if (value->next)
874 value->next->prev = value->prev;
875 if (value == registeredScriptStrings)
876 registeredScriptStrings = value->next;
877 value->prev = 0;
878 value->next = 0;
879}
880
881inline QScriptContext *QScriptEnginePrivate::contextForFrame(JSC::ExecState *frame)
882{
883 if (frame && frame->callerFrame()->hasHostCallFrameFlag() && !frame->callee()
884 && frame->callerFrame()->removeHostCallFrameFlag() == QScript::scriptEngineFromExec(exec: frame)->globalExec()) {
885 //skip the "fake" context created in Interpreter::execute.
886 frame = frame->callerFrame()->removeHostCallFrameFlag();
887 }
888 return reinterpret_cast<QScriptContext *>(frame);
889}
890
891inline JSC::ExecState *QScriptEnginePrivate::frameForContext(QScriptContext *context)
892{
893 return reinterpret_cast<JSC::ExecState*>(context);
894}
895
896inline const JSC::ExecState *QScriptEnginePrivate::frameForContext(const QScriptContext *context)
897{
898 return reinterpret_cast<const JSC::ExecState*>(context);
899}
900
901inline bool QScriptEnginePrivate::hasValidCodeBlockRegister(JSC::ExecState *frame)
902{
903#if ENABLE(JIT)
904 // Frames created by the VM don't have their CodeBlock register
905 // initialized. We can detect such frames by checking if the
906 // callee is a host JSFunction.
907 JSC::JSObject *callee = frame->callee();
908 return !(callee && callee->inherits(info: &JSC::JSFunction::info)
909 && JSC::asFunction(value: callee)->isHostFunction());
910#else
911 Q_UNUSED(frame);
912 return true;
913#endif
914}
915
916inline JSC::ExecState *QScriptEnginePrivate::globalExec() const
917{
918 return originalGlobalObject()->globalExec();
919}
920
921inline JSC::JSValue QScriptEnginePrivate::newArray(JSC::ExecState *exec, uint length)
922{
923 return JSC::constructEmptyArray(exec, initialLength: length);
924}
925
926inline JSC::JSValue QScriptEnginePrivate::newDate(JSC::ExecState *exec, qsreal value)
927{
928 JSC::JSValue val = JSC::jsNumber(exec, d: value);
929 JSC::ArgList args(&val, 1);
930 return JSC::constructDate(exec, args);
931}
932
933inline JSC::JSValue QScriptEnginePrivate::newDate(JSC::ExecState *exec, const QDateTime &value)
934{
935 return newDate(exec, value: QScript::DateTimeToMs(exec, value));
936}
937
938inline JSC::JSValue QScriptEnginePrivate::newObject()
939{
940 return new (currentFrame)QScriptObject(scriptObjectStructure);
941}
942
943inline bool QScriptEnginePrivate::isObject(JSC::JSValue value)
944{
945 return value && value.isObject();
946}
947
948inline bool QScriptEnginePrivate::isArray(JSC::JSValue value)
949{
950 return isObject(value) && value.inherits(classInfo: &JSC::JSArray::info);
951}
952
953inline bool QScriptEnginePrivate::isDate(JSC::JSValue value)
954{
955 return isObject(value) && value.inherits(classInfo: &JSC::DateInstance::info);
956}
957
958inline bool QScriptEnginePrivate::isError(JSC::JSValue value)
959{
960 return isObject(value) && value.inherits(classInfo: &JSC::ErrorInstance::info);
961}
962
963inline bool QScriptEnginePrivate::isRegExp(JSC::JSValue value)
964{
965 return isObject(value) && value.inherits(classInfo: &JSC::RegExpObject::info);
966}
967
968inline bool QScriptEnginePrivate::isVariant(JSC::JSValue value)
969{
970 if (!isObject(value) || !value.inherits(classInfo: &QScriptObject::info))
971 return false;
972 QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(value));
973 QScriptObjectDelegate *delegate = object->delegate();
974 return (delegate && (delegate->type() == QScriptObjectDelegate::Variant));
975}
976
977inline bool QScriptEnginePrivate::isQObject(JSC::JSValue value)
978{
979#ifndef QT_NO_QOBJECT
980 if (!isObject(value) || !value.inherits(classInfo: &QScriptObject::info))
981 return false;
982 QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(value));
983 QScriptObjectDelegate *delegate = object->delegate();
984
985 if (delegate) {
986 if (delegate->type() == QScriptObjectDelegate::QtObject
987 || (delegate->type() == QScriptObjectDelegate::DeclarativeClassObject
988 && static_cast<QScript::DeclarativeObjectDelegate*>(delegate)->scriptClass()->isQObject()))
989 return true;
990
991 if (delegate->type() == QScriptObjectDelegate::Variant) {
992 QVariant var = variantValue(value);
993 int type = var.userType();
994 if ((QMetaType::typeFlags(type) & QMetaType::PointerToQObject))
995 return true;
996 }
997 }
998#endif
999 return false;
1000}
1001
1002inline bool QScriptEnginePrivate::isQMetaObject(JSC::JSValue value)
1003{
1004#ifndef QT_NO_QOBJECT
1005 return isObject(value) && JSC::asObject(value)->inherits(info: &QScript::QMetaObjectWrapperObject::info);
1006#else
1007 return false;
1008#endif
1009}
1010
1011inline bool QScriptEnginePrivate::toBool(JSC::ExecState *exec, JSC::JSValue value)
1012{
1013 JSC::JSValue savedException;
1014 saveException(exec, val: &savedException);
1015 bool result = value.toBoolean(exec);
1016 restoreException(exec, val: savedException);
1017 return result;
1018}
1019
1020inline qsreal QScriptEnginePrivate::toInteger(JSC::ExecState *exec, JSC::JSValue value)
1021{
1022 JSC::JSValue savedException;
1023 saveException(exec, val: &savedException);
1024 qsreal result = value.toInteger(exec);
1025 restoreException(exec, val: savedException);
1026 return result;
1027}
1028
1029inline qsreal QScriptEnginePrivate::toNumber(JSC::ExecState *exec, JSC::JSValue value)
1030{
1031 JSC::JSValue savedException;
1032 saveException(exec, val: &savedException);
1033 qsreal result = value.toNumber(exec);
1034 restoreException(exec, val: savedException);
1035 return result;
1036}
1037
1038inline qint32 QScriptEnginePrivate::toInt32(JSC::ExecState *exec, JSC::JSValue value)
1039{
1040 JSC::JSValue savedException;
1041 saveException(exec, val: &savedException);
1042 qint32 result = value.toInt32(exec);
1043 restoreException(exec, val: savedException);
1044 return result;
1045}
1046
1047inline quint32 QScriptEnginePrivate::toUInt32(JSC::ExecState *exec, JSC::JSValue value)
1048{
1049 JSC::JSValue savedException;
1050 saveException(exec, val: &savedException);
1051 quint32 result = value.toUInt32(exec);
1052 restoreException(exec, val: savedException);
1053 return result;
1054}
1055
1056inline quint16 QScriptEnginePrivate::toUInt16(JSC::ExecState *exec, JSC::JSValue value)
1057{
1058 // ### no equivalent function in JSC
1059 return QScript::ToUInt16(toNumber(exec, value));
1060}
1061
1062inline JSC::UString QScriptEnginePrivate::toString(JSC::ExecState *exec, JSC::JSValue value)
1063{
1064 if (!value)
1065 return JSC::UString();
1066 JSC::JSValue savedException;
1067 saveException(exec, val: &savedException);
1068 JSC::UString str = value.toString(exec);
1069 if (exec && exec->hadException() && !str.size()) {
1070 JSC::JSValue savedException2;
1071 saveException(exec, val: &savedException2);
1072 str = savedException2.toString(exec);
1073 restoreException(exec, val: savedException2);
1074 }
1075 if (savedException)
1076 restoreException(exec, val: savedException);
1077 return str;
1078}
1079
1080inline QDateTime QScriptEnginePrivate::toDateTime(JSC::ExecState *exec, JSC::JSValue value)
1081{
1082 if (!isDate(value))
1083 return QDateTime();
1084 qsreal t = static_cast<JSC::DateInstance*>(JSC::asObject(value))->internalNumber();
1085 return QScript::MsToDateTime(exec, t);
1086}
1087
1088inline QObject *QScriptEnginePrivate::toQObject(JSC::ExecState *exec, JSC::JSValue value)
1089{
1090#ifndef QT_NO_QOBJECT
1091 if (isObject(value) && value.inherits(classInfo: &QScriptObject::info)) {
1092 QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(value));
1093 QScriptObjectDelegate *delegate = object->delegate();
1094 if (!delegate)
1095 return 0;
1096 if (delegate->type() == QScriptObjectDelegate::QtObject)
1097 return static_cast<QScript::QObjectDelegate*>(delegate)->value();
1098 if (delegate->type() == QScriptObjectDelegate::DeclarativeClassObject)
1099 return static_cast<QScript::DeclarativeObjectDelegate*>(delegate)->scriptClass()->toQObject(declarativeObject(value));
1100 if (delegate->type() == QScriptObjectDelegate::Variant) {
1101 QVariant var = variantValue(value);
1102 int type = var.userType();
1103 if (QMetaType::typeFlags(type) & QMetaType::PointerToQObject)
1104 return *reinterpret_cast<QObject* const *>(var.constData());
1105 }
1106 } else if (isObject(value) && value.inherits(classInfo: &QScript::QScriptActivationObject::info)) {
1107 QScript::QScriptActivationObject *proxy = static_cast<QScript::QScriptActivationObject *>(JSC::asObject(value));
1108 return toQObject(exec, value: proxy->delegate());
1109 }
1110#endif
1111 return 0;
1112}
1113
1114inline const QMetaObject *QScriptEnginePrivate::toQMetaObject(JSC::ExecState*, JSC::JSValue value)
1115{
1116#ifndef QT_NO_QOBJECT
1117 if (isQMetaObject(value))
1118 return static_cast<QScript::QMetaObjectWrapperObject*>(JSC::asObject(value))->value();
1119#endif
1120 return 0;
1121}
1122
1123inline QVariant &QScriptEnginePrivate::variantValue(JSC::JSValue value)
1124{
1125 Q_ASSERT(value.inherits(&QScriptObject::info));
1126 QScriptObjectDelegate *delegate = static_cast<QScriptObject*>(JSC::asObject(value))->delegate();
1127 Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::Variant));
1128 return static_cast<QScript::QVariantDelegate*>(delegate)->value();
1129}
1130
1131inline void QScriptEnginePrivate::setVariantValue(JSC::JSValue objectValue, const QVariant &value)
1132{
1133 Q_ASSERT(objectValue.inherits(&QScriptObject::info));
1134 QScriptObjectDelegate *delegate = static_cast<QScriptObject*>(JSC::asObject(value: objectValue))->delegate();
1135 Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::Variant));
1136 static_cast<QScript::QVariantDelegate*>(delegate)->setValue(value);
1137}
1138
1139inline QScriptDeclarativeClass *QScriptEnginePrivate::declarativeClass(JSC::JSValue v)
1140{
1141 if (!QScriptEnginePrivate::isObject(value: v) || !v.inherits(classInfo: &QScriptObject::info))
1142 return 0;
1143 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(value: v));
1144 QScriptObjectDelegate *delegate = scriptObject->delegate();
1145 if (!delegate || (delegate->type() != QScriptObjectDelegate::DeclarativeClassObject))
1146 return 0;
1147 return static_cast<QScript::DeclarativeObjectDelegate*>(delegate)->scriptClass();
1148}
1149
1150inline QScriptDeclarativeClass::Object *QScriptEnginePrivate::declarativeObject(JSC::JSValue v)
1151{
1152 if (!QScriptEnginePrivate::isObject(value: v) || !v.inherits(classInfo: &QScriptObject::info))
1153 return 0;
1154 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(value: v));
1155 QScriptObjectDelegate *delegate = scriptObject->delegate();
1156 if (!delegate || (delegate->type() != QScriptObjectDelegate::DeclarativeClassObject))
1157 return 0;
1158 return static_cast<QScript::DeclarativeObjectDelegate*>(delegate)->object();
1159}
1160
1161QT_END_NAMESPACE
1162
1163#endif
1164

source code of qtscript/src/script/api/qscriptengine_p.h