LCOV - code coverage report
Current view: directory - js/src - jsinterp.h (source / functions) Found Hit Coverage
Test: app.info Lines: 25 25 100.0 %
Date: 2012-06-02 Functions: 8 8 100.0 %

       1                 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=4 sw=4 et tw=78:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla Communicator client code, released
      18                 :  * March 31, 1998.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  * Netscape Communications Corporation.
      22                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #ifndef jsinterp_h___
      42                 : #define jsinterp_h___
      43                 : /*
      44                 :  * JS interpreter interface.
      45                 :  */
      46                 : #include "jsprvtd.h"
      47                 : #include "jspubtd.h"
      48                 : #include "jsopcode.h"
      49                 : 
      50                 : #include "vm/Stack.h"
      51                 : 
      52                 : namespace js {
      53                 : 
      54                 : /*
      55                 :  * Refresh and return fp->scopeChain.  It may be stale if block scopes are
      56                 :  * active but not yet reflected by objects in the scope chain.  If a block
      57                 :  * scope contains a with, eval, XML filtering predicate, or similar such
      58                 :  * dynamically scoped construct, then compile-time block scope at fp->blocks
      59                 :  * must reflect at runtime.
      60                 :  */
      61                 : 
      62                 : extern JSObject *
      63                 : GetScopeChain(JSContext *cx);
      64                 : 
      65                 : extern JSObject *
      66                 : GetScopeChain(JSContext *cx, StackFrame *fp);
      67                 : 
      68                 : /*
      69                 :  * ScriptPrologue/ScriptEpilogue must be called in pairs. ScriptPrologue
      70                 :  * must be called before the script executes. ScriptEpilogue must be called
      71                 :  * after the script returns or exits via exception.
      72                 :  */
      73                 : 
      74                 : inline bool
      75                 : ScriptPrologue(JSContext *cx, StackFrame *fp, JSScript *script);
      76                 : 
      77                 : inline bool
      78                 : ScriptEpilogue(JSContext *cx, StackFrame *fp, bool ok);
      79                 : 
      80                 : /*
      81                 :  * It is not valid to call ScriptPrologue when a generator is resumed or to
      82                 :  * call ScriptEpilogue when a generator yields. However, the debugger still
      83                 :  * needs LIFO notification of generator start/stop. This pair of functions does
      84                 :  * the right thing based on the state of 'fp'.
      85                 :  */
      86                 : 
      87                 : inline bool
      88                 : ScriptPrologueOrGeneratorResume(JSContext *cx, StackFrame *fp);
      89                 : 
      90                 : inline bool
      91                 : ScriptEpilogueOrGeneratorYield(JSContext *cx, StackFrame *fp, bool ok);
      92                 : 
      93                 : /* Implemented in jsdbgapi: */
      94                 : 
      95                 : /*
      96                 :  * Announce to the debugger that the thread has entered a new JavaScript frame,
      97                 :  * |fp|. Call whatever hooks have been registered to observe new frames, and
      98                 :  * return a JSTrapStatus code indication how execution should proceed:
      99                 :  *
     100                 :  * - JSTRAP_CONTINUE: Continue execution normally.
     101                 :  * 
     102                 :  * - JSTRAP_THROW: Throw an exception. ScriptDebugPrologue has set |cx|'s
     103                 :  *   pending exception to the value to be thrown.
     104                 :  *
     105                 :  * - JSTRAP_ERROR: Terminate execution (as is done when a script is terminated
     106                 :  *   for running too long). ScriptDebugPrologue has cleared |cx|'s pending
     107                 :  *   exception.
     108                 :  *
     109                 :  * - JSTRAP_RETURN: Return from the new frame immediately. ScriptDebugPrologue
     110                 :  *   has set |cx->fp()|'s return value appropriately.
     111                 :  */
     112                 : extern JSTrapStatus
     113                 : ScriptDebugPrologue(JSContext *cx, StackFrame *fp);
     114                 : 
     115                 : /*
     116                 :  * Announce to the debugger that the thread has exited a JavaScript frame, |fp|.
     117                 :  * If |ok| is true, the frame is returning normally; if |ok| is false, the frame
     118                 :  * is throwing an exception or terminating. 
     119                 :  *
     120                 :  * Call whatever hooks have been registered to observe frame exits. Change cx's
     121                 :  * current exception and |fp|'s return value to reflect the changes in behavior
     122                 :  * the hooks request, if any. Return the new error/success value.
     123                 :  *
     124                 :  * This function may be called twice for the same outgoing frame; only the
     125                 :  * first call has any effect. (Permitting double calls simplifies some
     126                 :  * cases where an onPop handler's resumption value changes a return to a
     127                 :  * throw, or vice versa: we can redirect to a complete copy of the
     128                 :  * alternative path, containing its own call to ScriptDebugEpilogue.)
     129                 :  */
     130                 : extern bool
     131                 : ScriptDebugEpilogue(JSContext *cx, StackFrame *fp, bool ok);
     132                 : 
     133                 : /*
     134                 :  * For a given |call|, convert null/undefined |this| into the global object for
     135                 :  * the callee and replace other primitives with boxed versions. This assumes
     136                 :  * that call.callee() is not strict mode code. This is the special/slow case of
     137                 :  * ComputeThis.
     138                 :  */
     139                 : extern bool
     140                 : BoxNonStrictThis(JSContext *cx, const CallReceiver &call);
     141                 : 
     142                 : /*
     143                 :  * Ensure that fp->thisValue() is the correct value of |this| for the scripted
     144                 :  * call represented by |fp|. ComputeThis is necessary because fp->thisValue()
     145                 :  * may be set to 'undefined' when 'this' should really be the global object (as
     146                 :  * an optimization to avoid global-this computation).
     147                 :  */
     148                 : inline bool
     149                 : ComputeThis(JSContext *cx, StackFrame *fp);
     150                 : 
     151                 : enum MaybeConstruct {
     152                 :     NO_CONSTRUCT = INITIAL_NONE,
     153                 :     CONSTRUCT = INITIAL_CONSTRUCT
     154                 : };
     155                 : 
     156                 : /*
     157                 :  * InvokeKernel assumes that the given args have been pushed on the top of the
     158                 :  * VM stack. Additionally, if 'args' is contained in a CallArgsList, that they
     159                 :  * have already been marked 'active'.
     160                 :  */
     161                 : extern bool
     162                 : InvokeKernel(JSContext *cx, CallArgs args, MaybeConstruct construct = NO_CONSTRUCT);
     163                 : 
     164                 : /*
     165                 :  * Invoke assumes that 'args' has been pushed (via ContextStack::pushInvokeArgs)
     166                 :  * and is currently at the top of the VM stack.
     167                 :  */
     168                 : inline bool
     169         8710107 : Invoke(JSContext *cx, InvokeArgsGuard &args, MaybeConstruct construct = NO_CONSTRUCT)
     170                 : {
     171         8710107 :     args.setActive();
     172         8710107 :     bool ok = InvokeKernel(cx, args, construct);
     173         8710107 :     args.setInactive();
     174         8710107 :     return ok;
     175                 : }
     176                 : 
     177                 : /*
     178                 :  * This Invoke overload places the least requirements on the caller: it may be
     179                 :  * called at any time and it takes care of copying the given callee, this, and
     180                 :  * arguments onto the stack.
     181                 :  */
     182                 : extern bool
     183                 : Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, Value *argv,
     184                 :        Value *rval);
     185                 : 
     186                 : /*
     187                 :  * This helper takes care of the infinite-recursion check necessary for
     188                 :  * getter/setter calls.
     189                 :  */
     190                 : extern bool
     191                 : InvokeGetterOrSetter(JSContext *cx, JSObject *obj, const Value &fval, unsigned argc, Value *argv,
     192                 :                      Value *rval);
     193                 : 
     194                 : /*
     195                 :  * InvokeConstructor* implement a function call from a constructor context
     196                 :  * (e.g. 'new') handling the the creation of the new 'this' object.
     197                 :  */
     198                 : extern bool
     199                 : InvokeConstructorKernel(JSContext *cx, const CallArgs &args);
     200                 : 
     201                 : /* See the InvokeArgsGuard overload of Invoke. */
     202                 : inline bool
     203            8237 : InvokeConstructor(JSContext *cx, InvokeArgsGuard &args)
     204                 : {
     205            8237 :     args.setActive();
     206            8237 :     bool ok = InvokeConstructorKernel(cx, ImplicitCast<CallArgs>(args));
     207            8237 :     args.setInactive();
     208            8237 :     return ok;
     209                 : }
     210                 : 
     211                 : /* See the fval overload of Invoke. */
     212                 : extern bool
     213                 : InvokeConstructor(JSContext *cx, const Value &fval, unsigned argc, Value *argv, Value *rval);
     214                 : 
     215                 : /*
     216                 :  * Executes a script with the given scopeChain/this. The 'type' indicates
     217                 :  * whether this is eval code or global code. To support debugging, the
     218                 :  * evalFrame parameter can point to an arbitrary frame in the context's call
     219                 :  * stack to simulate executing an eval in that frame.
     220                 :  */
     221                 : extern bool
     222                 : ExecuteKernel(JSContext *cx, JSScript *script, JSObject &scopeChain, const Value &thisv,
     223                 :               ExecuteType type, StackFrame *evalInFrame, Value *result);
     224                 : 
     225                 : /* Execute a script with the given scopeChain as global code. */
     226                 : extern bool
     227                 : Execute(JSContext *cx, JSScript *script, JSObject &scopeChain, Value *rval);
     228                 : 
     229                 : /* Flags to toggle js::Interpret() execution. */
     230                 : enum InterpMode
     231                 : {
     232                 :     JSINTERP_NORMAL    = 0, /* interpreter is running normally */
     233                 :     JSINTERP_REJOIN    = 1, /* as normal, but the frame has already started */
     234                 :     JSINTERP_SKIP_TRAP = 2  /* as REJOIN, but skip trap at first opcode */
     235                 : };
     236                 : 
     237                 : /*
     238                 :  * Execute the caller-initialized frame for a user-defined script or function
     239                 :  * pointed to by cx->fp until completion or error.
     240                 :  */
     241                 : extern JS_NEVER_INLINE bool
     242                 : Interpret(JSContext *cx, StackFrame *stopFp, InterpMode mode = JSINTERP_NORMAL);
     243                 : 
     244                 : extern bool
     245                 : RunScript(JSContext *cx, JSScript *script, StackFrame *fp);
     246                 : 
     247                 : extern bool
     248                 : StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *equal);
     249                 : 
     250                 : extern bool
     251                 : LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *equal);
     252                 : 
     253                 : /* === except that NaN is the same as NaN and -0 is not the same as +0. */
     254                 : extern bool
     255                 : SameValue(JSContext *cx, const Value &v1, const Value &v2, bool *same);
     256                 : 
     257                 : extern JSType
     258                 : TypeOfValue(JSContext *cx, const Value &v);
     259                 : 
     260                 : extern JSBool
     261                 : HasInstance(JSContext *cx, JSObject *obj, const js::Value *v, JSBool *bp);
     262                 : 
     263                 : extern bool
     264                 : ValueToId(JSContext *cx, const Value &v, jsid *idp);
     265                 : 
     266                 : /*
     267                 :  * @param closureLevel      The static level of the closure that the cookie
     268                 :  *                          pertains to.
     269                 :  * @param cookie            Level amount is a "skip" (delta) value from the
     270                 :  *                          closure level.
     271                 :  * @return  The value of the upvar.
     272                 :  */
     273                 : extern const Value &
     274                 : GetUpvar(JSContext *cx, unsigned level, UpvarCookie cookie);
     275                 : 
     276                 : /* Search the call stack for the nearest frame with static level targetLevel. */
     277                 : extern StackFrame *
     278                 : FindUpvarFrame(JSContext *cx, unsigned targetLevel);
     279                 : 
     280                 : /*
     281                 :  * A linked list of the |FrameRegs regs;| variables belonging to all
     282                 :  * js::Interpret C++ frames on this thread's stack.
     283                 :  *
     284                 :  * Note that this is *not* a list of all JS frames running under the
     285                 :  * interpreter; that would include inlined frames, whose FrameRegs are
     286                 :  * saved in various pieces in various places. Rather, this lists each
     287                 :  * js::Interpret call's live 'regs'; when control returns to that call, it
     288                 :  * will resume execution with this 'regs' instance.
     289                 :  *
     290                 :  * When Debugger puts a script in single-step mode, all js::Interpret
     291                 :  * invocations that might be presently running that script must have
     292                 :  * interrupts enabled. It's not practical to simply check
     293                 :  * script->stepModeEnabled() at each point some callee could have changed
     294                 :  * it, because there are so many places js::Interpret could possibly cause
     295                 :  * JavaScript to run: each place an object might be coerced to a primitive
     296                 :  * or a number, for example. So instead, we simply expose a list of the
     297                 :  * 'regs' those frames are using, and let Debugger tweak the affected
     298                 :  * js::Interpret frames when an onStep handler is established.
     299                 :  *
     300                 :  * Elements of this list are allocated within the js::Interpret stack
     301                 :  * frames themselves; the list is headed by this thread's js::ThreadData.
     302                 :  */
     303                 : class InterpreterFrames {
     304                 :   public:
     305         1977915 :     class InterruptEnablerBase {
     306                 :       public:
     307                 :         virtual void enableInterrupts() const = 0;
     308                 :     };
     309                 : 
     310                 :     InterpreterFrames(JSContext *cx, FrameRegs *regs, const InterruptEnablerBase &enabler);
     311                 :     ~InterpreterFrames();
     312                 : 
     313                 :     /* If this js::Interpret frame is running |script|, enable interrupts. */
     314                 :     inline void enableInterruptsIfRunning(JSScript *script);
     315                 : 
     316                 :     InterpreterFrames *older;
     317                 : 
     318                 :   private:
     319                 :     JSContext *context;
     320                 :     FrameRegs *regs;
     321                 :     const InterruptEnablerBase &enabler;
     322                 : };
     323                 : 
     324                 : /*
     325                 :  * Unwind block and scope chains to match the given depth. The function sets
     326                 :  * fp->sp on return to stackDepth.
     327                 :  */
     328                 : extern void
     329                 : UnwindScope(JSContext *cx, uint32_t stackDepth);
     330                 : 
     331                 : /*
     332                 :  * Unwind for an uncatchable exception. This means not running finalizers, etc;
     333                 :  * just preserving the basic engine stack invariants.
     334                 :  */
     335                 : extern void
     336                 : UnwindForUncatchableException(JSContext *cx, const FrameRegs &regs);
     337                 : 
     338                 : extern bool
     339                 : OnUnknownMethod(JSContext *cx, JSObject *obj, Value idval, Value *vp);
     340                 : 
     341                 : extern bool
     342                 : IsActiveWithOrBlock(JSContext *cx, JSObject &obj, uint32_t stackDepth);
     343                 : 
     344                 : class TryNoteIter
     345                 : {
     346                 :     const FrameRegs &regs;
     347                 :     JSScript *script;
     348                 :     uint32_t pcOffset;
     349                 :     JSTryNote *tn, *tnEnd;
     350                 :     void settle();
     351                 :   public:
     352                 :     TryNoteIter(const FrameRegs &regs);
     353                 :     bool done() const;
     354                 :     void operator++();
     355           56411 :     JSTryNote *operator*() const { return tn; }
     356                 : };
     357                 : 
     358                 : /************************************************************************/
     359                 : 
     360                 : /*
     361                 :  * To really poison a set of values, using 'magic' or 'undefined' isn't good
     362                 :  * enough since often these will just be ignored by buggy code (see bug 629974)
     363                 :  * in debug builds and crash in release builds. Instead, we use a safe-for-crash
     364                 :  * pointer.
     365                 :  */
     366                 : static JS_ALWAYS_INLINE void
     367         7072811 : Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end)
     368                 : {
     369                 : #ifdef DEBUG
     370       127401722 :     for (Value *v = beg; v != end; ++v)
     371       120328911 :         v->setObject(*reinterpret_cast<JSObject *>(0x42));
     372                 : #endif
     373         7072811 : }
     374                 : 
     375                 : static JS_ALWAYS_INLINE void
     376         7072811 : Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len)
     377                 : {
     378                 : #ifdef DEBUG
     379         7072811 :     Debug_SetValueRangeToCrashOnTouch(vec, vec + len);
     380                 : #endif
     381         7072811 : }
     382                 : 
     383                 : static JS_ALWAYS_INLINE void
     384                 : Debug_SetValueRangeToCrashOnTouch(HeapValue *vec, size_t len)
     385                 : {
     386                 : #ifdef DEBUG
     387                 :     Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
     388                 : #endif
     389                 : }
     390                 : 
     391                 : static JS_ALWAYS_INLINE void
     392         6364621 : Debug_SetSlotRangeToCrashOnTouch(HeapSlot *vec, size_t len)
     393                 : {
     394                 : #ifdef DEBUG
     395         6364621 :     Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
     396                 : #endif
     397         6364621 : }
     398                 : 
     399                 : static JS_ALWAYS_INLINE void
     400            5084 : Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end)
     401                 : {
     402                 : #ifdef DEBUG
     403            5084 :     Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin);
     404                 : #endif
     405            5084 : }
     406                 : 
     407                 : }  /* namespace js */
     408                 : 
     409                 : #endif /* jsinterp_h___ */

Generated by: LCOV version 1.7