/[jscoverage]/trunk/js/jsfun.cpp
ViewVC logotype

Diff of /trunk/js/jsfun.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 399 by siliconforks, Tue Dec 9 03:37:47 2008 UTC revision 460 by siliconforks, Sat Sep 26 23:15:22 2009 UTC
# Line 365  Line 365 
365      return JS_TRUE;      return JS_TRUE;
366  }  }
367    
368    static JS_REQUIRES_STACK JSObject *
369    WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunction *fun)
370    {
371        JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
372        JS_ASSERT(fun->optimizedClosure());
373        JS_ASSERT(!fun->u.i.wrapper);
374    
375        /*
376         * We do not attempt to reify Call and Block objects on demand for outer
377         * scopes. This could be done (see the "v8" patch in bug 494235) but it is
378         * fragile in the face of ongoing compile-time optimization. Instead, the
379         * _DBG* opcodes used by wrappers created here must cope with unresolved
380         * upvars and throw them as reference errors. Caveat debuggers!
381         */
382        JSObject *scopeChain = js_GetScopeChain(cx, fp);
383        if (!scopeChain)
384            return NULL;
385    
386        JSObject *wfunobj = js_NewObjectWithGivenProto(cx, &js_FunctionClass,
387                                                       funobj, scopeChain, 0);
388        if (!wfunobj)
389            return NULL;
390        JSAutoTempValueRooter tvr(cx, wfunobj);
391    
392        JSFunction *wfun = (JSFunction *) wfunobj;
393        wfunobj->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(wfun);
394        wfun->nargs = 0;
395        wfun->flags = fun->flags | JSFUN_HEAVYWEIGHT;
396        wfun->u.i.nvars = 0;
397        wfun->u.i.nupvars = 0;
398        wfun->u.i.skipmin = fun->u.i.skipmin;
399        wfun->u.i.wrapper = true;
400        wfun->u.i.script = NULL;
401        wfun->u.i.names.taggedAtom = NULL;
402        wfun->atom = fun->atom;
403    
404        if (fun->hasLocalNames()) {
405            void *mark = JS_ARENA_MARK(&cx->tempPool);
406            jsuword *names = js_GetLocalNameArray(cx, fun, &cx->tempPool);
407            if (!names)
408                return NULL;
409    
410            JSBool ok = true;
411            for (uintN i = 0, n = fun->countLocalNames(); i != n; i++) {
412                jsuword name = names[i];
413                JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(name);
414                JSLocalKind localKind = (i < fun->nargs)
415                                        ? JSLOCAL_ARG
416                                        : (i < fun->countArgsAndVars())
417                                        ? (JS_LOCAL_NAME_IS_CONST(name)
418                                           ? JSLOCAL_CONST
419                                           : JSLOCAL_VAR)
420                                        : JSLOCAL_UPVAR;
421    
422                ok = js_AddLocal(cx, wfun, atom, localKind);
423                if (!ok)
424                    break;
425            }
426    
427            JS_ARENA_RELEASE(&cx->tempPool, mark);
428            if (!ok)
429                return NULL;
430            JS_ASSERT(wfun->nargs == fun->nargs);
431            JS_ASSERT(wfun->u.i.nvars == fun->u.i.nvars);
432            JS_ASSERT(wfun->u.i.nupvars == fun->u.i.nupvars);
433            js_FreezeLocalNames(cx, wfun);
434        }
435    
436        JSScript *script = fun->u.i.script;
437        jssrcnote *snbase = SCRIPT_NOTES(script);
438        jssrcnote *sn = snbase;
439        while (!SN_IS_TERMINATOR(sn))
440            sn = SN_NEXT(sn);
441        uintN nsrcnotes = (sn - snbase) + 1;
442    
443        /* NB: GC must not occur before wscript is homed in wfun->u.i.script. */
444        JSScript *wscript = js_NewScript(cx, script->length, nsrcnotes,
445                                         script->atomMap.length,
446                                         (script->objectsOffset != 0)
447                                         ? JS_SCRIPT_OBJECTS(script)->length
448                                         : 0,
449                                         fun->u.i.nupvars,
450                                         (script->regexpsOffset != 0)
451                                         ? JS_SCRIPT_REGEXPS(script)->length
452                                         : 0,
453                                         (script->trynotesOffset != 0)
454                                         ? JS_SCRIPT_TRYNOTES(script)->length
455                                         : 0);
456        if (!wscript)
457            return NULL;
458    
459        memcpy(wscript->code, script->code, script->length);
460        wscript->main = wscript->code + (script->main - script->code);
461    
462        memcpy(SCRIPT_NOTES(wscript), snbase, nsrcnotes);
463        memcpy(wscript->atomMap.vector, script->atomMap.vector,
464               wscript->atomMap.length * sizeof(JSAtom *));
465        if (script->objectsOffset != 0) {
466            memcpy(JS_SCRIPT_OBJECTS(wscript)->vector, JS_SCRIPT_OBJECTS(script)->vector,
467                   JS_SCRIPT_OBJECTS(wscript)->length * sizeof(JSObject *));
468        }
469        if (script->regexpsOffset != 0) {
470            memcpy(JS_SCRIPT_REGEXPS(wscript)->vector, JS_SCRIPT_REGEXPS(script)->vector,
471                   JS_SCRIPT_REGEXPS(wscript)->length * sizeof(JSObject *));
472        }
473        if (script->trynotesOffset != 0) {
474            memcpy(JS_SCRIPT_TRYNOTES(wscript)->vector, JS_SCRIPT_TRYNOTES(script)->vector,
475                   JS_SCRIPT_TRYNOTES(wscript)->length * sizeof(JSTryNote));
476        }
477    
478        if (wfun->u.i.nupvars != 0) {
479            JS_ASSERT(wfun->u.i.nupvars == JS_SCRIPT_UPVARS(wscript)->length);
480            memcpy(JS_SCRIPT_UPVARS(wscript)->vector, JS_SCRIPT_UPVARS(script)->vector,
481                   wfun->u.i.nupvars * sizeof(uint32));
482        }
483    
484        jsbytecode *pc = wscript->code;
485        while (*pc != JSOP_STOP) {
486            /* XYZZYbe should copy JSOP_TRAP? */
487            JSOp op = js_GetOpcode(cx, wscript, pc);
488            const JSCodeSpec *cs = &js_CodeSpec[op];
489            ptrdiff_t oplen = cs->length;
490            if (oplen < 0)
491                oplen = js_GetVariableBytecodeLength(pc);
492    
493            /*
494             * Rewrite JSOP_{GET,CALL}DSLOT as JSOP_{GET,CALL}UPVAR_DBG for the
495             * case where fun is an escaping flat closure. This works because the
496             * UPVAR and DSLOT ops by design have the same format: an upvar index
497             * immediate operand.
498             */
499            switch (op) {
500              case JSOP_GETUPVAR:       *pc = JSOP_GETUPVAR_DBG; break;
501              case JSOP_CALLUPVAR:      *pc = JSOP_CALLUPVAR_DBG; break;
502              case JSOP_GETDSLOT:       *pc = JSOP_GETUPVAR_DBG; break;
503              case JSOP_CALLDSLOT:      *pc = JSOP_CALLUPVAR_DBG; break;
504              case JSOP_DEFFUN_FC:      *pc = JSOP_DEFFUN_DBGFC; break;
505              case JSOP_DEFLOCALFUN_FC: *pc = JSOP_DEFLOCALFUN_DBGFC; break;
506              case JSOP_LAMBDA_FC:      *pc = JSOP_LAMBDA_DBGFC; break;
507              default:;
508            }
509            pc += oplen;
510        }
511    
512        /*
513         * Fill in the rest of wscript. This means if you add members to JSScript
514         * you must update this code. FIXME: factor into JSScript::clone method.
515         */
516        wscript->flags = script->flags;
517        wscript->version = script->version;
518        wscript->nfixed = script->nfixed;
519        wscript->filename = script->filename;
520        wscript->lineno = script->lineno;
521        wscript->nslots = script->nslots;
522        wscript->staticLevel = script->staticLevel;
523        wscript->principals = script->principals;
524        if (wscript->principals)
525            JSPRINCIPALS_HOLD(cx, wscript->principals);
526    #ifdef CHECK_SCRIPT_OWNER
527        wscript->owner = script->owner;
528    #endif
529    
530        /* Deoptimize wfun from FUN_{FLAT,NULL}_CLOSURE to FUN_INTERPRETED. */
531        FUN_SET_KIND(wfun, JSFUN_INTERPRETED);
532        wfun->u.i.script = wscript;
533        return wfunobj;
534    }
535    
536  static JSBool  static JSBool
537  args_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)  args_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
538  {  {
# Line 382  Line 550 
550      slot = JSVAL_TO_INT(id);      slot = JSVAL_TO_INT(id);
551      switch (slot) {      switch (slot) {
552        case ARGS_CALLEE:        case ARGS_CALLEE:
553          if (!TEST_OVERRIDE_BIT(fp, slot))          if (!TEST_OVERRIDE_BIT(fp, slot)) {
554                /*
555                 * If this function or one in it needs upvars that reach above it
556                 * in the scope chain, it must not be a null closure (it could be a
557                 * flat closure, or an unoptimized closure -- the latter itself not
558                 * necessarily heavyweight). Rather than wrap here, we simply throw
559                 * to reduce code size and tell debugger users the truth instead of
560                 * passing off a fibbing wrapper.
561                 */
562                if (fp->fun->needsWrapper()) {
563                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
564                                         JSMSG_OPTIMIZED_CLOSURE_LEAK);
565                    return JS_FALSE;
566                }
567              *vp = OBJECT_TO_JSVAL(fp->callee);              *vp = OBJECT_TO_JSVAL(fp->callee);
568            }
569          break;          break;
570    
571        case ARGS_LENGTH:        case ARGS_LENGTH:
# Line 461  Line 643 
643              }              }
644              *objp = obj;              *objp = obj;
645          }          }
646      } else {      } else if (JSVAL_IS_STRING(id)) {
647          str = JSVAL_TO_STRING(id);          str = JSVAL_TO_STRING(id);
648          atom = cx->runtime->atomState.lengthAtom;          atom = cx->runtime->atomState.lengthAtom;
649          if (str == ATOM_TO_STRING(atom)) {          if (str == ATOM_TO_STRING(atom)) {
# Line 586  Line 768 
768      JS_CLASS_TRACE(args_or_call_trace), NULL      JS_CLASS_TRACE(args_or_call_trace), NULL
769  };  };
770    
771  #define JSSLOT_SCRIPTED_FUNCTION         (JSSLOT_PRIVATE + 1)  #define JSSLOT_CALLEE                    (JSSLOT_PRIVATE + 1)
772  #define JSSLOT_CALL_ARGUMENTS            (JSSLOT_PRIVATE + 2)  #define JSSLOT_CALL_ARGUMENTS            (JSSLOT_PRIVATE + 2)
773  #define CALL_CLASS_FIXED_RESERVED_SLOTS  2  #define CALL_CLASS_FIXED_RESERVED_SLOTS  2
774    
775    /*
776     * A Declarative Environment object stores its active JSStackFrame pointer in
777     * its private slot, just as Call and Arguments objects do.
778     */
779    JSClass js_DeclEnvClass = {
780        js_Object_str,
781        JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
782        JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
783        JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   JS_FinalizeStub,
784        JSCLASS_NO_OPTIONAL_MEMBERS
785    };
786    
787    static JS_REQUIRES_STACK JSBool
788    CheckForEscapingClosure(JSContext *cx, JSObject *obj, jsval *vp)
789    {
790        JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass ||
791                  STOBJ_GET_CLASS(obj) == &js_DeclEnvClass);
792    
793        jsval v = *vp;
794    
795        if (VALUE_IS_FUNCTION(cx, v)) {
796            JSObject *funobj = JSVAL_TO_OBJECT(v);
797            JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
798    
799            /*
800             * Any escaping null or flat closure that reaches above itself or
801             * contains nested functions that reach above it must be wrapped.
802             * We can wrap only when this Call or Declarative Environment obj
803             * still has an active stack frame associated with it.
804             */
805            if (fun->needsWrapper()) {
806                JSStackFrame *fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
807                if (fp) {
808                    JSObject *wrapper = WrapEscapingClosure(cx, fp, funobj, fun);
809                    if (!wrapper)
810                        return false;
811                    *vp = OBJECT_TO_JSVAL(wrapper);
812                    return true;
813                }
814    
815                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
816                                     JSMSG_OPTIMIZED_CLOSURE_LEAK);
817                return false;
818            }
819        }
820        return true;
821    }
822    
823    static JS_REQUIRES_STACK JSBool
824    CalleeGetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
825    {
826        return CheckForEscapingClosure(cx, obj, vp);
827    }
828    
829  JSObject *  JSObject *
830  js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent)  js_GetCallObject(JSContext *cx, JSStackFrame *fp)
831  {  {
832      JSObject *callobj, *funobj;      JSObject *callobj;
833    
834      /* Create a call object for fp only if it lacks one. */      /* Create a call object for fp only if it lacks one. */
835      JS_ASSERT(fp->fun);      JS_ASSERT(fp->fun);
# Line 601  Line 837 
837      if (callobj)      if (callobj)
838          return callobj;          return callobj;
839    
840      /* The default call parent is its function's parent (static link). */  #ifdef DEBUG
841      if (!parent) {      /* A call object should be a frame's outermost scope chain element.  */
842          funobj = fp->callee;      JSClass *classp = OBJ_GET_CLASS(cx, fp->scopeChain);
843          if (funobj)      if (classp == &js_WithClass || classp == &js_BlockClass || classp == &js_CallClass)
844              parent = OBJ_GET_PARENT(cx, funobj);          JS_ASSERT(OBJ_GET_PRIVATE(cx, fp->scopeChain) != fp);
845    #endif
846    
847        /*
848         * Create the call object, using the frame's enclosing scope as its
849         * parent, and link the call to its stack frame. For a named function
850         * expression Call's parent points to an environment object holding
851         * function's name.
852         */
853        JSAtom *lambdaName = (fp->fun->flags & JSFUN_LAMBDA) ? fp->fun->atom : NULL;
854        if (lambdaName) {
855            JSObject *env = js_NewObjectWithGivenProto(cx, &js_DeclEnvClass, NULL,
856                                                       fp->scopeChain, 0);
857            if (!env)
858                return NULL;
859            env->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fp);
860    
861            /* Root env before js_DefineNativeProperty (-> JSClass.addProperty). */
862            fp->scopeChain = env;
863            if (!js_DefineNativeProperty(cx, fp->scopeChain, ATOM_TO_JSID(lambdaName),
864                                         OBJECT_TO_JSVAL(fp->callee),
865                                         CalleeGetter, NULL,
866                                         JSPROP_PERMANENT | JSPROP_READONLY,
867                                         0, 0, NULL)) {
868                return NULL;
869            }
870      }      }
871    
872      /* Create the call object and link it to its stack frame. */      callobj = js_NewObjectWithGivenProto(cx, &js_CallClass, NULL,
873      callobj = js_NewObject(cx, &js_CallClass, NULL, parent, 0);                                           fp->scopeChain, 0);
874      if (!callobj)      if (!callobj)
875          return NULL;          return NULL;
876    
877      JS_SetPrivate(cx, callobj, fp);      JS_SetPrivate(cx, callobj, fp);
878      STOBJ_SET_SLOT(callobj, JSSLOT_SCRIPTED_FUNCTION,      JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, fp->callee));
879                     OBJECT_TO_JSVAL(FUN_OBJECT(fp->fun)));      STOBJ_SET_SLOT(callobj, JSSLOT_CALLEE, OBJECT_TO_JSVAL(fp->callee));
880      fp->callobj = callobj;      fp->callobj = callobj;
881    
882      /* Make callobj be the scope chain and the variables object. */      /*
883      JS_ASSERT(fp->scopeChain == parent);       * Push callobj on the top of the scope chain, and make it the
884         * variables object.
885         */
886      fp->scopeChain = callobj;      fp->scopeChain = callobj;
887      fp->varobj = callobj;      fp->varobj = callobj;
888      return callobj;      return callobj;
889  }  }
890    
891  JSFunction *  static JSFunction *
892  js_GetCallObjectFunction(JSObject *obj)  GetCallObjectFunction(JSObject *obj)
893  {  {
894      jsval v;      jsval v;
895    
896      JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass);      JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass);
897      v = STOBJ_GET_SLOT(obj, JSSLOT_SCRIPTED_FUNCTION);      v = STOBJ_GET_SLOT(obj, JSSLOT_CALLEE);
898      if (JSVAL_IS_VOID(v)) {      if (JSVAL_IS_VOID(v)) {
899          /* Newborn or prototype object. */          /* Newborn or prototype object. */
900          return NULL;          return NULL;
901      }      }
902      JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));      JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
903      return (JSFunction *) JSVAL_TO_OBJECT(v);      return GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v));
904  }  }
905    
906  JS_FRIEND_API(JSBool)  JS_FRIEND_API(JSBool)
# Line 673  Line 936 
936      }      }
937    
938      fun = fp->fun;      fun = fp->fun;
939      JS_ASSERT(fun == js_GetCallObjectFunction(callobj));      JS_ASSERT(fun == GetCallObjectFunction(callobj));
940      n = JS_GET_LOCAL_NAME_COUNT(fun);      n = fun->countArgsAndVars();
941      if (n != 0) {      if (n != 0) {
942          JS_LOCK_OBJ(cx, callobj);          JS_LOCK_OBJ(cx, callobj);
943          n += JS_INITIAL_NSLOTS;          n += JS_INITIAL_NSLOTS;
# Line 685  Line 948 
948              memcpy(callobj->dslots, fp->argv, fun->nargs * sizeof(jsval));              memcpy(callobj->dslots, fp->argv, fun->nargs * sizeof(jsval));
949              memcpy(callobj->dslots + fun->nargs, fp->slots,              memcpy(callobj->dslots + fun->nargs, fp->slots,
950                     fun->u.i.nvars * sizeof(jsval));                     fun->u.i.nvars * sizeof(jsval));
951              if (scope->object == callobj && n > scope->map.freeslot)              if (scope->object == callobj && n > scope->freeslot)
952                  scope->map.freeslot = n;                  scope->freeslot = n;
953          }          }
954          JS_UNLOCK_SCOPE(cx, scope);          JS_UNLOCK_SCOPE(cx, scope);
955      }      }
956    
957      /*      /*
958       * Clear the private pointer to fp, which is about to go away (js_Invoke).       * Clear private pointers to fp, which is about to go away (js_Invoke).
959       * Do this last because js_GetProperty calls above need to follow the       * Do this last because js_GetProperty calls above need to follow the
960       * private slot to find fp.       * call object's private slot to find fp.
961       */       */
962        if ((fun->flags & JSFUN_LAMBDA) && fun->atom) {
963            JSObject *env = STOBJ_GET_PARENT(callobj);
964    
965            JS_ASSERT(STOBJ_GET_CLASS(env) == &js_DeclEnvClass);
966            JS_ASSERT(STOBJ_GET_PRIVATE(env) == fp);
967            JS_SetPrivate(cx, env, NULL);
968        }
969    
970      JS_SetPrivate(cx, callobj, NULL);      JS_SetPrivate(cx, callobj, NULL);
971      fp->callobj = NULL;      fp->callobj = NULL;
972      return ok;      return ok;
# Line 713  Line 984 
984      JSObject *pobj;      JSObject *pobj;
985      JSProperty *prop;      JSProperty *prop;
986    
987      fun = js_GetCallObjectFunction(obj);      fun = GetCallObjectFunction(obj);
988      n = JS_GET_LOCAL_NAME_COUNT(fun);      n = fun ? fun->countArgsAndVars() : 0;
989      if (n == 0)      if (n == 0)
990          return JS_TRUE;          return JS_TRUE;
991    
# Line 741  Line 1012 
1012              goto out;              goto out;
1013    
1014          /*          /*
1015           * At this point the call object always has a property corresponding           * The call object will always have a property corresponding to the
1016           * to the local name because call_resolve creates the property using           * argument or variable name because call_resolve creates the property
1017           * JSPROP_PERMANENT.           * using JSPROP_PERMANENT.
1018           */           */
1019          JS_ASSERT(prop && pobj == obj);          JS_ASSERT(prop);
1020            JS_ASSERT(pobj == obj);
1021          OBJ_DROP_PROPERTY(cx, pobj, prop);          OBJ_DROP_PROPERTY(cx, pobj, prop);
1022      }      }
1023      ok = JS_TRUE;      ok = JS_TRUE;
# Line 773  Line 1045 
1045      if (STOBJ_GET_CLASS(obj) != &js_CallClass)      if (STOBJ_GET_CLASS(obj) != &js_CallClass)
1046          return JS_TRUE;          return JS_TRUE;
1047    
1048      fun = js_GetCallObjectFunction(obj);      fun = GetCallObjectFunction(obj);
1049      fp = (JSStackFrame *) JS_GetPrivate(cx, obj);      fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
1050    
1051      if (kind == JSCPK_ARGUMENTS) {      if (kind == JSCPK_ARGUMENTS) {
# Line 818  Line 1090 
1090          JS_ASSERT(kind == JSCPK_VAR);          JS_ASSERT(kind == JSCPK_VAR);
1091          array = fp->slots;          array = fp->slots;
1092      }      }
1093      if (setter)      if (setter) {
1094            GC_POKE(cx, array[i]);
1095          array[i] = *vp;          array[i] = *vp;
1096      else      } else {
1097          *vp = array[i];          *vp = array[i];
1098        }
1099      return JS_TRUE;      return JS_TRUE;
1100  }  }
1101    
# Line 855  Line 1129 
1129      return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_FALSE);      return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_FALSE);
1130  }  }
1131    
1132    JSBool
1133    js_GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
1134    {
1135        if (!CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_FALSE))
1136            return JS_FALSE;
1137    
1138        return CheckForEscapingClosure(cx, obj, vp);
1139    }
1140    
1141  static JSBool  static JSBool
1142  SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp)  SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
1143  {  {
# Line 865  Line 1148 
1148  call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,  call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
1149               JSObject **objp)               JSObject **objp)
1150  {  {
1151        jsval callee;
1152      JSFunction *fun;      JSFunction *fun;
1153      jsid id;      jsid id;
1154      JSLocalKind localKind;      JSLocalKind localKind;
1155      JSPropertyOp getter, setter;      JSPropertyOp getter, setter;
1156      uintN slot, attrs;      uintN slot, attrs;
1157    
1158        JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass);
1159        JS_ASSERT(!STOBJ_GET_PROTO(obj));
1160    
1161      if (!JSVAL_IS_STRING(idval))      if (!JSVAL_IS_STRING(idval))
1162          return JS_TRUE;          return JS_TRUE;
1163    
1164      fun = js_GetCallObjectFunction(obj);      callee = STOBJ_GET_SLOT(obj, JSSLOT_CALLEE);
1165      if (!fun)      if (JSVAL_IS_VOID(callee))
1166          return JS_TRUE;          return JS_TRUE;
1167        fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(callee));
1168    
1169      if (!js_ValueToStringId(cx, idval, &id))      if (!js_ValueToStringId(cx, idval, &id))
1170          return JS_FALSE;          return JS_FALSE;
1171    
1172        /*
1173         * Check whether the id refers to a formal parameter, local variable or
1174         * the arguments special name.
1175         *
1176         * We define all such names using JSDNP_DONT_PURGE to avoid an expensive
1177         * shape invalidation in js_DefineNativeProperty. If such an id happens to
1178         * shadow a global or upvar of the same name, any inner functions can
1179         * never access the outer binding. Thus it cannot invalidate any property
1180         * cache entries or derived trace guards for the outer binding. See also
1181         * comments in js_PurgeScopeChainHelper from jsobj.cpp.
1182         */
1183      localKind = js_LookupLocal(cx, fun, JSID_TO_ATOM(id), &slot);      localKind = js_LookupLocal(cx, fun, JSID_TO_ATOM(id), &slot);
1184      if (localKind != JSLOCAL_NONE) {      if (localKind != JSLOCAL_NONE && localKind != JSLOCAL_UPVAR) {
1185          JS_ASSERT((uint16) slot == slot);          JS_ASSERT((uint16) slot == slot);
1186          attrs = JSPROP_PERMANENT | JSPROP_SHARED;  
1187            /*
1188             * We follow 10.2.3 of ECMA 262 v3 and make argument and variable
1189             * properties of the Call objects enumerable.
1190             */
1191            attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED;
1192          if (localKind == JSLOCAL_ARG) {          if (localKind == JSLOCAL_ARG) {
1193              JS_ASSERT(slot < fun->nargs);              JS_ASSERT(slot < fun->nargs);
1194              getter = js_GetCallArg;              getter = js_GetCallArg;
# Line 896  Line 1200 
1200              setter = SetCallVar;              setter = SetCallVar;
1201              if (localKind == JSLOCAL_CONST)              if (localKind == JSLOCAL_CONST)
1202                  attrs |= JSPROP_READONLY;                  attrs |= JSPROP_READONLY;
1203    
1204                /*
1205                 * Use js_GetCallVarChecked if the local's value is a null closure.
1206                 * This way we penalize performance only slightly on first use of a
1207                 * null closure, not on every use.
1208                 */
1209                jsval v;
1210                if (!CallPropertyOp(cx, obj, INT_TO_JSID((int16)slot), &v, JSCPK_VAR, JS_FALSE))
1211                    return JS_FALSE;
1212                if (VALUE_IS_FUNCTION(cx, v) &&
1213                    GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v))->needsWrapper()) {
1214                    getter = js_GetCallVarChecked;
1215                }
1216          }          }
1217          if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, getter, setter,          if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, getter, setter,
1218                                       attrs, SPROP_HAS_SHORTID, (int16) slot,                                       attrs, SPROP_HAS_SHORTID, (int16) slot,
1219                                       NULL)) {                                       NULL, JSDNP_DONT_PURGE)) {
1220              return JS_FALSE;              return JS_FALSE;
1221          }          }
1222          *objp = obj;          *objp = obj;
# Line 914  Line 1231 
1231          if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID,          if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID,
1232                                       GetCallArguments, SetCallArguments,                                       GetCallArguments, SetCallArguments,
1233                                       JSPROP_PERMANENT | JSPROP_SHARED,                                       JSPROP_PERMANENT | JSPROP_SHARED,
1234                                       0, 0, NULL)) {                                       0, 0, NULL, JSDNP_DONT_PURGE)) {
1235              return JS_FALSE;              return JS_FALSE;
1236          }          }
1237          *objp = obj;          *objp = obj;
1238          return JS_TRUE;          return JS_TRUE;
1239      }      }
1240    
1241        /* Control flow reaches here only if id was not resolved. */
1242      return JS_TRUE;      return JS_TRUE;
1243  }  }
1244    
# Line 943  Line 1262 
1262  {  {
1263      JSFunction *fun;      JSFunction *fun;
1264    
1265      fun = js_GetCallObjectFunction(obj);      fun = GetCallObjectFunction(obj);
1266      return JS_GET_LOCAL_NAME_COUNT(fun);      return fun->countArgsAndVars();
1267  }  }
1268    
1269  JS_FRIEND_DATA(JSClass) js_CallClass = {  JS_FRIEND_DATA(JSClass) js_CallClass = {
1270      js_Call_str,      "Call",
1271      JSCLASS_HAS_PRIVATE |      JSCLASS_HAS_PRIVATE |
1272      JSCLASS_HAS_RESERVED_SLOTS(CALL_CLASS_FIXED_RESERVED_SLOTS) |      JSCLASS_HAS_RESERVED_SLOTS(CALL_CLASS_FIXED_RESERVED_SLOTS) |
1273      JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS |      JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE,
     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Call),  
1274      JS_PropertyStub,    JS_PropertyStub,      JS_PropertyStub,    JS_PropertyStub,
1275      JS_PropertyStub,    JS_PropertyStub,      JS_PropertyStub,    JS_PropertyStub,
1276      call_enumerate,     (JSResolveOp)call_resolve,      call_enumerate,     (JSResolveOp)call_resolve,
# Line 1005  Line 1323 
1323      }      }
1324    
1325      /* Find fun's top-most activation record. */      /* Find fun's top-most activation record. */
1326      for (fp = cx->fp; fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));      for (fp = js_GetTopStackFrame(cx);
1327             fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));
1328           fp = fp->down) {           fp = fp->down) {
1329          continue;          continue;
1330      }      }
# Line 1040  Line 1359 
1359          break;          break;
1360    
1361        case FUN_CALLER:        case FUN_CALLER:
1362          if (fp && fp->down && fp->down->fun)          if (fp && fp->down && fp->down->fun) {
1363                JSFunction *caller = fp->down->fun;
1364                /*
1365                 * See equivalent condition in args_getProperty for ARGS_CALLEE,
1366                 * but here we do not want to throw, since this escape can happen
1367                 * via foo.caller alone, without any debugger or indirect eval. And
1368                 * it seems foo.caller is still used on the Web.
1369                 */
1370                if (caller->needsWrapper()) {
1371                    JSObject *wrapper = WrapEscapingClosure(cx, fp->down, FUN_OBJECT(caller), caller);
1372                    if (!wrapper)
1373                        return JS_FALSE;
1374                    *vp = OBJECT_TO_JSVAL(wrapper);
1375                    return JS_TRUE;
1376                }
1377    
1378              *vp = OBJECT_TO_JSVAL(fp->down->callee);              *vp = OBJECT_TO_JSVAL(fp->down->callee);
1379          else          } else {
1380              *vp = JSVAL_NULL;              *vp = JSVAL_NULL;
1381            }
1382          if (!JSVAL_IS_PRIMITIVE(*vp)) {          if (!JSVAL_IS_PRIMITIVE(*vp)) {
1383              callbacks = JS_GetSecurityCallbacks(cx);              callbacks = JS_GetSecurityCallbacks(cx);
1384              if (callbacks && callbacks->checkObjectAccess) {              if (callbacks && callbacks->checkObjectAccess) {
# Line 1129  Line 1464 
1464    
1465      /*      /*
1466       * No need to reflect fun.prototype in 'fun.prototype = ... '.       * No need to reflect fun.prototype in 'fun.prototype = ... '.
      *  
      * This is not just an optimization, because we must not resolve when  
      * defining hidden properties during compilation. The setup code for the  
      * prototype and the lazy properties below eventually calls the property  
      * hooks for the function object. That in turn calls fun_reserveSlots to  
      * get the number of the reserved slots which is just the number of  
      * regular expressions literals in the function. When compiling, that  
      * number is not yet ready so we must make sure that fun_resolve does  
      * nothing until the code for the function is generated.  
1467       */       */
1468      if (flags & JSRESOLVE_ASSIGNING)      if (flags & JSRESOLVE_ASSIGNING)
1469          return JS_TRUE;          return JS_TRUE;
# Line 1217  Line 1543 
1543  #if JS_HAS_XDR  #if JS_HAS_XDR
1544    
1545  /* XXX store parent and proto, if defined */  /* XXX store parent and proto, if defined */
1546  static JSBool  JSBool
1547  fun_xdrObject(JSXDRState *xdr, JSObject **objp)  js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
1548  {  {
1549      JSContext *cx;      JSContext *cx;
1550      JSFunction *fun;      JSFunction *fun;
1551      uint32 nullAtom;            /* flag to indicate if fun->atom is NULL */      uint32 firstword;           /* flag telling whether fun->atom is non-null,
1552      uintN nargs, nvars, n;                                     plus for fun->u.i.skipmin, fun->u.i.wrapper,
1553      uint32 localsword;          /* word to xdr argument and variable counts */                                     and 14 bits reserved for future use */
1554      uint32 flagsword;           /* originally only flags was JS_XDRUint8'd */      uintN nargs, nvars, nupvars, n;
1555        uint32 localsword;          /* word for argument and variable counts */
1556        uint32 flagsword;           /* word for fun->u.i.nupvars and fun->flags */
1557      JSTempValueRooter tvr;      JSTempValueRooter tvr;
1558      JSBool ok;      JSBool ok;
1559    
# Line 1238  Line 1566 
1566                                   JS_GetFunctionName(fun));                                   JS_GetFunctionName(fun));
1567              return JS_FALSE;              return JS_FALSE;
1568          }          }
1569          nullAtom = !fun->atom;          if (fun->u.i.wrapper) {
1570                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1571                                     JSMSG_XDR_CLOSURE_WRAPPER,
1572                                     JS_GetFunctionName(fun));
1573                return JS_FALSE;
1574            }
1575            JS_ASSERT((fun->u.i.wrapper & ~1U) == 0);
1576            firstword = (fun->u.i.skipmin << 2) | (fun->u.i.wrapper << 1) | !!fun->atom;
1577          nargs = fun->nargs;          nargs = fun->nargs;
1578          nvars = fun->u.i.nvars;          nvars = fun->u.i.nvars;
1579            nupvars = fun->u.i.nupvars;
1580          localsword = (nargs << 16) | nvars;          localsword = (nargs << 16) | nvars;
1581          flagsword = fun->flags;          flagsword = (nupvars << 16) | fun->flags;
1582      } else {      } else {
1583          fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);          fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
1584          if (!fun)          if (!fun)
# Line 1250  Line 1586 
1586          STOBJ_CLEAR_PARENT(FUN_OBJECT(fun));          STOBJ_CLEAR_PARENT(FUN_OBJECT(fun));
1587          STOBJ_CLEAR_PROTO(FUN_OBJECT(fun));          STOBJ_CLEAR_PROTO(FUN_OBJECT(fun));
1588  #ifdef __GNUC__  #ifdef __GNUC__
1589          nvars = nargs = 0;   /* quell GCC uninitialized warning */          nvars = nargs = nupvars = 0;    /* quell GCC uninitialized warning */
1590  #endif  #endif
1591      }      }
1592    
1593      /* From here on, control flow must flow through label out. */      /* From here on, control flow must flow through label out. */
1594        MUST_FLOW_THROUGH("out");
1595      JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr);      JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr);
1596      ok = JS_TRUE;      ok = JS_TRUE;
1597    
1598      if (!JS_XDRUint32(xdr, &nullAtom))      if (!JS_XDRUint32(xdr, &firstword))
1599          goto bad;          goto bad;
1600      if (!nullAtom && !js_XDRStringAtom(xdr, &fun->atom))      if ((firstword & 1U) && !js_XDRStringAtom(xdr, &fun->atom))
1601          goto bad;          goto bad;
1602      if (!JS_XDRUint32(xdr, &localsword) ||      if (!JS_XDRUint32(xdr, &localsword) ||
1603          !JS_XDRUint32(xdr, &flagsword)) {          !JS_XDRUint32(xdr, &flagsword)) {
# Line 1269  Line 1606 
1606    
1607      if (xdr->mode == JSXDR_DECODE) {      if (xdr->mode == JSXDR_DECODE) {
1608          nargs = localsword >> 16;          nargs = localsword >> 16;
1609          nvars = localsword & JS_BITMASK(16);          nvars = uint16(localsword);
1610          JS_ASSERT(flagsword | JSFUN_INTERPRETED);          JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
1611          fun->flags = (uint16) flagsword;          nupvars = flagsword >> 16;
1612            fun->flags = uint16(flagsword);
1613            fun->u.i.skipmin = uint16(firstword >> 2);
1614            fun->u.i.wrapper = (firstword >> 1) & 1;
1615      }      }
1616    
1617      /* do arguments and local vars */      /* do arguments and local vars */
1618      n = nargs + nvars;      n = nargs + nvars + nupvars;
1619      if (n != 0) {      if (n != 0) {
1620          void *mark;          void *mark;
1621          uintN i;          uintN i;
# Line 1297  Line 1637 
1637           * names (indexes starting from nargs) bitmap's bit is set when the           * names (indexes starting from nargs) bitmap's bit is set when the
1638           * name is declared as const, not as ordinary var.           * name is declared as const, not as ordinary var.
1639           * */           * */
1640            MUST_FLOW_THROUGH("release_mark");
1641          bitmapLength = JS_HOWMANY(n, JS_BITS_PER_UINT32);          bitmapLength = JS_HOWMANY(n, JS_BITS_PER_UINT32);
1642          JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &xdr->cx->tempPool,          JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &xdr->cx->tempPool,
1643                                 bitmapLength * sizeof *bitmap);                                 bitmapLength * sizeof *bitmap);
# Line 1352  Line 1693 
1693              if (xdr->mode == JSXDR_DECODE) {              if (xdr->mode == JSXDR_DECODE) {
1694                  localKind = (i < nargs)                  localKind = (i < nargs)
1695                              ? JSLOCAL_ARG                              ? JSLOCAL_ARG
1696                              : bitmap[i >> JS_BITS_PER_UINT32_LOG2] &                              : (i < nargs + nvars)
1697                                JS_BIT(i & (JS_BITS_PER_UINT32 - 1))                              ? (bitmap[i >> JS_BITS_PER_UINT32_LOG2] &
1698                              ? JSLOCAL_CONST                                 JS_BIT(i & (JS_BITS_PER_UINT32 - 1))
1699                              : JSLOCAL_VAR;                                 ? JSLOCAL_CONST
1700                                   : JSLOCAL_VAR)
1701                                : JSLOCAL_UPVAR;
1702                  ok = js_AddLocal(xdr->cx, fun, name, localKind);                  ok = js_AddLocal(xdr->cx, fun, name, localKind);
1703                  if (!ok)                  if (!ok)
1704                      goto release_mark;                      goto release_mark;
# Line 1394  Line 1737 
1737    
1738  #else  /* !JS_HAS_XDR */  #else  /* !JS_HAS_XDR */
1739    
1740  #define fun_xdrObject NULL  #define js_XDRFunctionObject NULL
1741    
1742  #endif /* !JS_HAS_XDR */  #endif /* !JS_HAS_XDR */
1743    
# Line 1493  Line 1836 
1836      fun = (JSFunction *) JS_GetPrivate(cx, obj);      fun = (JSFunction *) JS_GetPrivate(cx, obj);
1837      nslots = 0;      nslots = 0;
1838      if (fun && FUN_INTERPRETED(fun) && fun->u.i.script) {      if (fun && FUN_INTERPRETED(fun) && fun->u.i.script) {
1839          if (fun->u.i.script->upvarsOffset != 0)          if (fun->u.i.nupvars != 0)
1840              nslots = JS_SCRIPT_UPVARS(fun->u.i.script)->length;              nslots = JS_SCRIPT_UPVARS(fun->u.i.script)->length;
1841          if (fun->u.i.script->regexpsOffset != 0)          if (fun->u.i.script->regexpsOffset != 0)
1842              nslots += JS_SCRIPT_REGEXPS(fun->u.i.script)->length;              nslots += JS_SCRIPT_REGEXPS(fun->u.i.script)->length;
# Line 1516  Line 1859 
1859      fun_convert,      fun_finalize,      fun_convert,      fun_finalize,
1860      NULL,             NULL,      NULL,             NULL,
1861      NULL,             NULL,      NULL,             NULL,
1862      fun_xdrObject,    fun_hasInstance,      js_XDRFunctionObject, fun_hasInstance,
1863      JS_CLASS_TRACE(fun_trace), fun_reserveSlots      JS_CLASS_TRACE(fun_trace), fun_reserveSlots
1864  };  };
1865    
# Line 1586  Line 1929 
1929  }  }
1930  #endif  #endif
1931    
1932  JSBool  JS_REQUIRES_STACK JSBool
1933  js_fun_call(JSContext *cx, uintN argc, jsval *vp)  js_fun_call(JSContext *cx, uintN argc, jsval *vp)
1934  {  {
1935      JSObject *obj;      JSObject *obj;
# Line 1645  Line 1988 
1988      return ok;      return ok;
1989  }  }
1990    
1991  JSBool  JS_REQUIRES_STACK JSBool
1992  js_fun_apply(JSContext *cx, uintN argc, jsval *vp)  js_fun_apply(JSContext *cx, uintN argc, jsval *vp)
1993  {  {
1994      JSObject *obj, *aobj;      JSObject *obj, *aobj;
# Line 1736  Line 2079 
2079  }  }
2080    
2081  #ifdef NARCISSUS  #ifdef NARCISSUS
2082  static JSBool  static JS_REQUIRES_STACK JSBool
2083  fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp)  fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp)
2084  {  {
2085      JSObject *aobj;      JSObject *aobj;
# Line 1797  Line 2140 
2140  static JSBool  static JSBool
2141  Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)  Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2142  {  {
     JSStackFrame *fp, *caller;  
2143      JSFunction *fun;      JSFunction *fun;
2144      JSObject *parent;      JSObject *parent;
2145        JSStackFrame *fp, *caller;
2146      uintN i, n, lineno;      uintN i, n, lineno;
2147      JSAtom *atom;      JSAtom *atom;
2148      const char *filename;      const char *filename;
# Line 1812  Line 2155 
2155      size_t arg_length, args_length, old_args_length;      size_t arg_length, args_length, old_args_length;
2156      JSTokenType tt;      JSTokenType tt;
2157    
2158      fp = cx->fp;      if (!JS_IsConstructing(cx)) {
     if (!(fp->flags & JSFRAME_CONSTRUCTING)) {  
2159          obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL, 0);          obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL, 0);
2160          if (!obj)          if (!obj)
2161              return JS_FALSE;              return JS_FALSE;
# Line 1852  Line 2194 
2194       * are built for Function.prototype.call or .apply activations that invoke       * are built for Function.prototype.call or .apply activations that invoke
2195       * Function indirectly from a script.       * Function indirectly from a script.
2196       */       */
2197        fp = js_GetTopStackFrame(cx);
2198      JS_ASSERT(!fp->script && fp->fun && fp->fun->u.n.native == Function);      JS_ASSERT(!fp->script && fp->fun && fp->fun->u.n.native == Function);
2199      caller = JS_GetScriptedCaller(cx, fp);      caller = js_GetScriptedCaller(cx, fp);
2200      if (caller) {      if (caller) {
2201          principals = JS_EvalFramePrincipals(cx, fp, caller);          principals = JS_EvalFramePrincipals(cx, fp, caller);
2202          filename = js_ComputeFilename(cx, caller, principals, &lineno);          filename = js_ComputeFilename(cx, caller, principals, &lineno);
# Line 2020  Line 2363 
2363          str = cx->runtime->emptyString;          str = cx->runtime->emptyString;
2364      }      }
2365    
2366      return js_CompileFunctionBody(cx, fun, principals,      return JSCompiler::compileFunctionBody(cx, fun, principals,
2367                                    JSSTRING_CHARS(str), JSSTRING_LENGTH(str),                                             JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
2368                                    filename, lineno);                                             filename, lineno);
2369  }  }
2370    
2371  JSObject *  JSObject *
# Line 2053  Line 2396 
2396      return NULL;      return NULL;
2397  }  }
2398    
 JSObject *  
 js_InitCallClass(JSContext *cx, JSObject *obj)  
 {  
     JSObject *proto;  
   
     proto = JS_InitClass(cx, obj, NULL, &js_CallClass, NULL, 0,  
                          NULL, NULL, NULL, NULL);  
     if (!proto)  
         return NULL;  
   
     /*  
      * Null Call.prototype's proto slot so that Object.prototype.* does not  
      * pollute the scope of heavyweight functions.  
      */  
     OBJ_CLEAR_PROTO(cx, proto);  
     return proto;  
 }  
   
