KJS

interpreter.h
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (C) 1999-2001 Harri Porten ([email protected])
4  * Copyright (C) 2001 Peter Kelly ([email protected])
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  */
291  void setCompatMode(CompatMode mode)
292  {
293  m_compatMode = mode;
294  }
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  */
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  */
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)
352  static Interpreter *firstInterpreter()
353  {
354  return s_hook;
355  }
356  Interpreter *nextInterpreter() const
357  {
358  return next;
359  }
360  Interpreter *prevInterpreter() const
361  {
362  return prev;
363  }
364 
365  Debugger *debugger() const
366  {
367  return m_debugger;
368  }
369  void setDebugger(Debugger *d)
370  {
371  m_debugger = d;
372  }
373 
374  void setExecState(ExecState *e)
375  {
376  m_execState = e;
377  }
378 
379  // Note: may be 0, if in globalExec
380  ExecState *execState()
381  {
382  return m_execState ? m_execState : &m_globalExec;
383  }
384 
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 
401  void ref()
402  {
403  ++m_refCount;
404  }
405  void deref()
406  {
407  if (--m_refCount <= 0) {
408  delete this;
409  }
410  }
411  int refCount() const
412  {
413  return m_refCount;
414  }
415 
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 
427  void stackFree(size_t size)
428  {
429  stackPtr -= size; // ### shrink it?
430  }
431 
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
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 
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_
JSValue is the base type for all primitives (Undefined, Null, Boolean, String, Number) and objects in...
Definition: value.h:58
void ref()
void deref()
void setCompatMode(CompatMode mode)
Call this to enable a compatibility mode with another browser.
Definition: interpreter.h:291
Completion objects are used to convey the return status and value from functions.
Definition: completion.h:52
Garbage collector.
Definition: collector.h:42
Represents the current state of script execution.
Definition: ExecState.h:53
Interpreter objects can be used to evaluate ECMAScript code.
Definition: interpreter.h:56
Unicode character.
Definition: ustring.h:70
void init(KXmlGuiWindow *window, KgDifficulty *difficulty=nullptr)
virtual int rtti()
Provides a way to distinguish derived classes.
Definition: interpreter.h:325
virtual bool isSafeScript(const Interpreter *)
Determine if the it is 'safe' to execute code in the target interpreter from an object that originate...
Definition: interpreter.h:342
QAction * next(const QObject *recvr, const char *slot, QObject *parent)
Unicode string class.
Definition: ustring.h:153
Interface to set enhanced Unicode support functions.
Definition: interpreter.h:574
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sat Sep 30 2023 03:56:09 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.