SpiderMonkey

SpiderMonkey

Die Mozilla JavaScript Engine

[die ersten Zeilen]

Als erstes laden wir uns die Sources von Mozilla runter und kompilieren die shared libraries.

Das Archiv: http://ftp.mozilla.org/pub/mozilla.org/js/js185-1.0.0.tar.gz

Das Verzeichnis: http://ftp.mozilla.org/pub/mozilla.org/js/ enthaelt unter anderem auch Rhino.

Latest Version: http://hg.mozilla.org/mozilla-central

http://developer.mozilla.org/en-US/docs/SpiderMonkey/Getting_SpiderMonkey_source_code (getting new and old sources)

Die Installation ist einfacher als gedacht. Es kompiliert fehlerfrei und installiert sich von alleine. Der Gang ist der gewohnte. Configure, Make, Make Install, Done.

	    cd /js-1.8.5/js/src
	    ./configure
	    make
	    make install
	    

Das wäre geschafft.

# make install
/js-1.8.5/js/src/config/nsinstall -t js-config /usr/local/bin
/js-1.8.5/js/src/config/nsinstall -t libjs_static.a /usr/local/lib
mv -f /usr/local/lib/libjs_static.a /usr/local/lib/libmozjs185-1.0.a
/js-1.8.5/js/src/config/nsinstall -t libmozjs185.so /usr/local/lib
mv -f /usr/local/lib/libmozjs185.so /usr/local/lib/libmozjs185.so.1.0.0
ln -s /usr/local/lib/libmozjs185.so.1.0.0 /usr/local/lib/libmozjs185.so.1.0
ln -s /usr/local/lib/libmozjs185.so.1.0 /usr/local/lib/libmozjs185.so

Erste Infos

https://developer.mozilla.org/en-US/docs/SpiderMonkey

Hier gibt es Gerüchte von nach 1.8.5. http://developer.mozilla.org/en-US/docs/SpiderMonkey/1.8.8

Die aktuelle Version gibt es mit dem Firefox Source Code bzw. in Mozilla-Central, denke ich, da ich jetzt alle Quellen untersucht habe. Die aktuelle Version und auch Gecko zu builden, soweit bin ich hingegen noch nicht.

Zur Gecko Rendering Engine komme ich demnächst, wenn ich das DOM haben will. SpiderMonkey ohne DOM ist, wie man sieht, mit ein paar Megabytes für die kompilierten Quellen bereites einsatzbereit. Ich werde euch jetzt ein paar geile Sachen zeigen.

SpiderMonkey coding conventions

http://developer.mozilla.org/en-US/docs/SpiderMonkey_conding_conventions

Geklautes Hello World

Von Brendan Eich dem Creator der Language

Copy + Paste: Dieses Beispiel ist von https://developer.mozilla.org/en-US/docs/How_to_embed_the_JavaScript_engine kopiert.

cat >> /hello.cpp
# Ein mittlerer Mausclick pastet Source im Clipboard
# Strg-D

Diesen Text hier habe ich direkt uebernommen.

Das Original ist von Brendan Eich (siehe Originalseite auf Mozilla)

/*
 * This define is for Windows only, it is a work-around for bug 661663.
 */
#ifdef _MSC_VER
# define XP_WIN
#endif
 
/* Include the JSAPI header file to get access to SpiderMonkey. */
#include "jsapi.h"
 
/* The class of the global object. */
static JSClass global_class = {
    "global", JSCLASS_GLOBAL_FLAGS,
    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
    JSCLASS_NO_OPTIONAL_MEMBERS
};
 
/* The error reporter callback. */
void reportError(JSContext *cx, const char *message, JSErrorReport *report)
{
    fprintf(stderr, "%s:%u:%s\n",
            report->filename ? report->filename : "",
            (unsigned int) report->lineno,
            message);
}
 
int main(int argc, const char *argv[])
{
    /* JSAPI variables. */
    JSRuntime *rt;
    JSContext *cx;
    JSObject  *global;
 
    /* Create a JS runtime. You always need at least one runtime per process. */
    rt = JS_NewRuntime(8 * 1024 * 1024);
    if (rt == NULL)
        return 1;
 
    /* 
     * Create a context. You always need a context per thread.
     * Note that this program is not multi-threaded.
     */
    cx = JS_NewContext(rt, 8192);
    if (cx == NULL)
        return 1;
    JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
    JS_SetVersion(cx, JSVERSION_LATEST);
    JS_SetErrorReporter(cx, reportError);
 
    /*
     * Create the global object in a new compartment.
     * You always need a global object per context.
     */
    global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
    if (global == NULL)
        return 1;
 
    /*
     * Populate the global object with the standard JavaScript
     * function and object classes, such as Object, Array, Date.
     */
    if (!JS_InitStandardClasses(cx, global))
        return 1;
 
    /* Your application code here. This may include JSAPI calls
     * to create your own custom JavaScript objects and to run scripts.
     *
     * The following example code creates a literal JavaScript script,
     * evaluates it, and prints the result to stdout.
     *
     * Errors are conventionally saved in a JSBool variable named ok.
     */
    char *script = "'Hello ' + 'World!'";
    jsval rval;
    JSString *str;
    JSBool ok;
    const char *filename = "noname";
    uintN lineno = 0;
 
    ok = JS_EvaluateScript(cx, global, script, strlen(script),
                           filename, lineno, &rval);
    if (rval == NULL | rval == JS_FALSE)
        return 1;
 
    str = JS_ValueToString(cx, rval);
    printf("%s\n", JS_EncodeString(cx, str));
 
    /* End of your application code */
 
    /* Clean things up and shut down SpiderMonkey. */
    JS_DestroyContext(cx);
    JS_DestroyRuntime(rt);
    JS_ShutDown();
    return 0;
}

Mit diesem Befehl habe ich das dann kompiliert.

g++ -I/js-1.8.5/js/src/dist/include -L/js-1.8.5/js/src/dist/bin -lmozjs185 hello.cpp -o hello

et voila

> ./hello
Hello World!

Jetzt kann man sich den Hello World Code durchlesen und erstmal was rausfinden.

Das Hello World wurde durch 'Hello ' + 'World!' zusammengesetzt. Gibt man auf Node z.B. "hello "+"world!" ein, kommt auch "hello world!" raus.

Es ist also eine Concatenation durchgefuehrt worden mit dem Plusoperator und der return Wert mit printf("%s", ..) ausgegeben worden, nachdem JS_EvaluateScript, JS_ValueToString, JS_EncodeString liefen.

Beachtet jsval: Das ist der ultimativ wichtige Datentyp (Die JavaScript Values) bei jeder Evaluation, jedem Function Call, der Returncode einer Funktion wird mit einer jsval gesetzt, die arguments sind jsvals, und und und...

Weiter oben, zuerst muss man JS_Runtime, JS_Context, usw. deklarieren. Ich muss das erstmal analysieren.

Ist anders als V8, aber schwerer oder mehr oder weniger auf keinen Fall. Das ist in etwa gleich.

Wird bestimmt Spass machen.

JSAPI

Finden wir mal heraus, welche Funktionen allein schon im ersten Beispiel laufen, und was die so bedeuten...

Types

Functions

(oder noch einige mehr)

