Browse Source

use include mechanism for large code blocks; draft on growing value stack

pull/1/head
Sami Vaarala 11 years ago
parent
commit
db22ccf283
  1. 162
      website/guide/gettingstarted.html
  2. 2
      website/guide/intro.html
  3. 61
      website/guide/programming.html

162
website/guide/gettingstarted.html

@ -39,24 +39,7 @@ Hello world!
<p>You can also run Ecmascript code from a file which is useful for playing with
features and algorithms. As an example, create <tt>fib.js</tt>:</p>
<pre class="ecmascript-code">
// fib.js
function fib(n) {
if (n == 0) { return 0; }
if (n == 1) { return 1; }
return fib(n-1) + fib(n-2);
}
function test() {
var res = [];
for (i = 0; i &lt; 20; i++) {
res.push(fib(i));
}
print(res.join(' '));
}
test();
</pre>
<pre class="ecmascript-code" include="fib.js"></pre>
<p>Test the script from the command line:</p>
<pre>
@ -114,72 +97,12 @@ without recompiling the C program.</p>
line processing function converts a plain text line into HTML, and
automatically bolds text between stars:</p>
<pre class="ecmascript-code">
// process.js
function processLine(line) {
return line.trim()
.replace(/[&lt;&gt;&amp;"'\u0000-\u001F\u007E-\uFFFF]/g, function(x) {
// escape HTML characters
return '&amp;#' + x.charCodeAt(0) + ';'
})
.replace(/\*(.*?)\*/g, function(x, m) {
// automatically bold text between stars
return '&lt;b&gt;' + m + '&lt;/b&gt;';
});
}
</pre>
<pre class="ecmascript-code" include="process.js"></pre>
<p>The C code, <tt>processlines.c</tt> initializes a Duktape context,
compiles the script, then proceeds to process lines from <tt>stdin</tt>,
calling <tt>processLine()</tt> for every line:</p>
<pre class="c-code">
/* processlines.c */
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include "duktape.h"
int main(int argc, const char *argv[]) {
duk_context *ctx = NULL;
char line[4096];
char idx;
int ch;
ctx = duk_create_heap_default();
if (!ctx) { exit(1); }
duk_eval_file(ctx, "process.js");
duk_pop(ctx); /* pop eval result */
memset(line, 0, sizeof(line));
idx = 0;
for (;;) {
if (idx &gt;= sizeof(line)) { exit(1); }
ch = fgetc(stdin);
if (ch == 0x0a) {
line[idx++] = '\0';
duk_push_global_object(ctx);
duk_get_prop_string(ctx, -1 /*index*/, "processLine");
duk_push_string(ctx, line);
duk_call(ctx, 1 /*nargs*/);
printf("%s\n", duk_to_string(ctx, -1));
duk_pop(ctx);
idx = 0;
} else if (ch == EOF) {
break;
} else {
line[idx++] = (char) ch;
}
}
duk_destroy_heap(ctx);
exit(0);
}
</pre>
<pre class="c-code" include="processlines.c"></pre>
<p>Let's look at the Duktape specific parts of the example code line by line.
Here we need to gloss over some details for brevity, see
@ -349,37 +272,7 @@ See <a href="#programming">Programming model</a> for more details.</li>
up Ecmascript algorithms. More specifically, our test program searches for
primes under 1000000 which end with the digits '9999'. The Ecmascript
version of the program is:</p>
<pre class="ecmascript-code">
// Pure Ecmascript version of low level helper
function primeCheckEcmascript(val, limit) {
for (var i = 2; i &lt;= limit; i++) {
if ((val % i) == 0) { return false; }
}
return true;
}
// Select available helper at load time
var primeCheckHelper = (this.primeCheckNative || primeCheckEcmascript);
// Check 'val' for primality
function primeCheck(val) {
if (val == 1 || val == 2) { return true; }
var limit = Math.ceil(Math.sqrt(val));
while (limit * limit &lt; val) { limit += 1; }
return primeCheckHelper(val, limit);
}
// Find primes below one million ending in '9999'.
function primeTest() {
var res = [];
print('Have native helper: ' + (primeCheckHelper !== primeCheckEcmascript));
for (var i = 1; i &lt; 1000000; i++) {
if (primeCheck(i) &amp;&amp; (i % 10000) == 9999) { res.push(i); }
}
print(res.join(' '));
}
</pre>
<pre class="ecmascript-code" include="prime.js"></pre>
<p>Note that the program uses the native helper if it's available but falls
back to an Ecmascript version if it's not. This allows the Ecmascript code
@ -393,52 +286,9 @@ which is more flexible.</p>
<p>A native helper with functionality equivalent to <tt>primeCheckEcmascript</tt>
is quite straightforward to implement. Adding a program main we get
<tt>primecheck.c</tt>:</p>
<pre class="c-code">
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include "duktape.h"
static int native_prime_check(duk_context *ctx) {
int val = duk_require_int(ctx, 0);
int lim = duk_require_int(ctx, 1);
int i;
for (i = 2; i &lt;= lim; i++) {
if (val % i == 0) {
duk_push_false(ctx);
return 1;
}
}
duk_push_true(ctx);
return 1;
}
int main(int argc, const char *argv[]) {
duk_context *ctx = NULL;
ctx = duk_create_heap_default();
if (!ctx) { exit(1); }
duk_push_global_object(ctx);
duk_push_c_function(ctx, native_prime_check, 2 /*nargs*/);
duk_put_prop_string(ctx, -2, "primeCheckNative");
duk_eval_file(ctx, "prime.js");
duk_pop(ctx); /* pop eval result */
duk_get_prop_string(ctx, -1, "primeTest");
duk_call(ctx, 0);
duk_pop(ctx);
duk_destroy_heap(ctx);
exit(0);
}
</pre>
<pre class="c-code" include="primecheck.c"></pre>
<p>The new steps here, line by line:</p>
<p>The new steps here are, line by line:</p>
<ul class="breakdown"> <!-- breakdown -->
<li>

