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

Diff of /trunk/js/jsobj.cpp

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

revision 459 by siliconforks, Tue Dec 9 03:37:47 2008 UTC revision 460 by siliconforks, Sat Sep 26 23:15:22 2009 UTC
# Line 1  Line 1 
1  /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-  /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2   * vim: set ts=8 sw=4 et tw=78:   * vim: set ts=8 sw=4 et tw=79:
3   *   *
4   * ***** BEGIN LICENSE BLOCK *****   * ***** BEGIN LICENSE BLOCK *****
5   * Version: MPL 1.1/GPL 2.0/LGPL 2.1   * Version: MPL 1.1/GPL 2.0/LGPL 2.1
# Line 69  Line 69 
69  #include "jsparse.h"  #include "jsparse.h"
70  #include "jsscope.h"  #include "jsscope.h"
71  #include "jsscript.h"  #include "jsscript.h"
 #include "jsstr.h"  
 #include "jsdbgapi.h"   /* whether or not JS_HAS_OBJ_WATCHPOINT */  
72  #include "jsstaticcheck.h"  #include "jsstaticcheck.h"
73    #include "jsstr.h"
74    #include "jstracer.h"
75    #include "jsdbgapi.h"
76    
77  #if JS_HAS_GENERATORS  #if JS_HAS_GENERATORS
78  #include "jsiter.h"  #include "jsiter.h"
# Line 101  Line 102 
102  #endif  #endif
103    
104  JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {  JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
105      js_NewObjectMap,        js_DestroyObjectMap,      NULL,
106      js_LookupProperty,      js_DefineProperty,      js_LookupProperty,      js_DefineProperty,
107      js_GetProperty,         js_SetProperty,      js_GetProperty,         js_SetProperty,
108      js_GetAttributes,       js_SetAttributes,      js_GetAttributes,       js_SetAttributes,
# Line 109  Line 110 
110      js_Enumerate,           js_CheckAccess,      js_Enumerate,           js_CheckAccess,
111      NULL,                   NATIVE_DROP_PROPERTY,      NULL,                   NATIVE_DROP_PROPERTY,
112      js_Call,                js_Construct,      js_Call,                js_Construct,
113      NULL,                   js_HasInstance,      js_HasInstance,         js_TraceObject,
114      js_SetProtoOrParent,    js_SetProtoOrParent,      js_Clear,               js_GetRequiredSlot,
115      js_TraceObject,         js_Clear,      js_SetRequiredSlot
     js_GetRequiredSlot,     js_SetRequiredSlot  
116  };  };
117    
118  JSClass js_ObjectClass = {  JSClass js_ObjectClass = {
# Line 169  Line 169 
169      uintN attrs;      uintN attrs;
170      JSObject *pobj;      JSObject *pobj;
171      JSClass *clasp;      JSClass *clasp;
     JSExtendedClass *xclasp;  
172    
173      slot = (uint32) JSVAL_TO_INT(id);      slot = (uint32) JSVAL_TO_INT(id);
174      if (id == INT_TO_JSVAL(JSSLOT_PROTO)) {      if (id == INT_TO_JSVAL(JSSLOT_PROTO)) {
# Line 190  Line 189 
189          if (clasp == &js_CallClass || clasp == &js_BlockClass) {          if (clasp == &js_CallClass || clasp == &js_BlockClass) {
190              /* Censor activations and lexical scopes per ECMA-262. */              /* Censor activations and lexical scopes per ECMA-262. */
191              *vp = JSVAL_NULL;              *vp = JSVAL_NULL;
192          } else if (clasp->flags & JSCLASS_IS_EXTENDED) {          } else {
193              xclasp = (JSExtendedClass *) clasp;              /*
194              if (xclasp->outerObject) {               * DeclEnv only exists as a parent for a Call object which we
195                  pobj = xclasp->outerObject(cx, pobj);               * censor. So it cannot escape to scripts.
196                 */
197                JS_ASSERT(clasp != &js_DeclEnvClass);
198                if (pobj->map->ops->thisObject) {
199                    pobj = pobj->map->ops->thisObject(cx, pobj);
200                  if (!pobj)                  if (!pobj)
201                      return JS_FALSE;                      return JS_FALSE;
202                  *vp = OBJECT_TO_JSVAL(pobj);                  *vp = OBJECT_TO_JSVAL(pobj);
# Line 237  Line 240 
240          return JS_FALSE;          return JS_FALSE;
241      }      }
242    
243      return js_SetProtoOrParent(cx, obj, slot, pobj);      return js_SetProtoOrParent(cx, obj, slot, pobj, JS_TRUE);
244  }  }
245    
246  static JSBool  static JSBool
# Line 276  Line 279 
279  #endif /* !JS_HAS_OBJ_PROTO_PROP */  #endif /* !JS_HAS_OBJ_PROTO_PROP */
280    
281  JSBool  JSBool
282  js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj)  js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj,
283                        JSBool checkForCycles)
284  {  {
285      JSSetSlotRequest ssr;      JS_ASSERT(slot == JSSLOT_PARENT || slot == JSSLOT_PROTO);
286      JSRuntime *rt;      JS_ASSERT_IF(!checkForCycles, obj != pobj);
287    
288      /* Optimize the null case to avoid the unnecessary overhead of js_GC. */      if (slot == JSSLOT_PROTO) {
289      if (!pobj) {          if (OBJ_IS_NATIVE(obj)) {
290          JS_LOCK_OBJ(cx, obj);              JS_LOCK_OBJ(cx, obj);
291          if (slot == JSSLOT_PROTO && !js_GetMutableScope(cx, obj)) {              bool ok = !!js_GetMutableScope(cx, obj);
292              JS_UNLOCK_OBJ(cx, obj);              JS_UNLOCK_OBJ(cx, obj);
293              return JS_FALSE;              if (!ok)
294                    return JS_FALSE;
295            }
296    
297            /*
298             * Regenerate property cache shape ids for all of the scopes along the
299             * old prototype chain to invalidate their property cache entries, in
300             * case any entries were filled by looking up starting from obj.
301             */
302            JSObject *oldproto = obj;
303            while (oldproto && OBJ_IS_NATIVE(oldproto)) {
304                JS_LOCK_OBJ(cx, oldproto);
305                JSScope *scope = OBJ_SCOPE(oldproto);
306                js_MakeScopeShapeUnique(cx, scope);
307                JSObject *tmp = STOBJ_GET_PROTO(scope->object);
308                JS_UNLOCK_OBJ(cx, oldproto);
309                oldproto = tmp;
310          }          }
         LOCKED_OBJ_SET_SLOT(obj, slot, JSVAL_NULL);  
         JS_UNLOCK_OBJ(cx, obj);  
         return JS_TRUE;  
311      }      }
312    
313      ssr.obj = obj;      if (!pobj || !checkForCycles) {
314      ssr.pobj = pobj;          if (slot == JSSLOT_PROTO)
315      ssr.slot = (uint16) slot;              STOBJ_SET_PROTO(obj, pobj);
316      ssr.errnum = (uint16) JSMSG_NOT_AN_ERROR;          else
317                STOBJ_SET_PARENT(obj, pobj);
318      rt = cx->runtime;      } else {
319      JS_LOCK_GC(rt);          /*
320      ssr.next = rt->setSlotRequests;           * Use the GC machinery to serialize access to all objects on the
321      rt->setSlotRequests = &ssr;           * prototype or parent chain.
322      for (;;) {           */
323          js_GC(cx, GC_SET_SLOT_REQUEST);          JSSetSlotRequest ssr;
324          JS_UNLOCK_GC(rt);          ssr.obj = obj;
325          if (!rt->setSlotRequests)          ssr.pobj = pobj;
326              break;          ssr.slot = (uint16) slot;
327            ssr.cycle = false;
328    
329            JSRuntime *rt = cx->runtime;
330          JS_LOCK_GC(rt);          JS_LOCK_GC(rt);
331      }          ssr.next = rt->setSlotRequests;
332            rt->setSlotRequests = &ssr;
333            for (;;) {
334                js_GC(cx, GC_SET_SLOT_REQUEST);
335                JS_UNLOCK_GC(rt);
336                if (!rt->setSlotRequests)
337                    break;
338                JS_LOCK_GC(rt);
339            }
340    
341      if (ssr.errnum != JSMSG_NOT_AN_ERROR) {          if (ssr.cycle) {
342          if (ssr.errnum == JSMSG_OUT_OF_MEMORY) {              JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
343              JS_ReportOutOfMemory(cx);                                   JSMSG_CYCLIC_VALUE,
         } else {  
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, ssr.errnum,  
344  #if JS_HAS_OBJ_PROTO_PROP  #if JS_HAS_OBJ_PROTO_PROP
345                                   object_props[slot].name                                   object_props[slot].name
346  #else  #else
# Line 322  Line 348 
348                                                          : js_parent_str                                                          : js_parent_str
349  #endif  #endif
350                                   );                                   );
351                return JS_FALSE;
352          }          }
         return JS_FALSE;  
     }  
   
     // Maintain the "any Array prototype has indexed properties hazard" flag.  
     if (slot == JSSLOT_PROTO &&  
         OBJ_IS_ARRAY(cx, pobj) &&  
         pobj->fslots[JSSLOT_ARRAY_LENGTH] != 0) {  
         rt->anyArrayProtoHasElement = JS_TRUE;  
353      }      }
354      return JS_TRUE;      return JS_TRUE;
355  }  }
# Line 363  Line 382 
382      JS_CHECK_RECURSION(cx, return NULL);      JS_CHECK_RECURSION(cx, return NULL);
383    
384      map = &cx->sharpObjectMap;      map = &cx->sharpObjectMap;
385        JS_ASSERT(map->depth >= 1);
386      table = map->table;      table = map->table;
387      hash = js_hash_object(obj);      hash = js_hash_object(obj);
388      hep = JS_HashTableRawLookup(table, hash, obj);      hep = JS_HashTableRawLookup(table, hash, obj);
# Line 376  Line 396 
396              return NULL;              return NULL;
397          }          }
398    
         /*  
          * Increment map->depth to protect js_EnterSharpObject from reentering  
          * itself badly.  Without this fix, if we reenter the basis case where  
          * map->depth == 0, when unwinding the inner call we will destroy the  
          * newly-created hash table and crash.  
          */  
         ++map->depth;  
399          ida = JS_Enumerate(cx, obj);          ida = JS_Enumerate(cx, obj);
         --map->depth;  
