jbarnette-johnson 1.0.0.20090326161333 → 1.0.0.20090402144841

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -299,8 +299,13 @@ js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj)
299
299
  JS_LOCK_GC(rt);
300
300
  ssr.next = rt->setSlotRequests;
301
301
  rt->setSlotRequests = &ssr;
302
- js_GC(cx, GC_SET_SLOT_REQUEST);
303
- JS_UNLOCK_GC(rt);
302
+ for (;;) {
303
+ js_GC(cx, GC_SET_SLOT_REQUEST);
304
+ JS_UNLOCK_GC(rt);
305
+ if (!rt->setSlotRequests)
306
+ break;
307
+ JS_LOCK_GC(rt);
308
+ }
304
309
 
305
310
  if (ssr.errnum != JSMSG_NOT_AN_ERROR) {
306
311
  if (ssr.errnum == JSMSG_OUT_OF_MEMORY) {
@@ -1140,8 +1145,10 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
1140
1145
  {
1141
1146
  uint32 flags;
1142
1147
 
1148
+ JS_ASSERT(principals || !cx->runtime->findObjectPrincipals);
1143
1149
  flags = JS_GetScriptFilenameFlags(caller->script);
1144
1150
  if ((flags & JSFILENAME_PROTECTED) &&
1151
+ principals &&
1145
1152
  strcmp(principals->codebase, "[System Principal]")) {
1146
1153
  *linenop = 0;
1147
1154
  return principals->codebase;
@@ -1214,13 +1221,16 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1214
1221
  return JS_FALSE;
1215
1222
 
1216
1223
  /*
1217
- * Script.prototype.compile/exec and Object.prototype.eval all take an
1218
- * optional trailing argument that overrides the scope object.
1224
+ * Script.prototype.compile/exec and Object.prototype.eval no longer take
1225
+ * an optional trailing argument.
1219
1226
  */
1220
1227
  if (argc >= 2) {
1221
- if (!js_ValueToObject(cx, argv[1], &scopeobj))
1228
+ if (!JS_ReportErrorFlagsAndNumber(cx,
1229
+ JSREPORT_WARNING | JSREPORT_STRICT,
1230
+ js_GetErrorMessage, NULL,
1231
+ JSMSG_EVAL_ARITY)) {
1222
1232
  return JS_FALSE;
1223
- argv[1] = OBJECT_TO_JSVAL(scopeobj);
1233
+ }
1224
1234
  }
1225
1235
 
1226
1236
  /* From here on, control must exit through label out with ok set. */
@@ -1242,7 +1252,7 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1242
1252
  }
1243
1253
  if (obj != callerScopeChain) {
1244
1254
  ok = js_CheckPrincipalsAccess(cx, obj,
1245
- caller->script->principals,
1255
+ JS_StackFramePrincipals(cx, caller),
1246
1256
  cx->runtime->atomState.evalAtom);
1247
1257
  if (!ok)
1248
1258
  goto out;
@@ -1432,6 +1442,9 @@ obj_watch(JSContext *cx, uintN argc, jsval *vp)
1432
1442
  if (attrs & JSPROP_READONLY)
1433
1443
  return JS_TRUE;
1434
1444
  *vp = JSVAL_VOID;
1445
+
1446
+ if (OBJ_IS_DENSE_ARRAY(cx, obj) && !js_MakeArraySlow(cx, obj))
1447
+ return JS_FALSE;
1435
1448
  return JS_SetWatchPoint(cx, obj, userid, obj_watch_handler, callable);
1436
1449
  }
1437
1450
 
@@ -3341,7 +3354,8 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3341
3354
  /* Resolved: juggle locks and lookup id again. */
3342
3355
  if (obj2 != obj) {
3343
3356
  JS_UNLOCK_OBJ(cx, obj);
3344
- JS_LOCK_OBJ(cx, obj2);
3357
+ if (OBJ_IS_NATIVE(obj2))
3358
+ JS_LOCK_OBJ(cx, obj2);
3345
3359
  }
3346
3360
  protoIndex = 0;
3347
3361
  for (proto = start; proto && proto != obj2;
@@ -3352,7 +3366,6 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3352
3366
  if (!MAP_IS_NATIVE(&scope->map)) {
3353
3367
  /* Whoops, newresolve handed back a foreign obj2. */
3354
3368
  JS_ASSERT(obj2 != obj);
3355
- JS_UNLOCK_OBJ(cx, obj2);
3356
3369
  ok = OBJ_LOOKUP_PROPERTY(cx, obj2, id, objp, propp);
3357
3370
  if (!ok || *propp)
3358
3371
  goto cleanup;
@@ -3373,7 +3386,8 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3373
3386
  JS_ASSERT(obj2 == scope->object);
3374
3387
  obj = obj2;
3375
3388
  } else if (obj2 != obj) {
3376
- JS_UNLOCK_OBJ(cx, obj2);
3389
+ if (OBJ_IS_NATIVE(obj2))
3390
+ JS_UNLOCK_OBJ(cx, obj2);
3377
3391
  JS_LOCK_OBJ(cx, obj);
3378
3392
  }
3379
3393
  }
@@ -4359,8 +4373,10 @@ js_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
4359
4373
 
4360
4374
  /* Avoid diverging for non-natives that reuse js_CheckAccess. */
4361
4375
  if (pobj->map->ops->checkAccess == js_CheckAccess) {
4362
- if (!writing)
4376
+ if (!writing) {
4363
4377
  *vp = JSVAL_VOID;
4378
+ *attrsp = 0;
4379
+ }
4364
4380
  break;
4365
4381
  }
4366
4382
  return OBJ_CHECK_ACCESS(cx, pobj, id, mode, vp, attrsp);
@@ -4824,7 +4824,7 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
4824
4824
 
4825
4825
  for (fp = cx->fp; fp && !fp->script; fp = fp->down)
4826
4826
  continue;
4827
- if (!fp || !fp->regs)
4827
+ if (!fp || !fp->regs || !fp->regs->sp)
4828
4828
  goto do_fallback;
4829
4829
 
4830
4830
  script = fp->script;
@@ -2029,6 +2029,16 @@ CheckDestructuring(JSContext *cx, BindData *data,
2029
2029
  return JS_FALSE;
2030
2030
  }
2031
2031
 
2032
+ #if JS_HAS_DESTRUCTURING_SHORTHAND
2033
+ if (right &&
2034
+ right->pn_arity == PN_LIST &&
2035
+ (right->pn_extra & PNX_SHORTHAND)) {
2036
+ js_ReportCompileErrorNumber(cx, TS(tc->parseContext), right,
2037
+ JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT);
2038
+ return JS_FALSE;
2039
+ }
2040
+ #endif
2041
+
2032
2042
  fpvd.table.ops = NULL;
2033
2043
  lhs = left->pn_head;
2034
2044
  if (lhs && lhs->pn_type == TOK_DEFSHARP) {
@@ -4555,18 +4565,32 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
4555
4565
  pn2->pn_pos.begin = pn->pn_pos.begin;
4556
4566
  pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
4557
4567
 
4558
- /* Optimize o['p'] to o.p by rewriting pn2. */
4559
- if (pn3->pn_type == TOK_STRING) {
4560
- pn2->pn_type = TOK_DOT;
4561
- pn2->pn_op = JSOP_GETPROP;
4562
- pn2->pn_arity = PN_NAME;
4563
- pn2->pn_expr = pn;
4564
- pn2->pn_atom = pn3->pn_atom;
4565
- } else {
4568
+ /*
4569
+ * Optimize o['p'] to o.p by rewriting pn2, but avoid rewriting
4570
+ * o['0'] to use JSOP_GETPROP, to keep fast indexing disjoint in
4571
+ * the interpreter from fast property access. However, if the
4572
+ * bracketed string is a uint32, we rewrite pn3 to be a number
4573
+ * instead of a string.
4574
+ */
4575
+ do {
4576
+ if (pn3->pn_type == TOK_STRING) {
4577
+ jsuint index;
4578
+
4579
+ if (!js_IdIsIndex(ATOM_TO_JSID(pn3->pn_atom), &index)) {
4580
+ pn2->pn_type = TOK_DOT;
4581
+ pn2->pn_op = JSOP_GETPROP;
4582
+ pn2->pn_arity = PN_NAME;
4583
+ pn2->pn_expr = pn;
4584
+ pn2->pn_atom = pn3->pn_atom;
4585
+ break;
4586
+ }
4587
+ pn3->pn_type = TOK_NUMBER;
4588
+ pn3->pn_dval = index;
4589
+ }
4566
4590
  pn2->pn_op = JSOP_GETELEM;
4567
4591
  pn2->pn_left = pn;
4568
4592
  pn2->pn_right = pn3;
4569
- }
4593
+ } while (0);
4570
4594
  } else if (allowCallSyntax && tt == TOK_LP) {
4571
4595
  pn2 = NewParseNode(cx, ts, PN_LIST, tc);
4572
4596
  if (!pn2)
@@ -3622,12 +3622,17 @@ regexp_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
3622
3622
 
3623
3623
  if (!JSVAL_IS_INT(id))
3624
3624
  return JS_TRUE;
3625
+ while (OBJ_GET_CLASS(cx, obj) != &js_RegExpClass) {
3626
+ obj = OBJ_GET_PROTO(cx, obj);
3627
+ if (!obj)
3628
+ return JS_TRUE;
3629
+ }
3625
3630
  slot = JSVAL_TO_INT(id);
3626
3631
  if (slot == REGEXP_LAST_INDEX)
3627
3632
  return JS_GetReservedSlot(cx, obj, 0, vp);
3628
3633
 
3629
3634
  JS_LOCK_OBJ(cx, obj);
3630
- re = (JSRegExp *) JS_GetInstancePrivate(cx, obj, &js_RegExpClass, NULL);
3635
+ re = (JSRegExp *) JS_GetPrivate(cx, obj);
3631
3636
  if (re) {
3632
3637
  switch (slot) {
3633
3638
  case REGEXP_SOURCE:
@@ -3661,6 +3666,11 @@ regexp_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
3661
3666
  ok = JS_TRUE;
3662
3667
  if (!JSVAL_IS_INT(id))
3663
3668
  return ok;
3669
+ while (OBJ_GET_CLASS(cx, obj) != &js_RegExpClass) {
3670
+ obj = OBJ_GET_PROTO(cx, obj);
3671
+ if (!obj)
3672
+ return JS_TRUE;
3673
+ }
3664
3674
  slot = JSVAL_TO_INT(id);
3665
3675
  if (slot == REGEXP_LAST_INDEX) {
3666
3676
  if (!JS_ValueToNumber(cx, *vp, &lastIndex))
@@ -4298,10 +4308,12 @@ js_NewRegExpObject(JSContext *cx, JSTokenStream *ts,
4298
4308
  str = js_NewStringCopyN(cx, chars, length);
4299
4309
  if (!str)
4300
4310
  return NULL;
4311
+ JS_PUSH_TEMP_ROOT_STRING(cx, str, &tvr);
4301
4312
  re = js_NewRegExp(cx, ts, str, flags, JS_FALSE);
4302
- if (!re)
4313
+ if (!re) {
4314
+ JS_POP_TEMP_ROOT(cx, &tvr);
4303
4315
  return NULL;
4304
- JS_PUSH_TEMP_ROOT_STRING(cx, str, &tvr);
4316
+ }
4305
4317
  obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL, 0);
4306
4318
  if (!obj || !JS_SetPrivate(cx, obj, re)) {
4307
4319
  js_DestroyRegExp(cx, re);
@@ -298,150 +298,144 @@ GetChar(JSTokenStream *ts)
298
298
  if (ts->ungetpos != 0) {
299
299
  c = ts->ungetbuf[--ts->ungetpos];
300
300
  } else {
301
- do {
302
- if (ts->linebuf.ptr == ts->linebuf.limit) {
303
- len = PTRDIFF(ts->userbuf.limit, ts->userbuf.ptr, jschar);
301
+ if (ts->linebuf.ptr == ts->linebuf.limit) {
302
+ len = PTRDIFF(ts->userbuf.limit, ts->userbuf.ptr, jschar);
303
+ if (len <= 0) {
304
+ if (!ts->file) {
305
+ ts->flags |= TSF_EOF;
306
+ return EOF;
307
+ }
308
+
309
+ /* Fill ts->userbuf so that \r and \r\n convert to \n. */
310
+ crflag = (ts->flags & TSF_CRFLAG) != 0;
311
+ len = js_fgets(cbuf, JS_LINE_LIMIT - crflag, ts->file);
304
312
  if (len <= 0) {
305
- if (!ts->file) {
306
- ts->flags |= TSF_EOF;
307
- return EOF;
308
- }
309
-
310
- /* Fill ts->userbuf so that \r and \r\n convert to \n. */
311
- crflag = (ts->flags & TSF_CRFLAG) != 0;
312
- len = js_fgets(cbuf, JS_LINE_LIMIT - crflag, ts->file);
313
- if (len <= 0) {
314
- ts->flags |= TSF_EOF;
315
- return EOF;
316
- }
317
- olen = len;
318
- ubuf = ts->userbuf.base;
319
- i = 0;
320
- if (crflag) {
321
- ts->flags &= ~TSF_CRFLAG;
322
- if (cbuf[0] != '\n') {
323
- ubuf[i++] = '\n';
324
- len++;
325
- ts->linepos--;
326
- }
327
- }
328
- for (j = 0; i < len; i++, j++)
329
- ubuf[i] = (jschar) (unsigned char) cbuf[j];
330
- ts->userbuf.limit = ubuf + len;
331
- ts->userbuf.ptr = ubuf;
313
+ ts->flags |= TSF_EOF;
314
+ return EOF;
332
315
  }
333
- if (ts->listener) {
334
- ts->listener(ts->filename, ts->lineno, ts->userbuf.ptr, len,
335
- &ts->listenerTSData, ts->listenerData);
316
+ olen = len;
317
+ ubuf = ts->userbuf.base;
318
+ i = 0;
319
+ if (crflag) {
320
+ ts->flags &= ~TSF_CRFLAG;
321
+ if (cbuf[0] != '\n') {
322
+ ubuf[i++] = '\n';
323
+ len++;
324
+ ts->linepos--;
325
+ }
336
326
  }
337
-
338
- nl = ts->saveEOL;
339
- if (!nl) {
327
+ for (j = 0; i < len; i++, j++)
328
+ ubuf[i] = (jschar) (unsigned char) cbuf[j];
329
+ ts->userbuf.limit = ubuf + len;
330
+ ts->userbuf.ptr = ubuf;
331
+ }
332
+ if (ts->listener) {
333
+ ts->listener(ts->filename, ts->lineno, ts->userbuf.ptr, len,
334
+ &ts->listenerTSData, ts->listenerData);
335
+ }
336
+
337
+ nl = ts->saveEOL;
338
+ if (!nl) {
339
+ /*
340
+ * Any one of \n, \r, or \r\n ends a line (the longest
341
+ * match wins). Also allow the Unicode line and paragraph
342
+ * separators.
343
+ */
344
+ for (nl = ts->userbuf.ptr; nl < ts->userbuf.limit; nl++) {
340
345
  /*
341
- * Any one of \n, \r, or \r\n ends a line (the longest
342
- * match wins). Also allow the Unicode line and paragraph
343
- * separators.
346
+ * Try to prevent value-testing on most characters by
347
+ * filtering out characters that aren't 000x or 202x.
344
348
  */
345
- for (nl = ts->userbuf.ptr; nl < ts->userbuf.limit; nl++) {
346
- /*
347
- * Try to prevent value-testing on most characters by
348
- * filtering out characters that aren't 000x or 202x.
349
- */
350
- if ((*nl & 0xDFD0) == 0) {
351
- if (*nl == '\n')
352
- break;
353
- if (*nl == '\r') {
354
- if (nl + 1 < ts->userbuf.limit && nl[1] == '\n')
355
- nl++;
356
- break;
357
- }
358
- if (*nl == LINE_SEPARATOR || *nl == PARA_SEPARATOR)
359
- break;
349
+ if ((*nl & 0xDFD0) == 0) {
350
+ if (*nl == '\n')
351
+ break;
352
+ if (*nl == '\r') {
353
+ if (nl + 1 < ts->userbuf.limit && nl[1] == '\n')
354
+ nl++;
355
+ break;
360
356
  }
357
+ if (*nl == LINE_SEPARATOR || *nl == PARA_SEPARATOR)
358
+ break;
361
359
  }
362
360
  }
363
-
364
- /*
365
- * If there was a line terminator, copy thru it into linebuf.
366
- * Else copy JS_LINE_LIMIT-1 bytes into linebuf.
367
- */
368
- if (nl < ts->userbuf.limit)
369
- len = PTRDIFF(nl, ts->userbuf.ptr, jschar) + 1;
370
- if (len >= JS_LINE_LIMIT) {
371
- len = JS_LINE_LIMIT - 1;
372
- ts->saveEOL = nl;
373
- } else {
374
- ts->saveEOL = NULL;
375
- }
376
- js_strncpy(ts->linebuf.base, ts->userbuf.ptr, len);
377
- ts->userbuf.ptr += len;
378
- olen = len;
379
-
380
- /*
381
- * Make sure linebuf contains \n for EOL (don't do this in
382
- * userbuf because the user's string might be readonly).
383
- */
384
- if (nl < ts->userbuf.limit) {
385
- if (*nl == '\r') {
386
- if (ts->linebuf.base[len-1] == '\r') {
387
- /*
388
- * Does the line segment end in \r? We must check
389
- * for a \n at the front of the next segment before
390
- * storing a \n into linebuf. This case matters
391
- * only when we're reading from a file.
392
- */
393
- if (nl + 1 == ts->userbuf.limit && ts->file) {
394
- len--;
395
- ts->flags |= TSF_CRFLAG; /* clear NLFLAG? */
396
- if (len == 0) {
397
- /*
398
- * This can happen when a segment ends in
399
- * \r\r. Start over. ptr == limit in this
400
- * case, so we'll fall into buffer-filling
401
- * code.
402
- */
403
- return GetChar(ts);
404
- }
405
- } else {
406
- ts->linebuf.base[len-1] = '\n';
407
- }
408
- }
409
- } else if (*nl == '\n') {
410
- if (nl > ts->userbuf.base &&
411
- nl[-1] == '\r' &&
412
- ts->linebuf.base[len-2] == '\r') {
361
+ }
362
+
363
+ /*
364
+ * If there was a line terminator, copy thru it into linebuf.
365
+ * Else copy JS_LINE_LIMIT-1 bytes into linebuf.
366
+ */
367
+ if (nl < ts->userbuf.limit)
368
+ len = PTRDIFF(nl, ts->userbuf.ptr, jschar) + 1;
369
+ if (len >= JS_LINE_LIMIT) {
370
+ len = JS_LINE_LIMIT - 1;
371
+ ts->saveEOL = nl;
372
+ } else {
373
+ ts->saveEOL = NULL;
374
+ }
375
+ js_strncpy(ts->linebuf.base, ts->userbuf.ptr, len);
376
+ ts->userbuf.ptr += len;
377
+ olen = len;
378
+
379
+ /*
380
+ * Make sure linebuf contains \n for EOL (don't do this in
381
+ * userbuf because the user's string might be readonly).
382
+ */
383
+ if (nl < ts->userbuf.limit) {
384
+ if (*nl == '\r') {
385
+ if (ts->linebuf.base[len-1] == '\r') {
386
+ /*
387
+ * Does the line segment end in \r? We must check
388
+ * for a \n at the front of the next segment before
389
+ * storing a \n into linebuf. This case matters
390
+ * only when we're reading from a file.
391
+ */
392
+ if (nl + 1 == ts->userbuf.limit && ts->file) {
413
393
  len--;
414
- JS_ASSERT(ts->linebuf.base[len] == '\n');
394
+ ts->flags |= TSF_CRFLAG; /* clear NLFLAG? */
395
+ if (len == 0) {
396
+ /*
397
+ * This can happen when a segment ends in
398
+ * \r\r. Start over. ptr == limit in this
399
+ * case, so we'll fall into buffer-filling
400
+ * code.
401
+ */
402
+ return GetChar(ts);
403
+ }
404
+ } else {
415
405
  ts->linebuf.base[len-1] = '\n';
416
406
  }
417
- } else if (*nl == LINE_SEPARATOR || *nl == PARA_SEPARATOR) {
407
+ }
408
+ } else if (*nl == '\n') {
409
+ if (nl > ts->userbuf.base &&
410
+ nl[-1] == '\r' &&
411
+ ts->linebuf.base[len-2] == '\r') {
412
+ len--;
413
+ JS_ASSERT(ts->linebuf.base[len] == '\n');
418
414
  ts->linebuf.base[len-1] = '\n';
419
415
  }
416
+ } else if (*nl == LINE_SEPARATOR || *nl == PARA_SEPARATOR) {
417
+ ts->linebuf.base[len-1] = '\n';
420
418
  }
421
-
422
- /* Reset linebuf based on adjusted segment length. */
423
- ts->linebuf.limit = ts->linebuf.base + len;
424
- ts->linebuf.ptr = ts->linebuf.base;
425
-
426
- /* Update position of linebuf within physical userbuf line. */
427
- if (!(ts->flags & TSF_NLFLAG))
428
- ts->linepos += ts->linelen;
429
- else
430
- ts->linepos = 0;
431
- if (ts->linebuf.limit[-1] == '\n')
432
- ts->flags |= TSF_NLFLAG;
433
- else
434
- ts->flags &= ~TSF_NLFLAG;
435
-
436
- /* Update linelen from original segment length. */
437
- ts->linelen = olen;
438
419
  }
439
- c = *ts->linebuf.ptr++;
440
- /*
441
- * In the hopes of being liberal in what we accept, we toss out little-
442
- * and big-endian byte order markers here, see bug 368516.
443
- */
444
- } while (c == 0xfffe || c == 0xfeff);
420
+
421
+ /* Reset linebuf based on adjusted segment length. */
422
+ ts->linebuf.limit = ts->linebuf.base + len;
423
+ ts->linebuf.ptr = ts->linebuf.base;
424
+
425
+ /* Update position of linebuf within physical userbuf line. */
426
+ if (!(ts->flags & TSF_NLFLAG))
427
+ ts->linepos += ts->linelen;
428
+ else
429
+ ts->linepos = 0;
430
+ if (ts->linebuf.limit[-1] == '\n')
431
+ ts->flags |= TSF_NLFLAG;
432
+ else
433
+ ts->flags &= ~TSF_NLFLAG;
434
+
435
+ /* Update linelen from original segment length. */
436
+ ts->linelen = olen;
437
+ }
438
+ c = *ts->linebuf.ptr++;
445
439
  }
446
440
  if (c == '\n')
447
441
  ts->lineno++;
@@ -819,6 +813,8 @@ GetXMLEntity(JSContext *cx, JSTokenStream *ts)
819
813
  /* Put the entity, including the '&' already scanned, in ts->tokenbuf. */
820
814
  offset = PTRDIFF(ts->tokenbuf.ptr, ts->tokenbuf.base, jschar);
821
815
  FastAppendChar(&ts->tokenbuf, '&');
816
+ if (!STRING_BUFFER_OK(&ts->tokenbuf))
817
+ return JS_FALSE;
822
818
  while ((c = GetChar(ts)) != ';') {
823
819
  if (c == EOF || c == '\n') {
824
820
  js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
@@ -826,6 +822,8 @@ GetXMLEntity(JSContext *cx, JSTokenStream *ts)
826
822
  return JS_FALSE;
827
823
  }
828
824
  FastAppendChar(&ts->tokenbuf, (jschar) c);
825
+ if (!STRING_BUFFER_OK(&ts->tokenbuf))
826
+ return JS_FALSE;
829
827
  }
830
828
 
831
829
  /* Let length be the number of jschars after the '&', including the ';'. */
@@ -911,6 +909,8 @@ badncr:
911
909
  msg = JSMSG_BAD_XML_NCR;
912
910
  bad:
913
911
  /* No match: throw a TypeError per ECMA-357 10.3.2.1 step 8(a). */
912
+ JS_ASSERT(STRING_BUFFER_OK(&ts->tokenbuf));
913
+ JS_ASSERT(PTRDIFF(ts->tokenbuf.ptr, bp, jschar) >= 1);
914
914
  bytes = js_DeflateString(cx, bp + 1,
915
915
  PTRDIFF(ts->tokenbuf.ptr, bp, jschar) - 1);
916
916
  if (bytes) {
@@ -990,6 +990,15 @@ NewToken(JSTokenStream *ts, ptrdiff_t adjust)
990
990
  return tp;
991
991
  }
992
992
 
993
+ static JS_INLINE JSBool
994
+ ScanAsSpace(jschar c)
995
+ {
996
+ /* Treat little- and big-endian BOMs as whitespace for compatibility. */
997
+ if (JS_ISSPACE(c) || c == 0xfffe || c == 0xfeff)
998
+ return JS_TRUE;
999
+ return JS_FALSE;
1000
+ }
1001
+
993
1002
  JSTokenType
994
1003
  js_GetToken(JSContext *cx, JSTokenStream *ts)
995
1004
  {
@@ -1200,7 +1209,7 @@ retry:
1200
1209
  if (ts->flags & TSF_NEWLINES)
1201
1210
  break;
1202
1211
  }
1203
- } while (JS_ISSPACE(c));
1212
+ } while (ScanAsSpace(c));
1204
1213
 
1205
1214
  tp = NewToken(ts, -1);
1206
1215
  if (c == EOF) {
@@ -1722,7 +1731,7 @@ retry:
1722
1731
  cp[3] == 'n' &&
1723
1732
  cp[4] == 'e') {
1724
1733
  SkipChars(ts, 5);
1725
- while ((c = GetChar(ts)) != '\n' && JS_ISSPACE(c))
1734
+ while ((c = GetChar(ts)) != '\n' && ScanAsSpace(c))
1726
1735
  continue;
1727
1736
  if (JS7_ISDEC(c)) {
1728
1737
  line = JS7_UNDEC(c);
@@ -1734,7 +1743,7 @@ retry:
1734
1743
  }
1735
1744
  line = temp;
1736
1745
  }
1737
- while (c != '\n' && JS_ISSPACE(c))
1746
+ while (c != '\n' && ScanAsSpace(c))
1738
1747
  c = GetChar(ts);
1739
1748
  i = 0;
1740
1749
  if (c == '"') {
@@ -1749,7 +1758,7 @@ retry:
1749
1758
  }
1750
1759
  if (c == '"') {
1751
1760
  while ((c = GetChar(ts)) != '\n' &&
1752
- JS_ISSPACE(c)) {
1761
+ ScanAsSpace(c)) {
1753
1762
  continue;
1754
1763
  }
1755
1764
  }
@@ -809,6 +809,7 @@ GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent,
809
809
  JSScopeProperty *sprop;
810
810
  PropTreeKidsChunk *chunk;
811
811
  uintN i, n;
812
+ uint32 shape;
812
813
 
813
814
  rt = cx->runtime;
814
815
  if (!parent) {
@@ -895,6 +896,12 @@ GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent,
895
896
  }
896
897
 
897
898
  locked_not_found:
899
+ /*
900
+ * Call js_GenerateShape before the allocation to prevent collecting the
901
+ * new property when the shape generation triggers the GC.
902
+ */
903
+ shape = js_GenerateShape(cx, JS_TRUE, NULL);
904
+
898
905
  sprop = NewScopeProperty(rt);
899
906
  if (!sprop)
900
907
  goto out_of_memory;
@@ -907,7 +914,7 @@ locked_not_found:
907
914
  sprop->flags = child->flags;
908
915
  sprop->shortid = child->shortid;
909
916
  sprop->parent = sprop->kids = NULL;
910
- sprop->shape = js_GenerateShape(cx, JS_TRUE);
917
+ sprop->shape = shape;
911
918
 
912
919
  if (!parent) {
913
920
  entry->child = sprop;
@@ -1256,9 +1263,11 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
1256
1263
  */
1257
1264
  if (!JS_CLIST_IS_EMPTY(&cx->runtime->watchPointList) &&
1258
1265
  js_FindWatchPoint(cx->runtime, scope, id)) {
1259
- JS_PUSH_TEMP_ROOT_SPROP(cx, overwriting, &tvr);
1266
+ if (overwriting)
1267
+ JS_PUSH_TEMP_ROOT_SPROP(cx, overwriting, &tvr);
1260
1268
  setter = js_WrapWatchedSetter(cx, id, attrs, setter);
1261
- JS_POP_TEMP_ROOT(cx, &tvr);
1269
+ if (overwriting)
1270
+ JS_POP_TEMP_ROOT(cx, &tvr);
1262
1271
  if (!setter)
1263
1272
  goto fail_overwrite;
1264
1273
  }
@@ -220,7 +220,7 @@ JS_STATIC_ASSERT(offsetof(JSScope, title) == sizeof(JSObjectMap));
220
220
  #define OBJ_SCOPE(obj) ((JSScope *)(obj)->map)
221
221
 
222
222
  #define SCOPE_MAKE_UNIQUE_SHAPE(cx,scope) \
223
- ((scope)->shape = js_GenerateShape((cx), JS_FALSE))
223
+ ((scope)->shape = js_GenerateShape((cx), JS_FALSE, NULL))
224
224
 
225
225
  #define SCOPE_EXTEND_SHAPE(cx,scope,sprop) \
226
226
  JS_BEGIN_MACRO \
@@ -228,7 +228,7 @@ JS_STATIC_ASSERT(offsetof(JSScope, title) == sizeof(JSObjectMap));
228
228
  (scope)->shape == (scope)->lastProp->shape) { \
229
229
  (scope)->shape = (sprop)->shape; \
230
230
  } else { \
231
- (scope)->shape = js_GenerateShape((cx), JS_FALSE); \
231
+ (scope)->shape = js_GenerateShape((cx), JS_FALSE, sprop); \
232
232
  } \
233
233
  JS_END_MACRO
234
234
 
@@ -1216,9 +1216,7 @@ match_or_replace(JSContext *cx,
1216
1216
 
1217
1217
  /* Assume a full array result is required, then prove otherwise. */
1218
1218
  test = JS_FALSE;
1219
- if (fp) {
1220
- JS_ASSERT(*fp->regs->pc == JSOP_CALL ||
1221
- *fp->regs->pc == JSOP_NEW);
1219
+ if (fp && (*fp->regs->pc == JSOP_CALL || *fp->regs->pc == JSOP_NEW)) {
1222
1220
  JS_ASSERT(js_CodeSpec[*fp->regs->pc].length == 3);
1223
1221
  switch (fp->regs->pc[3]) {
1224
1222
  case JSOP_POP:
@@ -1949,6 +1947,9 @@ str_concat(JSContext *cx, uintN argc, jsval *vp)
1949
1947
 
1950
1948
  NORMALIZE_THIS(cx, vp, str);
1951
1949
 
1950
+ /* Set vp (aka rval) early to handle the argc == 0 case. */
1951
+ *vp = STRING_TO_JSVAL(str);
1952
+
1952
1953
  for (i = 0, argv = vp + 2; i < argc; i++) {
1953
1954
  str2 = js_ValueToString(cx, argv[i]);
1954
1955
  if (!str2)
@@ -1958,9 +1959,9 @@ str_concat(JSContext *cx, uintN argc, jsval *vp)
1958
1959
  str = js_ConcatStrings(cx, str, str2);
1959
1960
  if (!str)
1960
1961
  return JS_FALSE;
1962
+ *vp = STRING_TO_JSVAL(str);
1961
1963
  }
1962
1964
 
1963
- *vp = STRING_TO_JSVAL(str);
1964
1965
  return JS_TRUE;
1965
1966
  }
1966
1967