📄 jsapi.c
字号:
CHECK_REQUEST(cx); switch (type) { case JSTYPE_VOID: *vp = JSVAL_VOID; ok = JS_TRUE; break; case JSTYPE_OBJECT: ok = js_ValueToObject(cx, v, &obj); if (ok) *vp = OBJECT_TO_JSVAL(obj); break; case JSTYPE_FUNCTION: *vp = v; obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK); ok = (obj != NULL); break; case JSTYPE_STRING: str = js_ValueToString(cx, v); ok = (str != NULL); if (ok) *vp = STRING_TO_JSVAL(str); break; case JSTYPE_NUMBER: ok = js_ValueToNumber(cx, v, &d); if (ok) { dp = js_NewDouble(cx, d, 0); ok = (dp != NULL); if (ok) *vp = DOUBLE_TO_JSVAL(dp); } break; case JSTYPE_BOOLEAN: ok = js_ValueToBoolean(cx, v, &b); if (ok) *vp = BOOLEAN_TO_JSVAL(b); break; default: { char numBuf[12]; JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type); JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE, numBuf); ok = JS_FALSE; break; } } return ok;}JS_PUBLIC_API(JSBool)JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp){ CHECK_REQUEST(cx); return js_ValueToObject(cx, v, objp);}JS_PUBLIC_API(JSFunction *)JS_ValueToFunction(JSContext *cx, jsval v){ CHECK_REQUEST(cx); return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);}JS_PUBLIC_API(JSFunction *)JS_ValueToConstructor(JSContext *cx, jsval v){ CHECK_REQUEST(cx); return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);}JS_PUBLIC_API(JSString *)JS_ValueToString(JSContext *cx, jsval v){ CHECK_REQUEST(cx); return js_ValueToString(cx, v);}JS_PUBLIC_API(JSBool)JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp){ CHECK_REQUEST(cx); return js_ValueToNumber(cx, v, dp);}JS_PUBLIC_API(JSBool)JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip){ CHECK_REQUEST(cx); return js_ValueToECMAInt32(cx, v, ip);}JS_PUBLIC_API(JSBool)JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip){ CHECK_REQUEST(cx); return js_ValueToECMAUint32(cx, v, ip);}JS_PUBLIC_API(JSBool)JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip){ CHECK_REQUEST(cx); return js_ValueToInt32(cx, v, ip);}JS_PUBLIC_API(JSBool)JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip){ CHECK_REQUEST(cx); return js_ValueToUint16(cx, v, ip);}JS_PUBLIC_API(JSBool)JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp){ CHECK_REQUEST(cx); return js_ValueToBoolean(cx, v, bp);}JS_PUBLIC_API(JSType)JS_TypeOfValue(JSContext *cx, jsval v){ JSType type; JSObject *obj; JSObjectOps *ops; JSClass *clasp; CHECK_REQUEST(cx); if (JSVAL_IS_OBJECT(v)) { type = JSTYPE_OBJECT; /* XXXbe JSTYPE_NULL for JS2 */ obj = JSVAL_TO_OBJECT(v); if (obj) { ops = obj->map->ops;#if JS_HAS_XML_SUPPORT if (ops == &js_XMLObjectOps.base) { type = JSTYPE_XML; } else#endif { /* * ECMA 262, 11.4.3 says that any native object that implements * [[Call]] should be of type "function". Note that RegExp and * Script are both of type "function" for compatibility with * older SpiderMonkeys. */ clasp = OBJ_GET_CLASS(cx, obj); if ((ops == &js_ObjectOps) ? (clasp->call ? (clasp == &js_RegExpClass || clasp == &js_ScriptClass) : clasp == &js_FunctionClass) : ops->call != NULL) { type = JSTYPE_FUNCTION; } else {#ifdef NARCISSUS if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(cx->runtime->atomState .callAtom), &v)) { JS_ClearPendingException(cx); } else if (VALUE_IS_FUNCTION(cx, v)) { type = JSTYPE_FUNCTION; }#endif } } } } else if (JSVAL_IS_NUMBER(v)) { type = JSTYPE_NUMBER; } else if (JSVAL_IS_STRING(v)) { type = JSTYPE_STRING; } else if (JSVAL_IS_BOOLEAN(v)) { type = JSTYPE_BOOLEAN; } else { type = JSTYPE_VOID; } return type;}JS_PUBLIC_API(const char *)JS_GetTypeName(JSContext *cx, JSType type){ if ((uintN)type >= (uintN)JSTYPE_LIMIT) return NULL; return js_type_strs[type];}/************************************************************************/JS_PUBLIC_API(JSRuntime *)JS_NewRuntime(uint32 maxbytes){ JSRuntime *rt;#ifdef DEBUG static JSBool didFirstChecks; if (!didFirstChecks) { /* * 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 compile-time 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#define MSG_DEF(name, number, count, exception, format) \ JS_BEGIN_MACRO \ uintN numfmtspecs = 0; \ const char *fmt; \ for (fmt = format; *fmt != '\0'; fmt++) { \ if (*fmt == '{' && isdigit(fmt[1])) \ ++numfmtspecs; \ } \ JS_ASSERT(count == numfmtspecs); \ JS_END_MACRO;#include "js.msg"#undef MSG_DEF didFirstChecks = JS_TRUE; }#endif /* DEBUG */ 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 if (PR_FAILURE == PR_NewThreadPrivateIndex(&rt->threadTPIndex, js_ThreadDestructorCB)) { goto bad; } rt->gcLock = JS_NEW_LOCK(); if (!rt->gcLock) goto bad; rt->gcDone = JS_NEW_CONDVAR(rt->gcLock); if (!rt->gcDone) goto bad; rt->requestDone = JS_NEW_CONDVAR(rt->gcLock); if (!rt->requestDone) goto bad; /* this is asymmetric with JS_ShutDown: */ if (!js_SetupLocks(8, 16)) goto bad; rt->rtLock = JS_NEW_LOCK(); if (!rt->rtLock) goto bad; rt->stateChange = JS_NEW_CONDVAR(rt->gcLock); if (!rt->stateChange) goto bad; rt->setSlotLock = JS_NEW_LOCK(); if (!rt->setSlotLock) goto bad; rt->setSlotDone = JS_NEW_CONDVAR(rt->setSlotLock); if (!rt->setSlotDone) goto bad; rt->scopeSharingDone = JS_NEW_CONDVAR(rt->gcLock); if (!rt->scopeSharingDone) goto bad; rt->scopeSharingTodo = NO_SCOPE_SHARING_TODO;#endif rt->propertyCache.empty = JS_TRUE; if (!js_InitPropertyTree(rt)) goto bad; return rt;bad: JS_DestroyRuntime(rt); return NULL;}JS_PUBLIC_API(void)JS_DestroyRuntime(JSRuntime *rt){#ifdef DEBUG /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */ if (!JS_CLIST_IS_EMPTY(&rt->contextList)) { JSContext *cx, *iter = NULL; uintN cxcount = 0; while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) cxcount++; fprintf(stderr,"JS API usage error: %u contexts left in runtime upon JS_DestroyRuntime.\n", cxcount); }#endif js_FreeRuntimeScriptState(rt); js_FinishAtomState(&rt->atomState); js_FinishGC(rt);#ifdef JS_THREADSAFE if (rt->gcLock) JS_DESTROY_LOCK(rt->gcLock); if (rt->gcDone) JS_DESTROY_CONDVAR(rt->gcDone); if (rt->requestDone) JS_DESTROY_CONDVAR(rt->requestDone); if (rt->rtLock) JS_DESTROY_LOCK(rt->rtLock); if (rt->stateChange) JS_DESTROY_CONDVAR(rt->stateChange); if (rt->setSlotLock) JS_DESTROY_LOCK(rt->setSlotLock); if (rt->setSlotDone) JS_DESTROY_CONDVAR(rt->setSlotDone); if (rt->scopeSharingDone) JS_DESTROY_CONDVAR(rt->scopeSharingDone);#else GSN_CACHE_CLEAR(&rt->gsnCache);#endif js_FinishPropertyTree(rt); free(rt);}JS_PUBLIC_API(void)JS_ShutDown(void){ js_FinishDtoa();#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_THREADSAFEJS_PUBLIC_API(void)JS_BeginRequest(JSContext *cx){ JSRuntime *rt; JS_ASSERT(cx->thread->id == js_CurrentThreadId()); if (!cx->requestDepth) { /* Wait until the GC is finished. */ rt = cx->runtime; JS_LOCK_GC(rt); /* NB: we use cx->thread here, not js_GetCurrentThread(). */ 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); if (rt->gcThread != cx->thread) { while (rt->gcLevel > 0) JS_AWAIT_GC_DONE(rt); } rt->requestCount++; JS_UNLOCK_GC(rt);}JS_PUBLIC_API(jsrefcount)JS_SuspendRequest(JSContext *cx){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -