/js/src/jsexn.cpp

http://github.com/zpao/v8monkey · C++ · 1333 lines · 979 code · 175 blank · 179 comment · 225 complexity · 51f5fbaa1b271d189b526506c08d921e MD5 · raw file

  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=8 sw=4 et tw=78:
  3. *
  4. * ***** BEGIN LICENSE BLOCK *****
  5. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6. *
  7. * The contents of this file are subject to the Mozilla Public License Version
  8. * 1.1 (the "License"); you may not use this file except in compliance with
  9. * the License. You may obtain a copy of the License at
  10. * http://www.mozilla.org/MPL/
  11. *
  12. * Software distributed under the License is distributed on an "AS IS" basis,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. * for the specific language governing rights and limitations under the
  15. * License.
  16. *
  17. * The Original Code is Mozilla Communicator client code, released
  18. * March 31, 1998.
  19. *
  20. * The Initial Developer of the Original Code is
  21. * Netscape Communications Corporation.
  22. * Portions created by the Initial Developer are Copyright (C) 1998
  23. * the Initial Developer. All Rights Reserved.
  24. *
  25. * Contributor(s):
  26. *
  27. * Alternatively, the contents of this file may be used under the terms of
  28. * either of the GNU General Public License Version 2 or later (the "GPL"),
  29. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  30. * in which case the provisions of the GPL or the LGPL are applicable instead
  31. * of those above. If you wish to allow use of your version of this file only
  32. * under the terms of either the GPL or the LGPL, and not to allow others to
  33. * use your version of this file under the terms of the MPL, indicate your
  34. * decision by deleting the provisions above and replace them with the notice
  35. * and other provisions required by the GPL or the LGPL. If you do not delete
  36. * the provisions above, a recipient may use your version of this file under
  37. * the terms of any one of the MPL, the GPL or the LGPL.
  38. *
  39. * ***** END LICENSE BLOCK ***** */
  40. /*
  41. * JS standard exception implementation.
  42. */
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include "mozilla/Util.h"
  46. #include "jstypes.h"
  47. #include "jsutil.h"
  48. #include "jsprf.h"
  49. #include "jsapi.h"
  50. #include "jscntxt.h"
  51. #include "jsversion.h"
  52. #include "jsexn.h"
  53. #include "jsfun.h"
  54. #include "jsgc.h"
  55. #include "jsgcmark.h"
  56. #include "jsinterp.h"
  57. #include "jsnum.h"
  58. #include "jsobj.h"
  59. #include "jsopcode.h"
  60. #include "jsscope.h"
  61. #include "jsscript.h"
  62. #include "jswrapper.h"
  63. #include "vm/GlobalObject.h"
  64. #include "jsinferinlines.h"
  65. #include "jsobjinlines.h"
  66. #include "jsstrinlines.h"
  67. #include "vm/Stack-inl.h"
  68. #include "vm/String-inl.h"
  69. using namespace mozilla;
  70. using namespace js;
  71. using namespace js::gc;
  72. using namespace js::types;
  73. /* Forward declarations for ErrorClass's initializer. */
  74. static JSBool
  75. Exception(JSContext *cx, uintN argc, Value *vp);
  76. static void
  77. exn_trace(JSTracer *trc, JSObject *obj);
  78. static void
  79. exn_finalize(JSContext *cx, JSObject *obj);
  80. static JSBool
  81. exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
  82. JSObject **objp);
  83. Class js::ErrorClass = {
  84. js_Error_str,
  85. JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
  86. JSCLASS_HAS_CACHED_PROTO(JSProto_Error),
  87. JS_PropertyStub, /* addProperty */
  88. JS_PropertyStub, /* delProperty */
  89. JS_PropertyStub, /* getProperty */
  90. JS_StrictPropertyStub, /* setProperty */
  91. JS_EnumerateStub,
  92. (JSResolveOp)exn_resolve,
  93. JS_ConvertStub,
  94. exn_finalize,
  95. NULL, /* reserved0 */
  96. NULL, /* checkAccess */
  97. NULL, /* call */
  98. NULL, /* construct */
  99. NULL, /* xdrObject */
  100. NULL, /* hasInstance */
  101. exn_trace
  102. };
  103. typedef struct JSStackTraceElem {
  104. js::HeapPtrString funName;
  105. size_t argc;
  106. const char *filename;
  107. uintN ulineno;
  108. } JSStackTraceElem;
  109. typedef struct JSExnPrivate {
  110. /* A copy of the JSErrorReport originally generated. */
  111. JSErrorReport *errorReport;
  112. js::HeapPtrString message;
  113. js::HeapPtrString filename;
  114. uintN lineno;
  115. size_t stackDepth;
  116. intN exnType;
  117. JSStackTraceElem stackElems[1];
  118. } JSExnPrivate;
  119. static JSString *
  120. StackTraceToString(JSContext *cx, JSExnPrivate *priv);
  121. static JSErrorReport *
  122. CopyErrorReport(JSContext *cx, JSErrorReport *report)
  123. {
  124. /*
  125. * We use a single malloc block to make a deep copy of JSErrorReport with
  126. * the following layout:
  127. * JSErrorReport
  128. * array of copies of report->messageArgs
  129. * jschar array with characters for all messageArgs
  130. * jschar array with characters for ucmessage
  131. * jschar array with characters for uclinebuf and uctokenptr
  132. * char array with characters for linebuf and tokenptr
  133. * char array with characters for filename
  134. * Such layout together with the properties enforced by the following
  135. * asserts does not need any extra alignment padding.
  136. */
  137. JS_STATIC_ASSERT(sizeof(JSErrorReport) % sizeof(const char *) == 0);
  138. JS_STATIC_ASSERT(sizeof(const char *) % sizeof(jschar) == 0);
  139. size_t filenameSize;
  140. size_t linebufSize;
  141. size_t uclinebufSize;
  142. size_t ucmessageSize;
  143. size_t i, argsArraySize, argsCopySize, argSize;
  144. size_t mallocSize;
  145. JSErrorReport *copy;
  146. uint8_t *cursor;
  147. #define JS_CHARS_SIZE(jschars) ((js_strlen(jschars) + 1) * sizeof(jschar))
  148. filenameSize = report->filename ? strlen(report->filename) + 1 : 0;
  149. linebufSize = report->linebuf ? strlen(report->linebuf) + 1 : 0;
  150. uclinebufSize = report->uclinebuf ? JS_CHARS_SIZE(report->uclinebuf) : 0;
  151. ucmessageSize = 0;
  152. argsArraySize = 0;
  153. argsCopySize = 0;
  154. if (report->ucmessage) {
  155. ucmessageSize = JS_CHARS_SIZE(report->ucmessage);
  156. if (report->messageArgs) {
  157. for (i = 0; report->messageArgs[i]; ++i)
  158. argsCopySize += JS_CHARS_SIZE(report->messageArgs[i]);
  159. /* Non-null messageArgs should have at least one non-null arg. */
  160. JS_ASSERT(i != 0);
  161. argsArraySize = (i + 1) * sizeof(const jschar *);
  162. }
  163. }
  164. /*
  165. * The mallocSize can not overflow since it represents the sum of the
  166. * sizes of already allocated objects.
  167. */
  168. mallocSize = sizeof(JSErrorReport) + argsArraySize + argsCopySize +
  169. ucmessageSize + uclinebufSize + linebufSize + filenameSize;
  170. cursor = (uint8_t *)cx->malloc_(mallocSize);
  171. if (!cursor)
  172. return NULL;
  173. copy = (JSErrorReport *)cursor;
  174. memset(cursor, 0, sizeof(JSErrorReport));
  175. cursor += sizeof(JSErrorReport);
  176. if (argsArraySize != 0) {
  177. copy->messageArgs = (const jschar **)cursor;
  178. cursor += argsArraySize;
  179. for (i = 0; report->messageArgs[i]; ++i) {
  180. copy->messageArgs[i] = (const jschar *)cursor;
  181. argSize = JS_CHARS_SIZE(report->messageArgs[i]);
  182. js_memcpy(cursor, report->messageArgs[i], argSize);
  183. cursor += argSize;
  184. }
  185. copy->messageArgs[i] = NULL;
  186. JS_ASSERT(cursor == (uint8_t *)copy->messageArgs[0] + argsCopySize);
  187. }
  188. if (report->ucmessage) {
  189. copy->ucmessage = (const jschar *)cursor;
  190. js_memcpy(cursor, report->ucmessage, ucmessageSize);
  191. cursor += ucmessageSize;
  192. }
  193. if (report->uclinebuf) {
  194. copy->uclinebuf = (const jschar *)cursor;
  195. js_memcpy(cursor, report->uclinebuf, uclinebufSize);
  196. cursor += uclinebufSize;
  197. if (report->uctokenptr) {
  198. copy->uctokenptr = copy->uclinebuf + (report->uctokenptr -
  199. report->uclinebuf);
  200. }
  201. }
  202. if (report->linebuf) {
  203. copy->linebuf = (const char *)cursor;
  204. js_memcpy(cursor, report->linebuf, linebufSize);
  205. cursor += linebufSize;
  206. if (report->tokenptr) {
  207. copy->tokenptr = copy->linebuf + (report->tokenptr -
  208. report->linebuf);
  209. }
  210. }
  211. if (report->filename) {
  212. copy->filename = (const char *)cursor;
  213. js_memcpy(cursor, report->filename, filenameSize);
  214. }
  215. JS_ASSERT(cursor + filenameSize == (uint8_t *)copy + mallocSize);
  216. /* HOLD called by the destination error object. */
  217. copy->originPrincipals = report->originPrincipals;
  218. /* Copy non-pointer members. */
  219. copy->lineno = report->lineno;
  220. copy->errorNumber = report->errorNumber;
  221. /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */
  222. copy->flags = report->flags;
  223. #undef JS_CHARS_SIZE
  224. return copy;
  225. }
  226. static HeapValue *
  227. GetStackTraceValueBuffer(JSExnPrivate *priv)
  228. {
  229. /*
  230. * We use extra memory after JSExnPrivateInfo.stackElems to store jsvals
  231. * that helps to produce more informative stack traces. The following
  232. * assert allows us to assume that no gap after stackElems is necessary to
  233. * align the buffer properly.
  234. */
  235. JS_STATIC_ASSERT(sizeof(JSStackTraceElem) % sizeof(jsval) == 0);
  236. return reinterpret_cast<HeapValue *>(priv->stackElems + priv->stackDepth);
  237. }
  238. struct SuppressErrorsGuard
  239. {
  240. JSContext *cx;
  241. JSErrorReporter prevReporter;
  242. JSExceptionState *prevState;
  243. SuppressErrorsGuard(JSContext *cx)
  244. : cx(cx),
  245. prevReporter(JS_SetErrorReporter(cx, NULL)),
  246. prevState(JS_SaveExceptionState(cx))
  247. {}
  248. ~SuppressErrorsGuard()
  249. {
  250. JS_RestoreExceptionState(cx, prevState);
  251. JS_SetErrorReporter(cx, prevReporter);
  252. }
  253. };
  254. struct AppendArg {
  255. Vector<Value> &values;
  256. AppendArg(Vector<Value> &values) : values(values) {}
  257. bool operator()(uintN, Value *vp) {
  258. return values.append(*vp);
  259. }
  260. };
  261. static void
  262. SetExnPrivate(JSContext *cx, JSObject *exnObject, JSExnPrivate *priv);
  263. static bool
  264. InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
  265. JSString *filename, uintN lineno, JSErrorReport *report, intN exnType)
  266. {
  267. JS_ASSERT(exnObject->isError());
  268. JS_ASSERT(!exnObject->getPrivate());
  269. JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx);
  270. JSCheckAccessOp checkAccess = callbacks ? callbacks->checkObjectAccess : NULL;
  271. Vector<JSStackTraceElem> frames(cx);
  272. Vector<Value> values(cx);
  273. {
  274. SuppressErrorsGuard seg(cx);
  275. for (FrameRegsIter i(cx); !i.done(); ++i) {
  276. /*
  277. * An exception object stores stack values from 'fp' which may be
  278. * in a different compartment from 'exnObject'. Engine compartment
  279. * invariants require such values to be wrapped. A simpler solution
  280. * is to just cut off the backtrace at compartment boundaries.
  281. * Also, avoid exposing values from different security principals.
  282. */
  283. StackFrame *fp = i.fp();
  284. if (fp->compartment() != cx->compartment)
  285. break;
  286. if (checkAccess && fp->isNonEvalFunctionFrame()) {
  287. Value v = NullValue();
  288. jsid callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom);
  289. if (!checkAccess(cx, &fp->callee(), callerid, JSACC_READ, &v))
  290. break;
  291. }
  292. if (!frames.growBy(1))
  293. return false;
  294. JSStackTraceElem &frame = frames.back();
  295. if (fp->isNonEvalFunctionFrame()) {
  296. frame.funName.init(fp->fun()->atom ? fp->fun()->atom : cx->runtime->emptyString);
  297. frame.argc = fp->numActualArgs();
  298. if (!fp->forEachCanonicalActualArg(AppendArg(values)))
  299. return false;
  300. } else {
  301. frame.funName.init(NULL);
  302. frame.argc = 0;
  303. }
  304. if (fp->isScriptFrame()) {
  305. frame.filename = fp->script()->filename;
  306. frame.ulineno = js_PCToLineNumber(cx, fp->script(), i.pc());
  307. } else {
  308. frame.ulineno = 0;
  309. frame.filename = NULL;
  310. }
  311. }
  312. }
  313. /* Do not need overflow check: the vm stack is already bigger. */
  314. JS_STATIC_ASSERT(sizeof(JSStackTraceElem) <= sizeof(StackFrame));
  315. size_t nbytes = offsetof(JSExnPrivate, stackElems) +
  316. frames.length() * sizeof(JSStackTraceElem) +
  317. values.length() * sizeof(HeapValue);
  318. JSExnPrivate *priv = (JSExnPrivate *)cx->malloc_(nbytes);
  319. if (!priv)
  320. return false;
  321. /* Initialize to zero so that write barriers don't witness undefined values. */
  322. memset(priv, 0, nbytes);
  323. if (report) {
  324. /*
  325. * Construct a new copy of the error report struct. We can't use the
  326. * error report struct that was passed in, because it's allocated on
  327. * the stack, and also because it may point to transient data in the
  328. * TokenStream.
  329. */
  330. priv->errorReport = CopyErrorReport(cx, report);
  331. if (!priv->errorReport) {
  332. cx->free_(priv);
  333. return false;
  334. }
  335. } else {
  336. priv->errorReport = NULL;
  337. }
  338. priv->message.init(message);
  339. priv->filename.init(filename);
  340. priv->lineno = lineno;
  341. priv->stackDepth = frames.length();
  342. priv->exnType = exnType;
  343. JSStackTraceElem *framesDest = priv->stackElems;
  344. HeapValue *valuesDest = reinterpret_cast<HeapValue *>(framesDest + frames.length());
  345. JS_ASSERT(valuesDest == GetStackTraceValueBuffer(priv));
  346. PodCopy(framesDest, frames.begin(), frames.length());
  347. for (size_t i = 0; i < values.length(); ++i)
  348. valuesDest[i].init(cx->compartment, values[i]);
  349. SetExnPrivate(cx, exnObject, priv);
  350. return true;
  351. }
  352. static inline JSExnPrivate *
  353. GetExnPrivate(JSObject *obj)
  354. {
  355. JS_ASSERT(obj->isError());
  356. return (JSExnPrivate *) obj->getPrivate();
  357. }
  358. static void
  359. exn_trace(JSTracer *trc, JSObject *obj)
  360. {
  361. JSExnPrivate *priv;
  362. JSStackTraceElem *elem;
  363. size_t vcount, i;
  364. HeapValue *vp;
  365. priv = GetExnPrivate(obj);
  366. if (priv) {
  367. if (priv->message)
  368. MarkString(trc, priv->message, "exception message");
  369. if (priv->filename)
  370. MarkString(trc, priv->filename, "exception filename");
  371. elem = priv->stackElems;
  372. for (vcount = i = 0; i != priv->stackDepth; ++i, ++elem) {
  373. if (elem->funName)
  374. MarkString(trc, elem->funName, "stack trace function name");
  375. if (IS_GC_MARKING_TRACER(trc) && elem->filename)
  376. js_MarkScriptFilename(elem->filename);
  377. vcount += elem->argc;
  378. }
  379. vp = GetStackTraceValueBuffer(priv);
  380. for (i = 0; i != vcount; ++i, ++vp) {
  381. MarkValue(trc, *vp, "stack trace argument");
  382. }
  383. }
  384. }
  385. /* NB: An error object's private must be set through this function. */
  386. static void
  387. SetExnPrivate(JSContext *cx, JSObject *exnObject, JSExnPrivate *priv)
  388. {
  389. JS_ASSERT(!exnObject->getPrivate());
  390. JS_ASSERT(exnObject->isError());
  391. if (JSErrorReport *report = priv->errorReport) {
  392. if (JSPrincipals *prin = report->originPrincipals)
  393. JSPRINCIPALS_HOLD(cx, prin);
  394. }
  395. exnObject->setPrivate(priv);
  396. }
  397. static void
  398. exn_finalize(JSContext *cx, JSObject *obj)
  399. {
  400. if (JSExnPrivate *priv = GetExnPrivate(obj)) {
  401. if (JSErrorReport *report = priv->errorReport) {
  402. /* HOLD called by SetExnPrivate. */
  403. if (JSPrincipals *prin = report->originPrincipals)
  404. JSPRINCIPALS_DROP(cx, prin);
  405. cx->free_(report);
  406. }
  407. cx->free_(priv);
  408. }
  409. }
  410. static JSBool
  411. exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
  412. JSObject **objp)
  413. {
  414. JSExnPrivate *priv;
  415. JSString *str;
  416. JSAtom *atom;
  417. JSString *stack;
  418. const char *prop;
  419. jsval v;
  420. uintN attrs;
  421. *objp = NULL;
  422. priv = GetExnPrivate(obj);
  423. if (priv && JSID_IS_ATOM(id)) {
  424. str = JSID_TO_STRING(id);
  425. atom = cx->runtime->atomState.messageAtom;
  426. if (str == atom) {
  427. prop = js_message_str;
  428. /*
  429. * Per ES5 15.11.1.1, if Error is called with no argument or with
  430. * undefined as the argument, it returns an Error object with no
  431. * own message property.
  432. */
  433. if (!priv->message)
  434. return true;
  435. v = STRING_TO_JSVAL(priv->message);
  436. attrs = 0;
  437. goto define;
  438. }
  439. atom = cx->runtime->atomState.fileNameAtom;
  440. if (str == atom) {
  441. prop = js_fileName_str;
  442. v = STRING_TO_JSVAL(priv->filename);
  443. attrs = JSPROP_ENUMERATE;
  444. goto define;
  445. }
  446. atom = cx->runtime->atomState.lineNumberAtom;
  447. if (str == atom) {
  448. prop = js_lineNumber_str;
  449. v = INT_TO_JSVAL(priv->lineno);
  450. attrs = JSPROP_ENUMERATE;
  451. goto define;
  452. }
  453. atom = cx->runtime->atomState.stackAtom;
  454. if (str == atom) {
  455. stack = StackTraceToString(cx, priv);
  456. if (!stack)
  457. return false;
  458. prop = js_stack_str;
  459. v = STRING_TO_JSVAL(stack);
  460. attrs = JSPROP_ENUMERATE;
  461. goto define;
  462. }
  463. }
  464. return true;
  465. define:
  466. if (!JS_DefineProperty(cx, obj, prop, v, NULL, NULL, attrs))
  467. return false;
  468. *objp = obj;
  469. return true;
  470. }
  471. JSErrorReport *
  472. js_ErrorFromException(JSContext *cx, jsval exn)
  473. {
  474. JSObject *obj;
  475. JSExnPrivate *priv;
  476. if (JSVAL_IS_PRIMITIVE(exn))
  477. return NULL;
  478. obj = JSVAL_TO_OBJECT(exn);
  479. if (!obj->isError())
  480. return NULL;
  481. priv = GetExnPrivate(obj);
  482. if (!priv)
  483. return NULL;
  484. return priv->errorReport;
  485. }
  486. static JSString *
  487. ValueToShortSource(JSContext *cx, const Value &v)
  488. {
  489. JSString *str;
  490. /* Avoid toSource bloat and fallibility for object types. */
  491. if (!v.isObject())
  492. return js_ValueToSource(cx, v);
  493. JSObject *obj = &v.toObject();
  494. AutoCompartment ac(cx, obj);
  495. if (!ac.enter())
  496. return NULL;
  497. if (obj->isFunction()) {
  498. /*
  499. * XXX Avoid function decompilation bloat for now.
  500. */
  501. str = JS_GetFunctionId(obj->toFunction());
  502. if (!str && !(str = js_ValueToSource(cx, v))) {
  503. /*
  504. * Continue to soldier on if the function couldn't be
  505. * converted into a string.
  506. */
  507. JS_ClearPendingException(cx);
  508. str = JS_NewStringCopyZ(cx, "[unknown function]");
  509. }
  510. } else {
  511. /*
  512. * XXX Avoid toString on objects, it takes too long and uses too much
  513. * memory, for too many classes (see Mozilla bug 166743).
  514. */
  515. char buf[100];
  516. JS_snprintf(buf, sizeof buf, "[object %s]", obj->getClass()->name);
  517. str = JS_NewStringCopyZ(cx, buf);
  518. }
  519. ac.leave();
  520. if (!str || !cx->compartment->wrap(cx, &str))
  521. return NULL;
  522. return str;
  523. }
  524. static JSString *
  525. StackTraceToString(JSContext *cx, JSExnPrivate *priv)
  526. {
  527. jschar *stackbuf;
  528. size_t stacklen, stackmax;
  529. JSStackTraceElem *elem, *endElem;
  530. HeapValue *values;
  531. size_t i;
  532. JSString *str;
  533. const char *cp;
  534. char ulnbuf[11];
  535. /* After this point, failing control flow must goto bad. */
  536. stackbuf = NULL;
  537. stacklen = stackmax = 0;
  538. /* Limit the stackbuf length to a reasonable value to avoid overflow checks. */
  539. #define STACK_LENGTH_LIMIT JS_BIT(20)
  540. #define APPEND_CHAR_TO_STACK(c) \
  541. JS_BEGIN_MACRO \
  542. if (stacklen == stackmax) { \
  543. void *ptr_; \
  544. if (stackmax >= STACK_LENGTH_LIMIT) \
  545. goto done; \
  546. stackmax = stackmax ? 2 * stackmax : 64; \
  547. ptr_ = cx->realloc_(stackbuf, (stackmax+1) * sizeof(jschar)); \
  548. if (!ptr_) \
  549. goto bad; \
  550. stackbuf = (jschar *) ptr_; \
  551. } \
  552. stackbuf[stacklen++] = (c); \
  553. JS_END_MACRO
  554. #define APPEND_STRING_TO_STACK(str) \
  555. JS_BEGIN_MACRO \
  556. JSString *str_ = str; \
  557. size_t length_ = str_->length(); \
  558. const jschar *chars_ = str_->getChars(cx); \
  559. if (!chars_) \
  560. goto bad; \
  561. \
  562. if (length_ > stackmax - stacklen) { \
  563. void *ptr_; \
  564. if (stackmax >= STACK_LENGTH_LIMIT || \
  565. length_ >= STACK_LENGTH_LIMIT - stacklen) { \
  566. goto done; \
  567. } \
  568. stackmax = RoundUpPow2(stacklen + length_); \
  569. ptr_ = cx->realloc_(stackbuf, (stackmax+1) * sizeof(jschar)); \
  570. if (!ptr_) \
  571. goto bad; \
  572. stackbuf = (jschar *) ptr_; \
  573. } \
  574. js_strncpy(stackbuf + stacklen, chars_, length_); \
  575. stacklen += length_; \
  576. JS_END_MACRO
  577. values = GetStackTraceValueBuffer(priv);
  578. elem = priv->stackElems;
  579. for (endElem = elem + priv->stackDepth; elem != endElem; elem++) {
  580. if (elem->funName) {
  581. APPEND_STRING_TO_STACK(elem->funName);
  582. APPEND_CHAR_TO_STACK('(');
  583. for (i = 0; i != elem->argc; i++, values++) {
  584. if (i > 0)
  585. APPEND_CHAR_TO_STACK(',');
  586. str = ValueToShortSource(cx, *values);
  587. if (!str)
  588. goto bad;
  589. APPEND_STRING_TO_STACK(str);
  590. }
  591. APPEND_CHAR_TO_STACK(')');
  592. }
  593. APPEND_CHAR_TO_STACK('@');
  594. if (elem->filename) {
  595. for (cp = elem->filename; *cp; cp++)
  596. APPEND_CHAR_TO_STACK(*cp);
  597. }
  598. APPEND_CHAR_TO_STACK(':');
  599. JS_snprintf(ulnbuf, sizeof ulnbuf, "%u", elem->ulineno);
  600. for (cp = ulnbuf; *cp; cp++)
  601. APPEND_CHAR_TO_STACK(*cp);
  602. APPEND_CHAR_TO_STACK('\n');
  603. }
  604. #undef APPEND_CHAR_TO_STACK
  605. #undef APPEND_STRING_TO_STACK
  606. #undef STACK_LENGTH_LIMIT
  607. done:
  608. if (stacklen == 0) {
  609. JS_ASSERT(!stackbuf);
  610. return cx->runtime->emptyString;
  611. }
  612. if (stacklen < stackmax) {
  613. /*
  614. * Realloc can fail when shrinking on some FreeBSD versions, so
  615. * don't use JS_realloc here; simply let the oversized allocation
  616. * be owned by the string in that rare case.
  617. */
  618. void *shrunk = cx->realloc_(stackbuf, (stacklen+1) * sizeof(jschar));
  619. if (shrunk)
  620. stackbuf = (jschar *) shrunk;
  621. }
  622. stackbuf[stacklen] = 0;
  623. str = js_NewString(cx, stackbuf, stacklen);
  624. if (str)
  625. return str;
  626. bad:
  627. if (stackbuf)
  628. cx->free_(stackbuf);
  629. return NULL;
  630. }
  631. /* XXXbe Consolidate the ugly truth that we don't treat filename as UTF-8
  632. with these two functions. */
  633. static JSString *
  634. FilenameToString(JSContext *cx, const char *filename)
  635. {
  636. return JS_NewStringCopyZ(cx, filename);
  637. }
  638. static JSBool
  639. Exception(JSContext *cx, uintN argc, Value *vp)
  640. {
  641. CallArgs args = CallArgsFromVp(argc, vp);
  642. /*
  643. * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
  644. * called as functions, without operator new. But as we do not give
  645. * each constructor a distinct JSClass, whose .name member is used by
  646. * NewNativeClassInstance to find the class prototype, we must get the
  647. * class prototype ourselves.
  648. */
  649. Value protov;
  650. if (!args.callee().getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &protov))
  651. return false;
  652. if (!protov.isObject()) {
  653. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, "Error");
  654. return false;
  655. }
  656. JSObject *errProto = &protov.toObject();
  657. JSObject *obj = NewObjectWithGivenProto(cx, &ErrorClass, errProto, NULL);
  658. if (!obj)
  659. return false;
  660. /* Set the 'message' property. */
  661. JSString *message;
  662. if (args.length() != 0 && !args[0].isUndefined()) {
  663. message = ToString(cx, args[0]);
  664. if (!message)
  665. return false;
  666. args[0].setString(message);
  667. } else {
  668. message = NULL;
  669. }
  670. /* Find the scripted caller. */
  671. FrameRegsIter iter(cx);
  672. while (!iter.done() && !iter.fp()->isScriptFrame())
  673. ++iter;
  674. /* Set the 'fileName' property. */
  675. JSString *filename;
  676. if (args.length() > 1) {
  677. filename = ToString(cx, args[1]);
  678. if (!filename)
  679. return false;
  680. args[1].setString(filename);
  681. } else {
  682. if (!iter.done()) {
  683. filename = FilenameToString(cx, iter.fp()->script()->filename);
  684. if (!filename)
  685. return false;
  686. } else {
  687. filename = cx->runtime->emptyString;
  688. }
  689. }
  690. /* Set the 'lineNumber' property. */
  691. uint32_t lineno;
  692. if (args.length() > 2) {
  693. if (!ToUint32(cx, args[2], &lineno))
  694. return false;
  695. } else {
  696. lineno = iter.done() ? 0 : js_PCToLineNumber(cx, iter.fp()->script(), iter.pc());
  697. }
  698. intN exnType = args.callee().toFunction()->getExtendedSlot(0).toInt32();
  699. if (!InitExnPrivate(cx, obj, message, filename, lineno, NULL, exnType))
  700. return false;
  701. args.rval().setObject(*obj);
  702. return true;
  703. }
  704. /* ES5 15.11.4.4 (NB: with subsequent errata). */
  705. static JSBool
  706. exn_toString(JSContext *cx, uintN argc, Value *vp)
  707. {
  708. JS_CHECK_RECURSION(cx, return false);
  709. CallArgs args = CallArgsFromVp(argc, vp);
  710. /* Step 2. */
  711. if (!args.thisv().isObject()) {
  712. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, "Error");
  713. return false;
  714. }
  715. /* Step 1. */
  716. JSObject &obj = args.thisv().toObject();
  717. /* Step 3. */
  718. Value nameVal;
  719. if (!obj.getProperty(cx, cx->runtime->atomState.nameAtom, &nameVal))
  720. return false;
  721. /* Step 4. */
  722. JSString *name;
  723. if (nameVal.isUndefined()) {
  724. name = CLASS_ATOM(cx, Error);
  725. } else {
  726. name = ToString(cx, nameVal);
  727. if (!name)
  728. return false;
  729. }
  730. /* Step 5. */
  731. Value msgVal;
  732. if (!obj.getProperty(cx, cx->runtime->atomState.messageAtom, &msgVal))
  733. return false;
  734. /* Step 6. */
  735. JSString *message;
  736. if (msgVal.isUndefined()) {
  737. message = cx->runtime->emptyString;
  738. } else {
  739. message = ToString(cx, msgVal);
  740. if (!message)
  741. return false;
  742. }
  743. /* Step 7. */
  744. if (name->empty() && message->empty()) {
  745. args.rval().setString(CLASS_ATOM(cx, Error));
  746. return true;
  747. }
  748. /* Step 8. */
  749. if (name->empty()) {
  750. args.rval().setString(message);
  751. return true;
  752. }
  753. /* Step 9. */
  754. if (message->empty()) {
  755. args.rval().setString(name);
  756. return true;
  757. }
  758. /* Step 10. */
  759. StringBuffer sb(cx);
  760. if (!sb.append(name) || !sb.append(": ") || !sb.append(message))
  761. return false;
  762. JSString *str = sb.finishString();
  763. if (!str)
  764. return false;
  765. args.rval().setString(str);
  766. return true;
  767. }
  768. #if JS_HAS_TOSOURCE
  769. /*
  770. * Return a string that may eval to something similar to the original object.
  771. */
  772. static JSBool
  773. exn_toSource(JSContext *cx, uintN argc, Value *vp)
  774. {
  775. JS_CHECK_RECURSION(cx, return false);
  776. CallArgs args = CallArgsFromVp(argc, vp);
  777. JSObject *obj = ToObject(cx, &args.thisv());
  778. if (!obj)
  779. return false;
  780. Value nameVal;
  781. JSString *name;
  782. if (!obj->getProperty(cx, cx->runtime->atomState.nameAtom, &nameVal) ||
  783. !(name = ToString(cx, nameVal)))
  784. {
  785. return false;
  786. }
  787. Value messageVal;
  788. JSString *message;
  789. if (!obj->getProperty(cx, cx->runtime->atomState.messageAtom, &messageVal) ||
  790. !(message = js_ValueToSource(cx, messageVal)))
  791. {
  792. return false;
  793. }
  794. Value filenameVal;
  795. JSString *filename;
  796. if (!obj->getProperty(cx, cx->runtime->atomState.fileNameAtom, &filenameVal) ||
  797. !(filename = js_ValueToSource(cx, filenameVal)))
  798. {
  799. return false;
  800. }
  801. Value linenoVal;
  802. uint32_t lineno;
  803. if (!obj->getProperty(cx, cx->runtime->atomState.lineNumberAtom, &linenoVal) ||
  804. !ToUint32(cx, linenoVal, &lineno))
  805. {
  806. return false;
  807. }
  808. StringBuffer sb(cx);
  809. if (!sb.append("(new ") || !sb.append(name) || !sb.append("("))
  810. return false;
  811. if (!sb.append(message))
  812. return false;
  813. if (!filename->empty()) {
  814. if (!sb.append(", ") || !sb.append(filename))
  815. return false;
  816. }
  817. if (lineno != 0) {
  818. /* We have a line, but no filename, add empty string */
  819. if (filename->empty() && !sb.append(", \"\""))
  820. return false;
  821. JSString *linenumber = ToString(cx, linenoVal);
  822. if (!linenumber)
  823. return false;
  824. if (!sb.append(", ") || !sb.append(linenumber))
  825. return false;
  826. }
  827. if (!sb.append("))"))
  828. return false;
  829. JSString *str = sb.finishString();
  830. if (!str)
  831. return false;
  832. args.rval().setString(str);
  833. return true;
  834. }
  835. #endif
  836. static JSFunctionSpec exception_methods[] = {
  837. #if JS_HAS_TOSOURCE
  838. JS_FN(js_toSource_str, exn_toSource, 0,0),
  839. #endif
  840. JS_FN(js_toString_str, exn_toString, 0,0),
  841. JS_FS_END
  842. };
  843. /* JSProto_ ordering for exceptions shall match JSEXN_ constants. */
  844. JS_STATIC_ASSERT(JSEXN_ERR == 0);
  845. JS_STATIC_ASSERT(JSProto_Error + JSEXN_INTERNALERR == JSProto_InternalError);
  846. JS_STATIC_ASSERT(JSProto_Error + JSEXN_EVALERR == JSProto_EvalError);
  847. JS_STATIC_ASSERT(JSProto_Error + JSEXN_RANGEERR == JSProto_RangeError);
  848. JS_STATIC_ASSERT(JSProto_Error + JSEXN_REFERENCEERR == JSProto_ReferenceError);
  849. JS_STATIC_ASSERT(JSProto_Error + JSEXN_SYNTAXERR == JSProto_SyntaxError);
  850. JS_STATIC_ASSERT(JSProto_Error + JSEXN_TYPEERR == JSProto_TypeError);
  851. JS_STATIC_ASSERT(JSProto_Error + JSEXN_URIERR == JSProto_URIError);
  852. static JSObject *
  853. InitErrorClass(JSContext *cx, GlobalObject *global, intN type, JSObject &proto)
  854. {
  855. JSProtoKey key = GetExceptionProtoKey(type);
  856. JSAtom *name = cx->runtime->atomState.classAtoms[key];
  857. JSObject *errorProto = global->createBlankPrototypeInheriting(cx, &ErrorClass, proto);
  858. if (!errorProto)
  859. return NULL;
  860. Value empty = StringValue(cx->runtime->emptyString);
  861. jsid nameId = ATOM_TO_JSID(cx->runtime->atomState.nameAtom);
  862. jsid messageId = ATOM_TO_JSID(cx->runtime->atomState.messageAtom);
  863. jsid fileNameId = ATOM_TO_JSID(cx->runtime->atomState.fileNameAtom);
  864. jsid lineNumberId = ATOM_TO_JSID(cx->runtime->atomState.lineNumberAtom);
  865. if (!DefineNativeProperty(cx, errorProto, nameId, StringValue(name),
  866. JS_PropertyStub, JS_StrictPropertyStub, 0, 0, 0) ||
  867. !DefineNativeProperty(cx, errorProto, messageId, empty,
  868. JS_PropertyStub, JS_StrictPropertyStub, 0, 0, 0) ||
  869. !DefineNativeProperty(cx, errorProto, fileNameId, empty,
  870. JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0) ||
  871. !DefineNativeProperty(cx, errorProto, lineNumberId, Int32Value(0),
  872. JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0))
  873. {
  874. return NULL;
  875. }
  876. /* Create the corresponding constructor. */
  877. JSFunction *ctor = global->createConstructor(cx, Exception, &ErrorClass, name, 1,
  878. JSFunction::ExtendedFinalizeKind);
  879. if (!ctor)
  880. return NULL;
  881. ctor->setExtendedSlot(0, Int32Value(int32_t(type)));
  882. if (!LinkConstructorAndPrototype(cx, ctor, errorProto))
  883. return NULL;
  884. if (!DefineConstructorAndPrototype(cx, global, key, ctor, errorProto))
  885. return NULL;
  886. JS_ASSERT(!errorProto->getPrivate());
  887. return errorProto;
  888. }
  889. JSObject *
  890. js_InitExceptionClasses(JSContext *cx, JSObject *obj)
  891. {
  892. JS_ASSERT(obj->isGlobal());
  893. JS_ASSERT(obj->isNative());
  894. GlobalObject *global = &obj->asGlobal();
  895. JSObject *objectProto = global->getOrCreateObjectPrototype(cx);
  896. if (!objectProto)
  897. return NULL;
  898. /* Initialize the base Error class first. */
  899. JSObject *errorProto = InitErrorClass(cx, global, JSEXN_ERR, *objectProto);
  900. if (!errorProto)
  901. return NULL;
  902. /* |Error.prototype| alone has method properties. */
  903. if (!DefinePropertiesAndBrand(cx, errorProto, NULL, exception_methods))
  904. return NULL;
  905. /* Define all remaining *Error constructors. */
  906. for (intN i = JSEXN_ERR + 1; i < JSEXN_LIMIT; i++) {
  907. if (!InitErrorClass(cx, global, i, *errorProto))
  908. return NULL;
  909. }
  910. return errorProto;
  911. }
  912. const JSErrorFormatString*
  913. js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale,
  914. const uintN errorNumber)
  915. {
  916. const JSErrorFormatString *errorString = NULL;
  917. if (cx->localeCallbacks && cx->localeCallbacks->localeGetErrorMessage) {
  918. errorString = cx->localeCallbacks
  919. ->localeGetErrorMessage(userRef, locale, errorNumber);
  920. }
  921. if (!errorString)
  922. errorString = js_GetErrorMessage(userRef, locale, errorNumber);
  923. return errorString;
  924. }
  925. #if defined ( DEBUG_mccabe ) && defined ( PRINTNAMES )
  926. /* For use below... get character strings for error name and exception name */
  927. static struct exnname { char *name; char *exception; } errortoexnname[] = {
  928. #define MSG_DEF(name, number, count, exception, format) \
  929. {#name, #exception},
  930. #include "js.msg"
  931. #undef MSG_DEF
  932. };
  933. #endif /* DEBUG */
  934. JSBool
  935. js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp,
  936. JSErrorCallback callback, void *userRef)
  937. {
  938. JSErrNum errorNumber;
  939. const JSErrorFormatString *errorString;
  940. JSExnType exn;
  941. jsval tv[4];
  942. JSBool ok;
  943. JSObject *errProto, *errObject;
  944. JSString *messageStr, *filenameStr;
  945. /*
  946. * Tell our caller to report immediately if this report is just a warning.
  947. */
  948. JS_ASSERT(reportp);
  949. if (JSREPORT_IS_WARNING(reportp->flags))
  950. return JS_FALSE;
  951. /* Find the exception index associated with this error. */
  952. errorNumber = (JSErrNum) reportp->errorNumber;
  953. if (!callback || callback == js_GetErrorMessage)
  954. errorString = js_GetLocalizedErrorMessage(cx, NULL, NULL, errorNumber);
  955. else
  956. errorString = callback(userRef, NULL, errorNumber);
  957. exn = errorString ? (JSExnType) errorString->exnType : JSEXN_NONE;
  958. JS_ASSERT(exn < JSEXN_LIMIT);
  959. #if defined( DEBUG_mccabe ) && defined ( PRINTNAMES )
  960. /* Print the error name and the associated exception name to stderr */
  961. fprintf(stderr, "%s\t%s\n",
  962. errortoexnname[errorNumber].name,
  963. errortoexnname[errorNumber].exception);
  964. #endif
  965. /*
  966. * Return false (no exception raised) if no exception is associated
  967. * with the given error number.
  968. */
  969. if (exn == JSEXN_NONE)
  970. return JS_FALSE;
  971. /*
  972. * Prevent runaway recursion, via cx->generatingError. If an out-of-memory
  973. * error occurs, no exception object will be created, but we don't assume
  974. * that OOM is the only kind of error that subroutines of this function
  975. * called below might raise.
  976. */
  977. if (cx->generatingError)
  978. return JS_FALSE;
  979. MUST_FLOW_THROUGH("out");
  980. cx->generatingError = JS_TRUE;
  981. /* Protect the newly-created strings below from nesting GCs. */
  982. PodArrayZero(tv);
  983. AutoArrayRooter tvr(cx, ArrayLength(tv), tv);
  984. /*
  985. * Try to get an appropriate prototype by looking up the corresponding
  986. * exception constructor name in the scope chain of the current context's
  987. * top stack frame, or in the global object if no frame is active.
  988. */
  989. ok = js_GetClassPrototype(cx, NULL, GetExceptionProtoKey(exn), &errProto);
  990. if (!ok)
  991. goto out;
  992. tv[0] = OBJECT_TO_JSVAL(errProto);
  993. errObject = NewObjectWithGivenProto(cx, &ErrorClass, errProto, NULL);
  994. if (!errObject) {
  995. ok = JS_FALSE;
  996. goto out;
  997. }
  998. tv[1] = OBJECT_TO_JSVAL(errObject);
  999. messageStr = JS_NewStringCopyZ(cx, message);
  1000. if (!messageStr) {
  1001. ok = JS_FALSE;
  1002. goto out;
  1003. }
  1004. tv[2] = STRING_TO_JSVAL(messageStr);
  1005. filenameStr = JS_NewStringCopyZ(cx, reportp->filename);
  1006. if (!filenameStr) {
  1007. ok = JS_FALSE;
  1008. goto out;
  1009. }
  1010. tv[3] = STRING_TO_JSVAL(filenameStr);
  1011. ok = InitExnPrivate(cx, errObject, messageStr, filenameStr,
  1012. reportp->lineno, reportp, exn);
  1013. if (!ok)
  1014. goto out;
  1015. JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject));
  1016. /* Flag the error report passed in to indicate an exception was raised. */
  1017. reportp->flags |= JSREPORT_EXCEPTION;
  1018. out:
  1019. cx->generatingError = JS_FALSE;
  1020. return ok;
  1021. }
  1022. JSBool
  1023. js_ReportUncaughtException(JSContext *cx)
  1024. {
  1025. jsval exn;
  1026. JSObject *exnObject;
  1027. jsval roots[5];
  1028. JSErrorReport *reportp, report;
  1029. JSString *str;
  1030. const char *bytes;
  1031. if (!JS_IsExceptionPending(cx))
  1032. return true;
  1033. if (!JS_GetPendingException(cx, &exn))
  1034. return false;
  1035. PodArrayZero(roots);
  1036. AutoArrayRooter tvr(cx, ArrayLength(roots), roots);
  1037. /*
  1038. * Because ToString below could error and an exception object could become
  1039. * unrooted, we must root exnObject. Later, if exnObject is non-null, we
  1040. * need to root other intermediates, so allocate an operand stack segment
  1041. * to protect all of these values.
  1042. */
  1043. if (JSVAL_IS_PRIMITIVE(exn)) {
  1044. exnObject = NULL;
  1045. } else {
  1046. exnObject = JSVAL_TO_OBJECT(exn);
  1047. roots[0] = exn;
  1048. }
  1049. JS_ClearPendingException(cx);
  1050. reportp = js_ErrorFromException(cx, exn);
  1051. /* XXX L10N angels cry once again. see also everywhere else */
  1052. str = ToString(cx, exn);
  1053. JSAutoByteString bytesStorage;
  1054. if (!str) {
  1055. bytes = "unknown (can't convert to string)";
  1056. } else {
  1057. roots[1] = StringValue(str);
  1058. if (!bytesStorage.encode(cx, str))
  1059. return false;
  1060. bytes = bytesStorage.ptr();
  1061. }
  1062. JSAutoByteString filename;
  1063. if (!reportp && exnObject && exnObject->isError()) {
  1064. if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2]))
  1065. return false;
  1066. if (JSVAL_IS_STRING(roots[2])) {
  1067. bytesStorage.clear();
  1068. if (!bytesStorage.encode(cx, str))
  1069. return false;
  1070. bytes = bytesStorage.ptr();
  1071. }
  1072. if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]))
  1073. return false;
  1074. str = ToString(cx, roots[3]);
  1075. if (!str || !filename.encode(cx, str))
  1076. return false;
  1077. if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]))
  1078. return false;
  1079. uint32_t lineno;
  1080. if (!ToUint32(cx, roots[4], &lineno))
  1081. return false;
  1082. reportp = &report;
  1083. PodZero(&report);
  1084. report.filename = filename.ptr();
  1085. report.lineno = (uintN) lineno;
  1086. if (JSVAL_IS_STRING(roots[2])) {
  1087. JSFixedString *fixed = JSVAL_TO_STRING(roots[2])->ensureFixed(cx);
  1088. if (!fixed)
  1089. return false;
  1090. report.ucmessage = fixed->chars();
  1091. }
  1092. }
  1093. if (!reportp) {
  1094. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
  1095. JSMSG_UNCAUGHT_EXCEPTION, bytes);
  1096. } else {
  1097. /* Flag the error as an exception. */
  1098. reportp->flags |= JSREPORT_EXCEPTION;
  1099. /* Pass the exception object. */
  1100. JS_SetPendingException(cx, exn);
  1101. js_ReportErrorAgain(cx, bytes, reportp);
  1102. JS_ClearPendingException(cx);
  1103. }
  1104. return true;
  1105. }
  1106. extern JSObject *
  1107. js_CopyErrorObject(JSContext *cx, JSObject *errobj, JSObject *scope)
  1108. {
  1109. assertSameCompartment(cx, scope);
  1110. JSExnPrivate *priv = GetExnPrivate(errobj);
  1111. uint32_t stackDepth = priv->stackDepth;
  1112. size_t valueCount = 0;
  1113. for (uint32_t i = 0; i < stackDepth; i++)
  1114. valueCount += priv->stackElems[i].argc;
  1115. size_t size = offsetof(JSExnPrivate, stackElems) +
  1116. stackDepth * sizeof(JSStackTraceElem) +
  1117. valueCount * sizeof(jsval);
  1118. JSExnPrivate *copy = (JSExnPrivate *)cx->malloc_(size);
  1119. if (!copy)
  1120. return NULL;
  1121. struct AutoFree {
  1122. JSContext *cx;
  1123. JSExnPrivate *p;
  1124. ~AutoFree() {
  1125. if (p) {
  1126. cx->free_(p->errorReport);
  1127. cx->free_(p);
  1128. }
  1129. }
  1130. } autoFree = {cx, copy};
  1131. // Copy each field. Don't bother copying the stack elements.
  1132. if (priv->errorReport) {
  1133. copy->errorReport = CopyErrorReport(cx, priv->errorReport);
  1134. if (!copy->errorReport)
  1135. return NULL;
  1136. } else {
  1137. copy->errorReport = NULL;
  1138. }
  1139. copy->message.init(priv->message);
  1140. if (!cx->compartment->wrap(cx, &copy->message))
  1141. return NULL;
  1142. JS::Anchor<JSString *> messageAnchor(copy->message);
  1143. copy->filename.init(priv->filename);
  1144. if (!cx->compartment->wrap(cx, &copy->filename))
  1145. return NULL;
  1146. JS::Anchor<JSString *> filenameAnchor(copy->filename);
  1147. copy->lineno = priv->lineno;
  1148. copy->stackDepth = 0;
  1149. copy->exnType = priv->exnType;
  1150. // Create the Error object.
  1151. JSObject *proto = scope->global().getOrCreateCustomErrorPrototype(cx, copy->exnType);
  1152. if (!proto)
  1153. return NULL;
  1154. JSObject *copyobj = NewObjectWithGivenProto(cx, &ErrorClass, proto, NULL);
  1155. SetExnPrivate(cx, copyobj, copy);
  1156. autoFree.p = NULL;
  1157. return copyobj;
  1158. }