400          if (!ida)          if (!ida)
401              return NULL;              return NULL;
402    
# Line 401  Line 413 
413              if (ok) {              if (ok) {
414                  if (OBJ_IS_NATIVE(obj2) &&                  if (OBJ_IS_NATIVE(obj2) &&
415                      (attrs & (JSPROP_GETTER | JSPROP_SETTER))) {                      (attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
416                        JSScopeProperty *sprop = (JSScopeProperty *) prop;
417                      val = JSVAL_NULL;                      val = JSVAL_NULL;
418                      if (attrs & JSPROP_GETTER)                      if (attrs & JSPROP_GETTER)
419                          val = (jsval) ((JSScopeProperty*)prop)->getter;                          val = js_CastAsObjectJSVal(sprop->getter);
420                      if (attrs & JSPROP_SETTER) {                      if (attrs & JSPROP_SETTER) {
421                          if (val != JSVAL_NULL) {                          if (val != JSVAL_NULL) {
422                              /* Mark the getter, then set val to setter. */                              /* Mark the getter, then set val to setter. */
# Line 411  Line 424 
424                                                     NULL)                                                     NULL)
425                                    != NULL);                                    != NULL);
426                          }                          }
427                          val = (jsval) ((JSScopeProperty*)prop)->setter;                          val = js_CastAsObjectJSVal(sprop->setter);
428                      }                      }
429                  } else {                  } else {
430                      ok = OBJ_GET_PROPERTY(cx, obj, id, &val);                      ok = OBJ_GET_PROPERTY(cx, obj, id, &val);
# Line 459  Line 472 
472      char buf[20];      char buf[20];
473      size_t len;      size_t len;
474    
475      if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_ENTER_SHARP))      if (!JS_CHECK_OPERATION_LIMIT(cx))
476          return NULL;          return NULL;
477    
478      /* Set to null in case we return an early error. */      /* Set to null in case we return an early error. */
# Line 480  Line 493 
493      /* From this point the control must flow either through out: or bad:. */      /* From this point the control must flow either through out: or bad:. */
494      ida = NULL;      ida = NULL;
495      if (map->depth == 0) {      if (map->depth == 0) {
496            /*
497             * Although MarkSharpObjects tries to avoid invoking getters,
498             * it ends up doing so anyway under some circumstances; for
499             * example, if a wrapped object has getters, the wrapper will
500             * prevent MarkSharpObjects from recognizing them as such.
501             * This could lead to js_LeaveSharpObject being called while
502             * MarkSharpObjects is still working.
503             *
504             * Increment map->depth while we call MarkSharpObjects, to
505             * ensure that such a call doesn't free the hash table we're
506             * still using.
507             */
508            ++map->depth;
509          he = MarkSharpObjects(cx, obj, &ida);          he = MarkSharpObjects(cx, obj, &ida);
510            --map->depth;
511          if (!he)          if (!he)
512              goto bad;              goto bad;
513          JS_ASSERT((JS_PTR_TO_UINT32(he->value) & SHARP_BIT) == 0);          JS_ASSERT((JS_PTR_TO_UINT32(he->value) & SHARP_BIT) == 0);
# Line 752  Line 779 
779              }              }
780              if (OBJ_IS_NATIVE(obj2) &&              if (OBJ_IS_NATIVE(obj2) &&
781                  (attrs & (JSPROP_GETTER | JSPROP_SETTER))) {                  (attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
782                    JSScopeProperty *sprop = (JSScopeProperty *) prop;
783                  if (attrs & JSPROP_GETTER) {                  if (attrs & JSPROP_GETTER) {
784                      val[valcnt] = (jsval) ((JSScopeProperty *)prop)->getter;                      val[valcnt] = js_CastAsObjectJSVal(sprop->getter);
785                      gsopold[valcnt] =                      gsopold[valcnt] =
786                          ATOM_TO_STRING(cx->runtime->atomState.getterAtom);                          ATOM_TO_STRING(cx->runtime->atomState.getterAtom);
787                      gsop[valcnt] =                      gsop[valcnt] =
# Line 762  Line 790 
790                      valcnt++;                      valcnt++;
791                  }                  }
792                  if (attrs & JSPROP_SETTER) {                  if (attrs & JSPROP_SETTER) {
793                      val[valcnt] = (jsval) ((JSScopeProperty *)prop)->setter;                      val[valcnt] = js_CastAsObjectJSVal(sprop->setter);
794                      gsopold[valcnt] =                      gsopold[valcnt] =
795                          ATOM_TO_STRING(cx->runtime->atomState.setterAtom);                          ATOM_TO_STRING(cx->runtime->atomState.setterAtom);
796                      gsop[valcnt] =                      gsop[valcnt] =
# Line 1082  Line 1110 
1110      return !JSVAL_IS_NULL(*vp);      return !JSVAL_IS_NULL(*vp);
1111  }  }
1112    
1113    #ifdef JS_TRACER
1114    static jsval FASTCALL
1115    Object_p_valueOf(JSContext* cx, JSObject* obj, JSString *hint)
1116    {
1117        return OBJECT_TO_JSVAL(obj);
1118    }
1119    #endif
1120    
1121  /*  /*
1122   * Check whether principals subsumes scopeobj's principals, and return true   * Check whether principals subsumes scopeobj's principals, and return true
1123   * if so (or if scopeobj has no principals, for backward compatibility with   * if so (or if scopeobj has no principals, for backward compatibility with
# Line 1167  Line 1203 
1203          return principals->codebase;          return principals->codebase;
1204      }      }
1205    
1206      if (caller->regs && *caller->regs->pc == JSOP_EVAL) {      jsbytecode *pc = caller->regs->pc;
1207          JS_ASSERT(caller->regs->pc[JSOP_EVAL_LENGTH] == JSOP_LINENO);      if (caller->regs && js_GetOpcode(cx, caller->script, pc) == JSOP_EVAL) {
1208          *linenop = GET_UINT16(caller->regs->pc + JSOP_EVAL_LENGTH);          JS_ASSERT(js_GetOpcode(cx, caller->script, pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
1209            *linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH);
1210      } else {      } else {
1211          *linenop = js_FramePCToLineNumber(cx, caller);          *linenop = js_FramePCToLineNumber(cx, caller);
1212      }      }
1213      return caller->script->filename;      return caller->script->filename;
1214  }  }
1215    
1216    #ifndef EVAL_CACHE_CHAIN_LIMIT
1217    # define EVAL_CACHE_CHAIN_LIMIT 4
1218    #endif
1219    
1220    static inline JSScript **
1221    EvalCacheHash(JSContext *cx, JSString *str)
1222    {
1223        const jschar *s;
1224        size_t n;
1225        uint32 h;
1226    
1227        JSSTRING_CHARS_AND_LENGTH(str, s, n);
1228        if (n > 100)
1229            n = 100;
1230        for (h = 0; n; s++, n--)
1231            h = JS_ROTATE_LEFT32(h, 4) ^ *s;
1232    
1233        h *= JS_GOLDEN_RATIO;
1234        h >>= 32 - JS_EVAL_CACHE_SHIFT;
1235        return &JS_SCRIPTS_TO_GC(cx)[h];
1236    }
1237    
1238  static JSBool  static JSBool
1239  obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)  obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1240  {  {
1241      JSStackFrame *fp, *caller;      JSStackFrame *fp, *caller;
1242      JSBool indirectCall;      JSBool indirectCall;
1243      JSObject *scopeobj;      uint32 tcflags;
1244      JSString *str;      JSPrincipals *principals;
1245      const char *file;      const char *file;
1246      uintN line;      uintN line;
1247      JSPrincipals *principals;      JSString *str;
     uint32 tcflags;  
1248      JSScript *script;      JSScript *script;
1249      JSBool ok;      JSBool ok;
1250        JSScript **bucket = NULL;   /* avoid GCC warning with early decl&init */
1251  #if JS_HAS_EVAL_THIS_SCOPE  #if JS_HAS_EVAL_THIS_SCOPE
1252      JSObject *callerScopeChain = NULL, *callerVarObj = NULL;      JSObject *callerScopeChain = NULL, *callerVarObj = NULL;
1253      JSObject *setCallerScopeChain = NULL;      JSObject *setCallerScopeChain = NULL;
1254      JSBool setCallerVarObj = JS_FALSE;      JSBool setCallerVarObj = JS_FALSE;
1255  #endif  #endif
1256    
1257      fp = cx->fp;      fp = js_GetTopStackFrame(cx);
1258      caller = JS_GetScriptedCaller(cx, fp);      caller = js_GetScriptedCaller(cx, fp);
1259      indirectCall = (caller && caller->regs && *caller->regs->pc != JSOP_EVAL);      indirectCall = (caller && caller->regs && *caller->regs->pc != JSOP_EVAL);
1260    
1261      /*      /*
1262         * This call to js_GetWrappedObject is safe because of the security checks
1263         * we do below. However, the control flow below is confusing, so we double
1264         * check. There are two cases:
1265         * - Direct call: This object is never used. So unwrapping can't hurt.
1266         * - Indirect call: If this object isn't already the scope chain (which
1267         *   we're guaranteed to be allowed to access) then we do a security
1268         *   check.
1269         */
1270        obj = js_GetWrappedObject(cx, obj);
1271    
1272        /*
1273       * Ban all indirect uses of eval (global.foo = eval; global.foo(...)) and       * Ban all indirect uses of eval (global.foo = eval; global.foo(...)) and
1274       * calls that attempt to use a non-global object as the "with" object in       * calls that attempt to use a non-global object as the "with" object in
1275       * the former indirect case.       * the former indirect case.
1276       */       */
1277      scopeobj = OBJ_GET_PARENT(cx, obj);      {
1278      if (scopeobj) {          JSObject *parent = OBJ_GET_PARENT(cx, obj);
1279          scopeobj = js_GetWrappedObject(cx, obj);          if (indirectCall || parent) {
1280          scopeobj = OBJ_GET_PARENT(cx, scopeobj);              uintN flags = parent
1281      }                            ? JSREPORT_ERROR
1282      if (indirectCall || scopeobj) {                            : JSREPORT_STRICT | JSREPORT_WARNING;
1283          uintN flags = scopeobj              if (!JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage, NULL,
1284                        ? JSREPORT_ERROR                                                JSMSG_BAD_INDIRECT_CALL,
1285                        : JSREPORT_STRICT | JSREPORT_WARNING;                                                js_eval_str)) {
1286          if (!JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage, NULL,                  return JS_FALSE;
1287                                            JSMSG_BAD_INDIRECT_CALL,              }
                                           js_eval_str)) {  
             return JS_FALSE;  
1288          }          }
1289      }      }
1290    
# Line 1230  Line 1298 
1298       * object, then we need to provide one for the compiler to stick any       * object, then we need to provide one for the compiler to stick any
1299       * declared (var) variables into.       * declared (var) variables into.
1300       */       */
1301      if (caller && !caller->varobj && !js_GetCallObject(cx, caller, NULL))      if (caller && !caller->varobj && !js_GetCallObject(cx, caller))
1302          return JS_FALSE;          return JS_FALSE;
1303    
1304      /* eval no longer takes an optional trailing argument. */      /* Accept an optional trailing argument that overrides the scope object. */
1305      if (argc >= 2 &&      JSObject *scopeobj = NULL;
1306          !JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT,      if (argc >= 2) {
1307                                        js_GetErrorMessage, NULL,          if (!js_ValueToObject(cx, argv[1], &scopeobj))
1308                                        JSMSG_EVAL_ARITY)) {              return JS_FALSE;
1309          return JS_FALSE;          argv[1] = OBJECT_TO_JSVAL(scopeobj);
1310      }      }
1311    
1312      /* From here on, control must exit through label out with ok set. */      /* From here on, control must exit through label out with ok set. */
# Line 1259  Line 1327 
1327              }              }
1328              if (obj != callerScopeChain) {              if (obj != callerScopeChain) {
1329                  ok = js_CheckPrincipalsAccess(cx, obj,                  ok = js_CheckPrincipalsAccess(cx, obj,
1330                                                caller->script->principals,                                                JS_StackFramePrincipals(cx, caller),
1331                                                cx->runtime->atomState.evalAtom);                                                cx->runtime->atomState.evalAtom);
1332                  if (!ok)                  if (!ok)
1333                      goto out;                      goto out;
# Line 1299  Line 1367 
1367                  goto out;                  goto out;
1368              }              }
1369          }          }
1370        } else {
1371            scopeobj = js_GetWrappedObject(cx, scopeobj);
1372            OBJ_TO_INNER_OBJECT(cx, scopeobj);
1373            if (!scopeobj) {
1374                ok = JS_FALSE;
1375                goto out;
1376            }
1377            ok = js_CheckPrincipalsAccess(cx, scopeobj,
1378                                          JS_StackFramePrincipals(cx, caller),
1379                                          cx->runtime->atomState.evalAtom);
1380            if (!ok)
1381                goto out;
1382    
1383            scopeobj = js_NewWithObject(cx, scopeobj,
1384                                        JS_GetGlobalForObject(cx, scopeobj), -1);
1385            if (!scopeobj) {
1386                ok = JS_FALSE;
1387                goto out;
1388            }
1389            argv[1] = OBJECT_TO_JSVAL(scopeobj);
1390      }      }
1391    
1392      /* Ensure we compile this eval with the right object in the scope chain. */      /* Ensure we compile this eval with the right object in the scope chain. */
# Line 1308  Line 1396 
1396          goto out;          goto out;
1397      }      }
1398    
1399      str = JSVAL_TO_STRING(argv[0]);      tcflags = TCF_COMPILE_N_GO;
1400      if (caller) {      if (caller) {
1401            tcflags |= TCF_PUT_STATIC_LEVEL(caller->script->staticLevel + 1);
1402          principals = JS_EvalFramePrincipals(cx, fp, caller);          principals = JS_EvalFramePrincipals(cx, fp, caller);
1403          file = js_ComputeFilename(cx, caller, principals, &line);          file = js_ComputeFilename(cx, caller, principals, &line);
1404      } else {      } else {
1405            principals = NULL;
1406          file = NULL;          file = NULL;
1407          line = 0;          line = 0;
         principals = NULL;  
1408      }      }
1409    
1410      tcflags = TCF_COMPILE_N_GO;      str = JSVAL_TO_STRING(argv[0]);
1411      if (caller)      script = NULL;
1412          tcflags |= TCF_PUT_STATIC_DEPTH(caller->script->staticDepth + 1);  
1413      script = js_CompileScript(cx, scopeobj, caller, principals, tcflags,      /* Cache local eval scripts indexed by source qualified by scope. */
1414                                JSSTRING_CHARS(str), JSSTRING_LENGTH(str),      bucket = EvalCacheHash(cx, str);
1415                                NULL, file, line);      if (caller->fun) {
1416            uintN count = 0;
1417            JSScript **scriptp = bucket;
1418    
1419            EVAL_CACHE_METER(probe);
1420            while ((script = *scriptp) != NULL) {
1421                if ((script->flags & JSSF_SAVED_CALLER_FUN) &&
1422                    script->version == cx->version &&
1423                    (script->principals == principals ||
1424                     (principals->subsume(principals, script->principals) &&
1425                      script->principals->subsume(script->principals, principals)))) {
1426                    /*
1427                     * Get the prior (cache-filling) eval's saved caller function.
1428                     * See JSCompiler::compileScript in jsparse.cpp.
1429                     */
1430                    JSFunction *fun;
1431                    JS_GET_SCRIPT_FUNCTION(script, 0, fun);
1432    
1433                    if (fun == caller->fun) {
1434                        /*
1435                         * Get the source string passed for safekeeping in the
1436                         * atom map by the prior eval to JSCompiler::compileScript.
1437                         */
1438                        JSString *src = ATOM_TO_STRING(script->atomMap.vector[0]);
1439    
1440                        if (src == str || js_EqualStrings(src, str)) {
1441                            /*
1442                             * Source matches, qualify by comparing scopeobj to the
1443                             * COMPILE_N_GO-memoized parent of the first literal
1444                             * function or regexp object if any. If none, then this
1445                             * script has no compiled-in dependencies on the prior
1446                             * eval's scopeobj.
1447                             */
1448                            JSObjectArray *objarray = JS_SCRIPT_OBJECTS(script);
1449                            int i = 1;
1450                            if (objarray->length == 1) {
1451                                if (script->regexpsOffset != 0) {
1452                                    objarray = JS_SCRIPT_REGEXPS(script);
1453                                    i = 0;
1454                                } else {
1455                                    EVAL_CACHE_METER(noscope);
1456                                    i = -1;
1457                                }
1458                            }
1459                            if (i < 0 ||
1460                                STOBJ_GET_PARENT(objarray->vector[i]) == scopeobj) {
1461                                EVAL_CACHE_METER(hit);
1462                                *scriptp = script->u.nextToGC;
1463                                script->u.nextToGC = NULL;
1464                                break;
1465                            }
1466                        }
1467                    }
1468                }
1469    
1470                if (++count == EVAL_CACHE_CHAIN_LIMIT) {
1471                    script = NULL;
1472                    break;
1473                }
1474                EVAL_CACHE_METER(step);
1475                scriptp = &script->u.nextToGC;
1476            }
1477        }
1478    
1479      if (!script) {      if (!script) {
1480          ok = JS_FALSE;          script = JSCompiler::compileScript(cx, scopeobj, caller, principals, tcflags,
1481          goto out;                                             JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
1482                                               NULL, file, line, str);
1483            if (!script) {
1484                ok = JS_FALSE;
1485                goto out;
1486            }
1487      }      }
1488    
1489      if (argc < 2) {      if (argc < 2) {
# Line 1344  Line 1501 
1501      if (ok)      if (ok)
1502          ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);          ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);
1503    
1504      script->u.nextToGC = JS_SCRIPTS_TO_GC(cx);      script->u.nextToGC = *bucket;
1505      JS_SCRIPTS_TO_GC(cx) = script;      *bucket = script;
1506  #ifdef CHECK_SCRIPT_OWNER  #ifdef CHECK_SCRIPT_OWNER
1507      script->owner = NULL;      script->owner = NULL;
1508  #endif  #endif
# Line 1385  Line 1542 
1542      callbacks = JS_GetSecurityCallbacks(cx);      callbacks = JS_GetSecurityCallbacks(cx);
1543      if (callbacks && callbacks->findObjectPrincipals) {      if (callbacks && callbacks->findObjectPrincipals) {
1544          /* Skip over any obj_watch_* frames between us and the real subject. */          /* Skip over any obj_watch_* frames between us and the real subject. */
1545          caller = JS_GetScriptedCaller(cx, cx->fp);          caller = js_GetScriptedCaller(cx, NULL);
1546          if (caller) {          if (caller) {
1547              /*              /*
1548               * Only call the watch handler if the watcher is allowed to watch               * Only call the watch handler if the watcher is allowed to watch
# Line 1555  Line 1712 
1712  }  }
1713    
1714  #ifdef JS_TRACER  #ifdef JS_TRACER
1715  static int32 FASTCALL  static JSBool FASTCALL
1716  Object_p_hasOwnProperty(JSContext* cx, JSObject* obj, JSString *str)  Object_p_hasOwnProperty(JSContext* cx, JSObject* obj, JSString *str)
1717  {  {
1718      jsid id;      jsid id;
1719      jsval v;      jsval v;
1720    
1721      if (!js_ValueToStringId(cx, STRING_TO_JSVAL(str), &id))      if (!js_ValueToStringId(cx, STRING_TO_JSVAL(str), &id) ||
1722          return JSVAL_TO_BOOLEAN(JSVAL_VOID);          !js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &v)) {
1723      if (!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &v))          js_SetBuiltinError(cx);
1724          return JSVAL_TO_BOOLEAN(JSVAL_VOID);          return JSVAL_TO_BOOLEAN(JSVAL_VOID);
1725        }
1726    
1727      JS_ASSERT(JSVAL_IS_BOOLEAN(v));      JS_ASSERT(JSVAL_IS_BOOLEAN(v));
1728      return JSVAL_TO_BOOLEAN(v);      return JSVAL_TO_BOOLEAN(v);
1729  }  }
# Line 1599  Line 1758 
1758  }  }
1759    
1760  #ifdef JS_TRACER  #ifdef JS_TRACER
1761  static int32 FASTCALL  static JSBool FASTCALL
1762  Object_p_propertyIsEnumerable(JSContext* cx, JSObject* obj, JSString *str)  Object_p_propertyIsEnumerable(JSContext* cx, JSObject* obj, JSString *str)
1763  {  {
1764      jsid id = ATOM_TO_JSID(STRING_TO_JSVAL(str));      jsid id = ATOM_TO_JSID(STRING_TO_JSVAL(str));
1765      jsval v;      jsval v;
1766      if (!js_PropertyIsEnumerable(cx, obj, id, &v))  
1767        if (!js_PropertyIsEnumerable(cx, obj, id, &v)) {
1768            js_SetBuiltinError(cx);
1769          return JSVAL_TO_BOOLEAN(JSVAL_VOID);          return JSVAL_TO_BOOLEAN(JSVAL_VOID);
1770        }
1771    
1772      JS_ASSERT(JSVAL_IS_BOOLEAN(v));      JS_ASSERT(JSVAL_IS_BOOLEAN(v));
1773      return JSVAL_TO_BOOLEAN(v);      return JSVAL_TO_BOOLEAN(v);
1774  }  }
# Line 1654  Line 1817 
1817  }  }
1818    
1819  #if JS_HAS_GETTER_SETTER  #if JS_HAS_GETTER_SETTER
1820  static JSBool  JS_FRIEND_API(JSBool)
1821  obj_defineGetter(JSContext *cx, uintN argc, jsval *vp)  js_obj_defineGetter(JSContext *cx, uintN argc, jsval *vp)
1822  {  {
1823      jsval fval, junk;      jsval fval, junk;
1824      jsid id;      jsid id;
# Line 1683  Line 1846 
1846          return JS_FALSE;          return JS_FALSE;
1847      *vp = JSVAL_VOID;      *vp = JSVAL_VOID;
1848      return OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID,      return OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID,
1849                                 (JSPropertyOp) JSVAL_TO_OBJECT(fval),                                 js_CastAsPropertyOp(JSVAL_TO_OBJECT(fval)),
1850                                 JS_PropertyStub,                                 JS_PropertyStub,
1851                                 JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED,                                 JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED,
1852                                 NULL);                                 NULL);
1853  }  }
1854    
1855  static JSBool  JS_FRIEND_API(JSBool)
1856  obj_defineSetter(JSContext *cx, uintN argc, jsval *vp)  js_obj_defineSetter(JSContext *cx, uintN argc, jsval *vp)
1857  {  {
1858      jsval fval, junk;      jsval fval, junk;
1859      jsid id;      jsid id;
# Line 1719  Line 1882 
1882      *vp = JSVAL_VOID;      *vp = JSVAL_VOID;
1883      return OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID,      return OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID,
1884                                 JS_PropertyStub,                                 JS_PropertyStub,
1885                                 (JSPropertyOp) JSVAL_TO_OBJECT(fval),                                 js_CastAsPropertyOp(JSVAL_TO_OBJECT(fval)),
1886                                 JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED,                                 JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED,
1887                                 NULL);                                 NULL);
1888  }  }
# Line 1742  Line 1905 
1905          if (OBJ_IS_NATIVE(pobj)) {          if (OBJ_IS_NATIVE(pobj)) {
1906              sprop = (JSScopeProperty *) prop;              sprop = (JSScopeProperty *) prop;
1907              if (sprop->attrs & JSPROP_GETTER)              if (sprop->attrs & JSPROP_GETTER)
1908                  *vp = OBJECT_TO_JSVAL(sprop->getter);                  *vp = js_CastAsObjectJSVal(sprop->getter);
1909          }          }
1910          OBJ_DROP_PROPERTY(cx, pobj, prop);          OBJ_DROP_PROPERTY(cx, pobj, prop);
1911      }      }
# Line 1767  Line 1930 
1930          if (OBJ_IS_NATIVE(pobj)) {          if (OBJ_IS_NATIVE(pobj)) {
1931              sprop = (JSScopeProperty *) prop;              sprop = (JSScopeProperty *) prop;
1932              if (sprop->attrs & JSPROP_SETTER)              if (sprop->attrs & JSPROP_SETTER)
1933                  *vp = OBJECT_TO_JSVAL(sprop->setter);                  *vp = js_CastAsObjectJSVal(sprop->setter);
1934          }          }
1935          OBJ_DROP_PROPERTY(cx, pobj, prop);          OBJ_DROP_PROPERTY(cx, pobj, prop);
1936      }      }
# Line 1810  Line 1973 
1973  const char js_lookupSetter_str[] = "__lookupSetter__";  const char js_lookupSetter_str[] = "__lookupSetter__";
1974  #endif  #endif
1975    
1976    JS_DEFINE_TRCINFO_1(obj_valueOf,
1977        (3, (static, JSVAL,     Object_p_valueOf,               CONTEXT, THIS, STRING,  0, 0)))
1978  JS_DEFINE_TRCINFO_1(obj_hasOwnProperty,  JS_DEFINE_TRCINFO_1(obj_hasOwnProperty,
1979      (3, (static, BOOL_FAIL, Object_p_hasOwnProperty, CONTEXT, THIS, STRING,       0, 0)))      (3, (static, BOOL_FAIL, Object_p_hasOwnProperty,        CONTEXT, THIS, STRING,  0, 0)))
1980  JS_DEFINE_TRCINFO_1(obj_propertyIsEnumerable,  JS_DEFINE_TRCINFO_1(obj_propertyIsEnumerable,
1981      (3, (static, BOOL_FAIL, Object_p_propertyIsEnumerable, CONTEXT, THIS, STRING, 0, 0)))      (3, (static, BOOL_FAIL, Object_p_propertyIsEnumerable,  CONTEXT, THIS, STRING,  0, 0)))
1982    
1983  static JSFunctionSpec object_methods[] = {  static JSFunctionSpec object_methods[] = {
1984  #if JS_HAS_TOSOURCE  #if JS_HAS_TOSOURCE
# Line 1821  Line 1986 
1986  #endif  #endif
1987      JS_FN(js_toString_str,             obj_toString,                0,0),      JS_FN(js_toString_str,             obj_toString,                0,0),
1988      JS_FN(js_toLocaleString_str,       obj_toLocaleString,          0,0),      JS_FN(js_toLocaleString_str,       obj_toLocaleString,          0,0),
1989      JS_FN(js_valueOf_str,              obj_valueOf,                 0,0),      JS_TN(js_valueOf_str,              obj_valueOf,                 0,0,
1990              obj_valueOf_trcinfo),
1991  #if JS_HAS_OBJ_WATCHPOINT  #if JS_HAS_OBJ_WATCHPOINT
1992      JS_FN(js_watch_str,                obj_watch,                   2,0),      JS_FN(js_watch_str,                obj_watch,                   2,0),
1993      JS_FN(js_unwatch_str,              obj_unwatch,                 1,0),      JS_FN(js_unwatch_str,              obj_unwatch,                 1,0),
# Line 1832  Line 1998 
1998      JS_TN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable,    1,0,      JS_TN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable,    1,0,
1999            obj_propertyIsEnumerable_trcinfo),            obj_propertyIsEnumerable_trcinfo),
2000  #if JS_HAS_GETTER_SETTER  #if JS_HAS_GETTER_SETTER
2001      JS_FN(js_defineGetter_str,         obj_defineGetter,            2,0),      JS_FN(js_defineGetter_str,         js_obj_defineGetter,         2,0),
2002      JS_FN(js_defineSetter_str,         obj_defineSetter,            2,0),      JS_FN(js_defineSetter_str,         js_obj_defineSetter,         2,0),
2003      JS_FN(js_lookupGetter_str,         obj_lookupGetter,            1,0),      JS_FN(js_lookupGetter_str,         obj_lookupGetter,            1,0),
2004      JS_FN(js_lookupSetter_str,         obj_lookupSetter,            1,0),      JS_FN(js_lookupSetter_str,         obj_lookupSetter,            1,0),
2005  #endif  #endif
# Line 1858  Line 2024 
2024      }      }
2025      if (!obj) {      if (!obj) {
2026          JS_ASSERT(!argc || JSVAL_IS_NULL(argv[0]) || JSVAL_IS_VOID(argv[0]));          JS_ASSERT(!argc || JSVAL_IS_NULL(argv[0]) || JSVAL_IS_VOID(argv[0]));
2027          if (cx->fp->flags & JSFRAME_CONSTRUCTING)          if (JS_IsConstructing(cx))
2028              return JS_TRUE;              return JS_TRUE;
2029          obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0);          obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0);
2030          if (!obj)          if (!obj)
# Line 1868  Line 2034 
2034      return JS_TRUE;      return JS_TRUE;
2035  }  }
2036    
2037    static inline bool
2038    InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto,
2039                       JSObjectOps* ops)
2040    {
2041        JS_ASSERT(OPS_IS_NATIVE(ops));
2042        JS_ASSERT(proto == OBJ_GET_PROTO(cx, obj));
2043    
2044        JSClass* protoclasp;
2045        JSClass* clasp = OBJ_GET_CLASS(cx, obj);
2046    
2047        /*
2048         * Share proto's map only if it has the same JSObjectOps, and only if
2049         * proto's class has the same private and reserved slots as obj's map
2050         * and class have.  We assume that if prototype and object are of the
2051         * same class, they always have the same number of computed reserved
2052         * slots (returned via clasp->reserveSlots); otherwise, prototype and
2053         * object classes must have the same (null or not) reserveSlots hook.
2054         */
2055        if (proto &&
2056            proto->map->ops == ops &&
2057            ((protoclasp = OBJ_GET_CLASS(cx, proto)) == clasp ||
2058             (!((protoclasp->flags ^ clasp->flags) &
2059                (JSCLASS_HAS_PRIVATE |
2060                 (JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) &&
2061              protoclasp->reserveSlots == clasp->reserveSlots)))
2062        {
2063            js_HoldScope(OBJ_SCOPE(proto));
2064            obj->map = proto->map;
2065            return true;
2066        }
2067    
2068        JSScope *scope = js_NewScope(cx, ops, clasp, obj);
2069        if (!scope)
2070            goto bad;
2071    
2072        /* Let js_NewScope set freeslot so as to reserve slots. */
2073        JS_ASSERT(scope->freeslot >= JSSLOT_PRIVATE);
2074        if (scope->freeslot > JS_INITIAL_NSLOTS &&
2075            !js_ReallocSlots(cx, obj, scope->freeslot, JS_TRUE)) {
2076            js_DestroyScope(cx, scope);
2077            goto bad;
2078        }
2079        obj->map = &scope->map;
2080        return true;
2081    
2082      bad:
2083        /* Ensure that the map field is initialized for GC. */
2084        obj->map = NULL;
2085        return false;
2086    }
2087    
2088    #ifdef JS_TRACER
2089    
2090    static inline JSObject*
2091    NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto, JSObject *parent)
2092    {
2093        JS_ASSERT(JS_ON_TRACE(cx));
2094        JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
2095        if (!obj)
2096            return NULL;
2097    
2098        obj->classword = jsuword(clasp);
2099        obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
2100        obj->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent);
2101        for (unsigned i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
2102            obj->fslots[i] = JSVAL_VOID;
2103    
2104        obj->dslots = NULL;
2105        return InitScopeForObject(cx, obj, proto, &js_ObjectOps) ? obj : NULL;
2106    }
2107    
2108    JSObject* FASTCALL
2109    js_Object_tn(JSContext* cx, JSObject* proto)
2110    {
2111        return NewNativeObject(cx, &js_ObjectClass, proto, JSVAL_TO_OBJECT(proto->fslots[JSSLOT_PARENT]));
2112    }
2113    
2114    JS_DEFINE_TRCINFO_1(js_Object,
2115        (2, (extern, CONSTRUCTOR_RETRY, js_Object_tn, CONTEXT, CALLEE_PROTOTYPE, 0, 0)))
2116    
2117    JSObject* FASTCALL
2118    js_NewInstance(JSContext *cx, JSClass *clasp, JSObject *ctor)
2119    {
2120        JS_ASSERT(HAS_FUNCTION_CLASS(ctor));
2121    
2122        JSAtom *atom = cx->runtime->atomState.classPrototypeAtom;
2123    
2124        JSScope *scope = OBJ_SCOPE(ctor);
2125    #ifdef JS_THREADSAFE
2126        if (scope->title.ownercx != cx)
2127            return NULL;
2128    #endif
2129        if (scope->object != ctor) {
2130            scope = js_GetMutableScope(cx, ctor);
2131            if (!scope)
2132                return NULL;
2133        }
2134    
2135        JSScopeProperty *sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));
2136        jsval pval = sprop ? STOBJ_GET_SLOT(ctor, sprop->slot) : JSVAL_HOLE;
2137    
2138        JSObject *proto;
2139        if (!JSVAL_IS_PRIMITIVE(pval)) {
2140            /* An object in ctor.prototype, let's use it as the new instance's proto. */
2141            proto = JSVAL_TO_OBJECT(pval);
2142        } else if (pval == JSVAL_HOLE) {
2143            /* No ctor.prototype yet, inline and optimize fun_resolve's prototype code. */
2144            proto = js_NewObject(cx, clasp, NULL, OBJ_GET_PARENT(cx, ctor), 0);
2145            if (!proto)
2146                return NULL;
2147            if (!js_SetClassPrototype(cx, ctor, proto, JSPROP_ENUMERATE | JSPROP_PERMANENT))
2148                return NULL;
2149        } else {
2150            /* Primitive value in .prototype means we use Object.prototype for proto. */
2151            if (!js_GetClassPrototype(cx, JSVAL_TO_OBJECT(ctor->fslots[JSSLOT_PARENT]),
2152                                      INT_TO_JSID(JSProto_Object), &proto)) {
2153                return NULL;
2154            }
2155        }
2156    
2157        return NewNativeObject(cx, clasp, proto, JSVAL_TO_OBJECT(ctor->fslots[JSSLOT_PARENT]));
2158    }
2159    
2160    JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_NewInstance, CONTEXT, CLASS, OBJECT, 0, 0)
2161    
2162    #else  /* !JS_TRACER */
2163    
2164    # define js_Object_trcinfo NULL
2165    
2166    #endif /* !JS_TRACER */
2167    
2168    /*
2169     * Given pc pointing after a property accessing bytecode, return true if the
2170     * access is "object-detecting" in the sense used by web scripts, e.g., when
2171     * checking whether document.all is defined.
2172     */
2173    static JS_REQUIRES_STACK JSBool
2174    Detecting(JSContext *cx, jsbytecode *pc)
2175    {
2176        JSScript *script;
2177        jsbytecode *endpc;
2178        JSOp op;
2179        JSAtom *atom;
2180    
2181        script = cx->fp->script;
2182        endpc = script->code + script->length;
2183        for (;; pc += js_CodeSpec[op].length) {
2184            JS_ASSERT(pc < endpc);
2185    
2186            /* General case: a branch or equality op follows the access. */
2187            op = js_GetOpcode(cx, script, pc);
2188            if (js_CodeSpec[op].format & JOF_DETECTING)
2189                return JS_TRUE;
2190    
2191            switch (op) {
2192              case JSOP_NULL:
2193                /*
2194                 * Special case #1: handle (document.all == null).  Don't sweat
2195                 * about JS1.2's revision of the equality operators here.
2196                 */
2197                if (++pc < endpc) {
2198                    op = js_GetOpcode(cx, script, pc);
2199                    return *pc == JSOP_EQ || *pc == JSOP_NE;
2200                }
2201                return JS_FALSE;
2202    
2203              case JSOP_NAME:
2204                /*
2205                 * Special case #2: handle (document.all == undefined).  Don't
2206                 * worry about someone redefining undefined, which was added by
2207                 * Edition 3, so is read/write for backward compatibility.
2208                 */
2209                GET_ATOM_FROM_BYTECODE(script, pc, 0, atom);
2210                if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] &&
2211                    (pc += js_CodeSpec[op].length) < endpc) {
2212                    op = js_GetOpcode(cx, script, pc);
2213                    return op == JSOP_EQ || op == JSOP_NE ||
2214                           op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
2215                }
2216                return JS_FALSE;
2217    
2218              default:
2219                /*
2220                 * At this point, anything but an extended atom index prefix means
2221                 * we're not detecting.
2222                 */
2223                if (!(js_CodeSpec[op].format & JOF_INDEXBASE))
2224                    return JS_FALSE;
2225                break;
2226            }
2227        }
2228    }
2229    
2230    /*
2231     * Infer lookup flags from the currently executing bytecode. This does
2232     * not attempt to infer JSRESOLVE_WITH, because the current bytecode
2233     * does not indicate whether we are in a with statement. Return defaultFlags
2234     * if a currently executing bytecode cannot be determined.
2235     */
2236    static uintN
2237    InferFlags(JSContext *cx, uintN defaultFlags)
2238    {
2239        JSStackFrame *fp;
2240        jsbytecode *pc;
2241        const JSCodeSpec *cs;
2242        uint32 format;
2243        uintN flags = 0;
2244    
2245        fp = js_GetTopStackFrame(cx);
2246        if (!fp || !fp->regs)
2247            return defaultFlags;
2248        pc = fp->regs->pc;
2249        cs = &js_CodeSpec[js_GetOpcode(cx, fp->script, pc)];
2250        format = cs->format;
2251        if (JOF_MODE(format) != JOF_NAME)
2252            flags |= JSRESOLVE_QUALIFIED;
2253        if ((format & (JOF_SET | JOF_FOR)) ||
2254            (fp->flags & JSFRAME_ASSIGNING)) {
2255            flags |= JSRESOLVE_ASSIGNING;
2256        } else {
2257            pc += cs->length;
2258            if (pc < cx->fp->script->code + cx->fp->script->length && Detecting(cx, pc))
2259                flags |= JSRESOLVE_DETECTING;
2260        }
2261        if (format & JOF_DECLARING)
2262            flags |= JSRESOLVE_DECLARING;
2263        return flags;
2264    }
2265    
2266  /*  /*
2267   * ObjectOps and Class for with-statement stack objects.   * ObjectOps and Class for with-statement stack objects.
2268   */   */
# Line 1875  Line 2270 
2270  with_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,  with_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
2271                      JSProperty **propp)                      JSProperty **propp)
2272  {  {
2273        /* Fixes bug 463997 */
2274        uintN flags = cx->resolveFlags;
2275        if (flags == JSRESOLVE_INFER)
2276            flags = InferFlags(cx, flags);
2277        flags |= JSRESOLVE_WITH;
2278        JSAutoResolveFlags rf(cx, flags);
2279      JSObject *proto = OBJ_GET_PROTO(cx, obj);      JSObject *proto = OBJ_GET_PROTO(cx, obj);
2280      if (!proto)      if (!proto)
2281          return js_LookupProperty(cx, obj, id, objp, propp);          return js_LookupProperty(cx, obj, id, objp, propp);
# Line 1967  Line 2368 
2368  }  }
2369    
2370  JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {  JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
2371      js_NewObjectMap,        js_DestroyObjectMap,      NULL,
2372      with_LookupProperty,    js_DefineProperty,      with_LookupProperty,    js_DefineProperty,
2373      with_GetProperty,       with_SetProperty,      with_GetProperty,       with_SetProperty,
2374      with_GetAttributes,     with_SetAttributes,      with_GetAttributes,     with_SetAttributes,
# Line 1975  Line 2376 
2376      with_Enumerate,         with_CheckAccess,      with_Enumerate,         with_CheckAccess,
2377      with_ThisObject,        NATIVE_DROP_PROPERTY,      with_ThisObject,        NATIVE_DROP_PROPERTY,
2378      NULL,                   NULL,      NULL,                   NULL,
2379      NULL,                   NULL,      NULL,                   js_TraceObject,
2380      js_SetProtoOrParent,    js_SetProtoOrParent,      js_Clear,               NULL,
2381      js_TraceObject,         js_Clear,      NULL
     NULL,                   NULL  
2382  };  };
2383    
2384  static JSObjectOps *  static JSObjectOps *
# Line 1996  Line 2396 
2396      0,0,0,0,0,0,0      0,0,0,0,0,0,0
2397  };  };
2398    
2399  JSObject *  JS_REQUIRES_STACK JSObject *
2400  js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)  js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
2401  {  {
2402      JSObject *obj;      JSObject *obj;
# Line 2012  Line 2412 
2412  JSObject *  JSObject *
2413  js_NewBlockObject(JSContext *cx)  js_NewBlockObject(JSContext *cx)
2414  {  {
     JSObject *obj;  
     JSBool ok;  
   
2415      /*      /*
2416       * Null obj's proto slot so that Object.prototype.* does not pollute block       * Null obj's proto slot so that Object.prototype.* does not pollute block
2417       * scopes.  Make sure obj has its own scope too, since clearing proto does       * scopes and to give the block object its own scope.
      * not affect OBJ_SCOPE(obj).  
2418       */       */
2419      obj = js_NewObject(cx, &js_BlockClass, NULL, NULL, 0);      JSObject *blockObj = js_NewObjectWithGivenProto(cx, &js_BlockClass,
2420      if (!obj)                                                      NULL, NULL, 0);
2421          return NULL;      JS_ASSERT_IF(blockObj, !OBJ_IS_CLONED_BLOCK(blockObj));
2422      JS_LOCK_OBJ(cx, obj);      return blockObj;
     ok = js_GetMutableScope(cx, obj) != NULL;  
     JS_UNLOCK_OBJ(cx, obj);  
     if (!ok)  
         return NULL;  
     OBJ_CLEAR_PROTO(cx, obj);  
     return obj;  
2423  }  }
2424    
2425  JSObject *  JSObject *
# Line 2047  Line 2437 
2437      STOBJ_SET_SLOT(clone, JSSLOT_BLOCK_DEPTH,      STOBJ_SET_SLOT(clone, JSSLOT_BLOCK_DEPTH,
2438                     OBJ_GET_SLOT(cx, proto, JSSLOT_BLOCK_DEPTH));                     OBJ_GET_SLOT(cx, proto, JSSLOT_BLOCK_DEPTH));
2439      JS_ASSERT(OBJ_IS_CLONED_BLOCK(clone));      JS_ASSERT(OBJ_IS_CLONED_BLOCK(clone));
2440        JS_ASSERT(OBJ_SCOPE(clone)->object == proto);
2441      return clone;      return clone;
2442  }  }
2443    
2444  JSBool  JS_REQUIRES_STACK JSBool
2445  js_PutBlockObject(JSContext *cx, JSBool normalUnwind)  js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
2446  {  {
2447      JSStackFrame *fp;      JSStackFrame *fp;
# Line 2069  Line 2460 
2460      /*      /*
2461       * Block objects should never be exposed to scripts. Thus the clone should       * Block objects should never be exposed to scripts. Thus the clone should
2462       * not own the property map and rather always share it with the prototype       * not own the property map and rather always share it with the prototype
2463       * object. This allows to skip updating OBJ_SCOPE(obj)->map.freeslot after       * object. This allows us to skip updating OBJ_SCOPE(obj)->freeslot after
2464       * we copy the stack slots into reserved slots.       * we copy the stack slots into reserved slots.
2465       */       */
2466      JS_ASSERT(OBJ_SCOPE(obj)->object != obj);      JS_ASSERT(OBJ_SCOPE(obj)->object != obj);
# Line 2174  Line 2565 
2565      return NO_PARENT_INDEX;      return NO_PARENT_INDEX;
2566  }  }
2567    
2568  static JSBool  JSBool
2569  block_xdrObject(JSXDRState *xdr, JSObject **objp)  js_XDRBlockObject(JSXDRState *xdr, JSObject **objp)
2570  {  {
2571      JSContext *cx;      JSContext *cx;
2572      uint32 parentId;      uint32 parentId;
# Line 2276  Line 2667 
2667          if (xdr->mode == JSXDR_DECODE) {          if (xdr->mode == JSXDR_DECODE) {
2668              if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom),              if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom),
2669                                           JSVAL_VOID, NULL, NULL,                                           JSVAL_VOID, NULL, NULL,
2670                                           JSPROP_ENUMERATE | JSPROP_PERMANENT,                                           JSPROP_ENUMERATE | JSPROP_PERMANENT |
2671                                             JSPROP_SHARED,
2672                                           SPROP_HAS_SHORTID, shortid, NULL)) {                                           SPROP_HAS_SHORTID, shortid, NULL)) {
2673                  ok = JS_FALSE;                  ok = JS_FALSE;
2674                  break;                  break;
# Line 2288  Line 2680 
2680      return ok;      return ok;
2681  }  }
2682    
 #else  
 # define block_xdrObject NULL  