2399  JSFunction *  JSFunction *
2400  js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,  js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
2401                 uintN flags, JSObject *parent, JSAtom *atom)                 uintN flags, JSObject *parent, JSAtom *atom)
# Line 2090  Line 2415 
2415    
2416      /* Initialize all function members. */      /* Initialize all function members. */
2417      fun->nargs = nargs;      fun->nargs = nargs;
2418      fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_INTERPRETED | JSFUN_TRACEABLE);      fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRACEABLE);
2419      if (flags & JSFUN_INTERPRETED) {      if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) {
2420          JS_ASSERT(!native);          JS_ASSERT(!native);
2421          JS_ASSERT(nargs == 0);          JS_ASSERT(nargs == 0);
2422          fun->u.i.nvars = 0;          fun->u.i.nvars = 0;
2423          fun->u.i.nupvars = 0;          fun->u.i.nupvars = 0;
2424            fun->u.i.skipmin = 0;
2425            fun->u.i.wrapper = false;
2426          fun->u.i.script = NULL;          fun->u.i.script = NULL;
2427  #ifdef DEBUG  #ifdef DEBUG
2428          fun->u.i.names.taggedAtom = 0;          fun->u.i.names.taggedAtom = 0;
# Line 2103  Line 2430 
2430      } else {      } else {
2431          fun->u.n.extra = 0;          fun->u.n.extra = 0;
2432          fun->u.n.spare = 0;          fun->u.n.spare = 0;
2433            fun->u.n.clasp = NULL;
2434          if (flags & JSFUN_TRACEABLE) {          if (flags & JSFUN_TRACEABLE) {
2435  #ifdef JS_TRACER  #ifdef JS_TRACER
2436              JSTraceableNative *trcinfo = (JSTraceableNative *) native;              JSTraceableNative *trcinfo =
2437                    JS_FUNC_TO_DATA_PTR(JSTraceableNative *, native);
2438              fun->u.n.native = (JSNative) trcinfo->native;              fun->u.n.native = (JSNative) trcinfo->native;
2439              FUN_TRCINFO(fun) = trcinfo;              fun->u.n.trcinfo = trcinfo;
2440  #else  #else
2441              JS_ASSERT(0);              fun->u.n.trcinfo = NULL;
2442  #endif  #endif
2443          } else {          } else {
2444              fun->u.n.native = native;              fun->u.n.native = native;
2445              FUN_CLASP(fun) = NULL;              fun->u.n.trcinfo = NULL;
2446          }          }
2447            JS_ASSERT(fun->u.n.native);
2448      }      }
2449      fun->atom = atom;      fun->atom = atom;
2450    
# Line 2126  Line 2456 
2456  JSObject *  JSObject *
2457  js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent)  js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent)
2458  {  {
     JSObject *clone;  
   
2459      /*      /*
2460       * The cloned function object does not need the extra fields beyond       * The cloned function object does not need the extra JSFunction members
2461       * JSObject as it points to fun via the private slot.       * beyond JSObject as it points to fun via the private slot.
2462       */       */
2463      clone = js_NewObject(cx, &js_FunctionClass, NULL, parent,      JSObject *clone = js_NewObject(cx, &js_FunctionClass, NULL, parent,
2464                           sizeof(JSObject));                                     sizeof(JSObject));
2465      if (!clone)      if (!clone)
2466          return NULL;          return NULL;
2467      clone->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);      clone->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);
2468      return clone;      return clone;
2469  }  }
2470    
2471    JSObject *
2472    js_NewFlatClosure(JSContext *cx, JSFunction *fun)
2473    {
2474        JS_ASSERT(FUN_FLAT_CLOSURE(fun));
2475    
2476        JSObject *closure = js_CloneFunctionObject(cx, fun, cx->fp->scopeChain);
2477        if (!closure || fun->u.i.script->upvarsOffset == 0)
2478            return closure;
2479    
2480        uint32 nslots = JSSLOT_FREE(&js_FunctionClass);
2481        JS_ASSERT(nslots == JS_INITIAL_NSLOTS);
2482        nslots += fun_reserveSlots(cx, closure);
2483        if (!js_ReallocSlots(cx, closure, nslots, JS_TRUE))
2484            return NULL;
2485    
2486        JSUpvarArray *uva = JS_SCRIPT_UPVARS(fun->u.i.script);
2487        JS_ASSERT(uva->length <= size_t(closure->dslots[-1]));
2488    
2489        uintN level = fun->u.i.script->staticLevel;
2490        for (uint32 i = 0, n = uva->length; i < n; i++)
2491            closure->dslots[i] = js_GetUpvar(cx, level, uva->vector[i]);
2492    
2493        return closure;
2494    }
2495    
2496    JSObject *
2497    js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun)
2498    {
2499        JS_ASSERT(cx->fp->fun->flags & JSFUN_HEAVYWEIGHT);
2500        JS_ASSERT(!cx->fp->fun->optimizedClosure());
2501    
2502        return WrapEscapingClosure(cx, cx->fp, FUN_OBJECT(fun), fun);
2503    }
2504    
2505  JSFunction *  JSFunction *
2506  js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,  js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
2507                    uintN nargs, uintN attrs)                    uintN nargs, uintN attrs)
2508  {  {
     JSFunction *fun;  
2509      JSPropertyOp gsop;      JSPropertyOp gsop;
2510        JSFunction *fun;
2511    
2512        if (attrs & JSFUN_STUB_GSOPS) {
2513            /*
2514             * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
2515             * the defined property's attributes. This allows us to encode another,
2516             * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
2517             * for more on this.
2518             */
2519            attrs &= ~JSFUN_STUB_GSOPS;
2520            gsop = JS_PropertyStub;
2521        } else {
2522            gsop = NULL;
2523        }
2524      fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom);      fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom);
2525      if (!fun)      if (!fun)
2526          return NULL;          return NULL;
     gsop = (attrs & JSFUN_STUB_GSOPS) ? JS_PropertyStub : NULL;  
