jbarnette-johnson 1.0.0.20090326161333 → 1.0.0.20090402144841

Sign up to get free protection for your applications and to get access to all the features.
@@ -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