JS 45 problem

Kent Williams <[email protected]>
Newsgroups gmane.comp.mozilla.devel.jseng
Message-ID <[email protected]>
I recently did the work to migrate from JS38 to JS45.  I can compile all 
my code embedding SpiderMonkey -- yay! -- but there's a problem with 
adding JSNative classes with JS_InitClass.

The following example (based on the "Hello World" example quits with an 
error message "TESTO.good is not a function"  This code worked fine 
built against JS38.

http://pastebin.com/H7gVxng1

// This is an example for SpiderMonkey 31.
// For SpiderMonkey 24 or 38, see each comment.

// following code might be needed in some case
// #define __STDC_LIMIT_MACROS
// #include <stdint.h>
#if defined(JSAPI_DEBUG)
#define DEBUG
#endif
#include <iostream>
#include <jsapi.h>
#include <js/Initialization.h>

// TEST CODE FOR JS_InitClass
static bool TESTO_good(JSContext *cx, unsigned int argc, JS::Value *vp) {
     JS::CallArgs      args = JS::CallArgsFromVp(argc, vp);
     JS::RootedObject obj( cx, JS_THIS_OBJECT(cx, vp) );
     args.rval().setBoolean(true);
     return true;
}

static JSFunctionSpec TESTO_methods[] = {
     JS_FS("good", TESTO_good, 1, 0),
     JS_FS_END
};

static void TESTO_dtor(JSFreeOp *, JSObject *obj) {
}

static JSClass TESTO = {
     "TESTO", JSCLASS_HAS_PRIVATE,
     0,                                      // JSPropertyOp addProperty;
     0,                                      // JSDeletePropertyOp 
delProperty;
     0,                                      // JSPropertyOp getProperty;
     0,                                      // JSStrictPropertyOp 
setProperty;
     0,                                      // JSEnumerateOp enumerate;
     0,                                      // JSResolveOp resolve;
     0,                                      // JSConvertOp convert;
     TESTO_dtor,                  // FinalizeOpType      finalize;
     0,                                      // JSNative call;
     0,                                      // JSHasInstanceOp hasInstance;
     0,                                      // JSNative construct;
     0,      // JSTraceOp           trace
};

static bool TESTO_ctor(JSContext *cx, unsigned int argc, JS::Value *vp) {
     JS::CallArgs      args = JS::CallArgsFromVp(argc, vp);
     JS::RootedObject obj(cx);
     if (args.isConstructing()) {
         obj = JS_NewObject(cx, &TESTO);
         if (!obj)
             return false;
     } else {
         obj = JS_THIS_OBJECT(cx, vp);
     }
     args.rval().setObject(*obj);
     return true;
}

bool init_TESTO(JSContext *cx, JS::HandleObject globs) {
     if(JS_InitClass(cx, globs, nullptr, &TESTO,
                          TESTO_ctor, 0, nullptr, TESTO_methods, 
nullptr, nullptr) == nullptr)
         abort();
     return true;
}

// KW ADD -- need JS_GlobalObjectTraceHook
JSClass global_class = {
     "global", JSCLASS_GLOBAL_FLAGS,
     0,                                      // JSPropertyOp addProperty;
     0,                                      // JSDeletePropertyOp 
delProperty;
     0,                                      // JSPropertyOp getProperty;
     0,                                      // JSStrictPropertyOp 
setProperty;
     0,                                      // JSEnumerateOp enumerate;
     0,                                      // JSResolveOp resolve;
     0,                                      // JSConvertOp convert;
     0,                                      // FinalizeOpType finalize;
     0,                                      // JSNative call;
     0,                                      // JSHasInstanceOp hasInstance;
     0,                                      // JSNative construct;
     JS_GlobalObjectTraceHook,      // JSTraceOp           trace
};

void JSErrorHandler(JSContext *cx, const char *message, JSErrorReport* 
what) {
     std::cout << "ERROR: " << message;
     if (what->filename)
         std::cout << ": file: " << what->filename;
     std::cout << ", line:" << (int) what->lineno
                  << ", column:" << (int) what->column
                  << std::endl;
}

int main(int argc, const char *argv[])
{
     // [SpiderMonkey 24] JS_Init does not exist. Remove this line.
     JS_Init();

     // [SpiderMonkey 38] useHelperThreads parameter is removed.
     JSRuntime *rt = JS_NewRuntime(8L * 1024 * 1024);
     // JSRuntime *rt = JS_NewRuntime(8L * 1024 * 1024, 
JS_USE_HELPER_THREADS);
     if (!rt)
         return 1;

     JSContext *cx = JS_NewContext(rt, 8192);
     if (!cx)
         return 1;
      // KW ADD -- everything that happens needs to be inside a request.
      JS_BeginRequest(cx);

     // [SpiderMonkey 24] hookOption parameter does not exist.
     // JS::RootedObject global(cx, JS_NewGlobalObject(cx, 
&global_class, nullptr));
      // KW ADD -- move global down into brace so it will go out of
     // scope before DestroyContext

      // KW ADD -- move rval inside scope, so
      // it will be destroyed before cleanup at end
     {
          JS::RootedValue rval(cx);
          JS::RootedObject global(cx,
                                          JS_NewGlobalObject(cx, 
&global_class, nullptr, JS::FireOnNewGlobalHook));
          if (!global)
              return 1;
         JSAutoCompartment ac(cx, global);
       JS_InitStandardClasses(cx, global);
         init_TESTO(cx, global);
         // set error reporter
         JS_SetErrorReporter(rt, JSErrorHandler);


       const char *script = "'hello'+'world, it is '+new Date();\n"
             "var TESTO = new TESTO(\"testzip.zip\");\n"
             "if (!TESTO || !TESTO.good())\n"
             "throw \"FAIL: cannot create TESTO\";\n";
       const char *filename = "noname";
       int lineno = 1;
       // [SpiderMonkey 24] The type of rval parameter is 'jsval *'.
       // bool ok = JS_EvaluateScript(cx, global, script, 
strlen(script), filename, lineno, rval.address());
       // [SpiderMonkey 38] JS_EvaluateScript is replaced with JS::Evaluate.
       JS::CompileOptions opts(cx);
       opts.setFileAndLine(filename, lineno);
       bool ok = JS::Evaluate(cx, opts, script, strlen(script), &rval);
       // bool ok = JS_EvaluateScript(cx, global, script, 
strlen(script), filename, lineno, &rval);
       if (!ok)
         return 1;

     JSString *str = rval.toString();
     printf("%s\n", JS_EncodeString(cx, str));
     }
      // KW ADD
      JS_EndRequest(cx);
     JS_DestroyContext(cx);
     JS_DestroyRuntime(rt);
     JS_ShutDown();
     return 0;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.