2527      if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),      if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
2528                               OBJECT_TO_JSVAL(FUN_OBJECT(fun)),                               OBJECT_TO_JSVAL(FUN_OBJECT(fun)),
2529                               gsop, gsop,                               gsop, gsop,
# Line 2202  Line 2575 
2575          return NULL;          return NULL;
2576      *vp = OBJECT_TO_JSVAL(FUN_OBJECT(fun));      *vp = OBJECT_TO_JSVAL(FUN_OBJECT(fun));
2577    
2578      caller = JS_GetScriptedCaller(cx, cx->fp);      caller = js_GetScriptedCaller(cx, NULL);
2579      if (caller) {      if (caller) {
2580          principals = JS_StackFramePrincipals(cx, caller);          principals = JS_StackFramePrincipals(cx, caller);
2581      } else {      } else {
# Line 2222  Line 2595 
2595  JSObject *  JSObject *
2596  js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags)  js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags)
2597  {  {
2598      JSObject *callable;      JSObject *callable = JSVAL_IS_OBJECT(*vp) ? JSVAL_TO_OBJECT(*vp) : NULL;
2599    
2600      callable = JSVAL_IS_PRIMITIVE(*vp) ? NULL : JSVAL_TO_OBJECT(*vp);      if (callable && js_IsCallable(callable, cx)) {
     if (callable &&  
         ((callable->map->ops == &js_ObjectOps)  
          ? OBJ_GET_CLASS(cx, callable)->call  
          : callable->map->ops->call)) {  
2601          *vp = OBJECT_TO_JSVAL(callable);          *vp = OBJECT_TO_JSVAL(callable);
2602      } else {          return callable;
         callable = js_ValueToFunctionObject(cx, vp, flags);  
2603      }      }
2604      return callable;      return js_ValueToFunctionObject(cx, vp, flags);
2605  }  }
2606    
2607  void  void
# Line 2244  Line 2612 
2612      const char *name, *source;      const char *name, *source;
2613      JSTempValueRooter tvr;      JSTempValueRooter tvr;
2614    
2615      for (fp = cx->fp; fp && !fp->regs; fp = fp->down)      for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down)
2616          continue;          continue;
2617      name = source = NULL;      name = source = NULL;
2618      JS_PUSH_TEMP_ROOT_STRING(cx, NULL, &tvr);      JS_PUSH_TEMP_ROOT_STRING(cx, NULL, &tvr);
# Line 2396  Line 2764 
2764          else          else
2765              JS_ASSERT(kind == JSLOCAL_VAR);              JS_ASSERT(kind == JSLOCAL_VAR);
2766      }      }
2767      n = JS_GET_LOCAL_NAME_COUNT(fun);      n = fun->countLocalNames();
2768      if (n == 0) {      if (n == 0) {
2769          JS_ASSERT(fun->u.i.names.taggedAtom == 0);          JS_ASSERT(fun->u.i.names.taggedAtom == 0);
2770          fun->u.i.names.taggedAtom = taggedAtom;          fun->u.i.names.taggedAtom = taggedAtom;
# Line 2444  Line 2812 
2812          map->lastdup = NULL;          map->lastdup = NULL;
2813          for (i = 0; i != MAX_ARRAY_LOCALS; ++i) {          for (i = 0; i != MAX_ARRAY_LOCALS; ++i) {
2814              taggedAtom = array[i];              taggedAtom = array[i];
2815              if (!HashLocalName(cx, map, (JSAtom *) (taggedAtom & ~1),              uintN j = i;
2816                                 (i < fun->nargs)              JSLocalKind k = JSLOCAL_ARG;
2817                                 ? JSLOCAL_ARG              if (j >= fun->nargs) {
2818                                 : (taggedAtom & 1) ? JSLOCAL_CONST : JSLOCAL_VAR,                  j -= fun->nargs;
2819                                 (i < fun->nargs) ? i : i - fun->nargs)) {                  if (j < fun->u.i.nvars) {
2820                        k = (taggedAtom & 1) ? JSLOCAL_CONST : JSLOCAL_VAR;
2821                    } else {
2822                        j -= fun->u.i.nvars;
2823                        k = JSLOCAL_UPVAR;
2824                    }
2825                }
2826                if (!HashLocalName(cx, map, (JSAtom *) (taggedAtom & ~1), k, j)) {
2827                  FreeLocalNameHash(cx, map);                  FreeLocalNameHash(cx, map);
2828                  return JS_FALSE;                  return JS_FALSE;
2829              }              }
# Line 2489  Line 2864 
2864      JSLocalNameHashEntry *entry;      JSLocalNameHashEntry *entry;
2865    
2866      JS_ASSERT(FUN_INTERPRETED(fun));      JS_ASSERT(FUN_INTERPRETED(fun));
2867      n = JS_GET_LOCAL_NAME_COUNT(fun);      n = fun->countLocalNames();
2868      if (n == 0)      if (n == 0)
2869          return JSLOCAL_NONE;          return JSLOCAL_NONE;
2870      if (n <= MAX_ARRAY_LOCALS) {      if (n <= MAX_ARRAY_LOCALS) {
# Line 2497  Line 2872 
2872    
2873          /* Search from the tail to pick up the last duplicated name. */          /* Search from the tail to pick up the last duplicated name. */
2874          i = n;          i = n;
2875          upvar_base = JS_UPVAR_LOCAL_NAME_START(fun);          upvar_base = fun->countArgsAndVars();
2876          do {          do {
2877              --i;              --i;
2878              if (atom == JS_LOCAL_NAME_TO_ATOM(array[i])) {              if (atom == JS_LOCAL_NAME_TO_ATOM(array[i])) {
# Line 2560  Line 2935 
2935          constFlag = 0;          constFlag = 0;
2936      } else {      } else {
2937          JS_ASSERT(entry->localKind == JSLOCAL_VAR ||          JS_ASSERT(entry->localKind == JSLOCAL_VAR ||
2938                    entry->localKind == JSLOCAL_CONST);                    entry->localKind == JSLOCAL_CONST ||
2939          JS_ASSERT(entry->index < args->fun->u.i.nvars);                    entry->localKind == JSLOCAL_UPVAR);
2940          JS_ASSERT(args->nCopiedVars++ < args->fun->u.i.nvars);          JS_ASSERT(entry->index < args->fun->u.i.nvars + args->fun->u.i.nupvars);
2941          i = args->fun->nargs + entry->index;          JS_ASSERT(args->nCopiedVars++ < args->fun->u.i.nvars + args->fun->u.i.nupvars);
2942            i = args->fun->nargs;
2943            if (entry->localKind == JSLOCAL_UPVAR)
2944               i += args->fun->u.i.nvars;
2945            i += entry->index;
2946          constFlag = (entry->localKind == JSLOCAL_CONST);          constFlag = (entry->localKind == JSLOCAL_CONST);
2947      }      }
2948      args->names[i] = (jsuword) entry->name | constFlag;      args->names[i] = (jsuword) entry->name | constFlag;
# Line 2579  Line 2958 
2958      JSLocalNameEnumeratorArgs args;      JSLocalNameEnumeratorArgs args;
2959      JSNameIndexPair *dup;      JSNameIndexPair *dup;
2960    
2961      JS_ASSERT(FUN_INTERPRETED(fun));      JS_ASSERT(fun->hasLocalNames());
2962      n = JS_GET_LOCAL_NAME_COUNT(fun);      n = fun->countLocalNames();
     JS_ASSERT(n != 0);  
2963    
2964      if (n <= MAX_ARRAY_LOCALS)      if (n <= MAX_ARRAY_LOCALS)
2965          return (n == 1) ? &fun->u.i.names.taggedAtom : fun->u.i.names.array;          return (n == 1) ? &fun->u.i.names.taggedAtom : fun->u.i.names.array;
# Line 2616  Line 2994 
2994  #if !JS_HAS_DESTRUCTURING  #if !JS_HAS_DESTRUCTURING
2995      JS_ASSERT(args.nCopiedArgs == fun->nargs);      JS_ASSERT(args.nCopiedArgs == fun->nargs);
2996  #endif  #endif
2997      JS_ASSERT(args.nCopiedVars == fun->u.i.nvars);      JS_ASSERT(args.nCopiedVars == fun->u.i.nvars + fun->u.i.nupvars);
2998    
2999      return names;      return names;
3000  }  }
# Line 2646  Line 3024 
3024      jsuword *array;      jsuword *array;
3025    
3026      JS_ASSERT(FUN_INTERPRETED(fun));      JS_ASSERT(FUN_INTERPRETED(fun));
3027      n = JS_GET_LOCAL_NAME_COUNT(fun);      n = fun->countLocalNames();
3028      if (n == 0)      if (n == 0)
3029          return;          return;
3030      if (n <= MAX_ARRAY_LOCALS) {      if (n <= MAX_ARRAY_LOCALS) {
# Line 2678  Line 3056 
3056  {  {
3057      uintN n;      uintN n;
3058    
3059      n = fun->nargs + fun->u.i.nvars;      n = fun->countLocalNames();
3060      if (n <= 1)      if (n <= 1)
3061          return;          return;
3062      if (n <= MAX_ARRAY_LOCALS)      if (n <= MAX_ARRAY_LOCALS)
# Line 2703  Line 3081 
3081          if (array)          if (array)
3082              fun->u.i.names.array = array;              fun->u.i.names.array = array;
3083      }      }
3084    #ifdef DEBUG
3085    // XXX no JS_DHashMarkTableImmutable on 1.9.1
3086    //    if (n > MAX_ARRAY_LOCALS)
3087    //        JS_DHashMarkTableImmutable(&fun->u.i.names.map->names);
3088    #endif
3089  }  }

Legend:
Removed from v.399  
changed lines
  Added in v.460

  ViewVC Help
Powered by ViewVC 1.1.24