2
website/guide/intro.html

@ -113,7 +113,7 @@ release.)</b></p>
<p><a href="#finalization">Finalization</a> and <a href="#coroutines">Coroutines</a>
discuss invididual technical topics separately from the basic programming model.
<b>(These are also very much in flux.)</b></p>
<b>(These are also very much under work.)</b></p>
<p><a href="#limitations">Limitations</a> discusses currently known limitations
and provides possible workarounds.</p>

61
website/guide/programming.html

@ -1,7 +1,7 @@
<hr> <!-- this improves readability on e.g. elinks and w3m -->
<h2 id="programming">Programming model</h2>
FIXME: growing/checking the value stack
<p><b>(This section is under work.)</b></p>
<h3>Overview</h3>
@ -30,15 +30,14 @@ FIXME: growing/checking the value stack
is used to allocate storage for strings, Ecmascript objects, and other
variable size, garbage collected data. Objects in the heap have an internal
heap header which provides the necessary information for reference counting,
mark-and-sweep garbage collection, object finalization, etc.</p>
<p>Heap objects can reference each other, creating a reachability graph from
mark-and-sweep garbage collection, object finalization, etc.
Heap objects can reference each other, creating a reachability graph from
a garbage collection perspective. For instance, the properties of an Ecmascript
object reference both the keys and values of the object's property set. You can
have multiple heaps, but objects in different heaps cannot reference each other
directly; you need to use serialization to pass values between heaps.</p>
<p>A Duktape <b>context</b> is an Ecmascript "thread of execution" which "lives"
<p>A Duktape <b>context</b> is an Ecmascript "thread of execution" which lives
in a certain Duktape heap. A context is represented by a <tt>duk_context *</tt>
in the Duktape API, and is associated with an internal Duktape coroutine (a form
of a co-operative thread). The context handle is given to almost every Duktape
@ -105,6 +104,12 @@ point of view.</p>
duk_destroy_heap(ctx);
</pre>
<p>This frees all heap objects allocated, and invalidates any pointers to
such objects. In particular, if the calling program holds string pointers
to values which resided on the value stack of a context associated with the
heap, such pointers are invalidated and must never be dereferenced after
the heap destruction call returns.</p>
<h3>Call stack and catch stack (of a context)</h3>
<p>The call stack of a context is not directly visible to the caller.
@ -124,7 +129,7 @@ caller than the call stack.</p>
accurately represent the true call chain: tail calls will be "squashed"
together in the call stack.</p>
<div class="note">Don't confuse with the C call stack.</div>
<div class="note">Don't confuse with the C stack.</div>
<h3>Value stack (of a context) and value stack index</h3>
@ -216,7 +221,42 @@ each other's values.</p>
<h3>Growing the value stack</h3>
<p>FIXME.</p>
<p>At any time, the value stack of a context is allocated for a certain
maximum number of entries. Attempt to push values beyond the allocated
size will cause an error to be thrown, it will <b>not</b> cause the value
stack to be automatically extended. This simplifies the internal
implementation and also improves performance by minimizing reallocations
when you know, beforehand, that a certain number of entries will be needed
during a function.</p>
<p>When a value stack is created or a Duktape/C function is entered, the
value stack is always guaranteed up to size XXX. In the typical case this
is more than sufficient so that the majority of Duktape/C functions don't
need to extend the value stack. Only functions that need more space or
perhaps need an input-dependent amount of space need to grow the value
stack.</p>
<p>You can extend the stack allocation explicitly with <tt>duk_check_stack()</tt>
or (usually more preferably) <tt>duk_require_stack()</tt>. Once successfully
extended, you are again guaranteed that the specified number of elements can
be pushed to the stack. There is no way to shrink the allocation except by
returning from a Duktape/C function.</p>
<p>Consider, for instance, the following function which will uppercase an
input ASCII string by pushing uppercased characters one-by-one on the stack
and then concatenating the result. This example illustrates how the number
of value stack entries required may depend on the input (otherwise this is
not a very good approach for uppercasing a string):</p>
<pre class="ecmascript-code" include="uppercase.c"></pre>
<p>In addition to user reserved elements, Duktape keeps an automatic internal
value stack reserve to ensure all API calls have enough value stack space to
work without further allocations. The value stack is also extended in somewhat
large steps to minimize memory reallocation activity. As a result the internal
number of value stack elements available beyond the caller specified extra
varies considerably. The caller does not need to take this into account and
should never rely on any additional elements being available.</p>
<h3>Ecmascript array index</h3>
@ -251,14 +291,15 @@ applies for Ecmascript code.</p>
<h3>Duktape API</h3>
<p>Duktape API is the collection of user callable API calls defined in
<tt>duktape.h</tt> and documented in the
<a href="api.html">API reference</a>.</p>
<p>The Duktape API calls are generally error tolerant and will check all
arguments for errors (such as <tt>NULL</tt> pointers). However, to minimize
footprint, the <tt>ctx</tt> argument is not checked, and the caller MUST NOT
call any Duktape API calls with a <tt>NULL</tt> context.</p>
<p>For details on the available API calls, please see the
<a href="api.html">API reference</a>.</p>
<h3>Duktape/C function</h3>
<p>A C function with a Duktape/C API signature can be associated with an

Loading…
Cancel
Save