Skip to content

Commit 4b138c8

Browse files
authored
Run V8 spec conformance test suite (#243)
The shell script runs the tests and diffs stdout against v8.txt. Lines added/removed means tests were broken/fixed. Future work is to a) fix failing tests, and b) enable more tests. A number are disabled for various reasons and mjsunit subdirectories are currently skipped. Need to decide on a case-by-case basis what is and isn't relevant to us. At the moment about 430 tests are run of which approx. 80% pass.
1 parent 9f9bf3c commit 4b138c8

File tree

7 files changed

+1928
-5
lines changed

7 files changed

+1928
-5
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ jobs:
3838
if: ${{ matrix.buildType == 'Release' }}
3939
run: |
4040
time make test262
41+
- name: test v8 mjsunit
42+
if: ${{ matrix.buildType == 'Release' }}
43+
run: |
44+
./v8.sh
4145
linux-32bits:
4246
runs-on: ubuntu-latest
4347
defaults:

qjs.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
extern const uint8_t qjsc_repl[];
4242
extern const uint32_t qjsc_repl_size;
4343

44+
static JSCFunctionListEntry argv0;
45+
4446
static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
4547
const char *filename, int eval_flags)
4648
{
@@ -94,6 +96,22 @@ static int eval_file(JSContext *ctx, const char *filename, int module)
9496
return ret;
9597
}
9698

99+
static JSValue js_gc(JSContext *ctx, JSValue this_val,
100+
int argc, JSValue *argv)
101+
{
102+
JS_RunGC(JS_GetRuntime(ctx));
103+
return JS_UNDEFINED;
104+
}
105+
106+
static const JSCFunctionListEntry navigator_obj[] = {
107+
JS_PROP_STRING_DEF("userAgent", "quickjs-ng", JS_PROP_ENUMERABLE),
108+
};
109+
110+
static const JSCFunctionListEntry global_obj[] = {
111+
JS_CFUNC_DEF("gc", 0, js_gc),
112+
JS_OBJECT_DEF("navigator", navigator_obj, countof(navigator_obj), JS_PROP_C_W_E),
113+
};
114+
97115
/* also used to initialize the worker context */
98116
static JSContext *JS_NewCustomContext(JSRuntime *rt)
99117
{
@@ -105,11 +123,9 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt)
105123
js_init_module_std(ctx, "std");
106124
js_init_module_os(ctx, "os");
107125

108-
/* navigator.userAgent */
109126
JSValue global = JS_GetGlobalObject(ctx);
110-
JSValue navigator = JS_NewObject(ctx);
111-
JS_DefinePropertyValueStr(ctx, navigator, "userAgent", JS_NewString(ctx, "quickjs-ng"), JS_PROP_ENUMERABLE);
112-
JS_DefinePropertyValueStr(ctx, global, "navigator", navigator, JS_PROP_ENUMERABLE);
127+
JS_SetPropertyFunctionList(ctx, global, global_obj, countof(global_obj));
128+
JS_SetPropertyFunctionList(ctx, global, &argv0, 1);
113129
JS_FreeValue(ctx, global);
114130

115131
return ctx;
@@ -283,6 +299,9 @@ int main(int argc, char **argv)
283299
int i, include_count = 0;
284300
size_t stack_size = 0;
285301

302+
argv0 = (JSCFunctionListEntry)JS_PROP_STRING_DEF("argv0", argv[0],
303+
JS_PROP_C_W_E);
304+
286305
/* cannot use getopt because we want to pass the command line to
287306
the script */
288307
optind = 1;

quickjs-libc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3739,7 +3739,7 @@ JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name)
37393739
/**********************************************************/
37403740

37413741
static JSValue js_print(JSContext *ctx, JSValue this_val,
3742-
int argc, JSValue *argv)
3742+
int argc, JSValue *argv)
37433743
{
37443744
int i;
37453745
const char *str;
@@ -3755,6 +3755,7 @@ static JSValue js_print(JSContext *ctx, JSValue this_val,
37553755
JS_FreeCString(ctx, str);
37563756
}
37573757
putchar('\n');
3758+
fflush(stdout);
37583759
return JS_UNDEFINED;
37593760
}
37603761

v8-tweak.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
;(function() {
2+
"use strict"
3+
const print = globalThis.print
4+
globalThis.print = function() {} // print nothing, v8 tests are chatty
5+
let count = 0 // rate limit to avoid excessive logs
6+
globalThis.failWithMessage = function(message) {
7+
if (count > 99) return
8+
if (++count > 99) return print("<output elided>")
9+
print(String(message).slice(0, 128))
10+
}
11+
})()

v8.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import * as std from "std"
2+
import * as os from "os"
3+
4+
argv0 = realpath(argv0)
5+
const tweak = realpath("v8-tweak.js")
6+
const dir = "test262/implementation-contributed/v8/mjsunit"
7+
8+
const exclude = [
9+
"array-concat.js", // slow
10+
"array-isarray.js", // unstable output due to stack overflow
11+
"ascii-regexp-subject.js", // slow
12+
"cyclic-array-to-string.js", // unstable output due to stack overflow
13+
"error-tostring.js", // unstable output due to stack overflow
14+
"regexp.js", // invalid, legitimate early SyntaxError
15+
"regexp-capture-3.js", // slow
16+
"string-replace.js", // unstable output
17+
18+
"mjsunit-assertion-error.js",
19+
"mjsunit.js",
20+
"mjsunit_suppressions.js",
21+
22+
"verify-assert-false.js", // self check
23+
"verify-check-false.js", // self check
24+
]
25+
26+
let files = scriptArgs.slice(1) // run only these tests
27+
if (files.length === 0) files = os.readdir(dir)[0].sort()
28+
29+
for (const file of files) {
30+
if (!file.endsWith(".js")) continue
31+
if (exclude.includes(file)) continue
32+
const source = std.loadFile(dir + "/" + file)
33+
if (/^(im|ex)port/m.test(source)) continue // TODO support modules
34+
if (source.includes('// Files:')) continue // TODO support includes
35+
// exclude tests that use V8 intrinsics like %OptimizeFunctionOnNextCall
36+
if (source.includes ("--allow-natives-syntax")) continue
37+
// exclude tests that use V8 extensions
38+
if (source.includes ("--expose-externalize-string")) continue
39+
const env =
40+
source.match(/environment variables:.*TZ=(?<TZ>[\S]+)/i)?.groups
41+
print(`=== ${file}`)
42+
// the fixed --stack-size is necessary to keep output of stack overflowing
43+
// tests stable; their stack traces are somewhat arbitrary otherwise
44+
const args = [argv0, "--stack-size", `${2048 * 1024}`,
45+
"-I", "mjsunit.js", "-I", tweak, file]
46+
const opts = {block:true, cwd:dir, env:env, usePath:false}
47+
os.exec(args, opts)
48+
}
49+
50+
function realpath(path) {
51+
return os.realpath(path)[0]
52+
}

v8.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
set -e
3+
: ${QJS:=build/qjs}
4+
"$QJS" v8.js $* 2>&1 | tee v8.txt$$
5+
diff -uw v8.txt v8.txt$$ || exit 1
6+
rm v8.txt$$

0 commit comments

Comments
 (0)