1 /*
2  *  This file is part of the KDE libraries
3  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
4  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
5  *  Copyright (C) 2003 Apple Computer, Inc.
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Library General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Library General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Library General Public License
18  *  along with this library; see the file COPYING.LIB.  If not, write to
19  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301, USA.
21  *
22  */
23 
24 #ifndef _KJS_INTERPRETER_H_
25 #define _KJS_INTERPRETER_H_
26 
27 #include "ExecState.h"
28 #include "protect.h"
29 #include "value.h"
30 #include "types.h"
31 #include <wtf/HashMap.h>
32 
33 namespace KJS
34 {
35 class Debugger;
36 class SavedBuiltins;
37 class TimeoutChecker;
38 class Package;
39 class ActivationImp;
40 class JSGlobalObject;
41 class StringImp;
42 
43 #if USE(BINDINGS)
44 namespace Bindings
45 {
46 class RootObject;
47 }
48 #endif
49 
50 /**
51  * Interpreter objects can be used to evaluate ECMAScript code. Each
52  * interpreter has a global object which is used for the purposes of code
53  * evaluation, and also provides access to built-in properties such as
54  * " Object" and "Number".
55  */
56 class KJS_EXPORT Interpreter
57 {
58     friend class Collector;
59     friend class TimeoutChecker;
60 public:
61     /**
62      * Creates a new interpreter. The supplied object will be used as the global
63      * object for all scripts executed with this interpreter. During
64      * construction, all the standard properties such as "Object" and "Number"
65      * will be added to the global object.
66      *
67      * Note: You should not use the same global object for multiple
68      * interpreters.
69      *
70      * This is due do the fact that the built-in properties are set in the
71      * constructor, and if these objects have been modified from another
72      * interpreter (e.g. a script modifying String.prototype), the changes will
73      * be overridden.
74      *
75      * @param globalObject The object to use as the global object for this interpreter
76      */
77     Interpreter(JSGlobalObject *globalObject);
78     /**
79      * Creates a new interpreter. A global object will be created and
80      * initialized with the standard global properties.
81      */
82     Interpreter();
83 
84     /**
85      * Returns the object that is used as the global object during all script
86      * execution performed by this interpreter
87      */
88     JSGlobalObject *globalObject() const;
89     void initGlobalObject();
90 
91     /**
92      * Returns the execution state object which can be used to execute
93      * scripts using this interpreter at a the "global" level, i.e. one
94      * with a execution context that has the global object as the "this"
95      * value, and who's scope chain contains only the global object.
96      *
97      * Note: this pointer remains constant for the life of the interpreter
98      * and should not be manually deleted.
99      *
100      * @return The interpreter global execution state object
101      */
102     virtual ExecState *globalExec();
103 
104     /**
105      * Sets the package instance that will be used to resolve the
106      * first level of identifiers of import statements.
107      *
108      * If no package is set which will make any "import" script
109      * statement fail with an error. This is the default in e.g.  a
110      * Web browser where package imports should be disabled for
111      * security reasons.
112      */
113     void setGlobalPackage(Package *p);
114 
115     /**
116      * Returns the package that was installed to handle top level
117      * package requests. Returns 0, the default, when no package was
118      * set.
119      *
120      * @return The global package
121      */
122     Package *globalPackage();
123 
124     /**
125      * Parses the supplied ECMAScript code and checks for syntax errors.
126      *
127      * @param code The code to check
128      * @param sourceURL A URL denoting the origin of the code
129      * @param startingLineNumber The line offset within an embedding context
130      * @return A normal completion if there were no syntax errors in the code,
131      * otherwise a throw completion with the syntax error as its value.
132      */
133     Completion checkSyntax(const UString &sourceURL, int startingLineNumber, const UString &code);
134     Completion checkSyntax(const UString &sourceURL, int startingLineNumber, const UChar *code, int codeLength);
135 
136     /**
137      * Evaluates the supplied ECMAScript code.
138      *
139      * Since this method returns a Completion, you should check the type of
140      * completion to detect an error or before attempting to access the returned
141      * value. For example, if an error occurs during script execution and is not
142      * caught by the script, the completion type will be Throw.
143      *
144      * If the supplied code is invalid, a SyntaxError will be thrown.
145      *
146      * @param sourceURL A URL denoting the origin of the code
147      * @param startingLineNumber The line offset within an embedding context
148      * @param code The code to evaluate
149      * @param codeLength The length of the code to evaluate
150      * @param thisV The value to pass in as the "this" value for the script
151      * execution. This should either be jsNull() or an Object.
152      * @return A completion object representing the result of the execution.
153      */
154     Completion evaluate(const UString &sourceURL, int startingLineNumber, const UChar *code, int codeLength, JSValue *thisV = nullptr);
155     Completion evaluate(const UString &sourceURL, int startingLineNumber, const UString &code, JSValue *thisV = nullptr);
156 
157     /**
158      * Pretty-prints the supplied ECMAScript code after checking it
159      * for syntax errors.
160      *
161      * @param sourceURL A URL denoting the origin of the code
162      * @param startingLineNumber The line offset within an embedding context
163      * @param codeIn The code to check
164      * @param codeIn Pointer to string that will contain reformatted code
165      *        upon successful parsing.
166      * @return A normal completion if there were no syntax errors in the code,
167      * otherwise a throw completion with the syntax error as its value.
168      */
169     static bool normalizeCode(const UString &codeIn, UString *codeOut,
170                               int *errLine = nullptr, UString *errMsg = nullptr);
171 
172     /**
173      * Returns the builtin "Object" object. This is the object that was set
174      * as a property of the global object during construction; if the property
175      * is replaced by script code, this method will still return the original
176      * object.
177      *
178      * @return The builtin "Object" object
179      */
180     JSObject *builtinObject() const;
181 
182     /**
183      * Returns the builtin "Function" object.
184      */
185     JSObject *builtinFunction() const;
186 
187     /**
188      * Returns the builtin "Array" object.
189      */
190     JSObject *builtinArray() const;
191 
192     /**
193      * Returns the builtin "Boolean" object.
194      */
195     JSObject *builtinBoolean() const;
196 
197     /**
198      * Returns the builtin "String" object.
199      */
200     JSObject *builtinString() const;
201 
202     /**
203      * Returns the builtin "Number" object.
204      */
205     JSObject *builtinNumber() const;
206 
207     /**
208      * Returns the builtin "Date" object.
209      */
210     JSObject *builtinDate() const;
211 
212     /**
213      * Returns the builtin "RegExp" object.
214      */
215     JSObject *builtinRegExp() const;
216 
217     /**
218      * Returns the builtin "Error" object.
219      */
220     JSObject *builtinError() const;
221 
222     /**
223      * Returns the builtin "Object.prototype" object.
224      */
225     JSObject *builtinObjectPrototype() const;
226 
227     /**
228      * Returns the builtin "Function.prototype" object.
229      */
230     JSObject *builtinFunctionPrototype() const;
231 
232     /**
233      * Returns the builtin "Array.prototype" object.
234      */
235     JSObject *builtinArrayPrototype() const;
236 
237     /**
238      * Returns the builtin "Boolean.prototype" object.
239      */
240     JSObject *builtinBooleanPrototype() const;
241 
242     /**
243      * Returns the builtin "String.prototype" object.
244      */
245     JSObject *builtinStringPrototype() const;
246 
247     /**
248      * Returns the builtin "Number.prototype" object.
249      */
250     JSObject *builtinNumberPrototype() const;
251 
252     /**
253      * Returns the builtin "Date.prototype" object.
254      */
255     JSObject *builtinDatePrototype() const;
256 
257     /**
258      * Returns the builtin "RegExp.prototype" object.
259      */
260     JSObject *builtinRegExpPrototype() const;
261 
262     /**
263      * Returns the builtin "Error.prototype" object.
264      */
265     JSObject *builtinErrorPrototype() const;
266 
267     /**
268      * The initial value of "Error" global property
269      */
270     JSObject *builtinEvalError() const;
271     JSObject *builtinRangeError() const;
272     JSObject *builtinReferenceError() const;
273     JSObject *builtinSyntaxError() const;
274     JSObject *builtinTypeError() const;
275     JSObject *builtinURIError() const;
276 
277     JSObject *builtinEvalErrorPrototype() const;
278     JSObject *builtinRangeErrorPrototype() const;
279     JSObject *builtinReferenceErrorPrototype() const;
280     JSObject *builtinSyntaxErrorPrototype() const;
281     JSObject *builtinTypeErrorPrototype() const;
282     JSObject *builtinURIErrorPrototype() const;
283 
284     enum CompatMode { NativeMode, IECompat, NetscapeCompat };
285     /**
286      * Call this to enable a compatibility mode with another browser.
287      * (by default konqueror is in "native mode").
288      * Currently, in KJS, this only changes the behavior of Date::getYear()
289      * which returns the full year under IE.
290      */
setCompatMode(CompatMode mode)291     void setCompatMode(CompatMode mode)
292     {
293         m_compatMode = mode;
294     }
compatMode()295     CompatMode compatMode() const
296     {
297         return m_compatMode;
298     }
299 
300     /**
301      * Run the garbage collection. Returns true when at least one object
302      * was collected; false otherwise.
303      */
304     static bool collect();
305 
306     /**
307      * Called during the mark phase of the garbage collector. Subclasses
308      * implementing custom mark methods must make sure to chain to this one.
309      */
310     virtual void mark(bool currentThreadIsMainThread);
311 
312     /**
313      * This marks all GC heap resources stored as optimizations;
314      * and which have their lifetime managed by the appropriate AST.
315      * It's static since code can survive the interpreter by a bit.
316      */
317     static void markSourceCachedObjects();
318 
319     /**
320      * Provides a way to distinguish derived classes.
321      * Only useful if you reimplement Interpreter and if different kind of
322      * interpreters are created in the same process.
323      * The base class returns 0, the ECMA-bindings interpreter returns 1.
324      */
rtti()325     virtual int rtti()
326     {
327         return 0;
328     }
329 
330     static bool shouldPrintExceptions();
331     static void setShouldPrintExceptions(bool);
332 
333     void saveBuiltins(SavedBuiltins &) const;
334     void restoreBuiltins(const SavedBuiltins &);
335 
336     /**
337      * Determine if the it is 'safe' to execute code in the target interpreter from an
338      * object that originated in this interpreter.  This check is used to enforce WebCore
339      * cross frame security rules.  In particular, attempts to access 'bound' objects are
340      * not allowed unless isSafeScript returns true.
341      */
isSafeScript(const Interpreter *)342     virtual bool isSafeScript(const Interpreter *)
343     {
344         return true;
345     }
346 
347 #if USE(BINDINGS)
348     virtual void *createLanguageInstanceForValue(ExecState *, int language, JSObject *value, const Bindings::RootObject *origin, const Bindings::RootObject *current);
349 #endif
350 
351     // Chained list of interpreters (ring)
firstInterpreter()352     static Interpreter *firstInterpreter()
353     {
354         return s_hook;
355     }
nextInterpreter()356     Interpreter *nextInterpreter() const
357     {
358         return next;
359     }
prevInterpreter()360     Interpreter *prevInterpreter() const
361     {
362         return prev;
363     }
364 
debugger()365     Debugger *debugger() const
366     {
367         return m_debugger;
368     }
setDebugger(Debugger * d)369     void setDebugger(Debugger *d)
370     {
371         m_debugger = d;
372     }
373 
setExecState(ExecState * e)374     void setExecState(ExecState *e)
375     {
376         m_execState = e;
377     }
378 
379     // Note: may be 0, if in globalExec
execState()380     ExecState *execState()
381     {
382         return m_execState ? m_execState : &m_globalExec;
383     }
384 
setTimeoutTime(unsigned timeoutTime)385     void setTimeoutTime(unsigned timeoutTime)
386     {
387         m_timeoutTime = timeoutTime;
388     }
389 
390     void startTimeoutCheck();
391     void stopTimeoutCheck();
392 
393     // Resets the timer to full time if it's running
394     void restartTimeoutCheck();
395 
396     void pauseTimeoutCheck();
397     void resumeTimeoutCheck();
398 
399     bool checkTimeout();
400 
ref()401     void ref()
402     {
403         ++m_refCount;
404     }
deref()405     void deref()
406     {
407         if (--m_refCount <= 0) {
408             delete this;
409         }
410     }
refCount()411     int refCount() const
412     {
413         return m_refCount;
414     }
415 
stackAlloc(size_t size)416     unsigned char *stackAlloc(size_t size)
417     {
418         unsigned char *nextPtr = stackPtr + size;
419         if (nextPtr <= stackEnd) {
420             unsigned char *toRet = stackPtr;
421             stackPtr = nextPtr;
422             return toRet;
423         }
424         return extendStack(size);
425     }
426 
stackFree(size_t size)427     void stackFree(size_t size)
428     {
429         stackPtr -= size;    // ### shrink it?
430     }
431 
getRecycledActivation()432     ActivationImp *getRecycledActivation()
433     {
434         ActivationImp *out = nullptr;
435         if (m_numCachedActivations) {
436             m_numCachedActivations--;
437             out = m_cachedActivations[m_numCachedActivations];
438         }
439         return out;
440     }
441 
442     void recycleActivation(ActivationImp *act);
443 
444     // Global string table management. This is used from StringNode
445     // to cache StringImp's for string literals. We keep refcounts
446     // to permit multiple ones to use the same value.
447     static StringImp *internString(const UString &literal);
448     static void releaseInternedString(const UString &literal);
449 
450     typedef WTF::HashMap<UString::Rep *, std::pair<KJS::StringImp *, int> > InternedStringsTable;
451 private:
452     static void markInternedStringsTable();
453 
454     // This creates a table if needed
455     static void initInternedStringsTable();
456 
457     static InternedStringsTable *s_internedStrings;
458 
459 protected:
460     virtual ~Interpreter(); // only deref should delete us
shouldInterruptScript()461     virtual bool shouldInterruptScript() const
462     {
463         return true;
464     }
465 
466     long m_timeoutTime;
467 
468 private:
469     bool handleTimeout();
470     void init();
471     void printException(const Completion &c, const UString &sourceURL);
472 
473     /**
474      * This constructor is not implemented, in order to prevent
475      * copy-construction of Interpreter objects. You should always pass around
476      * pointers to an interpreter instance instead.
477      */
478     Interpreter(const Interpreter &);
479 
480     /**
481      * This operator is not implemented, in order to prevent assignment of
482      * Interpreter objects. You should always pass around pointers to an
483      * interpreter instance instead.
484      */
485     Interpreter operator=(const Interpreter &);
486 
487     int m_refCount;
488 
489     JSGlobalObject *m_globalObject;
490     GlobalExecState m_globalExec;
491     Package *globPkg;
492 
493     // Execution stack stuff for this interpreter.
494     unsigned char *stackBase; // lowest address in the array
495     unsigned char *stackPtr;  // current top/next to allocate
496     unsigned char *stackEnd;  // last address in the stack
497     unsigned char *extendStack(size_t needed);
498 
499     // A list of cached activations
500     enum {MaxCachedActivations = 32};
501 
502     ActivationImp *m_cachedActivations[MaxCachedActivations];
503     int            m_numCachedActivations;
504 
505     // Chained list of interpreters (ring) - for collector
506     static Interpreter *s_hook;
507     Interpreter *next, *prev;
508 
509     int m_recursion;
510 
511     Debugger *m_debugger;
512     ExecState *m_execState;
513     CompatMode m_compatMode;
514 
515     TimeoutChecker *m_timeoutChecker;
516     bool m_timedOut;
517 
518     unsigned m_startTimeoutCheckCount;
519     unsigned m_pauseTimeoutCheckCount;
520 
521     // Helper for setting constructors, making sure their function names are OK
522     void putNamedConstructor(const char *name, JSObject *value);
523 
524     ProtectedPtr<JSObject> m_Object;
525     ProtectedPtr<JSObject> m_Function;
526     ProtectedPtr<JSObject> m_Array;
527     ProtectedPtr<JSObject> m_Boolean;
528     ProtectedPtr<JSObject> m_String;
529     ProtectedPtr<JSObject> m_Number;
530     ProtectedPtr<JSObject> m_Date;
531     ProtectedPtr<JSObject> m_RegExp;
532     ProtectedPtr<JSObject> m_Error;
533 
534     ProtectedPtr<JSObject> m_ObjectPrototype;
535     ProtectedPtr<JSObject> m_FunctionPrototype;
536     ProtectedPtr<JSObject> m_ArrayPrototype;
537     ProtectedPtr<JSObject> m_BooleanPrototype;
538     ProtectedPtr<JSObject> m_StringPrototype;
539     ProtectedPtr<JSObject> m_NumberPrototype;
540     ProtectedPtr<JSObject> m_DatePrototype;
541     ProtectedPtr<JSObject> m_RegExpPrototype;
542     ProtectedPtr<JSObject> m_ErrorPrototype;
543 
544     ProtectedPtr<JSObject> m_EvalError;
545     ProtectedPtr<JSObject> m_RangeError;
546     ProtectedPtr<JSObject> m_ReferenceError;
547     ProtectedPtr<JSObject> m_SyntaxError;
548     ProtectedPtr<JSObject> m_TypeError;
549     ProtectedPtr<JSObject> m_UriError;
550 
551     ProtectedPtr<JSObject> m_EvalErrorPrototype;
552     ProtectedPtr<JSObject> m_RangeErrorPrototype;
553     ProtectedPtr<JSObject> m_ReferenceErrorPrototype;
554     ProtectedPtr<JSObject> m_SyntaxErrorPrototype;
555     ProtectedPtr<JSObject> m_TypeErrorPrototype;
556     ProtectedPtr<JSObject> m_UriErrorPrototype;
557 };
558 
checkTimeout()559 inline bool Interpreter::checkTimeout()
560 {
561     if (!m_timedOut) {
562         return false;
563     }
564 
565     return handleTimeout();
566 }
567 
568 /**
569  * Interface to set enhanced Unicode support functions. By default
570  * the interpreter will use the standard C library functions.
571  *
572  * @internal
573  */
574 class KJS_EXPORT UnicodeSupport
575 {
576 public:
577     UnicodeSupport();
578 
579     typedef bool (*CharCategoryFunction)(int c);
580     static void setIdentStartChecker(CharCategoryFunction f);
581     static void setIdentPartChecker(CharCategoryFunction f);
582 
583     typedef int (*StringConversionFunction)(uint16_t *str, int strLength,
584                                             uint16_t *&destIfNeeded);
585     static void setToLowerFunction(StringConversionFunction f);
586     static void setToUpperFunction(StringConversionFunction f);
587 };
588 
589 /**
590  * Define a Qt-based version of the Unicode support functions.
591  *
592  * @internal
593  */
594 #define KJS_QT_UNICODE_IMPL \
595     namespace KJS { \
596     static bool qtIdentStart(int c) { if (c & 0xffff0000) return false; QChar::Category cat = QChar((unsigned short)c).category(); return cat == QChar::Letter_Uppercase || cat == QChar::Letter_Lowercase || cat == QChar::Letter_Titlecase || cat == QChar::Letter_Modifier || cat == QChar::Letter_Other || c == '$' || c == '_'; } \
597     static bool qtIdentPart(int c) { if (c & 0xffff0000) return false; QChar::Category cat = QChar((unsigned short)c).category(); return cat == QChar::Letter_Uppercase || cat == QChar::Letter_Lowercase || cat == QChar::Letter_Titlecase || cat == QChar::Letter_Modifier || cat == QChar::Letter_Other || cat == QChar::Mark_NonSpacing || cat == QChar::Mark_SpacingCombining || cat == QChar::Number_DecimalDigit || cat == QChar::Punctuation_Connector || c == '$' || c == '_'; } \
598     static int qtToLower(uint16_t* str, int strLength, uint16_t*& destIfNeeded) { \
599         destIfNeeded = 0; \
600         for (int i = 0; i < strLength; ++i) \
601             str[i] = QChar(str[i]).toLower().unicode(); \
602         return strLength; } \
603     static int qtToUpper(uint16_t* str, int strLength, uint16_t*& destIfNeeded) { \
604         destIfNeeded = 0; \
605         for (int i = 0; i < strLength; ++i) \
606             str[i] = QChar(str[i]).toUpper().unicode(); \
607         return strLength; } \
608     }
609 
610 /**
611  * Set the Qt-based version of the Unicode support functions.
612  *
613  * @internal
614  */
615 #define KJS_QT_UNICODE_SET \
616     { KJS::UnicodeSupport::setIdentStartChecker(KJS::qtIdentStart); \
617         KJS::UnicodeSupport::setIdentPartChecker(KJS::qtIdentPart); \
618         KJS::UnicodeSupport::setToLowerFunction(KJS::qtToLower); \
619         KJS::UnicodeSupport::setToUpperFunction(KJS::qtToUpper); }
620 
621 } // namespace
622 
623 #endif // _KJS_INTERPRETER_H_
624