*** /dev/null Sat Nov 23 01:23:45 2024
--- - Sat Nov 23 01:23:57 2024
***************
*** 0 ****
--- 1,4823 ----
+ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=80:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+ /*
+ * JavaScript API.
+ */
+ #include "jsstddef.h"
+ #include <ctype.h>
+ #include <stdarg.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include "jstypes.h"
+ #include "jsarena.h" /* Added by JSIFY */
+ #include "jsutil.h" /* Added by JSIFY */
+ #include "jsclist.h"
+ #include "jsdhash.h"
+ #include "jsprf.h"
+ #include "jsapi.h"
+ #include "jsarray.h"
+ #include "jsatom.h"
+ #include "jsbool.h"
+ #include "jscntxt.h"
+ #include "jsconfig.h"
+ #include "jsdate.h"
+ #include "jsdtoa.h"
+ #include "jsemit.h"
+ #include "jsexn.h"
+ #include "jsfun.h"
+ #include "jsgc.h"
+ #include "jsinterp.h"
+ #include "jslock.h"
+ #include "jsmath.h"
+ #include "jsnum.h"
+ #include "jsobj.h"
+ #include "jsopcode.h"
+ #include "jsparse.h"
+ #include "jsregexp.h"
+ #include "jsscan.h"
+ #include "jsscope.h"
+ #include "jsscript.h"
+ #include "jsstr.h"
+ #include "prmjtime.h"
+
+ #if JS_HAS_FILE_OBJECT
+ #include "jsfile.h"
+ #endif
+
+ #if JS_HAS_XML_SUPPORT
+ #include "jsxml.h"
+ #endif
+
+ #ifdef HAVE_VA_LIST_AS_ARRAY
+ #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
+ #else
+ #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
+ #endif
+
+ #if defined(JS_PARANOID_REQUEST) && defined(JS_THREADSAFE)
+ #define CHECK_REQUEST(cx) JS_ASSERT(cx->requestDepth)
+ #else
+ #define CHECK_REQUEST(cx) ((void)0)
+ #endif
+
+ JS_PUBLIC_API(int64)
+ JS_Now()
+ {
+ return PRMJ_Now();
+ }
+
+ JS_PUBLIC_API(jsval)
+ JS_GetNaNValue(JSContext *cx)
+ {
+ return DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
+ }
+
+ JS_PUBLIC_API(jsval)
+ JS_GetNegativeInfinityValue(JSContext *cx)
+ {
+ return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
+ }
+
+ JS_PUBLIC_API(jsval)
+ JS_GetPositiveInfinityValue(JSContext *cx)
+ {
+ return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
+ }
+
+ JS_PUBLIC_API(jsval)
+ JS_GetEmptyStringValue(JSContext *cx)
+ {
+ return STRING_TO_JSVAL(cx->runtime->emptyString);
+ }
+
+ static JSBool
+ TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
+ #ifdef OSSP
+ jsval **vpp, va_list app)
+ #else
+ jsval **vpp, va_list *app)
+ #endif
+ {
+ const char *format;
+ JSArgumentFormatMap *map;
+
+ format = *formatp;
+ for (map = cx->argumentFormatMap; map; map = map->next) {
+ if (!strncmp(format, map->format, map->length)) {
+ *formatp = format + map->length;
+ return map->formatter(cx, format, fromJS, vpp, app);
+ }
+ }
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
+ return JS_FALSE;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
+ ...)
+ {
+ va_list ap;
+ JSBool ok;
+
+ va_start(ap, format);
+ ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
+ va_end(ap);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
+ const char *format, va_list ap)
+ {
+ jsval *sp;
+ JSBool required;
+ char c;
+ JSFunction *fun;
+ jsdouble d;
+ JSString *str;
+ JSObject *obj;
+
+ CHECK_REQUEST(cx);
+ sp = argv;
+ required = JS_TRUE;
+ while ((c = *format++) != '\0') {
+ if (isspace(c))
+ continue;
+ if (c == '/') {
+ required = JS_FALSE;
+ continue;
+ }
+ if (sp == argv + argc) {
+ if (required) {
+ fun = js_ValueToFunction(cx, &argv[-2], 0);
+ if (fun) {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_MORE_ARGS_NEEDED,
+ JS_GetFunctionName(fun), numBuf,
+ (argc == 1) ? "" : "s");
+ }
+ return JS_FALSE;
+ }
+ break;
+ }
+ switch (c) {
+ case 'b':
+ if (!js_ValueToBoolean(cx, *sp, va_arg(ap, JSBool *)))
+ return JS_FALSE;
+ break;
+ case 'c':
+ if (!js_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
+ return JS_FALSE;
+ break;
+ case 'i':
+ if (!js_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
+ return JS_FALSE;
+ break;
+ case 'u':
+ if (!js_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
+ return JS_FALSE;
+ break;
+ case 'j':
+ if (!js_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
+ return JS_FALSE;
+ break;
+ case 'd':
+ if (!js_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
+ return JS_FALSE;
+ break;
+ case 'I':
+ if (!js_ValueToNumber(cx, *sp, &d))
+ return JS_FALSE;
+ *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
+ break;
+ case 's':
+ case 'S':
+ case 'W':
+ str = js_ValueToString(cx, *sp);
+ if (!str)
+ return JS_FALSE;
+ *sp = STRING_TO_JSVAL(str);
+ if (c == 's')
+ *va_arg(ap, char **) = JS_GetStringBytes(str);
+ else if (c == 'W')
+ *va_arg(ap, jschar **) = JS_GetStringChars(str);
+ else
+ *va_arg(ap, JSString **) = str;
+ break;
+ case 'o':
+ if (!js_ValueToObject(cx, *sp, &obj))
+ return JS_FALSE;
+ *sp = OBJECT_TO_JSVAL(obj);
+ *va_arg(ap, JSObject **) = obj;
+ break;
+ case 'f':
+ obj = js_ValueToFunctionObject(cx, sp, 0);
+ if (!obj)
+ return JS_FALSE;
+ *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj);
+ break;
+ case 'v':
+ *va_arg(ap, jsval *) = *sp;
+ break;
+ case '*':
+ break;
+ default:
+ format--;
+ if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
+ #ifdef OSSP
+ ap)) {
+ #else
+ JS_ADDRESSOF_VA_LIST(ap))) {
+ #endif
+ return JS_FALSE;
+ }
+ /* NB: the formatter already updated sp, so we continue here. */
+ continue;
+ }
+ sp++;
+ }
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(jsval *)
+ JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
+ {
+ va_list ap;
+ jsval *argv;
+
+ va_start(ap, format);
+ argv = JS_PushArgumentsVA(cx, markp, format, ap);
+ va_end(ap);
+ return argv;
+ }
+
+ JS_PUBLIC_API(jsval *)
+ JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
+ {
+ uintN argc;
+ jsval *argv, *sp;
+ char c;
+ const char *cp;
+ JSString *str;
+ JSFunction *fun;
+ JSStackHeader *sh;
+
+ CHECK_REQUEST(cx);
+ *markp = NULL;
+ argc = 0;
+ for (cp = format; (c = *cp) != '\0'; cp++) {
+ /*
+ * Count non-space non-star characters as individual jsval arguments.
+ * This may over-allocate stack, but we'll fix below.
+ */
+ if (isspace(c) || c == '*')
+ continue;
+ argc++;
+ }
+ sp = js_AllocStack(cx, argc, markp);
+ if (!sp)
+ return NULL;
+ argv = sp;
+ while ((c = *format++) != '\0') {
+ if (isspace(c) || c == '*')
+ continue;
+ switch (c) {
+ case 'b':
+ *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int));
+ break;
+ case 'c':
+ *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int));
+ break;
+ case 'i':
+ case 'j':
+ if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp))
+ goto bad;
+ break;
+ case 'u':
+ if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
+ goto bad;
+ break;
+ case 'd':
+ case 'I':
+ if (!js_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
+ goto bad;
+ break;
+ case 's':
+ str = JS_NewStringCopyZ(cx, va_arg(ap, char *));
+ if (!str)
+ goto bad;
+ *sp = STRING_TO_JSVAL(str);
+ break;
+ case 'W':
+ str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *));
+ if (!str)
+ goto bad;
+ *sp = STRING_TO_JSVAL(str);
+ break;
+ case 'S':
+ str = va_arg(ap, JSString *);
+ *sp = STRING_TO_JSVAL(str);
+ break;
+ case 'o':
+ *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *));
+ break;
+ case 'f':
+ fun = va_arg(ap, JSFunction *);
+ *sp = fun ? OBJECT_TO_JSVAL(fun->object) : JSVAL_NULL;
+ break;
+ case 'v':
+ *sp = va_arg(ap, jsval);
+ break;
+ default:
+ format--;
+ if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp,
+ #ifdef OSSP
+ ap)) {
+ #else
+ JS_ADDRESSOF_VA_LIST(ap))) {
+ #endif
+ goto bad;
+ }
+ /* NB: the formatter already updated sp, so we continue here. */
+ continue;
+ }
+ sp++;
+ }
+
+ /*
+ * We may have overallocated stack due to a multi-character format code
+ * handled by a JSArgumentFormatter. Give back that stack space!
+ */
+ JS_ASSERT(sp <= argv + argc);
+ if (sp < argv + argc) {
+ /* Return slots not pushed to the current stack arena. */
+ cx->stackPool.current->avail = (jsuword)sp;
+
+ /* Reduce the count of slots the GC will scan in this stack segment. */
+ sh = cx->stackHeaders;
+ JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc);
+ sh->nslots -= argc - (sp - argv);
+ }
+ return argv;
+
+ bad:
+ js_FreeStack(cx, *markp);
+ return NULL;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_PopArguments(JSContext *cx, void *mark)
+ {
+ CHECK_REQUEST(cx);
+ js_FreeStack(cx, mark);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_AddArgumentFormatter(JSContext *cx, const char *format,
+ JSArgumentFormatter formatter)
+ {
+ size_t length;
+ JSArgumentFormatMap **mpp, *map;
+
+ length = strlen(format);
+ mpp = &cx->argumentFormatMap;
+ while ((map = *mpp) != NULL) {
+ /* Insert before any shorter string to match before prefixes. */
+ if (map->length < length)
+ break;
+ if (map->length == length && !strcmp(map->format, format))
+ goto out;
+ mpp = &map->next;
+ }
+ map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map);
+ if (!map)
+ return JS_FALSE;
+ map->format = format;
+ map->length = length;
+ map->next = *mpp;
+ *mpp = map;
+ out:
+ map->formatter = formatter;
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
+ {
+ size_t length;
+ JSArgumentFormatMap **mpp, *map;
+
+ length = strlen(format);
+ mpp = &cx->argumentFormatMap;
+ while ((map = *mpp) != NULL) {
+ if (map->length == length && !strcmp(map->format, format)) {
+ *mpp = map->next;
+ JS_free(cx, map);
+ return;
+ }
+ mpp = &map->next;
+ }
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
+ {
+ JSBool ok, b;
+ JSObject *obj;
+ JSString *str;
+ jsdouble d, *dp;
+
+ CHECK_REQUEST(cx);
+ switch (type) {
+ case JSTYPE_VOID:
+ *vp = JSVAL_VOID;
+ ok = JS_TRUE;
+ break;
+ case JSTYPE_OBJECT:
+ ok = js_ValueToObject(cx, v, &obj);
+ if (ok)
+ *vp = OBJECT_TO_JSVAL(obj);
+ break;
+ case JSTYPE_FUNCTION:
+ *vp = v;
+ obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
+ ok = (obj != NULL);
+ break;
+ case JSTYPE_STRING:
+ str = js_ValueToString(cx, v);
+ ok = (str != NULL);
+ if (ok)
+ *vp = STRING_TO_JSVAL(str);
+ break;
+ case JSTYPE_NUMBER:
+ ok = js_ValueToNumber(cx, v, &d);
+ if (ok) {
+ dp = js_NewDouble(cx, d, 0);
+ ok = (dp != NULL);
+ if (ok)
+ *vp = DOUBLE_TO_JSVAL(dp);
+ }
+ break;
+ case JSTYPE_BOOLEAN:
+ ok = js_ValueToBoolean(cx, v, &b);
+ if (ok)
+ *vp = BOOLEAN_TO_JSVAL(b);
+ break;
+ default: {
+ char numBuf[12];
+ JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
+ numBuf);
+ ok = JS_FALSE;
+ break;
+ }
+ }
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
+ {
+ CHECK_REQUEST(cx);
+ return js_ValueToObject(cx, v, objp);
+ }
+
+ JS_PUBLIC_API(JSFunction *)
+ JS_ValueToFunction(JSContext *cx, jsval v)
+ {
+ CHECK_REQUEST(cx);
+ return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
+ }
+
+ JS_PUBLIC_API(JSFunction *)
+ JS_ValueToConstructor(JSContext *cx, jsval v)
+ {
+ CHECK_REQUEST(cx);
+ return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_ValueToString(JSContext *cx, jsval v)
+ {
+ CHECK_REQUEST(cx);
+ return js_ValueToString(cx, v);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
+ {
+ CHECK_REQUEST(cx);
+ return js_ValueToNumber(cx, v, dp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
+ {
+ CHECK_REQUEST(cx);
+ return js_ValueToECMAInt32(cx, v, ip);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
+ {
+ CHECK_REQUEST(cx);
+ return js_ValueToECMAUint32(cx, v, ip);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
+ {
+ CHECK_REQUEST(cx);
+ return js_ValueToInt32(cx, v, ip);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
+ {
+ CHECK_REQUEST(cx);
+ return js_ValueToUint16(cx, v, ip);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
+ {
+ CHECK_REQUEST(cx);
+ return js_ValueToBoolean(cx, v, bp);
+ }
+
+ JS_PUBLIC_API(JSType)
+ JS_TypeOfValue(JSContext *cx, jsval v)
+ {
+ JSType type;
+ JSObject *obj;
+ JSObjectOps *ops;
+ JSClass *clasp;
+
+ CHECK_REQUEST(cx);
+ if (JSVAL_IS_OBJECT(v)) {
+ type = JSTYPE_OBJECT; /* XXXbe JSTYPE_NULL for JS2 */
+ obj = JSVAL_TO_OBJECT(v);
+ if (obj) {
+ ops = obj->map->ops;
+ #if JS_HAS_XML_SUPPORT
+ if (ops == &js_XMLObjectOps.base) {
+ type = JSTYPE_XML;
+ } else
+ #endif
+ {
+ /*
+ * ECMA 262, 11.4.3 says that any native object that implements
+ * [[Call]] should be of type "function". Note that RegExp and
+ * Script are both of type "function" for compatibility with
+ * older SpiderMonkeys.
+ */
+ clasp = OBJ_GET_CLASS(cx, obj);
+ if ((ops == &js_ObjectOps)
+ ? (clasp->call
+ ? (clasp == &js_RegExpClass || clasp == &js_ScriptClass)
+ : clasp == &js_FunctionClass)
+ : ops->call != NULL) {
+ type = JSTYPE_FUNCTION;
+ } else {
+ #ifdef NARCISSUS
+ if (!OBJ_GET_PROPERTY(cx, obj,
+ ATOM_TO_JSID(cx->runtime->atomState
+ .callAtom),
+ &v)) {
+ JS_ClearPendingException(cx);
+ } else if (JSVAL_IS_FUNCTION(cx, v)) {
+ type = JSTYPE_FUNCTION;
+ }
+ #endif
+ }
+ }
+ }
+ } else if (JSVAL_IS_NUMBER(v)) {
+ type = JSTYPE_NUMBER;
+ } else if (JSVAL_IS_STRING(v)) {
+ type = JSTYPE_STRING;
+ } else if (JSVAL_IS_BOOLEAN(v)) {
+ type = JSTYPE_BOOLEAN;
+ } else {
+ type = JSTYPE_VOID;
+ }
+ return type;
+ }
+
+ JS_PUBLIC_API(const char *)
+ JS_GetTypeName(JSContext *cx, JSType type)
+ {
+ if ((uintN)type >= (uintN)JSTYPE_LIMIT)
+ return NULL;
+ return js_type_str[type];
+ }
+
+ /************************************************************************/
+
+ JS_PUBLIC_API(JSRuntime *)
+ JS_NewRuntime(uint32 maxbytes)
+ {
+ JSRuntime *rt;
+
+ #ifdef DEBUG
+ JS_BEGIN_MACRO
+ /*
+ * This code asserts that the numbers associated with the error names in
+ * jsmsg.def are monotonically increasing. It uses values for the error
+ * names enumerated in jscntxt.c. It's not a compiletime check, but it's
+ * better than nothing.
+ */
+ int errorNumber = 0;
+ #define MSG_DEF(name, number, count, exception, format) \
+ JS_ASSERT(name == errorNumber++);
+ #include "js.msg"
+ #undef MSG_DEF
+ JS_END_MACRO;
+ #endif /* DEBUG */
+
+ if (!js_InitStringGlobals())
+ return NULL;
+ rt = (JSRuntime *) malloc(sizeof(JSRuntime));
+ if (!rt)
+ return NULL;
+
+ /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
+ memset(rt, 0, sizeof(JSRuntime));
+ JS_INIT_CLIST(&rt->contextList);
+ JS_INIT_CLIST(&rt->trapList);
+ JS_INIT_CLIST(&rt->watchPointList);
+
+ if (!js_InitGC(rt, maxbytes))
+ goto bad;
+ #ifdef JS_THREADSAFE
+ rt->gcLock = JS_NEW_LOCK();
+ if (!rt->gcLock)
+ goto bad;
+ rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
+ if (!rt->gcDone)
+ goto bad;
+ rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
+ if (!rt->requestDone)
+ goto bad;
+ /* this is asymmetric with JS_ShutDown: */
+ if (!js_SetupLocks(8, 16))
+ goto bad;
+ rt->rtLock = JS_NEW_LOCK();
+ if (!rt->rtLock)
+ goto bad;
+ rt->stateChange = JS_NEW_CONDVAR(rt->gcLock);
+ if (!rt->stateChange)
+ goto bad;
+ rt->setSlotLock = JS_NEW_LOCK();
+ if (!rt->setSlotLock)
+ goto bad;
+ rt->setSlotDone = JS_NEW_CONDVAR(rt->setSlotLock);
+ if (!rt->setSlotDone)
+ goto bad;
+ rt->scopeSharingDone = JS_NEW_CONDVAR(rt->gcLock);
+ if (!rt->scopeSharingDone)
+ goto bad;
+ rt->scopeSharingTodo = NO_SCOPE_SHARING_TODO;
+ #endif
+ rt->propertyCache.empty = JS_TRUE;
+ if (!js_InitPropertyTree(rt))
+ goto bad;
+ return rt;
+
+ bad:
+ JS_DestroyRuntime(rt);
+ return NULL;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_DestroyRuntime(JSRuntime *rt)
+ {
+ #ifdef DEBUG
+ /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
+ if (!JS_CLIST_IS_EMPTY(&rt->contextList)) {
+ JSContext *cx, *iter = NULL;
+ uintN cxcount = 0;
+ while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
+ cxcount++;
+ fprintf(stderr,
+ "JS API usage error: %u contexts left in runtime upon JS_DestroyRuntime.\n",
+ cxcount);
+ }
+ #endif
+
+ js_FreeRuntimeScriptState(rt);
+ js_FinishAtomState(&rt->atomState);
+ js_FinishGC(rt);
+ #ifdef JS_THREADSAFE
+ if (rt->gcLock)
+ JS_DESTROY_LOCK(rt->gcLock);
+ if (rt->gcDone)
+ JS_DESTROY_CONDVAR(rt->gcDone);
+ if (rt->requestDone)
+ JS_DESTROY_CONDVAR(rt->requestDone);
+ if (rt->rtLock)
+ JS_DESTROY_LOCK(rt->rtLock);
+ if (rt->stateChange)
+ JS_DESTROY_CONDVAR(rt->stateChange);
+ if (rt->setSlotLock)
+ JS_DESTROY_LOCK(rt->setSlotLock);
+ if (rt->setSlotDone)
+ JS_DESTROY_CONDVAR(rt->setSlotDone);
+ if (rt->scopeSharingDone)
+ JS_DESTROY_CONDVAR(rt->scopeSharingDone);
+ #endif
+ js_FinishPropertyTree(rt);
+ free(rt);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_ShutDown(void)
+ {
+ JS_ArenaShutDown();
+ js_FinishDtoa();
+ js_FreeStringGlobals();
+ #ifdef JS_THREADSAFE
+ js_CleanupLocks();
+ #endif
+ }
+
+ JS_PUBLIC_API(void *)
+ JS_GetRuntimePrivate(JSRuntime *rt)
+ {
+ return rt->data;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_SetRuntimePrivate(JSRuntime *rt, void *data)
+ {
+ rt->data = data;
+ }
+
+ #ifdef JS_THREADSAFE
+
+ JS_PUBLIC_API(void)
+ JS_BeginRequest(JSContext *cx)
+ {
+ JSRuntime *rt;
+
+ JS_ASSERT(cx->thread);
+ if (!cx->requestDepth) {
+ /* Wait until the GC is finished. */
+ rt = cx->runtime;
+ JS_LOCK_GC(rt);
+
+ /* NB: we use cx->thread here, not js_CurrentThreadId(). */
+ if (rt->gcThread != cx->thread) {
+ while (rt->gcLevel > 0)
+ JS_AWAIT_GC_DONE(rt);
+ }
+
+ /* Indicate that a request is running. */
+ rt->requestCount++;
+ cx->requestDepth = 1;
+ JS_UNLOCK_GC(rt);
+ return;
+ }
+ cx->requestDepth++;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_EndRequest(JSContext *cx)
+ {
+ JSRuntime *rt;
+ JSScope *scope, **todop;
+ uintN nshares;
+
+ CHECK_REQUEST(cx);
+ JS_ASSERT(cx->requestDepth > 0);
+ if (cx->requestDepth == 1) {
+ /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
+ rt = cx->runtime;
+ JS_LOCK_GC(rt);
+ cx->requestDepth = 0;
+
+ /* See whether cx has any single-threaded scopes to start sharing. */
+ todop = &rt->scopeSharingTodo;
+ nshares = 0;
+ while ((scope = *todop) != NO_SCOPE_SHARING_TODO) {
+ if (scope->ownercx != cx) {
+ todop = &scope->u.link;
+ continue;
+ }
+ *todop = scope->u.link;
+ scope->u.link = NULL; /* null u.link for sanity ASAP */
+
+ /*
+ * If js_DropObjectMap returns null, we held the last ref to scope.
+ * The waiting thread(s) must have been killed, after which the GC
+ * collected the object that held this scope. Unlikely, because it
+ * requires that the GC ran (e.g., from a branch callback) during
+ * this request, but possible.
+ */
+ if (js_DropObjectMap(cx, &scope->map, NULL)) {
+ js_InitLock(&scope->lock);
+ scope->u.count = 0; /* NULL may not pun as 0 */
+ js_FinishSharingScope(rt, scope); /* set ownercx = NULL */
+ nshares++;
+ }
+ }
+ if (nshares)
+ JS_NOTIFY_ALL_CONDVAR(rt->scopeSharingDone);
+
+ /* Give the GC a chance to run if this was the last request running. */
+ JS_ASSERT(rt->requestCount > 0);
+ rt->requestCount--;
+ if (rt->requestCount == 0)
+ JS_NOTIFY_REQUEST_DONE(rt);
+
+ JS_UNLOCK_GC(rt);
+ return;
+ }
+
+ cx->requestDepth--;
+ }
+
+ /* Yield to pending GC operations, regardless of request depth */
+ JS_PUBLIC_API(void)
+ JS_YieldRequest(JSContext *cx)
+ {
+ JSRuntime *rt;
+
+ JS_ASSERT(cx->thread);
+ CHECK_REQUEST(cx);
+
+ rt = cx->runtime;
+ JS_LOCK_GC(rt);
+ JS_ASSERT(rt->requestCount > 0);
+ rt->requestCount--;
+ if (rt->requestCount == 0)
+ JS_NOTIFY_REQUEST_DONE(rt);
+ JS_UNLOCK_GC(rt);
+ /* XXXbe give the GC or another request calling it a chance to run here?
+ Assumes FIFO scheduling */
+ JS_LOCK_GC(rt);
+ rt->requestCount++;
+ JS_UNLOCK_GC(rt);
+ }
+
+ JS_PUBLIC_API(jsrefcount)
+ JS_SuspendRequest(JSContext *cx)
+ {
+ jsrefcount saveDepth = cx->requestDepth;
+
+ while (cx->requestDepth)
+ JS_EndRequest(cx);
+ return saveDepth;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
+ {
+ JS_ASSERT(!cx->requestDepth);
+ while (--saveDepth >= 0)
+ JS_BeginRequest(cx);
+ }
+
+ #endif /* JS_THREADSAFE */
+
+ JS_PUBLIC_API(void)
+ JS_Lock(JSRuntime *rt)
+ {
+ JS_LOCK_RUNTIME(rt);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_Unlock(JSRuntime *rt)
+ {
+ JS_UNLOCK_RUNTIME(rt);
+ }
+
+ JS_PUBLIC_API(JSContext *)
+ JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
+ {
+ return js_NewContext(rt, stackChunkSize);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_DestroyContext(JSContext *cx)
+ {
+ js_DestroyContext(cx, JS_FORCE_GC);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_DestroyContextNoGC(JSContext *cx)
+ {
+ js_DestroyContext(cx, JS_NO_GC);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_DestroyContextMaybeGC(JSContext *cx)
+ {
+ js_DestroyContext(cx, JS_MAYBE_GC);
+ }
+
+ JS_PUBLIC_API(void *)
+ JS_GetContextPrivate(JSContext *cx)
+ {
+ return cx->data;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_SetContextPrivate(JSContext *cx, void *data)
+ {
+ cx->data = data;
+ }
+
+ JS_PUBLIC_API(JSRuntime *)
+ JS_GetRuntime(JSContext *cx)
+ {
+ return cx->runtime;
+ }
+
+ JS_PUBLIC_API(JSContext *)
+ JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
+ {
+ return js_ContextIterator(rt, JS_TRUE, iterp);
+ }
+
+ JS_PUBLIC_API(JSVersion)
+ JS_GetVersion(JSContext *cx)
+ {
+ return cx->version & JSVERSION_MASK;
+ }
+
+ JS_PUBLIC_API(JSVersion)
+ JS_SetVersion(JSContext *cx, JSVersion version)
+ {
+ JSVersion oldVersion;
+
+ JS_ASSERT(version != JSVERSION_UNKNOWN);
+ JS_ASSERT((version & ~JSVERSION_MASK) == 0);
+
+ oldVersion = cx->version & JSVERSION_MASK;
+ if (version == oldVersion)
+ return oldVersion;
+
+ cx->version = (cx->version & ~JSVERSION_MASK) | version;
+ js_OnVersionChange(cx);
+ return oldVersion;
+ }
+
+ static struct v2smap {
+ JSVersion version;
+ const char *string;
+ } v2smap[] = {
+ {JSVERSION_1_0, "1.0"},
+ {JSVERSION_1_1, "1.1"},
+ {JSVERSION_1_2, "1.2"},
+ {JSVERSION_1_3, "1.3"},
+ {JSVERSION_1_4, "1.4"},
+ {JSVERSION_ECMA_3, "ECMAv3"},
+ {JSVERSION_1_5, "1.5"},
+ {JSVERSION_1_6, "1.6"},
+ {JSVERSION_DEFAULT, js_default_str},
+ {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
+ };
+
+ JS_PUBLIC_API(const char *)
+ JS_VersionToString(JSVersion version)
+ {
+ int i;
+
+ for (i = 0; v2smap[i].string; i++)
+ if (v2smap[i].version == version)
+ return v2smap[i].string;
+ return "unknown";
+ }
+
+ JS_PUBLIC_API(JSVersion)
+ JS_StringToVersion(const char *string)
+ {
+ int i;
+
+ for (i = 0; v2smap[i].string; i++)
+ if (strcmp(v2smap[i].string, string) == 0)
+ return v2smap[i].version;
+ return JSVERSION_UNKNOWN;
+ }
+
+ JS_PUBLIC_API(uint32)
+ JS_GetOptions(JSContext *cx)
+ {
+ return cx->options;
+ }
+
+ #define SYNC_OPTIONS_TO_VERSION(cx) \
+ JS_BEGIN_MACRO \
+ if ((cx)->options & JSOPTION_XML) \
+ (cx)->version |= JSVERSION_HAS_XML; \
+ else \
+ (cx)->version &= ~JSVERSION_HAS_XML; \
+ JS_END_MACRO
+
+ JS_PUBLIC_API(uint32)
+ JS_SetOptions(JSContext *cx, uint32 options)
+ {
+ uint32 oldopts = cx->options;
+ cx->options = options;
+ SYNC_OPTIONS_TO_VERSION(cx);
+ return oldopts;
+ }
+
+ JS_PUBLIC_API(uint32)
+ JS_ToggleOptions(JSContext *cx, uint32 options)
+ {
+ uint32 oldopts = cx->options;
+ cx->options ^= options;
+ SYNC_OPTIONS_TO_VERSION(cx);
+ return oldopts;
+ }
+
+ JS_PUBLIC_API(const char *)
+ JS_GetImplementationVersion(void)
+ {
+ return "JavaScript-C 1.6 pre-release 1 2006-04-04";
+ }
+
+
+ JS_PUBLIC_API(JSObject *)
+ JS_GetGlobalObject(JSContext *cx)
+ {
+ return cx->globalObject;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_SetGlobalObject(JSContext *cx, JSObject *obj)
+ {
+ cx->globalObject = obj;
+ #if JS_HAS_XML_SUPPORT
+ cx->xmlSettingFlags = 0;
+ #endif
+ }
+
+ static JSObject *
+ InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
+ {
+ JSDHashTable *table;
+ JSBool resolving;
+ JSRuntime *rt;
+ JSResolvingKey key;
+ JSResolvingEntry *entry;
+ JSObject *fun_proto, *obj_proto;
+
+ /* If cx has no global object, use obj so prototypes can be found. */
+ if (!cx->globalObject)
+ JS_SetGlobalObject(cx, obj);
+
+ /* Record Function and Object in cx->resolvingTable, if we are resolving. */
+ table = cx->resolvingTable;
+ resolving = (table && table->entryCount);
+ if (resolving) {
+ rt = cx->runtime;
+ key.obj = obj;
+ key.id = ATOM_TO_JSID(rt->atomState.FunctionAtom);
+ entry = (JSResolvingEntry *)
+ JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
+ if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) {
+ /* Already resolving Function, record Object too. */
+ JS_ASSERT(entry->key.obj == obj);
+ key.id = ATOM_TO_JSID(rt->atomState.ObjectAtom);
+ entry = (JSResolvingEntry *)
+ JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
+ }
+ if (!entry) {
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+ }
+ JS_ASSERT(!entry->key.obj && entry->flags == 0);
+ entry->key = key;
+ entry->flags = JSRESFLAG_LOOKUP;
+ }
+
+ /* Initialize the function class first so constructors can be made. */
+ fun_proto = js_InitFunctionClass(cx, obj);
+ if (!fun_proto)
+ goto out;
+
+ /* Initialize the object class next so Object.prototype works. */
+ obj_proto = js_InitObjectClass(cx, obj);
+ if (!obj_proto) {
+ fun_proto = NULL;
+ goto out;
+ }
+
+ /* Function.prototype and the global object delegate to Object.prototype. */
+ OBJ_SET_PROTO(cx, fun_proto, obj_proto);
+ if (!OBJ_GET_PROTO(cx, obj))
+ OBJ_SET_PROTO(cx, obj, obj_proto);
+
+ out:
+ /* If resolving, remove the other entry (Object or Function) from table. */
+ if (resolving)
+ JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
+ return fun_proto;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_InitStandardClasses(JSContext *cx, JSObject *obj)
+ {
+ CHECK_REQUEST(cx);
+
+ #if JS_HAS_UNDEFINED
+ {
+ /* Define a top-level property 'undefined' with the undefined value. */
+ JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
+ if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
+ NULL, NULL, JSPROP_PERMANENT, NULL)) {
+ return JS_FALSE;
+ }
+ }
+ #endif
+
+ /* Function and Object require cooperative bootstrapping magic. */
+ if (!InitFunctionAndObjectClasses(cx, obj))
+ return JS_FALSE;
+
+ /* Initialize the rest of the standard objects and functions. */
+ return js_InitArrayClass(cx, obj) &&
+ js_InitBooleanClass(cx, obj) &&
+ js_InitMathClass(cx, obj) &&
+ js_InitNumberClass(cx, obj) &&
+ js_InitStringClass(cx, obj) &&
+ #if JS_HAS_CALL_OBJECT
+ js_InitCallClass(cx, obj) &&
+ #endif
+ #if JS_HAS_REGEXPS
+ js_InitRegExpClass(cx, obj) &&
+ #endif
+ #if JS_HAS_SCRIPT_OBJECT
+ js_InitScriptClass(cx, obj) &&
+ #endif
+ #if JS_HAS_ERROR_EXCEPTIONS
+ js_InitExceptionClasses(cx, obj) &&
+ #endif
+ #if JS_HAS_XML_SUPPORT
+ js_InitXMLClasses(cx, obj) &&
+ #endif
+ #if JS_HAS_FILE_OBJECT
+ js_InitFileClass(cx, obj) &&
+ #endif
+ js_InitDateClass(cx, obj);
+ }
+
+ #define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom)
+ #define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
+
+ /*
+ * Table of class initializers and their atom offsets in rt->atomState.
+ * If you add a "standard" class, remember to update this table.
+ */
+ static struct {
+ JSObjectOp init;
+ size_t atomOffset;
+ } standard_class_atoms[] = {
+ {InitFunctionAndObjectClasses, ATOM_OFFSET(Function)},
+ {InitFunctionAndObjectClasses, ATOM_OFFSET(Object)},
+ {js_InitArrayClass, ATOM_OFFSET(Array)},
+ {js_InitBooleanClass, ATOM_OFFSET(Boolean)},
+ {js_InitDateClass, ATOM_OFFSET(Date)},
+ {js_InitMathClass, ATOM_OFFSET(Math)},
+ {js_InitNumberClass, ATOM_OFFSET(Number)},
+ {js_InitStringClass, ATOM_OFFSET(String)},
+ #if JS_HAS_CALL_OBJECT
+ {js_InitCallClass, ATOM_OFFSET(Call)},
+ #endif
+ #if JS_HAS_ERROR_EXCEPTIONS
+ {js_InitExceptionClasses, ATOM_OFFSET(Error)},
+ #endif
+ #if JS_HAS_REGEXPS
+ {js_InitRegExpClass, ATOM_OFFSET(RegExp)},
+ #endif
+ #if JS_HAS_SCRIPT_OBJECT
+ {js_InitScriptClass, ATOM_OFFSET(Script)},
+ #endif
+ #if JS_HAS_XML_SUPPORT
+ {js_InitXMLClass, ATOM_OFFSET(XML)},
+ {js_InitNamespaceClass, ATOM_OFFSET(Namespace)},
+ {js_InitQNameClass, ATOM_OFFSET(QName)},
+ #endif
+ #if JS_HAS_FILE_OBJECT
+ {js_InitFileClass, ATOM_OFFSET(File)},
+ #endif
+ {NULL, 0}
+ };
+
+ /*
+ * Table of top-level function and constant names and their init functions.
+ * If you add a "standard" global function or property, remember to update
+ * this table.
+ */
+ typedef struct JSStdName {
+ JSObjectOp init;
+ size_t atomOffset; /* offset of atom pointer in JSAtomState */
+ const char *name; /* null if atom is pre-pinned, else name */
+ } JSStdName;
+
+ static JSAtom *
+ StdNameToAtom(JSContext *cx, JSStdName *stdn)
+ {
+ size_t offset;
+ JSAtom *atom;
+ const char *name;
+
+ offset = stdn->atomOffset;
+ atom = OFFSET_TO_ATOM(cx->runtime, offset);
+ if (!atom) {
+ name = stdn->name;
+ if (name) {
+ atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
+ OFFSET_TO_ATOM(cx->runtime, offset) = atom;
+ }
+ }
+ return atom;
+ }
+
+ #define EAGERLY_PINNED_ATOM(name) ATOM_OFFSET(name), NULL
+ #define LAZILY_PINNED_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
+
+ static JSStdName standard_class_names[] = {
+ /* ECMA requires that eval be a direct property of the global object. */
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(eval)},
+
+ /* Global properties and functions defined by the Number class. */
+ {js_InitNumberClass, LAZILY_PINNED_ATOM(NaN)},
+ {js_InitNumberClass, LAZILY_PINNED_ATOM(Infinity)},
+ {js_InitNumberClass, LAZILY_PINNED_ATOM(isNaN)},
+ {js_InitNumberClass, LAZILY_PINNED_ATOM(isFinite)},
+ {js_InitNumberClass, LAZILY_PINNED_ATOM(parseFloat)},
+ {js_InitNumberClass, LAZILY_PINNED_ATOM(parseInt)},
+
+ /* String global functions. */
+ {js_InitStringClass, LAZILY_PINNED_ATOM(escape)},
+ {js_InitStringClass, LAZILY_PINNED_ATOM(unescape)},
+ {js_InitStringClass, LAZILY_PINNED_ATOM(decodeURI)},
+ {js_InitStringClass, LAZILY_PINNED_ATOM(encodeURI)},
+ {js_InitStringClass, LAZILY_PINNED_ATOM(decodeURIComponent)},
+ {js_InitStringClass, LAZILY_PINNED_ATOM(encodeURIComponent)},
+ #if JS_HAS_UNEVAL
+ {js_InitStringClass, LAZILY_PINNED_ATOM(uneval)},
+ #endif
+
+ /* Exception constructors. */
+ #if JS_HAS_ERROR_EXCEPTIONS
+ {js_InitExceptionClasses, EAGERLY_PINNED_ATOM(Error)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(InternalError)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(EvalError)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(RangeError)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(ReferenceError)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(SyntaxError)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(TypeError)},
+ {js_InitExceptionClasses, LAZILY_PINNED_ATOM(URIError)},
+ #endif
+
+ #if JS_HAS_XML_SUPPORT
+ {js_InitAnyNameClass, LAZILY_PINNED_ATOM(AnyName)},
+ {js_InitAttributeNameClass, LAZILY_PINNED_ATOM(AttributeName)},
+ {js_InitXMLClass, LAZILY_PINNED_ATOM(XMLList)},
+ {js_InitXMLClass, LAZILY_PINNED_ATOM(isXMLName)},
+ #endif
+
+ {NULL, 0, NULL}
+ };
+
+ static JSStdName object_prototype_names[] = {
+ /* Object.prototype properties (global delegates to Object.prototype). */
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(proto)},
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(parent)},
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(count)},
+ #if JS_HAS_TOSOURCE
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(toSource)},
+ #endif
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(toString)},
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(toLocaleString)},
+ {js_InitObjectClass, EAGERLY_PINNED_ATOM(valueOf)},
+ #if JS_HAS_OBJ_WATCHPOINT
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(watch)},
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(unwatch)},
+ #endif
+ #if JS_HAS_NEW_OBJ_METHODS
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(hasOwnProperty)},
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(isPrototypeOf)},
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(propertyIsEnumerable)},
+ #endif
+ #if JS_HAS_GETTER_SETTER
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(defineGetter)},
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(defineSetter)},
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(lookupGetter)},
+ {js_InitObjectClass, LAZILY_PINNED_ATOM(lookupSetter)},
+ #endif
+
+ {NULL, 0, NULL}
+ };
+
+ #undef EAGERLY_PINNED_ATOM
+ #undef LAZILY_PINNED_ATOM
+
+ JS_PUBLIC_API(JSBool)
+ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
+ JSBool *resolved)
+ {
+ JSString *idstr;
+ JSRuntime *rt;
+ JSAtom *atom;
+ JSObjectOp init;
+ uintN i;
+
+ CHECK_REQUEST(cx);
+ *resolved = JS_FALSE;
+
+ if (!JSVAL_IS_STRING(id))
+ return JS_TRUE;
+ idstr = JSVAL_TO_STRING(id);
+ rt = cx->runtime;
+
+ #if JS_HAS_UNDEFINED
+ /* Check whether we're resolving 'undefined', and define it if so. */
+ atom = rt->atomState.typeAtoms[JSTYPE_VOID];
+ if (idstr == ATOM_TO_STRING(atom)) {
+ *resolved = JS_TRUE;
+ return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
+ NULL, NULL, JSPROP_PERMANENT, NULL);
+ }
+ #endif
+
+ /* Try for class constructors/prototypes named by well-known atoms. */
+ init = NULL;
+ for (i = 0; standard_class_atoms[i].init; i++) {
+ atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
+ if (idstr == ATOM_TO_STRING(atom)) {
+ init = standard_class_atoms[i].init;
+ break;
+ }
+ }
+
+ if (!init) {
+ /* Try less frequently used top-level functions and constants. */
+ for (i = 0; standard_class_names[i].init; i++) {
+ atom = StdNameToAtom(cx, &standard_class_names[i]);
+ if (!atom)
+ return JS_FALSE;
+ if (idstr == ATOM_TO_STRING(atom)) {
+ init = standard_class_names[i].init;
+ break;
+ }
+ }
+
+ if (!init && !OBJ_GET_PROTO(cx, obj)) {
+ /*
+ * Try even less frequently used names delegated from the global
+ * object to Object.prototype, but only if the Object class hasn't
+ * yet been initialized.
+ */
+ for (i = 0; object_prototype_names[i].init; i++) {
+ atom = StdNameToAtom(cx, &object_prototype_names[i]);
+ if (!atom)
+ return JS_FALSE;
+ if (idstr == ATOM_TO_STRING(atom)) {
+ init = standard_class_names[i].init;
+ break;
+ }
+ }
+ }
+ }
+
+ if (init) {
+ if (!init(cx, obj))
+ return JS_FALSE;
+ *resolved = JS_TRUE;
+ }
+ return JS_TRUE;
+ }
+
+ static JSBool
+ AlreadyHasOwnProperty(JSObject *obj, JSAtom *atom)
+ {
+ JS_ASSERT(OBJ_IS_NATIVE(obj));
+ return SCOPE_GET_PROPERTY(OBJ_SCOPE(obj), ATOM_TO_JSID(atom)) != NULL;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
+ {
+ JSRuntime *rt;
+ JSAtom *atom;
+ uintN i;
+
+ CHECK_REQUEST(cx);
+ rt = cx->runtime;
+
+ #if JS_HAS_UNDEFINED
+ /* Check whether we need to bind 'undefined' and define it if so. */
+ atom = rt->atomState.typeAtoms[JSTYPE_VOID];
+ if (!AlreadyHasOwnProperty(obj, atom) &&
+ !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
+ NULL, NULL, JSPROP_PERMANENT, NULL)) {
+ return JS_FALSE;
+ }
+ #endif
+
+ /* Initialize any classes that have not been resolved yet. */
+ for (i = 0; standard_class_atoms[i].init; i++) {
+ atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
+ if (!AlreadyHasOwnProperty(obj, atom) &&
+ !standard_class_atoms[i].init(cx, obj)) {
+ return JS_FALSE;
+ }
+ }
+
+ return JS_TRUE;
+ }
+
+ static JSIdArray *
+ AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
+ {
+ jsint i, length;
+
+ i = *ip;
+ length = ida->length;
+ if (i >= length) {
+ ida = js_SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
+ if (!ida)
+ return NULL;
+ JS_ASSERT(i < ida->length);
+ }
+ ida->vector[i] = ATOM_TO_JSID(atom);
+ *ip = i + 1;
+ return ida;
+ }
+
+ static JSIdArray *
+ EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
+ jsint *ip, JSBool *foundp)
+ {
+ *foundp = AlreadyHasOwnProperty(obj, atom);
+ if (*foundp)
+ ida = AddAtomToArray(cx, atom, ida, ip);
+ return ida;
+ }
+
+ JS_PUBLIC_API(JSIdArray *)
+ JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
+ JSIdArray *ida)
+ {
+ JSRuntime *rt;
+ jsint i, j, k;
+ JSAtom *atom;
+ JSBool found;
+ JSObjectOp init;
+
+ CHECK_REQUEST(cx);
+ rt = cx->runtime;
+ if (ida) {
+ i = ida->length;
+ } else {
+ ida = js_NewIdArray(cx, 8);
+ if (!ida)
+ return NULL;
+ i = 0;
+ }
+
+ #if JS_HAS_UNDEFINED
+ /* Check whether 'undefined' has been resolved and enumerate it if so. */
+ atom = rt->atomState.typeAtoms[JSTYPE_VOID];
+ ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
+ if (!ida)
+ return NULL;
+ #endif
+
+ /* Enumerate only classes that *have* been resolved. */
+ for (j = 0; standard_class_atoms[j].init; j++) {
+ atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
+ ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
+ if (!ida)
+ return NULL;
+
+ if (found) {
+ init = standard_class_atoms[j].init;
+
+ for (k = 0; standard_class_names[k].init; k++) {
+ if (standard_class_names[k].init == init) {
+ atom = StdNameToAtom(cx, &standard_class_names[k]);
+ ida = AddAtomToArray(cx, atom, ida, &i);
+ if (!ida)
+ return NULL;
+ }
+ }
+
+ if (init == js_InitObjectClass) {
+ for (k = 0; object_prototype_names[k].init; k++) {
+ atom = StdNameToAtom(cx, &object_prototype_names[k]);
+ ida = AddAtomToArray(cx, atom, ida, &i);
+ if (!ida)
+ return NULL;
+ }
+ }
+ }
+ }
+
+ /* Trim to exact length via js_SetIdArrayLength. */
+ return js_SetIdArrayLength(cx, ida, i);
+ }
+
+ #undef ATOM_OFFSET
+ #undef OFFSET_TO_ATOM
+
+ JS_PUBLIC_API(JSObject *)
+ JS_GetScopeChain(JSContext *cx)
+ {
+ return cx->fp ? cx->fp->scopeChain : NULL;
+ }
+
+ JS_PUBLIC_API(void *)
+ JS_malloc(JSContext *cx, size_t nbytes)
+ {
+ void *p;
+
+ JS_ASSERT(nbytes != 0);
+ if (nbytes == 0)
+ nbytes = 1;
+ cx->runtime->gcMallocBytes += nbytes;
+ p = malloc(nbytes);
+ if (!p)
+ JS_ReportOutOfMemory(cx);
+ return p;
+ }
+
+ JS_PUBLIC_API(void *)
+ JS_realloc(JSContext *cx, void *p, size_t nbytes)
+ {
+ p = realloc(p, nbytes);
+ if (!p)
+ JS_ReportOutOfMemory(cx);
+ return p;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_free(JSContext *cx, void *p)
+ {
+ if (p)
+ free(p);
+ }
+
+ JS_PUBLIC_API(char *)
+ JS_strdup(JSContext *cx, const char *s)
+ {
+ size_t n;
+ void *p;
+
+ n = strlen(s) + 1;
+ p = JS_malloc(cx, n);
+ if (!p)
+ return NULL;
+ return (char *)memcpy(p, s, n);
+ }
+
+ JS_PUBLIC_API(jsdouble *)
+ JS_NewDouble(JSContext *cx, jsdouble d)
+ {
+ CHECK_REQUEST(cx);
+ return js_NewDouble(cx, d, 0);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
+ {
+ CHECK_REQUEST(cx);
+ return js_NewDoubleValue(cx, d, rval);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
+ {
+ CHECK_REQUEST(cx);
+ return js_NewNumberValue(cx, d, rval);
+ }
+
+ #undef JS_AddRoot
+ JS_PUBLIC_API(JSBool)
+ JS_AddRoot(JSContext *cx, void *rp)
+ {
+ CHECK_REQUEST(cx);
+ return js_AddRoot(cx, rp, NULL);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
+ {
+ return js_AddRootRT(rt, rp, name);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_RemoveRoot(JSContext *cx, void *rp)
+ {
+ CHECK_REQUEST(cx);
+ return js_RemoveRoot(cx->runtime, rp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_RemoveRootRT(JSRuntime *rt, void *rp)
+ {
+ return js_RemoveRoot(rt, rp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
+ {
+ CHECK_REQUEST(cx);
+ return js_AddRoot(cx, rp, name);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_ClearNewbornRoots(JSContext *cx)
+ {
+ uintN i;
+
+ for (i = 0; i < GCX_NTYPES; i++)
+ cx->newborn[i] = NULL;
+ cx->lastAtom = NULL;
+ cx->lastInternalResult = JSVAL_NULL;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_EnterLocalRootScope(JSContext *cx)
+ {
+ CHECK_REQUEST(cx);
+ return js_EnterLocalRootScope(cx);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_LeaveLocalRootScope(JSContext *cx)
+ {
+ CHECK_REQUEST(cx);
+ js_LeaveLocalRootScope(cx);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_ForgetLocalRoot(JSContext *cx, void *thing)
+ {
+ CHECK_REQUEST(cx);
+ js_ForgetLocalRoot(cx, (jsval) thing);
+ }
+
+ #include "jshash.h" /* Added by JSIFY */
+
+ #ifdef DEBUG
+
+ typedef struct NamedRootDumpArgs {
+ void (*dump)(const char *name, void *rp, void *data);
+ void *data;
+ } NamedRootDumpArgs;
+
+ JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+ js_named_root_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
+ void *arg)
+ {
+ NamedRootDumpArgs *args = (NamedRootDumpArgs *) arg;
+ JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
+
+ if (rhe->name)
+ args->dump(rhe->name, rhe->root, args->data);
+ return JS_DHASH_NEXT;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_DumpNamedRoots(JSRuntime *rt,
+ void (*dump)(const char *name, void *rp, void *data),
+ void *data)
+ {
+ NamedRootDumpArgs args;
+
+ args.dump = dump;
+ args.data = data;
+ JS_DHashTableEnumerate(&rt->gcRootsHash, js_named_root_dumper, &args);
+ }
+
+ #endif /* DEBUG */
+
+ typedef struct GCRootMapArgs {
+ JSGCRootMapFun map;
+ void *data;
+ } GCRootMapArgs;
+
+ JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+ js_gcroot_mapper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
+ void *arg)
+ {
+ GCRootMapArgs *args = (GCRootMapArgs *) arg;
+ JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
+ intN mapflags;
+ JSDHashOperator op;
+
+ mapflags = args->map(rhe->root, rhe->name, args->data);
+
+ #if JS_MAP_GCROOT_NEXT == JS_DHASH_NEXT && \
+ JS_MAP_GCROOT_STOP == JS_DHASH_STOP && \
+ JS_MAP_GCROOT_REMOVE == JS_DHASH_REMOVE
+ op = (JSDHashOperator)mapflags;
+ #else
+ op = JS_DHASH_NEXT;
+ if (mapflags & JS_MAP_GCROOT_STOP)
+ op |= JS_DHASH_STOP;
+ if (mapflags & JS_MAP_GCROOT_REMOVE)
+ op |= JS_DHASH_REMOVE;
+ #endif
+
+ return op;
+ }
+
+ JS_PUBLIC_API(uint32)
+ JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
+ {
+ GCRootMapArgs args;
+ uint32 rv;
+
+ args.map = map;
+ args.data = data;
+ JS_LOCK_GC(rt);
+ rv = JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args);
+ JS_UNLOCK_GC(rt);
+ return rv;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_LockGCThing(JSContext *cx, void *thing)
+ {
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ ok = js_LockGCThing(cx, thing);
+ if (!ok)
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_LOCK);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_LockGCThingRT(JSRuntime *rt, void *thing)
+ {
+ return js_LockGCThingRT(rt, thing);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_UnlockGCThing(JSContext *cx, void *thing)
+ {
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ ok = js_UnlockGCThingRT(cx->runtime, thing);
+ if (!ok)
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
+ {
+ return js_UnlockGCThingRT(rt, thing);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg)
+ {
+ JS_ASSERT(cx->runtime->gcLevel > 0);
+ #ifdef JS_THREADSAFE
+ JS_ASSERT(cx->runtime->gcThread == js_CurrentThreadId());
+ #endif
+
+ GC_MARK(cx, thing, name, arg);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_GC(JSContext *cx)
+ {
+ /* Don't nuke active arenas if executing or compiling. */
+ if (cx->stackPool.current == &cx->stackPool.first)
+ JS_FinishArenaPool(&cx->stackPool);
+ if (cx->tempPool.current == &cx->tempPool.first)
+ JS_FinishArenaPool(&cx->tempPool);
+ js_ForceGC(cx, 0);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_MaybeGC(JSContext *cx)
+ {
+ #ifdef WAY_TOO_MUCH_GC
+ JS_GC(cx);
+ #else
+ JSRuntime *rt;
+ uint32 bytes, lastBytes;
+
+ rt = cx->runtime;
+ bytes = rt->gcBytes;
+ lastBytes = rt->gcLastBytes;
+ if ((bytes > 8192 && bytes > lastBytes + lastBytes / 2) ||
+ rt->gcMallocBytes > rt->gcMaxMallocBytes) {
+ /*
+ * Run the GC if we have half again as many bytes of GC-things as
+ * the last time we GC'd, or if we have malloc'd more bytes through
+ * JS_malloc than we were told to allocate by JS_NewRuntime.
+ */
+ JS_GC(cx);
+ }
+ #endif
+ }
+
+ JS_PUBLIC_API(JSGCCallback)
+ JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
+ {
+ return JS_SetGCCallbackRT(cx->runtime, cb);
+ }
+
+ JS_PUBLIC_API(JSGCCallback)
+ JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
+ {
+ JSGCCallback oldcb;
+
+ oldcb = rt->gcCallback;
+ rt->gcCallback = cb;
+ return oldcb;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
+ {
+ JS_ASSERT(thing);
+ return js_IsAboutToBeFinalized(cx, thing);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
+ {
+ switch (key) {
+ case JSGC_MAX_BYTES:
+ rt->gcMaxBytes = value;
+ break;
+ case JSGC_MAX_MALLOC_BYTES:
+ rt->gcMaxMallocBytes = value;
+ break;
+ }
+ }
+
+ JS_PUBLIC_API(intN)
+ JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
+ {
+ return js_ChangeExternalStringFinalizer(NULL, finalizer);
+ }
+
+ JS_PUBLIC_API(intN)
+ JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
+ {
+ return js_ChangeExternalStringFinalizer(finalizer, NULL);
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
+ {
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ JS_ASSERT(GCX_EXTERNAL_STRING <= type && type < (intN) GCX_NTYPES);
+
+ str = (JSString *) js_NewGCThing(cx, (uintN) type, sizeof(JSString));
+ if (!str)
+ return NULL;
+ str->length = length;
+ str->chars = chars;
+ return str;
+ }
+
+ JS_PUBLIC_API(intN)
+ JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
+ {
+ uint8 type = (uint8) (*js_GetGCThingFlags(str) & GCF_TYPEMASK);
+
+ if (type >= GCX_EXTERNAL_STRING)
+ return (intN)type;
+ JS_ASSERT(type == GCX_STRING || type == GCX_MUTABLE_STRING);
+ return -1;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
+ {
+ #if JS_STACK_GROWTH_DIRECTION > 0
+ if (limitAddr == 0)
+ limitAddr = (jsuword)-1;
+ #endif
+ cx->stackLimit = limitAddr;
+ }
+
+ /************************************************************************/
+
+ JS_PUBLIC_API(void)
+ JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
+ {
+ JS_free(cx, ida);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
+ {
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ if (JSVAL_IS_INT(v)) {
+ *idp = v;
+ } else {
+ atom = js_ValueToStringAtom(cx, v);
+ if (!atom)
+ return JS_FALSE;
+ *idp = ATOM_TO_JSID(atom);
+ }
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
+ {
+ CHECK_REQUEST(cx);
+ *vp = ID_TO_VALUE(id);
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+ {
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_EnumerateStub(JSContext *cx, JSObject *obj)
+ {
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id)
+ {
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
+ {
+ #if JS_BUG_EAGER_TOSTRING
+ if (type == JSTYPE_STRING)
+ return JS_TRUE;
+ #endif
+ js_TryValueOf(cx, obj, type, vp);
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_FinalizeStub(JSContext *cx, JSObject *obj)
+ {
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
+ JSClass *clasp, JSNative constructor, uintN nargs,
+ JSPropertySpec *ps, JSFunctionSpec *fs,
+ JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
+ {
+ JSAtom *atom;
+ JSObject *proto, *ctor;
+ JSTempValueRooter tvr;
+ jsval cval, rval;
+ JSBool named;
+ JSFunction *fun;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
+ if (!atom)
+ return NULL;
+
+ /* Create a prototype object for this class. */
+ proto = js_NewObject(cx, clasp, parent_proto, obj);
+ if (!proto)
+ return NULL;
+
+ /* After this point, control must exit via label bad or out. */
+ JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(proto), &tvr);
+
+ if (!constructor) {
+ /* Lacking a constructor, name the prototype (e.g., Math). */
+ named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
+ OBJECT_TO_JSVAL(proto),
+ NULL, NULL, 0, NULL);
+ if (!named)
+ goto bad;
+ ctor = proto;
+ } else {
+ /* Define the constructor function in obj's scope. */
+ fun = js_DefineFunction(cx, obj, atom, constructor, nargs, 0);
+ named = (fun != NULL);
+ if (!fun)
+ goto bad;
+
+ /*
+ * Remember the class this function is a constructor for so that
+ * we know to create an object of this class when we call the
+ * constructor.
+ */
+ fun->clasp = clasp;
+
+ /*
+ * Optionally construct the prototype object, before the class has
+ * been fully initialized. Allow the ctor to replace proto with a
+ * different object, as is done for operator new -- and as at least
+ * XML support requires.
+ */
+ ctor = fun->object;
+ if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) {
+ cval = OBJECT_TO_JSVAL(ctor);
+ if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval))
+ goto bad;
+ if (!JSVAL_IS_PRIMITIVE(rval) && JSVAL_TO_OBJECT(rval) != proto)
+ proto = JSVAL_TO_OBJECT(rval);
+ }
+
+ /* Connect constructor and prototype by named properties. */
+ if (!js_SetClassPrototype(cx, ctor, proto,
+ JSPROP_READONLY | JSPROP_PERMANENT)) {
+ goto bad;
+ }
+
+ /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
+ if (OBJ_GET_CLASS(cx, ctor) == clasp) {
+ /* XXXMLM - this fails in framesets that are writing over
+ * themselves!
+ * JS_ASSERT(!OBJ_GET_PROTO(cx, ctor));
+ */
+ OBJ_SET_PROTO(cx, ctor, proto);
+ }
+ }
+
+ /* Add properties and methods to the prototype and the constructor. */
+ if ((ps && !JS_DefineProperties(cx, proto, ps)) ||
+ (fs && !JS_DefineFunctions(cx, proto, fs)) ||
+ (static_ps && !JS_DefineProperties(cx, ctor, static_ps)) ||
+ (static_fs && !JS_DefineFunctions(cx, ctor, static_fs))) {
+ goto bad;
+ }
+
+ out:
+ JS_POP_TEMP_ROOT(cx, &tvr);
+ return proto;
+
+ bad:
+ if (named)
+ (void) OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &rval);
+ proto = NULL;
+ goto out;
+ }
+
+ #ifdef JS_THREADSAFE
+ JS_PUBLIC_API(JSClass *)
+ JS_GetClass(JSContext *cx, JSObject *obj)
+ {
+ return (JSClass *)
+ JSVAL_TO_PRIVATE(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_CLASS));
+ }
+ #else
+ JS_PUBLIC_API(JSClass *)
+ JS_GetClass(JSObject *obj)
+ {
+ return LOCKED_OBJ_GET_CLASS(obj);
+ }
+ #endif
+
+ JS_PUBLIC_API(JSBool)
+ JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
+ {
+ JSFunction *fun;
+
+ CHECK_REQUEST(cx);
+ if (OBJ_GET_CLASS(cx, obj) == clasp)
+ return JS_TRUE;
+ if (argv) {
+ fun = js_ValueToFunction(cx, &argv[-2], 0);
+ if (fun) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_INCOMPATIBLE_PROTO,
+ clasp->name, JS_GetFunctionName(fun),
+ OBJ_GET_CLASS(cx, obj)->name);
+ }
+ }
+ return JS_FALSE;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
+ {
+ return js_HasInstance(cx, obj, v, bp);
+ }
+
+ JS_PUBLIC_API(void *)
+ JS_GetPrivate(JSContext *cx, JSObject *obj)
+ {
+ jsval v;
+
+ JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
+ v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ if (!JSVAL_IS_INT(v))
+ return NULL;
+ return JSVAL_TO_PRIVATE(v);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
+ {
+ JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(data));
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(void *)
+ JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp,
+ jsval *argv)
+ {
+ if (!JS_InstanceOf(cx, obj, clasp, argv))
+ return NULL;
+ return JS_GetPrivate(cx, obj);
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_GetPrototype(JSContext *cx, JSObject *obj)
+ {
+ JSObject *proto;
+
+ CHECK_REQUEST(cx);
+ proto = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PROTO));
+
+ /* Beware ref to dead object (we may be called from obj's finalizer). */
+ return proto && proto->map ? proto : NULL;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
+ {
+ CHECK_REQUEST(cx);
+ if (obj->map->ops->setProto)
+ return obj->map->ops->setProto(cx, obj, JSSLOT_PROTO, proto);
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PROTO, OBJECT_TO_JSVAL(proto));
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_GetParent(JSContext *cx, JSObject *obj)
+ {
+ JSObject *parent;
+
+ parent = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PARENT));
+
+ /* Beware ref to dead object (we may be called from obj's finalizer). */
+ return parent && parent->map ? parent : NULL;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
+ {
+ CHECK_REQUEST(cx);
+ if (obj->map->ops->setParent)
+ return obj->map->ops->setParent(cx, obj, JSSLOT_PARENT, parent);
+ OBJ_SET_SLOT(cx, obj, JSSLOT_PARENT, OBJECT_TO_JSVAL(parent));
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_GetConstructor(JSContext *cx, JSObject *proto)
+ {
+ jsval cval;
+
+ CHECK_REQUEST(cx);
+ if (!OBJ_GET_PROPERTY(cx, proto,
+ ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
+ &cval)) {
+ return NULL;
+ }
+ if (!JSVAL_IS_FUNCTION(cx, cval)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
+ OBJ_GET_CLASS(cx, proto)->name);
+ return NULL;
+ }
+ return JSVAL_TO_OBJECT(cval);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
+ {
+ JS_ASSERT(((jsid)obj & JSID_TAGMASK) == 0);
+ *idp = OBJECT_TO_JSID(obj);
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
+ {
+ CHECK_REQUEST(cx);
+ if (!clasp)
+ clasp = &js_ObjectClass; /* default class is Object */
+ return js_NewObject(cx, clasp, proto, parent);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
+ {
+ JSScope *scope;
+ JSIdArray *ida;
+ uint32 nslots;
+ jsval v, *vp, *end;
+
+ if (!OBJ_IS_NATIVE(obj)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_CANT_SEAL_OBJECT,
+ OBJ_GET_CLASS(cx, obj)->name);
+ return JS_FALSE;
+ }
+
+ scope = OBJ_SCOPE(obj);
+
+ #if defined JS_THREADSAFE && defined DEBUG
+ /* Insist on scope being used exclusively by cx's thread. */
+ if (scope->ownercx != cx) {
+ JS_LOCK_OBJ(cx, obj);
+ JS_ASSERT(OBJ_SCOPE(obj) == scope);
+ JS_ASSERT(scope->ownercx == cx);
+ JS_UNLOCK_SCOPE(cx, scope);
+ }
+ #endif
+
+ /* Nothing to do if obj's scope is already sealed. */
+ if (SCOPE_IS_SEALED(scope))
+ return JS_TRUE;
+
+ /* XXX Enumerate lazy properties now, as they can't be added later. */
+ ida = JS_Enumerate(cx, obj);
+ if (!ida)
+ return JS_FALSE;
+ JS_DestroyIdArray(cx, ida);
+
+ /* Ensure that obj has its own, mutable scope, and seal that scope. */
+ JS_LOCK_OBJ(cx, obj);
+ scope = js_GetMutableScope(cx, obj);
+ if (scope)
+ SCOPE_SET_SEALED(scope);
+ JS_UNLOCK_SCOPE(cx, scope);
+ if (!scope)
+ return JS_FALSE;
+
+ /* If we are not sealing an entire object graph, we're done. */
+ if (!deep)
+ return JS_TRUE;
+
+ /* Walk obj->slots and if any value is a non-null object, seal it. */
+ nslots = JS_MIN(scope->map.freeslot, scope->map.nslots);
+ for (vp = obj->slots, end = vp + nslots; vp < end; vp++) {
+ v = *vp;
+ if (JSVAL_IS_PRIMITIVE(v))
+ continue;
+ if (!JS_SealObject(cx, JSVAL_TO_OBJECT(v), deep))
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
+ JSObject *parent)
+ {
+ CHECK_REQUEST(cx);
+ if (!clasp)
+ clasp = &js_ObjectClass; /* default class is Object */
+ return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto,
+ JSObject *parent, uintN argc, jsval *argv)
+ {
+ CHECK_REQUEST(cx);
+ if (!clasp)
+ clasp = &js_ObjectClass; /* default class is Object */
+ return js_ConstructObject(cx, clasp, proto, parent, argc, argv);
+ }
+
+ static JSBool
+ DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
+ uintN flags, intN tinyid)
+ {
+ jsid id;
+ JSAtom *atom;
+
+ if (attrs & JSPROP_INDEX) {
+ id = INT_TO_JSID(JS_PTR_TO_INT32(name));
+ atom = NULL;
+ attrs &= ~JSPROP_INDEX;
+ } else {
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ id = ATOM_TO_JSID(atom);
+ }
+ if (flags != 0 && OBJ_IS_NATIVE(obj)) {
+ return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
+ attrs, flags, tinyid, NULL);
+ }
+ return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs,
+ NULL);
+ }
+
+ #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
+
+ static JSBool
+ DefineUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
+ uintN flags, intN tinyid)
+ {
+ JSAtom *atom;
+
+ atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
+ if (!atom)
+ return JS_FALSE;
+ if (flags != 0 && OBJ_IS_NATIVE(obj)) {
+ return js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
+ getter, setter, attrs, flags, tinyid,
+ NULL);
+ }
+ return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), value,
+ getter, setter, attrs, NULL);
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
+ JSObject *proto, uintN attrs)
+ {
+ JSObject *nobj;
+
+ CHECK_REQUEST(cx);
+ if (!clasp)
+ clasp = &js_ObjectClass; /* default class is Object */
+ nobj = js_NewObject(cx, clasp, proto, obj);
+ if (!nobj)
+ return NULL;
+ if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs,
+ 0, 0)) {
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+ return nobj;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
+ {
+ JSBool ok;
+ jsval value;
+ uintN flags;
+
+ CHECK_REQUEST(cx);
+ for (ok = JS_TRUE; cds->name; cds++) {
+ ok = js_NewNumberValue(cx, cds->dval, &value);
+ if (!ok)
+ break;
+ flags = cds->flags;
+ if (!flags)
+ flags = JSPROP_READONLY | JSPROP_PERMANENT;
+ ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, flags, 0, 0);
+ if (!ok)
+ break;
+ }
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
+ {
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ for (ok = JS_TRUE; ps->name; ps++) {
+ ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID,
+ ps->getter, ps->setter, ps->flags,
+ SPROP_HAS_SHORTID, ps->tinyid);
+ if (!ok)
+ break;
+ }
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
+ {
+ CHECK_REQUEST(cx);
+ return DefineProperty(cx, obj, name, value, getter, setter, attrs, 0, 0);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
+ int8 tinyid, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter,
+ uintN attrs)
+ {
+ CHECK_REQUEST(cx);
+ return DefineProperty(cx, obj, name, value, getter, setter, attrs,
+ SPROP_HAS_SHORTID, tinyid);
+ }
+
+ static JSBool
+ LookupProperty(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
+ JSProperty **propp)
+ {
+ JSAtom *atom;
+
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), objp, propp);
+ }
+
+ static JSBool
+ LookupUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ JSObject **objp, JSProperty **propp)
+ {
+ JSAtom *atom;
+
+ atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), objp, propp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
+ const char *alias)
+ {
+ JSObject *obj2;
+ JSProperty *prop;
+ JSAtom *atom;
+ JSBool ok;
+ JSScopeProperty *sprop;
+
+ CHECK_REQUEST(cx);
+ if (!LookupProperty(cx, obj, name, &obj2, &prop))
+ return JS_FALSE;
+ if (!prop) {
+ js_ReportIsNotDefined(cx, name);
+ return JS_FALSE;
+ }
+ if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
+ alias, name, OBJ_GET_CLASS(cx, obj2)->name);
+ return JS_FALSE;
+ }
+ atom = js_Atomize(cx, alias, strlen(alias), 0);
+ if (!atom) {
+ ok = JS_FALSE;
+ } else {
+ sprop = (JSScopeProperty *)prop;
+ ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
+ sprop->getter, sprop->setter, sprop->slot,
+ sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
+ sprop->shortid)
+ != NULL);
+ }
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return ok;
+ }
+
+ static jsval
+ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop)
+ {
+ JSScopeProperty *sprop;
+ jsval rval;
+
+ if (!prop) {
+ /* XXX bad API: no way to tell "not defined" from "void value" */
+ return JSVAL_VOID;
+ }
+ if (OBJ_IS_NATIVE(obj2)) {
+ /* Peek at the native property's slot value, without doing a Get. */
+ sprop = (JSScopeProperty *)prop;
+ rval = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2))
+ ? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot)
+ : JSVAL_TRUE;
+ } else {
+ /* XXX bad API: no way to return "defined but value unknown" */
+ rval = JSVAL_TRUE;
+ }
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ return rval;
+ }
+
+ static JSBool
+ GetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
+ uintN *attrsp, JSBool *foundp,
+ JSPropertyOp *getterp, JSPropertyOp *setterp)
+ {
+ JSObject *obj2;
+ JSProperty *prop;
+ JSBool ok;
+
+ if (!atom)
+ return JS_FALSE;
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
+ return JS_FALSE;
+
+ if (!prop || obj != obj2) {
+ *attrsp = 0;
+ *foundp = JS_FALSE;
+ if (getterp)
+ *getterp = NULL;
+ if (setterp)
+ *setterp = NULL;
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ return JS_TRUE;
+ }
+
+ *foundp = JS_TRUE;
+ ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, attrsp);
+ if (ok && OBJ_IS_NATIVE(obj)) {
+ JSScopeProperty *sprop = (JSScopeProperty *) prop;
+
+ if (getterp)
+ *getterp = sprop->getter;
+ if (setterp)
+ *setterp = sprop->setter;
+ }
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return ok;
+ }
+
+ static JSBool
+ SetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
+ uintN attrs, JSBool *foundp)
+ {
+ JSObject *obj2;
+ JSProperty *prop;
+ JSBool ok;
+
+ if (!atom)
+ return JS_FALSE;
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
+ return JS_FALSE;
+ if (!prop || obj != obj2) {
+ *foundp = JS_FALSE;
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ return JS_TRUE;
+ }
+
+ *foundp = JS_TRUE;
+ ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs);
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
+ uintN *attrsp, JSBool *foundp)
+ {
+ CHECK_REQUEST(cx);
+ return GetPropertyAttributes(cx, obj,
+ js_Atomize(cx, name, strlen(name), 0),
+ attrsp, foundp, NULL, NULL);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
+ const char *name,
+ uintN *attrsp, JSBool *foundp,
+ JSPropertyOp *getterp,
+ JSPropertyOp *setterp)
+ {
+ CHECK_REQUEST(cx);
+ return GetPropertyAttributes(cx, obj,
+ js_Atomize(cx, name, strlen(name), 0),
+ attrsp, foundp, getterp, setterp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
+ uintN attrs, JSBool *foundp)
+ {
+ CHECK_REQUEST(cx);
+ return SetPropertyAttributes(cx, obj,
+ js_Atomize(cx, name, strlen(name), 0),
+ attrs, foundp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
+ {
+ JSBool ok;
+ JSObject *obj2;
+ JSProperty *prop;
+
+ CHECK_REQUEST(cx);
+ ok = LookupProperty(cx, obj, name, &obj2, &prop);
+ if (ok) {
+ *foundp = (prop != NULL);
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ }
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
+ {
+ JSBool ok;
+ JSObject *obj2;
+ JSProperty *prop;
+
+ CHECK_REQUEST(cx);
+ ok = LookupProperty(cx, obj, name, &obj2, &prop);
+ if (ok)
+ *vp = LookupResult(cx, obj, obj2, prop);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
+ uintN flags, jsval *vp)
+ {
+ JSAtom *atom;
+ JSBool ok;
+ JSObject *obj2;
+ JSProperty *prop;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ ok = OBJ_IS_NATIVE(obj)
+ ? js_LookupPropertyWithFlags(cx, obj, ATOM_TO_JSID(atom), flags,
+ &obj2, &prop)
+ : OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop);
+ if (ok)
+ *vp = LookupResult(cx, obj, obj2, prop);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
+ {
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
+ jsval *vp)
+ {
+ JSAtom *atom;
+ jsid id;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ id = ATOM_TO_JSID(atom);
+
+ #if JS_HAS_XML_SUPPORT
+ if (OBJECT_IS_XML(cx, obj)) {
+ JSXMLObjectOps *ops;
+
+ ops = (JSXMLObjectOps *) obj->map->ops;
+ obj = ops->getMethod(cx, obj, id, vp);
+ if (!obj)
+ return JS_FALSE;
+ } else
+ #endif
+ {
+ if (!OBJ_GET_PROPERTY(cx, obj, id, vp))
+ return JS_FALSE;
+ }
+
+ *objp = obj;
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
+ {
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
+ {
+ jsval junk;
+
+ CHECK_REQUEST(cx);
+ return JS_DeleteProperty2(cx, obj, name, &junk);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name,
+ jsval *rval)
+ {
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DefineUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter,
+ uintN attrs)
+ {
+ CHECK_REQUEST(cx);
+ return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
+ attrs, 0, 0);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ uintN *attrsp, JSBool *foundp)
+ {
+ CHECK_REQUEST(cx);
+ return GetPropertyAttributes(cx, obj,
+ js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
+ attrsp, foundp, NULL, NULL);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ uintN *attrsp, JSBool *foundp,
+ JSPropertyOp *getterp,
+ JSPropertyOp *setterp)
+ {
+ CHECK_REQUEST(cx);
+ return GetPropertyAttributes(cx, obj,
+ js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
+ attrsp, foundp, getterp, setterp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ uintN attrs, JSBool *foundp)
+ {
+ CHECK_REQUEST(cx);
+ return SetPropertyAttributes(cx, obj,
+ js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
+ attrs, foundp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ int8 tinyid, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter,
+ uintN attrs)
+ {
+ CHECK_REQUEST(cx);
+ return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
+ attrs, SPROP_HAS_SHORTID, tinyid);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_HasUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ JSBool *vp)
+ {
+ JSBool ok;
+ JSObject *obj2;
+ JSProperty *prop;
+
+ CHECK_REQUEST(cx);
+ ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
+ if (ok) {
+ *vp = (prop != NULL);
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ }
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_LookupUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ jsval *vp)
+ {
+ JSBool ok;
+ JSObject *obj2;
+ JSProperty *prop;
+
+ CHECK_REQUEST(cx);
+ ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
+ if (ok)
+ *vp = LookupResult(cx, obj, obj2, prop);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_GetUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ jsval *vp)
+ {
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_SetUCProperty(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ jsval *vp)
+ {
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen,
+ jsval *rval)
+ {
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
+ if (!atom)
+ return JS_FALSE;
+ return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
+ {
+ CHECK_REQUEST(cx);
+ /* NB: jsuint cast does ToUint32. */
+ return js_NewArrayObject(cx, (jsuint)length, vector);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_IsArrayObject(JSContext *cx, JSObject *obj)
+ {
+ return OBJ_GET_CLASS(cx, obj) == &js_ArrayClass;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
+ {
+ CHECK_REQUEST(cx);
+ return js_GetLengthProperty(cx, obj, lengthp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
+ {
+ CHECK_REQUEST(cx);
+ return js_SetLengthProperty(cx, obj, length);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
+ {
+ CHECK_REQUEST(cx);
+ return js_HasLengthProperty(cx, obj, lengthp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
+ JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
+ {
+ CHECK_REQUEST(cx);
+ return OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(index), value,
+ getter, setter, attrs, NULL);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
+ {
+ JSObject *obj2;
+ JSProperty *prop;
+ JSScopeProperty *sprop;
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ if (!LookupProperty(cx, obj, name, &obj2, &prop))
+ return JS_FALSE;
+ if (!prop) {
+ js_ReportIsNotDefined(cx, name);
+ return JS_FALSE;
+ }
+ if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
+ char numBuf[12];
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
+ numBuf, name, OBJ_GET_CLASS(cx, obj2)->name);
+ return JS_FALSE;
+ }
+ sprop = (JSScopeProperty *)prop;
+ ok = (js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
+ sprop->getter, sprop->setter, sprop->slot,
+ sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
+ sprop->shortid)
+ != NULL);
+ OBJ_DROP_PROPERTY(cx, obj, prop);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
+ {
+ JSBool ok;
+ JSObject *obj2;
+ JSProperty *prop;
+
+ CHECK_REQUEST(cx);
+ ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop);
+ if (ok) {
+ *foundp = (prop != NULL);
+ if (prop)
+ OBJ_DROP_PROPERTY(cx, obj2, prop);
+ }
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
+ {
+ JSBool ok;
+ JSObject *obj2;
+ JSProperty *prop;
+
+ CHECK_REQUEST(cx);
+ ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop);
+ if (ok)
+ *vp = LookupResult(cx, obj, obj2, prop);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
+ {
+ CHECK_REQUEST(cx);
+ return OBJ_GET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
+ {
+ CHECK_REQUEST(cx);
+ return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
+ {
+ jsval junk;
+
+ CHECK_REQUEST(cx);
+ return JS_DeleteElement2(cx, obj, index, &junk);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
+ {
+ CHECK_REQUEST(cx);
+ return OBJ_DELETE_PROPERTY(cx, obj, INT_TO_JSID(index), rval);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_ClearScope(JSContext *cx, JSObject *obj)
+ {
+ CHECK_REQUEST(cx);
+
+ if (obj->map->ops->clear)
+ obj->map->ops->clear(cx, obj);
+ }
+
+ JS_PUBLIC_API(JSIdArray *)
+ JS_Enumerate(JSContext *cx, JSObject *obj)
+ {
+ jsint i, n;
+ jsval iter_state, num_properties;
+ jsid id;
+ JSIdArray *ida;
+ jsval *vector;
+
+ CHECK_REQUEST(cx);
+
+ ida = NULL;
+ iter_state = JSVAL_NULL;
+
+ /* Get the number of properties to enumerate. */
+ if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties))
+ goto error;
+ if (!JSVAL_IS_INT(num_properties)) {
+ JS_ASSERT(0);
+ goto error;
+ }
+
+ /* Grow as needed if we don't know the exact amount ahead of time. */
+ n = JSVAL_TO_INT(num_properties);
+ if (n <= 0)
+ n = 8;
+
+ /* Create an array of jsids large enough to hold all the properties */
+ ida = js_NewIdArray(cx, n);
+ if (!ida)
+ goto error;
+
+ i = 0;
+ vector = &ida->vector[0];
+ for (;;) {
+ if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id))
+ goto error;
+
+ /* No more jsid's to enumerate ? */
+ if (iter_state == JSVAL_NULL)
+ break;
+
+ if (i == ida->length) {
+ ida = js_SetIdArrayLength(cx, ida, ida->length * 2);
+ if (!ida)
+ goto error;
+ vector = &ida->vector[0];
+ }
+ vector[i++] = id;
+ }
+ return js_SetIdArrayLength(cx, ida, i);
+
+ error:
+ if (iter_state != JSVAL_NULL)
+ OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0);
+ if (ida)
+ JS_DestroyIdArray(cx, ida);
+ return NULL;
+ }
+
+ /*
+ * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
+ * prop_iterator_class somehow...
+ * + preserve the OBJ_ENUMERATE API while optimizing the native object case
+ * + native case here uses a JSScopeProperty *, but that iterates in reverse!
+ * + so we make non-native match, by reverse-iterating after JS_Enumerating
+ */
+ #define JSSLOT_ITER_INDEX (JSSLOT_PRIVATE + 1)
+
+ #if JSSLOT_ITER_INDEX >= JS_INITIAL_NSLOTS
+ # error "JSSLOT_ITER_INDEX botch!"
+ #endif
+
+ static void
+ prop_iter_finalize(JSContext *cx, JSObject *obj)
+ {
+ jsval v;
+ jsint i;
+ JSIdArray *ida;
+
+ v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX);
+ if (JSVAL_IS_VOID(v))
+ return;
+
+ i = JSVAL_TO_INT(v);
+ if (i >= 0) {
+ /* Non-native case: destroy the ida enumerated when obj was created. */
+ ida = (JSIdArray *) JS_GetPrivate(cx, obj);
+ if (ida)
+ JS_DestroyIdArray(cx, ida);
+ }
+ }
+
+ static uint32
+ prop_iter_mark(JSContext *cx, JSObject *obj, void *arg)
+ {
+ jsval v;
+ jsint i, n;
+ JSScopeProperty *sprop;
+ JSIdArray *ida;
+ jsid id;
+
+ v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
+ JS_ASSERT(!JSVAL_IS_VOID(v));
+
+ i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX));
+ if (i < 0) {
+ /* Native case: just mark the next property to visit. */
+ sprop = (JSScopeProperty *) JSVAL_TO_PRIVATE(v);
+ if (sprop)
+ MARK_SCOPE_PROPERTY(sprop);
+ } else {
+ /* Non-native case: mark each id in the JSIdArray private. */
+ ida = (JSIdArray *) JSVAL_TO_PRIVATE(v);
+ for (i = 0, n = ida->length; i < n; i++) {
+ id = ida->vector[i];
+ if (JSID_IS_ATOM(id))
+ GC_MARK_ATOM(cx, JSID_TO_ATOM(id), arg);
+ else if (JSID_IS_OBJECT(id))
+ GC_MARK(cx, JSID_TO_OBJECT(id), "id", arg);
+ }
+ }
+ return 0;
+ }
+
+ static JSClass prop_iter_class = {
+ "PropertyIterator",
+ JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1),
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, prop_iter_finalize,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, prop_iter_mark, NULL
+ };
+
+ JS_PUBLIC_API(JSObject *)
+ JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
+ {
+ JSObject *iterobj;
+ JSScope *scope;
+ void *pdata;
+ jsint index;
+ JSIdArray *ida;
+
+ CHECK_REQUEST(cx);
+ iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj);
+ if (!iterobj)
+ return NULL;
+
+ if (OBJ_IS_NATIVE(obj)) {
+ /* Native case: start with the last property in obj's own scope. */
+ scope = OBJ_SCOPE(obj);
+ pdata = (scope->object == obj) ? scope->lastProp : NULL;
+ index = -1;
+ } else {
+ /* Non-native case: enumerate a JSIdArray and keep it via private. */
+ ida = JS_Enumerate(cx, obj);
+ if (!ida)
+ goto bad;
+ pdata = ida;
+ index = ida->length;
+ }
+
+ if (!JS_SetPrivate(cx, iterobj, pdata))
+ goto bad;
+ OBJ_SET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(index));
+ return iterobj;
+
+ bad:
+ cx->newborn[GCX_OBJECT] = NULL;
+ return NULL;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
+ {
+ jsint i;
+ JSObject *obj;
+ JSScope *scope;
+ JSScopeProperty *sprop;
+ JSIdArray *ida;
+
+ CHECK_REQUEST(cx);
+ i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX));
+ if (i < 0) {
+ /* Native case: private data is a property tree node pointer. */
+ obj = OBJ_GET_PARENT(cx, iterobj);
+ JS_ASSERT(OBJ_IS_NATIVE(obj));
+ scope = OBJ_SCOPE(obj);
+ JS_ASSERT(scope->object == obj);
+ sprop = (JSScopeProperty *) JS_GetPrivate(cx, iterobj);
+
+ /*
+ * If the next property mapped by scope in the property tree ancestor
+ * line is not enumerable, or it's an alias, or one or more properties
+ * were deleted from the "middle" of the scope-mapped ancestor line
+ * and the next property was among those deleted, skip it and keep on
+ * trying to find an enumerable property that is still in scope.
+ */
+ while (sprop &&
+ (!(sprop->attrs & JSPROP_ENUMERATE) ||
+ (sprop->flags & SPROP_IS_ALIAS) ||
+ (SCOPE_HAD_MIDDLE_DELETE(scope) &&
+ !SCOPE_HAS_PROPERTY(scope, sprop)))) {
+ sprop = sprop->parent;
+ }
+
+ if (!sprop) {
+ *idp = JSVAL_VOID;
+ } else {
+ if (!JS_SetPrivate(cx, iterobj, sprop->parent))
+ return JS_FALSE;
+ *idp = sprop->id;
+ }
+ } else {
+ /* Non-native case: use the ida enumerated when iterobj was created. */
+ ida = (JSIdArray *) JS_GetPrivate(cx, iterobj);
+ JS_ASSERT(i <= ida->length);
+ if (i == 0) {
+ *idp = JSVAL_VOID;
+ } else {
+ *idp = ida->vector[--i];
+ OBJ_SET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(i));
+ }
+ }
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
+ jsval *vp, uintN *attrsp)
+ {
+ CHECK_REQUEST(cx);
+ return OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, attrsp);
+ }
+
+ JS_PUBLIC_API(JSCheckAccessOp)
+ JS_SetCheckObjectAccessCallback(JSRuntime *rt, JSCheckAccessOp acb)
+ {
+ JSCheckAccessOp oldacb;
+
+ oldacb = rt->checkObjectAccess;
+ rt->checkObjectAccess = acb;
+ return oldacb;
+ }
+
+ static JSBool
+ ReservedSlotIndexOK(JSContext *cx, JSObject *obj, JSClass *clasp,
+ uint32 index, uint32 limit)
+ {
+ /* Check the computed, possibly per-instance, upper bound. */
+ if (clasp->reserveSlots)
+ JS_LOCK_OBJ_VOID(cx, obj, limit += clasp->reserveSlots(cx, obj));
+ if (index >= limit) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_RESERVED_SLOT_RANGE);
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
+ {
+ JSClass *clasp;
+ uint32 limit, slot;
+
+ CHECK_REQUEST(cx);
+ clasp = OBJ_GET_CLASS(cx, obj);
+ limit = JSCLASS_RESERVED_SLOTS(clasp);
+ if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
+ return JS_FALSE;
+ slot = JSSLOT_START(clasp) + index;
+ *vp = OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
+ {
+ JSClass *clasp;
+ uint32 limit, slot;
+
+ CHECK_REQUEST(cx);
+ clasp = OBJ_GET_CLASS(cx, obj);
+ limit = JSCLASS_RESERVED_SLOTS(clasp);
+ if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
+ return JS_FALSE;
+ slot = JSSLOT_START(clasp) + index;
+ return OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
+ }
+
+ #ifdef JS_THREADSAFE
+ JS_PUBLIC_API(jsrefcount)
+ JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
+ {
+ return JS_ATOMIC_INCREMENT(&principals->refcount);
+ }
+
+ JS_PUBLIC_API(jsrefcount)
+ JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
+ {
+ jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
+ if (rc == 0)
+ principals->destroy(cx, principals);
+ return rc;
+ }
+ #endif
+
+ JS_PUBLIC_API(JSPrincipalsTranscoder)
+ JS_SetPrincipalsTranscoder(JSRuntime *rt, JSPrincipalsTranscoder px)
+ {
+ JSPrincipalsTranscoder oldpx;
+
+ oldpx = rt->principalsTranscoder;
+ rt->principalsTranscoder = px;
+ return oldpx;
+ }
+
+ JS_PUBLIC_API(JSObjectPrincipalsFinder)
+ JS_SetObjectPrincipalsFinder(JSRuntime *rt, JSObjectPrincipalsFinder fop)
+ {
+ JSObjectPrincipalsFinder oldfop;
+
+ oldfop = rt->findObjectPrincipals;
+ rt->findObjectPrincipals = fop;
+ return oldfop;
+ }
+
+ JS_PUBLIC_API(JSFunction *)
+ JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
+ JSObject *parent, const char *name)
+ {
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+
+ if (!name) {
+ atom = NULL;
+ } else {
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return NULL;
+ }
+ return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom);
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
+ {
+ CHECK_REQUEST(cx);
+ if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) {
+ /* Indicate we cannot clone this object. */
+ return funobj;
+ }
+ return js_CloneFunctionObject(cx, funobj, parent);
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_GetFunctionObject(JSFunction *fun)
+ {
+ return fun->object;
+ }
+
+ JS_PUBLIC_API(const char *)
+ JS_GetFunctionName(JSFunction *fun)
+ {
+ return fun->atom
+ ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
+ : js_anonymous_str;
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_GetFunctionId(JSFunction *fun)
+ {
+ return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
+ }
+
+ JS_PUBLIC_API(uintN)
+ JS_GetFunctionFlags(JSFunction *fun)
+ {
+ return fun->flags;
+ }
+
+ JS_PUBLIC_API(uint16)
+ JS_GetFunctionArity(JSFunction *fun)
+ {
+ return fun->nargs;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
+ {
+ return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass;
+ }
+
+ JS_STATIC_DLL_CALLBACK(JSBool)
+ js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
+ uintN argc, jsval *argv, jsval *rval)
+ {
+ jsval fsv;
+ JSFunctionSpec *fs;
+ JSObject *tmp;
+
+ if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv))
+ return JS_FALSE;
+ fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
+
+ /*
+ * We know that argv[0] is valid because JS_DefineFunctions, which is our
+ * only (indirect) referrer, defined us as requiring at least one argument
+ * (notice how it passes fs->nargs + 1 as the next-to-last argument to
+ * JS_DefineFunction).
+ */
+ if (JSVAL_IS_PRIMITIVE(argv[0])) {
+ /*
+ * Make sure that this is an object or null, as required by the generic
+ * functions.
+ */
+ if (!js_ValueToObject(cx, argv[0], &tmp))
+ return JS_FALSE;
+ argv[0] = OBJECT_TO_JSVAL(tmp);
+ }
+
+ /*
+ * Copy all actual (argc) and required but missing (fs->nargs + 1 - argc)
+ * args down over our |this| parameter, argv[-1], which is almost always
+ * the class constructor object, e.g. Array. Then call the corresponding
+ * prototype native method with our first argument passed as |this|.
+ */
+ memmove(argv - 1, argv, JS_MAX(fs->nargs + 1U, argc) * sizeof(jsval));
+
+ /*
+ * Follow Function.prototype.apply and .call by using the global object as
+ * the 'this' param if no args.
+ */
+ JS_ASSERT(cx->fp->argv == argv);
+ if (!js_ComputeThis(cx, JSVAL_TO_OBJECT(argv[-1]), cx->fp))
+ return JS_FALSE;
+
+ /*
+ * Protect against argc - 1 underflowing below. By calling js_ComputeThis,
+ * we made it as if the static was called with one parameter.
+ */
+ if (argc == 0)
+ argc = 1;
+
+ return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc - 1, argv, rval);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
+ {
+ uintN flags;
+ JSObject *ctor;
+ JSFunction *fun;
+
+ CHECK_REQUEST(cx);
+ ctor = NULL;
+ for (; fs->name; fs++) {
+ flags = fs->flags;
+
+ /*
+ * Define a generic arity N+1 static method for the arity N prototype
+ * method if flags contains JSFUN_GENERIC_NATIVE.
+ */
+ if (flags & JSFUN_GENERIC_NATIVE) {
+ if (!ctor) {
+ ctor = JS_GetConstructor(cx, obj);
+ if (!ctor)
+ return JS_FALSE;
+ }
+
+ flags &= ~JSFUN_GENERIC_NATIVE;
+ fun = JS_DefineFunction(cx, ctor, fs->name,
+ js_generic_native_method_dispatcher,
+ fs->nargs + 1, flags);
+ if (!fun)
+ return JS_FALSE;
+ fun->extra = fs->extra;
+
+ /*
+ * As jsapi.h notes, fs must point to storage that lives as long
+ * as fun->object lives.
+ */
+ if (!JS_SetReservedSlot(cx, fun->object, 0, PRIVATE_TO_JSVAL(fs)))
+ return JS_FALSE;
+ }
+
+ fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
+ if (!fun)
+ return JS_FALSE;
+ fun->extra = fs->extra;
+ }
+ return JS_TRUE;
+ }
+
+ JS_PUBLIC_API(JSFunction *)
+ JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
+ uintN nargs, uintN attrs)
+ {
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return NULL;
+ return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
+ }
+
+ JS_PUBLIC_API(JSFunction *)
+ JS_DefineUCFunction(JSContext *cx, JSObject *obj,
+ const jschar *name, size_t namelen, JSNative call,
+ uintN nargs, uintN attrs)
+ {
+ JSAtom *atom;
+
+ atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
+ if (!atom)
+ return NULL;
+ return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
+ }
+
+ static JSScript *
+ CompileTokenStream(JSContext *cx, JSObject *obj, JSTokenStream *ts,
+ void *tempMark, JSBool *eofp)
+ {
+ JSBool eof;
+ JSArenaPool codePool, notePool;
+ JSCodeGenerator cg;
+ JSScript *script;
+
+ CHECK_REQUEST(cx);
+ eof = JS_FALSE;
+ JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode));
+ JS_InitArenaPool(¬ePool, "note", 1024, sizeof(jssrcnote));
+ if (!js_InitCodeGenerator(cx, &cg, &codePool, ¬ePool,
+ ts->filename, ts->lineno,
+ ts->principals)) {
+ script = NULL;
+ } else if (!js_CompileTokenStream(cx, obj, ts, &cg)) {
+ script = NULL;
+ eof = (ts->flags & TSF_EOF) != 0;
+ } else {
+ script = js_NewScriptFromCG(cx, &cg, NULL);
+ }
+ if (eofp)
+ *eofp = eof;
+ if (!js_CloseTokenStream(cx, ts)) {
+ if (script)
+ js_DestroyScript(cx, script);
+ script = NULL;
+ }
+ cg.tempMark = tempMark;
+ js_FinishCodeGenerator(cx, &cg);
+ JS_FinishArenaPool(&codePool);
+ JS_FinishArenaPool(¬ePool);
+ return script;
+ }
+
+ JS_PUBLIC_API(JSScript *)
+ JS_CompileScript(JSContext *cx, JSObject *obj,
+ const char *bytes, size_t length,
+ const char *filename, uintN lineno)
+ {
+ jschar *chars;
+ JSScript *script;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+ script = JS_CompileUCScript(cx, obj, chars, length, filename, lineno);
+ JS_free(cx, chars);
+ return script;
+ }
+
+ JS_PUBLIC_API(JSScript *)
+ JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals,
+ const char *bytes, size_t length,
+ const char *filename, uintN lineno)
+ {
+ jschar *chars;
+ JSScript *script;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+ script = JS_CompileUCScriptForPrincipals(cx, obj, principals,
+ chars, length, filename, lineno);
+ JS_free(cx, chars);
+ return script;
+ }
+
+ JS_PUBLIC_API(JSScript *)
+ JS_CompileUCScript(JSContext *cx, JSObject *obj,
+ const jschar *chars, size_t length,
+ const char *filename, uintN lineno)
+ {
+ CHECK_REQUEST(cx);
+ return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length,
+ filename, lineno);
+ }
+
+ #if JS_HAS_EXCEPTIONS
+ # define LAST_FRAME_EXCEPTION_CHECK(cx,result) \
+ JS_BEGIN_MACRO \
+ if (!(result)) \
+ js_ReportUncaughtException(cx); \
+ JS_END_MACRO
+ #else
+ # define LAST_FRAME_EXCEPTION_CHECK(cx,result) /* nothing */
+ #endif
+
+ #define LAST_FRAME_CHECKS(cx,result) \
+ JS_BEGIN_MACRO \
+ if (!(cx)->fp) { \
+ (cx)->lastInternalResult = JSVAL_NULL; \
+ LAST_FRAME_EXCEPTION_CHECK(cx, result); \
+ } \
+ JS_END_MACRO
+
+ JS_PUBLIC_API(JSScript *)
+ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals,
+ const jschar *chars, size_t length,
+ const char *filename, uintN lineno)
+ {
+ void *mark;
+ JSTokenStream *ts;
+ JSScript *script;
+
+ CHECK_REQUEST(cx);
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
+ if (!ts)
+ return NULL;
+ script = CompileTokenStream(cx, obj, ts, mark, NULL);
+ LAST_FRAME_CHECKS(cx, script);
+ return script;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
+ const char *bytes, size_t length)
+ {
+ jschar *chars;
+ JSBool result;
+ JSExceptionState *exnState;
+ void *tempMark;
+ JSTokenStream *ts;
+ JSErrorReporter older;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return JS_TRUE;
+
+ /*
+ * Return true on any out-of-memory error, so our caller doesn't try to
+ * collect more buffered source.
+ */
+ result = JS_TRUE;
+ exnState = JS_SaveExceptionState(cx);
+ tempMark = JS_ARENA_MARK(&cx->tempPool);
+ ts = js_NewTokenStream(cx, chars, length, NULL, 0, NULL);
+ if (ts) {
+ older = JS_SetErrorReporter(cx, NULL);
+ if (!js_ParseTokenStream(cx, obj, ts) &&
+ (ts->flags & TSF_UNEXPECTED_EOF)) {
+ /*
+ * We ran into an error. If it was because we ran out of source,
+ * we return false, so our caller will know to try to collect more
+ * buffered source.
+ */
+ result = JS_FALSE;
+ }
+
+ JS_SetErrorReporter(cx, older);
+ js_CloseTokenStream(cx, ts);
+ JS_ARENA_RELEASE(&cx->tempPool, tempMark);
+ }
+
+ JS_free(cx, chars);
+ JS_RestoreExceptionState(cx, exnState);
+ return result;
+ }
+
+ JS_PUBLIC_API(JSScript *)
+ JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
+ {
+ void *mark;
+ JSTokenStream *ts;
+ JSScript *script;
+
+ CHECK_REQUEST(cx);
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ ts = js_NewFileTokenStream(cx, filename, stdin);
+ if (!ts)
+ return NULL;
+ script = CompileTokenStream(cx, obj, ts, mark, NULL);
+ LAST_FRAME_CHECKS(cx, script);
+ return script;
+ }
+
+ JS_PUBLIC_API(JSScript *)
+ JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename,
+ FILE *file)
+ {
+ return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
+ }
+
+ JS_PUBLIC_API(JSScript *)
+ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
+ const char *filename, FILE *file,
+ JSPrincipals *principals)
+ {
+ void *mark;
+ JSTokenStream *ts;
+ JSScript *script;
+
+ CHECK_REQUEST(cx);
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ ts = js_NewFileTokenStream(cx, NULL, file);
+ if (!ts)
+ return NULL;
+ ts->filename = filename;
+ /* XXXshaver js_NewFileTokenStream should do this, because it drops */
+ if (principals) {
+ ts->principals = principals;
+ JSPRINCIPALS_HOLD(cx, ts->principals);
+ }
+ script = CompileTokenStream(cx, obj, ts, mark, NULL);
+ LAST_FRAME_CHECKS(cx, script);
+ return script;
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_NewScriptObject(JSContext *cx, JSScript *script)
+ {
+ JSObject *obj;
+
+ obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
+ if (!obj)
+ return NULL;
+
+ if (script) {
+ if (!JS_SetPrivate(cx, obj, script))
+ return NULL;
+ script->object = obj;
+ }
+ return obj;
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_GetScriptObject(JSScript *script)
+ {
+ return script->object;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_DestroyScript(JSContext *cx, JSScript *script)
+ {
+ CHECK_REQUEST(cx);
+ js_DestroyScript(cx, script);
+ }
+
+ JS_PUBLIC_API(JSFunction *)
+ JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
+ uintN nargs, const char **argnames,
+ const char *bytes, size_t length,
+ const char *filename, uintN lineno)
+ {
+ jschar *chars;
+ JSFunction *fun;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+ fun = JS_CompileUCFunction(cx, obj, name, nargs, argnames, chars, length,
+ filename, lineno);
+ JS_free(cx, chars);
+ return fun;
+ }
+
+ JS_PUBLIC_API(JSFunction *)
+ JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals, const char *name,
+ uintN nargs, const char **argnames,
+ const char *bytes, size_t length,
+ const char *filename, uintN lineno)
+ {
+ jschar *chars;
+ JSFunction *fun;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+ fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
+ nargs, argnames, chars, length,
+ filename, lineno);
+ JS_free(cx, chars);
+ return fun;
+ }
+
+ JS_PUBLIC_API(JSFunction *)
+ JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
+ uintN nargs, const char **argnames,
+ const jschar *chars, size_t length,
+ const char *filename, uintN lineno)
+ {
+ CHECK_REQUEST(cx);
+ return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name,
+ nargs, argnames,
+ chars, length,
+ filename, lineno);
+ }
+
+ JS_PUBLIC_API(JSFunction *)
+ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals, const char *name,
+ uintN nargs, const char **argnames,
+ const jschar *chars, size_t length,
+ const char *filename, uintN lineno)
+ {
+ void *mark;
+ JSTokenStream *ts;
+ JSFunction *fun;
+ JSAtom *funAtom, *argAtom;
+ uintN i;
+
+ CHECK_REQUEST(cx);
+ mark = JS_ARENA_MARK(&cx->tempPool);
+ ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
+ if (!ts) {
+ fun = NULL;
+ goto out;
+ }
+ if (!name) {
+ funAtom = NULL;
+ } else {
+ funAtom = js_Atomize(cx, name, strlen(name), 0);
+ if (!funAtom) {
+ fun = NULL;
+ goto out;
+ }
+ }
+ fun = js_NewFunction(cx, NULL, NULL, nargs, 0, obj, funAtom);
+ if (!fun)
+ goto out;
+ if (nargs) {
+ for (i = 0; i < nargs; i++) {
+ argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
+ if (!argAtom)
+ break;
+ if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom),
+ js_GetArgument, js_SetArgument,
+ SPROP_INVALID_SLOT,
+ JSPROP_PERMANENT | JSPROP_SHARED,
+ SPROP_HAS_SHORTID, i)) {
+ break;
+ }
+ }
+ if (i < nargs) {
+ fun = NULL;
+ goto out;
+ }
+ }
+ if (!js_CompileFunctionBody(cx, ts, fun)) {
+ fun = NULL;
+ goto out;
+ }
+ if (obj && funAtom) {
+ if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(funAtom),
+ OBJECT_TO_JSVAL(fun->object),
+ NULL, NULL, JSPROP_ENUMERATE, NULL)) {
+ return NULL;
+ }
+ }
+ out:
+ if (ts)
+ js_CloseTokenStream(cx, ts);
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
+ LAST_FRAME_CHECKS(cx, fun);
+ return fun;
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
+ uintN indent)
+ {
+ JSPrinter *jp;
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ jp = js_NewPrinter(cx, name,
+ indent & ~JS_DONT_PRETTY_PRINT,
+ !(indent & JS_DONT_PRETTY_PRINT));
+ if (!jp)
+ return NULL;
+ if (js_DecompileScript(jp, script))
+ str = js_GetPrinterOutput(jp);
+ else
+ str = NULL;
+ js_DestroyPrinter(jp);
+ return str;
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
+ {
+ JSPrinter *jp;
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
+ indent & ~JS_DONT_PRETTY_PRINT,
+ !(indent & JS_DONT_PRETTY_PRINT));
+ if (!jp)
+ return NULL;
+ if (js_DecompileFunction(jp, fun))
+ str = js_GetPrinterOutput(jp);
+ else
+ str = NULL;
+ js_DestroyPrinter(jp);
+ return str;
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
+ {
+ JSPrinter *jp;
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
+ indent & ~JS_DONT_PRETTY_PRINT,
+ !(indent & JS_DONT_PRETTY_PRINT));
+ if (!jp)
+ return NULL;
+ if (js_DecompileFunctionBody(jp, fun))
+ str = js_GetPrinterOutput(jp);
+ else
+ str = NULL;
+ js_DestroyPrinter(jp);
+ return str;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
+ {
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ ok = js_Execute(cx, obj, script, NULL, 0, rval);
+ LAST_FRAME_CHECKS(cx, ok);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script,
+ JSExecPart part, jsval *rval)
+ {
+ JSScript tmp;
+ JSRuntime *rt;
+ JSBool ok;
+
+ /* Make a temporary copy of the JSScript structure and farble it a bit. */
+ tmp = *script;
+ if (part == JSEXEC_PROLOG) {
+ tmp.length = PTRDIFF(tmp.main, tmp.code, jsbytecode);
+ } else {
+ tmp.length -= PTRDIFF(tmp.main, tmp.code, jsbytecode);
+ tmp.code = tmp.main;
+ }
+
+ /* Tell the debugger about our temporary copy of the script structure. */
+ rt = cx->runtime;
+ if (rt->newScriptHook) {
+ rt->newScriptHook(cx, tmp.filename, tmp.lineno, &tmp, NULL,
+ rt->newScriptHookData);
+ }
+
+ /* Execute the farbled struct and tell the debugger to forget about it. */
+ ok = JS_ExecuteScript(cx, obj, &tmp, rval);
+ if (rt->destroyScriptHook)
+ rt->destroyScriptHook(cx, &tmp, rt->destroyScriptHookData);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_EvaluateScript(JSContext *cx, JSObject *obj,
+ const char *bytes, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval)
+ {
+ jschar *chars;
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return JS_FALSE;
+ ok = JS_EvaluateUCScript(cx, obj, chars, length, filename, lineno, rval);
+ JS_free(cx, chars);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals,
+ const char *bytes, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval)
+ {
+ jschar *chars;
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return JS_FALSE;
+ ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
+ filename, lineno, rval);
+ JS_free(cx, chars);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_EvaluateUCScript(JSContext *cx, JSObject *obj,
+ const jschar *chars, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval)
+ {
+ CHECK_REQUEST(cx);
+ return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length,
+ filename, lineno, rval);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
+ JSPrincipals *principals,
+ const jschar *chars, uintN length,
+ const char *filename, uintN lineno,
+ jsval *rval)
+ {
+ uint32 options;
+ JSScript *script;
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ options = cx->options;
+ cx->options = options | JSOPTION_COMPILE_N_GO;
+ script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length,
+ filename, lineno);
+ cx->options = options;
+ if (!script)
+ return JS_FALSE;
+ ok = js_Execute(cx, obj, script, NULL, 0, rval);
+ LAST_FRAME_CHECKS(cx, ok);
+ JS_DestroyScript(cx, script);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
+ jsval *argv, jsval *rval)
+ {
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(fun->object), argc, argv,
+ rval);
+ LAST_FRAME_CHECKS(cx, ok);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
+ jsval *argv, jsval *rval)
+ {
+ JSBool ok;
+ jsval fval;
+
+ CHECK_REQUEST(cx);
+ #if JS_HAS_XML_SUPPORT
+ if (OBJECT_IS_XML(cx, obj)) {
+ JSXMLObjectOps *ops;
+ JSAtom *atom;
+
+ ops = (JSXMLObjectOps *) obj->map->ops;
+ atom = js_Atomize(cx, name, strlen(name), 0);
+ if (!atom)
+ return JS_FALSE;
+ obj = ops->getMethod(cx, obj, ATOM_TO_JSID(atom), &fval);
+ if (!obj)
+ return JS_FALSE;
+ } else
+ #endif
+ if (!JS_GetProperty(cx, obj, name, &fval))
+ return JS_FALSE;
+ ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
+ LAST_FRAME_CHECKS(cx, ok);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
+ jsval *argv, jsval *rval)
+ {
+ JSBool ok;
+
+ CHECK_REQUEST(cx);
+ ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
+ LAST_FRAME_CHECKS(cx, ok);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBranchCallback)
+ JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb)
+ {
+ JSBranchCallback oldcb;
+
+ oldcb = cx->branchCallback;
+ cx->branchCallback = cb;
+ return oldcb;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_IsRunning(JSContext *cx)
+ {
+ return cx->fp != NULL;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_IsConstructing(JSContext *cx)
+ {
+ return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING);
+ }
+
+ JS_FRIEND_API(JSBool)
+ JS_IsAssigning(JSContext *cx)
+ {
+ JSStackFrame *fp;
+ jsbytecode *pc;
+
+ for (fp = cx->fp; fp && !fp->script; fp = fp->down)
+ continue;
+ if (!fp || !(pc = fp->pc))
+ return JS_FALSE;
+ return (js_CodeSpec[*pc].format & JOF_ASSIGNING) != 0;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_SetCallReturnValue2(JSContext *cx, jsval v)
+ {
+ #if JS_HAS_LVALUE_RETURN
+ cx->rval2 = v;
+ cx->rval2set = JS_TRUE;
+ #endif
+ }
+
+ /************************************************************************/
+
+ JS_PUBLIC_API(JSString *)
+ JS_NewString(JSContext *cx, char *bytes, size_t length)
+ {
+ jschar *chars;
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ /* Make a Unicode vector from the 8-bit char codes in bytes. */
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+
+ /* Free chars (but not bytes, which caller frees on error) if we fail. */
+ str = js_NewString(cx, chars, length, 0);
+ if (!str) {
+ JS_free(cx, chars);
+ return NULL;
+ }
+
+ /* Hand off bytes to the deflated string cache, if possible. */
+ if (!js_SetStringBytes(str, bytes, length))
+ JS_free(cx, bytes);
+ return str;
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
+ {
+ jschar *js;
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ js = js_InflateString(cx, s, n);
+ if (!js)
+ return NULL;
+ str = js_NewString(cx, js, n, 0);
+ if (!str)
+ JS_free(cx, js);
+ return str;
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_NewStringCopyZ(JSContext *cx, const char *s)
+ {
+ size_t n;
+ jschar *js;
+ JSString *str;
+
+ CHECK_REQUEST(cx);
+ if (!s)
+ return cx->runtime->emptyString;
+ n = strlen(s);
+ js = js_InflateString(cx, s, n);
+ if (!js)
+ return NULL;
+ str = js_NewString(cx, js, n, 0);
+ if (!str)
+ JS_free(cx, js);
+ return str;
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_InternString(JSContext *cx, const char *s)
+ {
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
+ if (!atom)
+ return NULL;
+ return ATOM_TO_STRING(atom);
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
+ {
+ CHECK_REQUEST(cx);
+ return js_NewString(cx, chars, length, 0);
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
+ {
+ CHECK_REQUEST(cx);
+ return js_NewStringCopyN(cx, s, n, 0);
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
+ {
+ CHECK_REQUEST(cx);
+ if (!s)
+ return cx->runtime->emptyString;
+ return js_NewStringCopyZ(cx, s, 0);
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
+ {
+ JSAtom *atom;
+
+ CHECK_REQUEST(cx);
+ atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
+ if (!atom)
+ return NULL;
+ return ATOM_TO_STRING(atom);
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_InternUCString(JSContext *cx, const jschar *s)
+ {
+ return JS_InternUCStringN(cx, s, js_strlen(s));
+ }
+
+ JS_PUBLIC_API(char *)
+ JS_GetStringBytes(JSString *str)
+ {
+ char *bytes;
+
+ bytes = js_GetStringBytes(str);
+ return bytes ? bytes : "";
+ }
+
+ JS_PUBLIC_API(jschar *)
+ JS_GetStringChars(JSString *str)
+ {
+ /*
+ * API botch (again, shades of JS_GetStringBytes): we have no cx to pass
+ * to js_UndependString (called by js_GetStringChars) for out-of-memory
+ * error reports, so js_UndependString passes NULL and suppresses errors.
+ * If it fails to convert a dependent string into an independent one, our
+ * caller will not be guaranteed a \u0000 terminator as a backstop. This
+ * may break some clients who already misbehave on embedded NULs.
+ *
+ * The gain of dependent strings, which cure quadratic and cubic growth
+ * rate bugs in string concatenation, is worth this slight loss in API
+ * compatibility.
+ */
+ jschar *chars;
+
+ chars = js_GetStringChars(str);
+ return chars ? chars : JSSTRING_CHARS(str);
+ }
+
+ JS_PUBLIC_API(size_t)
+ JS_GetStringLength(JSString *str)
+ {
+ return JSSTRING_LENGTH(str);
+ }
+
+ JS_PUBLIC_API(intN)
+ JS_CompareStrings(JSString *str1, JSString *str2)
+ {
+ return js_CompareStrings(str1, str2);
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
+ {
+ CHECK_REQUEST(cx);
+ return js_NewString(cx, chars, length, GCF_MUTABLE);
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
+ size_t length)
+ {
+ CHECK_REQUEST(cx);
+ return js_NewDependentString(cx, str, start, length, 0);
+ }
+
+ JS_PUBLIC_API(JSString *)
+ JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
+ {
+ CHECK_REQUEST(cx);
+ return js_ConcatStrings(cx, left, right);
+ }
+
+ JS_PUBLIC_API(const jschar *)
+ JS_UndependString(JSContext *cx, JSString *str)
+ {
+ CHECK_REQUEST(cx);
+ return js_UndependString(cx, str);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_MakeStringImmutable(JSContext *cx, JSString *str)
+ {
+ CHECK_REQUEST(cx);
+ if (!js_UndependString(cx, str))
+ return JS_FALSE;
+
+ *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
+ return JS_TRUE;
+ }
+
+ /************************************************************************/
+
+ JS_PUBLIC_API(void)
+ JS_ReportError(JSContext *cx, const char *format, ...)
+ {
+ va_list ap;
+
+ va_start(ap, format);
+ js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
+ va_end(ap);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
+ void *userRef, const uintN errorNumber, ...)
+ {
+ va_list ap;
+
+ va_start(ap, errorNumber);
+ js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
+ errorNumber, JS_TRUE, ap);
+ va_end(ap);
+ }
+
+ JS_PUBLIC_API(void)
+ JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
+ void *userRef, const uintN errorNumber, ...)
+ {
+ va_list ap;
+
+ va_start(ap, errorNumber);
+ js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
+ errorNumber, JS_FALSE, ap);
+ va_end(ap);
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ReportWarning(JSContext *cx, const char *format, ...)
+ {
+ va_list ap;
+ JSBool ok;
+
+ va_start(ap, format);
+ ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
+ va_end(ap);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
+ JSErrorCallback errorCallback, void *userRef,
+ const uintN errorNumber, ...)
+ {
+ va_list ap;
+ JSBool ok;
+
+ va_start(ap, errorNumber);
+ ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
+ errorNumber, JS_TRUE, ap);
+ va_end(ap);
+ return ok;
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
+ JSErrorCallback errorCallback, void *userRef,
+ const uintN errorNumber, ...)
+ {
+ va_list ap;
+ JSBool ok;
+
+ va_start(ap, errorNumber);
+ ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
+ errorNumber, JS_FALSE, ap);
+ va_end(ap);
+ return ok;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_ReportOutOfMemory(JSContext *cx)
+ {
+ js_ReportOutOfMemory(cx, js_GetErrorMessage);
+ }
+
+ JS_PUBLIC_API(JSErrorReporter)
+ JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
+ {
+ JSErrorReporter older;
+
+ older = cx->errorReporter;
+ cx->errorReporter = er;
+ return older;
+ }
+
+ /************************************************************************/
+
+ /*
+ * Regular Expressions.
+ */
+ JS_PUBLIC_API(JSObject *)
+ JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags)
+ {
+ #if JS_HAS_REGEXPS
+ jschar *chars;
+ JSObject *obj;
+
+ CHECK_REQUEST(cx);
+ chars = js_InflateString(cx, bytes, length);
+ if (!chars)
+ return NULL;
+ obj = js_NewRegExpObject(cx, NULL, chars, length, flags);
+ JS_free(cx, chars);
+ return obj;
+ #else
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_REG_EXPS);
+ return NULL;
+ #endif
+ }
+
+ JS_PUBLIC_API(JSObject *)
+ JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags)
+ {
+ CHECK_REQUEST(cx);
+ #if JS_HAS_REGEXPS
+ return js_NewRegExpObject(cx, NULL, chars, length, flags);
+ #else
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_REG_EXPS);
+ return NULL;
+ #endif
+ }
+
+ JS_PUBLIC_API(void)
+ JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline)
+ {
+ JSRegExpStatics *res;
+
+ CHECK_REQUEST(cx);
+ /* No locking required, cx is thread-private and input must be live. */
+ res = &cx->regExpStatics;
+ res->input = input;
+ res->multiline = multiline;
+ cx->runtime->gcPoke = JS_TRUE;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_ClearRegExpStatics(JSContext *cx)
+ {
+ JSRegExpStatics *res;
+
+ /* No locking required, cx is thread-private and input must be live. */
+ res = &cx->regExpStatics;
+ res->input = NULL;
+ res->multiline = JS_FALSE;
+ res->parenCount = 0;
+ res->lastMatch = res->lastParen = js_EmptySubString;
+ res->leftContext = res->rightContext = js_EmptySubString;
+ cx->runtime->gcPoke = JS_TRUE;
+ }
+
+ JS_PUBLIC_API(void)
+ JS_ClearRegExpRoots(JSContext *cx)
+ {
+ JSRegExpStatics *res;
+
+ /* No locking required, cx is thread-private and input must be live. */
+ res = &cx->regExpStatics;
+ res->input = NULL;
+ cx->runtime->gcPoke = JS_TRUE;
+ }
+
+ /* TODO: compile, execute, get/set other statics... */
+
+ /************************************************************************/
+
+ JS_PUBLIC_API(void)
+ JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
+ {
+ cx->localeCallbacks = callbacks;
+ }
+
+ JS_PUBLIC_API(JSLocaleCallbacks *)
+ JS_GetLocaleCallbacks(JSContext *cx)
+ {
+ return cx->localeCallbacks;
+ }
+
+ /************************************************************************/
+
+ JS_PUBLIC_API(JSBool)
+ JS_IsExceptionPending(JSContext *cx)
+ {
+ #if JS_HAS_EXCEPTIONS
+ return (JSBool) cx->throwing;
+ #else
+ return JS_FALSE;
+ #endif
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_GetPendingException(JSContext *cx, jsval *vp)
+ {
+ #if JS_HAS_EXCEPTIONS
+ CHECK_REQUEST(cx);
+ if (!cx->throwing)
+ return JS_FALSE;
+ *vp = cx->exception;
+ return JS_TRUE;
+ #else
+ return JS_FALSE;
+ #endif
+ }
+
+ JS_PUBLIC_API(void)
+ JS_SetPendingException(JSContext *cx, jsval v)
+ {
+ CHECK_REQUEST(cx);
+ #if JS_HAS_EXCEPTIONS
+ cx->throwing = JS_TRUE;
+ cx->exception = v;
+ #endif
+ }
+
+ JS_PUBLIC_API(void)
+ JS_ClearPendingException(JSContext *cx)
+ {
+ #if JS_HAS_EXCEPTIONS
+ cx->throwing = JS_FALSE;
+ cx->exception = JSVAL_VOID;
+ #endif
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ReportPendingException(JSContext *cx)
+ {
+ #if JS_HAS_EXCEPTIONS
+ JSBool save, ok;
+
+ CHECK_REQUEST(cx);
+
+ /*
+ * Set cx->creatingException to suppress the standard error-to-exception
+ * conversion done by all {js,JS}_Report* functions except for OOM. The
+ * cx->creatingException flag was added to suppress recursive divergence
+ * under js_ErrorToException, but it serves for our purposes here too.
+ */
+ save = cx->creatingException;
+ cx->creatingException = JS_TRUE;
+ ok = js_ReportUncaughtException(cx);
+ cx->creatingException = save;
+ return ok;
+ #else
+ return JS_TRUE;
+ #endif
+ }
+
+ #if JS_HAS_EXCEPTIONS
+ struct JSExceptionState {
+ JSBool throwing;
+ jsval exception;
+ };
+ #endif
+
+ JS_PUBLIC_API(JSExceptionState *)
+ JS_SaveExceptionState(JSContext *cx)
+ {
+ #if JS_HAS_EXCEPTIONS
+ JSExceptionState *state;
+
+ CHECK_REQUEST(cx);
+ state = (JSExceptionState *) JS_malloc(cx, sizeof(JSExceptionState));
+ if (state) {
+ state->throwing = JS_GetPendingException(cx, &state->exception);
+ if (state->throwing && JSVAL_IS_GCTHING(state->exception))
+ js_AddRoot(cx, &state->exception, "JSExceptionState.exception");
+ }
+ return state;
+ #else
+ return NULL;
+ #endif
+ }
+
+ JS_PUBLIC_API(void)
+ JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
+ {
+ #if JS_HAS_EXCEPTIONS
+ CHECK_REQUEST(cx);
+ if (state) {
+ if (state->throwing)
+ JS_SetPendingException(cx, state->exception);
+ else
+ JS_ClearPendingException(cx);
+ JS_DropExceptionState(cx, state);
+ }
+ #endif
+ }
+
+ JS_PUBLIC_API(void)
+ JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
+ {
+ #if JS_HAS_EXCEPTIONS
+ CHECK_REQUEST(cx);
+ if (state) {
+ if (state->throwing && JSVAL_IS_GCTHING(state->exception))
+ JS_RemoveRoot(cx, &state->exception);
+ JS_free(cx, state);
+ }
+ #endif
+ }
+
+ JS_PUBLIC_API(JSErrorReport *)
+ JS_ErrorFromException(JSContext *cx, jsval v)
+ {
+ #if JS_HAS_ERROR_EXCEPTIONS
+ CHECK_REQUEST(cx);
+ return js_ErrorFromException(cx, v);
+ #else
+ return NULL;
+ #endif
+ }
+
+ JS_PUBLIC_API(JSBool)
+ JS_ThrowReportedError(JSContext *cx, const char *message,
+ JSErrorReport *reportp)
+ {
+ return js_ErrorToException(cx, message, reportp);
+ }
+
+ #ifdef JS_THREADSAFE
+ JS_PUBLIC_API(jsword)
+ JS_GetContextThread(JSContext *cx)
+ {
+ return cx->thread;
+ }
+
+ JS_PUBLIC_API(jsword)
+ JS_SetContextThread(JSContext *cx)
+ {
+ jsword old = cx->thread;
+ cx->thread = js_CurrentThreadId();
+ return old;
+ }
+
+ JS_PUBLIC_API(jsword)
+ JS_ClearContextThread(JSContext *cx)
+ {
+ jsword old = cx->thread;
+ cx->thread = 0;
+ return old;
+ }
+ #endif
+
+ /************************************************************************/
+
+ #if defined(XP_WIN)
+ #include <windows.h>
+ /*
+ * Initialization routine for the JS DLL...
+ */
+
+ /*
+ * Global Instance handle...
+ * In Win32 this is the module handle of the DLL.
+ *
+ * In Win16 this is the instance handle of the application
+ * which loaded the DLL.
+ */
+
+ #ifdef _WIN32
+ BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
+ {
+ return TRUE;
+ }
+
+ #else /* !_WIN32 */
+
+ int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg,
+ WORD cbHeapSize, LPSTR lpszCmdLine )
+ {
+ return TRUE;
+ }
+
+ BOOL CALLBACK __loadds WEP(BOOL fSystemExit)
+ {
+ return TRUE;
+ }
+
+ #endif /* !_WIN32 */
+ #endif /* XP_WIN */
|