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