changeset 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 293eaba319ac
children f6e3733eac01
files pavement.py spidermonkey-playground.cpp tcb.cpp tcb.h
diffstat 4 files changed, 273 insertions(+), 239 deletions(-) [+]
line wrap: on
line diff
--- a/pavement.py	Thu Jun 25 12:36:38 2009 -0700
+++ b/pavement.py	Thu Jun 25 17:53:28 2009 -0700
@@ -17,6 +17,7 @@
                "-g", # produce output for gdb
                "-DDEBUG",
                "spidermonkey-playground.cpp",
+               "tcb.cpp",
                "wrapper.cpp",
                "server_socket.cpp",
                "memory_profiler.cpp",
--- a/spidermonkey-playground.cpp	Thu Jun 25 12:36:38 2009 -0700
+++ b/spidermonkey-playground.cpp	Thu Jun 25 17:53:28 2009 -0700
@@ -42,6 +42,7 @@
 #include "jsapi.h"
 #include "jsdbgapi.h"
 
+#include "tcb.h"
 #include "wrapper.h"
 #include "server_socket.h"
 #include "memory_profiler.h"
@@ -53,41 +54,14 @@
 static JSContext *tcb_cx;
 static JSObject  *tcb_global;
 
-// TODO: Make sure we're rooting objects appropriately here so that
-// the interpreter doesn't randomly crash or something.
-
-/* The class of the global object. */
-JSClass global_class = {
-  "global", JSCLASS_GLOBAL_FLAGS,
+// The class of SecurableModules.
+static JSClass SM_global_class = {
+  "SecurableModuleGlobal", 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.
-
-static JSBool 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.
-
-static JSBool forceGC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-                      jsval *rval)
-{
-  JS_GC(cx);
-  return JS_TRUE;
-}
-
 // This native JS function is an implementation of the SecurableModule
 // require() function.  For more information, see:
 //
@@ -125,7 +99,8 @@
   // TODO: Check for return values here.
   JSContext *module_cx = JS_NewContext(JS_GetRuntime(cx), 8192);
   JS_BeginRequest(module_cx);
-  JSObject *module_global = JS_NewObject(module_cx, &global_class, NULL,
+  JSObject *module_global = JS_NewObject(module_cx,
+                                         &SM_global_class, NULL,
                                          NULL);
   JS_InitStandardClasses(module_cx, module_global);
   JS_DefineProperty(module_cx, module_global, "imports",
@@ -151,206 +126,6 @@
   return JS_TRUE;
 }
 
-// This native JS function is a wrapper for JS_Enumerate().
-
-static JSBool 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.
-
-static JSBool 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.
-
-static JSBool 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.
-
-static JSBool 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().
-
-static JSTrapStatus 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 (!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;
-}
-
 // Our global checkAccess callback just checks to see if a JS function called
 // 'checkAccess' has been defined in the TCB, and delegates to that if so. If
 // not, though, we do a default checkAccess.
@@ -376,16 +151,16 @@
 }
 
 static JSFunctionSpec tcb_global_functions[] = {
-  JS_FS("print",          print,              1, 0, 0),
+  JS_FS("print",          TCB_print,          1, 0, 0),
+  JS_FS("stack",          TCB_stack,          0, 0, 0),
+  JS_FS("lookupProperty", TCB_lookupProperty, 2, 0, 0),
+  JS_FS("functionInfo",   TCB_functionInfo,   1, 0, 0),
+  JS_FS("enumerate",      TCB_enumerate,      1, 0, 0),
+  JS_FS("forceGC",        TCB_forceGC,        0, 0, 0),
   JS_FS("getWrapper",     getWrapper,         1, 0, 0),
   JS_FS("unwrap",         unwrapObject,       1, 0, 0),
   JS_FS("wrap",           wrapObject,         2, 0, 0),
-  JS_FS("stack",          stack,              0, 0, 0),
   JS_FS("require",        require,            2, 0, 0),
-  JS_FS("lookupProperty", lookupProperty,     2, 0, 0),
-  JS_FS("functionInfo",   functionInfo,       1, 0, 0),
-  JS_FS("enumerate",      enumerate,          1, 0, 0),
-  JS_FS("forceGC",        forceGC,            0, 0, 0),
   JS_FS("profileMemory",  profileMemory,      0, 0, 0),
   JS_FS("ServerSocket",   createServerSocket, 0, 0, 0),
   JS_FS_END
@@ -423,7 +198,7 @@
 #endif
 
   /* Create the TCB's global object. */
-  tcb_global = JS_NewObject(tcb_cx, &global_class, NULL, NULL);
+  tcb_global = JS_NewObject(tcb_cx, &TCB_global_class, NULL, NULL);
   if (tcb_global == NULL)
     return 1;
 
@@ -438,7 +213,7 @@
     return 1;
 
   // TODO: Check for return values here.
-  JS_SetThrowHook(rt, throwHook, tcb_global);
+  JS_SetThrowHook(rt, TCB_throwHook, tcb_global);
   JS_DefineProperty(tcb_cx, tcb_global, "lastExceptionTraceback", JSVAL_NULL,
                     NULL, NULL, 0);
   JS_DefineProperty(tcb_cx, tcb_global, "lastException", JSVAL_NULL,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcb.cpp	Thu Jun 25 17:53:28 2009 -0700
@@ -0,0 +1,233 @@
+#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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcb.h	Thu Jun 25 17:53:28 2009 -0700
@@ -0,0 +1,25 @@
+#include "jsapi.h"
+#include "jsdbgapi.h"
+
+extern JSClass TCB_global_class;
+
+extern JSBool TCB_print(JSContext *cx, JSObject *obj, uintN argc,
+                        jsval *argv, jsval *rval);
+
+extern JSBool TCB_forceGC(JSContext *cx, JSObject *obj, uintN argc,
+                          jsval *argv, jsval *rval);
+
+extern JSBool TCB_enumerate(JSContext *cx, JSObject *obj, uintN argc,
+                            jsval *argv, jsval *rval);
+
+extern JSBool TCB_lookupProperty(JSContext *cx, JSObject *obj, uintN argc,
+                                 jsval *argv, jsval *rval);
+
+extern JSBool TCB_functionInfo(JSContext *cx, JSObject *obj, uintN argc,
+                               jsval *argv, jsval *rval);
+
+extern JSBool TCB_stack(JSContext *cx, JSObject *obj, uintN argc,
+                        jsval *argv, jsval *rval);
+
+extern JSTrapStatus TCB_throwHook(JSContext *cx, JSScript *script,
+                                  jsbytecode *pc, jsval *rval, void *closure);