1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the Qt Solutions component.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 ** * Redistributions of source code must retain the above copyright
15 ** notice, this list of conditions and the following disclaimer.
16 ** * Redistributions in binary form must reproduce the above copyright
17 ** notice, this list of conditions and the following disclaimer in
18 ** the documentation and/or other materials provided with the
19 ** distribution.
20 ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
21 ** of its contributors may be used to endorse or promote products derived
22 ** from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41
42 #include "qscriptengine_p.h"
43
44
45 #include "qscriptvalueimpl_p.h"
46 #include "qscriptcontext_p.h"
47 #include "qscriptmember_p.h"
48 #include "qscriptobject_p.h"
49 #include "qscriptlexer_p.h"
50 #include "qscriptnodepool_p.h"
51 #include "qscriptparser_p.h"
52 #include "qscriptcompiler_p.h"
53 #include "qscriptvalueiteratorimpl_p.h"
54 #include "qscriptecmaglobal_p.h"
55 #include "qscriptecmamath_p.h"
56 #include "qscriptecmaarray_p.h"
57 #include "qscriptextenumeration_p.h"
58 #include "qscriptsyntaxchecker_p.h"
59 #include "qscriptsyntaxcheckresult_p.h"
60 #include "qscriptclass.h"
61 #include "qscriptclass_p.h"
62 #include "qscriptengineagent.h"
63
64 #include <QDate>
65 #include <QDateTime>
66 #include <QRegExp>
67 #include <QStringList>
68 #include <QVariant>
69
70 #ifndef QT_NO_QOBJECT
71 #include "qscriptextensioninterface.h"
72 #include <QDir>
73 #include <QFile>
74 #include <QFileInfo>
75 #include <QTextStream>
76 #include <QCoreApplication>
77 #include <QPluginLoader>
78 #endif
79
80 Q_DECLARE_METATYPE(QScriptValue)
81 #ifndef QT_NO_QOBJECT
82 Q_DECLARE_METATYPE(QObjectList)
83 #endif
84 Q_DECLARE_METATYPE(QList<int>)
85
86 QT_BEGIN_NAMESPACE
87
88 extern char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str);
89 extern double qstrtod(const char *s00, char const **se, bool *ok);
90
91 namespace QScript {
92
numberToString(qsreal value)93 QString numberToString(qsreal value)
94 {
95 if (qIsNaN(value))
96 return QLatin1String("NaN");
97
98 else if (qIsInf(value))
99 return QLatin1String(value < 0 ? "-Infinity" : "Infinity");
100
101 else if (value == 0)
102 return QLatin1String("0");
103
104 QByteArray buf;
105 buf.reserve(80);
106
107 int decpt;
108 int sign;
109 char *result = 0;
110 (void) qdtoa(value, 0, 0, &decpt, &sign, 0, &result);
111
112 if (! result)
113 return QString();
114
115 else if (decpt <= 0 && decpt > -6) {
116
117 buf.fill('0', -decpt + 2 + sign);
118
119 if (sign) // fix the sign.
120 buf[0] = '-';
121
122 buf[sign + 1] = '.';
123 buf += result;
124 }
125
126 else {
127 if (sign)
128 buf += '-';
129
130 buf += result;
131 int length = buf.length() - sign;
132
133 if (decpt <= 21 && decpt > 0) {
134 if (length <= decpt)
135 buf += QByteArray().fill('0', decpt - length);
136 else
137 buf.insert(decpt + sign, '.');
138 }
139
140 else if (result[0] >= '0' && result[0] <= '9') {
141 if (length > 1)
142 buf.insert(1 + sign, '.');
143
144 buf += 'e';
145 buf += (decpt >= 0) ? '+' : '-';
146
147 int e = decpt - 1;
148
149 if (e < 0)
150 e = -e;
151
152 if (e >= 100)
153 buf += '0' + e / 100;
154
155 if (e >= 10)
156 buf += '0' + (e % 100) / 10;
157
158 buf += '0' + e % 10;
159 }
160 }
161
162 free(result);
163
164 return QString::fromLatin1(buf);
165 }
166
toDigit(char c)167 static int toDigit(char c)
168 {
169 if ((c >= '0') && (c <= '9'))
170 return c - '0';
171 else if ((c >= 'a') && (c <= 'z'))
172 return 10 + c - 'a';
173 else if ((c >= 'A') && (c <= 'Z'))
174 return 10 + c - 'A';
175 return -1;
176 }
177
integerFromString(const char * buf,int size,int radix)178 qsreal integerFromString(const char *buf, int size, int radix)
179 {
180 if (size == 0)
181 return qSNaN();
182
183 qsreal sign = 1.0;
184 int i = 0;
185 if (buf[0] == '+') {
186 ++i;
187 } else if (buf[0] == '-') {
188 sign = -1.0;
189 ++i;
190 }
191
192 if (((size-i) >= 2) && (buf[i] == '0')) {
193 if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
194 && (radix < 34)) {
195 if ((radix != 0) && (radix != 16))
196 return 0;
197 radix = 16;
198 i += 2;
199 } else {
200 if (radix == 0) {
201 radix = 8;
202 ++i;
203 }
204 }
205 } else if (radix == 0) {
206 radix = 10;
207 }
208
209 int j = i;
210 for ( ; i < size; ++i) {
211 int d = toDigit(buf[i]);
212 if ((d == -1) || (d >= radix))
213 break;
214 }
215 qsreal result;
216 if (j == i) {
217 if (!qstrcmp(buf, "Infinity"))
218 result = qInf();
219 else
220 result = qSNaN();
221 } else {
222 result = 0;
223 qsreal multiplier = 1;
224 for (--i ; i >= j; --i, multiplier *= radix)
225 result += toDigit(buf[i]) * multiplier;
226 }
227 result *= sign;
228 return result;
229 }
230
integerFromString(const QString & str,int radix)231 qsreal integerFromString(const QString &str, int radix)
232 {
233 QByteArray ba = str.trimmed().toUtf8();
234 return integerFromString(ba.constData(), ba.size(), radix);
235 }
236
numberFromString(const QString & repr)237 qsreal numberFromString(const QString &repr)
238 {
239 QString str = repr.trimmed();
240 if ((str.length() > 2) && (str.at(0) == QLatin1Char('0')) && (str.at(1).toUpper() == QLatin1Char('X')))
241 return integerFromString(str.mid(2), 16);
242 QByteArray latin1 = str.toLatin1();
243 const char *data = latin1.constData();
244 const char *eptr = 0;
245 qsreal result = qstrtod(data, &eptr, 0);
246 if (eptr == data) {
247 if (str == QLatin1String("Infinity"))
248 result = +qInf();
249 else if (str == QLatin1String("+Infinity"))
250 result = +qInf();
251 else if (str == QLatin1String("-Infinity"))
252 result = -qInf();
253 else if (str.isEmpty())
254 result = 0;
255 else
256 result = qSNaN();
257 } else if (eptr != (data + latin1.length())) {
258 result = qSNaN();
259 }
260 return result;
261 }
262
NodePool(const QString & fileName,QScriptEnginePrivate * engine)263 NodePool::NodePool(const QString &fileName, QScriptEnginePrivate *engine)
264 : m_fileName(fileName), m_engine(engine)
265 {
266 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
267 m_id = engine->nextScriptId();
268 #endif
269 }
270
~NodePool()271 NodePool::~NodePool()
272 {
273 qDeleteAll(m_codeCache);
274 m_codeCache.clear();
275
276 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
277 m_engine->notifyScriptUnload(id());
278 #endif
279 }
280
createCompiledCode(AST::Node * node,CompilationUnit & compilation)281 Code *NodePool::createCompiledCode(AST::Node *node, CompilationUnit &compilation)
282 {
283 QHash<AST::Node*, Code*>::const_iterator it = m_codeCache.constFind(node);
284 if (it != m_codeCache.constEnd())
285 return it.value();
286
287 Code *code = new Code();
288 code->init(compilation, this);
289
290 m_codeCache.insert(node, code);
291 return code;
292 }
293
294 class EvalFunction : public QScriptFunction
295 {
296 public:
EvalFunction(QScriptEnginePrivate *)297 EvalFunction(QScriptEnginePrivate *)
298 { length = 1; }
299
~EvalFunction()300 virtual ~EvalFunction() {}
301
evaluate(QScriptContextPrivate * context,const QString & contents,int lineNo,const QString & fileName,bool calledFromScript)302 void evaluate(QScriptContextPrivate *context, const QString &contents,
303 int lineNo, const QString &fileName, bool calledFromScript)
304 {
305 QScriptEnginePrivate *eng_p = context->engine();
306
307 QExplicitlySharedDataPointer<NodePool> pool;
308 pool = new NodePool(fileName, eng_p);
309 eng_p->setNodePool(pool.data());
310
311 QString errorMessage;
312 int errorLineNumber;
313 AST::Node *program = eng_p->createAbstractSyntaxTree(
314 contents, lineNo, &errorMessage, &errorLineNumber);
315
316 eng_p->setNodePool(0);
317
318 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
319 eng_p->notifyScriptLoad(pool->id(), contents, fileName, lineNo);
320 #endif
321
322 Code *code = 0;
323 if (program) {
324 Compiler compiler(eng_p);
325 compiler.setTopLevelCompiler(true);
326 CompilationUnit compilation = compiler.compile(program);
327 if (!compilation.isValid()) {
328 errorMessage = compilation.errorMessage();
329 errorLineNumber = compilation.errorLineNumber();
330 } else {
331 code = pool->createCompiledCode(program, compilation);
332 }
333 }
334
335 if (!code) {
336 context->errorLineNumber = errorLineNumber;
337 context->currentLine = errorLineNumber;
338 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
339 Code *oldCode = context->m_code;
340 Code dummy;
341 dummy.astPool = pool.data();
342 context->m_code = &dummy; // so agents get the script ID
343 bool wasEvaluating = eng_p->m_evaluating;
344 eng_p->m_evaluating = true;
345 eng_p->notifyFunctionEntry(context);
346 #endif
347 context->throwError(QScriptContext::SyntaxError, errorMessage);
348 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
349 eng_p->notifyFunctionExit(context);
350 eng_p->m_evaluating = wasEvaluating;
351 context->m_code = oldCode;
352 #endif
353 return;
354 }
355
356 if (calledFromScript) {
357 if (QScriptContextPrivate *pc = context->parentContext()) {
358 context->setActivationObject(pc->activationObject());
359 context->setThisObject(pc->thisObject());
360 context->m_scopeChain = pc->m_scopeChain;
361 }
362 }
363
364 const QScriptInstruction *iPtr = context->instructionPointer();
365 context->execute(code);
366 context->setInstructionPointer(iPtr);
367 }
368
execute(QScriptContextPrivate * context)369 virtual void execute(QScriptContextPrivate *context)
370 {
371 QScriptEnginePrivate *eng = context->engine();
372 int lineNo = context->currentLine;
373 if (lineNo == -1) {
374 QScriptContextPrivate *pc = context->parentContext();
375 if (pc)
376 lineNo = pc->currentLine;
377 else
378 lineNo = 1;
379 }
380 QString fileName; // don't set this for now, we don't want to change the official eval() for now.
381
382 if (context->argumentCount() == 0) {
383 context->setReturnValue(eng->undefinedValue());
384 } else {
385 QScriptValueImpl arg = context->argument(0);
386 if (arg.isString()) {
387 QString contents = arg.toString();
388 evaluate(context, contents, lineNo, fileName, /*calledFromScript=*/true);
389 } else {
390 context->setReturnValue(arg);
391 }
392 }
393 }
394
functionName() const395 QString functionName() const
396 {
397 return QLatin1String("eval");
398 }
399 };
400
401 class ArgumentsClassData: public QScriptClassData
402 {
403
404 public:
405
get(const QScriptValueImpl & object)406 static inline QScript::ArgumentsObjectData *get(const QScriptValueImpl &object)
407 { return static_cast<QScript::ArgumentsObjectData*>(object.objectData()); }
408
409 virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId,
410 QScript::Member *member, QScriptValueImpl *base,
411 QScript::AccessMode access);
412 virtual bool get(const QScriptValueImpl &object, const QScript::Member &member,
413 QScriptValueImpl *out_value);
414 virtual bool put(QScriptValueImpl *object, const QScript::Member &member,
415 const QScriptValueImpl &value);
416 virtual void mark(const QScriptValueImpl &object, int generation);
417 virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object);
418 };
419
420 class ArgumentsClassDataIterator: public QScriptClassDataIterator
421 {
422 public:
423 ArgumentsClassDataIterator(ArgumentsObjectData *data);
424 virtual ~ArgumentsClassDataIterator();
425
426 virtual bool hasNext() const;
427 virtual void next(QScript::Member *member);
428
429 virtual bool hasPrevious() const;
430 virtual void previous(QScript::Member *member);
431
432 virtual void toFront();
433 virtual void toBack();
434
435 private:
436 ArgumentsObjectData *m_data;
437 uint m_pos;
438 };
439
resolve(const QScriptValueImpl & object,QScriptNameIdImpl * nameId,QScript::Member * member,QScriptValueImpl * base,QScript::AccessMode)440 bool ArgumentsClassData::resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId,
441 QScript::Member *member, QScriptValueImpl *base,
442 QScript::AccessMode /*access*/)
443 {
444 QString propertyName = object.engine()->toString(nameId);
445 bool isNumber;
446 quint32 index = propertyName.toUInt(&isNumber);
447 if (isNumber) {
448 QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object);
449 if (index < data->length) {
450 member->native(/*nameId=*/0, index, QScriptValue::SkipInEnumeration);
451 *base = object;
452 return true;
453 }
454 }
455
456 return false;
457 }
458
get(const QScriptValueImpl & object,const QScript::Member & member,QScriptValueImpl * out_value)459 bool ArgumentsClassData::get(const QScriptValueImpl &object, const QScript::Member &member,
460 QScriptValueImpl *out_value)
461 {
462 QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object);
463 if (member.nameId() == 0) {
464 QScriptObject *activation_data = data->activation.objectValue();
465 *out_value = activation_data->m_values[member.id()];
466 return true;
467 }
468 return false;
469 }
470
put(QScriptValueImpl * object,const QScript::Member & member,const QScriptValueImpl & value)471 bool ArgumentsClassData::put(QScriptValueImpl *object, const QScript::Member &member,
472 const QScriptValueImpl &value)
473 {
474 Q_ASSERT(member.nameId() == 0);
475 QScript::ArgumentsObjectData *data = ArgumentsClassData::get(*object);
476 QScriptObject *activation_data = data->activation.objectValue();
477 activation_data->m_values[member.id()] = value;
478 return true;
479 }
480
mark(const QScriptValueImpl & object,int generation)481 void ArgumentsClassData::mark(const QScriptValueImpl &object, int generation)
482 {
483 QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object);
484 data->activation.mark(generation);
485 }
486
newIterator(const QScriptValueImpl & object)487 QScriptClassDataIterator *ArgumentsClassData::newIterator(const QScriptValueImpl &object)
488 {
489 QScript::ArgumentsObjectData *data = ArgumentsClassData::get(object);
490 return new ArgumentsClassDataIterator(data);
491 }
492
ArgumentsClassDataIterator(ArgumentsObjectData * data)493 ArgumentsClassDataIterator::ArgumentsClassDataIterator(ArgumentsObjectData *data)
494 : m_data(data), m_pos(0)
495 {
496 }
497
~ArgumentsClassDataIterator()498 ArgumentsClassDataIterator::~ArgumentsClassDataIterator()
499 {
500 }
501
hasNext() const502 bool ArgumentsClassDataIterator::hasNext() const
503 {
504 return m_pos < m_data->length;
505 }
506
next(QScript::Member * member)507 void ArgumentsClassDataIterator::next(QScript::Member *member)
508 {
509 if (m_pos == m_data->length) {
510 member->invalidate();
511 } else {
512 member->native(/*nameId=*/0, m_pos, QScriptValue::SkipInEnumeration);
513 ++m_pos;
514 }
515 }
516
hasPrevious() const517 bool ArgumentsClassDataIterator::hasPrevious() const
518 {
519 return (m_pos != 0);
520 }
521
previous(QScript::Member * member)522 void ArgumentsClassDataIterator::previous(QScript::Member *member)
523 {
524 if (m_pos == 0) {
525 member->invalidate();
526 } else {
527 --m_pos;
528 member->native(/*nameId=*/0, m_pos, QScriptValue::SkipInEnumeration);
529 }
530 }
531
toFront()532 void ArgumentsClassDataIterator::toFront()
533 {
534 m_pos = 0;
535 }
536
toBack()537 void ArgumentsClassDataIterator::toBack()
538 {
539 m_pos = m_data->length;
540 }
541
542 } // namespace QScript
543
544 const qsreal QScriptEnginePrivate::D16 = 65536.0;
545 const qsreal QScriptEnginePrivate::D32 = 4294967296.0;
546
~QScriptEnginePrivate()547 QScriptEnginePrivate::~QScriptEnginePrivate()
548 {
549 while (!m_agents.isEmpty())
550 delete m_agents.takeFirst();
551
552 // invalidate values that we have references to
553 {
554 QHash<QScriptObject*, QScriptValuePrivate*>::const_iterator it;
555 for (it = m_objectHandles.constBegin(); it != m_objectHandles.constEnd(); ++it)
556 (*it)->invalidate();
557 }
558 {
559 QHash<QScriptNameIdImpl*, QScriptValuePrivate*>::const_iterator it;
560 for (it = m_stringHandles.constBegin(); it != m_stringHandles.constEnd(); ++it)
561 (*it)->invalidate();
562 }
563 {
564 QVector<QScriptValuePrivate*>::const_iterator it;
565 for (it = m_otherHandles.constBegin(); it != m_otherHandles.constEnd(); ++it)
566 (*it)->invalidate();
567 }
568
569 // invalidate interned strings that are known to the outside world
570 {
571 QHash<QScriptNameIdImpl*, QScriptStringPrivate*>::const_iterator it;
572 for (it = m_internedStrings.constBegin(); it != m_internedStrings.constEnd(); ++it)
573 it.value()->nameId = 0;
574 }
575
576 delete[] m_string_hash_base;
577 qDeleteAll(m_stringRepository);
578 qDeleteAll(m_tempStringRepository);
579
580 if (tempStackBegin)
581 delete[] tempStackBegin;
582
583 #ifndef QT_NO_QOBJECT
584 deletePendingQObjects();
585 qDeleteAll(m_qobjectData);
586 # ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
587 qDeleteAll(m_cachedMetaObjects);
588 # endif
589 #endif
590
591 qDeleteAll(m_allocated_classes);
592 }
593
changeAbstractSyntaxTree(QScript::AST::Node * prg)594 QScript::AST::Node *QScriptEnginePrivate::changeAbstractSyntaxTree(QScript::AST::Node *prg)
595 {
596 QScript::AST::Node *was = m_abstractSyntaxTree;
597 m_abstractSyntaxTree = prg;
598 return was;
599 }
600
createAbstractSyntaxTree(const QString & source,int lineNumber,QString * errorMessage,int * errorLineNumber)601 QScript::AST::Node *QScriptEnginePrivate::createAbstractSyntaxTree(
602 const QString &source, int lineNumber, QString *errorMessage, int *errorLineNumber)
603 {
604 QScript::Lexer lex(this);
605 setLexer(&lex);
606 lex.setCode(source, lineNumber);
607
608 QScriptParser parser;
609
610 if (! parser.parse(this)) {
611 if (errorMessage)
612 *errorMessage = parser.errorMessage();
613 if (errorLineNumber)
614 *errorLineNumber = parser.errorLineNumber();
615 return 0;
616 }
617
618 return abstractSyntaxTree();
619 }
620
markObject(const QScriptValueImpl & object,int generation)621 void QScriptEnginePrivate::markObject(const QScriptValueImpl &object, int generation)
622 {
623 QScriptObject *instance = object.objectValue();
624 QScript::GCBlock *block = QScript::GCBlock::get(instance);
625
626 enum { MAX_GC_DEPTH = 32 };
627
628 if (block->generation + 1 != generation)
629 return;
630
631 if (m_gc_depth >= MAX_GC_DEPTH) {
632 // do the marking later
633 m_markStack.append(object);
634 return;
635 }
636
637 ++block->generation;
638 ++m_gc_depth;
639
640 if (QScriptClassData *data = object.classInfo()->data())
641 data->mark(object, generation);
642
643 if (instance->m_prototype.isObject())
644 markObject(instance->m_prototype, generation);
645
646 if (instance->m_scope.isObject())
647 markObject(instance->m_scope, generation);
648
649 const QScriptValueImpl &internalValue = instance->m_internalValue;
650
651 if (internalValue.isValid()) {
652 if (internalValue.isObject())
653 markObject(internalValue, generation);
654
655 else if (internalValue.isString())
656 markString(internalValue.m_string_value, generation);
657 }
658
659 int garbage = 0;
660
661 for (int i = 0; i < instance->memberCount(); ++i) {
662 QScript::Member m;
663 instance->member(i, &m);
664
665 if (! m.isValid()) {
666 ++garbage;
667 continue;
668 }
669
670 Q_ASSERT(m.isObjectProperty());
671
672 QScriptValueImpl child;
673 instance->get(m, &child);
674
675 if (m.nameId())
676 markString(m.nameId(), generation);
677
678 if (! child.isValid())
679 continue;
680
681 else if (child.isObject())
682 markObject(child, generation);
683
684 else if (child.isString())
685 markString(child.m_string_value, generation);
686 }
687
688 --m_gc_depth;
689
690 if (garbage < 128) // ###
691 return;
692
693 int j = 0;
694 for (int i = 0; i < instance->memberCount(); ++i) {
695 QScript::Member m;
696 instance->member(i, &m);
697
698 if (! m.isValid())
699 continue;
700
701 if (i != j) {
702 instance->m_members[j].object(m.nameId(), j, m.flags());
703 instance->m_values[j] = instance->m_values[i];
704 }
705 ++j;
706 }
707 //qDebug() << "==> old:" << instance->m_members.size() << "new:" << j;
708 instance->m_members.resize(j);
709 instance->m_values.resize(j);
710 }
711
markFrame(QScriptContextPrivate * context,int generation)712 void QScriptEnginePrivate::markFrame(QScriptContextPrivate *context, int generation)
713 {
714 QScriptValueImpl activation = context->activationObject();
715 QScriptValueImpl thisObject = context->thisObject();
716 QScriptValueImpl scopeChain = context->m_scopeChain;
717 QScriptValueImpl callee = context->m_callee;
718 QScriptValueImpl arguments = context->m_arguments;
719
720 if (activation.isObject())
721 markObject(activation, generation);
722
723 if (scopeChain.isObject())
724 markObject(scopeChain, generation);
725
726 if (thisObject.isObject())
727 markObject(thisObject, generation);
728
729 if (callee.isObject())
730 markObject(callee, generation);
731
732 if (arguments.isObject())
733 markObject(arguments, generation);
734
735 if (context->returnValue().isValid()) {
736 if (context->returnValue().isObject())
737 markObject(context->returnValue(), generation);
738
739 else if (context->returnValue().isString())
740 markString(context->returnValue().m_string_value, generation);
741 }
742
743 if (context->baseStackPointer() != context->currentStackPointer()) {
744 // mark the temp stack
745
746 for (const QScriptValueImpl *it = context->baseStackPointer(); it != (context->currentStackPointer() + 1); ++it) {
747 if (! it) {
748 qWarning() << "no temp stack!!!";
749 break;
750 }
751
752 else if (! it->isValid()) // ### assert?
753 continue;
754
755 else if (it->isObject())
756 markObject(*it, generation);
757
758 else if (it->isString())
759 markString(it->m_string_value, generation);
760 }
761 }
762 }
763
isCollecting() const764 bool QScriptEnginePrivate::isCollecting() const
765 {
766 return (m_gc_depth != -1) || objectAllocator.sweeping();
767 }
768
maybeGC_helper(bool do_string_gc)769 void QScriptEnginePrivate::maybeGC_helper(bool do_string_gc)
770 {
771 // qDebug() << "==>" << objectAllocator.newAllocatedBlocks() << "free:" << objectAllocator.freeBlocks();
772 Q_ASSERT(m_gc_depth == -1);
773 ++m_gc_depth;
774
775 int generation = m_objectGeneration + 1;
776
777 markObject(m_globalObject, generation);
778
779 objectConstructor->mark(this, generation);
780 numberConstructor->mark(this, generation);
781 booleanConstructor->mark(this, generation);
782 stringConstructor->mark(this, generation);
783 dateConstructor->mark(this, generation);
784 functionConstructor->mark(this, generation);
785 arrayConstructor->mark(this, generation);
786 regexpConstructor->mark(this, generation);
787 errorConstructor->mark(this, generation);
788 enumerationConstructor->mark(this, generation);
789 variantConstructor->mark(this, generation);
790 #ifndef QT_NO_QOBJECT
791 qobjectConstructor->mark(this, generation);
792 qmetaObjectConstructor->mark(this, generation);
793 #endif
794
795 {
796 QScriptContextPrivate *current = currentContext();
797 while (current != 0) {
798 markFrame (current, generation);
799 current = current->parentContext();
800 }
801 }
802
803 {
804 QHash<QScriptObject*, QScriptValuePrivate*>::const_iterator it;
805 for (it = m_objectHandles.constBegin(); it != m_objectHandles.constEnd(); ++it)
806 markObject((*it)->value, generation);
807 }
808
809 {
810 QHash<QScriptNameIdImpl*, QScriptValuePrivate*>::const_iterator it;
811 for (it = m_stringHandles.constBegin(); it != m_stringHandles.constEnd(); ++it)
812 markString((*it)->value.stringValue(), generation);
813 }
814
815 {
816 QHash<int, QScriptCustomTypeInfo>::const_iterator it;
817 for (it = m_customTypes.constBegin(); it != m_customTypes.constEnd(); ++it)
818 (*it).prototype.mark(generation);
819 }
820
821 #ifndef QT_NO_QOBJECT
822 # ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
823 {
824 QHash<const QMetaObject*, QScriptMetaObject*>::const_iterator it;
825 for (it = m_cachedMetaObjects.constBegin(); it != m_cachedMetaObjects.constEnd(); ++it) {
826 {
827 QList<QScriptNameIdImpl*> memberNames = (*it)->registeredMemberNames();
828 QList<QScriptNameIdImpl*>::const_iterator it2;
829 for (it2 = memberNames.constBegin(); it2 != memberNames.constEnd(); ++it2)
830 markString(*it2, generation);
831 }
832 {
833 QList<QScriptValueImpl> propertyAccessors = (*it)->registeredPropertyAccessors();
834 QList<QScriptValueImpl>::const_iterator it2;
835 for (it2 = propertyAccessors.constBegin(); it2 != propertyAccessors.constEnd(); ++it2)
836 markObject(*it2, generation);
837 }
838 }
839 }
840 # endif
841 processMarkStack(generation); // make sure everything is marked before marking qobject data
842 {
843 QHash<QObject*, QScriptQObjectData*>::const_iterator it;
844 for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) {
845 QScriptQObjectData *qdata = it.value();
846 qdata->mark(generation);
847 }
848 }
849 #endif
850 processMarkStack(generation);
851
852 Q_ASSERT(m_gc_depth == 0);
853 --m_gc_depth;
854
855 objectAllocator.sweep(generation);
856
857 m_objectGeneration = generation;
858
859 //qDebug() << "free blocks:" << objectAllocator.freeBlocks();
860
861 #ifndef QT_NO_QOBJECT
862 deletePendingQObjects();
863 #endif
864
865 if (! do_string_gc)
866 return;
867
868 {
869 QHash<QScriptNameIdImpl*, QScriptStringPrivate*>::const_iterator it;
870 for (it = m_internedStrings.constBegin(); it != m_internedStrings.constEnd(); ++it) {
871 it.value()->nameId->used = true;
872 }
873 }
874
875 #if 0
876 qDebug() << "do_string_gc:" << do_string_gc
877 << ((m_stringRepository.size() - m_oldStringRepositorySize) > 256)
878 << ((m_tempStringRepository.size() - m_oldTempStringRepositorySize) > 2048);
879 #endif
880
881 QVector<QScriptNameIdImpl*> compressed;
882 compressed.reserve(m_stringRepository.size());
883
884 for (int i = 0; i < m_stringRepository.size(); ++i) {
885 QScriptNameIdImpl *entry = m_stringRepository.at(i);
886
887 if (entry->used || entry->persistent) {
888 compressed.append(entry);
889 entry->used = false;
890 }
891
892 else {
893 //qDebug() << "deleted unique:" << entry->s;
894 delete entry;
895 }
896 }
897
898 // qDebug() << "before:" << m_stringRepository.size() << "after:" << compressed.size() << globalObject.objectValue()->m_members.size();
899 m_stringRepository = compressed;
900 rehashStringRepository(/*resize=*/ false);
901 m_oldStringRepositorySize = m_stringRepository.size();
902 m_newAllocatedStringRepositoryChars = 0;
903
904 compressed.clear();
905 for (int i = 0; i < m_tempStringRepository.size(); ++i) {
906 QScriptNameIdImpl *entry = m_tempStringRepository.at(i);
907
908 if (entry->used || entry->persistent) {
909 compressed.append(entry);
910 entry->used = false;
911 }
912
913 else {
914 //qDebug() << "deleted:" << entry->s;
915 delete entry;
916 }
917 }
918
919 //qDebug() << "before:" << m_tempStringRepository.size() << "after:" << compressed.size();
920
921 m_tempStringRepository = compressed;
922 m_oldTempStringRepositorySize = m_tempStringRepository.size();
923 m_newAllocatedTempStringRepositoryChars = 0;
924 }
925
processMarkStack(int generation)926 void QScriptEnginePrivate::processMarkStack(int generation)
927 {
928 // mark the objects we couldn't process due to recursion depth
929 while (!m_markStack.isEmpty())
930 markObject(m_markStack.takeLast(), generation);
931 }
932
evaluate(QScriptContextPrivate * context,const QString & contents,int lineNumber,const QString & fileName)933 void QScriptEnginePrivate::evaluate(QScriptContextPrivate *context, const QString &contents, int lineNumber, const QString &fileName)
934 {
935 // ### try to remove cast
936 QScript::EvalFunction *evalFunction = static_cast<QScript::EvalFunction*>(m_evalFunction);
937 evalFunction->evaluate(context, contents, lineNumber, fileName, /*calledFromScript=*/ false);
938 }
939
convertToNativeDouble_helper(const QScriptValueImpl & value)940 qsreal QScriptEnginePrivate::convertToNativeDouble_helper(const QScriptValueImpl &value)
941 {
942 switch (value.type()) {
943 case QScript::InvalidType:
944 Q_ASSERT(value.isValid());
945 break;
946
947 case QScript::UndefinedType:
948 case QScript::PointerType:
949 break;
950
951 case QScript::NullType:
952 return 0;
953
954 case QScript::BooleanType:
955 return value.m_bool_value;
956
957 case QScript::IntegerType:
958 case QScript::ReferenceType:
959 return value.m_int_value;
960
961 case QScript::NumberType:
962 return value.m_number_value;
963
964 case QScript::StringType:
965 return QScript::numberFromString(toString(value.m_string_value));
966
967 case QScript::ObjectType: {
968 QScriptValueImpl p = value.engine()->toPrimitive(value, QScriptValueImpl::NumberTypeHint);
969 if (! p.isValid() || p.isObject())
970 break;
971
972 return convertToNativeDouble(p);
973 }
974
975 case QScript::LazyStringType:
976 return QScript::numberFromString(*value.m_lazy_string_value);
977
978 } // switch
979
980 return qSNaN();
981 }
982
convertToNativeBoolean_helper(const QScriptValueImpl & value)983 bool QScriptEnginePrivate::convertToNativeBoolean_helper(const QScriptValueImpl &value)
984 {
985 switch (value.type()) {
986 case QScript::InvalidType:
987 Q_ASSERT(value.isValid());
988 return false;
989
990 case QScript::UndefinedType:
991 case QScript::PointerType:
992 case QScript::NullType:
993 case QScript::ReferenceType:
994 return false;
995
996 case QScript::BooleanType:
997 return value.m_bool_value;
998
999 case QScript::IntegerType:
1000 return value.m_int_value != 0;
1001
1002 case QScript::NumberType:
1003 return value.m_number_value != 0 && !qIsNaN(value.m_number_value);
1004
1005 case QScript::StringType:
1006 return toString(value.m_string_value).length() != 0;
1007
1008 case QScript::ObjectType:
1009 return true;
1010
1011 case QScript::LazyStringType:
1012 return value.m_lazy_string_value->length() != 0;
1013
1014 } // switch
1015
1016 return false;
1017 }
1018
convertToNativeString_helper(const QScriptValueImpl & value)1019 QString QScriptEnginePrivate::convertToNativeString_helper(const QScriptValueImpl &value)
1020 {
1021 static QStringList predefined;
1022 if (predefined.isEmpty()) {
1023 predefined.append(QString::fromLatin1("undefined"));
1024 predefined.append(QString::fromLatin1("null"));
1025 predefined.append(QString::fromLatin1("true"));
1026 predefined.append(QString::fromLatin1("false"));
1027 predefined.append(QString::fromLatin1("pointer"));
1028 }
1029
1030 switch (value.type()) {
1031 case QScript::InvalidType:
1032 Q_ASSERT(value.isValid());
1033 return QString();
1034
1035 case QScript::UndefinedType:
1036 return predefined.at(0);
1037
1038 case QScript::NullType:
1039 return predefined.at(1);
1040
1041 case QScript::BooleanType:
1042 return value.m_bool_value ? predefined.at(2) : predefined.at(3);
1043
1044 case QScript::IntegerType:
1045 return QString::number(value.m_int_value);
1046
1047 case QScript::NumberType:
1048 return QScript::numberToString(value.m_number_value);
1049
1050 case QScript::PointerType:
1051 return predefined.at(4);
1052
1053 case QScript::StringType:
1054 return toString(value.m_string_value);
1055
1056 case QScript::ReferenceType:
1057 return QString();
1058
1059 case QScript::ObjectType: {
1060 QScriptValueImpl p = value.engine()->toPrimitive(value, QScriptValueImpl::StringTypeHint);
1061
1062 if (!p.isValid() || strictlyEquals(p, value))
1063 return p.classInfo()->name();
1064
1065 return convertToNativeString(p);
1066 }
1067
1068 case QScript::LazyStringType:
1069 return *value.m_lazy_string_value;
1070
1071 } // switch
1072
1073 return QString();
1074 }
1075
toObject_helper(const QScriptValueImpl & value)1076 QScriptValueImpl QScriptEnginePrivate::toObject_helper(const QScriptValueImpl &value)
1077 {
1078 QScriptValueImpl result;
1079 switch (value.type()) {
1080 case QScript::BooleanType:
1081 booleanConstructor->newBoolean(&result, value.m_bool_value);
1082 break;
1083
1084 case QScript::NumberType:
1085 numberConstructor->newNumber(&result, value.m_number_value);
1086 break;
1087
1088 case QScript::StringType:
1089 stringConstructor->newString(&result, value.m_string_value->s);
1090 break;
1091
1092 case QScript::LazyStringType:
1093 stringConstructor->newString(&result, *value.m_lazy_string_value);
1094 break;
1095
1096 case QScript::InvalidType:
1097 case QScript::UndefinedType:
1098 case QScript::NullType:
1099 case QScript::IntegerType:
1100 case QScript::ReferenceType:
1101 case QScript::PointerType:
1102 case QScript::ObjectType:
1103 break;
1104 } // switch
1105
1106 return result;
1107 }
1108
1109 // [[defaultValue]]
toPrimitive_helper(const QScriptValueImpl & object,QScriptValueImpl::TypeHint hint)1110 QScriptValueImpl QScriptEnginePrivate::toPrimitive_helper(const QScriptValueImpl &object,
1111 QScriptValueImpl::TypeHint hint)
1112 {
1113 QScriptNameIdImpl *functionIds[2];
1114
1115 if ((hint == QScriptValueImpl::NumberTypeHint)
1116 || (hint == QScriptValueImpl::NoTypeHint
1117 && object.classInfo() != dateConstructor->classInfo())) {
1118 functionIds[0] = idTable()->id_valueOf;
1119 functionIds[1] = idTable()->id_toString;
1120 } else {
1121 functionIds[0] = idTable()->id_toString;
1122 functionIds[1] = idTable()->id_valueOf;
1123 }
1124
1125 for (int i = 0; i < 2; ++i) {
1126 QScriptValueImpl base;
1127 QScript::Member member;
1128
1129 if (! object.resolve(functionIds[i], &member, &base, QScriptValue::ResolvePrototype, QScript::Read))
1130 return object;
1131
1132 QScriptValueImpl f_valueOf;
1133 base.get(member, &f_valueOf);
1134
1135 if (QScriptFunction *foo = convertToNativeFunction(f_valueOf)) {
1136 QScriptContextPrivate *me = pushContext();
1137 QScriptValueImpl activation;
1138 newActivation(&activation);
1139 if (f_valueOf.scope().isValid())
1140 activation.setScope(f_valueOf.scope());
1141 else
1142 activation.setScope(m_globalObject);
1143 me->setActivationObject(activation);
1144 me->setThisObject(object);
1145 me->m_callee = f_valueOf;
1146 foo->execute(me);
1147 QScriptValueImpl result = me->returnValue();
1148 bool exception = (me->state() == QScriptContext::ExceptionState);
1149 popContext();
1150 if (exception || (result.isValid() && !result.isObject()))
1151 return result;
1152 }
1153 }
1154
1155 return object;
1156 }
1157
rehashStringRepository(bool resize)1158 void QScriptEnginePrivate::rehashStringRepository(bool resize)
1159 {
1160 if (resize) {
1161 delete[] m_string_hash_base;
1162 m_string_hash_size <<= 1; // ### use primes
1163
1164 m_string_hash_base = new QScriptNameIdImpl* [m_string_hash_size];
1165 }
1166
1167 memset(m_string_hash_base, 0, sizeof(QScriptNameIdImpl*) * m_string_hash_size);
1168
1169 for (int index = 0; index < m_stringRepository.size(); ++index) {
1170 QScriptNameIdImpl *entry = m_stringRepository.at(index);
1171 uint h = _q_scriptHash(entry->s) % m_string_hash_size;
1172 entry->h = h;
1173 entry->next = m_string_hash_base[h];
1174 m_string_hash_base[h] = entry;
1175 }
1176 }
1177
insertStringEntry(const QString & s)1178 QScriptNameIdImpl *QScriptEnginePrivate::insertStringEntry(const QString &s)
1179 {
1180 QScriptNameIdImpl *entry = new QScriptNameIdImpl(s);
1181 entry->unique = true;
1182 m_stringRepository.append(entry);
1183 m_newAllocatedStringRepositoryChars += s.length();
1184
1185 uint h = _q_scriptHash(s) % m_string_hash_size;
1186 entry->h = h;
1187 entry->next = m_string_hash_base[h];
1188 m_string_hash_base[h] = entry;
1189
1190 if (m_stringRepository.count() == m_string_hash_size)
1191 rehashStringRepository();
1192
1193 return entry;
1194 }
1195
call(const QScriptValueImpl & callee,const QScriptValueImpl & thisObject,const QScriptValueImplList & args,bool asConstructor)1196 QScriptValueImpl QScriptEnginePrivate::call(const QScriptValueImpl &callee,
1197 const QScriptValueImpl &thisObject,
1198 const QScriptValueImplList &args,
1199 bool asConstructor)
1200 {
1201 QScriptFunction *function = callee.toFunction();
1202 Q_ASSERT(function);
1203
1204 if (++m_callDepth == m_maxCallDepth) {
1205 QScriptContextPrivate *ctx_p = currentContext();
1206 return ctx_p->throwError(QLatin1String("call stack overflow"));
1207 }
1208
1209 QScriptContextPrivate *nested = pushContext();
1210 // set up the temp stack
1211 if (! nested->tempStack)
1212 nested->stackPtr = nested->tempStack = tempStackBegin;
1213
1214 newActivation(&nested->m_activation);
1215 if (callee.m_object_value->m_scope.isValid())
1216 nested->m_activation.m_object_value->m_scope = callee.m_object_value->m_scope;
1217 else
1218 nested->m_activation.m_object_value->m_scope = m_globalObject;
1219
1220 QScriptObject *activation_data = nested->m_activation.m_object_value;
1221
1222 int formalCount = function->formals.count();
1223 int argc = args.count();
1224 int mx = qMax(formalCount, argc);
1225 activation_data->m_members.resize(mx);
1226 activation_data->m_values.resize(mx);
1227 for (int i = 0; i < mx; ++i) {
1228 QScriptNameIdImpl *nameId = 0;
1229 if (i < formalCount)
1230 nameId = function->formals.at(i);
1231
1232 activation_data->m_members[i].object(nameId, i, QScriptValue::SkipInEnumeration);
1233 QScriptValueImpl arg = (i < argc) ? args.at(i) : m_undefinedValue;
1234 if (arg.isValid() && arg.engine() && (arg.engine() != this)) {
1235 qWarning("QScriptValue::call() failed: "
1236 "cannot call function with argument created in "
1237 "a different engine");
1238 popContext();
1239 return QScriptValueImpl();
1240 }
1241 activation_data->m_values[i] = arg.isValid() ? arg : m_undefinedValue;
1242 }
1243
1244 nested->argc = argc;
1245 QVector<QScriptValueImpl> argsv = args.toVector();
1246 nested->args = const_cast<QScriptValueImpl*> (argsv.constData());
1247
1248 if (thisObject.isObject())
1249 nested->m_thisObject = thisObject;
1250 else
1251 nested->m_thisObject = m_globalObject;
1252 nested->m_callee = callee;
1253 nested->m_calledAsConstructor = asConstructor;
1254
1255 nested->m_result = m_undefinedValue;
1256 function->execute(nested);
1257 --m_callDepth;
1258 QScriptValueImpl result = nested->m_result;
1259 nested->args = 0;
1260 popContext();
1261
1262 return result;
1263 }
1264
call(const QScriptValueImpl & callee,const QScriptValueImpl & thisObject,const QScriptValueImpl & args,bool asConstructor)1265 QScriptValueImpl QScriptEnginePrivate::call(const QScriptValueImpl &callee,
1266 const QScriptValueImpl &thisObject,
1267 const QScriptValueImpl &args,
1268 bool asConstructor)
1269 {
1270 QScriptValueImplList argsList;
1271 if (QScript::Ecma::Array::Instance *arr = arrayConstructor->get(args)) {
1272 QScript::Array actuals = arr->value;
1273 for (quint32 i = 0; i < actuals.count(); ++i) {
1274 QScriptValueImpl a = actuals.at(i);
1275 if (! a.isValid())
1276 argsList << undefinedValue();
1277 else
1278 argsList << a;
1279 }
1280 } else if (args.classInfo() == m_class_arguments) {
1281 QScript::ArgumentsObjectData *arguments;
1282 arguments = static_cast<QScript::ArgumentsObjectData*> (args.objectData());
1283 QScriptObject *activation = arguments->activation.objectValue();
1284 for (uint i = 0; i < arguments->length; ++i)
1285 argsList << activation->m_values[i];
1286 } else if (!(args.isUndefined() || args.isNull())) {
1287 return currentContext()->throwError(
1288 QScriptContext::TypeError,
1289 QLatin1String("QScriptValue::call(): arguments must be an array"));
1290 }
1291 return call(callee, thisObject, argsList, asConstructor);
1292 }
1293
arrayFromStringList(const QStringList & lst)1294 QScriptValueImpl QScriptEnginePrivate::arrayFromStringList(const QStringList &lst)
1295 {
1296 QScriptValueImpl arr = newArray(lst.size());
1297 for (int i = 0; i < lst.size(); ++i)
1298 arr.setProperty(i, QScriptValueImpl(this, lst.at(i)));
1299 return arr;
1300 }
1301
stringListFromArray(const QScriptValueImpl & arr)1302 QStringList QScriptEnginePrivate::stringListFromArray(const QScriptValueImpl &arr)
1303 {
1304 QStringList lst;
1305 uint len = arr.property(QLatin1String("length")).toUInt32();
1306 for (uint i = 0; i < len; ++i)
1307 lst.append(arr.property(i).toString());
1308 return lst;
1309 }
1310
arrayFromVariantList(const QVariantList & lst)1311 QScriptValueImpl QScriptEnginePrivate::arrayFromVariantList(const QVariantList &lst)
1312 {
1313 QScriptValueImpl arr = newArray(lst.size());
1314 for (int i = 0; i < lst.size(); ++i)
1315 arr.setProperty(i, valueFromVariant(lst.at(i)));
1316 return arr;
1317 }
1318
variantListFromArray(const QScriptValueImpl & arr)1319 QVariantList QScriptEnginePrivate::variantListFromArray(const QScriptValueImpl &arr)
1320 {
1321 QVariantList lst;
1322 uint len = arr.property(QLatin1String("length")).toUInt32();
1323 for (uint i = 0; i < len; ++i)
1324 lst.append(arr.property(i).toVariant());
1325 return lst;
1326 }
1327
objectFromVariantMap(const QVariantMap & vmap)1328 QScriptValueImpl QScriptEnginePrivate::objectFromVariantMap(const QVariantMap &vmap)
1329 {
1330 QScriptValueImpl obj = newObject();
1331 QVariantMap::const_iterator it;
1332 for (it = vmap.constBegin(); it != vmap.constEnd(); ++it)
1333 obj.setProperty(it.key(), valueFromVariant(it.value()));
1334 return obj;
1335 }
1336
variantMapFromObject(const QScriptValueImpl & obj)1337 QVariantMap QScriptEnginePrivate::variantMapFromObject(const QScriptValueImpl &obj)
1338 {
1339 QVariantMap vmap;
1340 QScriptValueIteratorImpl it(obj);
1341 while (it.hasNext()) {
1342 it.next();
1343 vmap.insert(it.name(), it.value().toVariant());
1344 }
1345 return vmap;
1346 }
1347
create(int type,const void * ptr)1348 QScriptValueImpl QScriptEnginePrivate::create(int type, const void *ptr)
1349 {
1350 Q_Q(QScriptEngine);
1351 Q_ASSERT(ptr);
1352 QScriptValueImpl result;
1353 QScriptCustomTypeInfo info = m_customTypes.value(type);
1354 if (info.marshal) {
1355 result = toImpl(info.marshal(q, ptr));
1356 } else {
1357 // check if it's one of the types we know
1358 switch (QMetaType::Type(type)) {
1359 case QMetaType::Void:
1360 result = m_undefinedValue;
1361 break;
1362 case QMetaType::Bool:
1363 result = QScriptValueImpl(*reinterpret_cast<const bool*>(ptr));
1364 break;
1365 case QMetaType::Int:
1366 result = QScriptValueImpl(*reinterpret_cast<const int*>(ptr));
1367 break;
1368 case QMetaType::UInt:
1369 result = QScriptValueImpl(*reinterpret_cast<const uint*>(ptr));
1370 break;
1371 case QMetaType::LongLong:
1372 result = QScriptValueImpl(qsreal(*reinterpret_cast<const qlonglong*>(ptr)));
1373 break;
1374 case QMetaType::ULongLong:
1375 #if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804
1376 #pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.")
1377 result = QScriptValueImpl(qsreal((qlonglong)*reinterpret_cast<const qulonglong*>(ptr)));
1378 #elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET)
1379 result = QScriptValueImpl(qsreal((qlonglong)*reinterpret_cast<const qulonglong*>(ptr)));
1380 #else
1381 result = QScriptValueImpl(qsreal(*reinterpret_cast<const qulonglong*>(ptr)));
1382 #endif
1383 break;
1384 case QMetaType::Double:
1385 result = QScriptValueImpl(*reinterpret_cast<const double*>(ptr));
1386 break;
1387 case QMetaType::QString:
1388 result = QScriptValueImpl(this, *reinterpret_cast<const QString*>(ptr));
1389 break;
1390 case QMetaType::Float:
1391 result = QScriptValueImpl(*reinterpret_cast<const float*>(ptr));
1392 break;
1393 case QMetaType::Short:
1394 result = QScriptValueImpl(*reinterpret_cast<const short*>(ptr));
1395 break;
1396 case QMetaType::UShort:
1397 result = QScriptValueImpl(*reinterpret_cast<const unsigned short*>(ptr));
1398 break;
1399 case QMetaType::Char:
1400 result = QScriptValueImpl(*reinterpret_cast<const char*>(ptr));
1401 break;
1402 case QMetaType::UChar:
1403 result = QScriptValueImpl(*reinterpret_cast<const unsigned char*>(ptr));
1404 break;
1405 case QMetaType::QChar:
1406 result = QScriptValueImpl((*reinterpret_cast<const QChar*>(ptr)).unicode());
1407 break;
1408 case QMetaType::QStringList:
1409 result = arrayFromStringList(*reinterpret_cast<const QStringList *>(ptr));
1410 break;
1411 case QMetaType::QVariantList:
1412 result = arrayFromVariantList(*reinterpret_cast<const QVariantList *>(ptr));
1413 break;
1414 case QMetaType::QVariantMap:
1415 result = objectFromVariantMap(*reinterpret_cast<const QVariantMap *>(ptr));
1416 break;
1417 case QMetaType::QDateTime: {
1418 QDateTime dateTime = *reinterpret_cast<const QDateTime *>(ptr);
1419 dateConstructor->newDate(&result, dateTime);
1420 } break;
1421 case QMetaType::QDate: {
1422 QDate date = *reinterpret_cast<const QDate *>(ptr);
1423 dateConstructor->newDate(&result, date);
1424 } break;
1425 #ifndef QT_NO_REGEXP
1426 case QMetaType::QRegExp: {
1427 QRegExp rx = *reinterpret_cast<const QRegExp *>(ptr);
1428 regexpConstructor->newRegExp(&result, rx);
1429 } break;
1430 #endif
1431 #ifndef QT_NO_QOBJECT
1432 case QMetaType::QObjectStar:
1433 case QMetaType::QWidgetStar:
1434 newQObject(&result, *reinterpret_cast<QObject* const *>(ptr));
1435 break;
1436 #endif
1437 default:
1438 if (type == qMetaTypeId<QScriptValue>()) {
1439 result = toImpl(*reinterpret_cast<const QScriptValue*>(ptr));
1440 if (!result.isValid())
1441 result = m_undefinedValue;
1442 }
1443
1444 #ifndef QT_NO_QOBJECT
1445 // lazy registration of some common list types
1446 else if (type == qMetaTypeId<QObjectList>()) {
1447 qScriptRegisterSequenceMetaType<QObjectList>(q);
1448 return create(type, ptr);
1449 }
1450 #endif
1451 else if (type == qMetaTypeId<QList<int> >()) {
1452 qScriptRegisterSequenceMetaType<QList<int> >(q);
1453 return create(type, ptr);
1454 }
1455
1456 else {
1457 QByteArray typeName = QMetaType::typeName(type);
1458 if (typeName == "QVariant")
1459 result = valueFromVariant(*reinterpret_cast<const QVariant*>(ptr));
1460 else if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(ptr))
1461 result = nullValue();
1462 else
1463 newVariant(&result, QVariant(type, ptr));
1464 }
1465 }
1466 }
1467 if (result.isObject() && info.prototype.isValid()
1468 && strictlyEquals(result.prototype(), objectConstructor->publicPrototype)) {
1469 result.setPrototype(info.prototype);
1470 }
1471 return result;
1472 }
1473
convert(const QScriptValueImpl & value,int type,void * ptr,QScriptEnginePrivate * eng)1474 bool QScriptEnginePrivate::convert(const QScriptValueImpl &value,
1475 int type, void *ptr,
1476 QScriptEnginePrivate *eng)
1477 {
1478 if (!eng)
1479 eng = value.engine();
1480 if (eng) {
1481 QScriptCustomTypeInfo info = eng->m_customTypes.value(type);
1482 if (info.demarshal) {
1483 info.demarshal(eng->toPublic(value), ptr);
1484 return true;
1485 }
1486 }
1487
1488 // check if it's one of the types we know
1489 switch (QMetaType::Type(type)) {
1490 case QMetaType::Bool:
1491 *reinterpret_cast<bool*>(ptr) = value.toBoolean();
1492 return true;
1493 case QMetaType::Int:
1494 *reinterpret_cast<int*>(ptr) = value.toInt32();
1495 return true;
1496 case QMetaType::UInt:
1497 *reinterpret_cast<uint*>(ptr) = value.toUInt32();
1498 return true;
1499 case QMetaType::LongLong:
1500 *reinterpret_cast<qlonglong*>(ptr) = qlonglong(value.toInteger());
1501 return true;
1502 case QMetaType::ULongLong:
1503 *reinterpret_cast<qulonglong*>(ptr) = qulonglong(value.toInteger());
1504 return true;
1505 case QMetaType::Double:
1506 *reinterpret_cast<double*>(ptr) = value.toNumber();
1507 return true;
1508 case QMetaType::QString:
1509 if (value.isUndefined() || value.isNull())
1510 *reinterpret_cast<QString*>(ptr) = QString();
1511 else
1512 *reinterpret_cast<QString*>(ptr) = value.toString();
1513 return true;
1514 case QMetaType::Float:
1515 *reinterpret_cast<float*>(ptr) = value.toNumber();
1516 return true;
1517 case QMetaType::Short:
1518 *reinterpret_cast<short*>(ptr) = short(value.toInt32());
1519 return true;
1520 case QMetaType::UShort:
1521 *reinterpret_cast<unsigned short*>(ptr) = value.toUInt16();
1522 return true;
1523 case QMetaType::Char:
1524 *reinterpret_cast<char*>(ptr) = char(value.toInt32());
1525 return true;
1526 case QMetaType::UChar:
1527 *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(value.toInt32());
1528 return true;
1529 case QMetaType::QChar:
1530 if (value.isString()) {
1531 QString str = value.toString();
1532 *reinterpret_cast<QChar*>(ptr) = str.isEmpty() ? QChar() : str.at(0);
1533 } else {
1534 *reinterpret_cast<QChar*>(ptr) = QChar(value.toUInt16());
1535 }
1536 return true;
1537 case QMetaType::QDateTime:
1538 if (value.isDate()) {
1539 *reinterpret_cast<QDateTime *>(ptr) = value.toDateTime();
1540 return true;
1541 } break;
1542 case QMetaType::QDate:
1543 if (value.isDate()) {
1544 *reinterpret_cast<QDate *>(ptr) = value.toDateTime().date();
1545 return true;
1546 } break;
1547 #ifndef QT_NO_REGEXP
1548 case QMetaType::QRegExp:
1549 if (value.isRegExp()) {
1550 *reinterpret_cast<QRegExp *>(ptr) = value.toRegExp();
1551 return true;
1552 } break;
1553 #endif
1554 #ifndef QT_NO_QOBJECT
1555 case QMetaType::QObjectStar:
1556 if (value.isQObject() || value.isNull()) {
1557 *reinterpret_cast<QObject* *>(ptr) = value.toQObject();
1558 return true;
1559 } break;
1560 case QMetaType::QWidgetStar:
1561 if (value.isQObject() || value.isNull()) {
1562 QObject *qo = value.toQObject();
1563 if (!qo || qo->isWidgetType()) {
1564 *reinterpret_cast<QWidget* *>(ptr) = reinterpret_cast<QWidget*>(qo);
1565 return true;
1566 }
1567 } break;
1568 #endif
1569 case QMetaType::QStringList:
1570 if (value.isArray()) {
1571 *reinterpret_cast<QStringList *>(ptr) = stringListFromArray(value);
1572 return true;
1573 } break;
1574 case QMetaType::QVariantList:
1575 if (value.isArray()) {
1576 *reinterpret_cast<QVariantList *>(ptr) = variantListFromArray(value);
1577 return true;
1578 } break;
1579 case QMetaType::QVariantMap:
1580 if (value.isObject()) {
1581 *reinterpret_cast<QVariantMap *>(ptr) = variantMapFromObject(value);
1582 return true;
1583 } break;
1584 default:
1585 ;
1586 }
1587
1588 QByteArray name = QMetaType::typeName(type);
1589 #ifndef QT_NO_QOBJECT
1590 if (convertToNativeQObject(value, name, reinterpret_cast<void* *>(ptr)))
1591 return true;
1592 #endif
1593 if (value.isVariant() && name.endsWith('*')) {
1594 int valueType = QMetaType::type(name.left(name.size()-1));
1595 QVariant &var = value.variantValue();
1596 if (valueType == var.userType()) {
1597 *reinterpret_cast<void* *>(ptr) = var.data();
1598 return true;
1599 } else {
1600 // look in the prototype chain
1601 QScriptValueImpl proto = value.prototype();
1602 while (proto.isObject()) {
1603 bool canCast = false;
1604 if (proto.isVariant()) {
1605 canCast = (type == proto.variantValue().userType())
1606 || (valueType && (valueType == proto.variantValue().userType()));
1607 }
1608 #ifndef QT_NO_QOBJECT
1609 else if (proto.isQObject()) {
1610 QByteArray className = name.left(name.size()-1);
1611 if (QObject *qobject = proto.toQObject())
1612 canCast = qobject->qt_metacast(className) != 0;
1613 }
1614 #endif
1615 if (canCast) {
1616 QByteArray varTypeName = QMetaType::typeName(var.userType());
1617 if (varTypeName.endsWith('*'))
1618 *reinterpret_cast<void* *>(ptr) = *reinterpret_cast<void* *>(var.data());
1619 else
1620 *reinterpret_cast<void* *>(ptr) = var.data();
1621 return true;
1622 }
1623 proto = proto.prototype();
1624 }
1625 }
1626 } else if (value.isNull() && name.endsWith('*')) {
1627 *reinterpret_cast<void* *>(ptr) = 0;
1628 return true;
1629 } else if (type == qMetaTypeId<QScriptValue>()) {
1630 if (!eng)
1631 return false;
1632 *reinterpret_cast<QScriptValue*>(ptr) = eng->toPublic(value);
1633 return true;
1634 } else if (name == "QVariant") {
1635 *reinterpret_cast<QVariant*>(ptr) = value.toVariant();
1636 return true;
1637 }
1638
1639 // lazy registration of some common list types
1640 #ifndef QT_NO_QOBJECT
1641 else if (type == qMetaTypeId<QObjectList>()) {
1642 if (!eng)
1643 return false;
1644 qScriptRegisterSequenceMetaType<QObjectList>(eng->q_func());
1645 return convert(value, type, ptr, eng);
1646 }
1647 #endif
1648 else if (type == qMetaTypeId<QList<int> >()) {
1649 if (!eng)
1650 return false;
1651 qScriptRegisterSequenceMetaType<QList<int> >(eng->q_func());
1652 return convert(value, type, ptr, eng);
1653 }
1654
1655 #if 0
1656 if (!name.isEmpty()) {
1657 qWarning("QScriptEngine::convert: unable to convert value to type `%s'",
1658 name.constData());
1659 }
1660 #endif
1661 return false;
1662 }
1663
demarshalFunction(int type) const1664 QScriptEngine::DemarshalFunction QScriptEnginePrivate::demarshalFunction(int type) const
1665 {
1666 return m_customTypes.value(type).demarshal;
1667 }
1668
registerValue(const QScriptValueImpl & value)1669 QScriptValuePrivate *QScriptEnginePrivate::registerValue(const QScriptValueImpl &value)
1670 {
1671 if (value.isString()) {
1672 QScriptNameIdImpl *id = value.stringValue();
1673 QScriptValuePrivate *p = m_stringHandles.value(id);
1674 if (p)
1675 return p;
1676 p = m_handleRepository.get();
1677 p->engine = q_func();
1678 p->value = value;
1679 m_stringHandles.insert(id, p);
1680 return p;
1681 } else if (value.isObject()) {
1682 QScriptObject *instance = value.objectValue();
1683 QScriptValuePrivate *p = m_objectHandles.value(instance);
1684 if (p)
1685 return p;
1686 p = m_handleRepository.get();
1687 p->engine = q_func();
1688 p->value = value;
1689 m_objectHandles.insert(instance, p);
1690 return p;
1691 }
1692 QScriptValuePrivate *p = m_handleRepository.get();
1693 p->engine = q_func();
1694 p->value = value;
1695 m_otherHandles.append(p);
1696 return p;
1697 }
1698
QScriptEnginePrivate()1699 QScriptEnginePrivate::QScriptEnginePrivate()
1700 {
1701 m_undefinedValue = QScriptValueImpl(QScriptValue::UndefinedValue);
1702 m_nullValue = QScriptValueImpl(QScriptValue::NullValue);
1703
1704 m_evaluating = false;
1705 m_abort = false;
1706 m_callDepth = 0;
1707 #if defined(Q_OS_WIN)
1708 m_maxCallDepth = 88;
1709 #elif defined(Q_OS_MAC)
1710 m_maxCallDepth = 640;
1711 #elif defined(QT_ARCH_ARM) || defined(QT_ARCH_ARMV6)
1712 m_maxCallDepth = 360;
1713 #else
1714 m_maxCallDepth = 512;
1715 #endif
1716 m_oldStringRepositorySize = 0;
1717 m_oldTempStringRepositorySize = 0;
1718 m_newAllocatedStringRepositoryChars = 0;
1719 m_newAllocatedTempStringRepositoryChars = 0;
1720 m_context = 0;
1721 m_abstractSyntaxTree = 0;
1722 m_lexer = 0;
1723 m_scriptCounter = 0;
1724 m_agent = 0;
1725 m_objectGeneration = 0;
1726 m_class_prev_id = QScriptClassInfo::CustomType;
1727 m_next_object_id = 0;
1728 m_gc_depth = -1;
1729
1730 objectConstructor = 0;
1731 numberConstructor = 0;
1732 booleanConstructor = 0;
1733 stringConstructor = 0;
1734 dateConstructor = 0;
1735 functionConstructor = 0;
1736 arrayConstructor = 0;
1737 regexpConstructor = 0;
1738 errorConstructor = 0;
1739 enumerationConstructor = 0;
1740 variantConstructor = 0;
1741 qobjectConstructor = 0;
1742 qmetaObjectConstructor = 0;
1743
1744 m_processEventsInterval = -1;
1745 m_nextProcessEvents = 0;
1746 m_processEventIncr = 0;
1747
1748 m_stringRepository.reserve(DefaultHashSize);
1749 m_string_hash_size = DefaultHashSize;
1750 m_string_hash_base = new QScriptNameIdImpl* [m_string_hash_size];
1751 memset(m_string_hash_base, 0, sizeof(QScriptNameIdImpl*) * m_string_hash_size);
1752
1753 tempStackBegin = 0;
1754 }
1755
init()1756 void QScriptEnginePrivate::init()
1757 {
1758 qMetaTypeId<QScriptValue>();
1759 qMetaTypeId<QList<int> >();
1760 #ifndef QT_NO_QOBJECT
1761 qMetaTypeId<QObjectList>();
1762 #endif
1763
1764 m_class_prev_id = QScriptClassInfo::CustomType;
1765 m_class_object = registerClass(QLatin1String("Object"), QScriptClassInfo::ObjectType);
1766 m_class_function = registerClass(QLatin1String("Function"), QScriptClassInfo::FunctionType);
1767 m_class_activation = registerClass(QLatin1String("activation"), QScriptClassInfo::ActivationType);
1768
1769 m_class_arguments = registerClass(QLatin1String("arguments"), QScript::ObjectType);
1770 m_class_arguments->setData(new QScript::ArgumentsClassData());
1771
1772 m_class_with = registerClass(QLatin1String("__qscript_internal_with"), QScript::ObjectType);
1773
1774 // public name ids
1775 m_id_table.id_constructor = nameId(QLatin1String("constructor"), true);
1776 m_id_table.id_false = nameId(QLatin1String("false"), true);
1777 m_id_table.id_null = nameId(QLatin1String("null"), true);
1778 m_id_table.id_object = nameId(QLatin1String("object"), true);
1779 m_id_table.id_pointer = nameId(QLatin1String("pointer"), true);
1780 m_id_table.id_prototype = nameId(QLatin1String("prototype"), true);
1781 m_id_table.id_arguments = nameId(QLatin1String("arguments"), true);
1782 m_id_table.id_this = nameId(QLatin1String("this"), true);
1783 m_id_table.id_toString = nameId(QLatin1String("toString"), true);
1784 m_id_table.id_true = nameId(QLatin1String("true"), true);
1785 m_id_table.id_undefined = nameId(QLatin1String("undefined"), true);
1786 m_id_table.id_valueOf = nameId(QLatin1String("valueOf"), true);
1787 m_id_table.id_length = nameId(QLatin1String("length"), true);
1788 m_id_table.id_callee = nameId(QLatin1String("callee"), true);
1789 m_id_table.id___proto__ = nameId(QLatin1String("__proto__"), true);
1790 m_id_table.id___qt_sender__ = nameId(QLatin1String("__qt_sender__"), true);
1791
1792 const int TEMP_STACK_SIZE = 10 * 1024;
1793 tempStackBegin = new QScriptValueImpl[TEMP_STACK_SIZE];
1794 tempStackEnd = tempStackBegin + TEMP_STACK_SIZE;
1795 tempStackBegin[0] = m_undefinedValue;
1796
1797 objectAllocator.blockGC(true);
1798
1799 QScript::Ecma::Global::construct(&m_globalObject, this);
1800
1801 // create the prototypes first...
1802 objectConstructor = new QScript::Ecma::Object(this, m_class_object);
1803 functionConstructor = new QScript::Ecma::Function(this, m_class_function);
1804 // ... then we can initialize
1805 functionConstructor->initialize();
1806 objectConstructor->initialize();
1807
1808 numberConstructor = new QScript::Ecma::Number(this);
1809 booleanConstructor = new QScript::Ecma::Boolean(this);
1810 stringConstructor = new QScript::Ecma::String(this);
1811 dateConstructor = new QScript::Ecma::Date(this);
1812 arrayConstructor = new QScript::Ecma::Array(this);
1813 regexpConstructor = new QScript::Ecma::RegExp(this);
1814 errorConstructor = new QScript::Ecma::Error(this);
1815
1816 QScript::Ecma::Global::initialize(&m_globalObject, this);
1817
1818 const QScriptValue::PropertyFlags flags = QScriptValue::SkipInEnumeration;
1819
1820 m_globalObject.setProperty(QLatin1String("Object"),
1821 objectConstructor->ctor, flags);
1822 m_globalObject.setProperty(QLatin1String("Function"),
1823 functionConstructor->ctor, flags);
1824 m_globalObject.setProperty(QLatin1String("Number"),
1825 numberConstructor->ctor, flags);
1826 m_globalObject.setProperty(QLatin1String("Boolean"),
1827 booleanConstructor->ctor, flags);
1828 m_globalObject.setProperty(QLatin1String("String"),
1829 stringConstructor->ctor, flags);
1830 m_globalObject.setProperty(QLatin1String("Date"),
1831 dateConstructor->ctor, flags);
1832 m_globalObject.setProperty(QLatin1String("Array"),
1833 arrayConstructor->ctor, flags);
1834 m_globalObject.setProperty(QLatin1String("RegExp"),
1835 regexpConstructor->ctor, flags);
1836 m_globalObject.setProperty(QLatin1String("Error"),
1837 errorConstructor->ctor, flags);
1838
1839 m_globalObject.setProperty(QLatin1String("EvalError"),
1840 errorConstructor->evalErrorCtor, flags);
1841 m_globalObject.setProperty(QLatin1String("RangeError"),
1842 errorConstructor->rangeErrorCtor, flags);
1843 m_globalObject.setProperty(QLatin1String("ReferenceError"),
1844 errorConstructor->referenceErrorCtor, flags);
1845 m_globalObject.setProperty(QLatin1String("SyntaxError"),
1846 errorConstructor->syntaxErrorCtor, flags);
1847 m_globalObject.setProperty(QLatin1String("TypeError"),
1848 errorConstructor->typeErrorCtor, flags);
1849 m_globalObject.setProperty(QLatin1String("URIError"),
1850 errorConstructor->uriErrorCtor, flags);
1851
1852 QScriptValueImpl tmp; // ### fixme
1853 m_evalFunction = new QScript::EvalFunction(this);
1854 functionConstructor->newFunction(&tmp, m_evalFunction);
1855 m_globalObject.setProperty(QLatin1String("eval"), tmp, flags);
1856
1857 QScriptValueImpl mathObject;
1858 QScript::Ecma::Math::construct(&mathObject, this);
1859 m_globalObject.setProperty(QLatin1String("Math"), mathObject, flags);
1860
1861 enumerationConstructor = new QScript::Ext::Enumeration(this);
1862
1863 variantConstructor = new QScript::Ext::Variant(this);
1864
1865 #ifndef QT_NO_QOBJECT
1866 qobjectConstructor = new QScript::ExtQObject(this);
1867 qmetaObjectConstructor = new QScript::ExtQMetaObject(this);
1868 #endif
1869
1870 objectAllocator.blockGC(false);
1871
1872 QScriptContextPrivate *context_p = pushContext();
1873 context_p->setActivationObject(m_globalObject);
1874 context_p->setThisObject(m_globalObject);
1875 }
1876
1877 #if !defined(QT_NO_QOBJECT) && !defined(QT_NO_LIBRARY)
__setupPackage__(QScriptContextPrivate * ctx,QScriptEnginePrivate * eng,QScriptClassInfo *)1878 static QScriptValueImpl __setupPackage__(QScriptContextPrivate *ctx,
1879 QScriptEnginePrivate *eng,
1880 QScriptClassInfo *)
1881 {
1882 QString path = ctx->argument(0).toString();
1883 QStringList components = path.split(QLatin1Char('.'));
1884 QScriptValueImpl o = eng->globalObject();
1885 for (int i = 0; i < components.count(); ++i) {
1886 QString name = components.at(i);
1887 QScriptValueImpl oo = o.property(name);
1888 if (!oo.isValid()) {
1889 oo = eng->newObject();
1890 o.setProperty(name, oo);
1891 }
1892 o = oo;
1893 }
1894 return o;
1895 }
1896 #endif
1897
importExtension(const QString & extension)1898 QScriptValueImpl QScriptEnginePrivate::importExtension(const QString &extension)
1899 {
1900 #if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
1901 Q_UNUSED(extension);
1902 #else
1903 Q_Q(QScriptEngine);
1904 if (m_importedExtensions.contains(extension))
1905 return undefinedValue(); // already imported
1906
1907 QScriptContextPrivate *context = currentContext();
1908 QCoreApplication *app = QCoreApplication::instance();
1909 if (!app)
1910 return context->throwError(QLatin1String("No application object"));
1911
1912 QObjectList staticPlugins = QPluginLoader::staticInstances();
1913 QStringList libraryPaths = app->libraryPaths();
1914 QString dot = QLatin1String(".");
1915 QStringList pathComponents = extension.split(dot);
1916 QString initDotJs = QLatin1String("__init__.js");
1917
1918 QString ext;
1919 for (int i = 0; i < pathComponents.count(); ++i) {
1920 if (!ext.isEmpty())
1921 ext.append(dot);
1922 ext.append(pathComponents.at(i));
1923 if (m_importedExtensions.contains(ext))
1924 continue; // already imported
1925
1926 if (m_extensionsBeingImported.contains(ext)) {
1927 return context->throwError(QString::fromLatin1("recursive import of %0")
1928 .arg(extension));
1929 }
1930 m_extensionsBeingImported.insert(ext);
1931
1932 QScriptExtensionInterface *iface = 0;
1933 QString initjsContents;
1934 QString initjsFileName;
1935
1936 // look for the extension in static plugins
1937 for (int j = 0; j < staticPlugins.size(); ++j) {
1938 iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(j));
1939 if (!iface)
1940 continue;
1941 if (iface->keys().contains(ext))
1942 break; // use this one
1943 else
1944 iface = 0; // keep looking
1945 }
1946
1947 {
1948 // look for __init__.js resource
1949 QString path = QString::fromLatin1(":/qtscriptextension");
1950 for (int j = 0; j <= i; ++j) {
1951 path.append(QLatin1Char('/'));
1952 path.append(pathComponents.at(j));
1953 }
1954 path.append(QLatin1Char('/'));
1955 path.append(initDotJs);
1956 QFile file(path);
1957 if (file.open(QIODevice::ReadOnly)) {
1958 QTextStream ts(&file);
1959 initjsContents = ts.readAll();
1960 initjsFileName = path;
1961 file.close();
1962 }
1963 }
1964
1965 if (!iface && initjsContents.isEmpty()) {
1966 // look for the extension in library paths
1967 for (int j = 0; j < libraryPaths.count(); ++j) {
1968 QString libPath = libraryPaths.at(j) + QDir::separator() + QLatin1String("script");
1969 QDir dir(libPath);
1970 if (!dir.exists(dot))
1971 continue;
1972
1973 // look for C++ plugin
1974 QFileInfoList files = dir.entryInfoList(QDir::Files);
1975 for (int k = 0; k < files.count(); ++k) {
1976 QFileInfo entry = files.at(k);
1977 QString filePath = entry.canonicalFilePath();
1978 QPluginLoader loader(filePath);
1979 iface = qobject_cast<QScriptExtensionInterface*>(loader.instance());
1980 if (iface) {
1981 if (iface->keys().contains(ext))
1982 break; // use this one
1983 else
1984 iface = 0; // keep looking
1985 }
1986 }
1987
1988 // look for __init__.js in the corresponding dir
1989 QDir dirdir(libPath);
1990 bool dirExists = dirdir.exists();
1991 for (int k = 0; dirExists && (k <= i); ++k)
1992 dirExists = dirdir.cd(pathComponents.at(k));
1993 if (dirExists && dirdir.exists(initDotJs)) {
1994 QFile file(dirdir.canonicalPath()
1995 + QDir::separator() + initDotJs);
1996 if (file.open(QIODevice::ReadOnly)) {
1997 QTextStream ts(&file);
1998 initjsContents = ts.readAll();
1999 initjsFileName = file.fileName();
2000 file.close();
2001 }
2002 }
2003
2004 if (iface || !initjsContents.isEmpty())
2005 break;
2006 }
2007 }
2008
2009 if (!iface && initjsContents.isEmpty()) {
2010 m_extensionsBeingImported.remove(ext);
2011 return context->throwError(
2012 QString::fromLatin1("Unable to import %0: no such extension")
2013 .arg(extension));
2014 }
2015
2016 // initialize the extension in a new context
2017 QScriptContextPrivate *ctx_p = pushContext();
2018 ctx_p->setThisObject(globalObject());
2019 newActivation(&ctx_p->m_activation);
2020 QScriptObject *activation_data = ctx_p->m_activation.m_object_value;
2021 activation_data->m_scope = globalObject();
2022
2023 activation_data->m_members.resize(4);
2024 activation_data->m_values.resize(4);
2025 activation_data->m_members[0].object(
2026 nameId(QLatin1String("__extension__")), 0,
2027 QScriptValue::ReadOnly | QScriptValue::Undeletable);
2028 activation_data->m_values[0] = QScriptValueImpl(this, ext);
2029 activation_data->m_members[1].object(
2030 nameId(QLatin1String("__setupPackage__")), 1, 0);
2031 activation_data->m_values[1] = createFunction(__setupPackage__, 0, 0);
2032 activation_data->m_members[2].object(
2033 nameId(QLatin1String("__all__")), 2, 0);
2034 activation_data->m_values[2] = undefinedValue();
2035 activation_data->m_members[3].object(
2036 nameId(QLatin1String("__postInit__")), 3, 0);
2037 activation_data->m_values[3] = undefinedValue();
2038
2039 // the script is evaluated first
2040 if (!initjsContents.isEmpty()) {
2041 evaluate(ctx_p, initjsContents, /*lineNumber=*/1, initjsFileName);
2042 if (hasUncaughtException()) {
2043 QScriptValueImpl r = ctx_p->returnValue();
2044 popContext();
2045 m_extensionsBeingImported.remove(ext);
2046 return r;
2047 }
2048 }
2049
2050 // next, the C++ plugin is called
2051 if (iface) {
2052 iface->initialize(ext, q);
2053 if (hasUncaughtException()) {
2054 QScriptValueImpl r = ctx_p->returnValue();
2055 popContext();
2056 m_extensionsBeingImported.remove(ext);
2057 return r;
2058 }
2059 }
2060
2061 // if the __postInit__ function has been set, we call it
2062 QScriptValueImpl postInit = ctx_p->m_activation.property(QLatin1String("__postInit__"));
2063 if (postInit.isFunction()) {
2064 postInit.call(globalObject());
2065 if (hasUncaughtException()) {
2066 QScriptValueImpl r = ctx_p->returnValue();
2067 popContext();
2068 m_extensionsBeingImported.remove(ext);
2069 return r;
2070 }
2071 }
2072
2073 popContext();
2074
2075 m_importedExtensions.insert(ext);
2076 m_extensionsBeingImported.remove(ext);
2077 } // for (i)
2078 #endif // QT_NO_QOBJECT
2079 return undefinedValue();
2080 }
2081
availableExtensions() const2082 QStringList QScriptEnginePrivate::availableExtensions() const
2083 {
2084 #if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
2085 return QStringList();
2086 #else
2087 QCoreApplication *app = QCoreApplication::instance();
2088 if (!app)
2089 return QStringList();
2090
2091 QSet<QString> result;
2092
2093 QObjectList staticPlugins = QPluginLoader::staticInstances();
2094 for (int i = 0; i < staticPlugins.size(); ++i) {
2095 QScriptExtensionInterface *iface;
2096 iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(i));
2097 if (iface) {
2098 QStringList keys = iface->keys();
2099 for (int j = 0; j < keys.count(); ++j)
2100 result << keys.at(j);
2101 }
2102 }
2103
2104 QStringList libraryPaths = app->libraryPaths();
2105 for (int i = 0; i < libraryPaths.count(); ++i) {
2106 QString libPath = libraryPaths.at(i) + QDir::separator() + QLatin1String("script");
2107 QDir dir(libPath);
2108 if (!dir.exists())
2109 continue;
2110
2111 // look for C++ plugins
2112 QFileInfoList files = dir.entryInfoList(QDir::Files);
2113 for (int j = 0; j < files.count(); ++j) {
2114 QFileInfo entry = files.at(j);
2115 QString filePath = entry.canonicalFilePath();
2116 QPluginLoader loader(filePath);
2117 QScriptExtensionInterface *iface;
2118 iface = qobject_cast<QScriptExtensionInterface*>(loader.instance());
2119 if (iface) {
2120 QStringList keys = iface->keys();
2121 for (int k = 0; k < keys.count(); ++k)
2122 result << keys.at(k);
2123 }
2124 }
2125
2126 // look for scripts
2127 QString initDotJs = QLatin1String("__init__.js");
2128 QList<QFileInfo> stack;
2129 stack << dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
2130 while (!stack.isEmpty()) {
2131 QFileInfo entry = stack.takeLast();
2132 QDir dd(entry.canonicalFilePath());
2133 if (dd.exists(initDotJs)) {
2134 QString rpath = dir.relativeFilePath(dd.canonicalPath());
2135 QStringList components = rpath.split(QLatin1Char('/'));
2136 result << components.join(QLatin1String("."));
2137 stack << dd.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
2138 }
2139 }
2140 }
2141
2142 QStringList lst = result.toList();
2143 qSort(lst);
2144 return lst;
2145 #endif
2146 }
2147
importedExtensions() const2148 QStringList QScriptEnginePrivate::importedExtensions() const
2149 {
2150 QStringList lst = m_importedExtensions.toList();
2151 qSort(lst);
2152 return lst;
2153 }
2154
gc()2155 void QScriptEnginePrivate::gc()
2156 {
2157 if (!objectAllocator.blocked()) {
2158 // do the GC now
2159 maybeGC_helper(/*do_string_gc=*/true);
2160 } else {
2161 // GC will be performed the next time maybeGC()
2162 // is called and the allocator is not blocked
2163 objectAllocator.requestGC();
2164 }
2165 }
2166
uncaughtExceptionBacktrace() const2167 QStringList QScriptEnginePrivate::uncaughtExceptionBacktrace() const
2168 {
2169 QScriptValueImpl value = uncaughtException();
2170 if (!value.isError())
2171 return m_exceptionBacktrace;
2172 return QScript::Ecma::Error::backtrace(value);
2173 }
2174
clearExceptions()2175 void QScriptEnginePrivate::clearExceptions()
2176 {
2177 m_exceptionBacktrace = QStringList();
2178 QScriptContextPrivate *ctx_p = currentContext();
2179 while (ctx_p) {
2180 ctx_p->m_state = QScriptContext::NormalState;
2181 ctx_p = ctx_p->parentContext();
2182 }
2183 }
2184
2185 #ifndef QT_NO_QOBJECT
emitSignalHandlerException()2186 void QScriptEnginePrivate::emitSignalHandlerException()
2187 {
2188 Q_Q(QScriptEngine);
2189 emit q->signalHandlerException(toPublic(uncaughtException()));
2190 }
2191 #endif
2192
processEvents()2193 void QScriptEnginePrivate::processEvents()
2194 {
2195 #ifndef QT_NO_QOBJECT
2196 Q_ASSERT(m_processEventTracker.isValid());
2197 int elapsed = m_processEventTracker.elapsed();
2198 if (m_nextProcessEvents < elapsed) {
2199 do {
2200 m_nextProcessEvents = m_nextProcessEvents + m_processEventsInterval;
2201 } while (m_nextProcessEvents < elapsed);
2202 QCoreApplication::processEvents();
2203 }
2204 #endif
2205 }
2206
setupProcessEvents()2207 void QScriptEnginePrivate::setupProcessEvents()
2208 {
2209 if (m_processEventsInterval > 0) {
2210 m_nextProcessEvents = m_processEventsInterval;
2211 m_processEventIncr = 0;
2212 m_processEventTracker.restart();
2213 }
2214 }
2215
abortEvaluation(const QScriptValueImpl & result)2216 void QScriptEnginePrivate::abortEvaluation(const QScriptValueImpl &result)
2217 {
2218 m_abort = true;
2219 currentContext()->setReturnValue(result);
2220 }
2221
2222 #ifndef QT_NO_QOBJECT
2223
newQObject(QScriptValueImpl * out,QObject * object,QScriptEngine::ValueOwnership ownership,const QScriptEngine::QObjectWrapOptions & options,bool setDefaultPrototype)2224 void QScriptEnginePrivate::newQObject(QScriptValueImpl *out, QObject *object,
2225 QScriptEngine::ValueOwnership ownership,
2226 const QScriptEngine::QObjectWrapOptions &options,
2227 bool setDefaultPrototype)
2228 {
2229 if (!object) {
2230 *out = m_nullValue;
2231 return;
2232 }
2233 Q_ASSERT(qobjectConstructor != 0);
2234 QScriptQObjectData *data = qobjectData(object);
2235 bool preferExisting = (options & QScriptEngine::PreferExistingWrapperObject) != 0;
2236 QScriptEngine::QObjectWrapOptions opt = options & ~QScriptEngine::PreferExistingWrapperObject;
2237 QScriptValueImpl existingWrapper;
2238 bool hasExisting = data->findWrapper(ownership, opt, &existingWrapper);
2239 if (preferExisting) {
2240 if (hasExisting) {
2241 *out = existingWrapper;
2242 } else {
2243 qobjectConstructor->newQObject(out, object, ownership, opt);
2244 data->registerWrapper(*out, ownership, opt);
2245 }
2246 } else {
2247 qobjectConstructor->newQObject(out, object, ownership, opt);
2248 if (!hasExisting)
2249 data->registerWrapper(*out, ownership, opt);
2250 }
2251
2252 if (setDefaultPrototype) {
2253 const QMetaObject *meta = object->metaObject();
2254 while (meta) {
2255 QByteArray typeString = meta->className();
2256 typeString.append('*');
2257 int typeId = QMetaType::type(typeString);
2258 if (typeId != 0) {
2259 QScriptValueImpl proto = defaultPrototype(typeId);
2260 if (proto.isValid()) {
2261 out->setPrototype(proto);
2262 break;
2263 }
2264 }
2265 meta = meta->superClass();
2266 }
2267 }
2268 }
2269
qobjectData(QObject * object)2270 QScriptQObjectData *QScriptEnginePrivate::qobjectData(QObject *object)
2271 {
2272 QHash<QObject*, QScriptQObjectData*>::const_iterator it;
2273 it = m_qobjectData.constFind(object);
2274 if (it != m_qobjectData.constEnd())
2275 return it.value();
2276
2277 QScriptQObjectData *data = new QScriptQObjectData();
2278 m_qobjectData.insert(object, data);
2279 QObject::connect(object, SIGNAL(destroyed(QObject*)),
2280 q_func(), SLOT(_q_objectDestroyed(QObject *)));
2281 return data;
2282 }
2283
_q_objectDestroyed(QObject * object)2284 void QScriptEnginePrivate::_q_objectDestroyed(QObject *object)
2285 {
2286 QHash<QObject*, QScriptQObjectData*>::iterator it;
2287 it = m_qobjectData.find(object);
2288 Q_ASSERT(it != m_qobjectData.end());
2289 QScriptQObjectData *data = it.value();
2290 m_qobjectData.erase(it);
2291 delete data;
2292 }
2293
disposeQObject(QObject * object)2294 void QScriptEnginePrivate::disposeQObject(QObject *object)
2295 {
2296 if (isCollecting()) {
2297 // wait until we're done with GC before deleting it
2298 int index = m_qobjectsToBeDeleted.indexOf(object);
2299 if (index == -1)
2300 m_qobjectsToBeDeleted.append(object);
2301 } else {
2302 delete object;
2303 }
2304 }
2305
deletePendingQObjects()2306 void QScriptEnginePrivate::deletePendingQObjects()
2307 {
2308 while (!m_qobjectsToBeDeleted.isEmpty())
2309 delete m_qobjectsToBeDeleted.takeFirst();
2310 }
2311
scriptConnect(QObject * sender,const char * signal,const QScriptValueImpl & receiver,const QScriptValueImpl & function,Qt::ConnectionType type)2312 bool QScriptEnginePrivate::scriptConnect(QObject *sender, const char *signal,
2313 const QScriptValueImpl &receiver,
2314 const QScriptValueImpl &function,
2315 Qt::ConnectionType type)
2316 {
2317 Q_ASSERT(sender);
2318 Q_ASSERT(signal);
2319 const QMetaObject *meta = sender->metaObject();
2320 int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
2321 if (index == -1)
2322 return false;
2323 return scriptConnect(sender, index, receiver, function, /*wrapper=*/QScriptValueImpl(), type);
2324 }
2325
scriptDisconnect(QObject * sender,const char * signal,const QScriptValueImpl & receiver,const QScriptValueImpl & function)2326 bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, const char *signal,
2327 const QScriptValueImpl &receiver,
2328 const QScriptValueImpl &function)
2329 {
2330 Q_ASSERT(sender);
2331 Q_ASSERT(signal);
2332 const QMetaObject *meta = sender->metaObject();
2333 int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
2334 if (index == -1)
2335 return false;
2336 return scriptDisconnect(sender, index, receiver, function);
2337 }
2338
scriptConnect(QObject * sender,int signalIndex,const QScriptValueImpl & receiver,const QScriptValueImpl & function,const QScriptValueImpl & senderWrapper,Qt::ConnectionType type)2339 bool QScriptEnginePrivate::scriptConnect(QObject *sender, int signalIndex,
2340 const QScriptValueImpl &receiver,
2341 const QScriptValueImpl &function,
2342 const QScriptValueImpl &senderWrapper,
2343 Qt::ConnectionType type)
2344 {
2345 QScriptQObjectData *data = qobjectData(sender);
2346 return data->addSignalHandler(sender, signalIndex, receiver, function, senderWrapper, type);
2347 }
2348
scriptDisconnect(QObject * sender,int signalIndex,const QScriptValueImpl & receiver,const QScriptValueImpl & function)2349 bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, int signalIndex,
2350 const QScriptValueImpl &receiver,
2351 const QScriptValueImpl &function)
2352 {
2353 QScriptQObjectData *data = qobjectData(sender);
2354 if (!data)
2355 return false;
2356 return data->removeSignalHandler(sender, signalIndex, receiver, function);
2357 }
2358
scriptConnect(const QScriptValueImpl & signal,const QScriptValueImpl & receiver,const QScriptValueImpl & function,Qt::ConnectionType type)2359 bool QScriptEnginePrivate::scriptConnect(const QScriptValueImpl &signal,
2360 const QScriptValueImpl &receiver,
2361 const QScriptValueImpl &function,
2362 Qt::ConnectionType type)
2363 {
2364 QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(signal.toFunction());
2365 int index = fun->mostGeneralMethod();
2366 return scriptConnect(fun->qobject(), index, receiver, function, fun->object(), type);
2367 }
2368
scriptDisconnect(const QScriptValueImpl & signal,const QScriptValueImpl & receiver,const QScriptValueImpl & function)2369 bool QScriptEnginePrivate::scriptDisconnect(const QScriptValueImpl &signal,
2370 const QScriptValueImpl &receiver,
2371 const QScriptValueImpl &function)
2372 {
2373 QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(signal.toFunction());
2374 int index = fun->mostGeneralMethod();
2375 return scriptDisconnect(fun->qobject(), index, receiver, function);
2376 }
2377
convertToNativeQObject(const QScriptValueImpl & value,const QByteArray & targetType,void ** result)2378 bool QScriptEnginePrivate::convertToNativeQObject(const QScriptValueImpl &value,
2379 const QByteArray &targetType,
2380 void **result)
2381 {
2382 if (!targetType.endsWith('*'))
2383 return false;
2384 if (QObject *qobject = value.toQObject()) {
2385 int start = targetType.startsWith("const ") ? 6 : 0;
2386 QByteArray className = targetType.mid(start, targetType.size()-start-1);
2387 if (void *instance = qobject->qt_metacast(className)) {
2388 *result = instance;
2389 return true;
2390 }
2391 }
2392 return false;
2393 }
2394
2395 #endif // QT_NO_QOBJECT
2396
setAgent(QScriptEngineAgent * agent)2397 void QScriptEnginePrivate::setAgent(QScriptEngineAgent *agent)
2398 {
2399 Q_Q(QScriptEngine);
2400 if (agent && (agent->engine() != q)) {
2401 qWarning("QScriptEngine::setAgent(): "
2402 "cannot set agent belonging to different engine");
2403 return;
2404 }
2405 if (agent) {
2406 int index = m_agents.indexOf(agent);
2407 if (index == -1)
2408 m_agents.append(agent);
2409 }
2410 m_agent = agent;
2411 }
2412
agent() const2413 QScriptEngineAgent *QScriptEnginePrivate::agent() const
2414 {
2415 return m_agent;
2416 }
2417
agentDeleted(QScriptEngineAgent * agent)2418 void QScriptEnginePrivate::agentDeleted(QScriptEngineAgent *agent)
2419 {
2420 m_agents.removeOne(agent);
2421 if (m_agent == agent)
2422 m_agent = 0;
2423 }
2424
2425 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
nextScriptId()2426 qint64 QScriptEnginePrivate::nextScriptId()
2427 {
2428 // ### reuse IDs by using a pool
2429 return m_scriptCounter++;
2430 }
2431
notifyScriptLoad_helper(qint64 id,const QString & program,const QString & fileName,int lineNumber)2432 void QScriptEnginePrivate::notifyScriptLoad_helper(qint64 id, const QString &program,
2433 const QString &fileName, int lineNumber)
2434 {
2435 m_agent->scriptLoad(id, program, fileName, lineNumber);
2436 }
2437
notifyScriptUnload_helper(qint64 id)2438 void QScriptEnginePrivate::notifyScriptUnload_helper(qint64 id)
2439 {
2440 m_agent->scriptUnload(id);
2441 }
2442
notifyPositionChange_helper(QScriptContextPrivate * ctx)2443 void QScriptEnginePrivate::notifyPositionChange_helper(QScriptContextPrivate *ctx)
2444 {
2445 m_agent->positionChange(ctx->scriptId(), ctx->currentLine, ctx->currentColumn);
2446 }
2447
notifyContextPush_helper()2448 void QScriptEnginePrivate::notifyContextPush_helper()
2449 {
2450 m_agent->contextPush();
2451 }
2452
notifyContextPop_helper()2453 void QScriptEnginePrivate::notifyContextPop_helper()
2454 {
2455 m_agent->contextPop();
2456 }
2457
notifyFunctionEntry_helper(QScriptContextPrivate * ctx)2458 void QScriptEnginePrivate::notifyFunctionEntry_helper(QScriptContextPrivate *ctx)
2459 {
2460 m_agent->functionEntry(ctx->scriptId());
2461 }
2462
notifyFunctionExit_helper(QScriptContextPrivate * ctx)2463 void QScriptEnginePrivate::notifyFunctionExit_helper(QScriptContextPrivate *ctx)
2464 {
2465 m_agent->functionExit(ctx->scriptId(), toPublic(ctx->returnValue()));
2466 }
2467
notifyException_helper(QScriptContextPrivate * ctx)2468 void QScriptEnginePrivate::notifyException_helper(QScriptContextPrivate *ctx)
2469 {
2470 bool hasHandler = (ctx->exceptionHandlerContext() != 0);
2471 m_agent->exceptionThrow(ctx->scriptId(), toPublic(ctx->returnValue()), hasHandler);
2472 }
2473
notifyExceptionCatch_helper(QScriptContextPrivate * ctx)2474 void QScriptEnginePrivate::notifyExceptionCatch_helper(QScriptContextPrivate *ctx)
2475 {
2476 m_agent->exceptionCatch(ctx->scriptId(), toPublic(ctx->returnValue()));
2477 }
2478
notifyDebugger(QScriptContextPrivate * ctx)2479 void QScriptEnginePrivate::notifyDebugger(QScriptContextPrivate *ctx)
2480 {
2481 if (m_agent && m_agent->supportsExtension(QScriptEngineAgent::DebuggerInvocationRequest)) {
2482 QVariantList args;
2483 args.append(ctx->scriptId());
2484 args.append(ctx->currentLine);
2485 args.append(ctx->currentColumn);
2486 QVariant ret = m_agent->extension(QScriptEngineAgent::DebuggerInvocationRequest, args);
2487 QScriptValueImpl val = valueFromVariant(ret);
2488 if (val.isValid())
2489 ctx->m_result = val;
2490 }
2491 }
2492
2493 #endif // Q_SCRIPT_NO_EVENT_NOTIFY
2494
internedString(const QString & str)2495 QScriptString QScriptEnginePrivate::internedString(const QString &str)
2496 {
2497 return internedString(nameId(str, /*persistent=*/false));
2498 }
2499
internedString(QScriptNameIdImpl * nid)2500 QScriptString QScriptEnginePrivate::internedString(QScriptNameIdImpl *nid)
2501 {
2502 if (!nid)
2503 return QScriptString();
2504 QScriptStringPrivate *d = m_internedStrings.value(nid);
2505 if (!d) {
2506 d = m_internedStringRepository.get();
2507 d->nameId = nid;
2508 d->engine = this;
2509 m_internedStrings.insert(d->nameId, d);
2510 }
2511 QScriptString result;
2512 QScriptStringPrivate::init(result, d);
2513 return result;
2514 }
2515
uninternString(QScriptStringPrivate * d)2516 void QScriptEnginePrivate::uninternString(QScriptStringPrivate *d)
2517 {
2518 Q_ASSERT(d->nameId);
2519 QHash<QScriptNameIdImpl*, QScriptStringPrivate*>::iterator it;
2520 it = m_internedStrings.find(d->nameId);
2521 Q_ASSERT(it != m_internedStrings.end());
2522 m_internedStrings.erase(it);
2523 m_internedStringRepository.release(d);
2524 }
2525
toImpl_helper(const QScriptValue & value)2526 QScriptValueImpl QScriptEnginePrivate::toImpl_helper(const QScriptValue &value)
2527 {
2528 QScriptValuePrivate *p = QScriptValuePrivate::get(value);
2529 Q_ASSERT(p != 0);
2530 Q_ASSERT(p->value.type() == QScript::LazyStringType);
2531 QString str = *p->value.m_lazy_string_value;
2532 if (!p->ref.deref())
2533 delete p;
2534 QScriptValueImpl v;
2535 newString(&v, str);
2536 p = registerValue(v);
2537 QScriptValuePrivate::init(const_cast<QScriptValue&>(value), p);
2538 return v;
2539 }
2540
newObject(QScriptClass * scriptClass,const QScriptValueImpl & data)2541 QScriptValueImpl QScriptEnginePrivate::newObject(QScriptClass *scriptClass,
2542 const QScriptValueImpl &data)
2543 {
2544 if (!scriptClass)
2545 return QScriptValueImpl();
2546 QScriptValueImpl v;
2547 QScriptValueImpl proto = toImpl(scriptClass->prototype());
2548 if (!proto.isObject())
2549 proto = objectConstructor->publicPrototype;
2550 newObject(&v, proto);
2551 QScriptClassPrivate *cls_p = QScriptClassPrivate::get(scriptClass);
2552 QScriptClassInfo *info = cls_p->classInfo();
2553 v.setClassInfo(info);
2554 if (info->type() & QScriptClassInfo::FunctionBased) {
2555 QScriptFunction *fun = cls_p->newFunction();
2556 v.setObjectData(fun);
2557 }
2558 v.setInternalValue(data);
2559 return v;
2560 }
2561
registerCustomClassType()2562 int QScriptEnginePrivate::registerCustomClassType()
2563 {
2564 return ++m_class_prev_id;
2565 }
2566
objectById(qint64 id) const2567 QScriptValueImpl QScriptEnginePrivate::objectById(qint64 id) const
2568 {
2569 QScript::GCAlloc<QScriptObject>::const_iterator it;
2570 for (it = objectAllocator.constBegin(); it != objectAllocator.constEnd(); ++it) {
2571 const QScriptObject *obj = it.data();
2572 if (obj->m_id == id) {
2573 QScriptValueImpl ret;
2574 ret.m_type = QScript::ObjectType;
2575 ret.m_object_value = const_cast<QScriptObject*>(obj);
2576 return ret;
2577 }
2578 }
2579 return QScriptValueImpl();
2580 }
2581
2582 namespace QScript {
2583
qsTranslate(QScriptContextPrivate * ctx,QScriptEnginePrivate * eng,QScriptClassInfo *)2584 static QScriptValueImpl qsTranslate(QScriptContextPrivate *ctx, QScriptEnginePrivate *eng, QScriptClassInfo *)
2585 {
2586 if (ctx->argumentCount() < 2)
2587 return ctx->throwError(QString::fromLatin1("qsTranslate() requires at least two arguments"));
2588 if (!ctx->argument(0).isString())
2589 return ctx->throwError(QString::fromLatin1("qsTranslate(): first argument (context) must be a string"));
2590 if (!ctx->argument(1).isString())
2591 return ctx->throwError(QString::fromLatin1("qsTranslate(): second argument (text) must be a string"));
2592 if ((ctx->argumentCount() > 2) && !ctx->argument(2).isString())
2593 return ctx->throwError(QString::fromLatin1("qsTranslate(): third argument (comment) must be a string"));
2594 if ((ctx->argumentCount() > 3) && !ctx->argument(3).isString())
2595 return ctx->throwError(QString::fromLatin1("qsTranslate(): fourth argument (encoding) must be a string"));
2596 if ((ctx->argumentCount() > 4) && !ctx->argument(4).isNumber())
2597 return ctx->throwError(QString::fromLatin1("qsTranslate(): fifth argument (n) must be a number"));
2598 #ifndef QT_NO_QOBJECT
2599 QString context = ctx->argument(0).toString();
2600 #endif
2601 QString text = ctx->argument(1).toString();
2602 #ifndef QT_NO_QOBJECT
2603 QString comment;
2604 if (ctx->argumentCount() > 2)
2605 comment = ctx->argument(2).toString();
2606 QCoreApplication::Encoding encoding = QCoreApplication::CodecForTr;
2607 if (ctx->argumentCount() > 3) {
2608 QString encStr = ctx->argument(3).toString();
2609 if (encStr == QLatin1String("CodecForTr"))
2610 encoding = QCoreApplication::CodecForTr;
2611 else if (encStr == QLatin1String("UnicodeUTF8"))
2612 encoding = QCoreApplication::UnicodeUTF8;
2613 else
2614 return ctx->throwError(QString::fromLatin1("qsTranslate(): invalid encoding '%s'").arg(encStr));
2615 }
2616 int n = -1;
2617 if (ctx->argumentCount() > 4)
2618 n = ctx->argument(4).toInt32();
2619 #endif
2620 QString result;
2621 #ifndef QT_NO_QOBJECT
2622 result = QCoreApplication::translate(context.toLatin1().constData(),
2623 text.toLatin1().constData(),
2624 comment.toLatin1().constData(),
2625 encoding, n);
2626 #else
2627 result = text;
2628 #endif
2629 return QScriptValueImpl(eng, result);
2630 }
2631
qTranslateNoOp(QScriptContextPrivate * ctx,QScriptEnginePrivate *,QScriptClassInfo *)2632 static QScriptValueImpl qTranslateNoOp(QScriptContextPrivate *ctx, QScriptEnginePrivate *, QScriptClassInfo *)
2633 {
2634 return ctx->argument(1);
2635 }
2636
qsTr(QScriptContextPrivate * ctx,QScriptEnginePrivate * eng,QScriptClassInfo *)2637 static QScriptValueImpl qsTr(QScriptContextPrivate *ctx, QScriptEnginePrivate *eng, QScriptClassInfo *)
2638 {
2639 if (ctx->argumentCount() < 1)
2640 return ctx->throwError(QString::fromLatin1("qsTr() requires at least one argument"));
2641 if (!ctx->argument(0).isString())
2642 return ctx->throwError(QString::fromLatin1("qsTr(): first argument (text) must be a string"));
2643 if ((ctx->argumentCount() > 1) && !ctx->argument(1).isString())
2644 return ctx->throwError(QString::fromLatin1("qsTr(): second argument (comment) must be a string"));
2645 if ((ctx->argumentCount() > 2) && !ctx->argument(2).isNumber())
2646 return ctx->throwError(QString::fromLatin1("qsTranslate(): third argument (n) must be a number"));
2647 #ifndef QT_NO_QOBJECT
2648 QString context;
2649 if (ctx->parentContext())
2650 context = QFileInfo(ctx->parentContext()->fileName()).baseName();
2651 #endif
2652 QString text = ctx->argument(0).toString();
2653 #ifndef QT_NO_QOBJECT
2654 QString comment;
2655 if (ctx->argumentCount() > 1)
2656 comment = ctx->argument(1).toString();
2657 int n = -1;
2658 if (ctx->argumentCount() > 2)
2659 n = ctx->argument(2).toInt32();
2660 #endif
2661 QString result;
2662 #ifndef QT_NO_QOBJECT
2663 result = QCoreApplication::translate(context.toLatin1().constData(),
2664 text.toLatin1().constData(),
2665 comment.toLatin1().constData(),
2666 QCoreApplication::CodecForTr, n);
2667 #else
2668 result = text;
2669 #endif
2670 return QScriptValueImpl(eng, result);
2671 }
2672
qTrNoOp(QScriptContextPrivate * ctx,QScriptEnginePrivate *,QScriptClassInfo *)2673 static QScriptValueImpl qTrNoOp(QScriptContextPrivate *ctx, QScriptEnginePrivate *, QScriptClassInfo *)
2674 {
2675 return ctx->argument(0);
2676 }
2677
2678 } // namespace QScript
2679
installTranslatorFunctions(QScriptValueImpl & object)2680 void QScriptEnginePrivate::installTranslatorFunctions(QScriptValueImpl &object)
2681 {
2682 Q_ASSERT(object.isObject());
2683 const QScriptValue::PropertyFlags flags = QScriptValue::SkipInEnumeration;
2684 object.setProperty(QLatin1String("qsTranslate"),
2685 createFunction(QScript::qsTranslate, /*length=*/5, /*classInfo=*/0),
2686 flags);
2687 object.setProperty(QLatin1String("QT_TRANSLATE_NOOP"),
2688 createFunction(QScript::qTranslateNoOp, /*length=*/2, /*classInfo=*/0),
2689 flags);
2690 object.setProperty(QLatin1String("qsTr"),
2691 createFunction(QScript::qsTr, /*length=*/3, /*classInfo=*/0),
2692 flags);
2693 object.setProperty(QLatin1String("QT_TR_NOOP"),
2694 createFunction(QScript::qTrNoOp, /*length=*/1, /*classInfo=*/0),
2695 flags);
2696
2697 stringConstructor->addPrototypeFunction(QLatin1String("arg"), QScript::Ecma::String::method_ext_arg, 1);
2698 }
2699
canEvaluate(const QString & program)2700 bool QScriptEnginePrivate::canEvaluate(const QString &program)
2701 {
2702 QScript::SyntaxChecker checker;
2703 QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
2704 return (result.state != QScript::SyntaxChecker::Intermediate);
2705 }
2706
checkSyntax(const QString & program)2707 QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &program)
2708 {
2709 QScript::SyntaxChecker checker;
2710 QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
2711 QScriptSyntaxCheckResultPrivate *p = new QScriptSyntaxCheckResultPrivate();
2712 switch (result.state) {
2713 case QScript::SyntaxChecker::Error:
2714 p->state = QScriptSyntaxCheckResult::Error;
2715 break;
2716 case QScript::SyntaxChecker::Intermediate:
2717 p->state = QScriptSyntaxCheckResult::Intermediate;
2718 break;
2719 case QScript::SyntaxChecker::Valid:
2720 p->state = QScriptSyntaxCheckResult::Valid;
2721 break;
2722 }
2723 p->errorLineNumber = result.errorLineNumber;
2724 p->errorColumnNumber = result.errorColumnNumber;
2725 p->errorMessage = result.errorMessage;
2726 return QScriptSyntaxCheckResult(p);
2727 }
2728
2729 QT_END_NAMESPACE
2730
2731