diff options
| author | MenTaLguY <mental@rydia.net> | 2006-01-16 02:36:01 +0000 |
|---|---|---|
| committer | mental <mental@users.sourceforge.net> | 2006-01-16 02:36:01 +0000 |
| commit | 179fa413b047bede6e32109e2ce82437c5fb8d34 (patch) | |
| tree | a5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/extension/script/js/jsapi.c | |
| download | inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip | |
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/extension/script/js/jsapi.c')
| -rw-r--r-- | src/extension/script/js/jsapi.c | 4187 |
1 files changed, 4187 insertions, 0 deletions
diff --git a/src/extension/script/js/jsapi.c b/src/extension/script/js/jsapi.c new file mode 100644 index 000000000..faf02d983 --- /dev/null +++ b/src/extension/script/js/jsapi.c @@ -0,0 +1,4187 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 + +#ifdef HAVE_VA_LIST_AS_ARRAY +#define JS_ADDRESSOF_VA_LIST(ap) (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, + jsval **vpp, va_list *app) +{ + 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': + fun = js_ValueToFunction(cx, sp, 0); + if (!fun) + return JS_FALSE; + *sp = OBJECT_TO_JSVAL(fun->object); + *va_arg(ap, JSFunction **) = fun; + break; + case 'v': + *va_arg(ap, jsval *) = *sp; + break; + case '*': + break; + default: + format--; + if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp, + JS_ADDRESSOF_VA_LIST(ap))) { + 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, + JS_ADDRESSOF_VA_LIST(ap))) { + 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; + JSFunction *fun; + 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: + fun = js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK); + ok = (fun != NULL); + if (ok) + *vp = OBJECT_TO_JSVAL(fun->object); + 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); + 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)) { + /* XXX JSVAL_IS_OBJECT(v) is true for null too! Can we change ECMA? */ + obj = JSVAL_TO_OBJECT(v); + if (obj && + (ops = obj->map->ops, + ops == &js_ObjectOps + ? (clasp = OBJ_GET_CLASS(cx, obj), + clasp->call || clasp == &js_FunctionClass) + : ops->call != 0)) { + type = JSTYPE_FUNCTION; + } else { + type = JSTYPE_OBJECT; + } + } 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_InitScriptGlobals()) + return NULL; + 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; + js_SetupLocks(8, 16); /* this is asymmetric with JS_ShutDown. */ + 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_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_FreeScriptGlobals(); + 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; +} + +JS_PUBLIC_API(JSVersion) +JS_SetVersion(JSContext *cx, JSVersion version) +{ + JSVersion oldVersion; + + oldVersion = cx->version; + if (version == oldVersion) + return oldVersion; + + cx->version = version; + +#if !JS_BUG_FALLIBLE_EQOPS + if (cx->version == JSVERSION_1_2) { + cx->jsop_eq = JSOP_NEW_EQ; + cx->jsop_ne = JSOP_NEW_NE; + } else { + cx->jsop_eq = JSOP_EQ; + cx->jsop_ne = JSOP_NE; + } +#endif /* !JS_BUG_FALLIBLE_EQOPS */ + + 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_DEFAULT, "default"}, + {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; +} + +JS_PUBLIC_API(uint32) +JS_SetOptions(JSContext *cx, uint32 options) +{ + uint32 oldopts = cx->options; + cx->options = options; + return oldopts; +} + +JS_PUBLIC_API(uint32) +JS_ToggleOptions(JSContext *cx, uint32 options) +{ + uint32 oldopts = cx->options; + cx->options ^= options; + return oldopts; +} + +JS_PUBLIC_API(const char *) +JS_GetImplementationVersion(void) +{ + return "JavaScript-C 1.5 pre-release 6 2004-01-27"; +} + + +JS_PUBLIC_API(JSObject *) +JS_GetGlobalObject(JSContext *cx) +{ + return cx->globalObject; +} + +JS_PUBLIC_API(void) +JS_SetGlobalObject(JSContext *cx, JSObject *obj) +{ + cx->globalObject = obj; +} + +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) + cx->globalObject = 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 = (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 = (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, (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_FILE_OBJECT + js_InitFileClass(cx, obj, JS_TRUE) && +#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 + {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 + + {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 + /* See if 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, (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 +HasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom, JSBool *ownp) +{ + JSObject *pobj; + JSProperty *prop; + + if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, &prop)) + return JS_FALSE; + if (prop) + OBJ_DROP_PROPERTY(cx, pobj, prop); + *ownp = (pobj == obj && prop); + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj) +{ + JSRuntime *rt; + JSAtom *atom; + JSBool found; + uintN i; + + CHECK_REQUEST(cx); + rt = cx->runtime; + +#if JS_HAS_UNDEFINED + /* See if we need to bind 'undefined' and define it if so. */ + atom = rt->atomState.typeAtoms[JSTYPE_VOID]; + if (!HasOwnProperty(cx, obj, atom, &found)) + return JS_FALSE; + if (!found && + !OBJ_DEFINE_PROPERTY(cx, obj, (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 (!HasOwnProperty(cx, obj, atom, &found)) + return JS_FALSE; + if (!found && !standard_class_atoms[i].init(cx, obj)) + return JS_FALSE; + } + + return JS_TRUE; +} + +#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); +} + +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; +} + +#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) +{ + JSRuntime *rt; + uint32 bytes, lastBytes; + + rt = cx->runtime; + bytes = rt->gcBytes; + lastBytes = rt->gcLastBytes; + if ((bytes > 8192 && bytes > lastBytes + lastBytes / 2) || + rt->gcMallocBytes > rt->gcMaxBytes) { + /* + * 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); + } +} + +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(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_AllocGCThing(cx, (uintN) type); + 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; +} + +#ifdef DEBUG +static void +CheckStackGrowthDirection(int *dummy1addr, jsuword limitAddr) +{ + int dummy2; + +#if JS_STACK_GROWTH_DIRECTION > 0 + JS_ASSERT(dummy1addr < &dummy2); + JS_ASSERT((jsuword)&dummy2 < limitAddr); +#else + /* Stack grows downward, the common case on modern architectures. */ + JS_ASSERT(&dummy2 < dummy1addr); + JS_ASSERT(limitAddr < (jsuword)&dummy2); +#endif +} +#endif + +JS_PUBLIC_API(void) +JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr) +{ +#ifdef DEBUG + int dummy1; + + CheckStackGrowthDirection(&dummy1, limitAddr); +#endif + +#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 = (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 + return js_TryValueOf(cx, obj, type, vp); +} + +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; + JSBool named; + JSFunction *fun; + jsval junk; + + 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; + + if (!constructor) { + /* Lacking a constructor, name the prototype (e.g., Math). */ + named = OBJ_DEFINE_PROPERTY(cx, obj, (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; + + /* Connect constructor and prototype by named properties. */ + ctor = fun->object; + 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; + } + return proto; + +bad: + if (named) + (void) OBJ_DELETE_PROPERTY(cx, obj, (jsid)atom, &junk); + cx->newborn[GCX_OBJECT] = NULL; + return NULL; +} + +#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(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, + (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) +{ + *idp = (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_JSVAL((jsint)name); + atom = NULL; + attrs &= ~JSPROP_INDEX; + } else { + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return JS_FALSE; + id = (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, (jsid)atom, value, + getter, setter, attrs, flags, tinyid, + NULL); + } + return OBJ_DEFINE_PROPERTY(cx, obj, (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, (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, (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, (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) +{ + JSObject *obj2; + JSProperty *prop; + JSBool ok; + + if (!atom) + return JS_FALSE; + if (!OBJ_LOOKUP_PROPERTY(cx, obj, (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_GET_ATTRIBUTES(cx, obj, (jsid)atom, prop, attrsp); + 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, (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, (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); +} + +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_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_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, (jsid)atom, vp); +} + +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, (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, (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); +} + +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_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, (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, (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, (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_JSVAL(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_JSVAL(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_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_JSVAL(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_JSVAL(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_JSVAL(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_JSVAL(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 (i == ida->length) { + /* Grow length by factor of 1.5 instead of doubling. */ + jsint newlen = ida->length + (((jsuint)ida->length + 1) >> 1); + ida = js_GrowIdArray(cx, ida, newlen); + if (!ida) + goto error; + vector = &ida->vector[0]; + } + + if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id)) + goto error; + + /* No more jsid's to enumerate ? */ + if (iter_state == JSVAL_NULL) + break; + vector[i++] = id; + } + ida->length = i; + return ida; + +error: + if (iter_state != JSVAL_NULL) + OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0); + if (ida) + JS_DestroyIdArray(cx, ida); + return NULL; +} + +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; +} + +JS_PUBLIC_API(JSBool) +JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp) +{ + JSClass *clasp; + uint32 slot; + + CHECK_REQUEST(cx); + clasp = OBJ_GET_CLASS(cx, obj); + if (index >= JSCLASS_RESERVED_SLOTS(clasp)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_RESERVED_SLOT_RANGE); + 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 slot; + + CHECK_REQUEST(cx); + clasp = OBJ_GET_CLASS(cx, obj); + if (index >= JSCLASS_RESERVED_SLOTS(clasp)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_RESERVED_SLOT_RANGE); + return JS_FALSE; + } + slot = JSSLOT_START(clasp) + index; + OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v); + return JS_TRUE; +} + +#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(JSContext *cx, JSObjectPrincipalsFinder fop) +{ + JSObjectPrincipalsFinder oldfop; + + oldfop = cx->findObjectPrincipals; + cx->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(JSBool) +JS_ObjectIsFunction(JSContext *cx, JSObject *obj) +{ + return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass; +} + +JS_PUBLIC_API(JSBool) +JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs) +{ + JSFunction *fun; + + CHECK_REQUEST(cx); + for (; fs->name; fs++) { + fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, + fs->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); +} + +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); +} + +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); +#if JS_HAS_EXCEPTIONS + if (!script && !cx->fp) + js_ReportUncaughtException(cx); +#endif + 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)) { + /* + * 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 = (ts->flags & TSF_EOF) == 0; + } + + 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); +#if JS_HAS_EXCEPTIONS + if (!script && !cx->fp) + js_ReportUncaughtException(cx); +#endif + 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); +#if JS_HAS_EXCEPTIONS + if (!script && !cx->fp) + js_ReportUncaughtException(cx); +#endif + return script; +} + +JS_PUBLIC_API(JSObject *) +JS_NewScriptObject(JSContext *cx, JSScript *script) +{ + JSObject *obj; + + /* + * We use a dummy stack frame to protect the script from a GC caused + * by debugger-hook execution. + * + * XXX We really need a way to manage local roots and such more + * XXX automatically, at which point we can remove this one-off hack + * XXX and others within the engine. See bug 40757 for discussion. + */ + JSStackFrame dummy; + + CHECK_REQUEST(cx); + + memset(&dummy, 0, sizeof dummy); + dummy.down = cx->fp; + dummy.script = script; + cx->fp = &dummy; + + obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); + + cx->fp = dummy.down; + 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_AddNativeProperty(cx, fun->object, (jsid)argAtom, + js_GetArgument, js_SetArgument, + SPROP_INVALID_SLOT, + JSPROP_ENUMERATE | 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, (jsid)funAtom, + OBJECT_TO_JSVAL(fun->object), + NULL, NULL, 0, NULL)) { + return NULL; + } + } +out: + if (ts) + js_CloseTokenStream(cx, ts); + JS_ARENA_RELEASE(&cx->tempPool, mark); +#if JS_HAS_EXCEPTIONS + if (!fun && !cx->fp) + js_ReportUncaughtException(cx); +#endif + 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) +{ + CHECK_REQUEST(cx); + if (!js_Execute(cx, obj, script, NULL, 0, rval)) { +#if JS_HAS_EXCEPTIONS + if (!cx->fp) + js_ReportUncaughtException(cx); +#endif + return JS_FALSE; + } + return JS_TRUE; +} + +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) +{ + JSScript *script; + JSBool ok; + + CHECK_REQUEST(cx); + script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, + filename, lineno); + if (!script) + return JS_FALSE; + ok = js_Execute(cx, obj, script, NULL, 0, rval); +#if JS_HAS_EXCEPTIONS + if (!ok && !cx->fp) + js_ReportUncaughtException(cx); +#endif + JS_DestroyScript(cx, script); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, + jsval *argv, jsval *rval) +{ + CHECK_REQUEST(cx); + if (!js_InternalCall(cx, obj, OBJECT_TO_JSVAL(fun->object), argc, argv, + rval)) { +#if JS_HAS_EXCEPTIONS + if (!cx->fp) + js_ReportUncaughtException(cx); +#endif + return JS_FALSE; + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, + jsval *argv, jsval *rval) +{ + jsval fval; + + CHECK_REQUEST(cx); + if (!JS_GetProperty(cx, obj, name, &fval)) + return JS_FALSE; + if (!js_InternalCall(cx, obj, fval, argc, argv, rval)) { +#if JS_HAS_EXCEPTIONS + if (!cx->fp) + js_ReportUncaughtException(cx); +#endif + return JS_FALSE; + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, + jsval *argv, jsval *rval) +{ + CHECK_REQUEST(cx); + if (!js_InternalCall(cx, obj, fval, argc, argv, rval)) { +#if JS_HAS_EXCEPTIONS + if (!cx->fp) + js_ReportUncaughtException(cx); +#endif + return JS_FALSE; + } + return JS_TRUE; +} + +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 +} + +#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_EXCEPTIONS + CHECK_REQUEST(cx); + return js_ErrorFromException(cx, v); +#else + return NULL; +#endif +} + +#ifdef JS_THREADSAFE +JS_PUBLIC_API(jsword) +JS_GetContextThread(JSContext *cx) +{ + return cx->thread; +} + +JS_PUBLIC_API(jsword) +JS_SetContextThread(JSContext *cx) +{ + intN old = cx->thread; + cx->thread = js_CurrentThreadId(); + return old; +} + +JS_PUBLIC_API(intN) +JS_ClearContextThread(JSContext *cx) +{ + intN 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 */ |
