@zappdev/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/dist/zapp-cli.js +9471 -0
- package/native/src/app/app.zc +490 -0
- package/native/src/event/event.zc +24 -0
- package/native/src/event/events.zc +70 -0
- package/native/src/platform/darwin/backend.zc +923 -0
- package/native/src/platform/darwin/backend_bootstrap.zc +9 -0
- package/native/src/platform/darwin/bootstrap.zc +9 -0
- package/native/src/platform/darwin/engine_jsc.zc +86 -0
- package/native/src/platform/darwin/engine_qjs.zc +92 -0
- package/native/src/platform/darwin/platform.zc +156 -0
- package/native/src/platform/darwin/webview.zc +550 -0
- package/native/src/platform/darwin/webview_bootstrap.zc +9 -0
- package/native/src/platform/darwin/window.zc +1223 -0
- package/native/src/platform/darwin/worker/common.zc +223 -0
- package/native/src/platform/darwin/worker/core/base64_core.zc +29 -0
- package/native/src/platform/darwin/worker/core/crypto_core.zc +19 -0
- package/native/src/platform/darwin/worker/core/encoding_core.zc +32 -0
- package/native/src/platform/darwin/worker/core/fetch_core.zc +145 -0
- package/native/src/platform/darwin/worker/core/url_core.zc +69 -0
- package/native/src/platform/darwin/worker/core/websocket_core.zc +179 -0
- package/native/src/platform/darwin/worker/dispatch.zc +55 -0
- package/native/src/platform/darwin/worker/jsc/base64_jsc.zc +39 -0
- package/native/src/platform/darwin/worker/jsc/crypto_jsc.zc +49 -0
- package/native/src/platform/darwin/worker/jsc/encoding_jsc.zc +86 -0
- package/native/src/platform/darwin/worker/jsc/fetch_jsc.zc +149 -0
- package/native/src/platform/darwin/worker/jsc/url_jsc.zc +54 -0
- package/native/src/platform/darwin/worker/jsc/websocket_jsc.zc +127 -0
- package/native/src/platform/darwin/worker/jsc.zc +670 -0
- package/native/src/platform/darwin/worker/mod.zc +30 -0
- package/native/src/platform/darwin/worker/qjs/fetch_qjs.zc +233 -0
- package/native/src/platform/darwin/worker/qjs/qjs_macros.zc +23 -0
- package/native/src/platform/darwin/worker/qjs/websocket_qjs.zc +223 -0
- package/native/src/platform/darwin/worker/qjs.zc +1053 -0
- package/native/src/platform/darwin/worker/timers.zc +149 -0
- package/native/src/platform/darwin/worker/timers_qjs.zc +209 -0
- package/native/src/platform/platform.zc +64 -0
- package/native/src/platform/shared/log.zc +156 -0
- package/native/src/platform/shared/worker/qjs/base64_qjs.zc +38 -0
- package/native/src/platform/shared/worker/qjs/crypto_qjs.zc +44 -0
- package/native/src/platform/shared/worker/qjs/encoding_qjs.zc +95 -0
- package/native/src/platform/shared/worker/qjs/url_qjs.zc +65 -0
- package/native/src/platform/shared/worker_registry.zc +206 -0
- package/native/src/platform/window.zc +446 -0
- package/native/src/platform/windows/backend.zc +452 -0
- package/native/src/platform/windows/backend_bootstrap.zc +9 -0
- package/native/src/platform/windows/bootstrap.zc +9 -0
- package/native/src/platform/windows/engine_qjs.zc +60 -0
- package/native/src/platform/windows/platform.zc +387 -0
- package/native/src/platform/windows/webview.zc +1175 -0
- package/native/src/platform/windows/webview_bootstrap.zc +9 -0
- package/native/src/platform/windows/window.zc +1271 -0
- package/native/src/platform/windows/worker/common.zc +409 -0
- package/native/src/platform/windows/worker/core/base64_core.zc +52 -0
- package/native/src/platform/windows/worker/core/crypto_core.zc +34 -0
- package/native/src/platform/windows/worker/core/encoding_core.zc +60 -0
- package/native/src/platform/windows/worker/core/fetch_core.zc +274 -0
- package/native/src/platform/windows/worker/core/url_core.zc +216 -0
- package/native/src/platform/windows/worker/core/websocket_core.zc +343 -0
- package/native/src/platform/windows/worker/dispatch.zc +34 -0
- package/native/src/platform/windows/worker/mod.zc +46 -0
- package/native/src/platform/windows/worker/qjs/fetch_qjs.zc +255 -0
- package/native/src/platform/windows/worker/qjs/websocket_qjs.zc +263 -0
- package/native/src/platform/windows/worker/qjs.zc +1049 -0
- package/native/src/platform/windows/worker/timers_qjs.zc +288 -0
- package/native/src/platform/worker.zc +8 -0
- package/native/src/service/service.zc +228 -0
- package/native/vendor/quickjs-ng/.gitattributes +4 -0
- package/native/vendor/quickjs-ng/.github/dependabot.yml +7 -0
- package/native/vendor/quickjs-ng/.github/workflows/ci.yml +812 -0
- package/native/vendor/quickjs-ng/.github/workflows/docs.yml +49 -0
- package/native/vendor/quickjs-ng/.github/workflows/release.yml +162 -0
- package/native/vendor/quickjs-ng/.github/workflows/test-docs.yml +23 -0
- package/native/vendor/quickjs-ng/.github/workflows/tsan.yml +32 -0
- package/native/vendor/quickjs-ng/.github/workflows/valgrind.yml +33 -0
- package/native/vendor/quickjs-ng/.gitmodules +5 -0
- package/native/vendor/quickjs-ng/CMakeLists.txt +553 -0
- package/native/vendor/quickjs-ng/LICENSE +24 -0
- package/native/vendor/quickjs-ng/Makefile +149 -0
- package/native/vendor/quickjs-ng/amalgam.js +53 -0
- package/native/vendor/quickjs-ng/api-test.c +927 -0
- package/native/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
- package/native/vendor/quickjs-ng/builtin-array-fromasync.js +36 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.js +194 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip.js +210 -0
- package/native/vendor/quickjs-ng/ctest.c +17 -0
- package/native/vendor/quickjs-ng/cutils.h +2013 -0
- package/native/vendor/quickjs-ng/cxxtest.cc +2 -0
- package/native/vendor/quickjs-ng/dtoa.c +1619 -0
- package/native/vendor/quickjs-ng/dtoa.h +87 -0
- package/native/vendor/quickjs-ng/examples/fib.c +67 -0
- package/native/vendor/quickjs-ng/examples/fib_module.js +10 -0
- package/native/vendor/quickjs-ng/examples/hello.js +1 -0
- package/native/vendor/quickjs-ng/examples/hello_module.js +6 -0
- package/native/vendor/quickjs-ng/examples/meson.build +17 -0
- package/native/vendor/quickjs-ng/examples/pi_bigint.js +118 -0
- package/native/vendor/quickjs-ng/examples/point.c +154 -0
- package/native/vendor/quickjs-ng/examples/test_fib.js +8 -0
- package/native/vendor/quickjs-ng/examples/test_point.js +43 -0
- package/native/vendor/quickjs-ng/fuzz.c +51 -0
- package/native/vendor/quickjs-ng/gen/function_source.c +81 -0
- package/native/vendor/quickjs-ng/gen/hello.c +53 -0
- package/native/vendor/quickjs-ng/gen/hello_module.c +106 -0
- package/native/vendor/quickjs-ng/gen/repl.c +3053 -0
- package/native/vendor/quickjs-ng/gen/standalone.c +324 -0
- package/native/vendor/quickjs-ng/gen/test_fib.c +81 -0
- package/native/vendor/quickjs-ng/libregexp-opcode.h +58 -0
- package/native/vendor/quickjs-ng/libregexp.c +2687 -0
- package/native/vendor/quickjs-ng/libregexp.h +98 -0
- package/native/vendor/quickjs-ng/libunicode-table.h +4707 -0
- package/native/vendor/quickjs-ng/libunicode.c +1746 -0
- package/native/vendor/quickjs-ng/libunicode.h +126 -0
- package/native/vendor/quickjs-ng/list.h +107 -0
- package/native/vendor/quickjs-ng/lre-test.c +73 -0
- package/native/vendor/quickjs-ng/meson.build +684 -0
- package/native/vendor/quickjs-ng/meson_options.txt +6 -0
- package/native/vendor/quickjs-ng/qjs-wasi-reactor.c +208 -0
- package/native/vendor/quickjs-ng/qjs.c +748 -0
- package/native/vendor/quickjs-ng/qjsc.c +673 -0
- package/native/vendor/quickjs-ng/quickjs-atom.h +267 -0
- package/native/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
- package/native/vendor/quickjs-ng/quickjs-libc.c +4986 -0
- package/native/vendor/quickjs-ng/quickjs-libc.h +79 -0
- package/native/vendor/quickjs-ng/quickjs-opcode.h +369 -0
- package/native/vendor/quickjs-ng/quickjs.c +60259 -0
- package/native/vendor/quickjs-ng/quickjs.h +1419 -0
- package/native/vendor/quickjs-ng/repl.js +1927 -0
- package/native/vendor/quickjs-ng/run-test262.c +2417 -0
- package/native/vendor/quickjs-ng/standalone.js +129 -0
- package/native/vendor/quickjs-ng/tests/assert.js +49 -0
- package/native/vendor/quickjs-ng/tests/bug1221.js +16 -0
- package/native/vendor/quickjs-ng/tests/bug1296.js +12 -0
- package/native/vendor/quickjs-ng/tests/bug1297.js +22 -0
- package/native/vendor/quickjs-ng/tests/bug1301.js +21 -0
- package/native/vendor/quickjs-ng/tests/bug1302.js +24 -0
- package/native/vendor/quickjs-ng/tests/bug1305.js +26 -0
- package/native/vendor/quickjs-ng/tests/bug1318.js +54 -0
- package/native/vendor/quickjs-ng/tests/bug1352.js +8 -0
- package/native/vendor/quickjs-ng/tests/bug1354.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug1355.js +58 -0
- package/native/vendor/quickjs-ng/tests/bug1368.js +9 -0
- package/native/vendor/quickjs-ng/tests/bug39/1.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug39/2.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug39/3.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug488-upstream.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug633/0.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug633/1.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug633/2.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug633/3.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug645/0.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug645/1.js +9 -0
- package/native/vendor/quickjs-ng/tests/bug645/2.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug648.js +13 -0
- package/native/vendor/quickjs-ng/tests/bug652.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug741.js +19 -0
- package/native/vendor/quickjs-ng/tests/bug775.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug776.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug832.js +2 -0
- package/native/vendor/quickjs-ng/tests/bug858.js +26 -0
- package/native/vendor/quickjs-ng/tests/bug904.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug988.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug999.js +3 -0
- package/native/vendor/quickjs-ng/tests/destructured-export.js +8 -0
- package/native/vendor/quickjs-ng/tests/detect_module/0.js +1 -0
- package/native/vendor/quickjs-ng/tests/detect_module/1.js +2 -0
- package/native/vendor/quickjs-ng/tests/detect_module/2.js +1 -0
- package/native/vendor/quickjs-ng/tests/detect_module/3.js +8 -0
- package/native/vendor/quickjs-ng/tests/detect_module/4.js +3 -0
- package/native/vendor/quickjs-ng/tests/empty.js +0 -0
- package/native/vendor/quickjs-ng/tests/fixture_cyclic_import.js +2 -0
- package/native/vendor/quickjs-ng/tests/fixture_string_exports.js +12 -0
- package/native/vendor/quickjs-ng/tests/function_source.js +14 -0
- package/native/vendor/quickjs-ng/tests/microbench.js +1267 -0
- package/native/vendor/quickjs-ng/tests/null_or_undefined.js +38 -0
- package/native/vendor/quickjs-ng/tests/str-pad-leak.js +5 -0
- package/native/vendor/quickjs-ng/tests/test_bigint.js +107 -0
- package/native/vendor/quickjs-ng/tests/test_bjson.js +366 -0
- package/native/vendor/quickjs-ng/tests/test_builtin.js +1314 -0
- package/native/vendor/quickjs-ng/tests/test_closure.js +220 -0
- package/native/vendor/quickjs-ng/tests/test_cyclic_import.js +12 -0
- package/native/vendor/quickjs-ng/tests/test_domexception.js +35 -0
- package/native/vendor/quickjs-ng/tests/test_language.js +755 -0
- package/native/vendor/quickjs-ng/tests/test_loop.js +367 -0
- package/native/vendor/quickjs-ng/tests/test_queue_microtask.js +39 -0
- package/native/vendor/quickjs-ng/tests/test_std.js +340 -0
- package/native/vendor/quickjs-ng/tests/test_string_exports.js +25 -0
- package/native/vendor/quickjs-ng/tests/test_worker.js +43 -0
- package/native/vendor/quickjs-ng/tests/test_worker_module.js +30 -0
- package/native/vendor/quickjs-ng/tests.conf +14 -0
- package/native/vendor/quickjs-ng/unicode_download.sh +19 -0
- package/native/vendor/quickjs-ng/unicode_gen.c +3108 -0
- package/native/vendor/quickjs-ng/unicode_gen_def.h +310 -0
- package/native/vendor/quickjs-ng/update-version.sh +32 -0
- package/native/vendor/webview2/include/WebView2.h +60636 -0
- package/native/vendor/webview2/include/WebView2EnvironmentOptions.h +406 -0
- package/package.json +33 -0
- package/src/backend.ts +139 -0
- package/src/build-config.ts +87 -0
- package/src/build.ts +276 -0
- package/src/common.ts +195 -0
- package/src/config.ts +89 -0
- package/src/dev.ts +164 -0
- package/src/generate.ts +200 -0
- package/src/icons.ts +116 -0
- package/src/init.ts +190 -0
- package/src/package.ts +150 -0
- package/src/zapp-cli.ts +263 -0
|
@@ -0,0 +1,2417 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ECMA Test 262 Runner for QuickJS
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2017-2021 Fabrice Bellard
|
|
5
|
+
* Copyright (c) 2017-2021 Charlie Gordon
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in
|
|
15
|
+
* all copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
20
|
+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
+
* THE SOFTWARE.
|
|
24
|
+
*/
|
|
25
|
+
#include <stdlib.h>
|
|
26
|
+
#include <stdio.h>
|
|
27
|
+
#include <stdarg.h>
|
|
28
|
+
#include <inttypes.h>
|
|
29
|
+
#include <string.h>
|
|
30
|
+
#include <assert.h>
|
|
31
|
+
#include <ctype.h>
|
|
32
|
+
#include <errno.h>
|
|
33
|
+
#include <time.h>
|
|
34
|
+
|
|
35
|
+
#ifdef _WIN32
|
|
36
|
+
#include <windows.h>
|
|
37
|
+
#include <process.h>
|
|
38
|
+
#else
|
|
39
|
+
#include <dirent.h>
|
|
40
|
+
#include <unistd.h>
|
|
41
|
+
#include <sys/stat.h>
|
|
42
|
+
#endif
|
|
43
|
+
|
|
44
|
+
#include "cutils.h"
|
|
45
|
+
#include "list.h"
|
|
46
|
+
#include "quickjs.h"
|
|
47
|
+
#include "quickjs-c-atomics.h"
|
|
48
|
+
#include "quickjs-libc.h"
|
|
49
|
+
|
|
50
|
+
#define CMD_NAME "run-test262"
|
|
51
|
+
|
|
52
|
+
// not quite correct because in theory someone could compile quickjs.c
|
|
53
|
+
// with a different compiler but in practice no one does that, right?
|
|
54
|
+
#ifdef __TINYC__
|
|
55
|
+
#define CC_IS_TCC 1
|
|
56
|
+
#else
|
|
57
|
+
#define CC_IS_TCC 0
|
|
58
|
+
#endif
|
|
59
|
+
|
|
60
|
+
typedef struct {
|
|
61
|
+
js_mutex_t agent_mutex;
|
|
62
|
+
js_cond_t agent_cond;
|
|
63
|
+
/* list of Test262Agent.link */
|
|
64
|
+
struct list_head agent_list;
|
|
65
|
+
js_mutex_t report_mutex;
|
|
66
|
+
/* list of AgentReport.link */
|
|
67
|
+
struct list_head report_list;
|
|
68
|
+
int async_done;
|
|
69
|
+
} ThreadLocalStorage;
|
|
70
|
+
|
|
71
|
+
typedef struct namelist_t {
|
|
72
|
+
char **array;
|
|
73
|
+
int count;
|
|
74
|
+
int size;
|
|
75
|
+
} namelist_t;
|
|
76
|
+
|
|
77
|
+
long nthreads; // invariant: 0 < nthreads < countof(threads)
|
|
78
|
+
js_thread_t threads[32];
|
|
79
|
+
js_thread_t progress_thread;
|
|
80
|
+
js_cond_t progress_cond;
|
|
81
|
+
js_mutex_t progress_mutex;
|
|
82
|
+
|
|
83
|
+
namelist_t test_list;
|
|
84
|
+
namelist_t exclude_list;
|
|
85
|
+
namelist_t exclude_dir_list;
|
|
86
|
+
|
|
87
|
+
FILE *outfile;
|
|
88
|
+
enum test_mode_t {
|
|
89
|
+
TEST_DEFAULT_NOSTRICT, /* run tests as nostrict unless test is flagged as strictonly */
|
|
90
|
+
TEST_DEFAULT_STRICT, /* run tests as strict unless test is flagged as nostrict */
|
|
91
|
+
TEST_NOSTRICT, /* run tests as nostrict, skip strictonly tests */
|
|
92
|
+
TEST_STRICT, /* run tests as strict, skip nostrict tests */
|
|
93
|
+
TEST_ALL, /* run tests in both strict and nostrict, unless restricted by spec */
|
|
94
|
+
} test_mode = TEST_DEFAULT_NOSTRICT;
|
|
95
|
+
int local;
|
|
96
|
+
int skip_async;
|
|
97
|
+
int skip_module;
|
|
98
|
+
int dump_memory;
|
|
99
|
+
int stats_count;
|
|
100
|
+
JSMemoryUsage stats_all, stats_avg, stats_min, stats_max;
|
|
101
|
+
char *stats_min_filename;
|
|
102
|
+
char *stats_max_filename;
|
|
103
|
+
js_mutex_t stats_mutex;
|
|
104
|
+
int verbose;
|
|
105
|
+
char *harness_dir;
|
|
106
|
+
char *harness_exclude;
|
|
107
|
+
char *harness_features;
|
|
108
|
+
char *harness_skip_features;
|
|
109
|
+
char *error_filename;
|
|
110
|
+
char *error_file;
|
|
111
|
+
FILE *error_out;
|
|
112
|
+
int update_errors;
|
|
113
|
+
int slow_test_threshold;
|
|
114
|
+
int start_index, stop_index;
|
|
115
|
+
int test_excluded;
|
|
116
|
+
_Atomic int test_count, test_failed, test_skipped;
|
|
117
|
+
_Atomic int new_errors, changed_errors, fixed_errors;
|
|
118
|
+
|
|
119
|
+
void warning(const char *, ...) __attribute__((__format__(__printf__, 1, 2)));
|
|
120
|
+
void fatal(int, const char *, ...) __attribute__((__format__(__printf__, 2, 3)));
|
|
121
|
+
|
|
122
|
+
void atomic_inc(volatile _Atomic int *p)
|
|
123
|
+
{
|
|
124
|
+
atomic_fetch_add(p, 1);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
void warning(const char *fmt, ...)
|
|
128
|
+
{
|
|
129
|
+
va_list ap;
|
|
130
|
+
|
|
131
|
+
fflush(stdout);
|
|
132
|
+
fprintf(stderr, "%s: ", CMD_NAME);
|
|
133
|
+
va_start(ap, fmt);
|
|
134
|
+
vfprintf(stderr, fmt, ap);
|
|
135
|
+
va_end(ap);
|
|
136
|
+
fputc('\n', stderr);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
void fatal(int errcode, const char *fmt, ...)
|
|
140
|
+
{
|
|
141
|
+
va_list ap;
|
|
142
|
+
|
|
143
|
+
fflush(stdout);
|
|
144
|
+
fprintf(stderr, "%s: ", CMD_NAME);
|
|
145
|
+
va_start(ap, fmt);
|
|
146
|
+
vfprintf(stderr, fmt, ap);
|
|
147
|
+
va_end(ap);
|
|
148
|
+
fputc('\n', stderr);
|
|
149
|
+
|
|
150
|
+
exit(errcode);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
void perror_exit(int errcode, const char *s)
|
|
154
|
+
{
|
|
155
|
+
fflush(stdout);
|
|
156
|
+
fprintf(stderr, "%s: ", CMD_NAME);
|
|
157
|
+
perror(s);
|
|
158
|
+
exit(errcode);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
char *strdup_len(const char *str, int len)
|
|
162
|
+
{
|
|
163
|
+
char *p = malloc(len + 1);
|
|
164
|
+
memcpy(p, str, len);
|
|
165
|
+
p[len] = '\0';
|
|
166
|
+
return p;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
static inline int str_equal(const char *a, const char *b) {
|
|
170
|
+
return !strcmp(a, b);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
static inline int str_count(const char *a, const char *b) {
|
|
174
|
+
int count = 0;
|
|
175
|
+
while ((a = strstr(a, b))) {
|
|
176
|
+
a += strlen(b);
|
|
177
|
+
count++;
|
|
178
|
+
}
|
|
179
|
+
return count;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
char *str_append(char **pp, const char *sep, const char *str) {
|
|
183
|
+
char *res, *p;
|
|
184
|
+
size_t len = 0;
|
|
185
|
+
p = *pp;
|
|
186
|
+
if (p) {
|
|
187
|
+
len = strlen(p) + strlen(sep);
|
|
188
|
+
}
|
|
189
|
+
res = malloc(len + strlen(str) + 1);
|
|
190
|
+
if (p) {
|
|
191
|
+
strcpy(res, p);
|
|
192
|
+
strcat(res, sep);
|
|
193
|
+
}
|
|
194
|
+
strcpy(res + len, str);
|
|
195
|
+
free(p);
|
|
196
|
+
return *pp = res;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
char *str_strip(char *p)
|
|
200
|
+
{
|
|
201
|
+
size_t len = strlen(p);
|
|
202
|
+
while (len > 0 && isspace((unsigned char)p[len - 1]))
|
|
203
|
+
p[--len] = '\0';
|
|
204
|
+
while (isspace((unsigned char)*p))
|
|
205
|
+
p++;
|
|
206
|
+
return p;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
int has_prefix(const char *str, const char *prefix)
|
|
210
|
+
{
|
|
211
|
+
return !strncmp(str, prefix, strlen(prefix));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
char *skip_prefix(const char *str, const char *prefix)
|
|
215
|
+
{
|
|
216
|
+
int i;
|
|
217
|
+
for (i = 0;; i++) {
|
|
218
|
+
if (prefix[i] == '\0') { /* skip the prefix */
|
|
219
|
+
str += i;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
if (str[i] != prefix[i])
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
return (char *)str;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
char *get_basename(const char *filename)
|
|
229
|
+
{
|
|
230
|
+
char *p;
|
|
231
|
+
|
|
232
|
+
p = strrchr(filename, '/');
|
|
233
|
+
if (!p)
|
|
234
|
+
return NULL;
|
|
235
|
+
return strdup_len(filename, p - filename);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
char *compose_path(const char *path, const char *name)
|
|
239
|
+
{
|
|
240
|
+
int path_len, name_len;
|
|
241
|
+
char *d, *q;
|
|
242
|
+
|
|
243
|
+
if (!path || path[0] == '\0' || *name == '/') {
|
|
244
|
+
d = strdup(name);
|
|
245
|
+
} else {
|
|
246
|
+
path_len = strlen(path);
|
|
247
|
+
name_len = strlen(name);
|
|
248
|
+
d = malloc(path_len + 1 + name_len + 1);
|
|
249
|
+
if (d) {
|
|
250
|
+
q = d;
|
|
251
|
+
memcpy(q, path, path_len);
|
|
252
|
+
q += path_len;
|
|
253
|
+
if (path[path_len - 1] != '/')
|
|
254
|
+
*q++ = '/';
|
|
255
|
+
memcpy(q, name, name_len + 1);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return d;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
int namelist_cmp(const char *a, const char *b)
|
|
262
|
+
{
|
|
263
|
+
/* compare strings in modified lexicographical order */
|
|
264
|
+
for (;;) {
|
|
265
|
+
int ca = (unsigned char)*a++;
|
|
266
|
+
int cb = (unsigned char)*b++;
|
|
267
|
+
if (isdigit(ca) && isdigit(cb)) {
|
|
268
|
+
int na = ca - '0';
|
|
269
|
+
int nb = cb - '0';
|
|
270
|
+
while (isdigit(ca = (unsigned char)*a++))
|
|
271
|
+
na = na * 10 + ca - '0';
|
|
272
|
+
while (isdigit(cb = (unsigned char)*b++))
|
|
273
|
+
nb = nb * 10 + cb - '0';
|
|
274
|
+
if (na < nb)
|
|
275
|
+
return -1;
|
|
276
|
+
if (na > nb)
|
|
277
|
+
return +1;
|
|
278
|
+
}
|
|
279
|
+
if (ca < cb)
|
|
280
|
+
return -1;
|
|
281
|
+
if (ca > cb)
|
|
282
|
+
return +1;
|
|
283
|
+
if (ca == '\0')
|
|
284
|
+
return 0;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
int namelist_cmp_indirect(const void *a, const void *b)
|
|
289
|
+
{
|
|
290
|
+
return namelist_cmp(*(const char **)a, *(const char **)b);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
void namelist_sort(namelist_t *lp)
|
|
294
|
+
{
|
|
295
|
+
int i, count;
|
|
296
|
+
if (lp->count > 1) {
|
|
297
|
+
qsort(lp->array, lp->count, sizeof(*lp->array), namelist_cmp_indirect);
|
|
298
|
+
/* remove duplicates */
|
|
299
|
+
for (count = i = 1; i < lp->count; i++) {
|
|
300
|
+
if (namelist_cmp(lp->array[count - 1], lp->array[i]) == 0) {
|
|
301
|
+
free(lp->array[i]);
|
|
302
|
+
} else {
|
|
303
|
+
lp->array[count++] = lp->array[i];
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
lp->count = count;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
int namelist_find(const namelist_t *lp, const char *name)
|
|
311
|
+
{
|
|
312
|
+
int a, b, m, cmp;
|
|
313
|
+
|
|
314
|
+
for (a = 0, b = lp->count; a < b;) {
|
|
315
|
+
m = a + (b - a) / 2;
|
|
316
|
+
cmp = namelist_cmp(lp->array[m], name);
|
|
317
|
+
if (cmp < 0)
|
|
318
|
+
a = m + 1;
|
|
319
|
+
else if (cmp > 0)
|
|
320
|
+
b = m;
|
|
321
|
+
else
|
|
322
|
+
return m;
|
|
323
|
+
}
|
|
324
|
+
return -1;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
void namelist_add(namelist_t *lp, const char *base, const char *name)
|
|
328
|
+
{
|
|
329
|
+
char *s;
|
|
330
|
+
|
|
331
|
+
s = compose_path(base, name);
|
|
332
|
+
if (!s)
|
|
333
|
+
goto fail;
|
|
334
|
+
if (lp->count == lp->size) {
|
|
335
|
+
size_t newsize = lp->size + (lp->size >> 1) + 4;
|
|
336
|
+
char **a = realloc(lp->array, sizeof(lp->array[0]) * newsize);
|
|
337
|
+
if (!a)
|
|
338
|
+
goto fail;
|
|
339
|
+
lp->array = a;
|
|
340
|
+
lp->size = newsize;
|
|
341
|
+
}
|
|
342
|
+
lp->array[lp->count] = s;
|
|
343
|
+
lp->count++;
|
|
344
|
+
return;
|
|
345
|
+
fail:
|
|
346
|
+
fatal(1, "allocation failure\n");
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
void namelist_load(namelist_t *lp, const char *filename)
|
|
350
|
+
{
|
|
351
|
+
char buf[1024];
|
|
352
|
+
char *base_name;
|
|
353
|
+
FILE *f;
|
|
354
|
+
|
|
355
|
+
f = fopen(filename, "r");
|
|
356
|
+
if (!f) {
|
|
357
|
+
perror_exit(1, filename);
|
|
358
|
+
}
|
|
359
|
+
base_name = get_basename(filename);
|
|
360
|
+
|
|
361
|
+
while (fgets(buf, sizeof(buf), f) != NULL) {
|
|
362
|
+
char *p = str_strip(buf);
|
|
363
|
+
if (*p == '#' || *p == ';' || *p == '\0')
|
|
364
|
+
continue; /* line comment */
|
|
365
|
+
|
|
366
|
+
namelist_add(lp, base_name, p);
|
|
367
|
+
}
|
|
368
|
+
free(base_name);
|
|
369
|
+
fclose(f);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
void namelist_add_from_error_file(namelist_t *lp, const char *file)
|
|
373
|
+
{
|
|
374
|
+
const char *p, *p0;
|
|
375
|
+
char *pp;
|
|
376
|
+
|
|
377
|
+
for (p = file; (p = strstr(p, ".js:")) != NULL; p++) {
|
|
378
|
+
for (p0 = p; p0 > file && p0[-1] != '\n'; p0--)
|
|
379
|
+
continue;
|
|
380
|
+
pp = strdup_len(p0, p + 3 - p0);
|
|
381
|
+
namelist_add(lp, NULL, pp);
|
|
382
|
+
free(pp);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
void namelist_free(namelist_t *lp)
|
|
387
|
+
{
|
|
388
|
+
while (lp->count > 0) {
|
|
389
|
+
free(lp->array[--lp->count]);
|
|
390
|
+
}
|
|
391
|
+
free(lp->array);
|
|
392
|
+
lp->array = NULL;
|
|
393
|
+
lp->size = 0;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
static int add_test_file(const char *filename)
|
|
397
|
+
{
|
|
398
|
+
namelist_t *lp = &test_list;
|
|
399
|
+
if (js__has_suffix(filename, ".js") && !js__has_suffix(filename, "_FIXTURE.js"))
|
|
400
|
+
namelist_add(lp, NULL, filename);
|
|
401
|
+
return 0;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
static void find_test_files(const char *path);
|
|
405
|
+
|
|
406
|
+
static bool ispathsep(int c)
|
|
407
|
+
{
|
|
408
|
+
return c == '/' || c == '\\';
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
static void consider_test_file(const char *path, const char *name, int is_dir)
|
|
412
|
+
{
|
|
413
|
+
size_t pathlen;
|
|
414
|
+
char s[1024];
|
|
415
|
+
|
|
416
|
+
if (str_equal(name, ".") || str_equal(name, ".."))
|
|
417
|
+
return;
|
|
418
|
+
pathlen = strlen(path);
|
|
419
|
+
while (pathlen > 0 && ispathsep(path[pathlen-1]))
|
|
420
|
+
pathlen--;
|
|
421
|
+
snprintf(s, sizeof(s), "%.*s/%s", (int)pathlen, path, name);
|
|
422
|
+
#if !defined(_WIN32) && !defined(DT_DIR)
|
|
423
|
+
struct stat st;
|
|
424
|
+
if (is_dir < 0)
|
|
425
|
+
is_dir = !stat(s, &st) && S_ISDIR(st.st_mode);
|
|
426
|
+
#endif
|
|
427
|
+
if (is_dir)
|
|
428
|
+
find_test_files(s);
|
|
429
|
+
else
|
|
430
|
+
add_test_file(s);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
static void find_test_files(const char *path)
|
|
434
|
+
{
|
|
435
|
+
#ifdef _WIN32
|
|
436
|
+
WIN32_FIND_DATAA d;
|
|
437
|
+
HANDLE h;
|
|
438
|
+
char s[1024];
|
|
439
|
+
|
|
440
|
+
snprintf(s, sizeof(s), "%s/*", path);
|
|
441
|
+
h = FindFirstFileA(s, &d);
|
|
442
|
+
if (h != INVALID_HANDLE_VALUE) {
|
|
443
|
+
do {
|
|
444
|
+
consider_test_file(path,
|
|
445
|
+
d.cFileName,
|
|
446
|
+
d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
|
447
|
+
} while (FindNextFileA(h, &d));
|
|
448
|
+
FindClose(h);
|
|
449
|
+
}
|
|
450
|
+
#else
|
|
451
|
+
struct dirent *d, **ds = NULL;
|
|
452
|
+
int i, n;
|
|
453
|
+
|
|
454
|
+
n = scandir(path, &ds, NULL, alphasort);
|
|
455
|
+
for (i = 0; i < n; i++) {
|
|
456
|
+
d = ds[i];
|
|
457
|
+
#ifdef DT_DIR
|
|
458
|
+
consider_test_file(path, d->d_name, d->d_type == DT_DIR);
|
|
459
|
+
#else
|
|
460
|
+
consider_test_file(path, d->d_name, -1);
|
|
461
|
+
#endif
|
|
462
|
+
free(d);
|
|
463
|
+
}
|
|
464
|
+
free(ds);
|
|
465
|
+
#endif
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/* find js files from the directory tree and sort the list */
|
|
469
|
+
static void enumerate_tests(const char *path)
|
|
470
|
+
{
|
|
471
|
+
namelist_t *lp = &test_list;
|
|
472
|
+
int start = lp->count;
|
|
473
|
+
find_test_files(path);
|
|
474
|
+
qsort(lp->array + start, lp->count - start, sizeof(*lp->array),
|
|
475
|
+
namelist_cmp_indirect);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
static JSValue js_print_262(JSContext *ctx, JSValueConst this_val,
|
|
479
|
+
int argc, JSValueConst *argv)
|
|
480
|
+
{
|
|
481
|
+
ThreadLocalStorage *tls = JS_GetRuntimeOpaque(JS_GetRuntime(ctx));
|
|
482
|
+
const char *s;
|
|
483
|
+
JSValueConst v;
|
|
484
|
+
int i;
|
|
485
|
+
|
|
486
|
+
for (i = 0; i < argc; i++) {
|
|
487
|
+
v = argv[i];
|
|
488
|
+
s = JS_ToCString(ctx, v);
|
|
489
|
+
// same logic as js_print in quickjs-libc.c
|
|
490
|
+
if (local && !s && JS_IsObject(v)) {
|
|
491
|
+
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
492
|
+
JSValue t = JS_ToObjectString(ctx, v);
|
|
493
|
+
s = JS_ToCString(ctx, t);
|
|
494
|
+
JS_FreeValue(ctx, t);
|
|
495
|
+
}
|
|
496
|
+
if (!s)
|
|
497
|
+
return JS_EXCEPTION;
|
|
498
|
+
if (!strcmp(s, "Test262:AsyncTestComplete")) {
|
|
499
|
+
tls->async_done++;
|
|
500
|
+
} else if (js__strstart(s, "Test262:AsyncTestFailure", NULL)) {
|
|
501
|
+
tls->async_done = 2; /* force an error */
|
|
502
|
+
}
|
|
503
|
+
if (outfile) {
|
|
504
|
+
if (i != 0)
|
|
505
|
+
fputc(' ', outfile);
|
|
506
|
+
fputs(s, outfile);
|
|
507
|
+
}
|
|
508
|
+
if (verbose > 1)
|
|
509
|
+
printf("%s%s", &" "[i < 1], s);
|
|
510
|
+
JS_FreeCString(ctx, s);
|
|
511
|
+
if (verbose > 2 && JS_IsError(v)) {
|
|
512
|
+
JSValue stack = JS_GetPropertyStr(ctx, v, "stack");
|
|
513
|
+
s = JS_ToCString(ctx, stack);
|
|
514
|
+
JS_FreeValue(ctx, stack);
|
|
515
|
+
if (s) {
|
|
516
|
+
printf("\n%s", s);
|
|
517
|
+
JS_FreeCString(ctx, s);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (outfile)
|
|
522
|
+
fputc('\n', outfile);
|
|
523
|
+
if (verbose > 1)
|
|
524
|
+
printf("\n");
|
|
525
|
+
return JS_UNDEFINED;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
static JSValue js_detachArrayBuffer(JSContext *ctx, JSValueConst this_val,
|
|
529
|
+
int argc, JSValueConst *argv)
|
|
530
|
+
{
|
|
531
|
+
JS_DetachArrayBuffer(ctx, argv[0]);
|
|
532
|
+
return JS_UNDEFINED;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
static JSValue js_evalScript_262(JSContext *ctx, JSValueConst this_val,
|
|
536
|
+
int argc, JSValueConst *argv)
|
|
537
|
+
{
|
|
538
|
+
const char *str;
|
|
539
|
+
size_t len;
|
|
540
|
+
JSValue ret;
|
|
541
|
+
str = JS_ToCStringLen(ctx, &len, argv[0]);
|
|
542
|
+
if (!str)
|
|
543
|
+
return JS_EXCEPTION;
|
|
544
|
+
ret = JS_Eval(ctx, str, len, "<evalScript>", JS_EVAL_TYPE_GLOBAL);
|
|
545
|
+
JS_FreeCString(ctx, str);
|
|
546
|
+
return ret;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
static long cpu_count(void)
|
|
550
|
+
{
|
|
551
|
+
#ifdef _WIN32
|
|
552
|
+
DWORD_PTR procmask, sysmask;
|
|
553
|
+
long count;
|
|
554
|
+
int i;
|
|
555
|
+
|
|
556
|
+
count = 0;
|
|
557
|
+
if (GetProcessAffinityMask(GetCurrentProcess(), &procmask, &sysmask))
|
|
558
|
+
for (i = 0; i < 8 * sizeof(procmask); i++)
|
|
559
|
+
count += 1 & (procmask >> i);
|
|
560
|
+
return count;
|
|
561
|
+
#else
|
|
562
|
+
return sysconf(_SC_NPROCESSORS_ONLN);
|
|
563
|
+
#endif
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
static void init_thread_local_storage(ThreadLocalStorage *p)
|
|
567
|
+
{
|
|
568
|
+
js_mutex_init(&p->agent_mutex);
|
|
569
|
+
js_cond_init(&p->agent_cond);
|
|
570
|
+
init_list_head(&p->agent_list);
|
|
571
|
+
js_mutex_init(&p->report_mutex);
|
|
572
|
+
init_list_head(&p->report_list);
|
|
573
|
+
p->async_done = 0;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
typedef struct {
|
|
577
|
+
struct list_head link;
|
|
578
|
+
js_thread_t tid;
|
|
579
|
+
char *script;
|
|
580
|
+
JSValue broadcast_func;
|
|
581
|
+
bool broadcast_pending;
|
|
582
|
+
JSValue broadcast_sab; /* in the main context */
|
|
583
|
+
uint8_t *broadcast_sab_buf;
|
|
584
|
+
size_t broadcast_sab_size;
|
|
585
|
+
int32_t broadcast_val;
|
|
586
|
+
ThreadLocalStorage *tls;
|
|
587
|
+
} Test262Agent;
|
|
588
|
+
|
|
589
|
+
typedef struct {
|
|
590
|
+
struct list_head link;
|
|
591
|
+
char *str;
|
|
592
|
+
} AgentReport;
|
|
593
|
+
|
|
594
|
+
static JSValue add_helpers1(JSContext *ctx);
|
|
595
|
+
static void add_helpers(JSContext *ctx);
|
|
596
|
+
|
|
597
|
+
static void agent_start(void *arg)
|
|
598
|
+
{
|
|
599
|
+
ThreadLocalStorage *tls;
|
|
600
|
+
Test262Agent *agent;
|
|
601
|
+
JSRuntime *rt;
|
|
602
|
+
JSContext *ctx;
|
|
603
|
+
JSValue ret_val;
|
|
604
|
+
int ret;
|
|
605
|
+
|
|
606
|
+
agent = arg;
|
|
607
|
+
tls = agent->tls; // shares thread-local storage with parent thread
|
|
608
|
+
rt = JS_NewRuntime();
|
|
609
|
+
if (rt == NULL) {
|
|
610
|
+
fatal(1, "JS_NewRuntime failure");
|
|
611
|
+
}
|
|
612
|
+
JS_SetRuntimeOpaque(rt, tls);
|
|
613
|
+
ctx = JS_NewContext(rt);
|
|
614
|
+
if (ctx == NULL) {
|
|
615
|
+
JS_FreeRuntime(rt);
|
|
616
|
+
fatal(1, "JS_NewContext failure");
|
|
617
|
+
}
|
|
618
|
+
JS_SetContextOpaque(ctx, agent);
|
|
619
|
+
JS_SetRuntimeInfo(rt, "agent");
|
|
620
|
+
JS_SetCanBlock(rt, true);
|
|
621
|
+
|
|
622
|
+
add_helpers(ctx);
|
|
623
|
+
ret_val = JS_Eval(ctx, agent->script, strlen(agent->script),
|
|
624
|
+
"<evalScript>", JS_EVAL_TYPE_GLOBAL);
|
|
625
|
+
free(agent->script);
|
|
626
|
+
agent->script = NULL;
|
|
627
|
+
if (JS_IsException(ret_val))
|
|
628
|
+
js_std_dump_error(ctx);
|
|
629
|
+
JS_FreeValue(ctx, ret_val);
|
|
630
|
+
|
|
631
|
+
for(;;) {
|
|
632
|
+
JSContext *ctx1;
|
|
633
|
+
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
|
|
634
|
+
if (ret < 0) {
|
|
635
|
+
js_std_dump_error(ctx);
|
|
636
|
+
break;
|
|
637
|
+
} else if (ret == 0) {
|
|
638
|
+
if (JS_IsUndefined(agent->broadcast_func)) {
|
|
639
|
+
break;
|
|
640
|
+
} else {
|
|
641
|
+
JSValue args[2];
|
|
642
|
+
|
|
643
|
+
js_mutex_lock(&tls->agent_mutex);
|
|
644
|
+
while (!agent->broadcast_pending) {
|
|
645
|
+
js_cond_wait(&tls->agent_cond, &tls->agent_mutex);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
agent->broadcast_pending = false;
|
|
649
|
+
js_cond_signal(&tls->agent_cond);
|
|
650
|
+
|
|
651
|
+
js_mutex_unlock(&tls->agent_mutex);
|
|
652
|
+
|
|
653
|
+
args[0] = JS_NewArrayBuffer(ctx, agent->broadcast_sab_buf,
|
|
654
|
+
agent->broadcast_sab_size,
|
|
655
|
+
NULL, NULL, true);
|
|
656
|
+
args[1] = JS_NewInt32(ctx, agent->broadcast_val);
|
|
657
|
+
ret_val = JS_Call(ctx, agent->broadcast_func, JS_UNDEFINED,
|
|
658
|
+
2, (JSValueConst *)args);
|
|
659
|
+
JS_FreeValue(ctx, args[0]);
|
|
660
|
+
JS_FreeValue(ctx, args[1]);
|
|
661
|
+
if (JS_IsException(ret_val))
|
|
662
|
+
js_std_dump_error(ctx);
|
|
663
|
+
JS_FreeValue(ctx, ret_val);
|
|
664
|
+
JS_FreeValue(ctx, agent->broadcast_func);
|
|
665
|
+
agent->broadcast_func = JS_UNDEFINED;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
JS_FreeValue(ctx, agent->broadcast_func);
|
|
670
|
+
|
|
671
|
+
JS_FreeContext(ctx);
|
|
672
|
+
JS_FreeRuntime(rt);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
static JSValue js_agent_start(JSContext *ctx, JSValueConst this_val,
|
|
676
|
+
int argc, JSValueConst *argv)
|
|
677
|
+
{
|
|
678
|
+
ThreadLocalStorage *tls = JS_GetRuntimeOpaque(JS_GetRuntime(ctx));
|
|
679
|
+
const char *script;
|
|
680
|
+
Test262Agent *agent;
|
|
681
|
+
|
|
682
|
+
if (JS_GetContextOpaque(ctx) != NULL)
|
|
683
|
+
return JS_ThrowTypeError(ctx, "cannot be called inside an agent");
|
|
684
|
+
|
|
685
|
+
script = JS_ToCString(ctx, argv[0]);
|
|
686
|
+
if (!script)
|
|
687
|
+
return JS_EXCEPTION;
|
|
688
|
+
agent = malloc(sizeof(*agent));
|
|
689
|
+
memset(agent, 0, sizeof(*agent));
|
|
690
|
+
agent->broadcast_func = JS_UNDEFINED;
|
|
691
|
+
agent->broadcast_sab = JS_UNDEFINED;
|
|
692
|
+
agent->script = strdup(script);
|
|
693
|
+
agent->tls = tls;
|
|
694
|
+
JS_FreeCString(ctx, script);
|
|
695
|
+
list_add_tail(&agent->link, &tls->agent_list);
|
|
696
|
+
js_thread_create(&agent->tid, agent_start, agent, /*flags*/0);
|
|
697
|
+
return JS_UNDEFINED;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
static void js_agent_free(JSContext *ctx)
|
|
701
|
+
{
|
|
702
|
+
ThreadLocalStorage *tls = JS_GetRuntimeOpaque(JS_GetRuntime(ctx));
|
|
703
|
+
struct list_head *el, *el1;
|
|
704
|
+
Test262Agent *agent;
|
|
705
|
+
|
|
706
|
+
list_for_each_safe(el, el1, &tls->agent_list) {
|
|
707
|
+
agent = list_entry(el, Test262Agent, link);
|
|
708
|
+
js_thread_join(agent->tid);
|
|
709
|
+
JS_FreeValue(ctx, agent->broadcast_sab);
|
|
710
|
+
list_del(&agent->link);
|
|
711
|
+
free(agent);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
static JSValue js_agent_leaving(JSContext *ctx, JSValueConst this_val,
|
|
716
|
+
int argc, JSValueConst *argv)
|
|
717
|
+
{
|
|
718
|
+
Test262Agent *agent = JS_GetContextOpaque(ctx);
|
|
719
|
+
if (!agent)
|
|
720
|
+
return JS_ThrowTypeError(ctx, "must be called inside an agent");
|
|
721
|
+
/* nothing to do */
|
|
722
|
+
return JS_UNDEFINED;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
static bool is_broadcast_pending(ThreadLocalStorage *tls)
|
|
726
|
+
{
|
|
727
|
+
struct list_head *el;
|
|
728
|
+
Test262Agent *agent;
|
|
729
|
+
list_for_each(el, &tls->agent_list) {
|
|
730
|
+
agent = list_entry(el, Test262Agent, link);
|
|
731
|
+
if (agent->broadcast_pending)
|
|
732
|
+
return true;
|
|
733
|
+
}
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
static JSValue js_agent_broadcast(JSContext *ctx, JSValueConst this_val,
|
|
738
|
+
int argc, JSValueConst *argv)
|
|
739
|
+
{
|
|
740
|
+
ThreadLocalStorage *tls = JS_GetRuntimeOpaque(JS_GetRuntime(ctx));
|
|
741
|
+
JSValueConst sab = argv[0];
|
|
742
|
+
struct list_head *el;
|
|
743
|
+
Test262Agent *agent;
|
|
744
|
+
uint8_t *buf;
|
|
745
|
+
size_t buf_size;
|
|
746
|
+
int32_t val;
|
|
747
|
+
|
|
748
|
+
if (JS_GetContextOpaque(ctx) != NULL)
|
|
749
|
+
return JS_ThrowTypeError(ctx, "cannot be called inside an agent");
|
|
750
|
+
|
|
751
|
+
buf = JS_GetArrayBuffer(ctx, &buf_size, sab);
|
|
752
|
+
if (!buf)
|
|
753
|
+
return JS_EXCEPTION;
|
|
754
|
+
if (JS_ToInt32(ctx, &val, argv[1]))
|
|
755
|
+
return JS_EXCEPTION;
|
|
756
|
+
|
|
757
|
+
/* broadcast the values and wait until all agents have started
|
|
758
|
+
calling their callbacks */
|
|
759
|
+
js_mutex_lock(&tls->agent_mutex);
|
|
760
|
+
list_for_each(el, &tls->agent_list) {
|
|
761
|
+
agent = list_entry(el, Test262Agent, link);
|
|
762
|
+
agent->broadcast_pending = true;
|
|
763
|
+
/* the shared array buffer is used by the thread, so increment
|
|
764
|
+
its refcount */
|
|
765
|
+
agent->broadcast_sab = JS_DupValue(ctx, sab);
|
|
766
|
+
agent->broadcast_sab_buf = buf;
|
|
767
|
+
agent->broadcast_sab_size = buf_size;
|
|
768
|
+
agent->broadcast_val = val;
|
|
769
|
+
}
|
|
770
|
+
js_cond_broadcast(&tls->agent_cond);
|
|
771
|
+
|
|
772
|
+
while (is_broadcast_pending(tls)) {
|
|
773
|
+
js_cond_wait(&tls->agent_cond, &tls->agent_mutex);
|
|
774
|
+
}
|
|
775
|
+
js_mutex_unlock(&tls->agent_mutex);
|
|
776
|
+
return JS_UNDEFINED;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
static JSValue js_agent_receiveBroadcast(JSContext *ctx, JSValueConst this_val,
|
|
780
|
+
int argc, JSValueConst *argv)
|
|
781
|
+
{
|
|
782
|
+
Test262Agent *agent = JS_GetContextOpaque(ctx);
|
|
783
|
+
if (!agent)
|
|
784
|
+
return JS_ThrowTypeError(ctx, "must be called inside an agent");
|
|
785
|
+
if (!JS_IsFunction(ctx, argv[0]))
|
|
786
|
+
return JS_ThrowTypeError(ctx, "expecting function");
|
|
787
|
+
JS_FreeValue(ctx, agent->broadcast_func);
|
|
788
|
+
agent->broadcast_func = JS_DupValue(ctx, argv[0]);
|
|
789
|
+
return JS_UNDEFINED;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
static JSValue js_agent_sleep(JSContext *ctx, JSValueConst this_val,
|
|
793
|
+
int argc, JSValueConst *argv)
|
|
794
|
+
{
|
|
795
|
+
uint32_t duration;
|
|
796
|
+
if (JS_ToUint32(ctx, &duration, argv[0]))
|
|
797
|
+
return JS_EXCEPTION;
|
|
798
|
+
#ifdef _WIN32
|
|
799
|
+
Sleep(duration);
|
|
800
|
+
#else
|
|
801
|
+
usleep(duration * 1000);
|
|
802
|
+
#endif
|
|
803
|
+
return JS_UNDEFINED;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
static int64_t get_clock_ms(void)
|
|
807
|
+
{
|
|
808
|
+
#ifdef _WIN32
|
|
809
|
+
return GetTickCount64();
|
|
810
|
+
#else
|
|
811
|
+
struct timespec ts;
|
|
812
|
+
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
813
|
+
return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000);
|
|
814
|
+
#endif
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
static JSValue js_agent_monotonicNow(JSContext *ctx, JSValueConst this_val,
|
|
818
|
+
int argc, JSValueConst *argv)
|
|
819
|
+
{
|
|
820
|
+
return JS_NewInt64(ctx, get_clock_ms());
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
static JSValue js_agent_getReport(JSContext *ctx, JSValueConst this_val,
|
|
824
|
+
int argc, JSValueConst *argv)
|
|
825
|
+
{
|
|
826
|
+
ThreadLocalStorage *tls = JS_GetRuntimeOpaque(JS_GetRuntime(ctx));
|
|
827
|
+
AgentReport *rep;
|
|
828
|
+
JSValue ret;
|
|
829
|
+
|
|
830
|
+
js_mutex_lock(&tls->report_mutex);
|
|
831
|
+
if (list_empty(&tls->report_list)) {
|
|
832
|
+
rep = NULL;
|
|
833
|
+
} else {
|
|
834
|
+
rep = list_entry(tls->report_list.next, AgentReport, link);
|
|
835
|
+
list_del(&rep->link);
|
|
836
|
+
}
|
|
837
|
+
js_mutex_unlock(&tls->report_mutex);
|
|
838
|
+
if (rep) {
|
|
839
|
+
ret = JS_NewString(ctx, rep->str);
|
|
840
|
+
free(rep->str);
|
|
841
|
+
free(rep);
|
|
842
|
+
} else {
|
|
843
|
+
ret = JS_NULL;
|
|
844
|
+
}
|
|
845
|
+
return ret;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
static JSValue js_agent_report(JSContext *ctx, JSValueConst this_val,
|
|
849
|
+
int argc, JSValueConst *argv)
|
|
850
|
+
{
|
|
851
|
+
ThreadLocalStorage *tls = JS_GetRuntimeOpaque(JS_GetRuntime(ctx));
|
|
852
|
+
const char *str;
|
|
853
|
+
AgentReport *rep;
|
|
854
|
+
|
|
855
|
+
str = JS_ToCString(ctx, argv[0]);
|
|
856
|
+
if (!str)
|
|
857
|
+
return JS_EXCEPTION;
|
|
858
|
+
rep = malloc(sizeof(*rep));
|
|
859
|
+
rep->str = strdup(str);
|
|
860
|
+
JS_FreeCString(ctx, str);
|
|
861
|
+
|
|
862
|
+
js_mutex_lock(&tls->report_mutex);
|
|
863
|
+
list_add_tail(&rep->link, &tls->report_list);
|
|
864
|
+
js_mutex_unlock(&tls->report_mutex);
|
|
865
|
+
return JS_UNDEFINED;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
static const JSCFunctionListEntry js_agent_funcs[] = {
|
|
869
|
+
/* only in main */
|
|
870
|
+
JS_CFUNC_DEF("start", 1, js_agent_start ),
|
|
871
|
+
JS_CFUNC_DEF("getReport", 0, js_agent_getReport ),
|
|
872
|
+
JS_CFUNC_DEF("broadcast", 2, js_agent_broadcast ),
|
|
873
|
+
/* only in agent */
|
|
874
|
+
JS_CFUNC_DEF("report", 1, js_agent_report ),
|
|
875
|
+
JS_CFUNC_DEF("leaving", 0, js_agent_leaving ),
|
|
876
|
+
JS_CFUNC_DEF("receiveBroadcast", 1, js_agent_receiveBroadcast ),
|
|
877
|
+
/* in both */
|
|
878
|
+
JS_CFUNC_DEF("sleep", 1, js_agent_sleep ),
|
|
879
|
+
JS_CFUNC_DEF("monotonicNow", 0, js_agent_monotonicNow ),
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
static JSValue js_new_agent(JSContext *ctx)
|
|
883
|
+
{
|
|
884
|
+
JSValue agent;
|
|
885
|
+
agent = JS_NewObject(ctx);
|
|
886
|
+
JS_SetPropertyFunctionList(ctx, agent, js_agent_funcs,
|
|
887
|
+
countof(js_agent_funcs));
|
|
888
|
+
return agent;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
static JSValue js_createRealm(JSContext *ctx, JSValueConst this_val,
|
|
892
|
+
int argc, JSValueConst *argv)
|
|
893
|
+
{
|
|
894
|
+
JSContext *ctx1;
|
|
895
|
+
JSValue ret;
|
|
896
|
+
|
|
897
|
+
ctx1 = JS_NewContext(JS_GetRuntime(ctx));
|
|
898
|
+
if (!ctx1)
|
|
899
|
+
return JS_ThrowOutOfMemory(ctx);
|
|
900
|
+
ret = add_helpers1(ctx1);
|
|
901
|
+
/* ctx1 has a refcount so it stays alive */
|
|
902
|
+
JS_FreeContext(ctx1);
|
|
903
|
+
return ret;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
static JSValue js_IsHTMLDDA(JSContext *ctx, JSValueConst this_val,
|
|
907
|
+
int argc, JSValueConst *argv)
|
|
908
|
+
{
|
|
909
|
+
return JS_NULL;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
static JSValue add_helpers1(JSContext *ctx)
|
|
913
|
+
{
|
|
914
|
+
JSValue global_obj;
|
|
915
|
+
JSValue obj262, is_html_dda;
|
|
916
|
+
|
|
917
|
+
global_obj = JS_GetGlobalObject(ctx);
|
|
918
|
+
|
|
919
|
+
JS_SetPropertyStr(ctx, global_obj, "print",
|
|
920
|
+
JS_NewCFunction(ctx, js_print_262, "print", 1));
|
|
921
|
+
|
|
922
|
+
is_html_dda = JS_NewCFunction(ctx, js_IsHTMLDDA, "IsHTMLDDA", 0);
|
|
923
|
+
JS_SetIsHTMLDDA(ctx, is_html_dda);
|
|
924
|
+
#define N 7
|
|
925
|
+
static const char *props[N] = {
|
|
926
|
+
"detachArrayBuffer", "evalScript", "codePointRange",
|
|
927
|
+
"agent", "global", "createRealm", "IsHTMLDDA",
|
|
928
|
+
};
|
|
929
|
+
JSValue values[N] = {
|
|
930
|
+
JS_NewCFunction(ctx, js_detachArrayBuffer, "detachArrayBuffer", 1),
|
|
931
|
+
JS_NewCFunction(ctx, js_evalScript_262, "evalScript", 1),
|
|
932
|
+
JS_NewCFunction(ctx, js_string_codePointRange, "codePointRange", 2),
|
|
933
|
+
js_new_agent(ctx),
|
|
934
|
+
JS_DupValue(ctx, global_obj),
|
|
935
|
+
JS_NewCFunction(ctx, js_createRealm, "createRealm", 0),
|
|
936
|
+
is_html_dda,
|
|
937
|
+
};
|
|
938
|
+
/* $262 special object used by the tests */
|
|
939
|
+
obj262 = JS_NewObjectFromStr(ctx, N, props, values);
|
|
940
|
+
JS_SetPropertyStr(ctx, global_obj, "$262", JS_DupValue(ctx, obj262));
|
|
941
|
+
#undef N
|
|
942
|
+
|
|
943
|
+
JS_FreeValue(ctx, global_obj);
|
|
944
|
+
return obj262;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
static void add_helpers(JSContext *ctx)
|
|
948
|
+
{
|
|
949
|
+
JS_FreeValue(ctx, add_helpers1(ctx));
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
static char *load_file(const char *filename, size_t *lenp)
|
|
953
|
+
{
|
|
954
|
+
char *buf;
|
|
955
|
+
size_t buf_len;
|
|
956
|
+
buf = (char *)js_load_file(NULL, &buf_len, filename);
|
|
957
|
+
if (!buf)
|
|
958
|
+
perror_exit(1, filename);
|
|
959
|
+
if (lenp)
|
|
960
|
+
*lenp = buf_len;
|
|
961
|
+
return buf;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
static int json_module_init(JSContext *ctx, JSModuleDef *m)
|
|
965
|
+
{
|
|
966
|
+
JSValue val;
|
|
967
|
+
val = JS_GetModulePrivateValue(ctx, m);
|
|
968
|
+
JS_SetModuleExport(ctx, m, "default", val);
|
|
969
|
+
return 0;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
static JSModuleDef *js_module_loader_test(JSContext *ctx,
|
|
973
|
+
const char *module_name, void *opaque,
|
|
974
|
+
JSValueConst attributes)
|
|
975
|
+
{
|
|
976
|
+
size_t buf_len;
|
|
977
|
+
uint8_t *buf;
|
|
978
|
+
JSModuleDef *m;
|
|
979
|
+
JSValue func_val;
|
|
980
|
+
char *filename, *slash, path[1024];
|
|
981
|
+
int res;
|
|
982
|
+
|
|
983
|
+
// interpret import("bar.js") from path/to/foo.js as
|
|
984
|
+
// import("path/to/bar.js") but leave import("./bar.js") untouched
|
|
985
|
+
filename = opaque;
|
|
986
|
+
if (!strchr(module_name, '/')) {
|
|
987
|
+
slash = strrchr(filename, '/');
|
|
988
|
+
if (slash) {
|
|
989
|
+
snprintf(path, sizeof(path), "%.*s/%s",
|
|
990
|
+
(int) (slash - filename), filename, module_name);
|
|
991
|
+
module_name = path;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/* check for JSON module */
|
|
996
|
+
res = js_module_test_json(ctx, attributes);
|
|
997
|
+
if (res < 0)
|
|
998
|
+
return NULL;
|
|
999
|
+
|
|
1000
|
+
buf = js_load_file(ctx, &buf_len, module_name);
|
|
1001
|
+
if (!buf) {
|
|
1002
|
+
JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
|
|
1003
|
+
module_name);
|
|
1004
|
+
return NULL;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
if (res > 0 || js__has_suffix(module_name, ".json")) {
|
|
1008
|
+
/* compile as JSON */
|
|
1009
|
+
JSValue val;
|
|
1010
|
+
val = JS_ParseJSON(ctx, (char *)buf, buf_len, module_name);
|
|
1011
|
+
js_free(ctx, buf);
|
|
1012
|
+
if (JS_IsException(val))
|
|
1013
|
+
return NULL;
|
|
1014
|
+
m = JS_NewCModule(ctx, module_name, json_module_init);
|
|
1015
|
+
if (!m) {
|
|
1016
|
+
JS_FreeValue(ctx, val);
|
|
1017
|
+
return NULL;
|
|
1018
|
+
}
|
|
1019
|
+
JS_AddModuleExport(ctx, m, "default");
|
|
1020
|
+
JS_SetModulePrivateValue(ctx, m, val);
|
|
1021
|
+
return m;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/* compile the module */
|
|
1025
|
+
func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
|
|
1026
|
+
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
|
1027
|
+
js_free(ctx, buf);
|
|
1028
|
+
if (JS_IsException(func_val))
|
|
1029
|
+
return NULL;
|
|
1030
|
+
/* the module is already referenced, so we must free it */
|
|
1031
|
+
m = JS_VALUE_GET_PTR(func_val);
|
|
1032
|
+
JS_FreeValue(ctx, func_val);
|
|
1033
|
+
return m;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
int is_line_sep(char c)
|
|
1037
|
+
{
|
|
1038
|
+
return (c == '\0' || c == '\n' || c == '\r');
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
char *find_line(const char *str, const char *line)
|
|
1042
|
+
{
|
|
1043
|
+
if (str) {
|
|
1044
|
+
const char *p;
|
|
1045
|
+
int len = strlen(line);
|
|
1046
|
+
for (p = str; (p = strstr(p, line)) != NULL; p += len + 1) {
|
|
1047
|
+
if ((p == str || is_line_sep(p[-1])) && is_line_sep(p[len]))
|
|
1048
|
+
return (char *)p;
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
return NULL;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
int is_word_sep(char c)
|
|
1055
|
+
{
|
|
1056
|
+
return (c == '\0' || isspace((unsigned char)c) || c == ',');
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
char *find_word(const char *str, const char *word)
|
|
1060
|
+
{
|
|
1061
|
+
const char *p;
|
|
1062
|
+
int len = strlen(word);
|
|
1063
|
+
if (str && len) {
|
|
1064
|
+
for (p = str; (p = strstr(p, word)) != NULL; p += len) {
|
|
1065
|
+
if ((p == str || is_word_sep(p[-1])) && is_word_sep(p[len]))
|
|
1066
|
+
return (char *)p;
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
return NULL;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
/* handle exclude directories */
|
|
1073
|
+
void update_exclude_dirs(void)
|
|
1074
|
+
{
|
|
1075
|
+
namelist_t *lp = &test_list;
|
|
1076
|
+
namelist_t *ep = &exclude_list;
|
|
1077
|
+
namelist_t *dp = &exclude_dir_list;
|
|
1078
|
+
char *name, *path;
|
|
1079
|
+
int i, j, count;
|
|
1080
|
+
size_t include, exclude;
|
|
1081
|
+
|
|
1082
|
+
/* split directpries from exclude_list */
|
|
1083
|
+
for (count = i = 0; i < ep->count; i++) {
|
|
1084
|
+
name = ep->array[i];
|
|
1085
|
+
if (js__has_suffix(name, "/")) {
|
|
1086
|
+
namelist_add(dp, NULL, name);
|
|
1087
|
+
free(name);
|
|
1088
|
+
} else {
|
|
1089
|
+
ep->array[count++] = name;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
ep->count = count;
|
|
1093
|
+
|
|
1094
|
+
namelist_sort(dp);
|
|
1095
|
+
|
|
1096
|
+
/* filter out excluded directories */
|
|
1097
|
+
for (count = i = 0; i < lp->count; i++) {
|
|
1098
|
+
name = lp->array[i];
|
|
1099
|
+
include = exclude = 0;
|
|
1100
|
+
for (j = 0; j < dp->count; j++) {
|
|
1101
|
+
path = dp->array[j];
|
|
1102
|
+
if (has_prefix(name, path))
|
|
1103
|
+
exclude = strlen(path);
|
|
1104
|
+
if (*path == '!' && has_prefix(name, &path[1]))
|
|
1105
|
+
include = strlen(&path[1]);
|
|
1106
|
+
}
|
|
1107
|
+
// most specific include/exclude wins
|
|
1108
|
+
if (exclude > include) {
|
|
1109
|
+
test_excluded++;
|
|
1110
|
+
free(name);
|
|
1111
|
+
} else {
|
|
1112
|
+
lp->array[count++] = name;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
lp->count = count;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
void load_config(const char *filename, const char *ignore)
|
|
1119
|
+
{
|
|
1120
|
+
char buf[1024];
|
|
1121
|
+
FILE *f;
|
|
1122
|
+
char *base_name;
|
|
1123
|
+
enum {
|
|
1124
|
+
SECTION_NONE = 0,
|
|
1125
|
+
SECTION_CONFIG,
|
|
1126
|
+
SECTION_EXCLUDE,
|
|
1127
|
+
SECTION_FEATURES,
|
|
1128
|
+
SECTION_TESTS,
|
|
1129
|
+
} section = SECTION_NONE;
|
|
1130
|
+
int lineno = 0;
|
|
1131
|
+
|
|
1132
|
+
f = fopen(filename, "r");
|
|
1133
|
+
if (!f) {
|
|
1134
|
+
perror_exit(1, filename);
|
|
1135
|
+
}
|
|
1136
|
+
base_name = get_basename(filename);
|
|
1137
|
+
|
|
1138
|
+
while (fgets(buf, sizeof(buf), f) != NULL) {
|
|
1139
|
+
char *p, *q;
|
|
1140
|
+
lineno++;
|
|
1141
|
+
p = str_strip(buf);
|
|
1142
|
+
if (*p == '#' || *p == ';' || *p == '\0')
|
|
1143
|
+
continue; /* line comment */
|
|
1144
|
+
|
|
1145
|
+
if (*p == "[]"[0]) {
|
|
1146
|
+
/* new section */
|
|
1147
|
+
p++;
|
|
1148
|
+
p[strcspn(p, "]")] = '\0';
|
|
1149
|
+
if (str_equal(p, "config"))
|
|
1150
|
+
section = SECTION_CONFIG;
|
|
1151
|
+
else if (str_equal(p, "exclude"))
|
|
1152
|
+
section = SECTION_EXCLUDE;
|
|
1153
|
+
else if (str_equal(p, "features"))
|
|
1154
|
+
section = SECTION_FEATURES;
|
|
1155
|
+
else if (str_equal(p, "tests"))
|
|
1156
|
+
section = SECTION_TESTS;
|
|
1157
|
+
else
|
|
1158
|
+
section = SECTION_NONE;
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
q = strchr(p, '=');
|
|
1162
|
+
if (q) {
|
|
1163
|
+
/* setting: name=value */
|
|
1164
|
+
*q++ = '\0';
|
|
1165
|
+
q = str_strip(q);
|
|
1166
|
+
}
|
|
1167
|
+
switch (section) {
|
|
1168
|
+
case SECTION_CONFIG:
|
|
1169
|
+
if (!q) {
|
|
1170
|
+
printf("%s:%d: syntax error\n", filename, lineno);
|
|
1171
|
+
continue;
|
|
1172
|
+
}
|
|
1173
|
+
if (strstr(ignore, p)) {
|
|
1174
|
+
printf("%s:%d: ignoring %s=%s\n", filename, lineno, p, q);
|
|
1175
|
+
continue;
|
|
1176
|
+
}
|
|
1177
|
+
if (str_equal(p, "local")) {
|
|
1178
|
+
local = str_equal(q, "yes");
|
|
1179
|
+
continue;
|
|
1180
|
+
}
|
|
1181
|
+
if (str_equal(p, "testdir")) {
|
|
1182
|
+
char *testdir = compose_path(base_name, q);
|
|
1183
|
+
enumerate_tests(testdir);
|
|
1184
|
+
free(testdir);
|
|
1185
|
+
continue;
|
|
1186
|
+
}
|
|
1187
|
+
if (str_equal(p, "harnessdir")) {
|
|
1188
|
+
harness_dir = compose_path(base_name, q);
|
|
1189
|
+
continue;
|
|
1190
|
+
}
|
|
1191
|
+
if (str_equal(p, "harnessexclude")) {
|
|
1192
|
+
str_append(&harness_exclude, " ", q);
|
|
1193
|
+
continue;
|
|
1194
|
+
}
|
|
1195
|
+
if (str_equal(p, "features")) {
|
|
1196
|
+
str_append(&harness_features, " ", q);
|
|
1197
|
+
continue;
|
|
1198
|
+
}
|
|
1199
|
+
if (str_equal(p, "skip-features")) {
|
|
1200
|
+
str_append(&harness_skip_features, " ", q);
|
|
1201
|
+
continue;
|
|
1202
|
+
}
|
|
1203
|
+
if (str_equal(p, "mode")) {
|
|
1204
|
+
if (str_equal(q, "default") || str_equal(q, "default-nostrict"))
|
|
1205
|
+
test_mode = TEST_DEFAULT_NOSTRICT;
|
|
1206
|
+
else if (str_equal(q, "default-strict"))
|
|
1207
|
+
test_mode = TEST_DEFAULT_STRICT;
|
|
1208
|
+
else if (str_equal(q, "nostrict"))
|
|
1209
|
+
test_mode = TEST_NOSTRICT;
|
|
1210
|
+
else if (str_equal(q, "strict"))
|
|
1211
|
+
test_mode = TEST_STRICT;
|
|
1212
|
+
else if (str_equal(q, "all") || str_equal(q, "both"))
|
|
1213
|
+
test_mode = TEST_ALL;
|
|
1214
|
+
else
|
|
1215
|
+
fatal(2, "unknown test mode: %s", q);
|
|
1216
|
+
continue;
|
|
1217
|
+
}
|
|
1218
|
+
if (str_equal(p, "strict")) {
|
|
1219
|
+
if (str_equal(q, "skip") || str_equal(q, "no"))
|
|
1220
|
+
test_mode = TEST_NOSTRICT;
|
|
1221
|
+
continue;
|
|
1222
|
+
}
|
|
1223
|
+
if (str_equal(p, "nostrict")) {
|
|
1224
|
+
if (str_equal(q, "skip") || str_equal(q, "no"))
|
|
1225
|
+
test_mode = TEST_STRICT;
|
|
1226
|
+
continue;
|
|
1227
|
+
}
|
|
1228
|
+
if (str_equal(p, "async")) {
|
|
1229
|
+
skip_async = !str_equal(q, "yes");
|
|
1230
|
+
continue;
|
|
1231
|
+
}
|
|
1232
|
+
if (str_equal(p, "module")) {
|
|
1233
|
+
skip_module = !str_equal(q, "yes");
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
if (str_equal(p, "verbose")) {
|
|
1237
|
+
int count = str_count(q, "yes");
|
|
1238
|
+
verbose = max_int(verbose, count);
|
|
1239
|
+
continue;
|
|
1240
|
+
}
|
|
1241
|
+
if (str_equal(p, "errorfile")) {
|
|
1242
|
+
error_filename = compose_path(base_name, q);
|
|
1243
|
+
continue;
|
|
1244
|
+
}
|
|
1245
|
+
if (str_equal(p, "excludefile")) {
|
|
1246
|
+
char *path = compose_path(base_name, q);
|
|
1247
|
+
namelist_load(&exclude_list, path);
|
|
1248
|
+
free(path);
|
|
1249
|
+
continue;
|
|
1250
|
+
}
|
|
1251
|
+
case SECTION_EXCLUDE:
|
|
1252
|
+
namelist_add(&exclude_list, base_name, p);
|
|
1253
|
+
break;
|
|
1254
|
+
case SECTION_FEATURES:
|
|
1255
|
+
if (!q || str_equal(q, "yes") || (!CC_IS_TCC && str_equal(q, "!tcc")))
|
|
1256
|
+
str_append(&harness_features, " ", p);
|
|
1257
|
+
else
|
|
1258
|
+
str_append(&harness_skip_features, " ", p);
|
|
1259
|
+
break;
|
|
1260
|
+
case SECTION_TESTS:
|
|
1261
|
+
namelist_add(&test_list, base_name, p);
|
|
1262
|
+
break;
|
|
1263
|
+
default:
|
|
1264
|
+
/* ignore settings in other sections */
|
|
1265
|
+
break;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
fclose(f);
|
|
1269
|
+
free(base_name);
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
char *find_error(const char *filename, int *pline, int is_strict)
|
|
1273
|
+
{
|
|
1274
|
+
if (error_file) {
|
|
1275
|
+
size_t len = strlen(filename);
|
|
1276
|
+
const char *p, *q, *r;
|
|
1277
|
+
int line;
|
|
1278
|
+
|
|
1279
|
+
for (p = error_file; (p = strstr(p, filename)) != NULL; p += len) {
|
|
1280
|
+
if ((p == error_file || p[-1] == '\n' || p[-1] == '(') && p[len] == ':') {
|
|
1281
|
+
q = p + len;
|
|
1282
|
+
line = 1;
|
|
1283
|
+
if (*q == ':') {
|
|
1284
|
+
line = strtol(q + 1, (char**)&q, 10);
|
|
1285
|
+
if (*q == ':')
|
|
1286
|
+
q++;
|
|
1287
|
+
}
|
|
1288
|
+
while (*q == ' ') {
|
|
1289
|
+
q++;
|
|
1290
|
+
}
|
|
1291
|
+
/* check strict mode indicator */
|
|
1292
|
+
if (!js__strstart(q, "strict mode: ", &q) != !is_strict)
|
|
1293
|
+
continue;
|
|
1294
|
+
r = q = skip_prefix(q, "unexpected error: ");
|
|
1295
|
+
r += strcspn(r, "\n");
|
|
1296
|
+
while (r[0] == '\n' && r[1] && strncmp(r + 1, filename, 8)) {
|
|
1297
|
+
r++;
|
|
1298
|
+
r += strcspn(r, "\n");
|
|
1299
|
+
}
|
|
1300
|
+
if (pline)
|
|
1301
|
+
*pline = line;
|
|
1302
|
+
return strdup_len(q, r - q);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
return NULL;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
int skip_comments(const char *str, int line, int *pline)
|
|
1310
|
+
{
|
|
1311
|
+
const char *p;
|
|
1312
|
+
int c;
|
|
1313
|
+
|
|
1314
|
+
p = str;
|
|
1315
|
+
while ((c = (unsigned char)*p++) != '\0') {
|
|
1316
|
+
if (isspace(c)) {
|
|
1317
|
+
if (c == '\n')
|
|
1318
|
+
line++;
|
|
1319
|
+
continue;
|
|
1320
|
+
}
|
|
1321
|
+
if (c == '/' && *p == '/') {
|
|
1322
|
+
while (*++p && *p != '\n')
|
|
1323
|
+
continue;
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1326
|
+
if (c == '/' && *p == '*') {
|
|
1327
|
+
for (p += 1; *p; p++) {
|
|
1328
|
+
if (*p == '\n') {
|
|
1329
|
+
line++;
|
|
1330
|
+
continue;
|
|
1331
|
+
}
|
|
1332
|
+
if (*p == '*' && p[1] == '/') {
|
|
1333
|
+
p += 2;
|
|
1334
|
+
break;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
continue;
|
|
1338
|
+
}
|
|
1339
|
+
break;
|
|
1340
|
+
}
|
|
1341
|
+
if (pline)
|
|
1342
|
+
*pline = line;
|
|
1343
|
+
|
|
1344
|
+
return p - str;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
int longest_match(const char *str, const char *find, int pos, int *ppos, int line, int *pline)
|
|
1348
|
+
{
|
|
1349
|
+
int len, maxlen;
|
|
1350
|
+
|
|
1351
|
+
maxlen = 0;
|
|
1352
|
+
|
|
1353
|
+
if (*find) {
|
|
1354
|
+
const char *p;
|
|
1355
|
+
for (p = str + pos; *p; p++) {
|
|
1356
|
+
if (*p == *find) {
|
|
1357
|
+
for (len = 1; p[len] && p[len] == find[len]; len++)
|
|
1358
|
+
continue;
|
|
1359
|
+
if (len > maxlen) {
|
|
1360
|
+
maxlen = len;
|
|
1361
|
+
if (ppos)
|
|
1362
|
+
*ppos = p - str;
|
|
1363
|
+
if (pline)
|
|
1364
|
+
*pline = line;
|
|
1365
|
+
if (!find[len])
|
|
1366
|
+
break;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
if (*p == '\n')
|
|
1370
|
+
line++;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
return maxlen;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
|
|
1377
|
+
const char *filename, int is_test, int is_negative,
|
|
1378
|
+
const char *error_type, int eval_flags, int is_async,
|
|
1379
|
+
int *msec)
|
|
1380
|
+
{
|
|
1381
|
+
ThreadLocalStorage *tls = JS_GetRuntimeOpaque(JS_GetRuntime(ctx));
|
|
1382
|
+
JSValue res_val, exception_val;
|
|
1383
|
+
int ret, error_line, pos, pos_line;
|
|
1384
|
+
bool is_error, has_error_line, ret_promise;
|
|
1385
|
+
const char *error_name;
|
|
1386
|
+
int start, duration;
|
|
1387
|
+
|
|
1388
|
+
pos = skip_comments(buf, 1, &pos_line);
|
|
1389
|
+
error_line = pos_line;
|
|
1390
|
+
has_error_line = false;
|
|
1391
|
+
exception_val = JS_UNDEFINED;
|
|
1392
|
+
error_name = NULL;
|
|
1393
|
+
|
|
1394
|
+
/* a module evaluation returns a promise */
|
|
1395
|
+
ret_promise = ((eval_flags & JS_EVAL_TYPE_MODULE) != 0);
|
|
1396
|
+
tls->async_done = 0; /* counter of "Test262:AsyncTestComplete" messages */
|
|
1397
|
+
|
|
1398
|
+
start = get_clock_ms();
|
|
1399
|
+
res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
|
|
1400
|
+
|
|
1401
|
+
if ((is_async || ret_promise) && !JS_IsException(res_val)) {
|
|
1402
|
+
JSValue promise = JS_UNDEFINED;
|
|
1403
|
+
if (ret_promise) {
|
|
1404
|
+
promise = res_val;
|
|
1405
|
+
} else {
|
|
1406
|
+
JS_FreeValue(ctx, res_val);
|
|
1407
|
+
}
|
|
1408
|
+
for(;;) {
|
|
1409
|
+
JSContext *ctx1;
|
|
1410
|
+
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
|
|
1411
|
+
if (ret < 0) {
|
|
1412
|
+
res_val = JS_EXCEPTION;
|
|
1413
|
+
break;
|
|
1414
|
+
} else if (ret == 0) {
|
|
1415
|
+
if (is_async) {
|
|
1416
|
+
/* test if the test called $DONE() once */
|
|
1417
|
+
if (tls->async_done != 1) {
|
|
1418
|
+
res_val = JS_ThrowTypeError(ctx, "$DONE() not called");
|
|
1419
|
+
} else {
|
|
1420
|
+
res_val = JS_UNDEFINED;
|
|
1421
|
+
}
|
|
1422
|
+
} else {
|
|
1423
|
+
/* check that the returned promise is fulfilled */
|
|
1424
|
+
JSPromiseStateEnum state = JS_PromiseState(ctx, promise);
|
|
1425
|
+
if (state == JS_PROMISE_FULFILLED)
|
|
1426
|
+
res_val = JS_UNDEFINED;
|
|
1427
|
+
else if (state == JS_PROMISE_REJECTED)
|
|
1428
|
+
res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise));
|
|
1429
|
+
else
|
|
1430
|
+
res_val = JS_ThrowTypeError(ctx, "promise is pending");
|
|
1431
|
+
}
|
|
1432
|
+
break;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
JS_FreeValue(ctx, promise);
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
duration = get_clock_ms() - start;
|
|
1439
|
+
*msec += duration;
|
|
1440
|
+
|
|
1441
|
+
if (JS_IsException(res_val)) {
|
|
1442
|
+
exception_val = JS_GetException(ctx);
|
|
1443
|
+
is_error = JS_IsError(exception_val);
|
|
1444
|
+
js_print_262(ctx, JS_NULL, 1, (JSValueConst *)&exception_val);
|
|
1445
|
+
if (is_error) {
|
|
1446
|
+
JSValue name, stack;
|
|
1447
|
+
const char *stack_str;
|
|
1448
|
+
|
|
1449
|
+
name = JS_GetPropertyStr(ctx, exception_val, "name");
|
|
1450
|
+
error_name = JS_ToCString(ctx, name);
|
|
1451
|
+
stack = JS_GetPropertyStr(ctx, exception_val, "stack");
|
|
1452
|
+
if (!JS_IsUndefined(stack)) {
|
|
1453
|
+
stack_str = JS_ToCString(ctx, stack);
|
|
1454
|
+
if (stack_str) {
|
|
1455
|
+
const char *p;
|
|
1456
|
+
int len;
|
|
1457
|
+
|
|
1458
|
+
len = strlen(filename);
|
|
1459
|
+
p = strstr(stack_str, filename);
|
|
1460
|
+
if (p != NULL && p[len] == ':') {
|
|
1461
|
+
error_line = atoi(p + len + 1);
|
|
1462
|
+
has_error_line = true;
|
|
1463
|
+
}
|
|
1464
|
+
JS_FreeCString(ctx, stack_str);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
JS_FreeValue(ctx, stack);
|
|
1468
|
+
JS_FreeValue(ctx, name);
|
|
1469
|
+
}
|
|
1470
|
+
if (is_negative) {
|
|
1471
|
+
ret = 0;
|
|
1472
|
+
if (error_type) {
|
|
1473
|
+
char *error_class;
|
|
1474
|
+
const char *msg;
|
|
1475
|
+
|
|
1476
|
+
msg = JS_ToCString(ctx, exception_val);
|
|
1477
|
+
if (msg == NULL) {
|
|
1478
|
+
ret = -1;
|
|
1479
|
+
} else {
|
|
1480
|
+
error_class = strdup_len(msg, strcspn(msg, ":"));
|
|
1481
|
+
if (!str_equal(error_class, error_type))
|
|
1482
|
+
ret = -1;
|
|
1483
|
+
free(error_class);
|
|
1484
|
+
JS_FreeCString(ctx, msg);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
} else {
|
|
1488
|
+
ret = -1;
|
|
1489
|
+
}
|
|
1490
|
+
} else {
|
|
1491
|
+
if (is_negative)
|
|
1492
|
+
ret = -1;
|
|
1493
|
+
else
|
|
1494
|
+
ret = 0;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
if (verbose && is_test) {
|
|
1498
|
+
JSValue msg_val = JS_UNDEFINED;
|
|
1499
|
+
const char *msg = NULL;
|
|
1500
|
+
int s_line;
|
|
1501
|
+
char *s = find_error(filename, &s_line, eval_flags & JS_EVAL_FLAG_STRICT);
|
|
1502
|
+
const char *strict_mode = (eval_flags & JS_EVAL_FLAG_STRICT) ? "strict mode: " : "";
|
|
1503
|
+
bool is_unexpected_error = true;
|
|
1504
|
+
|
|
1505
|
+
if (!JS_IsUndefined(exception_val)) {
|
|
1506
|
+
msg_val = JS_ToString(ctx, exception_val);
|
|
1507
|
+
msg = JS_ToCString(ctx, msg_val);
|
|
1508
|
+
}
|
|
1509
|
+
if (is_negative) { // expect error
|
|
1510
|
+
if (ret == 0) {
|
|
1511
|
+
if (msg && s &&
|
|
1512
|
+
(str_equal(s, "expected error") ||
|
|
1513
|
+
js__strstart(s, "unexpected error type:", NULL) ||
|
|
1514
|
+
str_equal(s, msg))) { // did not have error yet
|
|
1515
|
+
if (!has_error_line) {
|
|
1516
|
+
longest_match(buf, msg, pos, &pos, pos_line, &error_line);
|
|
1517
|
+
}
|
|
1518
|
+
printf("%s:%d: %sOK, now has error %s\n",
|
|
1519
|
+
filename, error_line, strict_mode, msg);
|
|
1520
|
+
atomic_inc(&fixed_errors);
|
|
1521
|
+
is_unexpected_error = false;
|
|
1522
|
+
}
|
|
1523
|
+
} else {
|
|
1524
|
+
if (!s) { // not yet reported
|
|
1525
|
+
if (msg) {
|
|
1526
|
+
fprintf(error_out, "%s:%d: %sunexpected error type: %s\n",
|
|
1527
|
+
filename, error_line, strict_mode, msg);
|
|
1528
|
+
} else {
|
|
1529
|
+
fprintf(error_out, "%s:%d: %sexpected error\n",
|
|
1530
|
+
filename, error_line, strict_mode);
|
|
1531
|
+
}
|
|
1532
|
+
atomic_inc(&new_errors);
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
} else { // should not have error
|
|
1536
|
+
if (msg) {
|
|
1537
|
+
if (!s || !str_equal(s, msg)) {
|
|
1538
|
+
if (!has_error_line) {
|
|
1539
|
+
char *p = skip_prefix(msg, "Test262 Error: ");
|
|
1540
|
+
if (strstr(p, "Test case returned non-true value!")) {
|
|
1541
|
+
longest_match(buf, "runTestCase", pos, &pos, pos_line, &error_line);
|
|
1542
|
+
} else {
|
|
1543
|
+
longest_match(buf, p, pos, &pos, pos_line, &error_line);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
fprintf(error_out, "%s:%d: %s%s%s\n", filename, error_line, strict_mode,
|
|
1547
|
+
error_file ? "unexpected error: " : "", msg);
|
|
1548
|
+
|
|
1549
|
+
if (s && (!str_equal(s, msg) || error_line != s_line)) {
|
|
1550
|
+
printf("%s:%d: %sprevious error: %s\n", filename, s_line, strict_mode, s);
|
|
1551
|
+
atomic_inc(&changed_errors);
|
|
1552
|
+
} else {
|
|
1553
|
+
atomic_inc(&new_errors);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
} else {
|
|
1557
|
+
if (s) {
|
|
1558
|
+
printf("%s:%d: %sOK, fixed error: %s\n", filename, s_line, strict_mode, s);
|
|
1559
|
+
atomic_inc(&fixed_errors);
|
|
1560
|
+
is_unexpected_error = false;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
if (is_unexpected_error && verbose > 1 && JS_IsException(exception_val)) {
|
|
1565
|
+
JSValue val = JS_GetPropertyStr(ctx, exception_val, "stack");
|
|
1566
|
+
if (!JS_IsException(val) &&
|
|
1567
|
+
!JS_IsUndefined(val) &&
|
|
1568
|
+
!JS_IsNull(val)) {
|
|
1569
|
+
const char *str = JS_ToCString(ctx, val);
|
|
1570
|
+
if (str)
|
|
1571
|
+
printf("%s\n", str);
|
|
1572
|
+
JS_FreeCString(ctx, str);
|
|
1573
|
+
JS_FreeValue(ctx, val);
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
JS_FreeValue(ctx, msg_val);
|
|
1577
|
+
JS_FreeCString(ctx, msg);
|
|
1578
|
+
free(s);
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
if (local) {
|
|
1582
|
+
ret = js_std_loop(ctx);
|
|
1583
|
+
if (ret)
|
|
1584
|
+
js_std_dump_error(ctx);
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
JS_FreeCString(ctx, error_name);
|
|
1588
|
+
JS_FreeValue(ctx, exception_val);
|
|
1589
|
+
JS_FreeValue(ctx, res_val);
|
|
1590
|
+
return ret;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
static int eval_file(JSContext *ctx, const char *base, const char *p,
|
|
1594
|
+
int eval_flags)
|
|
1595
|
+
{
|
|
1596
|
+
char *buf;
|
|
1597
|
+
size_t buf_len;
|
|
1598
|
+
char *filename = compose_path(base, p);
|
|
1599
|
+
int msec = 0;
|
|
1600
|
+
|
|
1601
|
+
buf = load_file(filename, &buf_len);
|
|
1602
|
+
if (!buf) {
|
|
1603
|
+
warning("cannot load %s", filename);
|
|
1604
|
+
goto fail;
|
|
1605
|
+
}
|
|
1606
|
+
if (eval_buf(ctx, buf, buf_len, filename, false, false, NULL,
|
|
1607
|
+
eval_flags, false, &msec)) {
|
|
1608
|
+
warning("error evaluating %s", filename);
|
|
1609
|
+
goto fail;
|
|
1610
|
+
}
|
|
1611
|
+
free(buf);
|
|
1612
|
+
free(filename);
|
|
1613
|
+
return 0;
|
|
1614
|
+
|
|
1615
|
+
fail:
|
|
1616
|
+
free(buf);
|
|
1617
|
+
free(filename);
|
|
1618
|
+
return 1;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
char *extract_desc(const char *buf)
|
|
1622
|
+
{
|
|
1623
|
+
const char *p, *desc_start;
|
|
1624
|
+
char *desc;
|
|
1625
|
+
int len;
|
|
1626
|
+
|
|
1627
|
+
p = buf;
|
|
1628
|
+
while (*p != '\0') {
|
|
1629
|
+
if (p[0] == '/' && p[1] == '*' && p[2] == '-' && p[3] != '/') {
|
|
1630
|
+
p += 3;
|
|
1631
|
+
desc_start = p;
|
|
1632
|
+
while (*p != '\0' && (p[0] != '*' || p[1] != '/'))
|
|
1633
|
+
p++;
|
|
1634
|
+
if (*p == '\0') {
|
|
1635
|
+
warning("Expecting end of desc comment");
|
|
1636
|
+
return NULL;
|
|
1637
|
+
}
|
|
1638
|
+
len = p - desc_start;
|
|
1639
|
+
desc = malloc(len + 1);
|
|
1640
|
+
memcpy(desc, desc_start, len);
|
|
1641
|
+
desc[len] = '\0';
|
|
1642
|
+
return desc;
|
|
1643
|
+
} else {
|
|
1644
|
+
p++;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
return NULL;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
static char *find_tag(char *desc, const char *tag, int *state)
|
|
1651
|
+
{
|
|
1652
|
+
char *p;
|
|
1653
|
+
p = strstr(desc, tag);
|
|
1654
|
+
if (p) {
|
|
1655
|
+
p += strlen(tag);
|
|
1656
|
+
*state = 0;
|
|
1657
|
+
}
|
|
1658
|
+
return p;
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
static char *get_option(char **pp, int *state)
|
|
1662
|
+
{
|
|
1663
|
+
char *p, *p0, *option = NULL;
|
|
1664
|
+
if (*pp) {
|
|
1665
|
+
for (p = *pp;; p++) {
|
|
1666
|
+
switch (*p) {
|
|
1667
|
+
case '[':
|
|
1668
|
+
*state += 1;
|
|
1669
|
+
continue;
|
|
1670
|
+
case ']':
|
|
1671
|
+
*state -= 1;
|
|
1672
|
+
if (*state > 0)
|
|
1673
|
+
continue;
|
|
1674
|
+
p = NULL;
|
|
1675
|
+
break;
|
|
1676
|
+
case ' ':
|
|
1677
|
+
case '\t':
|
|
1678
|
+
case '\r':
|
|
1679
|
+
case ',':
|
|
1680
|
+
case '-':
|
|
1681
|
+
continue;
|
|
1682
|
+
case '\n':
|
|
1683
|
+
if (*state > 0 || p[1] == ' ')
|
|
1684
|
+
continue;
|
|
1685
|
+
p = NULL;
|
|
1686
|
+
break;
|
|
1687
|
+
case '\0':
|
|
1688
|
+
p = NULL;
|
|
1689
|
+
break;
|
|
1690
|
+
default:
|
|
1691
|
+
p0 = p;
|
|
1692
|
+
p += strcspn(p0, " \t\r\n,]");
|
|
1693
|
+
option = strdup_len(p0, p - p0);
|
|
1694
|
+
break;
|
|
1695
|
+
}
|
|
1696
|
+
break;
|
|
1697
|
+
}
|
|
1698
|
+
*pp = p;
|
|
1699
|
+
}
|
|
1700
|
+
return option;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
void update_stats(JSRuntime *rt, const char *filename) {
|
|
1704
|
+
JSMemoryUsage stats;
|
|
1705
|
+
JS_ComputeMemoryUsage(rt, &stats);
|
|
1706
|
+
js_mutex_lock(&stats_mutex);
|
|
1707
|
+
if (stats_count++ == 0) {
|
|
1708
|
+
stats_avg = stats_all = stats_min = stats_max = stats;
|
|
1709
|
+
free(stats_min_filename);
|
|
1710
|
+
stats_min_filename = strdup(filename);
|
|
1711
|
+
free(stats_max_filename);
|
|
1712
|
+
stats_max_filename = strdup(filename);
|
|
1713
|
+
} else {
|
|
1714
|
+
if (stats_max.malloc_size < stats.malloc_size) {
|
|
1715
|
+
stats_max = stats;
|
|
1716
|
+
free(stats_max_filename);
|
|
1717
|
+
stats_max_filename = strdup(filename);
|
|
1718
|
+
}
|
|
1719
|
+
if (stats_min.malloc_size > stats.malloc_size) {
|
|
1720
|
+
stats_min = stats;
|
|
1721
|
+
free(stats_min_filename);
|
|
1722
|
+
stats_min_filename = strdup(filename);
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
#define update(f) stats_avg.f = (stats_all.f += stats.f) / stats_count
|
|
1726
|
+
update(malloc_count);
|
|
1727
|
+
update(malloc_size);
|
|
1728
|
+
update(memory_used_count);
|
|
1729
|
+
update(memory_used_size);
|
|
1730
|
+
update(atom_count);
|
|
1731
|
+
update(atom_size);
|
|
1732
|
+
update(str_count);
|
|
1733
|
+
update(str_size);
|
|
1734
|
+
update(obj_count);
|
|
1735
|
+
update(obj_size);
|
|
1736
|
+
update(prop_count);
|
|
1737
|
+
update(prop_size);
|
|
1738
|
+
update(shape_count);
|
|
1739
|
+
update(shape_size);
|
|
1740
|
+
update(js_func_count);
|
|
1741
|
+
update(js_func_size);
|
|
1742
|
+
update(js_func_code_size);
|
|
1743
|
+
update(js_func_pc2line_count);
|
|
1744
|
+
update(js_func_pc2line_size);
|
|
1745
|
+
update(c_func_count);
|
|
1746
|
+
update(array_count);
|
|
1747
|
+
update(fast_array_count);
|
|
1748
|
+
update(fast_array_elements);
|
|
1749
|
+
}
|
|
1750
|
+
#undef update
|
|
1751
|
+
js_mutex_unlock(&stats_mutex);
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
static JSValue qjs_black_box(JSContext *ctx, JSValueConst this_val,
|
|
1755
|
+
int argc, JSValueConst argv[], int magic)
|
|
1756
|
+
{
|
|
1757
|
+
return JS_NewInt32(ctx, js_std_cmd(magic, ctx, &argv[0]));
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
static const JSCFunctionListEntry qjs_methods[] = {
|
|
1761
|
+
JS_CFUNC_MAGIC_DEF("getStringKind", 1, qjs_black_box, /*GetStringKind*/3),
|
|
1762
|
+
};
|
|
1763
|
+
|
|
1764
|
+
static const JSCFunctionListEntry qjs_object =
|
|
1765
|
+
JS_OBJECT_DEF("qjs", qjs_methods, countof(qjs_methods), JS_PROP_C_W_E);
|
|
1766
|
+
|
|
1767
|
+
JSContext *JS_NewCustomContext(JSRuntime *rt)
|
|
1768
|
+
{
|
|
1769
|
+
JSContext *ctx;
|
|
1770
|
+
JSValue obj;
|
|
1771
|
+
|
|
1772
|
+
ctx = JS_NewContext(rt);
|
|
1773
|
+
if (ctx && local) {
|
|
1774
|
+
js_init_module_std(ctx, "qjs:std");
|
|
1775
|
+
js_init_module_os(ctx, "qjs:os");
|
|
1776
|
+
js_init_module_bjson(ctx, "qjs:bjson");
|
|
1777
|
+
obj = JS_GetGlobalObject(ctx);
|
|
1778
|
+
JS_SetPropertyFunctionList(ctx, obj, &qjs_object, 1);
|
|
1779
|
+
JS_FreeValue(ctx, obj);
|
|
1780
|
+
}
|
|
1781
|
+
return ctx;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
int run_test_buf(ThreadLocalStorage *tls, const char *filename, char *harness,
|
|
1785
|
+
namelist_t *ip, char *buf, size_t buf_len,
|
|
1786
|
+
const char* error_type, int eval_flags, bool is_negative,
|
|
1787
|
+
bool is_async, bool can_block, bool track_promise_rejections,
|
|
1788
|
+
int *msec)
|
|
1789
|
+
{
|
|
1790
|
+
JSRuntime *rt;
|
|
1791
|
+
JSContext *ctx;
|
|
1792
|
+
int i, ret;
|
|
1793
|
+
|
|
1794
|
+
rt = JS_NewRuntime();
|
|
1795
|
+
if (rt == NULL) {
|
|
1796
|
+
fatal(1, "JS_NewRuntime failure");
|
|
1797
|
+
}
|
|
1798
|
+
JS_SetDumpFlags(rt, JS_DUMP_LEAKS);
|
|
1799
|
+
JS_SetRuntimeOpaque(rt, tls);
|
|
1800
|
+
js_std_init_handlers(rt);
|
|
1801
|
+
ctx = JS_NewCustomContext(rt);
|
|
1802
|
+
if (ctx == NULL) {
|
|
1803
|
+
JS_FreeRuntime(rt);
|
|
1804
|
+
fatal(1, "JS_NewContext failure");
|
|
1805
|
+
}
|
|
1806
|
+
JS_SetRuntimeInfo(rt, filename);
|
|
1807
|
+
|
|
1808
|
+
JS_SetCanBlock(rt, can_block);
|
|
1809
|
+
|
|
1810
|
+
/* loader for ES6 modules */
|
|
1811
|
+
JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader_test, NULL, (void *) filename);
|
|
1812
|
+
|
|
1813
|
+
if (track_promise_rejections)
|
|
1814
|
+
JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker, NULL);
|
|
1815
|
+
|
|
1816
|
+
add_helpers(ctx);
|
|
1817
|
+
|
|
1818
|
+
for (i = 0; i < ip->count; i++) {
|
|
1819
|
+
if (eval_file(ctx, harness, ip->array[i], JS_EVAL_TYPE_GLOBAL)) {
|
|
1820
|
+
fatal(1, "error including %s for %s", ip->array[i], filename);
|
|
1821
|
+
}
|
|
1822
|
+
// hack to get useful stack traces from Test262Error exceptions
|
|
1823
|
+
if (verbose > 1 && str_equal(ip->array[i], "sta.js")) {
|
|
1824
|
+
static const char hack[] =
|
|
1825
|
+
";(function(C){"
|
|
1826
|
+
"globalThis.Test262Error = class Test262Error extends Error {};"
|
|
1827
|
+
"globalThis.Test262Error.thrower = C.thrower;"
|
|
1828
|
+
"})(Test262Error)";
|
|
1829
|
+
JS_FreeValue(ctx, JS_Eval(ctx, hack, sizeof(hack)-1, "sta.js", JS_EVAL_TYPE_GLOBAL));
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
ret = eval_buf(ctx, buf, buf_len, filename, true, is_negative,
|
|
1834
|
+
error_type, eval_flags, is_async, msec);
|
|
1835
|
+
ret = (ret != 0);
|
|
1836
|
+
|
|
1837
|
+
if (dump_memory) {
|
|
1838
|
+
update_stats(rt, filename);
|
|
1839
|
+
}
|
|
1840
|
+
js_agent_free(ctx);
|
|
1841
|
+
JS_FreeContext(ctx);
|
|
1842
|
+
js_std_free_handlers(rt);
|
|
1843
|
+
JS_FreeRuntime(rt);
|
|
1844
|
+
|
|
1845
|
+
atomic_inc(&test_count);
|
|
1846
|
+
if (ret)
|
|
1847
|
+
atomic_inc(&test_failed);
|
|
1848
|
+
return ret;
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
int run_test(ThreadLocalStorage *tls, const char *filename, int *msec)
|
|
1852
|
+
{
|
|
1853
|
+
char harnessbuf[1024];
|
|
1854
|
+
char *harness;
|
|
1855
|
+
char *buf;
|
|
1856
|
+
size_t buf_len;
|
|
1857
|
+
char *desc, *p;
|
|
1858
|
+
char *error_type;
|
|
1859
|
+
int ret, eval_flags, use_strict, use_nostrict;
|
|
1860
|
+
bool is_negative, is_nostrict, is_onlystrict, is_async, is_module, skip;
|
|
1861
|
+
bool detect_module = true;
|
|
1862
|
+
bool track_promise_rejections = false;
|
|
1863
|
+
bool can_block;
|
|
1864
|
+
namelist_t include_list = { 0 }, *ip = &include_list;
|
|
1865
|
+
|
|
1866
|
+
is_nostrict = is_onlystrict = is_negative = is_async = is_module = skip = false;
|
|
1867
|
+
can_block = true;
|
|
1868
|
+
error_type = NULL;
|
|
1869
|
+
buf = load_file(filename, &buf_len);
|
|
1870
|
+
|
|
1871
|
+
harness = harness_dir;
|
|
1872
|
+
|
|
1873
|
+
if (!harness) {
|
|
1874
|
+
p = strstr(filename, "test/");
|
|
1875
|
+
if (p) {
|
|
1876
|
+
snprintf(harnessbuf, sizeof(harnessbuf), "%.*s%s",
|
|
1877
|
+
(int)(p - filename), filename, "harness");
|
|
1878
|
+
}
|
|
1879
|
+
harness = harnessbuf;
|
|
1880
|
+
}
|
|
1881
|
+
if (!local) {
|
|
1882
|
+
namelist_add(ip, NULL, "sta.js");
|
|
1883
|
+
namelist_add(ip, NULL, "assert.js");
|
|
1884
|
+
}
|
|
1885
|
+
/* extract the YAML frontmatter */
|
|
1886
|
+
desc = extract_desc(buf);
|
|
1887
|
+
if (desc) {
|
|
1888
|
+
char *ifile, *option;
|
|
1889
|
+
int state;
|
|
1890
|
+
p = find_tag(desc, "includes:", &state);
|
|
1891
|
+
if (p) {
|
|
1892
|
+
while ((ifile = get_option(&p, &state)) != NULL) {
|
|
1893
|
+
// skip unsupported harness files
|
|
1894
|
+
if (find_word(harness_exclude, ifile)) {
|
|
1895
|
+
skip |= 1;
|
|
1896
|
+
} else {
|
|
1897
|
+
namelist_add(ip, NULL, ifile);
|
|
1898
|
+
}
|
|
1899
|
+
free(ifile);
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
p = find_tag(desc, "flags:", &state);
|
|
1903
|
+
if (p) {
|
|
1904
|
+
while ((option = get_option(&p, &state)) != NULL) {
|
|
1905
|
+
if (str_equal(option, "noStrict") ||
|
|
1906
|
+
str_equal(option, "raw")) {
|
|
1907
|
+
is_nostrict = true;
|
|
1908
|
+
skip |= (test_mode == TEST_STRICT);
|
|
1909
|
+
}
|
|
1910
|
+
else if (str_equal(option, "onlyStrict")) {
|
|
1911
|
+
is_onlystrict = true;
|
|
1912
|
+
skip |= (test_mode == TEST_NOSTRICT);
|
|
1913
|
+
}
|
|
1914
|
+
else if (str_equal(option, "async")) {
|
|
1915
|
+
is_async = true;
|
|
1916
|
+
skip |= skip_async;
|
|
1917
|
+
}
|
|
1918
|
+
else if (str_equal(option, "qjs:no-detect-module")) {
|
|
1919
|
+
detect_module = false;
|
|
1920
|
+
}
|
|
1921
|
+
else if (str_equal(option, "qjs:track-promise-rejections")) {
|
|
1922
|
+
track_promise_rejections = true;
|
|
1923
|
+
}
|
|
1924
|
+
else if (str_equal(option, "module")) {
|
|
1925
|
+
is_module = true;
|
|
1926
|
+
skip |= skip_module;
|
|
1927
|
+
}
|
|
1928
|
+
else if (str_equal(option, "CanBlockIsFalse")) {
|
|
1929
|
+
can_block = false;
|
|
1930
|
+
}
|
|
1931
|
+
free(option);
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
p = find_tag(desc, "negative:", &state);
|
|
1935
|
+
if (p) {
|
|
1936
|
+
/* XXX: should extract the phase */
|
|
1937
|
+
char *q = find_tag(p, "type:", &state);
|
|
1938
|
+
if (q) {
|
|
1939
|
+
while (isspace((unsigned char)*q))
|
|
1940
|
+
q++;
|
|
1941
|
+
error_type = strdup_len(q, strcspn(q, " \r\n"));
|
|
1942
|
+
}
|
|
1943
|
+
is_negative = true;
|
|
1944
|
+
}
|
|
1945
|
+
p = find_tag(desc, "features:", &state);
|
|
1946
|
+
if (p) {
|
|
1947
|
+
while ((option = get_option(&p, &state)) != NULL) {
|
|
1948
|
+
if (find_word(harness_features, option)) {
|
|
1949
|
+
/* feature is enabled */
|
|
1950
|
+
} else if (find_word(harness_skip_features, option)) {
|
|
1951
|
+
/* skip disabled feature */
|
|
1952
|
+
skip |= 1;
|
|
1953
|
+
} else {
|
|
1954
|
+
/* feature is not listed: skip and warn */
|
|
1955
|
+
printf("%s:%d: unknown feature: %s\n", filename, 1, option);
|
|
1956
|
+
skip |= 1;
|
|
1957
|
+
}
|
|
1958
|
+
free(option);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
free(desc);
|
|
1962
|
+
}
|
|
1963
|
+
if (is_async)
|
|
1964
|
+
namelist_add(ip, NULL, "doneprintHandle.js");
|
|
1965
|
+
|
|
1966
|
+
use_strict = use_nostrict = 0;
|
|
1967
|
+
/* XXX: should remove 'test_mode' or simplify it just to force
|
|
1968
|
+
strict or non strict mode for single file tests */
|
|
1969
|
+
switch (test_mode) {
|
|
1970
|
+
case TEST_DEFAULT_NOSTRICT:
|
|
1971
|
+
if (is_onlystrict)
|
|
1972
|
+
use_strict = 1;
|
|
1973
|
+
else
|
|
1974
|
+
use_nostrict = 1;
|
|
1975
|
+
break;
|
|
1976
|
+
case TEST_DEFAULT_STRICT:
|
|
1977
|
+
if (is_nostrict)
|
|
1978
|
+
use_nostrict = 1;
|
|
1979
|
+
else
|
|
1980
|
+
use_strict = 1;
|
|
1981
|
+
break;
|
|
1982
|
+
case TEST_NOSTRICT:
|
|
1983
|
+
if (!is_onlystrict)
|
|
1984
|
+
use_nostrict = 1;
|
|
1985
|
+
break;
|
|
1986
|
+
case TEST_STRICT:
|
|
1987
|
+
if (!is_nostrict)
|
|
1988
|
+
use_strict = 1;
|
|
1989
|
+
break;
|
|
1990
|
+
case TEST_ALL:
|
|
1991
|
+
if (is_module) {
|
|
1992
|
+
use_nostrict = 1;
|
|
1993
|
+
} else {
|
|
1994
|
+
if (!is_nostrict)
|
|
1995
|
+
use_strict = 1;
|
|
1996
|
+
if (!is_onlystrict)
|
|
1997
|
+
use_nostrict = 1;
|
|
1998
|
+
}
|
|
1999
|
+
break;
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
if (skip || use_strict + use_nostrict == 0) {
|
|
2003
|
+
atomic_inc(&test_skipped);
|
|
2004
|
+
ret = -2;
|
|
2005
|
+
} else {
|
|
2006
|
+
if (local && detect_module) {
|
|
2007
|
+
is_module = JS_DetectModule(buf, buf_len);
|
|
2008
|
+
}
|
|
2009
|
+
if (is_module) {
|
|
2010
|
+
eval_flags = JS_EVAL_TYPE_MODULE;
|
|
2011
|
+
} else {
|
|
2012
|
+
eval_flags = JS_EVAL_TYPE_GLOBAL;
|
|
2013
|
+
}
|
|
2014
|
+
ret = 0;
|
|
2015
|
+
if (use_nostrict) {
|
|
2016
|
+
ret = run_test_buf(tls, filename, harness, ip, buf, buf_len,
|
|
2017
|
+
error_type, eval_flags, is_negative, is_async,
|
|
2018
|
+
can_block, track_promise_rejections, msec);
|
|
2019
|
+
}
|
|
2020
|
+
if (use_strict) {
|
|
2021
|
+
ret |= run_test_buf(tls, filename, harness, ip, buf, buf_len,
|
|
2022
|
+
error_type, eval_flags | JS_EVAL_FLAG_STRICT,
|
|
2023
|
+
is_negative, is_async, can_block,
|
|
2024
|
+
track_promise_rejections, msec);
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
namelist_free(&include_list);
|
|
2028
|
+
free(error_type);
|
|
2029
|
+
free(buf);
|
|
2030
|
+
|
|
2031
|
+
return ret;
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
/* run a test when called by test262-harness+eshost */
|
|
2035
|
+
int run_test262_harness_test(ThreadLocalStorage *tls, const char *filename,
|
|
2036
|
+
bool is_module)
|
|
2037
|
+
{
|
|
2038
|
+
JSRuntime *rt;
|
|
2039
|
+
JSContext *ctx;
|
|
2040
|
+
char *buf;
|
|
2041
|
+
size_t buf_len;
|
|
2042
|
+
int eval_flags, ret_code, ret;
|
|
2043
|
+
JSValue res_val;
|
|
2044
|
+
bool can_block;
|
|
2045
|
+
|
|
2046
|
+
outfile = stdout; /* for js_print_262 */
|
|
2047
|
+
|
|
2048
|
+
rt = JS_NewRuntime();
|
|
2049
|
+
if (rt == NULL) {
|
|
2050
|
+
fatal(1, "JS_NewRuntime failure");
|
|
2051
|
+
}
|
|
2052
|
+
JS_SetDumpFlags(rt, JS_DUMP_LEAKS);
|
|
2053
|
+
JS_SetRuntimeOpaque(rt, tls);
|
|
2054
|
+
ctx = JS_NewContext(rt);
|
|
2055
|
+
if (ctx == NULL) {
|
|
2056
|
+
JS_FreeRuntime(rt);
|
|
2057
|
+
fatal(1, "JS_NewContext failure");
|
|
2058
|
+
}
|
|
2059
|
+
JS_SetRuntimeInfo(rt, filename);
|
|
2060
|
+
|
|
2061
|
+
can_block = true;
|
|
2062
|
+
JS_SetCanBlock(rt, can_block);
|
|
2063
|
+
|
|
2064
|
+
/* loader for ES6 modules */
|
|
2065
|
+
JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader_test, NULL, (void *) filename);
|
|
2066
|
+
|
|
2067
|
+
add_helpers(ctx);
|
|
2068
|
+
|
|
2069
|
+
buf = load_file(filename, &buf_len);
|
|
2070
|
+
|
|
2071
|
+
if (is_module) {
|
|
2072
|
+
eval_flags = JS_EVAL_TYPE_MODULE;
|
|
2073
|
+
} else {
|
|
2074
|
+
eval_flags = JS_EVAL_TYPE_GLOBAL;
|
|
2075
|
+
}
|
|
2076
|
+
res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
|
|
2077
|
+
ret_code = 0;
|
|
2078
|
+
if (JS_IsException(res_val)) {
|
|
2079
|
+
js_std_dump_error(ctx);
|
|
2080
|
+
ret_code = 1;
|
|
2081
|
+
} else {
|
|
2082
|
+
JSValue promise = JS_UNDEFINED;
|
|
2083
|
+
if (is_module) {
|
|
2084
|
+
promise = res_val;
|
|
2085
|
+
} else {
|
|
2086
|
+
JS_FreeValue(ctx, res_val);
|
|
2087
|
+
}
|
|
2088
|
+
for(;;) {
|
|
2089
|
+
JSContext *ctx1;
|
|
2090
|
+
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
|
|
2091
|
+
if (ret < 0) {
|
|
2092
|
+
js_std_dump_error(ctx1);
|
|
2093
|
+
ret_code = 1;
|
|
2094
|
+
} else if (ret == 0) {
|
|
2095
|
+
break;
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
/* dump the error if the module returned an error. */
|
|
2099
|
+
if (is_module) {
|
|
2100
|
+
JSPromiseStateEnum state = JS_PromiseState(ctx, promise);
|
|
2101
|
+
if (state == JS_PROMISE_REJECTED) {
|
|
2102
|
+
JS_Throw(ctx, JS_PromiseResult(ctx, promise));
|
|
2103
|
+
js_std_dump_error(ctx);
|
|
2104
|
+
ret_code = 1;
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
JS_FreeValue(ctx, promise);
|
|
2108
|
+
}
|
|
2109
|
+
free(buf);
|
|
2110
|
+
js_agent_free(ctx);
|
|
2111
|
+
JS_FreeContext(ctx);
|
|
2112
|
+
JS_FreeRuntime(rt);
|
|
2113
|
+
return ret_code;
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
clock_t last_clock;
|
|
2117
|
+
|
|
2118
|
+
void show_progress(void *unused) {
|
|
2119
|
+
int interval = 1000*1000*1000 / 4; // 250 ms
|
|
2120
|
+
|
|
2121
|
+
js_mutex_lock(&progress_mutex);
|
|
2122
|
+
while (js_cond_timedwait(&progress_cond, &progress_mutex, interval)) {
|
|
2123
|
+
/* output progress indicator: erase end of line and return to col 0 */
|
|
2124
|
+
fprintf(stderr, "%d/%d/%d \r",
|
|
2125
|
+
atomic_load(&test_failed),
|
|
2126
|
+
atomic_load(&test_count),
|
|
2127
|
+
atomic_load(&test_skipped));
|
|
2128
|
+
fflush(stderr);
|
|
2129
|
+
}
|
|
2130
|
+
js_mutex_unlock(&progress_mutex);
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
enum { INCLUDE, EXCLUDE, SKIP };
|
|
2134
|
+
|
|
2135
|
+
int include_exclude_or_skip(int i) // naming is hard...
|
|
2136
|
+
{
|
|
2137
|
+
if (namelist_find(&exclude_list, test_list.array[i]) >= 0)
|
|
2138
|
+
return EXCLUDE;
|
|
2139
|
+
if (i < start_index)
|
|
2140
|
+
return SKIP;
|
|
2141
|
+
if (stop_index >= 0 && i > stop_index)
|
|
2142
|
+
return SKIP;
|
|
2143
|
+
return INCLUDE;
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
void run_test_dir_list(void *arg)
|
|
2147
|
+
{
|
|
2148
|
+
ThreadLocalStorage tls_s, *tls = &tls_s;
|
|
2149
|
+
const char *p;
|
|
2150
|
+
int i, msec;
|
|
2151
|
+
|
|
2152
|
+
init_thread_local_storage(tls);
|
|
2153
|
+
|
|
2154
|
+
for (i = (uintptr_t)arg; i < test_list.count; i += nthreads) {
|
|
2155
|
+
if (INCLUDE != include_exclude_or_skip(i))
|
|
2156
|
+
continue;
|
|
2157
|
+
p = test_list.array[i];
|
|
2158
|
+
msec = 0;
|
|
2159
|
+
run_test(tls, p, &msec);
|
|
2160
|
+
if (verbose > 1 || (slow_test_threshold && msec >= slow_test_threshold))
|
|
2161
|
+
fprintf(stderr, "%s (%d ms)\n", p, msec);
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
void help(void)
|
|
2166
|
+
{
|
|
2167
|
+
printf("run-test262 version %s\n"
|
|
2168
|
+
"usage: run-test262 [options] {-f file ... | [dir_list] [index range]}\n"
|
|
2169
|
+
"-h help\n"
|
|
2170
|
+
"-a run tests in strict and nostrict modes\n"
|
|
2171
|
+
"-m print memory usage summary\n"
|
|
2172
|
+
"-N run test prepared by test262-harness+eshost\n"
|
|
2173
|
+
"-s run tests in strict mode, skip @nostrict tests\n"
|
|
2174
|
+
"-E only run tests from the error file\n"
|
|
2175
|
+
"-u update error file\n"
|
|
2176
|
+
"-v verbose: output error messages\n"
|
|
2177
|
+
"-vv like -v but also print test name and running time\n"
|
|
2178
|
+
"-T duration display tests taking more than 'duration' ms\n"
|
|
2179
|
+
"-t threads number of parallel threads; default: numcpus - 1\n"
|
|
2180
|
+
"-c file read configuration from 'file'\n"
|
|
2181
|
+
"-d dir run all test files in directory tree 'dir'\n"
|
|
2182
|
+
"-e file load the known errors from 'file'\n"
|
|
2183
|
+
"-f file execute single test from 'file'\n"
|
|
2184
|
+
"-x file exclude tests listed in 'file'\n",
|
|
2185
|
+
JS_GetVersion());
|
|
2186
|
+
exit(1);
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
char *get_opt_arg(const char *option, char *arg)
|
|
2190
|
+
{
|
|
2191
|
+
if (!arg) {
|
|
2192
|
+
fatal(2, "missing argument for option %s", option);
|
|
2193
|
+
}
|
|
2194
|
+
return arg;
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
int main(int argc, char **argv)
|
|
2198
|
+
{
|
|
2199
|
+
ThreadLocalStorage tls_s, *tls = &tls_s;
|
|
2200
|
+
int i, optind;
|
|
2201
|
+
bool is_dir_list;
|
|
2202
|
+
bool only_check_errors = false;
|
|
2203
|
+
const char *filename;
|
|
2204
|
+
const char *ignore = "";
|
|
2205
|
+
bool is_test262_harness = false;
|
|
2206
|
+
bool is_module = false;
|
|
2207
|
+
bool enable_progress = true;
|
|
2208
|
+
|
|
2209
|
+
js_std_set_worker_new_context_func(JS_NewCustomContext);
|
|
2210
|
+
|
|
2211
|
+
init_thread_local_storage(tls);
|
|
2212
|
+
js_mutex_init(&stats_mutex);
|
|
2213
|
+
|
|
2214
|
+
#ifndef _WIN32
|
|
2215
|
+
/* Date tests assume California local time */
|
|
2216
|
+
setenv("TZ", "America/Los_Angeles", 1);
|
|
2217
|
+
#endif
|
|
2218
|
+
|
|
2219
|
+
// minus one to not (over)commit the system completely
|
|
2220
|
+
nthreads = cpu_count() - 1;
|
|
2221
|
+
|
|
2222
|
+
optind = 1;
|
|
2223
|
+
while (optind < argc) {
|
|
2224
|
+
char *arg = argv[optind];
|
|
2225
|
+
if (*arg != '-')
|
|
2226
|
+
break;
|
|
2227
|
+
optind++;
|
|
2228
|
+
if (strstr("-c -d -e -x -f -E -T -t", arg))
|
|
2229
|
+
optind++;
|
|
2230
|
+
if (strstr("-d -f", arg))
|
|
2231
|
+
ignore = "testdir"; // run only the tests from -d or -f
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
/* cannot use getopt because we want to pass the command line to
|
|
2235
|
+
the script */
|
|
2236
|
+
optind = 1;
|
|
2237
|
+
is_dir_list = true;
|
|
2238
|
+
while (optind < argc) {
|
|
2239
|
+
char *arg = argv[optind];
|
|
2240
|
+
if (*arg != '-')
|
|
2241
|
+
break;
|
|
2242
|
+
optind++;
|
|
2243
|
+
if (str_equal(arg, "-h")) {
|
|
2244
|
+
help();
|
|
2245
|
+
} else if (str_equal(arg, "-m")) {
|
|
2246
|
+
dump_memory++;
|
|
2247
|
+
} else if (str_equal(arg, "-s")) {
|
|
2248
|
+
test_mode = TEST_STRICT;
|
|
2249
|
+
} else if (str_equal(arg, "-a")) {
|
|
2250
|
+
test_mode = TEST_ALL;
|
|
2251
|
+
} else if (str_equal(arg, "-u")) {
|
|
2252
|
+
update_errors++;
|
|
2253
|
+
} else if (arg == strstr(arg, "-v")) {
|
|
2254
|
+
verbose += str_count(arg, "v");
|
|
2255
|
+
} else if (str_equal(arg, "-c")) {
|
|
2256
|
+
load_config(get_opt_arg(arg, argv[optind++]), ignore);
|
|
2257
|
+
} else if (str_equal(arg, "-d")) {
|
|
2258
|
+
enumerate_tests(get_opt_arg(arg, argv[optind++]));
|
|
2259
|
+
} else if (str_equal(arg, "-e")) {
|
|
2260
|
+
error_filename = get_opt_arg(arg, argv[optind++]);
|
|
2261
|
+
} else if (str_equal(arg, "-x")) {
|
|
2262
|
+
namelist_load(&exclude_list, get_opt_arg(arg, argv[optind++]));
|
|
2263
|
+
} else if (str_equal(arg, "-f")) {
|
|
2264
|
+
is_dir_list = false;
|
|
2265
|
+
} else if (str_equal(arg, "-E")) {
|
|
2266
|
+
only_check_errors = true;
|
|
2267
|
+
} else if (str_equal(arg, "-T")) {
|
|
2268
|
+
slow_test_threshold = atoi(get_opt_arg(arg, argv[optind++]));
|
|
2269
|
+
} else if (str_equal(arg, "-t")) {
|
|
2270
|
+
nthreads = atoi(get_opt_arg(arg, argv[optind++]));
|
|
2271
|
+
} else if (str_equal(arg, "-N")) {
|
|
2272
|
+
is_test262_harness = true;
|
|
2273
|
+
} else if (str_equal(arg, "--module")) {
|
|
2274
|
+
is_module = true;
|
|
2275
|
+
} else {
|
|
2276
|
+
fatal(1, "unknown option: %s", arg);
|
|
2277
|
+
break;
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
if (optind >= argc && !test_list.count)
|
|
2282
|
+
help();
|
|
2283
|
+
|
|
2284
|
+
if (is_test262_harness) {
|
|
2285
|
+
return run_test262_harness_test(tls, argv[optind], is_module);
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
nthreads = max_int(nthreads, 1);
|
|
2289
|
+
nthreads = min_int(nthreads, countof(threads));
|
|
2290
|
+
|
|
2291
|
+
error_out = stdout;
|
|
2292
|
+
if (error_filename) {
|
|
2293
|
+
error_file = load_file(error_filename, NULL);
|
|
2294
|
+
if (only_check_errors && error_file) {
|
|
2295
|
+
namelist_free(&test_list);
|
|
2296
|
+
namelist_add_from_error_file(&test_list, error_file);
|
|
2297
|
+
}
|
|
2298
|
+
if (update_errors) {
|
|
2299
|
+
free(error_file);
|
|
2300
|
+
error_file = NULL;
|
|
2301
|
+
error_out = fopen(error_filename, "w");
|
|
2302
|
+
if (!error_out) {
|
|
2303
|
+
perror_exit(1, error_filename);
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
update_exclude_dirs();
|
|
2309
|
+
|
|
2310
|
+
#ifndef _WIN32
|
|
2311
|
+
if (!isatty(STDOUT_FILENO)) {
|
|
2312
|
+
enable_progress = false;
|
|
2313
|
+
}
|
|
2314
|
+
#endif
|
|
2315
|
+
|
|
2316
|
+
if (is_dir_list) {
|
|
2317
|
+
if (optind < argc && !isdigit((unsigned char)argv[optind][0])) {
|
|
2318
|
+
filename = argv[optind++];
|
|
2319
|
+
namelist_load(&test_list, filename);
|
|
2320
|
+
}
|
|
2321
|
+
start_index = 0;
|
|
2322
|
+
stop_index = -1;
|
|
2323
|
+
if (optind < argc) {
|
|
2324
|
+
start_index = atoi(argv[optind++]);
|
|
2325
|
+
if (optind < argc) {
|
|
2326
|
+
stop_index = atoi(argv[optind++]);
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
// exclude_dir_list has already been sorted by update_exclude_dirs()
|
|
2330
|
+
namelist_sort(&test_list);
|
|
2331
|
+
namelist_sort(&exclude_list);
|
|
2332
|
+
for (i = 0; i < test_list.count; i++) {
|
|
2333
|
+
switch (include_exclude_or_skip(i)) {
|
|
2334
|
+
case EXCLUDE:
|
|
2335
|
+
test_excluded++;
|
|
2336
|
+
break;
|
|
2337
|
+
case SKIP:
|
|
2338
|
+
test_skipped++;
|
|
2339
|
+
break;
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
js_cond_init(&progress_cond);
|
|
2343
|
+
js_mutex_init(&progress_mutex);
|
|
2344
|
+
if (enable_progress) {
|
|
2345
|
+
js_thread_create(&progress_thread, show_progress, NULL, /*flags*/0);
|
|
2346
|
+
}
|
|
2347
|
+
for (i = 0; i < nthreads; i++) {
|
|
2348
|
+
js_thread_create(&threads[i], run_test_dir_list,
|
|
2349
|
+
(void *)(uintptr_t)i, /*flags*/0);
|
|
2350
|
+
}
|
|
2351
|
+
for (i = 0; i < nthreads; i++)
|
|
2352
|
+
js_thread_join(threads[i]);
|
|
2353
|
+
js_mutex_lock(&progress_mutex);
|
|
2354
|
+
js_cond_signal(&progress_cond);
|
|
2355
|
+
js_mutex_unlock(&progress_mutex);
|
|
2356
|
+
if (enable_progress) {
|
|
2357
|
+
js_thread_join(progress_thread);
|
|
2358
|
+
}
|
|
2359
|
+
js_mutex_destroy(&progress_mutex);
|
|
2360
|
+
js_cond_destroy(&progress_cond);
|
|
2361
|
+
} else {
|
|
2362
|
+
while (optind < argc) {
|
|
2363
|
+
int msec = 0;
|
|
2364
|
+
run_test(tls, argv[optind++], &msec);
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
if (dump_memory) {
|
|
2369
|
+
if (dump_memory > 1 && stats_count > 1) {
|
|
2370
|
+
printf("\nMininum memory statistics for %s:\n\n", stats_min_filename);
|
|
2371
|
+
JS_DumpMemoryUsage(stdout, &stats_min, NULL);
|
|
2372
|
+
printf("\nMaximum memory statistics for %s:\n\n", stats_max_filename);
|
|
2373
|
+
JS_DumpMemoryUsage(stdout, &stats_max, NULL);
|
|
2374
|
+
}
|
|
2375
|
+
printf("\nAverage memory statistics for %d tests:\n\n", stats_count);
|
|
2376
|
+
JS_DumpMemoryUsage(stdout, &stats_avg, NULL);
|
|
2377
|
+
printf("\n");
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
if (is_dir_list) {
|
|
2381
|
+
fprintf(stderr, "Result: %d/%d error%s",
|
|
2382
|
+
test_failed, test_count, test_count != 1 ? "s" : "");
|
|
2383
|
+
if (test_excluded)
|
|
2384
|
+
fprintf(stderr, ", %d excluded", test_excluded);
|
|
2385
|
+
if (test_skipped)
|
|
2386
|
+
fprintf(stderr, ", %d skipped", test_skipped);
|
|
2387
|
+
if (error_file) {
|
|
2388
|
+
if (new_errors)
|
|
2389
|
+
fprintf(stderr, ", %d new", new_errors);
|
|
2390
|
+
if (changed_errors)
|
|
2391
|
+
fprintf(stderr, ", %d changed", changed_errors);
|
|
2392
|
+
if (fixed_errors)
|
|
2393
|
+
fprintf(stderr, ", %d fixed", fixed_errors);
|
|
2394
|
+
}
|
|
2395
|
+
fprintf(stderr, "\n");
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
if (error_out && error_out != stdout) {
|
|
2399
|
+
fclose(error_out);
|
|
2400
|
+
error_out = NULL;
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
namelist_free(&test_list);
|
|
2404
|
+
namelist_free(&exclude_list);
|
|
2405
|
+
namelist_free(&exclude_dir_list);
|
|
2406
|
+
free(harness_dir);
|
|
2407
|
+
free(harness_features);
|
|
2408
|
+
free(harness_exclude);
|
|
2409
|
+
free(harness_skip_features);
|
|
2410
|
+
free(error_file);
|
|
2411
|
+
free(error_filename);
|
|
2412
|
+
free(stats_min_filename);
|
|
2413
|
+
free(stats_max_filename);
|
|
2414
|
+
|
|
2415
|
+
/* Signal that the error file is out of date. */
|
|
2416
|
+
return new_errors || changed_errors || fixed_errors;
|
|
2417
|
+
}
|