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_