2683  #endif  #endif
2684    
2685  static uint32  static uint32
# Line 2300  Line 2690 
2690    
2691  JSClass js_BlockClass = {  JSClass js_BlockClass = {
2692      "Block",      "Block",
2693      JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |      JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS,
     JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_CACHED_PROTO(JSProto_Block),  
2694      JS_PropertyStub,  JS_PropertyStub,  block_getProperty, block_setProperty,      JS_PropertyStub,  JS_PropertyStub,  block_getProperty, block_setProperty,
2695      JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,    JS_FinalizeStub,      JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,    JS_FinalizeStub,
2696      NULL, NULL, NULL, NULL, block_xdrObject, NULL, NULL, block_reserveSlots      NULL, NULL, NULL, NULL, NULL, NULL, NULL, block_reserveSlots
2697  };  };
2698    
 JSObject*  
 js_InitBlockClass(JSContext *cx, JSObject* obj)  
 {  
     JSObject *proto;  
   
     proto = JS_InitClass(cx, obj, NULL, &js_BlockClass, NULL, 0, NULL,  
                          NULL, NULL, NULL);  
     if (!proto)  
         return NULL;  
   
     OBJ_CLEAR_PROTO(cx, proto);  
     return proto;  
 }  
   
2699  JSObject *  JSObject *
2700  js_InitEval(JSContext *cx, JSObject *obj)  js_InitEval(JSContext *cx, JSObject *obj)
2701  {  {
# Line 2336  Line 2711 
2711  JSObject *  JSObject *
2712  js_InitObjectClass(JSContext *cx, JSObject *obj)  js_InitObjectClass(JSContext *cx, JSObject *obj)
2713  {  {
2714      return JS_InitClass(cx, obj, NULL, &js_ObjectClass, js_Object, 1,      return js_InitClass(cx, obj, NULL, &js_ObjectClass, js_Object, 1,
2715                          object_props, object_methods, NULL,                          object_props, object_methods, NULL, object_static_methods);
                         object_static_methods);  
2716  }  }
2717    
2718  void  JSObject *
2719  js_InitObjectMap(JSObjectMap *map, jsrefcount nrefs, JSObjectOps *ops,  js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
2720                   JSClass *clasp)               JSClass *clasp, JSNative constructor, uintN nargs,
2721  {               JSPropertySpec *ps, JSFunctionSpec *fs,
2722      map->nrefs = nrefs;               JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
     map->ops = ops;  
     map->freeslot = JSSLOT_FREE(clasp);  
 }  
   
 JSObjectMap *  
 js_NewObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,  
                 JSClass *clasp, JSObject *obj)  
2723  {  {
2724      return (JSObjectMap *) js_NewScope(cx, nrefs, ops, clasp, obj);      JSAtom *atom;
2725  }      JSProtoKey key;
2726        JSObject *proto, *ctor;
2727        JSTempValueRooter tvr;
2728        jsval cval, rval;
2729        JSBool named;
2730        JSFunction *fun;
2731    
2732  void      atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
2733  js_DestroyObjectMap(JSContext *cx, JSObjectMap *map)      if (!atom)
2734  {          return NULL;
     js_DestroyScope(cx, (JSScope *)map);  
 }  
2735    
2736  JSObjectMap *      /*
2737  js_HoldObjectMap(JSContext *cx, JSObjectMap *map)       * When initializing a standard class, if no parent_proto (grand-proto of
2738  {       * instances of the class, parent-proto of the class's prototype object)
2739      JS_ASSERT(map->nrefs >= 0);       * is given, we must use Object.prototype if it is available.  Otherwise,
2740      JS_ATOMIC_INCREMENT(&map->nrefs);       * we could look up the wrong binding for a class name in obj.  Example:
2741      return map;       *
2742  }       *   String = Array;
2743         *   print("hi there".join);
2744         *
2745         * should print undefined, not Array.prototype.join.  This is required by
2746         * ECMA-262, alas.  It might have been better to make String readonly and
2747         * permanent in the global object, instead -- but that's too big a change
2748         * to swallow at this point.
2749         */
2750        key = JSCLASS_CACHED_PROTO_KEY(clasp);
2751        if (key != JSProto_Null &&
2752            !parent_proto &&
2753            !js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
2754                                  &parent_proto)) {
2755            return NULL;
2756        }
2757    
2758  JSObjectMap *      /* Create a prototype object for this class. */
2759  js_DropObjectMap(JSContext *cx, JSObjectMap *map, JSObject *obj)      proto = js_NewObject(cx, clasp, parent_proto, obj, 0);
2760  {      if (!proto)
     JS_ASSERT(map->nrefs > 0);  
     JS_ATOMIC_DECREMENT(&map->nrefs);  
     if (map->nrefs == 0) {  
         map->ops->destroyObjectMap(cx, map);  
2761          return NULL;          return NULL;
2762    
2763        /* After this point, control must exit via label bad or out. */
2764        JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr);
2765    
2766        if (!constructor) {
2767            /*
2768             * Lacking a constructor, name the prototype (e.g., Math) unless this
2769             * class (a) is anonymous, i.e. for internal use only; (b) the class
2770             * of obj (the global object) is has a reserved slot indexed by key;
2771             * and (c) key is not the null key.
2772             */
2773            if ((clasp->flags & JSCLASS_IS_ANONYMOUS) &&
2774                (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL) &&
2775                key != JSProto_Null) {
2776                named = JS_FALSE;
2777            } else {
2778                named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
2779                                            OBJECT_TO_JSVAL(proto),
2780                                            JS_PropertyStub, JS_PropertyStub,
2781                                            (clasp->flags & JSCLASS_IS_ANONYMOUS)
2782                                            ? JSPROP_READONLY | JSPROP_PERMANENT
2783                                            : 0,
2784                                            NULL);
2785                if (!named)
2786                    goto bad;
2787            }
2788    
2789            ctor = proto;
2790        } else {
2791            /* Define the constructor function in obj's scope. */
2792            fun = js_DefineFunction(cx, obj, atom, constructor, nargs,
2793                                    JSFUN_STUB_GSOPS);
2794            named = (fun != NULL);
2795            if (!fun)
2796                goto bad;
2797    
2798            /*
2799             * Remember the class this function is a constructor for so that
2800             * we know to create an object of this class when we call the
2801             * constructor.
2802             */
2803            FUN_CLASP(fun) = clasp;
2804    
2805            /*
2806             * Optionally construct the prototype object, before the class has
2807             * been fully initialized.  Allow the ctor to replace proto with a
2808             * different object, as is done for operator new -- and as at least
2809             * XML support requires.
2810             */
2811            ctor = FUN_OBJECT(fun);
2812            if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) {
2813                cval = OBJECT_TO_JSVAL(ctor);
2814                if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval))
2815                    goto bad;
2816                if (!JSVAL_IS_PRIMITIVE(rval) && JSVAL_TO_OBJECT(rval) != proto)
2817                    proto = JSVAL_TO_OBJECT(rval);
2818            }
2819    
2820            /* Connect constructor and prototype by named properties. */
2821            if (!js_SetClassPrototype(cx, ctor, proto,
2822                                      JSPROP_READONLY | JSPROP_PERMANENT)) {
2823                goto bad;
2824            }
2825    
2826            /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
2827            if (OBJ_GET_CLASS(cx, ctor) == clasp)
2828                OBJ_SET_PROTO(cx, ctor, proto);
2829      }      }
2830      if (MAP_IS_NATIVE(map) && ((JSScope *)map)->object == obj)  
2831          ((JSScope *)map)->object = NULL;      /* Add properties and methods to the prototype and the constructor. */
2832      return map;      if ((ps && !JS_DefineProperties(cx, proto, ps)) ||
2833            (fs && !JS_DefineFunctions(cx, proto, fs)) ||
2834            (static_ps && !JS_DefineProperties(cx, ctor, static_ps)) ||
2835            (static_fs && !JS_DefineFunctions(cx, ctor, static_fs))) {
2836            goto bad;
2837        }
2838    
2839        /* If this is a standard class, cache its prototype. */
2840        if (key != JSProto_Null && !js_SetClassObject(cx, obj, key, ctor))
2841            goto bad;
2842    
2843    out:
2844        JS_POP_TEMP_ROOT(cx, &tvr);
2845        return proto;
2846    
2847    bad:
2848        if (named)
2849            (void) OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &rval);
2850        proto = NULL;
2851        goto out;
2852  }  }
2853    
2854  static void  static void
# Line 2568  Line 3034 
3034  js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,  js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
3035                             JSObject *parent, uintN objectSize)                             JSObject *parent, uintN objectSize)
3036  {  {
     JSObject *obj;  
     JSObjectOps *ops;  
     JSObjectMap *map;  
     JSClass *protoclasp;  
     uint32 nslots, i;  
     JSTempValueRooter tvr;  
   
3037  #ifdef INCLUDE_MOZILLA_DTRACE  #ifdef INCLUDE_MOZILLA_DTRACE
3038      if (JAVASCRIPT_OBJECT_CREATE_START_ENABLED())      if (JAVASCRIPT_OBJECT_CREATE_START_ENABLED())
3039          jsdtrace_object_create_start(cx->fp, clasp);          jsdtrace_object_create_start(cx->fp, clasp);
# Line 2591  Line 3050 
3050          objectSize = sizeof(JSObject);          objectSize = sizeof(JSObject);
3051      }      }
3052    
3053        /* Assert that the class is a proper class. */
3054        JS_ASSERT_IF(clasp->flags & JSCLASS_IS_EXTENDED,
3055                     ((JSExtendedClass *)clasp)->equality);
3056    
3057        /* Always call the class's getObjectOps hook if it has one. */
3058        JSObjectOps *ops = clasp->getObjectOps
3059                           ? clasp->getObjectOps(cx, clasp)
3060                           : &js_ObjectOps;
3061    
3062      /*      /*
3063       * Allocate an object from the GC heap and initialize all its fields before       * Allocate an object from the GC heap and initialize all its fields before
3064       * doing any operation that can potentially trigger GC.       * doing any operation that can potentially trigger GC.
3065       */       */
3066      obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, objectSize);      JSObject *obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, objectSize);
3067      if (!obj)      if (!obj)
3068          goto earlybad;          goto out;
   
     obj->map = NULL;  
     obj->dslots = NULL;  
