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