mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 14:47:37 +03:00
933 lines
27 KiB
C
933 lines
27 KiB
C
/*
|
|
* Micro QuickJS build utility
|
|
*
|
|
* Copyright (c) 2017-2025 Fabrice Bellard
|
|
* Copyright (c) 2017-2025 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 <math.h>
|
|
|
|
#include "cutils.h"
|
|
#include "list.h"
|
|
#include "mquickjs_build.h"
|
|
|
|
static unsigned JSW = 4; // override this with -m64
|
|
|
|
typedef struct {
|
|
char *str;
|
|
int offset;
|
|
} AtomDef;
|
|
|
|
typedef struct {
|
|
AtomDef *tab;
|
|
int count;
|
|
int size;
|
|
int offset;
|
|
} AtomList;
|
|
|
|
typedef struct {
|
|
char *name;
|
|
int length;
|
|
char *magic;
|
|
char *cproto_name;
|
|
char *cfunc_name;
|
|
} CFuncDef;
|
|
|
|
typedef struct {
|
|
CFuncDef *tab;
|
|
int count;
|
|
int size;
|
|
} CFuncList;
|
|
|
|
typedef struct {
|
|
struct list_head link;
|
|
const JSClassDef *class1;
|
|
int class_idx;
|
|
char *finalizer_name;
|
|
char *class_id;
|
|
} ClassDefEntry;
|
|
|
|
typedef struct {
|
|
AtomList atom_list;
|
|
CFuncList cfunc_list;
|
|
int cur_offset;
|
|
int sorted_atom_table_offset;
|
|
int global_object_offset;
|
|
struct list_head class_list;
|
|
} BuildContext;
|
|
|
|
static const char *atoms[] = {
|
|
#define DEF(a, b) b,
|
|
/* keywords */
|
|
DEF(null, "null") /* must be first */
|
|
DEF(false, "false")
|
|
DEF(true, "true")
|
|
DEF(if, "if")
|
|
DEF(else, "else")
|
|
DEF(return, "return")
|
|
DEF(var, "var")
|
|
DEF(this, "this")
|
|
DEF(delete, "delete")
|
|
DEF(void, "void")
|
|
DEF(typeof, "typeof")
|
|
DEF(new, "new")
|
|
DEF(in, "in")
|
|
DEF(instanceof, "instanceof")
|
|
DEF(do, "do")
|
|
DEF(while, "while")
|
|
DEF(for, "for")
|
|
DEF(break, "break")
|
|
DEF(continue, "continue")
|
|
DEF(switch, "switch")
|
|
DEF(case, "case")
|
|
DEF(default, "default")
|
|
DEF(throw, "throw")
|
|
DEF(try, "try")
|
|
DEF(catch, "catch")
|
|
DEF(finally, "finally")
|
|
DEF(function, "function")
|
|
DEF(debugger, "debugger")
|
|
DEF(with, "with")
|
|
/* FutureReservedWord */
|
|
DEF(class, "class")
|
|
DEF(const, "const")
|
|
DEF(enum, "enum")
|
|
DEF(export, "export")
|
|
DEF(extends, "extends")
|
|
DEF(import, "import")
|
|
DEF(super, "super")
|
|
/* FutureReservedWords when parsing strict mode code */
|
|
DEF(implements, "implements")
|
|
DEF(interface, "interface")
|
|
DEF(let, "let")
|
|
DEF(package, "package")
|
|
DEF(private, "private")
|
|
DEF(protected, "protected")
|
|
DEF(public, "public")
|
|
DEF(static, "static")
|
|
DEF(yield, "yield")
|
|
#undef DEF
|
|
|
|
/* other atoms */
|
|
"",
|
|
"toString",
|
|
"valueOf",
|
|
"number",
|
|
"object",
|
|
"undefined",
|
|
"string",
|
|
"boolean",
|
|
"<ret>",
|
|
"<eval>",
|
|
"eval",
|
|
"arguments",
|
|
"value",
|
|
"get",
|
|
"set",
|
|
"prototype",
|
|
"constructor",
|
|
"length",
|
|
"target",
|
|
"of",
|
|
"NaN",
|
|
"Infinity",
|
|
"-Infinity",
|
|
"name",
|
|
"Error",
|
|
"__proto__",
|
|
"index",
|
|
"input",
|
|
};
|
|
|
|
|
|
static char *cvt_name(char *buf, size_t buf_size, const char *str)
|
|
{
|
|
size_t i, len = strlen(str);
|
|
assert(len < buf_size);
|
|
if (len == 0) {
|
|
strcpy(buf, "empty");
|
|
} else {
|
|
strcpy(buf, str);
|
|
for(i = 0; i < len; i++) {
|
|
if (buf[i] == '<' || buf[i] == '>' || buf[i] == '-')
|
|
buf[i] = '_';
|
|
}
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
static BOOL is_ascii_string(const char *buf, size_t len)
|
|
{
|
|
size_t i;
|
|
for(i = 0; i < len; i++) {
|
|
if ((uint8_t)buf[i] > 0x7f)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL is_numeric_string(const char *buf, size_t len)
|
|
{
|
|
return (!strcmp(buf, "NaN") ||
|
|
!strcmp(buf, "Infinity") ||
|
|
!strcmp(buf, "-Infinity"));
|
|
}
|
|
|
|
static int find_atom(AtomList *s, const char *str)
|
|
{
|
|
int i;
|
|
for(i = 0; i < s->count; i++) {
|
|
if (!strcmp(str, s->tab[i].str))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int add_atom(AtomList *s, const char *str)
|
|
{
|
|
int i;
|
|
AtomDef *e;
|
|
i = find_atom(s, str);
|
|
if (i >= 0)
|
|
return s->tab[i].offset;
|
|
if ((s->count + 1) > s->size) {
|
|
s->size = max_int(s->count + 1, s->size * 3 / 2);
|
|
s->tab = realloc(s->tab, sizeof(s->tab[0]) * s->size);
|
|
}
|
|
e = &s->tab[s->count++];
|
|
e->str = strdup(str);
|
|
e->offset = s->offset;
|
|
s->offset += 1 + ((strlen(str) + JSW) / JSW);
|
|
return s->count - 1;
|
|
}
|
|
|
|
static int add_cfunc(CFuncList *s, const char *name, int length, const char *magic, const char *cproto_name, const char *cfunc_name)
|
|
{
|
|
int i;
|
|
CFuncDef *e;
|
|
|
|
for(i = 0; i < s->count; i++) {
|
|
e = &s->tab[i];
|
|
if (!strcmp(name, e->name) &&
|
|
length == e->length &&
|
|
!strcmp(magic, e->magic) &&
|
|
!strcmp(cproto_name, e->cproto_name) &&
|
|
!strcmp(cfunc_name, e->cfunc_name)) {
|
|
return i;
|
|
}
|
|
}
|
|
if ((s->count + 1) > s->size) {
|
|
s->size = max_int(s->count + 1, s->size * 3 / 2);
|
|
s->tab = realloc(s->tab, sizeof(s->tab[0]) * s->size);
|
|
}
|
|
e = &s->tab[s->count++];
|
|
e->name = strdup(name);
|
|
e->magic = strdup(magic);
|
|
e->length = length;
|
|
e->cproto_name = strdup(cproto_name);
|
|
e->cfunc_name = strdup(cfunc_name);
|
|
return s->count - 1;
|
|
}
|
|
|
|
static void dump_atom_defines(void)
|
|
{
|
|
AtomList atom_list_s, *s = &atom_list_s;
|
|
AtomDef *e;
|
|
int i;
|
|
char buf[256];
|
|
|
|
memset(s, 0, sizeof(*s));
|
|
|
|
/* add the predefined atoms (they have a corresponding define) */
|
|
for(i = 0; i < countof(atoms); i++) {
|
|
add_atom(s, atoms[i]);
|
|
}
|
|
|
|
for(i = 0; i < s->count; i++) {
|
|
e = &s->tab[i];
|
|
printf("#define JS_ATOM_%s %d\n",
|
|
cvt_name(buf, sizeof(buf), e->str), e->offset);
|
|
}
|
|
printf("\n");
|
|
printf("#define JS_ATOM_END %d\n", s->offset);
|
|
printf("\n");
|
|
}
|
|
|
|
static int atom_cmp(const void *p1, const void *p2)
|
|
{
|
|
const AtomDef *a1 = (const AtomDef *)p1;
|
|
const AtomDef *a2 = (const AtomDef *)p2;
|
|
return strcmp(a1->str, a2->str);
|
|
}
|
|
|
|
/* js_atom_table must be properly aligned because the property hash
|
|
table uses the low bits of the atom pointer value */
|
|
#define ATOM_ALIGN 64
|
|
|
|
static void dump_atoms(BuildContext *ctx)
|
|
{
|
|
AtomList *s = &ctx->atom_list;
|
|
int i, j, k, l, len, len1, is_ascii, is_numeric;
|
|
uint64_t v;
|
|
const char *str;
|
|
AtomDef *sorted_atoms;
|
|
char buf[256];
|
|
|
|
sorted_atoms = malloc(sizeof(sorted_atoms[0]) * s->count);
|
|
memcpy(sorted_atoms, s->tab, sizeof(sorted_atoms[0]) * s->count);
|
|
qsort(sorted_atoms, s->count, sizeof(sorted_atoms[0]), atom_cmp);
|
|
|
|
printf(" /* atom_table */\n");
|
|
for(i = 0; i < s->count; i++) {
|
|
str = s->tab[i].str;
|
|
len = strlen(str);
|
|
is_ascii = is_ascii_string(str, len);
|
|
is_numeric = is_numeric_string(str, len);
|
|
printf(" (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (%d << (JS_MTAG_BITS + 1)) | (%d << (JS_MTAG_BITS + 2)) | (%d << (JS_MTAG_BITS + 3)), /* \"%s\" (offset=%d) */\n",
|
|
is_ascii, is_numeric, len, str, ctx->cur_offset);
|
|
len1 = (len + JSW) / JSW;
|
|
for(j = 0; j < len1; j++) {
|
|
l = min_uint32(JSW, len - j * JSW);
|
|
v = 0;
|
|
for(k = 0; k < l; k++)
|
|
v |= (uint64_t)(uint8_t)str[j * JSW + k] << (k * 8);
|
|
printf(" 0x%0*" PRIx64 ",\n", JSW * 2, v);
|
|
}
|
|
assert(ctx->cur_offset == s->tab[i].offset);
|
|
ctx->cur_offset += len1 + 1;
|
|
}
|
|
printf("\n");
|
|
|
|
ctx->sorted_atom_table_offset = ctx->cur_offset;
|
|
|
|
printf(" /* sorted atom table (offset=%d) */\n", ctx->cur_offset);
|
|
printf(" JS_VALUE_ARRAY_HEADER(%d),\n", s->count);
|
|
for(i = 0; i < s->count; i++) {
|
|
AtomDef *e = &sorted_atoms[i];
|
|
printf(" JS_ROM_VALUE(%d), /* %s */\n",
|
|
e->offset, cvt_name(buf, sizeof(buf), e->str));
|
|
}
|
|
ctx->cur_offset += s->count + 1;
|
|
printf("\n");
|
|
|
|
free(sorted_atoms);
|
|
}
|
|
|
|
static int define_value(BuildContext *s, const JSPropDef *d);
|
|
|
|
static uint32_t dump_atom(BuildContext *s, const char *str, BOOL value_only)
|
|
{
|
|
int len, idx, i, offset;
|
|
|
|
len = strlen(str);
|
|
for(i = 0; i < len; i++) {
|
|
if ((uint8_t)str[i] >= 128) {
|
|
fprintf(stderr, "unicode property names are not supported yet (%s)\n", str);
|
|
exit(1);
|
|
}
|
|
}
|
|
if (len >= 1 && (str[0] >= '0' && str[0] <= '9')) {
|
|
fprintf(stderr, "numeric property names are not supported yet (%s)\n", str);
|
|
exit(1);
|
|
}
|
|
if (len == 1) {
|
|
if (value_only) {
|
|
/* XXX: hardcoded */
|
|
return ((uint8_t)str[0] << 5) | 0x1b;
|
|
}
|
|
printf("JS_VALUE_MAKE_SPECIAL(JS_TAG_STRING_CHAR, %d)",
|
|
(uint8_t)str[0]);
|
|
} else {
|
|
idx = find_atom(&s->atom_list, str);
|
|
if (idx < 0) {
|
|
fprintf(stderr, "atom '%s' is undefined\n", str);
|
|
exit(1);
|
|
}
|
|
offset = s->atom_list.tab[idx].offset;
|
|
if (value_only)
|
|
return (offset * JSW) + 1; /* correct modulo ATOM_ALIGN */
|
|
printf("JS_ROM_VALUE(%d)", offset);
|
|
}
|
|
printf(" /* %s */", str);
|
|
return 0;
|
|
}
|
|
|
|
static void dump_cfuncs(BuildContext *s)
|
|
{
|
|
int i;
|
|
CFuncDef *e;
|
|
|
|
printf("static const JSCFunctionDef js_c_function_table[] = {\n");
|
|
for(i = 0; i < s->cfunc_list.count; i++) {
|
|
e = &s->cfunc_list.tab[i];
|
|
printf(" { { .%s = %s },\n", e->cproto_name, e->cfunc_name);
|
|
printf(" ");
|
|
dump_atom(s, e->name, FALSE);
|
|
printf(",\n");
|
|
printf(" JS_CFUNC_%s, %d, %s },\n",
|
|
e->cproto_name, e->length, e->magic);
|
|
}
|
|
printf("};\n\n");
|
|
}
|
|
|
|
static void dump_cfinalizers(BuildContext *s)
|
|
{
|
|
struct list_head *el;
|
|
ClassDefEntry *e;
|
|
|
|
printf("static const JSCFinalizer js_c_finalizer_table[JS_CLASS_COUNT - JS_CLASS_USER] = {\n");
|
|
list_for_each(el, &s->class_list) {
|
|
e = list_entry(el, ClassDefEntry, link);
|
|
if (e->finalizer_name &&
|
|
strcmp(e->finalizer_name, "NULL") != 0) {
|
|
printf(" [%s - JS_CLASS_USER] = %s,\n", e->class_id, e->finalizer_name);
|
|
}
|
|
}
|
|
printf("};\n\n");
|
|
}
|
|
|
|
typedef enum {
|
|
PROPS_KIND_GLOBAL,
|
|
PROPS_KIND_PROTO,
|
|
PROPS_KIND_CLASS,
|
|
PROPS_KIND_OBJECT,
|
|
} JSPropsKindEnum;
|
|
|
|
static inline uint32_t hash_prop(BuildContext *s, const char *name)
|
|
{
|
|
/* Compute the hash for a symbol, must be consistent with
|
|
mquickjs.c implementation.
|
|
*/
|
|
uint32_t prop = dump_atom(s, name, TRUE);
|
|
return (prop / JSW) ^ (prop % JSW); /* XXX: improve */
|
|
}
|
|
|
|
static int define_props(BuildContext *s, const JSPropDef *props_def,
|
|
JSPropsKindEnum props_kind, const char *class_id_str)
|
|
{
|
|
int i, *ident_tab, idx, props_ident, n_props;
|
|
int prop_idx;
|
|
const JSPropDef *d;
|
|
uint32_t *prop_hash;
|
|
BOOL is_global_object = (props_kind == PROPS_KIND_GLOBAL);
|
|
static const JSPropDef dummy_props[] = {
|
|
{ JS_DEF_END },
|
|
};
|
|
|
|
if (!props_def)
|
|
props_def = dummy_props;
|
|
|
|
n_props = 0;
|
|
for(d = props_def; d->def_type != JS_DEF_END; d++) {
|
|
n_props++;
|
|
}
|
|
if (props_kind == PROPS_KIND_PROTO ||
|
|
props_kind == PROPS_KIND_CLASS)
|
|
n_props++;
|
|
ident_tab = malloc(sizeof(ident_tab[0]) * n_props);
|
|
|
|
/* define the various objects */
|
|
for(d = props_def, i = 0; d->def_type != JS_DEF_END; d++, i++) {
|
|
ident_tab[i] = define_value(s, d);
|
|
}
|
|
|
|
props_ident = -1;
|
|
prop_hash = NULL;
|
|
if (is_global_object) {
|
|
props_ident = s->cur_offset;
|
|
printf(" /* global object properties (offset=%d) */\n", props_ident);
|
|
printf(" JS_VALUE_ARRAY_HEADER(%d),\n", 2 * n_props);
|
|
s->cur_offset += 2 * n_props + 1;
|
|
} else {
|
|
int hash_size_log2;
|
|
uint32_t hash_size, hash_mask;
|
|
uint32_t *hash_table, h;
|
|
|
|
if (n_props <= 1)
|
|
hash_size_log2 = 0;
|
|
else
|
|
hash_size_log2 = (32 - clz32(n_props - 1)) - 1;
|
|
hash_size = 1 << hash_size_log2;
|
|
if (hash_size > ATOM_ALIGN / JSW) {
|
|
#if !defined __APPLE__
|
|
// XXX: Cannot request data alignment larger than 64 bytes on Darwin
|
|
fprintf(stderr, "Too many properties, consider increasing ATOM_ALIGN\n");
|
|
#endif
|
|
hash_size = ATOM_ALIGN / JSW;
|
|
}
|
|
hash_mask = hash_size - 1;
|
|
|
|
hash_table = malloc(sizeof(hash_table[0]) * hash_size);
|
|
prop_hash = malloc(sizeof(prop_hash[0]) * n_props);
|
|
/* build the hash table */
|
|
for(i = 0; i < hash_size; i++)
|
|
hash_table[i] = 0;
|
|
prop_idx = 0;
|
|
for(i = 0, d = props_def; i < n_props; i++, d++) {
|
|
const char *name;
|
|
if (d->def_type != JS_DEF_END) {
|
|
name = d->name;
|
|
} else {
|
|
if (props_kind == PROPS_KIND_PROTO)
|
|
name = "constructor";
|
|
else
|
|
name = "prototype";
|
|
}
|
|
h = hash_prop(s, name) & hash_mask;
|
|
prop_hash[prop_idx] = hash_table[h];
|
|
hash_table[h] = 2 + hash_size + 3 * prop_idx;
|
|
prop_idx++;
|
|
}
|
|
|
|
props_ident = s->cur_offset;
|
|
printf(" /* properties (offset=%d) */\n", props_ident);
|
|
printf(" JS_VALUE_ARRAY_HEADER(%d),\n", 2 + hash_size + n_props * 3);
|
|
printf(" %d << 1, /* n_props */\n", n_props);
|
|
printf(" %d << 1, /* hash_mask */\n", hash_mask);
|
|
for(i = 0; i < hash_size; i++) {
|
|
printf(" %d << 1,\n", hash_table[i]);
|
|
}
|
|
s->cur_offset += hash_size + 3 + 3 * n_props;
|
|
free(hash_table);
|
|
}
|
|
prop_idx = 0;
|
|
for(d = props_def, i = 0; i < n_props; d++, i++) {
|
|
const char *name, *prop_type;
|
|
/* name */
|
|
printf(" ");
|
|
if (d->def_type != JS_DEF_END) {
|
|
name = d->name;
|
|
} else {
|
|
if (props_kind == PROPS_KIND_PROTO)
|
|
name = "constructor";
|
|
else
|
|
name = "prototype";
|
|
}
|
|
dump_atom(s, name, FALSE);
|
|
printf(",\n");
|
|
|
|
printf(" ");
|
|
prop_type = "NORMAL";
|
|
switch(d->def_type) {
|
|
case JS_DEF_PROP_DOUBLE:
|
|
if (ident_tab[i] >= 0)
|
|
goto value_ptr;
|
|
/* short int */
|
|
printf("%d << 1,", (int32_t)d->u.f64);
|
|
break;
|
|
case JS_DEF_CGETSET:
|
|
if (is_global_object) {
|
|
fprintf(stderr, "getter/setter forbidden in global object\n");
|
|
exit(1);
|
|
}
|
|
prop_type = "GETSET";
|
|
goto value_ptr;
|
|
case JS_DEF_CLASS:
|
|
value_ptr:
|
|
assert(ident_tab[i] >= 0);
|
|
printf("JS_ROM_VALUE(%d),", ident_tab[i]);
|
|
break;
|
|
case JS_DEF_PROP_UNDEFINED:
|
|
printf("JS_UNDEFINED,");
|
|
break;
|
|
case JS_DEF_PROP_NULL:
|
|
printf("JS_NULL,");
|
|
break;
|
|
case JS_DEF_PROP_STRING:
|
|
dump_atom(s, d->u.str, FALSE);
|
|
printf(",");
|
|
break;
|
|
case JS_DEF_CFUNC:
|
|
idx = add_cfunc(&s->cfunc_list,
|
|
d->name,
|
|
d->u.func.length,
|
|
d->u.func.magic,
|
|
d->u.func.cproto_name,
|
|
d->u.func.func_name);
|
|
printf("JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, %d),", idx);
|
|
break;
|
|
case JS_DEF_END:
|
|
if (props_kind == PROPS_KIND_PROTO) {
|
|
/* constructor property */
|
|
printf("(uint32_t)(-%s - 1) << 1,", class_id_str);
|
|
} else {
|
|
/* prototype property */
|
|
printf("%s << 1,", class_id_str);
|
|
}
|
|
prop_type = "SPECIAL";
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
printf("\n");
|
|
if (!is_global_object) {
|
|
printf(" (%d << 1) | (JS_PROP_%s << 30),\n",
|
|
prop_hash[prop_idx], prop_type);
|
|
}
|
|
prop_idx++;
|
|
}
|
|
|
|
free(prop_hash);
|
|
free(ident_tab);
|
|
return props_ident;
|
|
}
|
|
|
|
static ClassDefEntry *find_class(BuildContext *s, const JSClassDef *d)
|
|
{
|
|
struct list_head *el;
|
|
ClassDefEntry *e;
|
|
|
|
list_for_each(el, &s->class_list) {
|
|
e = list_entry(el, ClassDefEntry, link);
|
|
if (e->class1 == d)
|
|
return e;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void free_class_entries(BuildContext *s)
|
|
{
|
|
struct list_head *el, *el1;
|
|
ClassDefEntry *e;
|
|
list_for_each_safe(el, el1, &s->class_list) {
|
|
e = list_entry(el, ClassDefEntry, link);
|
|
free(e->class_id);
|
|
free(e->finalizer_name);
|
|
free(e);
|
|
}
|
|
init_list_head(&s->class_list);
|
|
}
|
|
|
|
static int define_class(BuildContext *s, const JSClassDef *d)
|
|
{
|
|
int ctor_func_idx = -1, class_props_idx = -1, proto_props_idx = -1;
|
|
int ident, parent_class_idx = -1;
|
|
ClassDefEntry *e;
|
|
|
|
/* check if the class is already defined */
|
|
e = find_class(s, d);
|
|
if (e)
|
|
return e->class_idx;
|
|
|
|
if (d->parent_class)
|
|
parent_class_idx = define_class(s, d->parent_class);
|
|
|
|
if (d->func_name) {
|
|
ctor_func_idx = add_cfunc(&s->cfunc_list,
|
|
d->name,
|
|
d->length,
|
|
d->class_id,
|
|
d->cproto_name,
|
|
d->func_name);
|
|
}
|
|
|
|
if (ctor_func_idx >= 0) {
|
|
class_props_idx = define_props(s, d->class_props, PROPS_KIND_CLASS, d->class_id);
|
|
proto_props_idx = define_props(s, d->proto_props, PROPS_KIND_PROTO, d->class_id);
|
|
} else {
|
|
if (d->class_props)
|
|
class_props_idx = define_props(s, d->class_props, PROPS_KIND_OBJECT, d->class_id);
|
|
}
|
|
|
|
ident = s->cur_offset;
|
|
printf(" /* class (offset=%d) */\n", ident);
|
|
printf(" JS_MB_HEADER_DEF(JS_MTAG_OBJECT),\n");
|
|
if (class_props_idx >= 0)
|
|
printf(" JS_ROM_VALUE(%d),\n", class_props_idx);
|
|
else
|
|
printf(" JS_NULL,\n");
|
|
printf(" %d,\n", ctor_func_idx);
|
|
if (proto_props_idx >= 0)
|
|
printf(" JS_ROM_VALUE(%d),\n", proto_props_idx);
|
|
else
|
|
printf(" JS_NULL,\n");
|
|
if (parent_class_idx >= 0) {
|
|
printf(" JS_ROM_VALUE(%d),\n", parent_class_idx);
|
|
} else {
|
|
printf(" JS_NULL,\n");
|
|
}
|
|
printf("\n");
|
|
|
|
s->cur_offset += 5;
|
|
|
|
e = malloc(sizeof(*e));
|
|
memset(e, 0, sizeof(*e));
|
|
e->class_idx = ident;
|
|
e->class1 = d;
|
|
if (ctor_func_idx >= 0) {
|
|
e->class_id = strdup(d->class_id);
|
|
e->finalizer_name = strdup(d->finalizer_name);
|
|
}
|
|
list_add_tail(&e->link, &s->class_list);
|
|
return ident;
|
|
}
|
|
|
|
#define JS_SHORTINT_MIN (-(1 << 30))
|
|
#define JS_SHORTINT_MAX ((1 << 30) - 1)
|
|
|
|
static BOOL is_short_int(double d)
|
|
{
|
|
return (d >= JS_SHORTINT_MIN && d <= JS_SHORTINT_MAX && (int32_t)d == d);
|
|
}
|
|
|
|
static int define_value(BuildContext *s, const JSPropDef *d)
|
|
{
|
|
int ident;
|
|
ident = -1;
|
|
switch(d->def_type) {
|
|
case JS_DEF_PROP_DOUBLE:
|
|
{
|
|
uint64_t v;
|
|
if (!is_short_int(d->u.f64)) {
|
|
ident = s->cur_offset;
|
|
printf(" /* float64 (offset=%d) */\n", ident);
|
|
printf(" JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),\n");
|
|
v = float64_as_uint64(d->u.f64);
|
|
if (JSW == 8) {
|
|
printf(" 0x%016zx,\n", (size_t)v);
|
|
printf("\n");
|
|
s->cur_offset += 2;
|
|
} else {
|
|
/* XXX: little endian assumed */
|
|
printf(" 0x%08x,\n", (uint32_t)v);
|
|
printf(" 0x%08x,\n", (uint32_t)(v >> 32));
|
|
printf("\n");
|
|
s->cur_offset += 3;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case JS_DEF_CLASS:
|
|
ident = define_class(s, d->u.class1);
|
|
break;
|
|
case JS_DEF_CGETSET:
|
|
{
|
|
int get_idx = -1, set_idx = -1;
|
|
char buf[256];
|
|
if (strcmp(d->u.getset.get_func_name, "NULL") != 0) {
|
|
snprintf(buf, sizeof(buf), "get %s", d->name);
|
|
get_idx = add_cfunc(&s->cfunc_list,
|
|
buf,
|
|
0, /* length */
|
|
d->u.getset.magic,
|
|
d->u.getset.cproto_name,
|
|
d->u.getset.get_func_name);
|
|
}
|
|
if (strcmp(d->u.getset.set_func_name, "NULL") != 0) {
|
|
snprintf(buf, sizeof(buf), "set %s", d->name);
|
|
set_idx = add_cfunc(&s->cfunc_list,
|
|
buf,
|
|
1, /* length */
|
|
d->u.getset.magic,
|
|
d->u.getset.cproto_name,
|
|
d->u.getset.set_func_name);
|
|
}
|
|
ident = s->cur_offset;
|
|
printf(" /* getset (offset=%d) */\n", ident);
|
|
printf(" JS_VALUE_ARRAY_HEADER(2),\n");
|
|
if (get_idx >= 0)
|
|
printf(" JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, %d),\n", get_idx);
|
|
else
|
|
printf(" JS_UNDEFINED,\n");
|
|
if (set_idx >= 0)
|
|
printf(" JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, %d),\n", set_idx);
|
|
else
|
|
printf(" JS_UNDEFINED,\n");
|
|
printf("\n");
|
|
s->cur_offset += 3;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return ident;
|
|
}
|
|
|
|
static void define_atoms_props(BuildContext *s, const JSPropDef *props_def, JSPropsKindEnum props_kind);
|
|
|
|
static void define_atoms_class(BuildContext *s, const JSClassDef *d)
|
|
{
|
|
ClassDefEntry *e;
|
|
/* check if the class is already defined */
|
|
e = find_class(s, d);
|
|
if (e)
|
|
return;
|
|
if (d->parent_class)
|
|
define_atoms_class(s, d->parent_class);
|
|
if (d->func_name)
|
|
add_atom(&s->atom_list, d->name);
|
|
if (d->class_props)
|
|
define_atoms_props(s, d->class_props, d->func_name ? PROPS_KIND_CLASS : PROPS_KIND_OBJECT);
|
|
if (d->proto_props)
|
|
define_atoms_props(s, d->proto_props, PROPS_KIND_PROTO);
|
|
}
|
|
|
|
static void define_atoms_props(BuildContext *s, const JSPropDef *props_def, JSPropsKindEnum props_kind)
|
|
{
|
|
const JSPropDef *d;
|
|
for(d = props_def; d->def_type != JS_DEF_END; d++) {
|
|
add_atom(&s->atom_list, d->name);
|
|
switch(d->def_type) {
|
|
case JS_DEF_PROP_STRING:
|
|
add_atom(&s->atom_list, d->u.str);
|
|
break;
|
|
case JS_DEF_CLASS:
|
|
define_atoms_class(s, d->u.class1);
|
|
break;
|
|
case JS_DEF_CGETSET:
|
|
{
|
|
char buf[256];
|
|
if (strcmp(d->u.getset.get_func_name, "NULL") != 0) {
|
|
snprintf(buf, sizeof(buf), "get %s", d->name);
|
|
add_atom(&s->atom_list, buf);
|
|
}
|
|
if (strcmp(d->u.getset.set_func_name, "NULL") != 0) {
|
|
snprintf(buf, sizeof(buf), "set %s", d->name);
|
|
add_atom(&s->atom_list, buf);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int usage(const char *name)
|
|
{
|
|
fprintf(stderr, "usage: %s {-m32 | -m64} [-a]\n", name);
|
|
fprintf(stderr,
|
|
" create a ROM file for the mquickjs standard library\n"
|
|
"--help list options\n"
|
|
"-m32 force generation for a 32 bit target\n"
|
|
"-m64 force generation for a 64 bit target\n"
|
|
"-a generate the mquickjs_atom.h header\n"
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
int build_atoms(const char *stdlib_name, const JSPropDef *global_obj,
|
|
const JSPropDef *c_function_decl, int argc, char **argv)
|
|
{
|
|
int i;
|
|
unsigned jsw;
|
|
BuildContext ss, *s = &ss;
|
|
BOOL build_atom_defines = FALSE;
|
|
|
|
#if INTPTR_MAX >= INT64_MAX
|
|
jsw = 8;
|
|
#else
|
|
jsw = 4;
|
|
#endif
|
|
for (i = 1; i < argc; i++) {
|
|
if (!strcmp(argv[i], "-m64")) {
|
|
jsw = 8;
|
|
} else if (!strcmp(argv[i], "-m32")) {
|
|
jsw = 4;
|
|
} else if (!strcmp(argv[i], "-a")) {
|
|
build_atom_defines = TRUE;
|
|
} else if (!strcmp(argv[i], "--help")) {
|
|
return usage(argv[0]);
|
|
} else {
|
|
fprintf(stderr, "invalid argument '%s'\n", argv[i]);
|
|
return usage(argv[0]);
|
|
}
|
|
}
|
|
|
|
JSW = jsw;
|
|
|
|
if (build_atom_defines) {
|
|
dump_atom_defines();
|
|
return 0;
|
|
}
|
|
|
|
memset(s, 0, sizeof(*s));
|
|
init_list_head(&s->class_list);
|
|
|
|
/* add the predefined atoms (they have a corresponding define) */
|
|
for(i = 0; i < countof(atoms); i++) {
|
|
add_atom(&s->atom_list, atoms[i]);
|
|
}
|
|
|
|
/* add the predefined functions */
|
|
if (c_function_decl) {
|
|
const JSPropDef *d;
|
|
for(d = c_function_decl; d->def_type != JS_DEF_END; d++) {
|
|
if (d->def_type != JS_DEF_CFUNC) {
|
|
fprintf(stderr, "only C functions are allowed in c_function_decl[]\n");
|
|
exit(1);
|
|
}
|
|
add_atom(&s->atom_list, d->name);
|
|
add_cfunc(&s->cfunc_list,
|
|
d->name,
|
|
d->u.func.length,
|
|
d->u.func.magic,
|
|
d->u.func.cproto_name,
|
|
d->u.func.func_name);
|
|
}
|
|
}
|
|
|
|
/* first pass to define the atoms */
|
|
define_atoms_props(s, global_obj, PROPS_KIND_GLOBAL);
|
|
free_class_entries(s);
|
|
|
|
printf("/* this file is automatically generated - do not edit */\n\n");
|
|
printf("#include \"mquickjs_priv.h\"\n\n");
|
|
|
|
printf("static const uint%u_t __attribute((aligned(%d))) js_stdlib_table[] = {\n",
|
|
JSW * 8, ATOM_ALIGN);
|
|
|
|
dump_atoms(s);
|
|
|
|
s->global_object_offset = define_props(s, global_obj, PROPS_KIND_GLOBAL, NULL);
|
|
|
|
printf("};\n\n");
|
|
|
|
dump_cfuncs(s);
|
|
|
|
printf("#ifndef JS_CLASS_COUNT\n"
|
|
"#define JS_CLASS_COUNT JS_CLASS_USER /* total number of classes */\n"
|
|
"#endif\n\n");
|
|
|
|
dump_cfinalizers(s);
|
|
|
|
free_class_entries(s);
|
|
|
|
printf("const JSSTDLibraryDef %s = {\n", stdlib_name);
|
|
printf(" js_stdlib_table,\n");
|
|
printf(" js_c_function_table,\n");
|
|
printf(" js_c_finalizer_table,\n");
|
|
printf(" %d,\n", s->cur_offset);
|
|
printf(" %d,\n", ATOM_ALIGN);
|
|
printf(" %d,\n", s->sorted_atom_table_offset);
|
|
printf(" %d,\n", s->global_object_offset);
|
|
printf(" JS_CLASS_COUNT,\n");
|
|
printf("};\n\n");
|
|
|
|
return 0;
|
|
}
|