3069    
3070      /*      /*
3071       * Set the class slot with the initial value of the system and delegate       * Set the class slot with the initial value of the system and delegate
# Line 2611  Line 3076 
3076      JS_ASSERT(!STOBJ_IS_DELEGATE(obj));      JS_ASSERT(!STOBJ_IS_DELEGATE(obj));
3077      JS_ASSERT(!STOBJ_IS_SYSTEM(obj));      JS_ASSERT(!STOBJ_IS_SYSTEM(obj));
3078    
3079      /* Set the proto and parent properties. */      obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
3080      STOBJ_SET_PROTO(obj, proto);  
3081      STOBJ_SET_PARENT(obj, parent);      /*
3082         * Default parent to the parent of the prototype, which was set from
3083         * the parent of the prototype's constructor.
3084         */
3085        obj->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL((!parent && proto)
3086                                                     ? OBJ_GET_PARENT(cx, proto)
3087                                                     : parent);
3088    
3089      /* Initialize the remaining fixed slots. */      /* Initialize the remaining fixed slots. */
3090      for (i = JSSLOT_PRIVATE; i != JS_INITIAL_NSLOTS; ++i)      for (uint32 i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
3091          obj->fslots[i] = JSVAL_VOID;          obj->fslots[i] = JSVAL_VOID;
3092    
3093        obj->dslots = NULL;
3094    
3095        if (OPS_IS_NATIVE(ops)) {
3096            if (!InitScopeForObject(cx, obj, proto, ops)) {
3097                obj = NULL;
3098                goto out;
3099            }
3100        } else {
3101            JS_ASSERT(ops->objectMap->ops == ops);
3102            obj->map = const_cast<JSObjectMap *>(ops->objectMap);
3103        }
3104    
3105  #ifdef DEBUG  #ifdef DEBUG
3106      memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,      memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
3107             objectSize - sizeof(JSObject));             objectSize - sizeof(JSObject));
3108  #endif  #endif
3109    
3110      /*      /* Check that the newborn root still holds the object. */
3111       * Root obj to prevent it from being collected out from under this call to      JS_ASSERT_IF(!cx->localRootStack, cx->weakRoots.newborn[GCX_OBJECT] == obj);
      * js_NewObject. There's a possibilty of GC under the objectHook call-out  
      * further below.  
      */  
     JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);  
   
     /* Always call the class's getObjectOps hook if it has one. */  
     ops = clasp->getObjectOps  
           ? clasp->getObjectOps(cx, clasp)  
           : &js_ObjectOps;  
