File indexing completed on 2024-05-12 15:43:24
0001 /* 0002 * This file is part of the KDE libraries 0003 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 0004 * Copyright (C) 2001 Peter Kelly (pmk@post.com) 0005 * Copyright (C) 2003 Apple Computer, Inc. 0006 * 0007 * This library is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU Library General Public 0009 * License as published by the Free Software Foundation; either 0010 * version 2 of the License, or (at your option) any later version. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Library General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Library General Public License 0018 * along with this library; see the file COPYING.LIB. If not, write to 0019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 * 0022 */ 0023 0024 #ifndef _KJS_INTERPRETER_H_ 0025 #define _KJS_INTERPRETER_H_ 0026 0027 #include "ExecState.h" 0028 #include "protect.h" 0029 #include "value.h" 0030 #include "types.h" 0031 #include <wtf/HashMap.h> 0032 0033 namespace KJS 0034 { 0035 class Debugger; 0036 class SavedBuiltins; 0037 class TimeoutChecker; 0038 class Package; 0039 class ActivationImp; 0040 class JSGlobalObject; 0041 class StringImp; 0042 0043 #if USE(BINDINGS) 0044 namespace Bindings 0045 { 0046 class RootObject; 0047 } 0048 #endif 0049 0050 /** 0051 * Interpreter objects can be used to evaluate ECMAScript code. Each 0052 * interpreter has a global object which is used for the purposes of code 0053 * evaluation, and also provides access to built-in properties such as 0054 * " Object" and "Number". 0055 */ 0056 class KJS_EXPORT Interpreter 0057 { 0058 friend class Collector; 0059 friend class TimeoutChecker; 0060 public: 0061 /** 0062 * Creates a new interpreter. The supplied object will be used as the global 0063 * object for all scripts executed with this interpreter. During 0064 * construction, all the standard properties such as "Object" and "Number" 0065 * will be added to the global object. 0066 * 0067 * Note: You should not use the same global object for multiple 0068 * interpreters. 0069 * 0070 * This is due do the fact that the built-in properties are set in the 0071 * constructor, and if these objects have been modified from another 0072 * interpreter (e.g. a script modifying String.prototype), the changes will 0073 * be overridden. 0074 * 0075 * @param globalObject The object to use as the global object for this interpreter 0076 */ 0077 Interpreter(JSGlobalObject *globalObject); 0078 /** 0079 * Creates a new interpreter. A global object will be created and 0080 * initialized with the standard global properties. 0081 */ 0082 Interpreter(); 0083 0084 /** 0085 * Returns the object that is used as the global object during all script 0086 * execution performed by this interpreter 0087 */ 0088 JSGlobalObject *globalObject() const; 0089 void initGlobalObject(); 0090 0091 /** 0092 * Returns the execution state object which can be used to execute 0093 * scripts using this interpreter at a the "global" level, i.e. one 0094 * with a execution context that has the global object as the "this" 0095 * value, and who's scope chain contains only the global object. 0096 * 0097 * Note: this pointer remains constant for the life of the interpreter 0098 * and should not be manually deleted. 0099 * 0100 * @return The interpreter global execution state object 0101 */ 0102 virtual ExecState *globalExec(); 0103 0104 /** 0105 * Sets the package instance that will be used to resolve the 0106 * first level of identifiers of import statements. 0107 * 0108 * If no package is set which will make any "import" script 0109 * statement fail with an error. This is the default in e.g. a 0110 * Web browser where package imports should be disabled for 0111 * security reasons. 0112 */ 0113 void setGlobalPackage(Package *p); 0114 0115 /** 0116 * Returns the package that was installed to handle top level 0117 * package requests. Returns 0, the default, when no package was 0118 * set. 0119 * 0120 * @return The global package 0121 */ 0122 Package *globalPackage(); 0123 0124 /** 0125 * Parses the supplied ECMAScript code and checks for syntax errors. 0126 * 0127 * @param code The code to check 0128 * @param sourceURL A URL denoting the origin of the code 0129 * @param startingLineNumber The line offset within an embedding context 0130 * @return A normal completion if there were no syntax errors in the code, 0131 * otherwise a throw completion with the syntax error as its value. 0132 */ 0133 Completion checkSyntax(const UString &sourceURL, int startingLineNumber, const UString &code); 0134 Completion checkSyntax(const UString &sourceURL, int startingLineNumber, const UChar *code, int codeLength); 0135 0136 /** 0137 * Evaluates the supplied ECMAScript code. 0138 * 0139 * Since this method returns a Completion, you should check the type of 0140 * completion to detect an error or before attempting to access the returned 0141 * value. For example, if an error occurs during script execution and is not 0142 * caught by the script, the completion type will be Throw. 0143 * 0144 * If the supplied code is invalid, a SyntaxError will be thrown. 0145 * 0146 * @param sourceURL A URL denoting the origin of the code 0147 * @param startingLineNumber The line offset within an embedding context 0148 * @param code The code to evaluate 0149 * @param codeLength The length of the code to evaluate 0150 * @param thisV The value to pass in as the "this" value for the script 0151 * execution. This should either be jsNull() or an Object. 0152 * @return A completion object representing the result of the execution. 0153 */ 0154 Completion evaluate(const UString &sourceURL, int startingLineNumber, const UChar *code, int codeLength, JSValue *thisV = nullptr); 0155 Completion evaluate(const UString &sourceURL, int startingLineNumber, const UString &code, JSValue *thisV = nullptr); 0156 0157 /** 0158 * Pretty-prints the supplied ECMAScript code after checking it 0159 * for syntax errors. 0160 * 0161 * @param sourceURL A URL denoting the origin of the code 0162 * @param startingLineNumber The line offset within an embedding context 0163 * @param codeIn The code to check 0164 * @param codeIn Pointer to string that will contain reformatted code 0165 * upon successful parsing. 0166 * @return A normal completion if there were no syntax errors in the code, 0167 * otherwise a throw completion with the syntax error as its value. 0168 */ 0169 static bool normalizeCode(const UString &codeIn, UString *codeOut, 0170 int *errLine = nullptr, UString *errMsg = nullptr); 0171 0172 /** 0173 * Returns the builtin "Object" object. This is the object that was set 0174 * as a property of the global object during construction; if the property 0175 * is replaced by script code, this method will still return the original 0176 * object. 0177 * 0178 * @return The builtin "Object" object 0179 */ 0180 JSObject *builtinObject() const; 0181 0182 /** 0183 * Returns the builtin "Function" object. 0184 */ 0185 JSObject *builtinFunction() const; 0186 0187 /** 0188 * Returns the builtin "Array" object. 0189 */ 0190 JSObject *builtinArray() const; 0191 0192 /** 0193 * Returns the builtin "Boolean" object. 0194 */ 0195 JSObject *builtinBoolean() const; 0196 0197 /** 0198 * Returns the builtin "String" object. 0199 */ 0200 JSObject *builtinString() const; 0201 0202 /** 0203 * Returns the builtin "Number" object. 0204 */ 0205 JSObject *builtinNumber() const; 0206 0207 /** 0208 * Returns the builtin "Date" object. 0209 */ 0210 JSObject *builtinDate() const; 0211 0212 /** 0213 * Returns the builtin "RegExp" object. 0214 */ 0215 JSObject *builtinRegExp() const; 0216 0217 /** 0218 * Returns the builtin "Error" object. 0219 */ 0220 JSObject *builtinError() const; 0221 0222 /** 0223 * Returns the builtin "Object.prototype" object. 0224 */ 0225 JSObject *builtinObjectPrototype() const; 0226 0227 /** 0228 * Returns the builtin "Function.prototype" object. 0229 */ 0230 JSObject *builtinFunctionPrototype() const; 0231 0232 /** 0233 * Returns the builtin "Array.prototype" object. 0234 */ 0235 JSObject *builtinArrayPrototype() const; 0236 0237 /** 0238 * Returns the builtin "Boolean.prototype" object. 0239 */ 0240 JSObject *builtinBooleanPrototype() const; 0241 0242 /** 0243 * Returns the builtin "String.prototype" object. 0244 */ 0245 JSObject *builtinStringPrototype() const; 0246 0247 /** 0248 * Returns the builtin "Number.prototype" object. 0249 */ 0250 JSObject *builtinNumberPrototype() const; 0251 0252 /** 0253 * Returns the builtin "Date.prototype" object. 0254 */ 0255 JSObject *builtinDatePrototype() const; 0256 0257 /** 0258 * Returns the builtin "RegExp.prototype" object. 0259 */ 0260 JSObject *builtinRegExpPrototype() const; 0261 0262 /** 0263 * Returns the builtin "Error.prototype" object. 0264 */ 0265 JSObject *builtinErrorPrototype() const; 0266 0267 /** 0268 * The initial value of "Error" global property 0269 */ 0270 JSObject *builtinEvalError() const; 0271 JSObject *builtinRangeError() const; 0272 JSObject *builtinReferenceError() const; 0273 JSObject *builtinSyntaxError() const; 0274 JSObject *builtinTypeError() const; 0275 JSObject *builtinURIError() const; 0276 0277 JSObject *builtinEvalErrorPrototype() const; 0278 JSObject *builtinRangeErrorPrototype() const; 0279 JSObject *builtinReferenceErrorPrototype() const; 0280 JSObject *builtinSyntaxErrorPrototype() const; 0281 JSObject *builtinTypeErrorPrototype() const; 0282 JSObject *builtinURIErrorPrototype() const; 0283 0284 enum CompatMode { NativeMode, IECompat, NetscapeCompat }; 0285 /** 0286 * Call this to enable a compatibility mode with another browser. 0287 * (by default konqueror is in "native mode"). 0288 * Currently, in KJS, this only changes the behavior of Date::getYear() 0289 * which returns the full year under IE. 0290 */ 0291 void setCompatMode(CompatMode mode) 0292 { 0293 m_compatMode = mode; 0294 } 0295 CompatMode compatMode() const 0296 { 0297 return m_compatMode; 0298 } 0299 0300 /** 0301 * Run the garbage collection. Returns true when at least one object 0302 * was collected; false otherwise. 0303 */ 0304 static bool collect(); 0305 0306 /** 0307 * Called during the mark phase of the garbage collector. Subclasses 0308 * implementing custom mark methods must make sure to chain to this one. 0309 */ 0310 virtual void mark(bool currentThreadIsMainThread); 0311 0312 /** 0313 * This marks all GC heap resources stored as optimizations; 0314 * and which have their lifetime managed by the appropriate AST. 0315 * It's static since code can survive the interpreter by a bit. 0316 */ 0317 static void markSourceCachedObjects(); 0318 0319 /** 0320 * Provides a way to distinguish derived classes. 0321 * Only useful if you reimplement Interpreter and if different kind of 0322 * interpreters are created in the same process. 0323 * The base class returns 0, the ECMA-bindings interpreter returns 1. 0324 */ 0325 virtual int rtti() 0326 { 0327 return 0; 0328 } 0329 0330 static bool shouldPrintExceptions(); 0331 static void setShouldPrintExceptions(bool); 0332 0333 void saveBuiltins(SavedBuiltins &) const; 0334 void restoreBuiltins(const SavedBuiltins &); 0335 0336 /** 0337 * Determine if the it is 'safe' to execute code in the target interpreter from an 0338 * object that originated in this interpreter. This check is used to enforce WebCore 0339 * cross frame security rules. In particular, attempts to access 'bound' objects are 0340 * not allowed unless isSafeScript returns true. 0341 */ 0342 virtual bool isSafeScript(const Interpreter *) 0343 { 0344 return true; 0345 } 0346 0347 #if USE(BINDINGS) 0348 virtual void *createLanguageInstanceForValue(ExecState *, int language, JSObject *value, const Bindings::RootObject *origin, const Bindings::RootObject *current); 0349 #endif 0350 0351 // Chained list of interpreters (ring) 0352 static Interpreter *firstInterpreter() 0353 { 0354 return s_hook; 0355 } 0356 Interpreter *nextInterpreter() const 0357 { 0358 return next; 0359 } 0360 Interpreter *prevInterpreter() const 0361 { 0362 return prev; 0363 } 0364 0365 Debugger *debugger() const 0366 { 0367 return m_debugger; 0368 } 0369 void setDebugger(Debugger *d) 0370 { 0371 m_debugger = d; 0372 } 0373 0374 void setExecState(ExecState *e) 0375 { 0376 m_execState = e; 0377 } 0378 0379 // Note: may be 0, if in globalExec 0380 ExecState *execState() 0381 { 0382 return m_execState ? m_execState : &m_globalExec; 0383 } 0384 0385 void setTimeoutTime(unsigned timeoutTime) 0386 { 0387 m_timeoutTime = timeoutTime; 0388 } 0389 0390 void startTimeoutCheck(); 0391 void stopTimeoutCheck(); 0392 0393 // Resets the timer to full time if it's running 0394 void restartTimeoutCheck(); 0395 0396 void pauseTimeoutCheck(); 0397 void resumeTimeoutCheck(); 0398 0399 bool checkTimeout(); 0400 0401 void ref() 0402 { 0403 ++m_refCount; 0404 } 0405 void deref() 0406 { 0407 if (--m_refCount <= 0) { 0408 delete this; 0409 } 0410 } 0411 int refCount() const 0412 { 0413 return m_refCount; 0414 } 0415 0416 unsigned char *stackAlloc(size_t size) 0417 { 0418 unsigned char *nextPtr = stackPtr + size; 0419 if (nextPtr <= stackEnd) { 0420 unsigned char *toRet = stackPtr; 0421 stackPtr = nextPtr; 0422 return toRet; 0423 } 0424 return extendStack(size); 0425 } 0426 0427 void stackFree(size_t size) 0428 { 0429 stackPtr -= size; // ### shrink it? 0430 } 0431 0432 ActivationImp *getRecycledActivation() 0433 { 0434 ActivationImp *out = nullptr; 0435 if (m_numCachedActivations) { 0436 m_numCachedActivations--; 0437 out = m_cachedActivations[m_numCachedActivations]; 0438 } 0439 return out; 0440 } 0441 0442 void recycleActivation(ActivationImp *act); 0443 0444 // Global string table management. This is used from StringNode 0445 // to cache StringImp's for string literals. We keep refcounts 0446 // to permit multiple ones to use the same value. 0447 static StringImp *internString(const UString &literal); 0448 static void releaseInternedString(const UString &literal); 0449 0450 typedef WTF::HashMap<UString::Rep *, std::pair<KJS::StringImp *, int> > InternedStringsTable; 0451 private: 0452 static void markInternedStringsTable(); 0453 0454 // This creates a table if needed 0455 static void initInternedStringsTable(); 0456 0457 static InternedStringsTable *s_internedStrings; 0458 0459 protected: 0460 virtual ~Interpreter(); // only deref should delete us 0461 virtual bool shouldInterruptScript() const 0462 { 0463 return true; 0464 } 0465 0466 long m_timeoutTime; 0467 0468 private: 0469 bool handleTimeout(); 0470 void init(); 0471 void printException(const Completion &c, const UString &sourceURL); 0472 0473 /** 0474 * This constructor is not implemented, in order to prevent 0475 * copy-construction of Interpreter objects. You should always pass around 0476 * pointers to an interpreter instance instead. 0477 */ 0478 Interpreter(const Interpreter &); 0479 0480 /** 0481 * This operator is not implemented, in order to prevent assignment of 0482 * Interpreter objects. You should always pass around pointers to an 0483 * interpreter instance instead. 0484 */ 0485 Interpreter operator=(const Interpreter &); 0486 0487 int m_refCount; 0488 0489 JSGlobalObject *m_globalObject; 0490 GlobalExecState m_globalExec; 0491 Package *globPkg; 0492 0493 // Execution stack stuff for this interpreter. 0494 unsigned char *stackBase; // lowest address in the array 0495 unsigned char *stackPtr; // current top/next to allocate 0496 unsigned char *stackEnd; // last address in the stack 0497 unsigned char *extendStack(size_t needed); 0498 0499 // A list of cached activations 0500 enum {MaxCachedActivations = 32}; 0501 0502 ActivationImp *m_cachedActivations[MaxCachedActivations]; 0503 int m_numCachedActivations; 0504 0505 // Chained list of interpreters (ring) - for collector 0506 static Interpreter *s_hook; 0507 Interpreter *next, *prev; 0508 0509 int m_recursion; 0510 0511 Debugger *m_debugger; 0512 ExecState *m_execState; 0513 CompatMode m_compatMode; 0514 0515 TimeoutChecker *m_timeoutChecker; 0516 bool m_timedOut; 0517 0518 unsigned m_startTimeoutCheckCount; 0519 unsigned m_pauseTimeoutCheckCount; 0520 0521 // Helper for setting constructors, making sure their function names are OK 0522 void putNamedConstructor(const char *name, JSObject *value); 0523 0524 ProtectedPtr<JSObject> m_Object; 0525 ProtectedPtr<JSObject> m_Function; 0526 ProtectedPtr<JSObject> m_Array; 0527 ProtectedPtr<JSObject> m_Boolean; 0528 ProtectedPtr<JSObject> m_String; 0529 ProtectedPtr<JSObject> m_Number; 0530 ProtectedPtr<JSObject> m_Date; 0531 ProtectedPtr<JSObject> m_RegExp; 0532 ProtectedPtr<JSObject> m_Error; 0533 0534 ProtectedPtr<JSObject> m_ObjectPrototype; 0535 ProtectedPtr<JSObject> m_FunctionPrototype; 0536 ProtectedPtr<JSObject> m_ArrayPrototype; 0537 ProtectedPtr<JSObject> m_BooleanPrototype; 0538 ProtectedPtr<JSObject> m_StringPrototype; 0539 ProtectedPtr<JSObject> m_NumberPrototype; 0540 ProtectedPtr<JSObject> m_DatePrototype; 0541 ProtectedPtr<JSObject> m_RegExpPrototype; 0542 ProtectedPtr<JSObject> m_ErrorPrototype; 0543 0544 ProtectedPtr<JSObject> m_EvalError; 0545 ProtectedPtr<JSObject> m_RangeError; 0546 ProtectedPtr<JSObject> m_ReferenceError; 0547 ProtectedPtr<JSObject> m_SyntaxError; 0548 ProtectedPtr<JSObject> m_TypeError; 0549 ProtectedPtr<JSObject> m_UriError; 0550 0551 ProtectedPtr<JSObject> m_EvalErrorPrototype; 0552 ProtectedPtr<JSObject> m_RangeErrorPrototype; 0553 ProtectedPtr<JSObject> m_ReferenceErrorPrototype; 0554 ProtectedPtr<JSObject> m_SyntaxErrorPrototype; 0555 ProtectedPtr<JSObject> m_TypeErrorPrototype; 0556 ProtectedPtr<JSObject> m_UriErrorPrototype; 0557 }; 0558 0559 inline bool Interpreter::checkTimeout() 0560 { 0561 if (!m_timedOut) { 0562 return false; 0563 } 0564 0565 return handleTimeout(); 0566 } 0567 0568 /** 0569 * Interface to set enhanced Unicode support functions. By default 0570 * the interpreter will use the standard C library functions. 0571 * 0572 * @internal 0573 */ 0574 class KJS_EXPORT UnicodeSupport 0575 { 0576 public: 0577 UnicodeSupport(); 0578 0579 typedef bool (*CharCategoryFunction)(int c); 0580 static void setIdentStartChecker(CharCategoryFunction f); 0581 static void setIdentPartChecker(CharCategoryFunction f); 0582 0583 typedef int (*StringConversionFunction)(uint16_t *str, int strLength, 0584 uint16_t *&destIfNeeded); 0585 static void setToLowerFunction(StringConversionFunction f); 0586 static void setToUpperFunction(StringConversionFunction f); 0587 }; 0588 0589 /** 0590 * Define a Qt-based version of the Unicode support functions. 0591 * 0592 * @internal 0593 */ 0594 #define KJS_QT_UNICODE_IMPL \ 0595 namespace KJS { \ 0596 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 == '_'; } \ 0597 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 == '_'; } \ 0598 static int qtToLower(uint16_t* str, int strLength, uint16_t*& destIfNeeded) { \ 0599 destIfNeeded = 0; \ 0600 for (int i = 0; i < strLength; ++i) \ 0601 str[i] = QChar(str[i]).toLower().unicode(); \ 0602 return strLength; } \ 0603 static int qtToUpper(uint16_t* str, int strLength, uint16_t*& destIfNeeded) { \ 0604 destIfNeeded = 0; \ 0605 for (int i = 0; i < strLength; ++i) \ 0606 str[i] = QChar(str[i]).toUpper().unicode(); \ 0607 return strLength; } \ 0608 } 0609 0610 /** 0611 * Set the Qt-based version of the Unicode support functions. 0612 * 0613 * @internal 0614 */ 0615 #define KJS_QT_UNICODE_SET \ 0616 { KJS::UnicodeSupport::setIdentStartChecker(KJS::qtIdentStart); \ 0617 KJS::UnicodeSupport::setIdentPartChecker(KJS::qtIdentPart); \ 0618 KJS::UnicodeSupport::setToLowerFunction(KJS::qtToLower); \ 0619 KJS::UnicodeSupport::setToUpperFunction(KJS::qtToUpper); } 0620 0621 } // namespace 0622 0623 #endif // _KJS_INTERPRETER_H_