source: trunk/src/script/api/qscriptengine_p.h@ 618

Last change on this file since 618 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 19.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtScript module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL-ONLY$
10** GNU Lesser General Public License Usage
11** This file may be used under the terms of the GNU Lesser
12** General Public License version 2.1 as published by the Free Software
13** Foundation and appearing in the file LICENSE.LGPL included in the
14** packaging of this file. Please review the following information to
15** ensure the GNU Lesser General Public License version 2.1 requirements
16** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17**
18** If you have questions regarding the use of this file, please contact
19** Nokia at [email protected].
20** $QT_END_LICENSE$
21**
22****************************************************************************/
23
24#ifndef QSCRIPTENGINE_P_H
25#define QSCRIPTENGINE_P_H
26
27//
28// W A R N I N G
29// -------------
30//
31// This file is not part of the Qt API. It exists purely as an
32// implementation detail. This header file may change from version to
33// version without notice, or even be removed.
34//
35// We mean it.
36//
37
38#include "private/qobject_p.h"
39
40#include <QtCore/qhash.h>
41#include <QtCore/qset.h>
42#include "qscriptvalue_p.h"
43#include "qscriptstring_p.h"
44
45#include "Debugger.h"
46#include "Lexer.h"
47#include "RefPtr.h"
48#include "SourceProvider.h"
49#include "Structure.h"
50#include "JSGlobalObject.h"
51#include "JSValue.h"
52
53namespace JSC
54{
55 class EvalExecutable;
56 class ExecState;
57 typedef ExecState CallFrame;
58 class JSCell;
59 class JSGlobalObject;
60 class UString;
61}
62
63
64QT_BEGIN_NAMESPACE
65
66class QString;
67class QStringList;
68class QScriptContext;
69class QScriptValue;
70class QScriptTypeInfo;
71class QScriptEngineAgent;
72class QScriptEnginePrivate;
73class QScriptSyntaxCheckResult;
74class QScriptEngine;
75
76namespace QScript
77{
78 class QObjectPrototype;
79 class QMetaObjectPrototype;
80 class QVariantPrototype;
81#ifndef QT_NO_QOBJECT
82 class QObjectData;
83#endif
84 class TimeoutCheckerProxy;
85
86 //some conversion helper functions
87 inline QScriptEnginePrivate *scriptEngineFromExec(const JSC::ExecState *exec);
88 bool isFunction(JSC::JSValue value);
89
90 class UStringSourceProviderWithFeedback;
91
92struct GlobalClientData : public JSC::JSGlobalData::ClientData
93{
94 GlobalClientData(QScriptEnginePrivate *e)
95 : engine(e) {}
96 virtual ~GlobalClientData() {}
97 virtual void mark(JSC::MarkStack& markStack);
98
99 QScriptEnginePrivate *engine;
100};
101
102} // namespace QScript
103
104class QScriptEnginePrivate
105#ifndef QT_NO_QOBJECT
106 : public QObjectPrivate
107#endif
108{
109 Q_DECLARE_PUBLIC(QScriptEngine)
110public:
111 QScriptEnginePrivate();
112 virtual ~QScriptEnginePrivate();
113
114 static QScriptEnginePrivate *get(QScriptEngine *q) { return q ? q->d_func() : 0; }
115 static QScriptEngine *get(QScriptEnginePrivate *d) { return d ? d->q_func() : 0; }
116
117 static bool convert(const QScriptValue &value,
118 int type, void *ptr,
119 QScriptEnginePrivate *eng);
120 QScriptValue create(int type, const void *ptr);
121 bool hasDemarshalFunction(int type) const;
122
123 inline QScriptValue scriptValueFromJSCValue(JSC::JSValue value);
124 inline JSC::JSValue scriptValueToJSCValue(const QScriptValue &value);
125
126 QScriptValue scriptValueFromVariant(const QVariant &value);
127 QVariant scriptValueToVariant(const QScriptValue &value, int targetType);
128
129 JSC::JSValue jscValueFromVariant(const QVariant &value);
130 QVariant jscValueToVariant(JSC::JSValue value, int targetType);
131
132 QScriptValue arrayFromStringList(const QStringList &lst);
133 static QStringList stringListFromArray(const QScriptValue &arr);
134
135 QScriptValue arrayFromVariantList(const QVariantList &lst);
136 static QVariantList variantListFromArray(const QScriptValue &arr);
137
138 QScriptValue objectFromVariantMap(const QVariantMap &vmap);
139 static QVariantMap variantMapFromObject(const QScriptValue &obj);
140
141 JSC::JSValue defaultPrototype(int metaTypeId) const;
142 void setDefaultPrototype(int metaTypeId, JSC::JSValue prototype);
143
144 static inline QScriptContext *contextForFrame(JSC::ExecState *frame);
145 static inline JSC::ExecState *frameForContext(QScriptContext *context);
146 static inline const JSC::ExecState *frameForContext(const QScriptContext *context);
147
148 JSC::JSGlobalObject *originalGlobalObject() const;
149 JSC::JSObject *getOriginalGlobalObjectProxy();
150 JSC::JSObject *customGlobalObject() const;
151 JSC::JSObject *globalObject() const;
152 void setGlobalObject(JSC::JSObject *object);
153 inline JSC::ExecState *globalExec() const;
154 JSC::JSValue toUsableValue(JSC::JSValue value);
155 static JSC::JSValue thisForContext(JSC::ExecState *frame);
156 static JSC::Register *thisRegisterForFrame(JSC::ExecState *frame);
157
158 JSC::CallFrame *pushContext(JSC::CallFrame *exec, JSC::JSValue thisObject, const JSC::ArgList& args,
159 JSC::JSObject *callee, bool calledAsConstructor = false, bool clearScopeChain = false);
160 void popContext();
161
162 void mark(JSC::MarkStack& markStack);
163 bool isCollecting() const;
164 void collectGarbage();
165
166 //flags that we set on the return value register for native function. (ie when codeBlock is 0)
167 enum ContextFlags {
168 NativeContext = 1,
169 CalledAsConstructorContext = 2,
170 HasScopeContext = 4, // Specifies that the is a QScriptActivationObject
171 ShouldRestoreCallFrame = 8
172 };
173 static uint contextFlags(JSC::ExecState *);
174 static void setContextFlags(JSC::ExecState *, uint);
175
176 QScript::TimeoutCheckerProxy *timeoutChecker() const;
177
178 void agentDeleted(QScriptEngineAgent *agent);
179
180 void setCurrentException(QScriptValue exception) { m_currentException = exception; }
181 QScriptValue currentException() const { return m_currentException; }
182 void clearCurrentException() { m_currentException.d_ptr.reset(); }
183
184#ifndef QT_NO_QOBJECT
185 JSC::JSValue newQObject(QObject *object,
186 QScriptEngine::ValueOwnership ownership = QScriptEngine::QtOwnership,
187 const QScriptEngine:: QObjectWrapOptions &options = 0);
188 JSC::JSValue newQMetaObject(const QMetaObject *metaObject,
189 JSC::JSValue ctor);
190
191 static QScriptSyntaxCheckResult checkSyntax(const QString &program);
192 static bool canEvaluate(const QString &program);
193 static bool convertToNativeQObject(const QScriptValue &value,
194 const QByteArray &targetType,
195 void **result);
196
197 JSC::JSValue evaluateHelper(JSC::ExecState *exec, intptr_t sourceId,
198 JSC::EvalExecutable *executable,
199 bool &compile);
200
201 QScript::QObjectData *qobjectData(QObject *object);
202 void disposeQObject(QObject *object);
203 void emitSignalHandlerException();
204
205 bool scriptConnect(QObject *sender, const char *signal,
206 JSC::JSValue receiver, JSC::JSValue function,
207 Qt::ConnectionType type);
208 bool scriptDisconnect(QObject *sender, const char *signal,
209 JSC::JSValue receiver, JSC::JSValue function);
210
211 bool scriptConnect(QObject *sender, int index,
212 JSC::JSValue receiver, JSC::JSValue function,
213 JSC::JSValue senderWrapper,
214 Qt::ConnectionType type);
215 bool scriptDisconnect(QObject *sender, int index,
216 JSC::JSValue receiver, JSC::JSValue function);
217
218 bool scriptConnect(JSC::JSValue signal, JSC::JSValue receiver,
219 JSC::JSValue function, Qt::ConnectionType type);
220 bool scriptDisconnect(JSC::JSValue signal, JSC::JSValue receiver,
221 JSC::JSValue function);
222
223 inline QScriptValuePrivate *allocateScriptValuePrivate(size_t);
224 inline void freeScriptValuePrivate(QScriptValuePrivate *p);
225
226 inline void registerScriptValue(QScriptValuePrivate *value);
227 inline void unregisterScriptValue(QScriptValuePrivate *value);
228 void detachAllRegisteredScriptValues();
229
230 inline void registerScriptString(QScriptStringPrivate *value);
231 inline void unregisterScriptString(QScriptStringPrivate *value);
232 void detachAllRegisteredScriptStrings();
233
234 // private slots
235 void _q_objectDestroyed(QObject *);
236#endif
237
238 JSC::JSGlobalData *globalData;
239 JSC::JSObject *originalGlobalObjectProxy;
240 JSC::ExecState *currentFrame;
241
242 WTF::RefPtr<JSC::Structure> scriptObjectStructure;
243
244 QScript::QObjectPrototype *qobjectPrototype;
245 WTF::RefPtr<JSC::Structure> qobjectWrapperObjectStructure;
246
247 QScript::QMetaObjectPrototype *qmetaobjectPrototype;
248 WTF::RefPtr<JSC::Structure> qmetaobjectWrapperObjectStructure;
249
250 QScript::QVariantPrototype *variantPrototype;
251 WTF::RefPtr<JSC::Structure> variantWrapperObjectStructure;
252
253 QList<QScriptEngineAgent*> ownedAgents;
254 QScriptEngineAgent *activeAgent;
255 int agentLineNumber;
256 QScriptValuePrivate *registeredScriptValues;
257 QScriptValuePrivate *freeScriptValues;
258 QScriptStringPrivate *registeredScriptStrings;
259 QHash<int, QScriptTypeInfo*> m_typeInfos;
260 int processEventsInterval;
261 QScriptValue abortResult;
262 bool inEval;
263
264 QSet<QString> importedExtensions;
265 QSet<QString> extensionsBeingImported;
266
267 QHash<intptr_t, QScript::UStringSourceProviderWithFeedback*> loadedScripts;
268 QScriptValue m_currentException;
269
270#ifndef QT_NO_QOBJECT
271 QHash<QObject*, QScript::QObjectData*> m_qobjectData;
272#endif
273
274#ifdef QT_NO_QOBJECT
275 QScriptEngine *q_ptr;
276#endif
277};
278
279namespace QScript
280{
281
282/*Helper class. Main purpose is to give debugger feedback about unloading and loading scripts.
283 It keeps pointer to JSGlobalObject assuming that it is always the same - there is no way to update
284 this data. Class is internal and used as an implementation detail in and only in QScriptEngine::evaluate.*/
285class UStringSourceProviderWithFeedback: public JSC::UStringSourceProvider
286{
287public:
288 static PassRefPtr<UStringSourceProviderWithFeedback> create(
289 const JSC::UString& source, const JSC::UString& url,
290 int lineNumber, QScriptEnginePrivate* engine)
291 {
292 return adoptRef(new UStringSourceProviderWithFeedback(source, url, lineNumber, engine));
293 }
294
295 /* Destruction means that there is no more copies of script so create scriptUnload event
296 and unregister script in QScriptEnginePrivate::loadedScripts */
297 virtual ~UStringSourceProviderWithFeedback()
298 {
299 if (m_ptr) {
300 if (JSC::Debugger* debugger = this->debugger())
301 debugger->scriptUnload(asID());
302 m_ptr->loadedScripts.remove(asID());
303 }
304 }
305
306 /* set internal QScriptEnginePrivate pointer to null and create unloadScript event, should be called
307 only if QScriptEnginePrivate is about to be destroyed.*/
308 void disconnectFromEngine()
309 {
310 if (JSC::Debugger* debugger = this->debugger())
311 debugger->scriptUnload(asID());
312 m_ptr = 0;
313 }
314
315 int columnNumberFromOffset(int offset) const
316 {
317 for (const UChar *c = m_source.data() + offset; c >= m_source.data(); --c) {
318 if (JSC::Lexer::isLineTerminator(*c))
319 return offset - static_cast<int>(c - data());
320 }
321 return offset + 1;
322 }
323
324protected:
325 UStringSourceProviderWithFeedback(const JSC::UString& source, const JSC::UString& url,
326 int lineNumber, QScriptEnginePrivate* engine)
327 : UStringSourceProvider(source, url),
328 m_ptr(engine)
329 {
330 if (JSC::Debugger* debugger = this->debugger())
331 debugger->scriptLoad(asID(), source, url, lineNumber);
332 if (m_ptr)
333 m_ptr->loadedScripts.insert(asID(), this);
334 }
335
336 JSC::Debugger* debugger()
337 {
338 //if m_ptr is null it mean that QScriptEnginePrivate was destroyed and scriptUnload was called
339 //else m_ptr is stable and we can use it as normal pointer without hesitation
340 if(!m_ptr)
341 return 0; //we are in ~QScriptEnginePrivate
342 else
343 return m_ptr->originalGlobalObject()->debugger(); //QScriptEnginePrivate is still alive
344 }
345
346 //trace global object and debugger instance
347 QScriptEnginePrivate* m_ptr;
348};
349
350class SaveFrameHelper
351{
352public:
353 SaveFrameHelper(QScriptEnginePrivate *eng,
354 JSC::ExecState *newFrame)
355 : engine(eng), oldFrame(eng->currentFrame)
356 {
357 eng->currentFrame = newFrame;
358 }
359 ~SaveFrameHelper()
360 {
361 engine->currentFrame = oldFrame;
362 }
363private:
364 QScriptEnginePrivate *engine;
365 JSC::ExecState *oldFrame;
366};
367
368inline QScriptEnginePrivate *scriptEngineFromExec(const JSC::ExecState *exec)
369{
370 return static_cast<GlobalClientData*>(exec->globalData().clientData)->engine;
371}
372
373} // namespace QScript
374
375inline QScriptValuePrivate *QScriptEnginePrivate::allocateScriptValuePrivate(size_t size)
376{
377 if (freeScriptValues) {
378 QScriptValuePrivate *p = freeScriptValues;
379 freeScriptValues = p->next;
380 return p;
381 }
382 return reinterpret_cast<QScriptValuePrivate*>(qMalloc(size));
383}
384
385inline void QScriptEnginePrivate::freeScriptValuePrivate(QScriptValuePrivate *p)
386{
387 p->next = freeScriptValues;
388 freeScriptValues = p;
389}
390
391inline void QScriptEnginePrivate::registerScriptValue(QScriptValuePrivate *value)
392{
393 value->prev = 0;
394 value->next = registeredScriptValues;
395 if (registeredScriptValues)
396 registeredScriptValues->prev = value;
397 registeredScriptValues = value;
398}
399
400inline void QScriptEnginePrivate::unregisterScriptValue(QScriptValuePrivate *value)
401{
402 if (value->prev)
403 value->prev->next = value->next;
404 if (value->next)
405 value->next->prev = value->prev;
406 if (value == registeredScriptValues)
407 registeredScriptValues = value->next;
408 value->prev = 0;
409 value->next = 0;
410}
411
412inline QScriptValue QScriptEnginePrivate::scriptValueFromJSCValue(JSC::JSValue value)
413{
414 if (!value)
415 return QScriptValue();
416
417 QScriptValuePrivate *p_value = new (this)QScriptValuePrivate(this);
418 p_value->initFrom(value);
419 return QScriptValuePrivate::toPublic(p_value);
420}
421
422inline JSC::JSValue QScriptEnginePrivate::scriptValueToJSCValue(const QScriptValue &value)
423{
424 QScriptValuePrivate *vv = QScriptValuePrivate::get(value);
425 if (!vv)
426 return JSC::JSValue();
427 if (vv->type != QScriptValuePrivate::JavaScriptCore) {
428 Q_ASSERT(!vv->engine || vv->engine == this);
429 vv->engine = this;
430 if (vv->type == QScriptValuePrivate::Number) {
431 vv->initFrom(JSC::jsNumber(currentFrame, vv->numberValue));
432 } else { //QScriptValuePrivate::String
433 vv->initFrom(JSC::jsString(currentFrame, vv->stringValue));
434 }
435 }
436 return vv->jscValue;
437}
438
439inline QScriptValuePrivate::~QScriptValuePrivate()
440{
441 if (engine)
442 engine->unregisterScriptValue(this);
443}
444
445inline void QScriptValuePrivate::initFrom(JSC::JSValue value)
446{
447 if (value.isCell()) {
448 Q_ASSERT(engine != 0);
449 value = engine->toUsableValue(value);
450 }
451 type = JavaScriptCore;
452 jscValue = value;
453 if (engine)
454 engine->registerScriptValue(this);
455}
456
457inline void QScriptValuePrivate::initFrom(qsreal value)
458{
459 type = Number;
460 numberValue = value;
461 if (engine)
462 engine->registerScriptValue(this);
463}
464
465inline void QScriptValuePrivate::initFrom(const QString &value)
466{
467 type = String;
468 stringValue = value;
469 if (engine)
470 engine->registerScriptValue(this);
471}
472
473inline QScriptValue QScriptValuePrivate::property(const QString &name, int resolveMode) const
474{
475 JSC::ExecState *exec = engine->currentFrame;
476 return property(JSC::Identifier(exec, name), resolveMode);
477}
478
479inline QScriptValue QScriptValuePrivate::property(const JSC::Identifier &id, int resolveMode) const
480{
481 Q_ASSERT(isObject());
482 JSC::ExecState *exec = engine->currentFrame;
483 JSC::JSObject *object = JSC::asObject(jscValue);
484 JSC::PropertySlot slot(object);
485 if ((resolveMode & QScriptValue::ResolvePrototype) && object->getPropertySlot(exec, id, slot))
486 return engine->scriptValueFromJSCValue(slot.getValue(exec, id));
487 return propertyHelper(id, resolveMode);
488}
489
490inline QScriptValue QScriptValuePrivate::property(quint32 index, int resolveMode) const
491{
492 Q_ASSERT(isObject());
493 JSC::ExecState *exec = engine->currentFrame;
494 JSC::JSObject *object = JSC::asObject(jscValue);
495 JSC::PropertySlot slot(object);
496 if ((resolveMode & QScriptValue::ResolvePrototype) && object->getPropertySlot(exec, index, slot))
497 return engine->scriptValueFromJSCValue(slot.getValue(exec, index));
498 return propertyHelper(index, resolveMode);
499}
500
501inline void* QScriptValuePrivate::operator new(size_t size, QScriptEnginePrivate *engine)
502{
503 if (engine)
504 return engine->allocateScriptValuePrivate(size);
505 return qMalloc(size);
506}
507
508inline void QScriptValuePrivate::operator delete(void *ptr)
509{
510 QScriptValuePrivate *d = reinterpret_cast<QScriptValuePrivate*>(ptr);
511 if (d->engine)
512 d->engine->freeScriptValuePrivate(d);
513 else
514 qFree(d);
515}
516
517inline void QScriptValuePrivate::saveException(JSC::ExecState *exec, JSC::JSValue *val)
518{
519 if (exec) {
520 *val = exec->exception();
521 exec->clearException();
522 } else {
523 *val = JSC::JSValue();
524 }
525}
526
527inline void QScriptValuePrivate::restoreException(JSC::ExecState *exec, JSC::JSValue val)
528{
529 if (exec && val)
530 exec->setException(val);
531}
532
533inline void QScriptEnginePrivate::registerScriptString(QScriptStringPrivate *value)
534{
535 Q_ASSERT(value->type == QScriptStringPrivate::HeapAllocated);
536 value->prev = 0;
537 value->next = registeredScriptStrings;
538 if (registeredScriptStrings)
539 registeredScriptStrings->prev = value;
540 registeredScriptStrings = value;
541}
542
543inline void QScriptEnginePrivate::unregisterScriptString(QScriptStringPrivate *value)
544{
545 Q_ASSERT(value->type == QScriptStringPrivate::HeapAllocated);
546 if (value->prev)
547 value->prev->next = value->next;
548 if (value->next)
549 value->next->prev = value->prev;
550 if (value == registeredScriptStrings)
551 registeredScriptStrings = value->next;
552 value->prev = 0;
553 value->next = 0;
554}
555
556inline QScriptContext *QScriptEnginePrivate::contextForFrame(JSC::ExecState *frame)
557{
558 if (frame && frame->callerFrame()->hasHostCallFrameFlag() && !frame->callee()
559 && frame->callerFrame()->removeHostCallFrameFlag() == QScript::scriptEngineFromExec(frame)->globalExec()) {
560 //skip the "fake" context created in Interpreter::execute.
561 frame = frame->callerFrame()->removeHostCallFrameFlag();
562 }
563 return reinterpret_cast<QScriptContext *>(frame);
564}
565
566inline JSC::ExecState *QScriptEnginePrivate::frameForContext(QScriptContext *context)
567{
568 return reinterpret_cast<JSC::ExecState*>(context);
569}
570
571inline const JSC::ExecState *QScriptEnginePrivate::frameForContext(const QScriptContext *context)
572{
573 return reinterpret_cast<const JSC::ExecState*>(context);
574}
575
576inline JSC::ExecState *QScriptEnginePrivate::globalExec() const
577{
578 return originalGlobalObject()->globalExec();
579}
580
581QT_END_NAMESPACE
582
583#endif
Note: See TracBrowser for help on using the repository browser.