3112    
3113      /*      /*
3114       * Default parent to the parent of the prototype, which was set from       * Do not call debug hooks on trace, because we might be in a non-_FAIL
3115       * the parent of the prototype's constructor.       * builtin. See bug 481444.
3116       */       */
3117      if (proto && !parent)      if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
3118          STOBJ_SET_PARENT(obj, OBJ_GET_PARENT(cx, proto));          JSAutoTempValueRooter tvr(cx, obj);
   
     /*  
      * Share proto's map only if it has the same JSObjectOps, and only if  
      * proto's class has the same private and reserved slots as obj's map  
      * and class have.  We assume that if prototype and object are of the  
      * same class, they always have the same number of computed reserved  
      * slots (returned via clasp->reserveSlots); otherwise, prototype and  
      * object classes must have the same (null or not) reserveSlots hook.  
      */  
     if (proto &&  
         (map = proto->map)->ops == ops &&  
         ((protoclasp = OBJ_GET_CLASS(cx, proto)) == clasp ||  
          (!((protoclasp->flags ^ clasp->flags) &  
             (JSCLASS_HAS_PRIVATE |  
              (JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) &&  
           protoclasp->reserveSlots == clasp->reserveSlots)))  
     {  
         /* Share the given prototype's map. */  
         obj->map = js_HoldObjectMap(cx, map);  
     } else {  
         map = ops->newObjectMap(cx, 1, ops, clasp, obj);  
         if (!map)  
             goto bad;  
         obj->map = map;  
   
         /* Let ops->newObjectMap set freeslot so as to reserve slots. */  
         nslots = map->freeslot;  
         JS_ASSERT(nslots >= JSSLOT_PRIVATE);  
         if (nslots > JS_INITIAL_NSLOTS &&  
             !js_ReallocSlots(cx, obj, nslots, JS_TRUE)) {  
             js_DropObjectMap(cx, map, obj);  
             obj->map = NULL;  
             goto bad;  
         }  
     }  
   
     if (cx->debugHooks->objectHook) {  
3119          JS_KEEP_ATOMS(cx->runtime);          JS_KEEP_ATOMS(cx->runtime);
3120          cx->debugHooks->objectHook(cx, obj, JS_TRUE,          cx->debugHooks->objectHook(cx, obj, JS_TRUE,
3121                                     cx->debugHooks->objectHookData);                                     cx->debugHooks->objectHookData);
3122          JS_UNKEEP_ATOMS(cx->runtime);          JS_UNKEEP_ATOMS(cx->runtime);
3123            cx->weakRoots.newborn[GCX_OBJECT] = obj;
3124      }      }
3125    
3126  out:  out:
     JS_POP_TEMP_ROOT(cx, &tvr);  
     cx->weakRoots.newborn[GCX_OBJECT] = obj;  
3127  #ifdef INCLUDE_MOZILLA_DTRACE  #ifdef INCLUDE_MOZILLA_DTRACE
3128      if (JAVASCRIPT_OBJECT_CREATE_ENABLED())      if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
3129          jsdtrace_object_create(cx, clasp, obj);          jsdtrace_object_create(cx, clasp, obj);
# Line 2695  Line 3131 
3131          jsdtrace_object_create_done(cx->fp, clasp);          jsdtrace_object_create_done(cx->fp, clasp);
3132  #endif  #endif
3133      return obj;      return obj;
3134    }
3135    
3136  bad:  JSObject*
3137      obj = NULL;  js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto, uint32 slot)
3138      goto out;  {
3139        JS_ASSERT(!clasp->getObjectOps);
3140        JS_ASSERT(proto->map->ops == &js_ObjectOps);
3141        JS_ASSERT(OBJ_GET_CLASS(cx, proto) == clasp);
3142    
3143  earlybad:      JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
3144  #ifdef INCLUDE_MOZILLA_DTRACE      if (!obj)
3145      if (JAVASCRIPT_OBJECT_CREATE_ENABLED())          return NULL;
3146          jsdtrace_object_create(cx, clasp, NULL);  
3147      if (JAVASCRIPT_OBJECT_CREATE_DONE_ENABLED())      js_HoldScope(OBJ_SCOPE(proto));
3148          jsdtrace_object_create_done(cx->fp, clasp);      obj->map = proto->map;
3149  #endif      obj->classword = jsuword(clasp);
3150      return NULL;      obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
3151        obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT];
3152    
3153        JS_ASSERT(slot > JSSLOT_PARENT);
3154        while (slot < JS_INITIAL_NSLOTS)
3155            obj->fslots[slot++] = JSVAL_VOID;
3156    
3157        obj->dslots = NULL;
3158        return obj;
3159  }  }
3160    
3161  JS_BEGIN_EXTERN_C  JS_BEGIN_EXTERN_C
# Line 2799  Line 3247 
3247  JSBool  JSBool
3248  js_FindClassObject(JSContext *cx, JSObject *start, jsid id, jsval *vp)  js_FindClassObject(JSContext *cx, JSObject *start, jsid id, jsval *vp)
3249  {  {
3250        JSStackFrame *fp;
3251      JSObject *obj, *cobj, *pobj;      JSObject *obj, *cobj, *pobj;
3252      JSProtoKey key;      JSProtoKey key;
3253      JSProperty *prop;      JSProperty *prop;
3254      jsval v;      jsval v;
3255      JSScopeProperty *sprop;      JSScopeProperty *sprop;
3256    
3257      if (start || (cx->fp && (start = cx->fp->scopeChain) != NULL)) {      /*
3258         * Find the global object. Use cx->fp directly to avoid falling off
3259         * trace; all JIT-elided stack frames have the same global object as
3260         * cx->fp.
3261         */
3262        VOUCH_DOES_NOT_REQUIRE_STACK();
3263        if (!start && (fp = cx->fp) != NULL)
3264            start = fp->scopeChain;
3265    
3266        if (start) {
3267          /* Find the topmost object in the scope chain. */          /* Find the topmost object in the scope chain. */
3268          do {          do {
3269              obj = start;              obj = start;
# Line 2946  Line 3404 
3404  void  void
3405  js_FinalizeObject(JSContext *cx, JSObject *obj)  js_FinalizeObject(JSContext *cx, JSObject *obj)
3406  {  {
     JSObjectMap *map;  
   
3407      /* Cope with stillborn objects that have no map. */      /* Cope with stillborn objects that have no map. */
3408      map = obj->map;      if (!obj->map)
     if (!map)  
3409          return;          return;
3410    
3411      if (cx->debugHooks->objectHook) {      if (cx->debugHooks->objectHook) {
# Line 2966  Line 3421 
3421          jsdtrace_object_finalize(obj);          jsdtrace_object_finalize(obj);
3422  #endif  #endif
3423    
3424      /* Drop map and free slots. */      if (OBJ_IS_NATIVE(obj))
3425      js_DropObjectMap(cx, map, obj);          js_DropScope(cx, OBJ_SCOPE(obj), obj);
3426      FreeSlots(cx, obj);      FreeSlots(cx, obj);
3427  }  }
3428    
# Line 2976  Line 3431 
3431  JSBool  JSBool
3432  js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)  js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)
3433  {  {
3434      JSObjectMap *map;      JS_ASSERT(OBJ_IS_NATIVE(obj));
     JSClass *clasp;  
3435    
3436      map = obj->map;      JSScope *scope = OBJ_SCOPE(obj);
3437      JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj);      JSClass *clasp = LOCKED_OBJ_GET_CLASS(obj);
3438      clasp = LOCKED_OBJ_GET_CLASS(obj);      if (scope->freeslot == JSSLOT_FREE(clasp) && clasp->reserveSlots) {
3439      if (map->freeslot == JSSLOT_FREE(clasp) && clasp->reserveSlots) {          /* Adjust scope->freeslot to include computed reserved slots, if any. */
3440          /* Adjust map->freeslot to include computed reserved slots, if any. */          scope->freeslot += clasp->reserveSlots(cx, obj);
         map->freeslot += clasp->reserveSlots(cx, obj);  
3441      }      }
3442    
3443      if (map->freeslot >= STOBJ_NSLOTS(obj) &&      if (scope->freeslot >= STOBJ_NSLOTS(obj) &&
3444          !js_ReallocSlots(cx, obj, map->freeslot + 1, JS_FALSE)) {          !js_ReallocSlots(cx, obj, scope->freeslot + 1, JS_FALSE)) {
3445          return JS_FALSE;          return JS_FALSE;
3446      }      }
3447    
3448      /* js_ReallocSlots or js_FreeSlot should set the free slots to void. */      /* js_ReallocSlots or js_FreeSlot should set the free slots to void. */
3449      JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, map->freeslot)));      JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, scope->freeslot)));
3450      *slotp = map->freeslot++;      *slotp = scope->freeslot++;
3451      return JS_TRUE;      return JS_TRUE;
3452  }  }
3453    
3454  void  void
3455  js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)  js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)
3456  {  {
3457      JSObjectMap *map;      JS_ASSERT(OBJ_IS_NATIVE(obj));
3458    
3459      map = obj->map;      JSScope *scope = OBJ_SCOPE(obj);
     JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj);  
3460      LOCKED_OBJ_SET_SLOT(obj, slot, JSVAL_VOID);      LOCKED_OBJ_SET_SLOT(obj, slot, JSVAL_VOID);
3461      if (map->freeslot == slot + 1) {      if (scope->freeslot == slot + 1) {
3462          map->freeslot = slot;          scope->freeslot = slot;
3463    
3464          /* When shrinking, js_ReallocSlots always returns true. */          /* When shrinking, js_ReallocSlots always returns true. */
3465          js_ReallocSlots(cx, obj, slot, JS_FALSE);          js_ReallocSlots(cx, obj, slot, JS_FALSE);
# Line 3030  Line 3482 
3482              cp++;              cp++;
3483          }          }
3484      }      }
3485      if (cp == end &&  
3486          (oldIndex < (JSVAL_INT_MAX / 10) ||      /*
3487           (oldIndex == (JSVAL_INT_MAX / 10) &&       * Non-integer indexes can't be represented as integers.  Also, distinguish
3488            c <= (JSVAL_INT_MAX % 10)))) {       * index "-0" from "0", because JSVAL_INT cannot.
3489         */
3490        if (cp != end || (negative && index == 0))
3491            return id;
3492        if (oldIndex < JSVAL_INT_MAX / 10 ||
3493            (oldIndex == JSVAL_INT_MAX / 10 && c <= (JSVAL_INT_MAX % 10))) {
3494          if (negative)          if (negative)
3495              index = 0 - index;              index = 0 - index;
3496          id = INT_TO_JSID((jsint)index);          id = INT_TO_JSID((jsint)index);
# Line 3057  Line 3514 
3514          sprop = SCOPE_GET_PROPERTY(scope, id);          sprop = SCOPE_GET_PROPERTY(scope, id);
3515          if (sprop) {          if (sprop) {
3516              PCMETER(JS_PROPERTY_CACHE(cx).pcpurges++);              PCMETER(JS_PROPERTY_CACHE(cx).pcpurges++);
3517              SCOPE_MAKE_UNIQUE_SHAPE(cx, scope);              js_MakeScopeShapeUnique(cx, scope);
3518              JS_UNLOCK_SCOPE(cx, scope);              JS_UNLOCK_SCOPE(cx, scope);
3519    
3520                if (!STOBJ_GET_PARENT(scope->object)) {
3521                    /*
3522                     * All scope chains end in a global object, so this will change
3523                     * the global shape. jstracer.cpp assumes that the global shape
3524                     * never changes on trace, so we must deep-bail here.
3525                     */
3526                    js_LeaveTrace(cx);
3527                }
3528              return JS_TRUE;              return JS_TRUE;
3529          }          }
3530          obj = LOCKED_OBJ_GET_PROTO(scope->object);          obj = LOCKED_OBJ_GET_PROTO(scope->object);
# Line 3067  Line 3533 
3533      return JS_FALSE;      return JS_FALSE;
3534  }  }
3535    
3536  static void  void
3537  PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id)  js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id)
3538  {  {
3539      if (!OBJ_IS_DELEGATE(cx, obj))      JS_ASSERT(OBJ_IS_DELEGATE(cx, obj));
         return;  
   
3540      PurgeProtoChain(cx, OBJ_GET_PROTO(cx, obj), id);      PurgeProtoChain(cx, OBJ_GET_PROTO(cx, obj), id);
3541      while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL) {  
3542          if (PurgeProtoChain(cx, obj, id))      /*
3543              return;       * We must purge the scope chain only for Call objects as they are the only
3544         * kind of cacheable non-global object that can gain properties after outer
3545         * properties with the same names have been cached or traced. Call objects
3546         * may gain such properties via eval introducing new vars; see bug 490364.
3547         */
3548        if (STOBJ_GET_CLASS(obj) == &js_CallClass) {
3549            while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL) {
3550                if (PurgeProtoChain(cx, obj, id))
3551                    break;
3552            }
3553      }      }
3554  }  }
3555    
# Line 3093  Line 3566 
3566       * this optimistically (assuming no failure below) before locking obj, so       * this optimistically (assuming no failure below) before locking obj, so
3567       * we can lock the shadowed scope.       * we can lock the shadowed scope.
3568       */       */
3569      PurgeScopeChain(cx, obj, id);      js_PurgeScopeChain(cx, obj, id);
3570    
3571      JS_LOCK_OBJ(cx, obj);      JS_LOCK_OBJ(cx, obj);
3572      scope = js_GetMutableScope(cx, obj);      scope = js_GetMutableScope(cx, obj);
# Line 3142  Line 3615 
3615   * nominal initial value of a slot-full property, while GC safety wants that   * nominal initial value of a slot-full property, while GC safety wants that
3616   * value to be stored before the call-out through the hook.  Optimize to do   * value to be stored before the call-out through the hook.  Optimize to do
3617   * both while saving cycles for classes that stub their addProperty hook.   * both while saving cycles for classes that stub their addProperty hook.
3618     *
3619     * As in js_SetProtoOrParent (see above), we maintain the "any Array prototype
3620     * has indexed properties hazard" flag by conservatively setting it.
3621   */   */
3622  #define ADD_PROPERTY_HELPER(cx,clasp,obj,scope,sprop,vp,cleanup)              \  #define ADD_PROPERTY_HELPER(cx,clasp,obj,scope,sprop,vp,cleanup)              \
3623      JS_BEGIN_MACRO                                                            \      JS_BEGIN_MACRO                                                            \
# Line 3160  Line 3636 
3636  JSBool  JSBool
3637  js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,  js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
3638                          JSPropertyOp getter, JSPropertyOp setter, uintN attrs,                          JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
3639                          uintN flags, intN shortid, JSProperty **propp)                          uintN flags, intN shortid, JSProperty **propp,
3640                            uintN defineHow /* = 0 */)
3641  {  {
3642      JSClass *clasp;      JSClass *clasp;
3643      JSScope *scope;      JSScope *scope;
3644      JSScopeProperty *sprop;      JSScopeProperty *sprop;
3645        bool added;
3646    
3647        JS_ASSERT((defineHow & ~(JSDNP_CACHE_RESULT | JSDNP_DONT_PURGE)) == 0);
3648        js_LeaveTraceIfGlobalObject(cx, obj);
3649    
3650      /* Convert string indices to integers if appropriate. */      /* Convert string indices to integers if appropriate. */
3651      CHECK_FOR_STRING_INDEX(id);      CHECK_FOR_STRING_INDEX(id);
# Line 3205  Line 3686 
3686    
3687              /* NB: obj == pobj, so we can share unlock code at the bottom. */              /* NB: obj == pobj, so we can share unlock code at the bottom. */
3688              if (!sprop)              if (!sprop)
3689                  goto bad;                  goto error;
3690          } else if (prop) {          } else if (prop) {
3691              /* NB: call OBJ_DROP_PROPERTY, as pobj might not be native. */              /* NB: call OBJ_DROP_PROPERTY, as pobj might not be native. */
3692              OBJ_DROP_PROPERTY(cx, pobj, prop);              OBJ_DROP_PROPERTY(cx, pobj, prop);
# Line 3216  Line 3697 
3697  #endif /* JS_HAS_GETTER_SETTER */  #endif /* JS_HAS_GETTER_SETTER */
3698    
3699      /*      /*
3700       * Purge the property cache of now-shadowed id in obj's scope chain.       * Purge the property cache of any properties named by id that are about
3701       * Do this early, before locking obj to avoid nesting locks.       * to be shadowed in obj's scope chain unless it is known a priori that it
3702         * is not possible. We do this before locking obj to avoid nesting locks.
3703         */
3704        if (!(defineHow & JSDNP_DONT_PURGE))
3705            js_PurgeScopeChain(cx, obj, id);
3706    
3707        /*
3708         * Check whether a readonly property or setter is being defined on a known
3709         * prototype object. See the comment in jscntxt.h before protoHazardShape's
3710         * member declaration.
3711       */       */
3712      PurgeScopeChain(cx, obj, id);      if (OBJ_IS_DELEGATE(cx, obj) && (attrs & (JSPROP_READONLY | JSPROP_SETTER)))
3713            cx->runtime->protoHazardShape = js_GenerateShape(cx, false);
3714    
3715      /* Lock if object locking is required by this implementation. */      /* Lock if object locking is required by this implementation. */
3716      JS_LOCK_OBJ(cx, obj);      JS_LOCK_OBJ(cx, obj);
# Line 3234  Line 3725 
3725      /* Get obj's own scope if it has one, or create a new one for obj. */      /* Get obj's own scope if it has one, or create a new one for obj. */
3726      scope = js_GetMutableScope(cx, obj);      scope = js_GetMutableScope(cx, obj);
3727      if (!scope)      if (!scope)
3728          goto bad;          goto error;
3729    
3730        added = false;
3731      if (!sprop) {      if (!sprop) {
3732          /* Add a new property, or replace an existing one of the same id. */          /* Add a new property, or replace an existing one of the same id. */
3733          if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES)          if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES)
# Line 3244  Line 3736 
3736                                      SPROP_INVALID_SLOT, attrs, flags,                                      SPROP_INVALID_SLOT, attrs, flags,
3737                                      shortid);                                      shortid);
3738          if (!sprop)          if (!sprop)
3739              goto bad;              goto error;
3740            added = true;
3741      }      }
3742    
3743      /* Store value before calling addProperty, in case the latter GC's. */      /* Store value before calling addProperty, in case the latter GC's. */
# Line 3254  Line 3747 
3747      /* XXXbe called with lock held */      /* XXXbe called with lock held */
3748      ADD_PROPERTY_HELPER(cx, clasp, obj, scope, sprop, &value,      ADD_PROPERTY_HELPER(cx, clasp, obj, scope, sprop, &value,
3749                          js_RemoveScopeProperty(cx, scope, id);                          js_RemoveScopeProperty(cx, scope, id);
3750                          goto bad);                          goto error);
3751    
3752        if (defineHow & JSDNP_CACHE_RESULT) {
3753            JS_ASSERT_NOT_ON_TRACE(cx);
3754            JSPropCacheEntry *entry;
3755            entry = js_FillPropertyCache(cx, obj, 0, 0, obj, sprop, added);
3756            TRACE_2(SetPropHit, entry, sprop);
3757        }
3758      if (propp)      if (propp)
3759          *propp = (JSProperty *) sprop;          *propp = (JSProperty *) sprop;
3760      else      else
3761          JS_UNLOCK_OBJ(cx, obj);          JS_UNLOCK_OBJ(cx, obj);
3762      return JS_TRUE;      return JS_TRUE;
3763    
3764  bad:  error: // TRACE_2 jumps here on error, as well.
3765      JS_UNLOCK_OBJ(cx, obj);      JS_UNLOCK_OBJ(cx, obj);
3766      return JS_FALSE;      return JS_FALSE;
3767  }  }
3768    
 /*  
  * Given pc pointing after a property accessing bytecode, return true if the  
  * access is "object-detecting" in the sense used by web scripts, e.g., when  
  * checking whether document.all is defined.  
  */  
 static JSBool  
 Detecting(JSContext *cx, jsbytecode *pc)  
 {  
     JSScript *script;  
     jsbytecode *endpc;  
     JSOp op;  
     JSAtom *atom;  
   
     if (!cx->fp)  
         return JS_FALSE;  
     script = cx->fp->script;  
     for (endpc = script->code + script->length;  
          pc < endpc;  
          pc += js_CodeSpec[op].length) {  
         /* General case: a branch or equality op follows the access. */  
         op = (JSOp) *pc;  
         if (js_CodeSpec[op].format & JOF_DETECTING)  
             return JS_TRUE;  
   
         switch (op) {  
           case JSOP_NULL:  
             /*  
              * Special case #1: handle (document.all == null).  Don't sweat  
              * about JS1.2's revision of the equality operators here.  
              */  
             if (++pc < endpc)  
                 return *pc == JSOP_EQ || *pc == JSOP_NE;  
             return JS_FALSE;  
   
           case JSOP_NAME:  
             /*  
              * Special case #2: handle (document.all == undefined).  Don't  
              * worry about someone redefining undefined, which was added by  
              * Edition 3, so is read/write for backward compatibility.  
              */  
             GET_ATOM_FROM_BYTECODE(script, pc, 0, atom);  
             if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] &&  
                 (pc += js_CodeSpec[op].length) < endpc) {  
                 op = (JSOp) *pc;  
                 return op == JSOP_EQ || op == JSOP_NE ||  
                        op == JSOP_STRICTEQ || op == JSOP_STRICTNE;  
             }  
             return JS_FALSE;  
   
           default:  
             /*  
              * At this point, anything but an extended atom index prefix means  
              * we're not detecting.  
              */  
             if (!(js_CodeSpec[op].format & JOF_INDEXBASE))  
                 return JS_FALSE;  
             break;  
         }  
     }  
     return JS_FALSE;  
 }  
   
