Index: ossp-pkg/js/src/README.html RCS File: /v/ossp/cvs/ossp-pkg/js/src/Attic/README.html,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/js/src/Attic/README.html,v' | diff -u /dev/null - -L'ossp-pkg/js/src/README.html' 2>/dev/null --- ossp-pkg/js/src/README.html +++ - 2026-02-04 19:45:20.614682084 +0100 @@ -0,0 +1,826 @@ + + + +
+ + +JSRef builds a library or DLL containing the +JavaScript runtime (compiler, interpreter, decompiler, garbage collector, +atom manager, standard classes). It then compiles a small "shell" program +and links that with the library to make an interpreter that can be used +interactively and with test .js files to run scripts. The code has +no dependencies on the rest of the Mozilla codebase. +
Quick start tip: skip to "Using the JS API" below, build the +js shell, and play with the object named "it" (start by setting 'it.noisy += true'). +
By default, all platforms build a version of the JS engine that is not +threadsafe. If you require thread-safety, you must also populate +the mozilla/dist directory with NSPR +headers and libraries. (NSPR implements a portable threading library, +among other things. The source is downloadable via CVS +from mozilla/nsprpub.) +Next, you must define JS_THREADSAFE when building the JS engine, +either on the command-line (gmake/nmake) or in a universal header file. +
/*
+ * Tune this to avoid wasting space for shallow stacks, while saving on
+ * malloc overhead/fragmentation for deep or highly-variable stacks.
+ */
+ #define STACK_CHUNK_SIZE 8192
+
+ JSRuntime *rt;
+ JSContext *cx;
+
+ /* You need a runtime and one or more contexts to do anything with JS. */
+ rt = JS_NewRuntime(0x400000L);
+ if (!rt)
+ fail("can't create JavaScript runtime");
+ cx = JS_NewContext(rt, STACK_CHUNK_SIZE);
+ if (!cx)
+ fail("can't create JavaScript context");
+
+ /*
+ * The context definitely wants a global object, in order to have standard
+ * classes and functions like Date and parseInt. See below for details on
+ * JS_NewObject.
+ */
+ JSObject *globalObj;
+
+ globalObj = JS_NewObject(cx, &my_global_class, 0, 0);
+ JS_InitStandardClasses(cx, globalObj);
+
+ /* Statically initialize a class to make "one-off" objects. */
+ JSClass my_class = {
+ "MyClass",
+
+ /* All of these can be replaced with the corresponding JS_*Stub
+ function pointers. */
+ my_addProperty, my_delProperty, my_getProperty, my_setProperty,
+ my_enumerate, my_resolve, my_convert, my_finalize
+ };
+
+ JSObject *obj;
+
+ /*
+ * Define an object named in the global scope that can be enumerated by
+ * for/in loops. The parent object is passed as the second argument, as
+ * with all other API calls that take an object/name pair. The prototype
+ * passed in is null, so the default object prototype will be used.
+ */
+ obj = JS_DefineObject(cx, globalObj, "myObject", &my_class, NULL,
+ JSPROP_ENUMERATE);
+
+ /*
+ * Define a bunch of properties with a JSPropertySpec array statically
+ * initialized and terminated with a null-name entry. Besides its name,
+ * each property has a "tiny" identifier (MY_COLOR, e.g.) that can be used
+ * in switch statements (in a common my_getProperty function, for example).
+ */
+ enum my_tinyid {
+ MY_COLOR, MY_HEIGHT, MY_WIDTH, MY_FUNNY, MY_ARRAY, MY_RDONLY
+ };
+
+ static JSPropertySpec my_props[] = {
+ {"color", MY_COLOR, JSPROP_ENUMERATE},
+ {"height", MY_HEIGHT, JSPROP_ENUMERATE},
+ {"width", MY_WIDTH, JSPROP_ENUMERATE},
+ {"funny", MY_FUNNY, JSPROP_ENUMERATE},
+ {"array", MY_ARRAY, JSPROP_ENUMERATE},
+ {"rdonly", MY_RDONLY, JSPROP_READONLY},
+ {0}
+ };
+
+ JS_DefineProperties(cx, obj, my_props);
+
+ /*
+ * Given the above definitions and call to JS_DefineProperties, obj will
+ * need this sort of "getter" method in its class (my_class, above). See
+ * the example for the "It" class in js.c.
+ */
+ static JSBool
+ my_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+ {
+ if (JSVAL_IS_INT(id)) {
+ switch (JSVAL_TO_INT(id)) {
+ case MY_COLOR: *vp = . . .; break;
+ case MY_HEIGHT: *vp = . . .; break;
+ case MY_WIDTH: *vp = . . .; break;
+ case MY_FUNNY: *vp = . . .; break;
+ case MY_ARRAY: *vp = . . .; break;
+ case MY_RDONLY: *vp = . . .; break;
+ }
+ }
+ return JS_TRUE;
+ }
+
+ /* Define a bunch of native functions first: */
+ static JSBool
+ my_abs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+ {
+ jsdouble x, z;
+
+ if (!JS_ValueToNumber(cx, argv[0], &x))
+ return JS_FALSE;
+ z = (x < 0) ? -x : x;
+ return JS_NewDoubleValue(cx, z, rval);
+ }
+
+ . . .
+
+ /*
+ * Use a JSFunctionSpec array terminated with a null name to define a
+ * bunch of native functions.
+ */
+ static JSFunctionSpec my_functions[] = {
+ /* name native nargs */
+ {"abs", my_abs, 1},
+ {"acos", my_acos, 1},
+ {"asin", my_asin, 1},
+ . . .
+ {0}
+ };
+
+ /*
+ * Pass a particular object to define methods for it alone. If you pass
+ * a prototype object, the methods will apply to all instances past and
+ * future of the prototype's class (see below for classes).
+ */
+ JS_DefineFunctions(cx, globalObj, my_functions);
+
+ /*
+ * This pulls together the above API elements by defining a constructor
+ * function, a prototype object, and properties of the prototype and of
+ * the constructor, all with one API call.
+ *
+ * Initialize a class by defining its constructor function, prototype, and
+ * per-instance and per-class properties. The latter are called "static"
+ * below by analogy to Java. They are defined in the constructor object's
+ * scope, so that 'MyClass.myStaticProp' works along with 'new MyClass()'.
+ *
+ * JS_InitClass takes a lot of arguments, but you can pass null for any of
+ * the last four if there are no such properties or methods.
+ *
+ * Note that you do not need to call JS_InitClass to make a new instance of
+ * that class -- otherwise there would be a chicken-and-egg problem making
+ * the global object -- but you should call JS_InitClass if you require a
+ * constructor function for script authors to call via new, and/or a class
+ * prototype object ('MyClass.prototype') for authors to extend with new
+ * properties at run-time. In general, if you want to support multiple
+ * instances that share behavior, use JS_InitClass.
+ */
+ protoObj = JS_InitClass(cx, globalObj, NULL, &my_class,
+
+ /* native constructor function and min arg count */
+ MyClass, 0,
+
+ /* prototype object properties and methods -- these
+ will be "inherited" by all instances through
+ delegation up the instance's prototype link. */
+ my_props, my_methods,
+
+ /* class constructor properties and methods */
+ my_static_props, my_static_methods);
+
+ /* These should indicate source location for diagnostics. */
+ char *filename;
+ uintN lineno;
+
+ /*
+ * The return value comes back here -- if it could be a GC thing, you must
+ * add it to the GC's "root set" with JS_AddRoot(cx, &thing) where thing
+ * is a JSString *, JSObject *, or jsdouble *, and remove the root before
+ * rval goes out of scope, or when rval is no longer needed.
+ */
+ jsval rval;
+ JSBool ok;
+
+ /*
+ * Some example source in a C string. Larger, non-null-terminated buffers
+ * can be used, if you pass the buffer length to JS_EvaluateScript.
+ */
+ char *source = "x * f(y)";
+
+ ok = JS_EvaluateScript(cx, globalObj, source, strlen(source),
+ filename, lineno, &rval);
+
+ if (ok) {
+ /* Should get a number back from the example source. */
+ jsdouble d;
+
+ ok = JS_ValueToNumber(cx, rval, &d);
+ . . .
+ }
+
+/* Call a global function named "foo" that takes no arguments. */ + ok = JS_CallFunctionName(cx, globalObj, "foo", 0, 0, &rval); + + jsval argv[2]; + + /* Call a function in obj's scope named "method", passing two arguments. */ + argv[0] = . . .; + argv[1] = . . .; + ok = JS_CallFunctionName(cx, obj, "method", 2, argv, &rval);+ +
/* For each context you've created: */ + JS_DestroyContext(cx); + + /* For each runtime: */ + JS_DestroyRuntime(rt); + + /* And finally: */ + JS_ShutDown();+ +
JavaScript uses untyped bytecode and runtime type tagging of data values. +The jsval type is a signed machine word that contains either a +signed integer value (if the low bit is set), or a type-tagged pointer +or boolean value (if the low bit is clear). Tagged pointers all refer to +8-byte-aligned things in the GC heap. +
Objects consist of a possibly shared structural description, called +the map or scope; and unshared property values in a vector, called the +slots. Object properties are associated with nonnegative integers stored +in jsval's, or with atoms (unique string descriptors) if named +by an identifier or a non-integral index expression. +
Scripts contain bytecode, source annotations, and a pool of string, +number, and identifier literals. Functions are objects that extend scripts +or native functions with formal parameters, a literal syntax, and a distinct +primitive type ("function"). +
The compiler consists of a recursive-descent parser and a random-logic +rather than table-driven lexical scanner. Semantic and lexical feedback +are used to disambiguate hard cases such as missing semicolons, assignable +expressions ("lvalues" in C parlance), etc. The parser generates bytecode +as it parses, using fixup lists for downward branches and code buffering +and rewriting for exceptional cases such as for loops. It attempts no error +recovery. The interpreter executes the bytecode of top-level scripts, and +calls itself indirectly to interpret function bodies (which are also scripts). +All state associated with an interpreter instance is passed through formal +parameters to the interpreter entry point; most implicit state is collected +in a type named JSContext. Therefore, all API and almost all other functions +in JSRef take a JSContext pointer as their first argument. +
The decompiler translates postfix bytecode into infix source by consulting +a separate byte-sized code, called source notes, to disambiguate bytecodes +that result from more than one grammatical production. +
The GC is a mark-and-sweep, non-conservative (exact) collector. It +can allocate only fixed-sized things -- the current size is two machine +words. It is used to hold JS object and string descriptors (but not property +lists or string bytes), and double-precision floating point numbers. It +runs automatically only when maxbytes (as passed to JS_NewRuntime()) +bytes of GC things have been allocated and another thing-allocation request +is made. JS API users should call JS_GC() or JS_MaybeGC() +between script executions or from the branch callback, as often as necessary. +
An important point about the GC's "exactness": you must add roots for +new objects created by your native methods if you store references to them +into a non-JS structure in the malloc heap or in static data. Also, if +you make a new object in a native method, but do not store it through the +rval +result parameter (see math_abs in the "Using the JS API" section above) +so that it is in a known root, the object is guaranteed to survive only +until another new object is created. Either lock the first new object when +making two in a row, or store it in a root you've added, or store it via +rval. +See the GC tips +document for more. +
The atom manager consists of a hash table associating strings uniquely +with scanner/parser information such as keyword type, index in script or +function literal pool, etc. Atoms play three roles in JSRef: as literals +referred to by unaligned 16-bit immediate bytecode operands, as unique +string descriptors for efficient property name hashing, and as members +of the root GC set for exact GC. +
Native objects and methods for arrays, booleans, dates, functions, numbers, +and strings are implemented using the JS API and certain internal interfaces +used as "fast paths". +
In general, errors are signaled by false or unoverloaded-null return +values, and are reported using JS_ReportError() or one of its +variants by the lowest level in order to provide the most detail. Client +code can substitute its own error reporting function and suppress errors, +or reflect them into Java or some other runtime system as exceptions, GUI +dialogs, etc.. +
14 function perfect(n)
+15 {
+16 print("The perfect numbers up to " + n + " are:");
+17
+18 // We build sumOfDivisors[i] to hold a string expression for
+19 // the sum of the divisors of i, excluding i itself.
+20 var sumOfDivisors = new ExprArray(n+1,1);
+21 for (var divisor = 2; divisor <= n; divisor++) {
+22 for (var j = divisor + divisor; j <= n; j += divisor) {
+23 sumOfDivisors[j] += " + " + divisor;
+24 }
+25 // At this point everything up to 'divisor' has its sumOfDivisors
+26 // expression calculated, so we can determine whether it's perfect
+27 // already by evaluating.
+28 if (eval(sumOfDivisors[divisor]) == divisor) {
+29 print("" + divisor + " = " + sumOfDivisors[divisor]);
+30 }
+31 }
+32 delete sumOfDivisors;
+33 print("That's all.");
+34 }
+The line number to PC and back mappings can be tested using the js program
+with the following script:
+ load("perfect.js")
+ print(perfect)
+ dis(perfect)
+
+ print()
+ for (var ln = 0; ln <= 40; ln++) {
+ var pc = line2pc(perfect,ln)
+ var ln2 = pc2line(perfect,pc)
+ print("\tline " + ln + " => pc " + pc + " => line " + ln2)
+ }
+The result of the for loop over lines 0 to 40 inclusive is:
+line 0 => pc 0 => line 16 + line 1 => pc 0 => line 16 + line 2 => pc 0 => line 16 + line 3 => pc 0 => line 16 + line 4 => pc 0 => line 16 + line 5 => pc 0 => line 16 + line 6 => pc 0 => line 16 + line 7 => pc 0 => line 16 + line 8 => pc 0 => line 16 + line 9 => pc 0 => line 16 + line 10 => pc 0 => line 16 + line 11 => pc 0 => line 16 + line 12 => pc 0 => line 16 + line 13 => pc 0 => line 16 + line 14 => pc 0 => line 16 + line 15 => pc 0 => line 16 + line 16 => pc 0 => line 16 + line 17 => pc 19 => line 20 + line 18 => pc 19 => line 20 + line 19 => pc 19 => line 20 + line 20 => pc 19 => line 20 + line 21 => pc 36 => line 21 + line 22 => pc 53 => line 22 + line 23 => pc 74 => line 23 + line 24 => pc 92 => line 22 + line 25 => pc 106 => line 28 + line 26 => pc 106 => line 28 + line 27 => pc 106 => line 28 + line 28 => pc 106 => line 28 + line 29 => pc 127 => line 29 + line 30 => pc 154 => line 21 + line 31 => pc 154 => line 21 + line 32 => pc 161 => line 32 + line 33 => pc 172 => line 33 + line 34 => pc 172 => line 33 + line 35 => pc 172 => line 33 + line 36 => pc 172 => line 33 + line 37 => pc 172 => line 33 + line 38 => pc 172 => line 33 + line 39 => pc 172 => line 33 + line 40 => pc 172 => line 33+ + +