Macros

  • My First Own Example

    Mein REPL heisst Spiderman

    Wenn ich das alles gelesen und verstanden habe, und die paar Befehle aus dem ersten Beispiel (oder noch wenige mehr) auswendig kann.

    Ich habe das heute vormittag kurz gemacht. Ich habe gerade noch ein wenig den Referenzteil verlinkt. Und dann eben einen REPL Prompt zu dem Beispiel hinzugefuegt. Unterwegs dachte ich irgendwann an Spiderman. Denn ich hatte eine Spiderman Wollmuetze auf, die ich irgendwann die Tage in der U-Bahn gefunden hatte.

        // Mein erster Anker, den ich werfe.
    
        Spiderman> Object.getOwnPropertyNames(this);
    
        // Finde heraus, was auf dem globalen Objekt definiert ist
        // Ohne JS_InitStandardClasses gar nichts
        
    

    Grins. Ich habe schon in der Referenz geguckt, wie man Funktionen aufruft und so weiter. Ab dann kann man schon eine API auf der Spidermonkey Library aufbauen. Es gibt zum Beispiel kein Console Interface mit console.log oder .dir oder .time oder .warn oder .error, wenn ich das richtig bemerkt habe. Das und noch vieles mehr wäre eine gute Idee. Dann natürlich libuv. Ich wäre blöd, wenn ich nicht eine lib wie libuv nehmen wuerde.

    #include <jsapi.h>
    #include <iostream>
    #include <string>
    
    static JSClass global_class = {
        "global",
        JSCLASS_GLOBAL_FLAGS,
        JS_PropertyStub,
        JS_PropertyStub,    
        JS_PropertyStub,    
        JS_StrictPropertyStub,    
        JS_EnumerateStub,        
        JS_ResolveStub,    
        JS_ConvertStub,    
        JS_FinalizeStub,    
        JSCLASS_NO_OPTIONAL_MEMBERS
    };
    
    void reportError (JSContext *cs, const char *message, JSErrorReport *report) {
        std::cout << (report->filename ? report->filename : "") << ":" << (unsigned int) report->lineno << ":" << (char *)message << std::endl;
    }
    
    int log(const char *str, int rc = 1) {
        std::cout << str << std::endl;
        return rc;
    }
    
    void prompt () {
        // mein REPL heisst jetzt spiderman
        std::cout << "Spiderman> ";
    }
    
    int main(int argc, char **argv) {
        JSRuntime *rt;
        JSContext *cx;
        JSObject *global;
    
        // Runtime erzeugen
        rt = JS_NewRuntime(8 * 1024 * 1024);
        if (rt == NULL) {
    	return log("Can not create JSRuntime, returning 1;");
        } else {
    	log("Created JSRuntime");
        }
    
        
        // Context erzeugen
        cx = JS_NewContext(rt, 8192);
        if (cx == NULL) {
    	return log("Can not create JSContext, returning 1;");
        } else {
    	log("Created JSContent");
        }
        
        // Error Reporter setzen - Die Funktion gibt den vorherigen Callback zurueck
        if (JS_SetErrorReporter(cx, reportError) == NULL) {
        	log("No previous Error Reporter has been set.");
        }
        // Ich teste jetzt, ob die Funktion auch zurueck gegeben wird. Die Antwort ist: JA.
        if (JS_SetErrorReporter(cx, reportError) == reportError) {
    	log("The previous Error Reporter is correctly returned.");
        }
        
        JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
        JS_SetVersion(cx, JSVERSION_LATEST);
        
        // Das GLOBALE OBJEKT setzen
        global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
        if (global == NULL) {
    	return log("Error creating global object with new compartment.");
        }
        
        // Jetzt String, Object, Array, Date initialisieren
        // Achtung: Es gibt kein Console.log Interface. Das kann ich schreiben, etc. pp.
        
        if (!JS_InitStandardClasses(cx, global)) {
    	return log("Can not initialize standard JS Classes");
        } else {
    	log("success JS_InitStandardClasses");
        }
        
    
    // Das ist die Stelle, wo mein Application Code hinkommt
    // Hier versuche ich einen Loop von STDIN an den Prozessor zu passen
    // Der Rest ist vom Hello World Example uebernommen, weil ich noch
    // keine Ahnung habe, wie es weiter geht.
    
        log("Enter some SpiderMonkey JavaScript and stop with Strg-D (EOF): ");
        
        std::string s;    
        jsval rval;
        JSString *str;
        JSBool ok;
        const char *filename = "noname";
        uintN lineno = 0;
    
        char c;
        
        prompt();
        
        while (true) {
    	c = std::cin.get();
    	if (std::cin.eof()) break;
    	s += c;
    	if (c == '\n') prompt();
        }
            
        ok = JS_EvaluateScript(cx, global, s.c_str(), s.length(),
        filename, lineno, &rval);
        if (rval == NULL | rval == JS_FALSE) {
    	return log("Error executing script: jsval rval ist NULL oder JS_FALSE");
        }
        
        str = JS_ValueToString(cx, rval);
        log(JS_EncodeString(cx, str));
        
        
        // Aufraeumen
        // des Programms    
        
        JS_DestroyContext(cx);
        JS_DestroyRuntime(rt);
        JS_ShutDown();
        return 0;
    }
    

    smfirst.cpp - der Source Code als File.

    Ergebnis

    Created JSRuntime
    Created JSContent
    No previous Error Reporter has been set.
    The previous Error Reporter is correctly returned.
    success JS_InitStandardClasses
    Enter some SpiderMonkey JavaScript and stop with Strg-D (EOF): 
    Spiderman> function f() { return "Yeah"; }
    Spiderman> f();
    Spiderman> [strg-d]
    Yeah
    

    Ich denke mal in JSVal wird gerade der LETZTE return Wert im Spiel gespeichert...

    Das habe ich dann kompiliert.

    g++ -I/js-1.8.5/js/src/dist/include -L/js-1.8.5/js/src/dist/bin -lmozjs185 smfirst.cpp -o smfirst
    

    Damit kann man dann auf der Standardeingabe JavaScript eingeben und es wird dann ausgefuehrt.

    Ich habe das Beispiel modifiziert. Ich war ein paar Stunden ausser Haus. Heute Mittag hatte es keinen Prompt und ich fand heraus, das print nicht existiert, wie auch console.log nicht in der jsshell.

    Created JSRuntime
    Created JSContent
    No previous Error Reporter has been set.
    The previous Error Reporter is correctly returned.
    success JS_InitStandardClasses
    Enter some SpiderMonkey JavaScript and stop with Strg-D (EOF): 
    function f() { return "yes"; } 
    print(f());
    noname:0:ReferenceError: print is not defined
    undefined
    

    Funktionen wie print, die die JSShell z.B. hat, gibt es in dem Code noch nicht. Es gibt ReferenceError, wenn das Ding dann ausgefuehrt wird.

    Referenz

    Übersicht: http://developer.mozilla.org/en-US/docs/SpiderMonkey

    Walkthrough (aus der Übersicht): http://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals

    Documentation

    Da die Original JavaScript Engine von Brendan Eich entwickelt wurde, heute ist das natürlich ein Gemeinschaftsprojekt, und er von Netscape nach Mozilla ging, er ist heute CTO bei Mozilla, gibt es die volle JSAPI Dokumentation natürlich auch im MDN.

    http://developer.mozilla.org/en-US/docs/SpiderMonkey

    User Guide

    Es gibt viele Dokumente im MDN, die SpiderMonkey oder die JSAPI beschreiben, wie zum Beispiel den JSAPI_User_Guide.

    Dieses Bild zeigt die Beziehung der Scripts, zwischen Runtime, Context und Objects.
    http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_User_Guide

    jsval

    JavaScript Values

    Was in JavaScript mit einem Befehl geht muss in C manchmal konvertiert werden. jsval speichert alle JavaScript Values, das sind Objects, Functions, Numbers, Strings, Booleans, Null, Undefined und die JSAPI bietet Macros und Funktionen zur einfachen Konversion. Die muss man nur lernen, dann hat man ein komplettes Utility Set um von jeder Seite aus an die Values in JavaScript oder im Code dran zu kommen.

        // JavaScript
        return 23;
        
        // SpiderMonkey (in der nativen Funktion setze ich den Ruckgabewert mit JS_SET_RVAL)
        // In V8 ist es komfortabler mit scope.Close(rval); aber das ist egal, es sieht nur so aus
        JS_SET_RVAL(cx, vp, INT_TO_JSVAL(23));
        return JS_TRUE;
        

    Der meistbenutzte und vielseitige Typ in Spidermonkey.

    Halt die JavaScript Values. Number, String, Boolean, Object, Function, Null, Undefined.

    	// Zum Beispiel in einer nativen Funktion
        	static JSBool nativeFunc (JSContext *cx, unsigned argc, jsval *vp) {
    	    jsval *argv = JS_ARGV(cx, vp);
    
    	    // Gibt alle Funktionsargumente mit Space getrennt aus zur Demo auf stdout aus
    		for (int i = 0; i < argc; i++) {
    		    if (i > 0) std::cout << " ";
    		    std::cout << JS_EncodeString(cx, JS_ValueToString(cx, argv[i]));
    		}
    		std::cout << std::endl;
    	
    	    JS_SET_RVAL(cx, vp, JSVAL_VOID); 
    	    return JS_TRUE; // signalisiere OK
    	}
    
    	// Wie man diese native Funktion zu global.nativeFunction = function nativeFunction (); macht
    	JSFunction *fn; // Wenn man keinen Pointer braucht kann man den auch im Code weglassen
            if ((fn = JS_DefineFunction(cx, global, "nativeFunktion", nativeFunktion, 0, 0)) == NULL) {
    	    // error
    	} // else fn assigned
        

    Zu Beginn ist der folgende Text eine Quasi-uebersetzung der http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/jsval Seite.

    jsval ist der type der JavaScript values in der JSAPI.

    Eine C/C++ Variable vom Typ jsval kann exakt den gleichen Wert halten, wie eine JavaScript var oder property (string, number, object, boolean, null, undefined. Arrays, functions und Errors sind objects.)

    jsval ist ein variierender Typ, dessen exakte Repraesentation von der Architektur der Mashine abhaengt. Darum soll man sich beim Einbetten nicht auf solche details verlassen.

    jsvals sind nicht richtig type-safe.

    JSVAL_MACROS

    type test type constants/constructors accessors
    JSVAL_IS_NULL(v) null JSVAL_NULL
    JSVAL_IS_VOID(v) undefined JSVAL_VOID
    JSVAL_IS_BOOLEAN(v) boolean JSVAL_TRUE, JSVAL_FALSE, BOOLEAN_TO_JSVAL(b) JSVAL_TO_BOOLEAN(v)
    JSVAL_IS_NUMBER(v), JSVAL_IS_INT(v), JSVAL_IS_DOUBLE(v) number JSVAL_ZERO, JSVAL_ONE, INT_TO_JSVAL(i), DOUBLE_TO_JSVAL(d) JSVAL_TO_INT(v), JSVAL_TO_DOUBLE(v
    JSVAL_IS_STRING(v) string STRING_TOP_JSVAL(str) JSVAL_TO_STRING(v), JS_GetStringChars(str), JS_GetStringLength(str)
    !JSVAL_IS_PRIMITIVE(v) object OBJECT_TO_JSVAL(obj) JSVAL_TO_OBJECT

    Warnung: Die JSVAL_TO_x Funktionen verwenden C casts und bit twiddling (twiddling?). Sie sind nur sicher, wenn du bereits weisst, dass die jsval exakt dem richtigen Typen entspricht. Wenn man zum Beispiel JSVAL_TO_DOUBLE auf einem int jsval ruft, kann es zu unvorhersehbaren Verhalten und einem Crash kommen. [Uebersetzt aus SpiderMonkey/JSAPI_Reference/jsval]

    jsvals koennten auf einen String oder ein Objekt zeigen, was bereits im GC Heap ist. Der GC pickt alles auf, was nicht irgendwie auf dem Boden festgenagelt ist, das kann auch dein JSObject betreffen. Die Loesung ist, SpiderMonkey zu sagen, dass man das Objekt verwendet und es spaeter mitzuteilen, wenn man fertig ist.

    http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/jsval

    jsint

    Wenn ihr Wissen wollt, wie viele Integer Typen es hier gibt. Was ihr wissen MUESST.

    jsint und jsuint sind 32-bit Integer Typen.

    jsword und jsuword sind Pointer-grosse Integer Typen

    intN und uintN sind Integertypen mit der gleichen Groesse wie die nativen int Typen der Platform.

    http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/jsint

    jsid

    ID der Property auf die zugregriffen wird.

    http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/jsid

    Ein paar Methoden nutzen jsid statt jsval.

    Exceptions

    	JSExceptionState *state;
        

    JS_SetPendingException setzt die Exception, welche dann im context cx geworfen werden soll.

    	void JS_SetPendingException(JSContext *cx, jsval v);
        

    Compartments

    Das Konzept mehrere Heaps statt einen fuer alle Objekte zu haben, wird mit den Compartments gefuellts. Das ist das Wort fuer je einen separaten Heap. Mehr Informationen gibt es auf den Seiten. Und statt JS_NewGlobalObject rufe ich in der Regel JS_NewCompartmentAndGlobalObject.

    Garbage Collection

    Internals

    http://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Garbage_Collection

    http://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/GC/Exact_Stack_Rooting

    Einfache Statistik, die der GC zur Laufzeit festhaelt: http://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/GC/Statistics_API

    Rooting Guide

    http://developer.mozilla.org/en-US/docs/SpiderMonkey/GC_Rooting_Guide

    Tips

    http://developer.mozilla.org/en/SpiderMonkey_Garbage_Collection_Tips

    Garbage Collector Funktionen

    Nach den Links zu den Dokumenten hier noch die Übersicht über die Funktionen.

    JS_GC

    Eine volle Garbage Collection im JS memory pool durchfuehren: JS_GC

        // void JS_GC(JSContext *cx);
        
        // ...code...
        JS_GC(cx);
        // ...code...
        

    Mit JS_SetGCCallback kann man noch Hooks adden, die bei der Garbage Collection durchgefuehrt werden.

        // JSGCCallback JS_SetGCCallback(JSRuntime *rt, JSGCCallback cb);
        // Gibt den letzten Callback zurueck, wird ein neuer gesetzt.
        
        old_cb = JS_SetGCCallback(rt, new_cb);
        
        typedef enum JSGCStatus {
    	JSGC_BEGIN, // Start of GC	
    	JSGC_END, 	// End of GC
    	JSGC_MARK_END, // End of Marking
    	JSGC_FINALIZE_END /* Obsolete since JSAPI 13 */
        } JSGCStatus;
        typedef JSBool (*JSGCCallback)(JSContext *cx, JSGCStatus status);
            
    

    Der Callback kann JS_IsAboutToBeFinalized benutzen um Weak References zu JSObjects aufzuraeumen, das sind Pointer, die nicht vom GC getraced werden koennen.

    JS_MaybeGC

    A typical JSAPI application should also run garbage collection periodically. An application can do this by periodically calling JS_MaybeGC

        // code laeuft
        // lass mal kurz gucken...
        JS_MaybeGC(cx);
        // code geht weiter...
    

    Von JSBranchCallbacks und JSOperationCallbacks aus gerufen kann JS_MaybeGC den Speicherverbrauch unten halten und die Performance verbessern.

    JSRuntime

    http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/JSRuntime

    JSContext

    http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/JSRuntime

    JSGlobal

    http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/JSGlobal

    JSNative

    JSNative ist der Datentyp fuer die native Implementation von JavaScript Funktionen.

    APIs wie http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/JS_InitClass und http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/JS_DefineFunctions erzeugen Methoden auf JavaScript Objekten, welche als JSNative callbacks zurueckgegeben werden...

    	typedef JSBool (*JSNative)(JSContext *cx, uintN argc, jsval *vp);
        

    Zu JSNative gehoeren auch noch ein paar Macros.

    JS_CALLEE(cx, vp) Gibt das Funktionsobjekt in Form einer jsval zurueck. Native Methoden duerfen JS_CALLEE NICHT nach JS_SET_RVAL rufen, weil das im gleichen Stack gespeichert wird.
    JS_THIS(cx, vp) Gibt das this Argument zurueck, oder NULL bei einem Fehler.
    JS_THIS_OBJECT(cx, vp) Gibt JSObject*, oder NULL beim Fehler zurueck. Native Methoden duerfen die Funktion nicht nach JS_SET_RVAL rufen. JS_THIS_OBJECT kann JS_CALLEE rufen.
    JS_ARGV(cx, vp) Gibt den argv Pointer zurueck. Zeigt auf Element 0 des argc jsvals array, den arguments die der caller gibt.
    JS_RVAL(cx, vp) Die jsval, welche momentan im return-value slot ist
    JS_SET_RVAL(cx, vp, value) Setzt den Return Wert der nativen Funktion. Man kann das Ding mehrmals mit einem Ruf mit JSNative rufen, falls JSNative JS_TRUE zurueckgibt, wird der letzte Wert der eingesetzt wurde an den Aufrufer (Caller) zurueckgegeben.

    http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/JSNative

    Functions

    Ich denke mal, hier landen die function-Docs.

     // Aus dem Phrasebook
     
     // JavaScript:
     // 1. Einfach in einem Schritt
        function j4f () {
        }
    
     // C/C++:
     // 1. Die native Funktion
     JSBool j4f (JSContext *cx, uintN argc, jsval *vp) {
        JS_SET_RVAL(cx, vp, JSVAL_NULL);
        return JS_TRUE;
     }
     // 2. Und man muss die noch einrichten 
     if (!JS_DefineFunction(cx, global, "j4f", &j4f, 0, 0)) {
        fprintf(stderr, "Error defining function j4f()\n");
     }
        
    
    // Funktionsdefinition (nativ)
    
        static JSBool meineFunktion (JSContext *cx, unsigned int argc, jsval *vp) {
    	jsval *argv = JS_ARGV(cx, vp); // brauch ich nicht (keine args)
    	if (true) {
    	    // Ruckgabewert (return) von meineFunktion wird gesetzt, nicht durch return bestimmt.
    	    JS_SET_RVAL(cx, vp, STRING_TO_JSVAL((JSString *)"Returnwert der Funktion"));
    	    
    		// cout << JSVAL_TO_STRING(argv[0]);
    	    
    	    return JS_TRUE; // zeigt Erfolg an
    	} else {
    	    return JS_FALSE; // zeigt an, dass die Funktion schiefging
    	}	    
        }
    
    // Definition der JavaScript Schnittstelle (global.meineFunktion)
    
        const int minargs = 0;
        if (!JS_DefineFunction(cx, global, "meineFunktion", meineFunktion, minargs, 0)) {
    	/* Fehler */
        } 
    
    

    JS_NewFunction, JS_DefineFunction, JS_CompileFunction geben JSFunction *fun zurück.

    	JSFunction *JS_NewFunction (JSContext *cx, JSNative call, uintN nargs, uintN flags, JSObject *parent, const char *name);
    	// cx = context
    	// call = native C Funktion mit der JSAPI (static JSBool nativeFunc (JSContext *cx, ...)
    	// nargs = Anzahl der Argumente
    	// flags = Reserviert. Immer 0 angeben fuer this argument
    	// parent = Pointer zum Parent Objekt der Funktion, falls NULL wird ein default Objekt genutzt
    	// name = Function Name oder NULL, falls kein Name 
    	// --- 
    	// NULL = Fehler
    	// JSFunction *fun = Erfolg	
        
        

    Name der Funktion erhalten

    	JSString * JS_GetFunctionId(JSFunction *fun);
        

    EvaluateScript und viel mehr

    JS_CompileFunction und JS_CompileScript, sowie JS_EvaluateScript

    Decompile gibt es auch

    Decompiling Function

    Function Callback

    Introduced in JS 1.8.5

    JS_SetFunctionCallback ermoeglicht das Function tracing (siehe User Guide)

    	// Rufe einen Callback wann auch immer eine Funktion invoked oder exited wird
    	// Damit kann man die Exekution tracen
    	void JS_SetFunctionCallback (JSContext *cs, JSFunctionCallback fcb);
        

    Die Callback Syntax (so muesst ihr eure Funktion deklarieren)

    	// JSFunctionCallback
    	typedef void (*JSFunctionCallback)(const JSFunction *fun, const JSScript *scr, const JSContext *cx, JSBool entering);
        
  • JSFunction
  • JSFunctionCallback
  • JS_SetFunctionCallback
  • JSScript

    Calling Function

    Aus dem Cookbook. foo ist eine globale Funktion.

    // foo ist Globale Funktion
    // JS
        var r = foo(); // foo ist eine globale Funktion
        jsval r;
        if (!JS_CallFunctionName(cx, JS_GetGlobalObject(cx), "foo", 0, NULL, &r)) {
    	// err
    	return JS__FALSE;
        }
    

    f ist eine lokale Variable. Auch hier gibt es Unterschiede, wie man sie aufruft.

    // f ist Lokale Variable 
        var r = f()
        jsval r;
        if (!JS_CallFunctionValue(cx, NULL, f, 0, NULL, &r)) { // FunctionValue = jsval (eine function als jsval)
    	return JS_FALSE;
        }
    
    • JS_CallFunction
      	JSBool JS_CallFunction (JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, jsval *argv, jsval *rval);
      	// cx = Der Context, in dem das laufen soll
      	// obj = Das this Objekt, wo die Funktion zu finden ist
      	// fun = Die Funktion, die gerufen werden soll
      	// argc = Der arguments counter
      	// argv = Der arguments vector
      	// rval = enthaelt den Return Wert der Funktion nach der Ausfuehrung (der, der mit z.B. JS_SET_RVAL gesetzt wurde, in der Funktion die gerufen wird)
          
          
    • JS_CallFunctionName
      	// Rufe Funktion (Objektmethode oder Global) bei ihrem Namen auf
      	// Enspricht object.meineFunktion(); (meineFunktion == global.meineFunktion)
      	
      	JSBool JS_CallFunctionName (JSContext *cx, JSObject *obj, const char *name, uintN argc, jsval *argv, jval *rval);
      	// ---
      	// cx = der Kontext
      	// obj = Das this Objekt
      	// name = 
      	// argc = Anzahl der Argumente der Funktion
      	// argv = Argumente der Funktion
      	// rval = Der return Wert der Funktion nach
      	// --- 
      	// gibt JS_TRUE im Erfolgsfall zurueck
      	// oder JS_FALSE beim Fehlschlag
          
    • JS_CallFunctionValue
          // JS_CallFunctionValue (rufe JavaScript Funktion (== function value))
          // Entspricht wohl fval.apply(obj, [].slice.call(argv, 0, argc)) in JavaScript
          
      	JSBool JS_CallFunctionValue (JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval *argv, jsval *rval);
      	// ---
      	// cx = Context
      	// obj = Das "this" Argument
      	// fval = Die Funktion, die man rufen will
      	// argc = Die Anzahl der Argumente zum uebergeben
      	// argv = Pointer zu den Arguments, oder argc == 0, dann argv = NULL		
      	// rval = Enthaelt den Return Wert der JavaScript Funktion die gerufen wird nach dem Aufruf von JS_CallFunctionValue
      	// ---
      	// gibt JS_TRUE zurueck, bei Erfolg
      	// oder JS_FALSE bei Misserfolg (dann ist rval unspezifiziert)
          

    Name einer Funktion auslesen.

    	JSString *functionName = JS_GetFunctionId(fun);
        

    Konvertiere jsval nach JSFunction

    	JSFunction *JS_ValueToFunction (JSContext *cx, jsval v);
    	// cx = context
    	// v = value zum umwandeln
    	
    	jsval *argv;
    	JSFunction *fun;
    	fun = JS_ValueToFunction(cx, argv[0]);
        

    Function Definition

    Mit DefineFunctions kann man Funktionen auf einem Objekt (dem globalen oder einem lokalen) definieren. Man kann eine Funktion mit JS_DefineFunction, oder mehrere mit JS_DefineFunctions definieren.

    • JS_NewFunction

      Der folgende Code entspricht in etwa function functionName () { return undefined; }.

      	// JSFunction *JS_NewFunction (JSContext *cx, JSNative call, uintN nargs, uintN flags, JSObject *parent, const char *name);
      
      	// Die native Funktion
      	static JSBool functionBody(JSContext *cx, uintN argv, jsval *vp) {
      	    jsval *argv = JS_ARGV(cx, vp);
      	    JS_SET_RVAL(cx, vp, JSVAL_VOID); // gebe undefined zurueck
      	    return JS_TRUE;
      	}
      	// Die Funktion binden.
      	JSFunction *fun = JS_NewFunction(cx, functionBody, 0, 0, &global, "functionName");
      

    Es gibt auch Value To Function

    LocalRootScope - verhindert, dass der GC das wegraeumt, worauf der Pointer gerade zeigt.

    • JS_EnterLocalRootScope

      Eine gerootete Variable wird nicht vom GC weggeraeumt. Lokale Root Scopes schuetzen neue Objekte, Strings, Doubles, ohne dass man der Engine ueber jede Variable berichten muss.

          JSBool my_GetProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp) {
      	JSBool ok;
      	if (!JS_EnterLocalRootScope(x)) return JS_FALSE;
      	ok = my_GetPropertyBody(cx, obj, id, vp);
      	JS_LeaveLocalRootScope(cx);
      	return ok;
          }
          // Vom MDN siehe JS_EnterLocalRootScope
      
    • JS_LeaveLocalRootScope
    • JS_ForgetLocalRoot
    • JS_AddRoot
    • JS_RemoveRoot

    Macros

    AEinige Macros, die zu den Funktionen gehoeren, beginnen mit JSFUN_. Das sind zum Beispiel:

  • Arguments

    Arrays

    JSObject *array;/h2>
        // Aus dem Cookbook
        
        // JavaScript
        var x = [];
        
        // JSAPI
        JSObject *x;
        if ((x = JS_NewArrayObject(cx, 0, NULL)) == NULL) {
    	// error
        }
    

    JSClass

    Eine Struktur mit Callback Funktionen fuer addProperty, delProperty, getProperty, eine StrictPropertyOp fuer setProperty, eine JSEnumerateOp fuer enumerate, und so weiter. Wenn man ein Objekt erzeugt, dann gehoert eine JSClass dazu. Und deren Verhalten kann man hier beeinflussen. So lassen sich zwar nicht crossbrowserweit, aber mit der API wunderbare Objekte in der Art einem konfigurierten Proxy und mit anderem Verhalten erzeugen.

    	struct JSClass {
    	    char *name;
    	    uint32 flags;
    	    /* function pointers */
    	    JSPropertyOp addProperty;
    	    JSPropertyOp delProperty;
    	    JSPropertyOp getProperty;
    	    JSStrictPropertyOp setProperty;
    	    JSEnumerateOp enumerate;
    	    JSResolveOp resolve;
    	    JSConvertOp convert;
    	    JSFinalizeOp finalize;
    	    /* members */
    	    JSClassInternal reserved;
    	    JSCheckAccessOp checkAccess;
    	    JSNative class;
    	    JSNative construct;
    	    JSXDRObjectOp xdrObject;
    	    JSHasInstanceOp hasInstance;
    	    JSTraceOp trace;
    	};
        

    Die Stubs der PropertyOp bis FinalizeOp kann man ueberall dort einsetzen, wo solche Funktionen erwartet werden.

        
    // Default implementations of the required callbacks in JSClass.
    JSBool JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
    JSBool JS_EnumerateStub(JSContext *cx, JSObject *obj);
    JSBool JS_ResolveStub(JSContext *cx, JSObject *obj, jsid id);
    JSBool JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
    void JS_FinalizeStub(JSContext *cx, JSObject *obj); // Obsolete since JSAPI 15
    

    JSExtendedClass

    Obsolete by JavaScript 1.8.5 (bedeutet, man sollte sie nicht mehr in neuen Projekten einsetzen).

        struct JSExtendedClass {
    	JSClass base;
    	JSEquality equality;
    	JSObjectOp outerObject;
    	JSObjectOp innerObject;
    	JSInteratorOp iteratorObject; // Added in 1.8
    	JSObjectOp wrappedObject; // Added in 1.8
    	// ... and additional reserved fields.
        };
        

    Split_object war allemal faellig und ein Architektur-Fix für das window Objekt. Es wird darauf hingewiesen, dass es in Mozilla gebraucht wurde und man es in anderen Projekten vermeiden sollte. Darauf wird ausfuehrlich erlaeutert, warum es split objects und den innerObject und outerObject Hook fuer JSExtentedClass gibt..

    Auch JSPrincipals kommen anderem Kontext dran, SpiderMonkey lauft die Scope Chain bis zum nächsten JSPrincipals attached JSObject hoch, ueber die (JSPrincipals) ich noch schreiben muss.

    JSObject

    Object

    JS_GetFunctionObject

        
    	JSObject *JS_GetFunctionObject (JSFunction *fun);
    	// fun = Pointer zu einer JSFunction
    	
        

    Da ist so eine Parent Funktion, besser man findet raus, was geht.

    	JSObject *parent = JS_GetParent(cx, obj);
    	
    	JSBool ok = JS_SetParent(cx, otherObj, parent);
        

    Standard Library Objekte haben das globale Objekt als Parent. Das ist das Objekt, auf dem die Funktion definiert wurde.

    Alle Objekte, die mit einem Constructor und new erzeugt wurden, haben den Constructor als Parent. Ein Objekt, was von einem Script via implizierter Konversion, erzeugt wird ({a:1,b:2} oder [1,2,3] oder [[ToObject]]), hat das globale Objekt als parent. parent ist also schon wichtig. parent folgt Regeln.

    parents einer Funktion hängen vom Scope ab. Wenn keine Function die andere Funktion einschliesst, dann ist der globale Scope parent der Funktion, sonst die Funktion, die sie einhuellt. Das ist ein wichtiges Ding hier: parent und Closure

    	JSObject *parent = JS_GetParent(obj);
        

    Und JS_SetParent nimmt gleicht drei Parameter. Den Context, das Objekt, und dessen neues Parent Objekt.

    	JSBool ok = JS_SetParent(cx, otherObj, parent);
        

    Object Property Definition

    Object.defineProperty beziehungsweise Object.defineProperties

    	
    	// In JavaScript:
    	// Define one Property on an object
    	Object.defineProperty(obj, "foo", {
    	    value: "bar",
    	    writeable: false
    	});
    	
    	// Plural in JavaScript
    	// Define multiple Properties on one object
    	Object.defineProperties(obj, {
    	    "foo": {
    		value: "bar"
    		writeable: false
    	    },
    	    "bar": {
    		value: "baz",
    		enumerable: true
    	    }
    	});
        

    Das konnte man in Spidermonkey wohl schon immer machen, und mir kommt Object.defineProperty eher wie eine Verwirklichung von JS_DefineProperty vor.

    JSPropertySpec

    	struct JSPropertySpec {
    	    const char *name;
    	    int8 tinyid;
    	    uint8 flags;
    	    JSPropertyOp getter;
    	    JSPropertyOp setter;
    	};
        

    Eine Property

    	char *prop = "foo";
    	char *value = "Eddie";
    
    	JSPropertySpec foo = {
    	    "foo",	// name
    	    0, // tinyid (enum) wenn nicht genutzt, dann 0
    	    JSPROP_READONLY, // flags
    	    NULL,	// getter
    	    NULL	// setter
    	};
    	
    	JS_DefineProperty(cx, obj, &foo);
        

    Mehrere Properties

    	static JSPropertySec pspec[] = {
    	    { "foo", 0, JSPROP_READONY, NULL, NULL },
    	    { "bar", 0, JSPROP_ENUMERATE, NULL, NULL },
    	    { 0, 0, 0, 0, 0 }  // terminierender Record
    	};
    	
    	JS_DefineProperties(cx, obj, &pspec);
        

    Getter und Setter

    	var obj = {
    	    get info () {
    		return "information";
    	    },
    	    set dark (v) {
    		this._dark = v;
    	    }
    	};
    	
    	var obj2 = Object.create(Object.prototype, {
    	    info: {
    		value: "information",
    		writeable: false,	// JSPROP_READONLY
    		configurable: false	// JSPROP_PERMANENT (? uebe noch)
    	    }
    	});
        

    JS_GetPropertyAttributes und JS_SetPropertyAttributes sind Funktionen, mit denen man die magischen JSPROP_* (uint attrs) setzen/lesen kann.

    	JSBool JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name, uintN attrs, JSBool *foundp);
    	JSBool JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, uintN attrs, JSBool *foundp);
        
    Flag Sinn und Zweck
    JSPROP_ENUMERATE Property ist sichtbar in for..in loops (enumerable: true)
    JSPROP_READONLY Property ist nur lesbar (writeable: false)
    JSPROP_PERMANENT Property kann nicht geloescht werden
    JSPROP_EXPORTED Property kann von anderen Objekten importiert werden
    JSPROP_INDEX Property ist ein Index in einen Array von Properties, und wird gecastet in ein const char *

    DefineFunctions

    static JSFunctionSpec system_functions[] = {
        { "log", log, LOG_MINARGS, 0 },
        { 0,0,0,0 }
    };
    

    JSString

    char *, Handle<String>, JSString *, std::string

    Ich muss Konversionstests machen.

    	// Sourcecode Konversionstest
    	JSString *jstr;
    	char *cstr;
    	std::string *ccstr = new std::string("Hello");
    	// Dann lasse mal casten und coercen...
        

    Neben JS_malloc gibt es JS_strdup was eine Kopie des nullterminierten Strings alloziert und einen Pointer zur Kopie zurueckgibt.

    	char * JS_strdup(JSContext *cx, const char *s);
        

    Die Funktionen habe ich gesucht, um mit JSString und (const char *)"Zeichenketten" arbeiten zu koennen.

    My second own Example

    Jetzt sollte ich Funktionen von der Shell aus rufen... und zwar C Funktionen, die ich selbst schreibe. Dann ist die Grundlage fuer einen Interpreter auch schon ausprobiert. Dann muss man die libs, die man nutzt lernen, sowie diese SpiderMonkey Library. Ich denke zuerstmal an libuv, um mit dem Netzwerk zu reden, und wegen der asynchronen Bauweise, an eben die. Das ist dann die Core Library aus dem node.js Projekt.

    libuv.html existierte sogar schon in meinem Verzeichnis. Noch ist damit aber nichts geschehen, das war nur eine Idee.

    Ok, hier ist mein verbesserter REPL. In meinem ersten Beispiel wurde bis zum STRG-D gelesen, wenn ich mich richtig entsinne, es wurde zwar Zeile fuer Zeile ein neues Prompt geschrieben, aber evaluiert wurde erst am Ende des Codes. Hier wird nun jede Zeile evaluiert. Und das gute ist, es wird durch das JSContext Objekt, denke ich, entsprechend alles von Schritt zu Schritt beibehalten.

    // Mein zweites Beispiel: Spiderman mit log Funktion
    // Ist bereits ein REPL mit einer Funktion "log"
    // log: Die einen oder mehrere Parameter als Strings mit Space getrennt und eine newline ausgibt.
    
    #include <jsapi.h>
    #include <iostream>
    #include <string>
    
    static JSClass global_class = {
        "global",
        JSCLASS_GLOBAL_FLAGS,
        JS_PropertyStub,
        JS_PropertyStub,    
        JS_PropertyStub,    
        JS_StrictPropertyStub,    
        JS_EnumerateStub,        
        JS_ResolveStub,    
        JS_ConvertStub,    
        JS_FinalizeStub,    
        JSCLASS_NO_OPTIONAL_MEMBERS
    };
    
    void reportError (JSContext *cs, const char *message, JSErrorReport *report) {
        // lieber cerr nehmen? Werde ich merken, wenn ich files mit >> erzeuge, ob ich es lesen will.
        std::cout << (report->filename ? report->filename : "") << ":" << (unsigned int) report->lineno << ":" << (char *)message << std::endl;
    }
    
    int say(const char *str, int rc = 1) {
        std::cout << str << std::endl;
        return rc;
    }
    
    void prompt () {
        // mein REPL heisst jetzt spiderman
        std::cout << "Spiderman> ";
    }
    
    
    #define LOG_MINARGS 1
    static JSBool log (JSContext *cx, unsigned argc, jsval *vp) {
        jsval *argv = JS_ARGV(cx, vp);
        for (int i = 0; i < argc; i++) {
    	if (i > 0) std::cout << " ";
    	std::cout << JS_EncodeString(cx, JS_ValueToString(cx, argv[i]));
        }
        std::cout << std::endl;
        JS_SET_RVAL(cx, vp, JSVAL_VOID); 
    }
    
    static JSFunctionSpec system_functions[] = {
        { "log", log, LOG_MINARGS, 0 },
        { 0,0,0,0 }
    };
    
    
    int main(int argc, char **argv) {
        JSRuntime *rt;
        JSContext *cx;
        JSObject *global;
    
        // Runtime erzeugen
        rt = JS_NewRuntime(8 * 1024 * 1024);
        if (rt == NULL) {
    	return say("Can not create JSRuntime, returning 1;");
        } else {
    	say("Created JSRuntime");
        }
    
        
        // Context erzeugen
        cx = JS_NewContext(rt, 8192);
        if (cx == NULL) {
    	return say("Can not create JSContext, returning 1;");
        } else {
    	say("Created JSContent");
        }
        
        // Error Reporter setzen - Die Funktion gibt den vorherigen Callback zurueck
        if (JS_SetErrorReporter(cx, reportError) == NULL) {
        	say("No previous Error Reporter has been set.");
        }
        // Ich teste jetzt, ob die Funktion auch zurueck gegeben wird. Die Antwort ist: JA.
        if (JS_SetErrorReporter(cx, reportError) == reportError) {
    	say("The previous Error Reporter is correctly returned.");
        }
        
        JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
        JS_SetVersion(cx, JSVERSION_LATEST);
        
        // Das GLOBALE OBJEKT setzen
        global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
        if (global == NULL) {
    	return say("Error creating global object with new compartment.");
        }
        
        // Jetzt String, Object, Array, Date initialisieren
        // Achtung: Es gibt kein Console.say Interface. Das kann ich schreiben, etc. pp.
        
        if (!JS_InitStandardClasses(cx, global)) {
    	return say("Can not initialize standard JS Classes");
        } else {
    	say("success JS_InitStandardClasses");
        }
        
    
    // Das ist die Stelle, wo mein Application Code hinkommt, sagt Brendan
    // Hier ist mein REPL. Danke fuer die geile Sprache.
    
        std::string s;    
        jsval rval;
        JSString *str;
        JSBool ok;
        const char *filename = "Spiderman-REPL";
        uintN lineno = 0;
    
    
        say("Defining my personal C Functions like log(s, ...r)");
        
        ok =  JS_DefineFunctions(cx, global, system_functions);
        //ok = JS_DefineFunction(cx, global, "log", log, LOG_MINARGS, 0);
        
        if (!ok) {
    	say("Failed defining my funcitons");
        } else {
    	say("Defined my functions");
        }
        // Jetzt muesste man in der Shell mit log(string) was loggen koennen
    
        say("#### Gib mir some SpiderMonkey JavaScript...");
        
        char c;
        bool exit = false;
        
        prompt();
    
        // Der Read Loop  (R)
    
        while (!exit) {
    	c = std::cin.get();
    	if (!std::cin.eof()) s+=c;
    	else exit = true;
    	if (c == '\n') {
    	    ++lineno;
    	    // In node wird das je Zeile gemacht.    
    	    // Eingabe evalen    (E)
    	    ok = JS_EvaluateScript(cx, global, s.c_str(), s.length(), filename, lineno, &rval);
    	    // letzter return Wert   
    	    if (rval == NULL | rval == JS_FALSE) {
    		say("Error executing input: jsval rval ist NULL oder JS_FALSE");
    	    }
    	// Manchmal kommt auch undefined raus, wenn man "" evaluiert...    
    	// oder die Funktion undefined zurueckwirft.
    	    str = JS_ValueToString(cx, rval);
    	    say(JS_EncodeString(cx, str));
    	// Das kann ich also verbessern.    
    	    s = ""; // Meinen "Input Buffer" leeren
    	    prompt();
    	}
        }
        
        // Der Loop wurde mit CTRL-D verlassen oder das mit < umgeleitete File ist zu Ende
        
        // Aufraeumen
        // des Programms    
        JS_DestroyContext(cx);
        JS_DestroyRuntime(rt);
        JS_ShutDown();
        return 0;
    }
    

    sm2nd.cpp - der Source Code als File.

    Und das ist das Ergebnis. Wie man sieht, habe ich jetzt einen eigenen REPL. Den Original-REPL, so wie ich ihn kannte, kann man bei node.js bewundern, aber auch die jsshell hat es in sich. Besonders hat sie Sachen, die V8 nicht hat, wie zum Beispiel die Generator Functions.

    Created JSRuntime
    Created JSContent
    No previous Error Reporter has been set.
    The previous Error Reporter is correctly returned.
    success JS_InitStandardClasses
    Defining my personal C Functions like log(s, ...r)
    Defined my functions
    #### Gib mir some SpiderMonkey JavaScript...
    Spiderman> undefined
    Spiderman> log
    function log() {
        [native code]
    }
    Spiderman> log("Yeah");
    Yeah
    undefined
    Spiderman> 
    

    Referenz finden

    Einfach den gesuchten Namen hinter das JSAPI_Reference Verzeichnis schreiben, und normalerweise erscheint dann ein Artikel, oder es wird zum "mozilla Persona login" weitergeleitet, was darauf hindeutet, dass die Seite nicht existiert...

    Also, wie es deutlich auffaellt, kann man mit http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/* (also das Verzeichnis gefolgt von z.B. JSRuntime oder JS_InitStandardClasses) sich zu praktisch jedem Datentyp (JS*) oder jeder Funktion (JS_*) oder jedem Macro (die GROSSGESCHRIEBENEN) Informationen abrufen. Beim verlinken der Grundbegriffe fiel mir die Struktur dann bereits auf.

    libuv und SpiderMonkey

    Nachdem ich den REPL Spiderman getauft hatte, noch gibt er staendig den jsval return Code aus, auch mehrmals, fiel mir ein, ich koennte fuer die ersten nativen Funktionen die libuv nehmen, weil darin die asynchronen Event Operationen fuer node.js gespeichert sind.

    Wie ich bereits bemerke, scheint das gar nicht schwer zu sein, libuv zu benutzen.

    Mir ist bereits eine funktionierende Variante eingefallen. Wenn man dem libuv Doc folgt, liest man, dass ich zuerstmal Listings vom uvbook ausprobiert habe, und bemerken muss, dass die getaddrinfo Slide vom Belder nicht kompilieren wollte, was aber auch mein Fehler sein kann, kann aber auch die Slide sein, selbst bei Crock habe ich Type-O´s gefunden, dann habe ich mal ausprobiert, ob ich den Loop einfach laufen lassen kann, waehrend das Programm geradeaus den REPL startet.

    	uv_loop_t *loop = uv_default_loop();
    	
    	uv_run(loop);
    	
    	while (true) {
    	    // Mein Spidermonkey REPL
    	}
        
    	// Geht zumindest, dass der REPL laueft
    	// Jetzt muss ich nur noch ein paar UV Funktionen
    	// einbauen um auszuprobieren, ob das ueberhaupt laeuft.
    	
        

    Mein drittes Beispiel

    Beispiel: TTY Funktion tty() im Spiderman REPL

    Der erste Versuch mit libuv zusammen zu arbeiten.

    Hier habe ich eine uv_tty_ Funktion, die ich vorhin aus dem Buch gemacht hatte, einfach mal in das Listing eingebaut. Wenn man die Shell startet, dann kann man tty() eingeben und das rote Hello TTY aus dem uvbook erscheint.

    #include <jsapi.h>
    #include <iostream>
    #include <string>
    
    #include <uv.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    
    #include <malloc.h>
    
    // vars libuv:
    
    uv_loop_t *loop;
    uv_tty_t tty;
    
    // decl spidermonkey:
    
    // ich fuer den repl
    bool constructor();
    void meinREPL();
    void destructor();
    
    // eich
    jsval rval;
    JSString *str, *oldstr;
    JSBool ok;
    const char *filename = "stdin";
    uintN lineno = 0;
    
    // Spidermonkey
    JSRuntime *rt;
    JSContext *cx;
    JSObject *global;
    
    static JSClass global_class = {
        "global",
        JSCLASS_GLOBAL_FLAGS,
        JS_PropertyStub,
        JS_PropertyStub,    
        JS_PropertyStub,    
        JS_StrictPropertyStub,    
        JS_EnumerateStub,        
        JS_ResolveStub,    
        JS_ConvertStub,    
        JS_FinalizeStub,    
        JSCLASS_NO_OPTIONAL_MEMBERS
    };
    
    void reportError (JSContext *cs, const char *message, JSErrorReport *report) {
        // lieber cerr nehmen? Werde ich merken, wenn ich files mit >> erzeuge, ob ich es lesen will.
        std::cout << (report->filename ? report->filename : "") << ":" << (unsigned int) report->lineno << ":" << (char *)message << std::endl;
    }
    
    bool say(const char *str, bool ok = false) {
        std::cout << str << std::endl;
        return ok;
    }
    
    void prompt () {
        // mein REPL heisst jetzt spiderman
        std::cout << "Spiderman> ";
    }
    
    #define LOG_MINARGS 1
    static JSBool log (JSContext *cx, unsigned argc, jsval *vp) {
        jsval *argv = JS_ARGV(cx, vp);
        for (int i = 0; i < argc; i++) {
    	if (i > 0) std::cout << " ";
    	std::cout << JS_EncodeString(cx, JS_ValueToString(cx, argv[i]));
        }
        std::cout << std::endl;
        JS_SET_RVAL(cx, vp, JSVAL_VOID); 
    }
    
    #define REQUEST_MINARGS 3
    static JSBool request (JSContext *cx, unsigned argc, jsval *vp) {
        jsval *argv = JS_ARGV(cx, vp);
        // hier kommt jetzt die LIBUV ins Spiel und nicht nur hier.    
        JS_SET_RVAL(cx, vp, JSVAL_VOID);
    }
    
    static JSBool print_tty (JSContext *cx, unsigned argc, jsval *vp) {
        jsval *argv = JS_ARGV(cx, vp); // brauch ich nicht (keine args)
    
        uv_tty_init(loop, &tty, 1, 0);
        uv_tty_set_mode(&tty, 0);
        
        if (uv_guess_handle(1) == UV_TTY) {
    	uv_write_t req;
    	uv_buf_t buf;
    	buf.base = (char *)"\033[41;37m";
    	buf.len = strlen(buf.base);
    	uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL);
        
        }
        
        uv_write_t req;
        uv_buf_t buf;
        buf.base = (char *)"Hello TTY!\n";
        buf.len = strlen(buf.base);
        uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL);
    
    
        if (uv_guess_handle(1) == UV_TTY) {
    	uv_write_t req;
    	uv_buf_t buf;
    	buf.base = (char *)"\033[20;12m";
    	buf.len = strlen(buf.base);
    	uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL);
        
        }
    
        uv_tty_reset_mode();
    //    uv_tty_stop(loop, &tty); // gibt es nicht
        // Das funktioniert noch nicht, dass ich jetzt hier die Farbe wiederherstelle????
        
        JS_SET_RVAL(cx, vp, JSVAL_VOID); // returns undefined
        // return uv_run(loop);
    }
    
    
    static JSBool exitRuntime (JSContext *cx, unsigned argc, jsval *vp) {
        jsval *argv = JS_ARGV(cx, vp); // brauch ich nicht (keine args)
        // Jetzt argv[0] holen und als return Code zurueckgeben
        int rc = JSVAL_TO_INT(argv[0]);
        
        destructor();
        exit(rc);
    }	
    
    static JSFunctionSpec system_functions[] = {
        { "log", log, LOG_MINARGS, 0 },		// noch mit cout
        { "request", request, REQUEST_MINARGS, 0 }, // mit libuv
        { "tty", print_tty, 0, 0 }, // mit libuv (ACHTUNG FUNKTIONIERT - Thema dieses Examples)
        { "exit", exitRuntime, 0, 0 }, // mit libuv (ACHTUNG FUNKTIONIERT - Thema dieses Examples)    
        { 0,0,0,0 }
    };
    
    
    bool constructor() {
    
        // Runtime erzeugen
        rt = JS_NewRuntime(8 * 1024 * 1024);
        if (rt == NULL) {
    	return say("Can not create JSRuntime, returning false");
        } else {
    	say("Created JSRuntime");
        }
    
        
        // Context erzeugen
        cx = JS_NewContext(rt, 8192);
        if (cx == NULL) {
    	return say("Can not create JSContext, returning false;");
        } else {
    	say("Created JSContent");
        }
        
        // Error Reporter setzen - Die Funktion gibt den vorherigen Callback zurueck
        if (JS_SetErrorReporter(cx, reportError) == NULL) {
        	say("No previous Error Reporter has been set.");
        }
        
        JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
        JS_SetVersion(cx, JSVERSION_LATEST);
        
        // Das GLOBALE OBJEKT setzen
        global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
        if (global == NULL) {
    	return say("Error creating global object with new compartment.");
        }
    
        if (!JS_InitStandardClasses(cx, global)) {
    	return say("Can not initialize standard JS Classes");
        } else {
    	say("success JS_InitStandardClasses");
        }
        
        say("Defining my personal C Functions like log(s, ...r), tty(), request kommt..");
        ok =  JS_DefineFunctions(cx, global, system_functions);
        if (!ok) {
    	say("Failed defining my funcitons");
        } else {
    	say("Defined my functions");
        }
        say("#### Gib mir some SpiderMonkey JavaScript...");
        
        return true;
    }
    
    void meinREPL () {
        
        char c;
        std::string s;    	
        bool stop = false;
    
        prompt();
        while (!stop) { // gerade oben globale Variable
    	c = std::cin.get();
    	if (!std::cin.eof()) s+=c;
    	else stop = true;
    	if (c == '\n') {
    	    ++lineno; 
    	    ok = JS_EvaluateScript(cx, global, s.c_str(), s.length(), filename, lineno, &rval);
    	    // Muss ich noch rausfinden, was er mit meinte
    	    if (rval == NULL | rval == JS_FALSE) {
    		say("Error executing input: jsval rval ist NULL (in C) oder JS_FALSE");
    	    }
    	    str = JS_ValueToString(cx, rval);
    	     // drucke nicht alle aus;
    	    if (str != oldstr) {
    		say(JS_EncodeString(cx, str)); 
    		oldstr = str; // OB DAS irgendwann Segmentation faulted? Oder ob der alte String gleich Garbage Collected wird und der oldstr Pointer (ehemals str, der alte str Pointer) nicht mehr stimmt?
    	    }
    	    s = "";
    	    prompt();
    	}
        }
    }
    
    void destructor() {
        JS_DestroyContext(cx);
        JS_DestroyRuntime(rt);
        JS_ShutDown();
    }
    
    int main(int argc, char **argv) {
        // libuv    
        loop = uv_default_loop();
        uv_run(loop);
        if (constructor()) {
    	meinREPL();
    	destructor();
        }
    }
    

    Schoen, wenn man tty() ruft, wird Hello TTY! in Farbe ausgegeben (eine farbige JS Funktion ist es damit), aber die Farbe wird erst wieder zurueckgesetzt, wenn ich die Befehle auswendig kenne, und den aktuellen Wert lesen kann.

    Ausserdem habe ich eine exit(rc) Funktion hinzugefuegt, die den Spiderman-REPL beendet. :-)

    Die "Refaktorierung" (extract methods) mit "constructor" und "desctructor" und "meinREPL" ist natuerlich schlecht, aber ich fange gerade erst an. Namen sind in dem Fall Schall und Rauch.

    Manchmal sind meine Kommentare auch komisch.

    User Guide

    Eine gute Idee ist ausserdem, den User Guide zu lesen.

    Hier: http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_User_Guide

    Da kann man noch was mehr lernen, als ich bislang ausprobiert habe. Wie zum Beispiel JS_CallFunctionName http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/JS_CallFunctionName

    Weiter geht es morgen. Ich habe vorhin schon was geschlafen aber bin nochmal wach geworden. So habe ich noch ein paar Minuten mit der JSAPI experimentiert.

    Mehr Referenz

    Das globale Objekt und JSClass

    Um das globale Objekt zu erzeugen, wird eine JSClass verwendet. Das ist eine struct, die ein paar Felder hat, die beim initialisieren ein paar zu Beginn seltsame Felder hat. Schluesseln wird das mal auf.

    static JSClass global_class = {
        "global",
        JSCLASS_GLOBAL_FLAGS,
        JS_PropertyStub,
        JS_PropertyStub,    
        JS_PropertyStub,    
        JS_StrictPropertyStub,    
        JS_EnumerateStub,        
        JS_ResolveStub,    
        JS_ConvertStub,    
        JS_FinalizeStub,    
        JSCLASS_NO_OPTIONAL_MEMBERS
    };
    

    Um ein globales Objekt mit den default Objekten einzurichten, benoetigt man neben JSRuntime und JSContext folgende Befehle.

        
    // Die JSClass fuer das globale Objekt wird als Speicher fuer die Informationen
    // der Variable Environment und der anderen Global Objekt Funktionalitaet gegeben.
    
    /* The class of the global object. */	
    static JSClass global_class = {
        "global", JSCLASS_GLOBAL_FLAGS,
        JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
        JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
        JSCLASS_NO_OPTIONAL_MEMBERS
    };
    
    // In der Funktion, in der der Context erzeugt wird
     
    /*
     * Create the global object in a new compartment.
     * You always need a global object per context.
     */
     
    JSObject *global;
    global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
    if (global == NULL) return 1;
    
    // Die Funktion erzeugt die JavaScript Objekte wie Math, Date, RegExp, Object, Array, Function, Boolean, String, Number
    
    if (!JS_InitStandardClasses(cx, global)) {
        return log("Can not initialize standard JS Classes");
    } else {
        log("Created all Default JavaScript Objects like Math, RegExp, Proxy.");
    }
    

    JSPrincipals

    JSprincipals beschreiben Security informationen fuer ein Objekt oder Script

    	struct JSPrincipals {
    	    char *codebase;	// Pointer zur Codebase fuer den Principal
    	    void *(*getPrincipalArray)(JSContext *cx, JSPrincipals *); // Diese Funktion gibt einen Array von Principaldefinitions zurueck
    	    JSBool (*globalPrivilegesEnabled)(JSContext *cx, JSPrincipals *); // Eine Funktion die ein Bool zurueckgibt, ob die Principals globally enabled sind
    	    uintN refcount;	// Eine Referenz pro Principal inkrementiert diesen Refcountzaehler um eins.
    	    void (*destroy)(JSContext *cx, JSPrincipals *); // Dieser Callback wird gerufen, um den Refcount zu dekrementieren und vielleicht Speicher freizugeben.
    	};
        

    SpiderMonkey geht die Scope Chain bis zum naechsten Objekt, was JSPrincipals attached hat, hoch.

    JSPrincipals http://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/JSPrincipals

    Thread Safety

    Was man in JavaScript nicht hat sind Threads (zumindest im Browser, abgesehen von WebWorker, der seit HTML5 hinzugekommen ist). In der Engine hingegen hat man sowas schon. Auf node.js hat man sowas auch. Und wie SpiderMonkey mit Threads klarkommt kann man hier lesen..

    Man kann hier also THREAD_SAFE kompilieren, und muss dazu eine JS_BeginRequest und JS_EndRequest Funktion nutzen. Manche Algorithmen muessen dann zwischen diesen beiden Operationen ablaufen.

    Mein 4. Beispiel

        uv_fs_read(loop, &uvin, 1, &c, 1, -1, on_key);	// uvin weil stdin in einem der anderen header schon deklariert war, denke an fprintf, also in stdio.h, wie stdout, stderr
        uv_fs_write(loop, &uvout, 0, (char *)prmpt, strlen(prmpt), -1, NULL);
    

    In dem Beispiel ist der Code zwar bereits scheisse, aber der Input loop ist ein asynchroner libuv loop. In dem Fall habe ich es mir einfach gemacht, und rufe den uv_fs_read Callback jedes Zeichen 1* und setze ihn neu. Das werde ich verbessern, wenn ich die library und dessen Verhalten besser kenne. Ich lerne gerade zwei, drei Bibliotheken (jsapi, libuv und noch den http-parser) gleichzeitig, das kann ruhig länger als 24 Stunden dauern.

    #include <jsapi.h>
    #include <string>
    #include <uv.h>
    
    using namespace std;
    
    uv_fs_t uv_stdin;
    uv_fs_t uv_stdout;
    uv_loop_t *loop;
    
    // Spidermonkey
    char c;	
    string s; 
    const char *prompt = "Spiderman> "; 
    jsval rval;
    JSString *str;
    JSBool ok;
    const char *filename = "stdin";
    uintN lineno = 0;
    JSRuntime *rt;
    JSContext *cx;
    JSObject *global;
    
    static JSClass global_class = {
        "global",
        JSCLASS_GLOBAL_FLAGS,
        JS_PropertyStub,
        JS_PropertyStub,    
        JS_PropertyStub,    
        JS_StrictPropertyStub,    
        JS_EnumerateStub,        
        JS_ResolveStub,    
        JS_ConvertStub,    
        JS_FinalizeStub,    
        JSCLASS_NO_OPTIONAL_MEMBERS
    };
    
    #define LOG_MINARGS 1
    static JSBool exit (JSContext *cx, unsigned argc, jsval *vp);
    static JSBool log (JSContext *cx, unsigned argc, jsval *vp);
    
    static JSFunctionSpec system_functions[] = {
        { "log", log, LOG_MINARGS, 0 },
        { "exit", exit, 0, 0 }, 
        { 0,0,0,0 }
    };
    
    bool InitJS();
    void ShutDownJS();
    void print(string str);
    void printLn(string str);
    
    void reportError (JSContext *cs, const char *message, JSErrorReport *report) {
        // lieber cerr nehmen? Werde ich merken, wenn ich files mit >> erzeuge, ob ich es lesen will.
        print( report->filename ? report->filename : "" );
        print(":");
        print(string((char *)report->lineno));
        print(":");
        printLn(string(message));
    }
    
    void print(string str) {
        uv_fs_write(loop, &uv_stdout, 0, (char *)str.c_str(), str.length(), -1, NULL);
    }
    
    void printLn(string str) {
        str += "\n";
        uv_fs_write(loop, &uv_stdout, 0, (char *)str.c_str(), str.length(), -1, NULL);
    }
    
    static JSBool log (JSContext *cx, unsigned argc, jsval *vp) {
        jsval *argv = JS_ARGV(cx, vp);
        for (int i = 0; i < argc; i++) {
    	if (i > 0) print(" ");
    	print(JS_EncodeString(cx, JS_ValueToString(cx, argv[i])));
        }
        printLn("");
        JS_SET_RVAL(cx, vp, JSVAL_VOID); 
        return JS_TRUE;
    }
    
    static JSBool exit (JSContext *cx, unsigned argc, jsval *vp) {
        jsval *argv = JS_ARGV(cx, vp); 
        JS_SET_RVAL(cx, vp, JSVAL_VOID); 
        ShutDownJS();	// Fuehrt zu einem Segmentation Fault, diese Exit Funktion (sobald sie zurueckkehrt ist ja der Context weg, denke ich, fuehrt dazu)
        return JS_TRUE;
    }	
    
    void Prompt () {
        uv_fs_write(loop, &uv_stdout, 0, (char *)prompt, strlen(prompt), -1, NULL);
    }
    
    void EvaluateNextLine( string s ) {
        ok = JS_EvaluateScript(cx, global, s.c_str(), s.length(), filename, lineno, &rval);
        if (rval == NULL | rval == JS_FALSE) {
    	printLn("Error evaluating input.");
        } else {
    	str = JS_ValueToString(cx, rval);
            printLn(JS_EncodeString(cx, str)); 
        }
    }
    
    void readLineCallback (uv_fs_t *handle) {
        uv_fs_req_cleanup(handle);
        s += c;
        if (c == '\n') {
            ++lineno; 
            EvaluateNextLine(s);
            s = "";
            Prompt();
        } 
        if (handle->result == -1) {
            ShutDownJS();
        } else {
            uv_fs_read(loop, &uv_stdin, 1, &c, 1, -1, readLineCallback);
        }
    }
    
    bool InitJS() {
        rt = JS_NewRuntime(8192 * 1024);
        if (rt != NULL) {
    	cx = JS_NewContext(rt, 8192 * 1024);
    	if (cx != NULL) {
    	    JS_SetErrorReporter(cx, reportError);
    	    JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
    	    JS_SetVersion(cx, JSVERSION_LATEST);
    	    global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
    	    if (global != NULL) {
    		JS_InitStandardClasses(cx, global);
    	        JS_DefineFunctions(cx, global, system_functions);
    	        return true;
    	    }
    	}
        }
        printLn("System initialization failure...");
        return false;
    }
    
    void ShutDownJS() {
        printLn("Shutting down the interpreter");
        JS_DestroyContext(cx);
        printLn("JS_DestroyContext(cx)");
        JS_DestroyRuntime(rt);
        printLn("JS_DestroyRuntime(rt)");    
        JS_ShutDown();
        printLn("JS_ShutDown()");    
        /*uv_unref((uv_handle_t*)&uv_stdin); wird nicht gebraucht glaube ich
        uv_unref((uv_handle_t*)&uv_stdout);*/
    }
    
    int main (int argc, char **argv) {
        loop = uv_default_loop();
        if (InitJS()) {
    	if (argc != 1) {
    	    printLn("Processing arguments mode...");
    	    // read and compile files
    	} else {
    	    printLn("Starting in C++ Shell Mode...");
    	    Prompt();
    	    uv_fs_read(loop, &uv_stdin, 1, &c, 1, -1, readLineCallback);
    	    uv_run(loop);    
    	}
        }
        return 0;
    }
    
    

    Mit uv_fs_read und uv_fs_write kann man also stdin und stdout und stderr lesen und schreiben, ich denke mal, die handles 0 (stdout), 1 (stdin), 2 (stderr) spielen hier eine Rolle, weil ich instinktiv 0 und 1 verwendet habe und das funktioniert. Ich muss dem nochmal nachgehen..

    Ich mach das erst ein paar Stunden. Und das zusammen mit den ganzen anderen neuen Sachen...

    Mehr zu libuv gibt es bei mir hier: libuv.html

    JSAPI Cookbook

    In dem Dokument stehen ein paar besondere Leckerbissen drin, um die Grundlagen der JSAPI zu erlernen. Funktionen, Objekte, Arrays, Errors, try-catch-finally, ...

    Zu jedem Thema gibt es ein Example und ein paar beschreibende Worte.

    https://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Cookbook

    Tag: SpiderMonkey

    Alle Seiten der Referenzen nochmal im Überblick auf 4 Seiten

    Mit SpiderMonkey getaggte Seiten.

    https://developer.mozilla.org/en-US/docs/tag/SpiderMonkey

    Dort gibt es die Files, die mit dem . im Dateinamen, die in der Aufzaehlung bislang vereinzelt vorkamen, aber nicht einzordnen waren. Auf dieser Seite sehen die . aber wirklich wie Properties aus. Den Eindruck machten sie zuerst. Mit dieser Seite werden sie aber auch dazu.

    js-ctypes

    Unterschätzte Interfaces

    js-ctypes erlaubt es, eine C Bibliothek zu oeffnen, und mit dem C Interface zu sprechen. Vom JavaScript aus.

    Mehr Informationen: http://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes

    Introducion: Using js-ctypes http://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/Using_js-ctypes

    Es gibt die Objekte CType und CData welche über einige Methoden verfügen.

    jsshell

    Mit SpiderMonkey kriegt man auch eine jsshell, oder ich hatte sie separat downgeloaded. Zumindest ist die JSSHELL mit SpiderMonkey produziert.

    // Destructuring gibt es im Moment bei Mozilla, wird aber Standard im neuen EcmaScript 
    js> var x = 11, y = 12;
    js> [y,x] = [x,y];
    js> x
    12
    js> y
    11
    js> [y,x] = [x,y];
    js> x
    11
    js> y
    12
    

    Hier gibt es auch die Generator Functions, die ich schon lange ausprobieren wollte.

    function genfunc () { // eigtl. function* aber da meckert der Parser
        yield 1;
        yield 2;
        yield 3;
        yield "Ich habe die ganze Zeit die Moeglichkeit";
    }
    var iter = genfunc();
    print(iter.next());
    print(iter.next());
    print(iter.next());
    print(iter.next());
    try {
        print(iter.next());
    } catch (ex) {
        print(ex.message); // ist gleich undefined, gibt gar keine ex.message ;-)
    }
    // 1
    // 2
    // 3
    // Ich habe die ganze Zeit die Moeglichkeit
    // undefined
    

    Mit jsshell -f gen.js >> gen.js habe ich die Ergebnisse ans File gehangen und mit // kurz auskommentiert. Das Skript laeuft. Der tryCatch Block ist dort, weil der Iterator eine Exception wirft, wenn man durch ist.

    Wenn man help() aufruft, kriegt eine Übersicht ueber eingebaute Kommandos.

    Ich hatte sie erst hier stehen, ich denke mir aber, der externe Link reicht.

    http://developer.mozilla.org/en-US/docs/SpiderMonkey/Shell_global_objects (In Farbe).

    js>getMaxArgs()
    491520
    js>
    

    getMaxArgs() ist eine der Funktionen, die bei help() erschienen. Bedeutet, man hat vierhunderteinundneunzigtausendfünfhundertzwanzig Argumente zur Verfügung, wenn man eine Funktion ruft. Das ist durchaus eine angenehme Zahl. ;-)

    Neu in SpiderMonkey 1.8.6

    JSDBGAPI

    Hiiermit kann man Breakpoint-Traps programmieren und dem, der sich das angucken will zugaenglich machen. Breakpoints, Watchpoints, Inspecting the Stack... http://developer.mozilla.org/en-US/docs/JSDBGAPI_Reference. JSDBGAPI.