3769  JS_FRIEND_API(JSBool)  JS_FRIEND_API(JSBool)
3770  js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,  js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
3771                    JSProperty **propp)                    JSProperty **propp)
# Line 3354  Line 3791 
3791      JSResolvingEntry *entry;      JSResolvingEntry *entry;
3792      uint32 generation;      uint32 generation;
3793      JSNewResolveOp newresolve;      JSNewResolveOp newresolve;
     jsbytecode *pc;  
     const JSCodeSpec *cs;  
     uint32 format;  
3794      JSBool ok;      JSBool ok;
3795    
3796      /* Convert string indices to integers if appropriate. */      /* Convert string indices to integers if appropriate. */
3797      CHECK_FOR_STRING_INDEX(id);      CHECK_FOR_STRING_INDEX(id);
     JS_COUNT_OPERATION(cx, JSOW_LOOKUP_PROPERTY);  
3798    
3799      /* Search scopes starting with obj and following the prototype link. */      /* Search scopes starting with obj and following the prototype link. */
3800      start = obj;      start = obj;
# Line 3406  Line 3839 
3839    
3840                  if (clasp->flags & JSCLASS_NEW_RESOLVE) {                  if (clasp->flags & JSCLASS_NEW_RESOLVE) {
3841                      newresolve = (JSNewResolveOp)resolve;                      newresolve = (JSNewResolveOp)resolve;
3842                      if (flags == JSRESOLVE_INFER && cx->fp && cx->fp->regs) {                      if (flags == JSRESOLVE_INFER)
3843                          flags = 0;                          flags = InferFlags(cx, flags);
                         pc = cx->fp->regs->pc;  
                         cs = &js_CodeSpec[*pc];  
                         format = cs->format;  
                         if (JOF_MODE(format) != JOF_NAME)  
                             flags |= JSRESOLVE_QUALIFIED;  
                         if ((format & (JOF_SET | JOF_FOR)) ||  
                             (cx->fp->flags & JSFRAME_ASSIGNING)) {  
                             flags |= JSRESOLVE_ASSIGNING;  
                         } else {  
                             pc += cs->length;  
                             if (Detecting(cx, pc))  
                                 flags |= JSRESOLVE_DETECTING;  
                         }  
                         if (format & JOF_DECLARING)  
                             flags |= JSRESOLVE_DECLARING;  
                     }  
3844                      obj2 = (clasp->flags & JSCLASS_NEW_RESOLVE_GETS_START)                      obj2 = (clasp->flags & JSCLASS_NEW_RESOLVE_GETS_START)
3845                             ? start                             ? start
3846                             : NULL;                             : NULL;
# Line 3449  Line 3866 
3866                               proto = OBJ_GET_PROTO(cx, proto)) {                               proto = OBJ_GET_PROTO(cx, proto)) {
3867                              protoIndex++;                              protoIndex++;
3868                          }                          }
3869                          scope = OBJ_SCOPE(obj2);                          if (!OBJ_IS_NATIVE(obj2)) {
                         if (!MAP_IS_NATIVE(&scope->map)) {  
3870                              /* Whoops, newresolve handed back a foreign obj2. */                              /* Whoops, newresolve handed back a foreign obj2. */
3871                              JS_ASSERT(obj2 != obj);                              JS_ASSERT(obj2 != obj);
3872                              ok = OBJ_LOOKUP_PROPERTY(cx, obj2, id, objp, propp);                              ok = OBJ_LOOKUP_PROPERTY(cx, obj2, id, objp, propp);
# Line 3466  Line 3882 
3882                               * not on obj's proto chain.  That last case is a                               * not on obj's proto chain.  That last case is a
3883                               * "too bad!" case.                               * "too bad!" case.
3884                               */                               */
3885                                scope = OBJ_SCOPE(obj2);
3886                              if (scope->object == obj2)                              if (scope->object == obj2)
3887                                  sprop = SCOPE_GET_PROPERTY(scope, id);                                  sprop = SCOPE_GET_PROPERTY(scope, id);
3888                          }                          }
# Line 3488  Line 3905 
3905                      if (!ok)                      if (!ok)
3906                          goto cleanup;                          goto cleanup;
3907                      JS_LOCK_OBJ(cx, obj);                      JS_LOCK_OBJ(cx, obj);
3908                        JS_ASSERT(OBJ_IS_NATIVE(obj));
3909                      scope = OBJ_SCOPE(obj);                      scope = OBJ_SCOPE(obj);
                     JS_ASSERT(MAP_IS_NATIVE(&scope->map));  
3910                      if (scope->object == obj)                      if (scope->object == obj)
3911                          sprop = SCOPE_GET_PROPERTY(scope, id);                          sprop = SCOPE_GET_PROPERTY(scope, id);
3912                  }                  }
# Line 3530  Line 3947 
3947      return protoIndex;      return protoIndex;
3948  }  }
3949    
3950  int  /*
3951  js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp,   * We cache name lookup results only for the global object or for native
3952                        JSObject **pobjp, JSProperty **propp,   * non-global objects without prototype or with prototype that never mutates,
3953                        JSPropCacheEntry **entryp)   * see bug 462734 and bug 487039.
3954     */
3955    static inline bool
3956    IsCacheableNonGlobalScope(JSObject *obj)
3957    {
3958        JS_ASSERT(STOBJ_GET_PARENT(obj));
3959    
3960        JSClass *clasp = STOBJ_GET_CLASS(obj);
3961        bool cacheable = (clasp == &js_CallClass ||
3962                          clasp == &js_BlockClass ||
3963                          clasp == &js_DeclEnvClass);
3964    
3965        JS_ASSERT_IF(cacheable, obj->map->ops->lookupProperty == js_LookupProperty);
3966        return cacheable;
3967    }
3968    
3969    JSPropCacheEntry *
3970    js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
3971                          JSObject **objp, JSObject **pobjp, JSProperty **propp)
3972  {  {
3973      JSObject *obj, *pobj, *lastobj;      JSObject *scopeChain, *obj, *parent, *pobj;
3974      uint32 shape;      JSPropCacheEntry *entry;
3975      int scopeIndex, protoIndex;      int scopeIndex, protoIndex;
3976      JSProperty *prop;      JSProperty *prop;
     JSScopeProperty *sprop;  
3977    
3978      obj = cx->fp->scopeChain;      JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx));
3979      shape = OBJ_SHAPE(obj);      scopeChain = js_GetTopStackFrame(cx)->scopeChain;
3980      for (scopeIndex = 0; ; scopeIndex++) {  
3981          if (obj->map->ops->lookupProperty == js_LookupProperty) {      /* Scan entries on the scope chain that we can cache across. */
3982              protoIndex =      entry = JS_NO_PROP_CACHE_FILL;
3983                  js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,      obj = scopeChain;
3984                                             &pobj, &prop);      parent = OBJ_GET_PARENT(cx, obj);
3985          } else {      for (scopeIndex = 0;
3986              if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop))           parent
3987                  return -1;           ? IsCacheableNonGlobalScope(obj)
3988              protoIndex = -1;           : obj->map->ops->lookupProperty == js_LookupProperty;
3989          }           ++scopeIndex) {
3990            protoIndex =
3991                js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,
3992                                           &pobj, &prop);
3993            if (protoIndex < 0)
3994                return NULL;
3995    
3996          if (prop) {          if (prop) {
3997              if (entryp) {  #ifdef DEBUG
3998                  if (protoIndex >= 0 && OBJ_IS_NATIVE(pobj)) {              if (parent) {
3999                      sprop = (JSScopeProperty *) prop;                  JSClass *clasp = OBJ_GET_CLASS(cx, obj);
4000                      js_FillPropertyCache(cx, cx->fp->scopeChain, shape,                  JS_ASSERT(OBJ_IS_NATIVE(pobj));
4001                                           scopeIndex, protoIndex, pobj, sprop,                  JS_ASSERT(OBJ_GET_CLASS(cx, pobj) == clasp);
4002                                           entryp);                  if (clasp == &js_BlockClass) {
4003                        /*
4004                         * Block instances on the scope chain are immutable and
4005                         * always share their scope with compile-time prototypes.
4006                         */
4007                        JS_ASSERT(pobj == OBJ_GET_PROTO(cx, obj));
4008                        JS_ASSERT(OBJ_SCOPE(obj)->object == pobj);
4009                        JS_ASSERT(protoIndex == 1);
4010                  } else {                  } else {
4011                      PCMETER(JS_PROPERTY_CACHE(cx).nofills++);                      /* Call and DeclEnvClass objects have no prototypes. */
4012                      *entryp = NULL;                      JS_ASSERT(!OBJ_GET_PROTO(cx, obj));
4013                        JS_ASSERT(protoIndex == 0);
4014                  }                  }
4015              }              }
4016    #endif
4017                if (cacheResult) {
4018                    entry = js_FillPropertyCache(cx, scopeChain,
4019                                                 scopeIndex, protoIndex, pobj,
4020                                                 (JSScopeProperty *) prop, false);
4021                }
4022              SCOPE_DEPTH_ACCUM(&rt->scopeSearchDepthStats, scopeIndex);              SCOPE_DEPTH_ACCUM(&rt->scopeSearchDepthStats, scopeIndex);
4023              *objp = obj;              goto out;
             *pobjp = pobj;  
             *propp = prop;  
             return scopeIndex;  
4024          }          }
4025    
4026          lastobj = obj;          if (!parent) {
4027          obj = OBJ_GET_PARENT(cx, obj);              pobj = NULL;
4028          if (!obj)              goto out;
4029            }
4030            obj = parent;
4031            parent = OBJ_GET_PARENT(cx, obj);
4032        }
4033    
4034        for (;;) {
4035            if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop))
4036                return NULL;
4037            if (prop) {
4038                PCMETER(JS_PROPERTY_CACHE(cx).nofills++);
4039                goto out;
4040            }
4041    
4042            /*
4043             * We conservatively assume that a resolve hook could mutate the scope
4044             * chain during OBJ_LOOKUP_PROPERTY. So we read parent here again.
4045             */
4046            parent = OBJ_GET_PARENT(cx, obj);
4047            if (!parent) {
4048                pobj = NULL;
4049              break;              break;
4050            }
4051            obj = parent;
4052      }      }
4053    
4054      *objp = lastobj;    out:
4055      *pobjp = NULL;      JS_ASSERT(!!pobj == !!prop);
4056      *propp = NULL;      *objp = obj;
4057      return scopeIndex;      *pobjp = pobj;
4058        *propp = prop;
4059        return entry;
4060  }  }
4061    
4062  JS_FRIEND_API(JSBool)  JS_FRIEND_API(JSBool)
4063  js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,  js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,
4064                  JSProperty **propp)                  JSProperty **propp)
4065  {  {
4066      return js_FindPropertyHelper(cx, id, objp, pobjp, propp, NULL) >= 0;      return !!js_FindPropertyHelper(cx, id, false, objp, pobjp, propp);
4067  }  }
4068    
4069  JSObject *  JSObject *
4070  js_FindIdentifierBase(JSContext *cx, jsid id, JSPropCacheEntry *entry)  js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
4071  {  {
     JSObject *obj, *pobj;  
     JSProperty *prop;  
   
4072      /*      /*
4073       * Look for id's property along the "with" statement chain and the       * This function should not be called for a global object or from the
4074       * statically-linked scope chain.       * trace and should have a valid cache entry for native scopeChain.
4075       */       */
4076      if (js_FindPropertyHelper(cx, id, &obj, &pobj, &prop, &entry) < 0)      JS_ASSERT(OBJ_GET_PARENT(cx, scopeChain));
4077          return NULL;      JS_ASSERT(!JS_ON_TRACE(cx));
     if (prop) {  
         OBJ_DROP_PROPERTY(cx, pobj, prop);  
         return obj;  
     }  
4078    
4079      /*      JSObject *obj = scopeChain;
      * Use the top-level scope from the scope chain, which won't end in the  
      * same scope as cx->globalObject for cross-context function calls.  
      */  
     JS_ASSERT(obj);  
4080    
4081      /*      /*
4082       * Property not found.  Give a strict warning if binding an undeclared       * Loop over cacheable objects on the scope chain until we find a
4083       * top-level variable.       * property. We also stop when we reach the global object skipping any
4084         * farther checks or lookups. For details see the JSOP_BINDNAME case of
4085         * js_Interpret.
4086       */       */
4087      if (JS_HAS_STRICT_OPTION(cx)) {      for (int scopeIndex = 0; IsCacheableNonGlobalScope(obj); scopeIndex++) {
4088          JSString *str = JSVAL_TO_STRING(ID_TO_VALUE(id));          JSObject *pobj;
4089          const char *bytes = js_GetStringBytes(cx, str);          JSProperty *prop;
4090            int protoIndex = js_LookupPropertyWithFlags(cx, obj, id,
4091          if (!bytes ||                                                      cx->resolveFlags,
4092              !JS_ReportErrorFlagsAndNumber(cx,                                                      &pobj, &prop);
4093                                            JSREPORT_WARNING | JSREPORT_STRICT,          if (protoIndex < 0)
                                           js_GetErrorMessage, NULL,  
                                           JSMSG_UNDECLARED_VAR, bytes)) {  
4094              return NULL;              return NULL;
4095            if (prop) {
4096                JS_ASSERT(OBJ_IS_NATIVE(pobj));
4097                JS_ASSERT(OBJ_GET_CLASS(cx, pobj) == OBJ_GET_CLASS(cx, obj));
4098    #ifdef DEBUG
4099                JSPropCacheEntry *entry =
4100    #endif
4101                js_FillPropertyCache(cx, scopeChain,
4102                                     scopeIndex, protoIndex, pobj,
4103                                     (JSScopeProperty *) prop, false);
4104                JS_ASSERT(entry);
4105                JS_UNLOCK_OBJ(cx, pobj);
4106                return obj;
4107          }          }
4108    
4109            /* Call and other cacheable objects always have a parent. */
4110            obj = OBJ_GET_PARENT(cx, obj);
4111            if (!OBJ_GET_PARENT(cx, obj))
4112                return obj;
4113      }      }
4114    
4115        /* Loop until we find a property or reach the global object. */
4116        do {
4117            JSObject *pobj;
4118            JSProperty *prop;
4119            if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop))
4120                return NULL;
4121            if (prop) {
4122                OBJ_DROP_PROPERTY(cx, pobj, prop);
4123                break;
4124            }
4125    
4126            /*
4127             * We conservatively assume that a resolve hook could mutate the scope
4128             * chain during OBJ_LOOKUP_PROPERTY. So we must check if parent is not
4129             * null here even if it wasn't before the lookup.
4130             */
4131            JSObject *parent = OBJ_GET_PARENT(cx, obj);
4132            if (!parent)
4133                break;
4134            obj = parent;
4135        } while (OBJ_GET_PARENT(cx, obj));
4136      return obj;      return obj;
4137  }  }
4138    
# Line 3639  Line 4140 
4140  js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,  js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,
4141               JSScopeProperty *sprop, jsval *vp)               JSScopeProperty *sprop, jsval *vp)
4142  {  {
4143        js_LeaveTraceIfGlobalObject(cx, pobj);
4144    
4145      JSScope *scope;      JSScope *scope;
4146      uint32 slot;      uint32 slot;
4147      int32 sample;      int32 sample;
4148      JSTempValueRooter tvr;      JSTempValueRooter tvr, tvr2;
4149      JSBool ok;      JSBool ok;
4150    
4151      JS_ASSERT(OBJ_IS_NATIVE(pobj));      JS_ASSERT(OBJ_IS_NATIVE(pobj));
# Line 3660  Line 4163 
4163      sample = cx->runtime->propertyRemovals;      sample = cx->runtime->propertyRemovals;
4164      JS_UNLOCK_SCOPE(cx, scope);      JS_UNLOCK_SCOPE(cx, scope);
4165      JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr);      JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr);
4166      ok = SPROP_GET(cx, sprop, obj, pobj, vp);      JS_PUSH_TEMP_ROOT_OBJECT(cx, pobj, &tvr2);
4167        ok = js_GetSprop(cx, sprop, obj, vp);
4168        JS_POP_TEMP_ROOT(cx, &tvr2);
4169      JS_POP_TEMP_ROOT(cx, &tvr);      JS_POP_TEMP_ROOT(cx, &tvr);
4170      if (!ok)      if (!ok)
4171          return JS_FALSE;          return JS_FALSE;
# Line 3679  Line 4184 
4184  JSBool  JSBool
4185  js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp)  js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp)
4186  {  {
4187        js_LeaveTraceIfGlobalObject(cx, obj);
4188    
4189      JSScope *scope;      JSScope *scope;
4190      uint32 slot;      uint32 slot;
4191      int32 sample;      int32 sample;
4192      JSTempValueRooter tvr;      JSTempValueRooter tvr;
4193      bool ok;      JSBool ok;
4194    
4195      JS_ASSERT(OBJ_IS_NATIVE(obj));      JS_ASSERT(OBJ_IS_NATIVE(obj));
4196      JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj));      JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj));
4197      scope = OBJ_SCOPE(obj);      scope = OBJ_SCOPE(obj);
4198      JS_ASSERT(scope->object == obj);      JS_ASSERT(scope->object == obj || (sprop->attrs & JSPROP_SHARED));
4199    
4200      slot = sprop->slot;      slot = sprop->slot;
4201      if (slot != SPROP_INVALID_SLOT) {      if (slot != SPROP_INVALID_SLOT) {
# Line 3702  Line 4209 
4209           * Allow API consumers to create shared properties with stub setters.           * Allow API consumers to create shared properties with stub setters.
4210           * Such properties lack value storage, so setting them is like writing           * Such properties lack value storage, so setting them is like writing
4211           * to /dev/null.           * to /dev/null.
4212             *
4213             * But we can't short-circuit if there's a scripted getter or setter
4214             * since we might need to throw. In that case, we let SPROP_SET
4215             * decide whether to throw an exception. See bug 478047.
4216           */           */
4217          if (SPROP_HAS_STUB_SETTER(sprop))          if (!(sprop->attrs & JSPROP_GETTER) && SPROP_HAS_STUB_SETTER(sprop)) {
4218                JS_ASSERT(!(sprop->attrs & JSPROP_SETTER));
4219              return JS_TRUE;              return JS_TRUE;
4220            }
4221      }      }
4222    
4223      sample = cx->runtime->propertyRemovals;      sample = cx->runtime->propertyRemovals;
4224      JS_UNLOCK_SCOPE(cx, scope);      JS_UNLOCK_SCOPE(cx, scope);
4225      JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr);      JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr);
4226      ok = SPROP_SET(cx, sprop, obj, obj, vp);      ok = js_SetSprop(cx, sprop, obj, vp);
4227      JS_POP_TEMP_ROOT(cx, &tvr);      JS_POP_TEMP_ROOT(cx, &tvr);
4228      if (!ok)      if (!ok)
4229          return JS_FALSE;          return JS_FALSE;
4230    
4231      JS_LOCK_SCOPE(cx, scope);      JS_LOCK_SCOPE(cx, scope);
4232      JS_ASSERT(scope->object == obj);      JS_ASSERT(scope->object == obj || (sprop->attrs & JSPROP_SHARED));
4233      if (SLOT_IN_SCOPE(slot, scope) &&      if (SLOT_IN_SCOPE(slot, scope) &&
4234          (JS_LIKELY(cx->runtime->propertyRemovals == sample) ||          (JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
4235           SCOPE_GET_PROPERTY(scope, sprop->id) == sprop)) {           SCOPE_GET_PROPERTY(scope, sprop->id) == sprop)) {
# Line 3728  Line 4241 
4241  }  }
4242    
4243  JSBool  JSBool
4244  js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,  js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
4245                       JSPropCacheEntry **entryp)                       jsval *vp)
4246  {  {
4247      uint32 shape;      JSObject *aobj, *obj2;
4248      int protoIndex;      int protoIndex;
     JSObject *obj2;  
4249      JSProperty *prop;      JSProperty *prop;
4250      JSScopeProperty *sprop;      JSScopeProperty *sprop;
4251    
4252        JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx));
4253      /* Convert string indices to integers if appropriate. */      /* Convert string indices to integers if appropriate. */
4254      CHECK_FOR_STRING_INDEX(id);      CHECK_FOR_STRING_INDEX(id);
     JS_COUNT_OPERATION(cx, JSOW_GET_PROPERTY);  
