2107 lines · 61.2 KB · C
RawDownload
/* * ECMA Test 262 Runner for QuickJS *  * Copyright (c) 2017-2020 Fabrice Bellard * Copyright (c) 2017-2020 Charlie Gordon * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <inttypes.h>#include <string.h>#include <assert.h>#include <ctype.h>#include <unistd.h>#include <errno.h>#include <time.h>#include <dirent.h>#include <ftw.h> #include "cutils.h"#include "list.h"#include "quickjs-libc.h" /* enable test262 thread support to test SharedArrayBuffer and Atomics */#define CONFIG_AGENT #define CMD_NAME "run-test262" typedef struct namelist_t {    char **array;    int count;    int size;    unsigned int sorted : 1;} namelist_t; namelist_t test_list;namelist_t exclude_list;namelist_t exclude_dir_list; FILE *outfile;enum test_mode_t {    TEST_DEFAULT_NOSTRICT, /* run tests as nostrict unless test is flagged as strictonly */    TEST_DEFAULT_STRICT,   /* run tests as strict unless test is flagged as nostrict */    TEST_NOSTRICT,         /* run tests as nostrict, skip strictonly tests */    TEST_STRICT,           /* run tests as strict, skip nostrict tests */    TEST_ALL,              /* run tests in both strict and nostrict, unless restricted by spec */} test_mode = TEST_DEFAULT_NOSTRICT;int skip_async;int skip_module;int new_style;int dump_memory;int stats_count;JSMemoryUsage stats_all, stats_avg, stats_min, stats_max;char *stats_min_filename;char *stats_max_filename;int verbose;char *harness_dir;char *harness_exclude;char *harness_features;char *harness_skip_features;char *error_filename;char *error_file;FILE *error_out;char *report_filename;int update_errors;int test_count, test_failed, test_index, test_skipped, test_excluded;int new_errors, changed_errors, fixed_errors;int async_done; void warning(const char *, ...) __attribute__((__format__(__printf__, 1, 2)));void fatal(int, const char *, ...) __attribute__((__format__(__printf__, 2, 3))); void warning(const char *fmt, ...){    va_list ap;     fflush(stdout);    fprintf(stderr, "%s: ", CMD_NAME);    va_start(ap, fmt);    vfprintf(stderr, fmt, ap);    va_end(ap);    fputc('\n', stderr);} void fatal(int errcode, const char *fmt, ...){    va_list ap;     fflush(stdout);    fprintf(stderr, "%s: ", CMD_NAME);    va_start(ap, fmt);    vfprintf(stderr, fmt, ap);    va_end(ap);    fputc('\n', stderr);     exit(errcode);} void perror_exit(int errcode, const char *s){    fflush(stdout);    fprintf(stderr, "%s: ", CMD_NAME);    perror(s);    exit(errcode);} char *strdup_len(const char *str, int len){    char *p = malloc(len + 1);    memcpy(p, str, len);    p[len] = '\0';    return p;} static inline int str_equal(const char *a, const char *b) {    return !strcmp(a, b);} char *str_append(char **pp, const char *sep, const char *str) {    char *res, *p;    size_t len = 0;    p = *pp;    if (p) {        len = strlen(p) + strlen(sep);    }    res = malloc(len + strlen(str) + 1);    if (p) {        strcpy(res, p);        strcat(res, sep);    }    strcpy(res + len, str);    free(p);    return *pp = res;} char *str_strip(char *p){    size_t len = strlen(p);    while (len > 0 && isspace((unsigned char)p[len - 1]))        p[--len] = '\0';    while (isspace((unsigned char)*p))        p++;    return p;} int has_prefix(const char *str, const char *prefix){    return !strncmp(str, prefix, strlen(prefix));} char *skip_prefix(const char *str, const char *prefix){    int i;    for (i = 0;; i++) {        if (prefix[i] == '\0') {  /* skip the prefix */            str += i;            break;        }        if (str[i] != prefix[i])            break;    }    return (char *)str;} char *get_basename(const char *filename){    char *p;     p = strrchr(filename, '/');    if (!p)        return NULL;    return strdup_len(filename, p - filename);} char *compose_path(const char *path, const char *name){    int path_len, name_len;    char *d, *q;     if (!path || path[0] == '\0' || *name == '/') {        d = strdup(name);    } else {        path_len = strlen(path);        name_len = strlen(name);        d = malloc(path_len + 1 + name_len + 1);        if (d) {            q = d;            memcpy(q, path, path_len);            q += path_len;            if (path[path_len - 1] != '/')                *q++ = '/';            memcpy(q, name, name_len + 1);        }    }    return d;} int namelist_cmp(const char *a, const char *b){    /* compare strings in modified lexicographical order */    for (;;) {        int ca = (unsigned char)*a++;        int cb = (unsigned char)*b++;        if (isdigit(ca) && isdigit(cb)) {            int na = ca - '0';            int nb = cb - '0';            while (isdigit(ca = (unsigned char)*a++))                na = na * 10 + ca - '0';            while (isdigit(cb = (unsigned char)*b++))                nb = nb * 10 + cb - '0';            if (na < nb)                return -1;            if (na > nb)                return +1;        }        if (ca < cb)            return -1;        if (ca > cb)            return +1;        if (ca == '\0')            return 0;    }} int namelist_cmp_indirect(const void *a, const void *b){    return namelist_cmp(*(const char **)a, *(const char **)b);} void namelist_sort(namelist_t *lp){    int i, count;    if (lp->count > 1) {        qsort(lp->array, lp->count, sizeof(*lp->array), namelist_cmp_indirect);        /* remove duplicates */        for (count = i = 1; i < lp->count; i++) {            if (namelist_cmp(lp->array[count - 1], lp->array[i]) == 0) {                free(lp->array[i]);            } else {                lp->array[count++] = lp->array[i];            }        }        lp->count = count;    }    lp->sorted = 1;} int namelist_find(namelist_t *lp, const char *name){    int a, b, m, cmp;     if (!lp->sorted) {        namelist_sort(lp);    }    for (a = 0, b = lp->count; a < b;) {        m = a + (b - a) / 2;        cmp = namelist_cmp(lp->array[m], name);        if (cmp < 0)            a = m + 1;        else if (cmp > 0)            b = m;        else            return m;    }    return -1;} void namelist_add(namelist_t *lp, const char *base, const char *name){    char *s;     s = compose_path(base, name);    if (!s)        goto fail;    if (lp->count == lp->size) {        size_t newsize = lp->size + (lp->size >> 1) + 4;        char **a = realloc(lp->array, sizeof(lp->array[0]) * newsize);        if (!a)            goto fail;        lp->array = a;        lp->size = newsize;    }    lp->array[lp->count] = s;    lp->count++;    return;fail:    fatal(1, "allocation failure\n");} void namelist_load(namelist_t *lp, const char *filename){    char buf[1024];    char *base_name;    FILE *f;     f = fopen(filename, "rb");    if (!f) {        perror_exit(1, filename);    }    base_name = get_basename(filename);     while (fgets(buf, sizeof(buf), f) != NULL) {        char *p = str_strip(buf);        if (*p == '#' || *p == ';' || *p == '\0')            continue;  /* line comment */                namelist_add(lp, base_name, p);    }    free(base_name);    fclose(f);} void namelist_add_from_error_file(namelist_t *lp, const char *file){    const char *p, *p0;    char *pp;     for (p = file; (p = strstr(p, ".js:")) != NULL; p++) {        for (p0 = p; p0 > file && p0[-1] != '\n'; p0--)            continue;        pp = strdup_len(p0, p + 3 - p0);        namelist_add(lp, NULL, pp);        free(pp);    }} void namelist_free(namelist_t *lp){    while (lp->count > 0) {        free(lp->array[--lp->count]);    }    free(lp->array);    lp->array = NULL;    lp->size = 0;} static int add_test_file(const char *filename, const struct stat *ptr, int flag){    namelist_t *lp = &test_list;    if (has_suffix(filename, ".js") && !has_suffix(filename, "_FIXTURE.js"))        namelist_add(lp, NULL, filename);    return 0;} /* find js files from the directory tree and sort the list */static void enumerate_tests(const char *path){    namelist_t *lp = &test_list;    int start = lp->count;    ftw(path, add_test_file, 100);    qsort(lp->array + start, lp->count - start, sizeof(*lp->array),          namelist_cmp_indirect);} static JSValue js_print(JSContext *ctx, JSValueConst this_val,                        int argc, JSValueConst *argv){    int i;    const char *str;     if (outfile) {        for (i = 0; i < argc; i++) {            if (i != 0)                fputc(' ', outfile);            str = JS_ToCString(ctx, argv[i]);            if (!str)                return JS_EXCEPTION;            if (!strcmp(str, "Test262:AsyncTestComplete")) {                async_done++;            } else if (strstart(str, "Test262:AsyncTestFailure", NULL)) {                async_done = 2; /* force an error */            }            fputs(str, outfile);            JS_FreeCString(ctx, str);        }        fputc('\n', outfile);    }    return JS_UNDEFINED;} static JSValue js_detachArrayBuffer(JSContext *ctx, JSValue this_val,                                    int argc, JSValue *argv){    JS_DetachArrayBuffer(ctx, argv[0]);    return JS_UNDEFINED;} static JSValue js_evalScript(JSContext *ctx, JSValue this_val,                             int argc, JSValue *argv){    const char *str;    size_t len;    JSValue ret;    str = JS_ToCStringLen(ctx, &len, argv[0]);    if (!str)        return JS_EXCEPTION;    ret = JS_Eval(ctx, str, len, "<evalScript>", JS_EVAL_TYPE_GLOBAL);    JS_FreeCString(ctx, str);    return ret;} #ifdef CONFIG_AGENT #include <pthread.h> typedef struct {    struct list_head link;    pthread_t tid;    char *script;    JSValue broadcast_func;    BOOL broadcast_pending;    JSValue broadcast_sab; /* in the main context */    uint8_t *broadcast_sab_buf;    size_t broadcast_sab_size;    int32_t broadcast_val;} Test262Agent; typedef struct {    struct list_head link;    char *str;} AgentReport; static JSValue add_helpers1(JSContext *ctx);static void add_helpers(JSContext *ctx); static pthread_mutex_t agent_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_cond_t agent_cond = PTHREAD_COND_INITIALIZER;/* list of Test262Agent.link */static struct list_head agent_list = LIST_HEAD_INIT(agent_list); static pthread_mutex_t report_mutex = PTHREAD_MUTEX_INITIALIZER;/* list of AgentReport.link */static struct list_head report_list = LIST_HEAD_INIT(report_list); static void *agent_start(void *arg){    Test262Agent *agent = arg;    JSRuntime *rt;    JSContext *ctx;    JSValue ret_val;    int ret;        rt = JS_NewRuntime();    if (rt == NULL) {        fatal(1, "JS_NewRuntime failure");    }            ctx = JS_NewContext(rt);    if (ctx == NULL) {        JS_FreeRuntime(rt);        fatal(1, "JS_NewContext failure");    }    JS_SetContextOpaque(ctx, agent);    JS_SetRuntimeInfo(rt, "agent");    JS_SetCanBlock(rt, TRUE);        add_helpers(ctx);    ret_val = JS_Eval(ctx, agent->script, strlen(agent->script),                      "<evalScript>", JS_EVAL_TYPE_GLOBAL);    free(agent->script);    agent->script = NULL;    if (JS_IsException(ret_val))        js_std_dump_error(ctx);    JS_FreeValue(ctx, ret_val);        for(;;) {        JSContext *ctx1;        ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);        if (ret < 0) {            js_std_dump_error(ctx);            break;        } else if (ret == 0) {            if (JS_IsUndefined(agent->broadcast_func)) {                break;            } else {                JSValue args[2];                                pthread_mutex_lock(&agent_mutex);                while (!agent->broadcast_pending) {                    pthread_cond_wait(&agent_cond, &agent_mutex);                }                                agent->broadcast_pending = FALSE;

Lines 1–500 of 2107.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t