Mercurial > spidermonkey-playground
view tcb.cpp @ 69:be61430630ab
Separated out some of the TCB-specific code into tcb.cpp/h.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Thu, 25 Jun 2009 17:53:28 -0700 |
parents | |
children | f6e3733eac01 |
line wrap: on
line source
#include "tcb.h" // The class of the global object. JSClass TCB_global_class = { "TCBGlobal", JSCLASS_GLOBAL_FLAGS, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS }; // This native JS function prints the given string to the console. JSBool TCB_print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char *str; if (!JS_ConvertArguments(cx, argc, argv, "s", &str)) return JS_FALSE; printf("%s\n", str); return JS_TRUE; } // This native JS function forces garbage collection. JSBool TCB_forceGC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JS_GC(cx); return JS_TRUE; } // This native JS function is a wrapper for JS_Enumerate(). JSBool TCB_enumerate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSObject *target; if (!JS_ConvertArguments(cx, argc, argv, "o", &target)) return JS_FALSE; JSIdArray *ids = JS_Enumerate(cx, target); if (ids == NULL) return JS_FALSE; JSObject *array = JS_NewArrayObject(cx, ids->length, ids->vector); *rval = OBJECT_TO_JSVAL(array); return JS_TRUE; } // This native JS function looks up the property of an object, bypassing // security checks and getters/setters. JSBool TCB_lookupProperty(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSObject *target; if (argc < 2) { JS_ReportError(cx, "Must provide id to lookup."); return JS_FALSE; } if (!JS_ConvertArguments(cx, argc, argv, "o", &target)) return JS_FALSE; return JS_LookupPropertyById(cx, target, argv[1], rval); } // This native JS function returns a JS object containing metadata about // the given function. JSBool TCB_functionInfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSFunction *func; if (!JS_ConvertArguments(cx, argc, argv, "f", &func)) return JS_FALSE; JSScript *script = JS_GetFunctionScript(cx, func); if (script == NULL) { *rval = JSVAL_NULL; return JS_TRUE; } jsval filenameVal = JSVAL_NULL; const char *filename = JS_GetScriptFilename(cx, script); if (filename) { JSString *filenameStr = JS_NewStringCopyZ(cx, filename); filenameVal = STRING_TO_JSVAL(filenameStr); } // TODO: Check for return values here. JSObject *funcInfo = JS_NewObject(cx, NULL, NULL, NULL); JS_DefineProperty(cx, funcInfo, "filename", filenameVal, NULL, NULL, 0); *rval = OBJECT_TO_JSVAL(funcInfo); return JS_TRUE; } // This native JS function returns a JS representation of the current // state of the stack, starting with the callee's stack frame and going // up from there. JSBool TCB_stack(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSAutoLocalRootScope autoScope(cx); JSStackFrame *iterator = NULL; JSStackFrame *frame; JSObject *prevFrameInfo = NULL; JSObject *firstFrameInfo = NULL; bool skippedMyFrame = false; if (obj == NULL) // We're being called from native code, don't skip the topmost frame. skippedMyFrame = true; while ((frame = JS_FrameIterator(cx, &iterator)) != NULL) { if (!skippedMyFrame) { skippedMyFrame = true; continue; } jsval functionNameVal = JSVAL_NULL; jsval filenameVal = JSVAL_NULL; jsval lineNoVal = JSVAL_ZERO; jsval functionObjectVal = JSVAL_NULL; jsval scopeChainVal = JSVAL_NULL; JSFunction *func = JS_GetFrameFunction(cx, frame); if (func) { JSString *functionName = JS_GetFunctionId(func); if (functionName) functionNameVal = STRING_TO_JSVAL(functionName); } if (!JS_IsNativeFrame(cx, frame)) { JSScript *script = JS_GetFrameScript(cx, frame); jsbytecode *bytecode = JS_GetFramePC(cx, frame); const char *filename = JS_GetScriptFilename(cx, script); if (filename) { JSString *filenameStr = JS_NewStringCopyZ(cx, filename); filenameVal = STRING_TO_JSVAL(filenameStr); } uintN lineNo = JS_PCToLineNumber(cx, script, bytecode); lineNoVal = INT_TO_JSVAL(lineNo); JSObject *functionObject = JS_GetFrameFunctionObject(cx, frame); functionObjectVal = OBJECT_TO_JSVAL(functionObject); JSObject *scopeChain = JS_GetFrameScopeChain(cx, frame); scopeChainVal = OBJECT_TO_JSVAL(scopeChain); } // TODO: Check for return values here. JSObject *frameInfo = JS_NewObject(cx, NULL, NULL, NULL); JS_DefineProperty(cx, frameInfo, "filename", filenameVal, NULL, NULL, 0); JS_DefineProperty(cx, frameInfo, "lineNo", lineNoVal, NULL, NULL, 0); JS_DefineProperty(cx, frameInfo, "functionName", functionNameVal, NULL, NULL, 0); JS_DefineProperty(cx, frameInfo, "functionObject", functionObjectVal, NULL, NULL, 0); JS_DefineProperty(cx, frameInfo, "scopeChain", scopeChainVal, NULL, NULL, 0); if (prevFrameInfo) JS_DefineProperty(cx, prevFrameInfo, "caller", OBJECT_TO_JSVAL(frameInfo), NULL, NULL, 0); else firstFrameInfo = frameInfo; prevFrameInfo = frameInfo; } if (firstFrameInfo) *rval = OBJECT_TO_JSVAL(firstFrameInfo); else *rval = JSVAL_NULL; return JS_TRUE; } // Our global hook called whenever an exception is thrown saves the current // exception and stack information to the 'lastException' and // 'lastExceptionTraceback' globals of the TCB, respectively, much like // Python's sys.exc_info(). JSTrapStatus TCB_throwHook(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure) { JSObject *tcb_global = (JSObject *) closure; jsval lastExceptionTraceback; jsval lastException; jsval exception = *rval; if (JS_IsExceptionPending(cx)) if (!JS_GetPendingException(cx, &exception)) printf("Getting exception failed.\n"); if (!JS_GetProperty(cx, tcb_global, "lastException", &lastException)) printf("Unable to retrieve last exception."); if (lastException == exception) // The same exception is just propagating through the stack; keep // our existing last-exception info. return JSTRAP_CONTINUE; if (!TCB_stack(cx, NULL, 0, NULL, &lastExceptionTraceback)) { printf("Generation of exception info failed."); lastExceptionTraceback = JSVAL_NULL; } if (!JS_SetProperty(cx, tcb_global, "lastExceptionTraceback", &lastExceptionTraceback) || !JS_SetProperty(cx, tcb_global, "lastException", &exception)) printf("Setting of exception info failed."); return JSTRAP_CONTINUE; }