4255    
4256      shape = OBJ_SHAPE(obj);      aobj = js_GetProtoIfDenseArray(cx, obj);
4257      protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,      protoIndex = js_LookupPropertyWithFlags(cx, aobj, id, cx->resolveFlags,
4258                                              &obj2, &prop);                                              &obj2, &prop);
4259      if (protoIndex < 0)      if (protoIndex < 0)
4260          return JS_FALSE;          return JS_FALSE;
4261      if (!prop) {      if (!prop) {
         jsbytecode *pc;  
   
4262          *vp = JSVAL_VOID;          *vp = JSVAL_VOID;
4263    
4264          if (!OBJ_GET_CLASS(cx, obj)->getProperty(cx, obj, ID_TO_VALUE(id), vp))          if (!OBJ_GET_CLASS(cx, obj)->getProperty(cx, obj, ID_TO_VALUE(id), vp))
4265              return JS_FALSE;              return JS_FALSE;
4266    
4267          if (entryp) {          PCMETER(cacheResult && JS_PROPERTY_CACHE(cx).nofills++);
             PCMETER(JS_PROPERTY_CACHE(cx).nofills++);  
             *entryp = NULL;  
         }  
4268    
4269          /*          /*
4270           * Give a strict warning if foo.bar is evaluated by a script for an           * Give a strict warning if foo.bar is evaluated by a script for an
4271           * object foo with no property named 'bar'.           * object foo with no property named 'bar'.
4272           */           */
4273          if (JSVAL_IS_VOID(*vp) && cx->fp && cx->fp->regs) {          jsbytecode *pc;
4274            if (JSVAL_IS_VOID(*vp) && ((pc = js_GetCurrentBytecodePC(cx)) != NULL)) {
4275              JSOp op;              JSOp op;
4276              uintN flags;              uintN flags;
4277    
             pc = cx->fp->regs->pc;  
4278              op = (JSOp) *pc;              op = (JSOp) *pc;
4279                if (op == JSOP_TRAP) {
4280                    JS_ASSERT_NOT_ON_TRACE(cx);
4281                    op = JS_GetTrapOpcode(cx, cx->fp->script, pc);
4282                }
4283              if (op == JSOP_GETXPROP) {              if (op == JSOP_GETXPROP) {
4284                  flags = JSREPORT_ERROR;                  flags = JSREPORT_ERROR;
4285              } else {              } else {
# Line 3784  Line 4295 
4295                  if (id == ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom))                  if (id == ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom))
4296                      return JS_TRUE;                      return JS_TRUE;
4297    
4298                  /* Kludge to allow (typeof foo == "undefined") tests. */                  /* Do not warn about tests like (obj[prop] == undefined). */
4299                  JS_ASSERT(cx->fp->script);                  if (cx->resolveFlags == JSRESOLVE_INFER) {
4300                  pc += js_CodeSpec[op].length;                      js_LeaveTrace(cx);
4301                  if (Detecting(cx, pc))                      pc += js_CodeSpec[op].length;
4302                        if (Detecting(cx, pc))
4303                            return JS_TRUE;
4304                    } else if (cx->resolveFlags & JSRESOLVE_DETECTING) {
4305                      return JS_TRUE;                      return JS_TRUE;
4306                    }
4307    
4308                  flags = JSREPORT_WARNING | JSREPORT_STRICT;                  flags = JSREPORT_WARNING | JSREPORT_STRICT;
4309              }              }
# Line 3809  Line 4324 
4324      }      }
4325    
4326      sprop = (JSScopeProperty *) prop;      sprop = (JSScopeProperty *) prop;
4327    
4328        if (cacheResult) {
4329            JS_ASSERT_NOT_ON_TRACE(cx);
4330            js_FillPropertyCache(cx, aobj, 0, protoIndex, obj2, sprop, false);
4331        }
4332    
4333      if (!js_NativeGet(cx, obj, obj2, sprop, vp))      if (!js_NativeGet(cx, obj, obj2, sprop, vp))
4334          return JS_FALSE;          return JS_FALSE;
4335    
     if (entryp)  
         js_FillPropertyCache(cx, obj, shape, 0, protoIndex, obj2, sprop, entryp);  
4336      JS_UNLOCK_OBJ(cx, obj2);      JS_UNLOCK_OBJ(cx, obj2);
4337      return JS_TRUE;      return JS_TRUE;
4338  }  }
# Line 3821  Line 4340 
4340  JSBool  JSBool
4341  js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)  js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
4342  {  {
4343      return js_GetPropertyHelper(cx, obj, id, vp, NULL);      return js_GetPropertyHelper(cx, obj, id, false, vp);
4344  }  }
4345    
4346  JSBool  JSBool
4347  js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,  js_GetMethod(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
4348                       JSPropCacheEntry **entryp)               jsval *vp)
4349    {
4350        if (obj->map->ops == &js_ObjectOps ||
4351            obj->map->ops->getProperty == js_GetProperty) {
4352            return js_GetPropertyHelper(cx, obj, id, cacheResult, vp);
4353        }
4354        JS_ASSERT_IF(cacheResult, OBJ_IS_DENSE_ARRAY(cx, obj));
4355    #if JS_HAS_XML_SUPPORT
4356        if (OBJECT_IS_XML(cx, obj))
4357            return js_GetXMLMethod(cx, obj, id, vp);
4358    #endif
4359        return OBJ_GET_PROPERTY(cx, obj, id, vp);
4360    }
4361    
4362    JS_FRIEND_API(JSBool)
4363    js_CheckUndeclaredVarAssignment(JSContext *cx)
4364    {
4365        JSStackFrame *fp;
4366        if (!JS_HAS_STRICT_OPTION(cx) ||
4367            !(fp = js_GetTopStackFrame(cx)) ||
4368            !fp->regs ||
4369            js_GetOpcode(cx, fp->script, fp->regs->pc) != JSOP_SETNAME) {
4370            return JS_TRUE;
4371        }
4372    
4373        JSAtom *atom;
4374        GET_ATOM_FROM_BYTECODE(fp->script, fp->regs->pc, 0, atom);
4375    
4376        const char *bytes = js_AtomToPrintableString(cx, atom);
4377        return bytes &&
4378               JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT,
4379                                            js_GetErrorMessage, NULL,
4380                                            JSMSG_UNDECLARED_VAR, bytes);
4381    }
4382    
4383    /*
4384     * Note: all non-error exits in this function must notify the tracer using
4385     * SetPropHit when called from the interpreter loop (cacheResult is true).
4386     */
4387    JSBool
4388    js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
4389                         jsval *vp)
4390  {  {
     uint32 shape;  
4391      int protoIndex;      int protoIndex;
4392      JSObject *pobj;      JSObject *pobj;
4393      JSProperty *prop;      JSProperty *prop;
# Line 3838  Line 4397 
4397      intN shortid;      intN shortid;
4398      JSClass *clasp;      JSClass *clasp;
4399      JSPropertyOp getter, setter;      JSPropertyOp getter, setter;
4400        bool added;
4401    
4402        if (cacheResult)
4403            JS_ASSERT_NOT_ON_TRACE(cx);
4404    
4405      /* Convert string indices to integers if appropriate. */      /* Convert string indices to integers if appropriate. */
4406      CHECK_FOR_STRING_INDEX(id);      CHECK_FOR_STRING_INDEX(id);
     JS_COUNT_OPERATION(cx, JSOW_SET_PROPERTY);  
4407    
4408      shape = OBJ_SHAPE(obj);      /*
4409         * We peek at OBJ_SCOPE(obj) without locking obj. Any race means a failure
4410         * to seal before sharing, which is inherently ambiguous.
4411         */
4412        if (SCOPE_IS_SEALED(OBJ_SCOPE(obj)) && OBJ_SCOPE(obj)->object == obj) {
4413            flags = JSREPORT_ERROR;
4414            goto read_only_error;
4415        }
4416    
4417      protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,      protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,
4418                                              &pobj, &prop);                                              &pobj, &prop);
4419      if (protoIndex < 0)      if (protoIndex < 0)
4420          return JS_FALSE;          return JS_FALSE;
4421        if (prop) {
4422            if (!OBJ_IS_NATIVE(pobj)) {
4423                OBJ_DROP_PROPERTY(cx, pobj, prop);
4424                prop = NULL;
4425            }
4426        } else {
4427            /* We should never add properties to lexical blocks.  */
4428            JS_ASSERT(OBJ_GET_CLASS(cx, obj) != &js_BlockClass);
4429    
4430      if (prop && !OBJ_IS_NATIVE(pobj)) {          if (!OBJ_GET_PARENT(cx, obj) && !js_CheckUndeclaredVarAssignment(cx))
4431          OBJ_DROP_PROPERTY(cx, pobj, prop);              return JS_FALSE;
         prop = NULL;  
4432      }      }
4433      sprop = (JSScopeProperty *) prop;      sprop = (JSScopeProperty *) prop;
4434    
# Line 3880  Line 4457 
4457    
4458          attrs = sprop->attrs;          attrs = sprop->attrs;
4459          if ((attrs & JSPROP_READONLY) ||          if ((attrs & JSPROP_READONLY) ||
4460              (SCOPE_IS_SEALED(scope) && pobj == obj)) {              (SCOPE_IS_SEALED(scope) && (attrs & JSPROP_SHARED))) {
4461              JS_UNLOCK_SCOPE(cx, scope);              JS_UNLOCK_SCOPE(cx, scope);
4462    
4463              /*              /*
# Line 3895  Line 4472 
4472              if (attrs & JSPROP_READONLY) {              if (attrs & JSPROP_READONLY) {
4473                  if (!JS_HAS_STRICT_OPTION(cx)) {                  if (!JS_HAS_STRICT_OPTION(cx)) {
4474                      /* Just return true per ECMA if not in strict mode. */                      /* Just return true per ECMA if not in strict mode. */
4475                      PCMETER(!entryp || JS_PROPERTY_CACHE(cx).rofills++);                      PCMETER(cacheResult && JS_PROPERTY_CACHE(cx).rofills++);
4476                        if (cacheResult)
4477                            TRACE_2(SetPropHit, JS_NO_PROP_CACHE_FILL, sprop);
4478                      return JS_TRUE;                      return JS_TRUE;
4479                    error: // TRACE_2 jumps here in case of error.
4480                        return JS_FALSE;
4481                  }                  }
4482    
4483                  /* Strict mode: report a read-only strict warning. */                  /* Strict mode: report a read-only strict warning. */
# Line 3915  Line 4496 
4496               */               */
4497              JS_UNLOCK_SCOPE(cx, scope);              JS_UNLOCK_SCOPE(cx, scope);
4498    
4499              /*              /* Don't clone a shared prototype property. */
              * Don't clone a shared prototype property. Don't fill it in the  
              * property cache either, since the JSOP_SETPROP/JSOP_SETNAME code  
              * in js_Interpret does not handle shared or prototype properties.  
              * Shared prototype properties require more hit qualification than  
              * the fast-path code for those ops, which is targeted on direct,  
              * slot-based properties.  
              */  
4500              if (attrs & JSPROP_SHARED) {              if (attrs & JSPROP_SHARED) {
4501                  if (entryp) {                  if (cacheResult) {
4502                      PCMETER(JS_PROPERTY_CACHE(cx).nofills++);                      JSPropCacheEntry *entry;
4503                      *entryp = NULL;                      entry = js_FillPropertyCache(cx, obj, 0, protoIndex, pobj, sprop, false);
4504                        TRACE_2(SetPropHit, entry, sprop);
4505                  }                  }
4506    
4507                  if (SPROP_HAS_STUB_SETTER(sprop) &&                  if (SPROP_HAS_STUB_SETTER(sprop) &&
# Line 3934  Line 4509 
4509                      return JS_TRUE;                      return JS_TRUE;
4510                  }                  }
4511    
4512                  return !!SPROP_SET(cx, sprop, obj, pobj, vp);                  return js_SetSprop(cx, sprop, obj, vp);
4513              }              }
4514    
4515              /* Restore attrs to the ECMA default for new properties. */              /* Restore attrs to the ECMA default for new properties. */
# Line 3966  Line 4541 
4541  #endif  #endif
4542      }      }
4543    
4544        added = false;
4545      if (!sprop) {      if (!sprop) {
         if (SCOPE_IS_SEALED(OBJ_SCOPE(obj)) && OBJ_SCOPE(obj)->object == obj) {  
             flags = JSREPORT_ERROR;  
             goto read_only_error;  
         }  
   
4546          /*          /*
4547           * Purge the property cache of now-shadowed id in obj's scope chain.           * Purge the property cache of now-shadowed id in obj's scope chain.
4548           * Do this early, before locking obj to avoid nesting locks.           * Do this early, before locking obj to avoid nesting locks.
4549           */           */
4550          PurgeScopeChain(cx, obj, id);          js_PurgeScopeChain(cx, obj, id);
4551    
4552          /* Find or make a property descriptor with the right heritage. */          /* Find or make a property descriptor with the right heritage. */
4553          JS_LOCK_OBJ(cx, obj);          JS_LOCK_OBJ(cx, obj);
# Line 4007  Line 4578 
4578                              js_RemoveScopeProperty(cx, scope, id);                              js_RemoveScopeProperty(cx, scope, id);
4579                              JS_UNLOCK_SCOPE(cx, scope);                              JS_UNLOCK_SCOPE(cx, scope);
4580                              return JS_FALSE);                              return JS_FALSE);
4581            added = true;
4582        }
4583    
4584        if (cacheResult) {
4585            JSPropCacheEntry *entry;
4586            entry = js_FillPropertyCache(cx, obj, 0, 0, obj, sprop, added);
4587            TRACE_2(SetPropHit, entry, sprop);
4588      }      }
4589    
4590      if (!js_NativeSet(cx, obj, sprop, vp))      if (!js_NativeSet(cx, obj, sprop, vp))
4591          return JS_FALSE;          return NULL;
4592    
     if (entryp) {  
         if (!(attrs & JSPROP_SHARED))  
             js_FillPropertyCache(cx, obj, shape, 0, 0, obj, sprop, entryp);  
         else  
             PCMETER(JS_PROPERTY_CACHE(cx).nofills++);  
     }  
4593      JS_UNLOCK_SCOPE(cx, scope);      JS_UNLOCK_SCOPE(cx, scope);
4594      return JS_TRUE;      return JS_TRUE;
4595    
# Line 4030  Line 4602 
4602  JSBool  JSBool
4603  js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)  js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
4604  {  {
4605      return js_SetPropertyHelper(cx, obj, id, vp, NULL);      return js_SetPropertyHelper(cx, obj, id, false, vp);
4606  }  }
4607    
4608  JSBool  JSBool
# Line 4101  Line 4673 
4673    
4674      /* Convert string indices to integers if appropriate. */      /* Convert string indices to integers if appropriate. */
4675      CHECK_FOR_STRING_INDEX(id);      CHECK_FOR_STRING_INDEX(id);
     JS_COUNT_OPERATION(cx, JSOW_DELETE_PROPERTY);  
4676    
4677      if (!js_LookupProperty(cx, obj, id, &proto, &prop))      if (!js_LookupProperty(cx, obj, id, &proto, &prop))
4678          return JS_FALSE;          return JS_FALSE;
# Line 4627  Line 5198 
5198          if (VALUE_IS_FUNCTION(cx, fval)) {          if (VALUE_IS_FUNCTION(cx, fval)) {
5199              if (!GetCurrentExecutionContext(cx, obj, &nargv[2]))              if (!GetCurrentExecutionContext(cx, obj, &nargv[2]))
5200                  return JS_FALSE;                  return JS_FALSE;
5201              args = js_GetArgsObject(cx, cx->fp);              args = js_GetArgsObject(cx, js_GetTopStackFrame(cx));
5202              if (!args)              if (!args)
5203                  return JS_FALSE;                  return JS_FALSE;
5204              nargv[0] = OBJECT_TO_JSVAL(obj);              nargv[0] = OBJECT_TO_JSVAL(obj);
# Line 4641  Line 5212 
5212              return ok;              return ok;
5213          }          }
5214  #endif  #endif
5215          js_ReportIsNotFunction(cx, &argv[-2], cx->fp->flags & JSFRAME_ITERATOR);          js_ReportIsNotFunction(cx, &argv[-2], js_GetTopStackFrame(cx)->flags & JSFRAME_ITERATOR);
5216          return JS_FALSE;          return JS_FALSE;
5217      }      }
5218      return clasp->call(cx, obj, argc, argv, rval);      return clasp->call(cx, obj, argc, argv, rval);
# Line 4670  Line 5241 
5241          if (VALUE_IS_FUNCTION(cx, cval)) {          if (VALUE_IS_FUNCTION(cx, cval)) {
5242              if (!GetCurrentExecutionContext(cx, obj, &nargv[1]))              if (!GetCurrentExecutionContext(cx, obj, &nargv[1]))
5243                  return JS_FALSE;                  return JS_FALSE;
5244              args = js_GetArgsObject(cx, cx->fp);              args = js_GetArgsObject(cx, js_GetTopStackFrame(cx));
5245              if (!args)              if (!args)
5246                  return JS_FALSE;                  return JS_FALSE;
5247              nargv[0] = OBJECT_TO_JSVAL(args);              nargv[0] = OBJECT_TO_JSVAL(args);
# Line 4885  Line 5456 
5456          obj = JSVAL_TO_OBJECT(v);          obj = JSVAL_TO_OBJECT(v);
5457          if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_OBJECT, &v))          if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_OBJECT, &v))
5458              return JS_FALSE;              return JS_FALSE;
5459          if (JSVAL_IS_OBJECT(v))          if (!JSVAL_IS_PRIMITIVE(v))
5460              obj = JSVAL_TO_OBJECT(v);              obj = JSVAL_TO_OBJECT(v);
5461      } else {      } else {
5462          if (!js_PrimitiveToObject(cx, &v))          if (!js_PrimitiveToObject(cx, &v))
# Line 4937  Line 5508 
5508      older = JS_SetErrorReporter(cx, NULL);      older = JS_SetErrorReporter(cx, NULL);
5509      id = ATOM_TO_JSID(atom);      id = ATOM_TO_JSID(atom);
5510      fval = JSVAL_VOID;      fval = JSVAL_VOID;
5511  #if JS_HAS_XML_SUPPORT      ok = js_GetMethod(cx, obj, id, false, &fval);
     if (OBJECT_IS_XML(cx, obj)) {  
         JSXMLObjectOps *ops;  
   
         ops = (JSXMLObjectOps *) obj->map->ops;  
         obj = ops->getMethod(cx, obj, id, &fval);  
         ok = (obj != NULL);  
     } else  
 #endif  
     {  
         ok = OBJ_GET_PROPERTY(cx, obj, id, &fval);  
     }  
5512      if (!ok)      if (!ok)
5513          JS_ClearPendingException(cx);          JS_ClearPendingException(cx);
5514      JS_SetErrorReporter(cx, older);      JS_SetErrorReporter(cx, older);
5515    
5516      return JSVAL_IS_PRIMITIVE(fval) ||      if (JSVAL_IS_PRIMITIVE(fval))
5517             js_InternalCall(cx, obj, fval, argc, argv, rval);          return JS_TRUE;
5518        return js_InternalCall(cx, obj, fval, argc, argv, rval);
5519  }  }
5520    
5521  #if JS_HAS_XDR  #if JS_HAS_XDR
# Line 5189  Line 5750 
5750              if (IS_GC_MARKING_TRACER(trc)) {              if (IS_GC_MARKING_TRACER(trc)) {
5751                  uint32 shape, oldshape;                  uint32 shape, oldshape;
5752    
5753                  shape = ++cx->runtime->shapeGen;                  shape = js_RegenerateShapeForGC(cx);
                 JS_ASSERT(shape != 0);  
   
5754                  if (!(sprop->flags & SPROP_MARK)) {                  if (!(sprop->flags & SPROP_MARK)) {
5755                      oldshape = sprop->shape;                      oldshape = sprop->shape;
5756                      sprop->shape = shape;                      sprop->shape = shape;
5757                      sprop->flags |= SPROP_FLAG_SHAPE_REGEN;                      sprop->flags |= SPROP_FLAG_SHAPE_REGEN;
5758                      if (scope->shape != oldshape) {                      if (scope->shape != oldshape)
5759                          shape = ++cx->runtime->shapeGen;                          shape = js_RegenerateShapeForGC(cx);
                         JS_ASSERT(shape != 0);  
                     }  
5760                  }                  }
5761    
5762                  scope->shape = shape;                  scope->shape = shape;
# Line 5238  Line 5795 
5795       * above.       * above.
5796       */       */
5797      nslots = STOBJ_NSLOTS(obj);      nslots = STOBJ_NSLOTS(obj);
5798      if (scope->object == obj && scope->map.freeslot < nslots)      if (scope->object == obj && scope->freeslot < nslots)
5799          nslots = scope->map.freeslot;          nslots = scope->freeslot;
5800    
5801      for (i = 0; i != nslots; ++i) {      for (i = 0; i != nslots; ++i) {
5802          v = STOBJ_GET_SLOT(obj, i);          v = STOBJ_GET_SLOT(obj, i);
# Line 5273  Line 5830 
5830          n = JSSLOT_FREE(LOCKED_OBJ_GET_CLASS(obj));          n = JSSLOT_FREE(LOCKED_OBJ_GET_CLASS(obj));
5831          while (--i >= n)          while (--i >= n)
5832              STOBJ_SET_SLOT(obj, i, JSVAL_VOID);              STOBJ_SET_SLOT(obj, i, JSVAL_VOID);
5833          scope->map.freeslot = n;          scope->freeslot = n;
5834      }      }
5835      JS_UNLOCK_OBJ(cx, obj);      JS_UNLOCK_OBJ(cx, obj);
5836  }  }
# Line 5322  Line 5879 
5879      }      }
5880    
5881      /* Whether or not we grew nslots, we may need to advance freeslot. */      /* Whether or not we grew nslots, we may need to advance freeslot. */
5882      if (scope->object == obj && slot >= scope->map.freeslot)      if (scope->object == obj && slot >= scope->freeslot)
5883          scope->map.freeslot = slot + 1;          scope->freeslot = slot + 1;
5884    
5885      STOBJ_SET_SLOT(obj, slot, v);      STOBJ_SET_SLOT(obj, slot, v);
5886        GC_POKE(cx, JS_NULL);
5887      JS_UNLOCK_SCOPE(cx, scope);      JS_UNLOCK_SCOPE(cx, scope);
5888      return JS_TRUE;      return JS_TRUE;
5889  }  }
# Line 5347  Line 5905 
5905      return obj;      return obj;
5906  }  }
5907    
5908  #if DEBUG  JSBool
5909    js_IsCallable(JSObject *obj, JSContext *cx)
5910    {
5911        if (!OBJ_IS_NATIVE(obj))
5912            return obj->map->ops->call != NULL;
5913    
5914        JS_LOCK_OBJ(cx, obj);
5915        JSBool callable = (obj->map->ops == &js_ObjectOps)
5916                          ? HAS_FUNCTION_CLASS(obj) || STOBJ_GET_CLASS(obj)->call
5917                          : obj->map->ops->call != NULL;
5918        JS_UNLOCK_OBJ(cx, obj);
5919        return callable;
5920    }
5921    
5922    void
5923    js_ReportGetterOnlyAssignment(JSContext *cx)
5924    {
5925        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5926                             JSMSG_GETTER_ONLY, NULL);
5927    }
5928    
5929    
5930    JS_FRIEND_API(JSBool)
5931    js_GetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
5932    {
5933        js_ReportGetterOnlyAssignment(cx);
5934        return JS_FALSE;
5935    }
5936    
5937    #ifdef DEBUG
5938    
5939  /*  /*
5940   * Routines to print out values during debugging.  These are FRIEND_API to help   * Routines to print out values during debugging.  These are FRIEND_API to help
# Line 5417  Line 6004 
6004          fprintf(stderr, "null");          fprintf(stderr, "null");
6005      } else if (JSVAL_IS_VOID(val)) {      } else if (JSVAL_IS_VOID(val)) {
6006          fprintf(stderr, "undefined");          fprintf(stderr, "undefined");
6007        } else if (JSVAL_IS_OBJECT(val) &&
6008                   HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(val))) {
6009            JSObject *funobj = JSVAL_TO_OBJECT(val);
6010            JSFunction *fun = (JSFunction *) STOBJ_GET_PRIVATE(funobj);
6011            fprintf(stderr, "<%s %s at %p (JSFunction at %p)>",
6012                    fun->atom ? "function" : "unnamed",
6013                    fun->atom ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom)) : "function",
6014                    (void *) funobj,
6015                    (void *) fun);
6016      } else if (JSVAL_IS_OBJECT(val)) {      } else if (JSVAL_IS_OBJECT(val)) {
6017          JSObject *obj = JSVAL_TO_OBJECT(val);          JSObject *obj = JSVAL_TO_OBJECT(val);
6018          JSClass *cls = STOBJ_GET_CLASS(obj);          JSClass *cls = STOBJ_GET_CLASS(obj);
6019          fprintf(stderr, "<%s%s at %p>",          fprintf(stderr, "<%s%s at %p>",
6020                  cls->name,                  cls->name,
6021                  cls == &js_ObjectClass ? "" : " object",                  cls == &js_ObjectClass ? "" : " object",
6022                  obj);                  (void *) obj);
6023      } else if (JSVAL_IS_INT(val)) {      } else if (JSVAL_IS_INT(val)) {
6024          fprintf(stderr, "%d", JSVAL_TO_INT(val));          fprintf(stderr, "%d", JSVAL_TO_INT(val));
6025      } else if (JSVAL_IS_STRING(val)) {      } else if (JSVAL_IS_STRING(val)) {
# Line 5488  Line 6084 
6084      uint32 i, slots;      uint32 i, slots;
6085      JSClass *clasp;      JSClass *clasp;
6086      jsuint reservedEnd;      jsuint reservedEnd;
6087      JSBool sharesScope = JS_FALSE;      bool sharesScope = false;
6088    
6089      fprintf(stderr, "object %p\n", (void *) obj);      fprintf(stderr, "object %p\n", (void *) obj);
6090      clasp = STOBJ_GET_CLASS(obj);      clasp = STOBJ_GET_CLASS(obj);
# Line 5497  Line 6093 
6093      /* OBJ_IS_DENSE_ARRAY ignores the cx argument. */      /* OBJ_IS_DENSE_ARRAY ignores the cx argument. */
6094      if (OBJ_IS_DENSE_ARRAY(BOGUS_CX, obj)) {      if (OBJ_IS_DENSE_ARRAY(BOGUS_CX, obj)) {
6095          slots = JS_MIN((jsuint) obj->fslots[JSSLOT_ARRAY_LENGTH],          slots = JS_MIN((jsuint) obj->fslots[JSSLOT_ARRAY_LENGTH],
6096                         ARRAY_DENSE_LENGTH(obj));                         js_DenseArrayCapacity(obj));
6097          fprintf(stderr, "elements\n");          fprintf(stderr, "elements\n");
6098          for (i = 0; i < slots; i++) {          for (i = 0; i < slots; i++) {
6099              fprintf(stderr, " %3d: ", i);              fprintf(stderr, " %3d: ", i);
# Line 5517  Line 6113 
6113    
6114          sharesScope = (scope->object != obj);          sharesScope = (scope->object != obj);
6115          if (sharesScope) {          if (sharesScope) {
6116              fprintf(stderr, "no own properties - see proto (%s at %p)\n",              if (proto) {
6117                      STOBJ_GET_CLASS(proto)->name, proto);                  fprintf(stderr, "no own properties - see proto (%s at %p)\n",
6118                            STOBJ_GET_CLASS(proto)->name, (void *) proto);
6119                } else {
6120                    fprintf(stderr, "no own properties - null proto\n");
6121                }
6122          } else {          } else {
6123              fprintf(stderr, "properties:\n");              fprintf(stderr, "properties:\n");
6124              for (JSScopeProperty *sprop = SCOPE_LAST_PROP(scope); sprop;              for (JSScopeProperty *sprop = SCOPE_LAST_PROP(scope); sprop;
# Line 5539  Line 6139 
6139      if (clasp->flags & JSCLASS_HAS_PRIVATE)      if (clasp->flags & JSCLASS_HAS_PRIVATE)
6140          reservedEnd++;          reservedEnd++;
6141      reservedEnd += JSCLASS_RESERVED_SLOTS(clasp);      reservedEnd += JSCLASS_RESERVED_SLOTS(clasp);
6142      slots = sharesScope ? reservedEnd : obj->map->freeslot;      slots = (OBJ_IS_NATIVE(obj) && !sharesScope)
6143                ? OBJ_SCOPE(obj)->freeslot
6144                : STOBJ_NSLOTS(obj);
6145      for (i = 0; i < slots; i++) {      for (i = 0; i < slots; i++) {
6146          fprintf(stderr, " %3d ", i);          fprintf(stderr, " %3d ", i);
6147          if (i == JSSLOT_PRIVATE && (clasp->flags & JSCLASS_HAS_PRIVATE)) {          if (i == JSSLOT_PRIVATE && (clasp->flags & JSCLASS_HAS_PRIVATE)) {

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

  ViewVC Help
Powered by ViewVC 1.1.24