|
|
/*
|
|
|
* Internal definitions for the JavaScript interpreter.
|
|
|
* Copyright (c) 1998-1999 New Generation Software (NGS) Oy
|
|
|
*
|
|
|
* Author: Markku Rossi <mtr@ngs.fi>
|
|
|
*/
|
|
|
|
|
|
/*
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
*
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
* Library General Public License for more details.
|
|
|
*
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
* License along with this library; if not, write to the Free
|
|
|
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
|
* MA 02111-1307, USA
|
|
|
*/
|
|
|
|
|
|
/*
|
|
|
* $Source: /tmp/cvsroot-15-2-2007/clamav-devel/libclamav/js/jsint.h,v $
|
|
|
* $Id: jsint.h,v 1.4 2006/11/10 20:17:43 njh Exp $
|
|
|
*/
|
|
|
|
|
|
#ifndef JSINT_H
|
|
|
#define JSINT_H
|
|
|
|
|
|
/* We have always jsconfig.h */
|
|
|
#include "jsconfig.h"
|
|
|
|
|
|
#include <stdio.h>
|
|
|
#include <assert.h>
|
|
|
#include <setjmp.h>
|
|
|
#include <math.h>
|
|
|
#include <time.h>
|
|
|
#include <limits.h>
|
|
|
|
|
|
#if HAVE_UNISTD_H
|
|
|
#include <unistd.h>
|
|
|
#endif
|
|
|
|
|
|
#if STDC_HEADERS
|
|
|
#include <stdlib.h>
|
|
|
#include <errno.h>
|
|
|
#include <string.h>
|
|
|
#include <float.h>
|
|
|
|
|
|
#else /* not STDC_HEADERS */
|
|
|
|
|
|
#if HAVE_STDLIB_H
|
|
|
#include <stdlib.h>
|
|
|
#endif
|
|
|
|
|
|
#if HAVE_ERRNO_H
|
|
|
#include <errno.h>
|
|
|
#endif
|
|
|
|
|
|
#if HAVE_STRING_H
|
|
|
#include <string.h>
|
|
|
#endif
|
|
|
|
|
|
#if HAVE_FLOAT_H
|
|
|
#include <float.h>
|
|
|
#endif
|
|
|
|
|
|
#endif /* not STDC_HEADERS */
|
|
|
|
|
|
/* Misc system headers. */
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
/*
|
|
|
* Protability kludges. If something is missing from the w32
|
|
|
* environment, please edit the micros/w32.{c,h} files and implement
|
|
|
* them.
|
|
|
*/
|
|
|
#ifndef WIN32
|
|
|
|
|
|
/* Directory handling. */
|
|
|
#include <dirent.h>
|
|
|
|
|
|
#endif /* not WIN32 */
|
|
|
|
|
|
#include "js.h"
|
|
|
|
|
|
#if __cplusplus
|
|
|
extern "C" {
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
|
* Types and definitions.
|
|
|
*/
|
|
|
|
|
|
/* Some portability features. */
|
|
|
#ifdef WIN32
|
|
|
|
|
|
#define JS_HOST_LINE_BREAK "\r\n"
|
|
|
#define JS_HOST_LINE_BREAK_LEN 2
|
|
|
|
|
|
#else /* not WIN32 */
|
|
|
|
|
|
#define JS_HOST_LINE_BREAK "\n"
|
|
|
#define JS_HOST_LINE_BREAK_LEN 1
|
|
|
|
|
|
#endif /* not WIN32 */
|
|
|
|
|
|
|
|
|
#define JS_BC_FILE_MAGIC 0xc0014a53
|
|
|
|
|
|
#define JS_GLOBAL_NAME ".global"
|
|
|
|
|
|
#define JS_SYMBOL_NULL ((JSSymbol) -1)
|
|
|
|
|
|
#define JS_IS_STR_WHITE_SPACE_CHAR(ch) \
|
|
|
((ch) == '\t' || (ch) == ' ' || (ch) == '\f' || (ch) == '\v' \
|
|
|
|| (ch) == '\r' || (ch) == '\n')
|
|
|
|
|
|
/*
|
|
|
* Read macros for byte code files.
|
|
|
*/
|
|
|
|
|
|
#define JS_BC_READ_INT32(cp, var) \
|
|
|
(var) = (cp)[0]; \
|
|
|
(var) <<= 8; \
|
|
|
(var) |= (cp)[1]; \
|
|
|
(var) <<= 8; \
|
|
|
(var) |= (cp)[2]; \
|
|
|
(var) <<= 8; \
|
|
|
(var) |= (cp)[3]
|
|
|
|
|
|
#define JS_BC_READ_INT16(cp, var) \
|
|
|
(var) = (cp)[0]; \
|
|
|
(var) <<= 8; \
|
|
|
(var) |= (cp)[1]
|
|
|
|
|
|
#define JS_BC_READ_INT8(cp, var) \
|
|
|
(var) = (cp)[0]
|
|
|
|
|
|
#define JS_BC_WRITE_INT32(cp, var) \
|
|
|
cp[3] = (unsigned char) ((var) & 0x000000ff); \
|
|
|
cp[2] = (unsigned char) (((var) >> 8) & 0x000000ff); \
|
|
|
cp[1] = (unsigned char) (((var) >> 16) & 0x000000ff); \
|
|
|
cp[0] = (unsigned char) (((var) >> 24) & 0x000000ff)
|
|
|
|
|
|
|
|
|
/* General VM macros. */
|
|
|
|
|
|
/* STACKFRAME */
|
|
|
|
|
|
#define JS_SP0 sp
|
|
|
#define JS_SP1 (sp + 1)
|
|
|
#define JS_SP2 (sp + 2)
|
|
|
#define JS_SP(n) (sp + (n))
|
|
|
|
|
|
#define JS_LOCAL(n) (fp - 4 - (n))
|
|
|
#define JS_ARG(n) (fp + 1 + (n))
|
|
|
|
|
|
#define JS_WITHPTR (fp - 2)
|
|
|
#define JS_ARGS_FIXP (fp - 1)
|
|
|
|
|
|
#define JS_PUSH() sp--
|
|
|
#define JS_POP() sp++
|
|
|
#define JS_POP_N(n) sp += (n)
|
|
|
|
|
|
#define JS_COPY(to, from) \
|
|
|
do { \
|
|
|
(to)->type = (from)->type; \
|
|
|
(to)->u.copy.a = (from)->u.copy.a; \
|
|
|
(to)->u.copy.b = (from)->u.copy.b; \
|
|
|
} while (0)
|
|
|
|
|
|
#define JS_CONST(n) (&vm->consts[(n)])
|
|
|
#define JS_GLOBAL(n) (&vm->globals[(n)])
|
|
|
|
|
|
#define JS_SAVE_REGS() \
|
|
|
do { \
|
|
|
vm->sp = sp; \
|
|
|
vm->pc = pc; \
|
|
|
} while (0)
|
|
|
|
|
|
#define JS_CALL_HOOK(event) \
|
|
|
do { \
|
|
|
int hook_result; \
|
|
|
\
|
|
|
if (vm->hook) \
|
|
|
if ((hook_result = (*vm->hook) ((event), vm->hook_context)) != 0) \
|
|
|
{ \
|
|
|
JS_SAVE_REGS (); \
|
|
|
sprintf (vm->error, "hook break %d", hook_result); \
|
|
|
js_vm_error (vm); \
|
|
|
/* NOTREACHED */ \
|
|
|
} \
|
|
|
} while (0)
|
|
|
|
|
|
#define JS_VM_ALLOCATE_FD(vm, where) \
|
|
|
do { \
|
|
|
if ((vm)->fd_count == 0) \
|
|
|
{ \
|
|
|
sprintf ((vm)->error, "%s: no more file descriptors allowed", \
|
|
|
(where)); \
|
|
|
js_vm_error (vm); \
|
|
|
} \
|
|
|
(vm)->fd_count--; \
|
|
|
} while (0)
|
|
|
|
|
|
#define JS_VM_FREE_FD(vm) \
|
|
|
do { \
|
|
|
(vm)->fd_count++; \
|
|
|
} while (0)
|
|
|
|
|
|
#define JS_MAYBE_GC() \
|
|
|
do { \
|
|
|
if (vm->gc.bytes_allocated >= vm->gc.trigger) \
|
|
|
{ \
|
|
|
js_vm_garbage_collect (vm, fp, sp); \
|
|
|
JS_CALL_HOOK (JS_VM_EVENT_GARBAGE_COLLECT); \
|
|
|
} \
|
|
|
} while (0)
|
|
|
|
|
|
#define JS_IS_TRUE(n) ((n)->type > JS_INTEGER \
|
|
|
|| ((n)->type == JS_BOOLEAN && (n)->u.vboolean) \
|
|
|
|| ((n)->type == JS_INTEGER && (n)->u.vinteger))
|
|
|
|
|
|
#define JS_IS_FALSE(n) ((n)->type < JS_BOOLEAN \
|
|
|
|| ((n)->type == JS_BOOLEAN && !(n)->u.vboolean) \
|
|
|
|| ((n)->type == JS_INTEGER && !(n)->u.vinteger))
|
|
|
|
|
|
#define JS_RESERVE_STACK_FOR_FUNCTION 10
|
|
|
|
|
|
#define JS_SUBROUTINE_CALL(function) \
|
|
|
do { \
|
|
|
/* Check that we have enought space in the stack. */ \
|
|
|
if (sp - JS_RESERVE_STACK_FOR_FUNCTION < vm->stack) \
|
|
|
ERROR ("stack overflow"); \
|
|
|
\
|
|
|
/* STACKFRAME */ \
|
|
|
\
|
|
|
/* Save frame pointer. */ \
|
|
|
JS_SP0->type = JS_IPTR; \
|
|
|
JS_SP0->u.iptr = fp; \
|
|
|
\
|
|
|
/* Update fp. */ \
|
|
|
fp = JS_SP0; \
|
|
|
JS_PUSH (); \
|
|
|
\
|
|
|
/* Insert an empty args_fix. */ \
|
|
|
JS_SP0->type = JS_ARGS_FIX; \
|
|
|
JS_SP0->u.args_fix.argc = 0; \
|
|
|
JS_SP0->u.args_fix.delta = 0; \
|
|
|
JS_PUSH (); \
|
|
|
\
|
|
|
/* Insert empty with pointer. */ \
|
|
|
JS_SP0->type = JS_IPTR; \
|
|
|
JS_SP0->u.iptr = NULL; \
|
|
|
JS_PUSH (); \
|
|
|
\
|
|
|
/* Save return address. */ \
|
|
|
JS_SP0->type = JS_IPTR; \
|
|
|
JS_SP0->u.iptr = pc; \
|
|
|
JS_PUSH (); \
|
|
|
\
|
|
|
/* And finally, jump to the method code. */ \
|
|
|
CALL_USER_FUNC ((function)); \
|
|
|
} while (0)
|
|
|
|
|
|
#define JS_OPERAND_CMP_REL(_OP_) \
|
|
|
do { \
|
|
|
if (JS_SP2->type == JS_STRING && JS_SP1->type == JS_STRING) \
|
|
|
{ \
|
|
|
JS_SP2->u.vboolean \
|
|
|
= js_compare_strings (JS_SP2, JS_SP1) _OP_ 0; \
|
|
|
JS_SP2->type = JS_BOOLEAN; \
|
|
|
JS_POP (); \
|
|
|
} \
|
|
|
else if (JS_SP2->type == JS_INTEGER && JS_SP1->type == JS_INTEGER) \
|
|
|
{ \
|
|
|
JS_SP2->u.vboolean \
|
|
|
= JS_SP2->u.vinteger _OP_ JS_SP1->u.vinteger; \
|
|
|
JS_SP2->type = JS_BOOLEAN; \
|
|
|
JS_POP (); \
|
|
|
} \
|
|
|
else \
|
|
|
{ \
|
|
|
JSNode l, r; \
|
|
|
\
|
|
|
/* Do it the hard way. */ \
|
|
|
switch (JS_SP2->type) \
|
|
|
{ \
|
|
|
case JS_INTEGER: \
|
|
|
case JS_FLOAT: \
|
|
|
case JS_NAN: \
|
|
|
JS_COPY (&l, JS_SP2); \
|
|
|
break; \
|
|
|
\
|
|
|
default: \
|
|
|
js_vm_to_number (vm, JS_SP2, &l); \
|
|
|
break; \
|
|
|
} \
|
|
|
\
|
|
|
switch (JS_SP1->type) \
|
|
|
{ \
|
|
|
case JS_INTEGER: \
|
|
|
case JS_FLOAT: \
|
|
|
case JS_NAN: \
|
|
|
JS_COPY (&r, JS_SP1); \
|
|
|
break; \
|
|
|
\
|
|
|
default: \
|
|
|
js_vm_to_number (vm, JS_SP1, &r); \
|
|
|
break; \
|
|
|
} \
|
|
|
\
|
|
|
/* Do the comparison. */ \
|
|
|
JS_POP (); \
|
|
|
\
|
|
|
if (l.type == JS_NAN || r.type == JS_NAN) \
|
|
|
JS_SP1->type = JS_UNDEFINED; \
|
|
|
else if (l.type == JS_INTEGER && r.type == JS_INTEGER) \
|
|
|
{ \
|
|
|
JS_SP1->type = JS_BOOLEAN; \
|
|
|
JS_SP1->u.vboolean = l.u.vinteger _OP_ r.u.vinteger; \
|
|
|
} \
|
|
|
else \
|
|
|
{ \
|
|
|
double ld, rd; \
|
|
|
\
|
|
|
if (l.type == JS_FLOAT) \
|
|
|
ld = l.u.vfloat; \
|
|
|
else \
|
|
|
ld = (double) l.u.vinteger; \
|
|
|
\
|
|
|
if (r.type == JS_FLOAT) \
|
|
|
rd = r.u.vfloat; \
|
|
|
else \
|
|
|
rd = (double) r.u.vinteger; \
|
|
|
\
|
|
|
JS_SP1->type = JS_BOOLEAN; \
|
|
|
JS_SP1->u.vboolean = ld _OP_ rd; \
|
|
|
} \
|
|
|
} \
|
|
|
} while (0)
|
|
|
|
|
|
#define JS_OPERAND_CMP_EQ(_OP_, _VAL_) \
|
|
|
while (1) { \
|
|
|
int res; \
|
|
|
if (JS_SP2->type == JS_SP1->type) \
|
|
|
{ \
|
|
|
/* Comparsion between same types. */ \
|
|
|
switch (JS_SP2->type) \
|
|
|
{ \
|
|
|
case JS_INTEGER: \
|
|
|
res = JS_SP2->u.vinteger _OP_ JS_SP1->u.vinteger; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_STRING: \
|
|
|
res = js_compare_strings (JS_SP2, JS_SP1) _OP_ 0; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_FLOAT: \
|
|
|
res = JS_SP2->u.vfloat _OP_ JS_SP1->u.vfloat; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_NAN: \
|
|
|
/* 11.9.3: cases 5 and 6 */ \
|
|
|
res = !_VAL_; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_BOOLEAN: \
|
|
|
res = JS_SP2->u.vboolean _OP_ JS_SP1->u.vboolean; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_OBJECT: \
|
|
|
res = JS_SP2->u.vobject _OP_ JS_SP1->u.vobject; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_BUILTIN: \
|
|
|
res = ((JS_SP2->u.vbuiltin->info \
|
|
|
== JS_SP1->u.vbuiltin->info \
|
|
|
&& (JS_SP2->u.vbuiltin->instance_context \
|
|
|
== JS_SP1->u.vbuiltin->instance_context)) \
|
|
|
? _VAL_ : !_VAL_); \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_FUNC: \
|
|
|
res = JS_SP2->u.vfunction _OP_ JS_SP1->u.vfunction; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_SYMBOL: \
|
|
|
res = JS_SP2->u.vsymbol _OP_ JS_SP1->u.vsymbol; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_IPTR: \
|
|
|
res = JS_SP2->u.iptr _OP_ JS_SP1->u.iptr; \
|
|
|
break; \
|
|
|
\
|
|
|
default: \
|
|
|
res = _VAL_; \
|
|
|
break; \
|
|
|
} \
|
|
|
} \
|
|
|
else \
|
|
|
{ \
|
|
|
/* Type conversions between different types. */ \
|
|
|
\
|
|
|
if ((JS_SP2->type == JS_UNDEFINED || JS_SP2->type == JS_NULL) \
|
|
|
&& (JS_SP1->type == JS_UNDEFINED \
|
|
|
|| JS_SP1->type == JS_NULL)) \
|
|
|
res = _VAL_; \
|
|
|
\
|
|
|
/* Numbers. */ \
|
|
|
else if (JS_IS_NUMBER (JS_SP2) && JS_IS_NUMBER (JS_SP1)) \
|
|
|
{ \
|
|
|
if (JS_SP2->type == JS_NAN || JS_SP1->type == JS_NAN) \
|
|
|
/* 11.9.3: cases 5 and 6 */ \
|
|
|
res = !_VAL_; \
|
|
|
else if (JS_SP2->type == JS_INTEGER) \
|
|
|
/* Integer-integer was already handled. */ \
|
|
|
res = (double) JS_SP2->u.vinteger _OP_ JS_SP1->u.vfloat; \
|
|
|
else \
|
|
|
/* Integer-integer was already handled. */ \
|
|
|
res = JS_SP2->u.vfloat _OP_ (double) JS_SP1->u.vinteger; \
|
|
|
} \
|
|
|
else \
|
|
|
{ \
|
|
|
JSNode l, r; \
|
|
|
\
|
|
|
/* Must perform type casts. */ \
|
|
|
\
|
|
|
if ((JS_SP2->type == JS_STRING || JS_SP2->type == JS_BOOLEAN \
|
|
|
|| JS_IS_NUMBER (JS_SP2)) \
|
|
|
&& (JS_SP1->type == JS_STRING \
|
|
|
|| JS_SP1->type == JS_BOOLEAN \
|
|
|
|| JS_IS_NUMBER (JS_SP1))) \
|
|
|
{ \
|
|
|
js_vm_to_number (vm, JS_SP2, &l); \
|
|
|
js_vm_to_number (vm, JS_SP1, &r); \
|
|
|
\
|
|
|
if (l.type == JS_NAN || r.type == JS_NAN) \
|
|
|
res = !_VAL_; \
|
|
|
else if (l.type == JS_INTEGER) \
|
|
|
{ \
|
|
|
if (r.type == JS_INTEGER) \
|
|
|
res = l.u.vinteger _OP_ r.u.vinteger; \
|
|
|
else \
|
|
|
res = (double) l.u.vinteger _OP_ r.u.vfloat; \
|
|
|
} \
|
|
|
else \
|
|
|
{ \
|
|
|
if (r.type == JS_INTEGER) \
|
|
|
res = l.u.vfloat _OP_ (double) r.u.vinteger; \
|
|
|
else \
|
|
|
res = l.u.vfloat _OP_ r.u.vfloat; \
|
|
|
} \
|
|
|
} \
|
|
|
else if (JS_SP2->type == JS_OBJECT \
|
|
|
&& (JS_SP1->type == JS_STRING \
|
|
|
|| JS_IS_NUMBER (JS_SP1))) \
|
|
|
{ \
|
|
|
JSNode cvt; \
|
|
|
\
|
|
|
/* ECMA 11.9.3 21. No preferred type specified. */ \
|
|
|
js_vm_to_primitive (vm, JS_SP2, &cvt, JS_UNDEFINED); \
|
|
|
JS_COPY (JS_SP2, &cvt); \
|
|
|
continue; \
|
|
|
} \
|
|
|
else if (JS_SP1->type == JS_OBJECT \
|
|
|
&& (JS_SP2->type == JS_STRING \
|
|
|
|| JS_IS_NUMBER (JS_SP2))) \
|
|
|
{ \
|
|
|
JSNode cvt; \
|
|
|
\
|
|
|
/* ECMA 11.9.3 20. No preferred type specified. */ \
|
|
|
js_vm_to_primitive (vm, JS_SP1, &cvt, JS_UNDEFINED); \
|
|
|
JS_COPY (JS_SP1, &cvt); \
|
|
|
continue; \
|
|
|
} \
|
|
|
else \
|
|
|
res = !_VAL_; \
|
|
|
} \
|
|
|
} \
|
|
|
\
|
|
|
JS_SP2->type = JS_BOOLEAN; \
|
|
|
JS_SP2->u.vboolean = res; \
|
|
|
JS_POP (); \
|
|
|
break; \
|
|
|
}
|
|
|
|
|
|
#define JS_OPERAND_CMP_SEQ(_OP_, _VAL_) \
|
|
|
do { \
|
|
|
int res; \
|
|
|
if (JS_SP2->type == JS_SP1->type) \
|
|
|
{ \
|
|
|
switch (JS_SP2->type) \
|
|
|
{ \
|
|
|
case JS_INTEGER: \
|
|
|
res = JS_SP2->u.vinteger _OP_ JS_SP1->u.vinteger; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_FLOAT: \
|
|
|
res = JS_SP2->u.vfloat _OP_ JS_SP1->u.vfloat; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_NAN: \
|
|
|
/* 11.9.6: cases 3 and 4 */ \
|
|
|
res = !_VAL_; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_STRING: \
|
|
|
res = js_compare_strings (JS_SP2, JS_SP1) _OP_ 0; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_BOOLEAN: \
|
|
|
res = JS_SP2->u.vboolean _OP_ JS_SP1->u.vboolean; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_OBJECT: \
|
|
|
res = JS_SP2->u.vobject _OP_ JS_SP1->u.vobject; \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_BUILTIN: \
|
|
|
res = ((JS_SP2->u.vbuiltin->info \
|
|
|
== JS_SP1->u.vbuiltin->info \
|
|
|
&& (JS_SP2->u.vbuiltin->instance_context \
|
|
|
== JS_SP1->u.vbuiltin->instance_context)) \
|
|
|
? _VAL_ : !_VAL_); \
|
|
|
break; \
|
|
|
\
|
|
|
case JS_FUNC: \
|
|
|
res = JS_SP2->u.vfunction _OP_ JS_SP1->u.vfunction; \
|
|
|
break; \
|
|
|
\
|
|
|
default: \
|
|
|
/* 11.9.6: case 12 */ \
|
|
|
res = !_VAL_; \
|
|
|
break; \
|
|
|
} \
|
|
|
} \
|
|
|
else \
|
|
|
{ \
|
|
|
/* Only numbers are allowed here. */ \
|
|
|
if (JS_IS_NUMBER (JS_SP2) && JS_IS_NUMBER (JS_SP1)) \
|
|
|
{ \
|
|
|
if (JS_SP2->type == JS_NAN || JS_SP1->type == JS_NAN) \
|
|
|
/* 11.9.6: cases 3 and 4 */ \
|
|
|
res = !_VAL_; \
|
|
|
else if (JS_SP2->type == JS_INTEGER) \
|
|
|
res = (double) JS_SP2->u.vinteger _OP_ JS_SP1->u.vfloat; \
|
|
|
else \
|
|
|
res = JS_SP2->u.vfloat _OP_ (double) JS_SP1->u.vinteger; \
|
|
|
} \
|
|
|
else \
|
|
|
res = !_VAL_; \
|
|
|
} \
|
|
|
\
|
|
|
JS_SP2->type = JS_BOOLEAN; \
|
|
|
JS_SP2->u.vboolean = res; \
|
|
|
JS_POP (); \
|
|
|
\
|
|
|
} while (0)
|
|
|
|
|
|
#define JS_OPERAND_BINARY(_OP_) \
|
|
|
do { \
|
|
|
if (JS_SP2->type == JS_INTEGER && JS_SP1->type == JS_INTEGER) \
|
|
|
{ \
|
|
|
JS_SP2->u.vinteger = ((JSInt32) JS_SP2->u.vinteger \
|
|
|
_OP_ (JSInt32) JS_SP1->u.vinteger); \
|
|
|
JS_POP (); \
|
|
|
} \
|
|
|
else \
|
|
|
{ \
|
|
|
JSInt32 l, r; \
|
|
|
\
|
|
|
l = js_vm_to_int32 (vm, JS_SP2); \
|
|
|
r = js_vm_to_int32 (vm, JS_SP1); \
|
|
|
\
|
|
|
JS_SP2->u.vinteger = (l _OP_ r); \
|
|
|
JS_SP2->type = JS_INTEGER; \
|
|
|
JS_POP (); \
|
|
|
} \
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
#define JS_IS_NUMBER(n) \
|
|
|
((n)->type == JS_INTEGER || (n)->type == JS_FLOAT || (n)->type == JS_NAN)
|
|
|
|
|
|
/* Some math macros. */
|
|
|
|
|
|
#define JS_MAKE_POSITIVE_INFINITY(node) \
|
|
|
do { \
|
|
|
(node)->type = JS_FLOAT; \
|
|
|
(node)->u.vfloat = HUGE_VAL; \
|
|
|
} while (0)
|
|
|
|
|
|
#define JS_MAKE_NEGATIVE_INFINITY(node) \
|
|
|
do { \
|
|
|
(node)->type = JS_FLOAT; \
|
|
|
(node)->u.vfloat = -HUGE_VAL; \
|
|
|
} while (0)
|
|
|
|
|
|
#define JS_IS_POSITIVE_INFINITY(node) \
|
|
|
((node)->type == JS_FLOAT && (node)->u.vfloat == HUGE_VAL)
|
|
|
|
|
|
#define JS_IS_NEGATIVE_INFINITY(node) \
|
|
|
((node)->type == JS_FLOAT && (node)->u.vfloat == -HUGE_VAL)
|
|
|
|
|
|
#define JS_IS_FINITE(node) \
|
|
|
(!JS_IS_POSITIVE_INFINITY ((node)) \
|
|
|
&& !JS_IS_NEGATIVE_INFINITY ((node)) \
|
|
|
&& (node)->type != JS_NAN) \
|
|
|
|
|
|
#define JS_IS_PRIMITIVE_VALUE(node) \
|
|
|
((node)->type == JS_UNDEFINED || (node)->type == JS_NULL \
|
|
|
|| (node)->type == JS_BOOLEAN || JS_IS_NUMBER ((node)) \
|
|
|
|| (node)->type == JS_STRING)
|
|
|
|
|
|
/* Macro to clear all flags from a heap memory block. */
|
|
|
#define JS_HEAP_MEMORY_BLOCK_CLEAR_FLAGS(mb) \
|
|
|
do { \
|
|
|
(mb)->flag_mark = 0; \
|
|
|
(mb)->flag_destroyable = 0; \
|
|
|
} while (0)
|
|
|
|
|
|
#define JS_NUM_HEAP_FREELISTS 20
|
|
|
|
|
|
/*
|
|
|
* Virtual machine security flags. When these flags are enabled in
|
|
|
* the vm->security, the appropriate built-in modules don't implement
|
|
|
* insecure methods.
|
|
|
*/
|
|
|
|
|
|
#define JS_VM_SECURE_FILE 0x01
|
|
|
#define JS_VM_SECURE_SYSTEM 0x02
|
|
|
|
|
|
/*
|
|
|
* Noticeable virtual machine events. The `JS_VM_EVENT_OPERAND_COUNT'
|
|
|
* event is generated only if the interpreter was configured with the
|
|
|
* `--enable-operand-hooks' option.
|
|
|
*/
|
|
|
|
|
|
#define JS_VM_EVENT_OPERAND_COUNT 1
|
|
|
#define JS_VM_EVENT_GARBAGE_COLLECT 2
|
|
|
|
|
|
/*
|
|
|
* Integer types.
|
|
|
*/
|
|
|
|
|
|
typedef unsigned char JSUInt8;
|
|
|
typedef signed char JSInt8;
|
|
|
|
|
|
typedef unsigned short JSUInt16;
|
|
|
typedef short JSInt16;
|
|
|
|
|
|
#if SIZEOF_INT == 4
|
|
|
|
|
|
typedef unsigned int JSUInt32;
|
|
|
typedef int JSInt32;
|
|
|
|
|
|
#else /* not SIZEOF_INT == 4 */
|
|
|
|
|
|
#if SIZEOF_LONG == 4
|
|
|
|
|
|
typedef unsigned long JSUInt32;
|
|
|
typedef long JSInt32;
|
|
|
|
|
|
#else /* not SIZEOF_LONG == 4 */
|
|
|
|
|
|
#error "do not know how to define a 32 bit long integer"
|
|
|
|
|
|
#endif /* not SIZEOF_LONG == 4 */
|
|
|
|
|
|
#endif /* not SIZEOF_INT == 4 */
|
|
|
|
|
|
/*
|
|
|
* An unsigned interger number that can be used to align structures to
|
|
|
* correct byte boundaries. On 64 bit machines (Alpha) this should be
|
|
|
* 64 bits long, etc. For now one, we just assume that the mashine is
|
|
|
* a LP64 so the `unsigned long' is a correct type for it.
|
|
|
*/
|
|
|
typedef unsigned long JSUIntAlign;
|
|
|
|
|
|
/* I/O streams. */
|
|
|
|
|
|
/* Buffer filler or flusher function. */
|
|
|
typedef int (*JSIOStreamIOFunc) (void *context, unsigned char *buffer,
|
|
|
unsigned int todo, int *error_return);
|
|
|
|
|
|
typedef int (*JSIOStreamSeek) (void *context, long offset, int whence);
|
|
|
|
|
|
typedef long (*JSIOStreamGetPosition) (void *context);
|
|
|
|
|
|
typedef long (*JSIOStreamGetLength) (void *context);
|
|
|
|
|
|
typedef void (*JSIOStreamClose) (void *context);
|
|
|
|
|
|
/* The I/O stream handle. */
|
|
|
struct js_io_stream_st
|
|
|
{
|
|
|
unsigned char *buffer; /* Must be reallocatable with js_realloc(). */
|
|
|
unsigned int buflen;
|
|
|
unsigned int data_in_buf;
|
|
|
unsigned int bufpos;
|
|
|
|
|
|
/* Flags. */
|
|
|
unsigned int at_eof : 1;
|
|
|
unsigned int autoflush : 1;
|
|
|
unsigned int writep : 1; /* Does the buffer contain write data? */
|
|
|
|
|
|
/* The system error code for the last operation that failed. */
|
|
|
int error;
|
|
|
|
|
|
/* Only one of the read and write is active. */
|
|
|
JSIOStreamIOFunc read;
|
|
|
JSIOStreamIOFunc write;
|
|
|
JSIOStreamSeek seek;
|
|
|
JSIOStreamGetPosition get_position;
|
|
|
JSIOStreamGetLength get_length;
|
|
|
|
|
|
JSIOStreamClose close;
|
|
|
|
|
|
void *context;
|
|
|
};
|
|
|
|
|
|
typedef struct js_io_stream_st JSIOStream;
|
|
|
|
|
|
|
|
|
/* The destroy callback for the destroyable heap blocks. */
|
|
|
typedef void (*JSHeapDestroyableCB) (void *ptr);
|
|
|
|
|
|
/*
|
|
|
* Each destroyable heap block must be castable to this structure e.g.
|
|
|
* the first item in the block must be pointer to the destroy function.
|
|
|
*/
|
|
|
struct js_heap_destroyable_st
|
|
|
{
|
|
|
JSHeapDestroyableCB destroy;
|
|
|
};
|
|
|
|
|
|
typedef struct js_heap_destroyable_st JSHeapDestroyable;
|
|
|
|
|
|
|
|
|
/* Interned symbol. */
|
|
|
typedef unsigned int JSSymbol;
|
|
|
|
|
|
/* JavaScript Types. */
|
|
|
|
|
|
typedef enum
|
|
|
{
|
|
|
JS_UNDEFINED = 0,
|
|
|
JS_NULL = 1,
|
|
|
JS_BOOLEAN = 2,
|
|
|
JS_INTEGER = 3, /* Integer, float and nan are `number' */
|
|
|
JS_STRING = 4,
|
|
|
JS_FLOAT = 5,
|
|
|
JS_ARRAY = 6,
|
|
|
JS_OBJECT = 7,
|
|
|
|
|
|
/*
|
|
|
* The following ones are the internal types, used by this implementation.
|
|
|
*/
|
|
|
|
|
|
JS_SYMBOL = 10,
|
|
|
JS_BUILTIN = 11,
|
|
|
JS_FUNC = 12,
|
|
|
JS_NAN = 13,
|
|
|
|
|
|
JS_IPTR = 14,
|
|
|
JS_ARGS_FIX = 15
|
|
|
} JSNodeType;
|
|
|
|
|
|
struct js_node_st;
|
|
|
struct js_vm_st;
|
|
|
struct js_builtin_info_st;
|
|
|
|
|
|
/* Registry information for builtin objects. */
|
|
|
|
|
|
#define JS_PROPERTY_FOUND 1
|
|
|
#define JS_PROPERTY_UNKNOWN 0
|
|
|
|
|
|
typedef void (*JSBuiltinGlobalMethod) (struct js_vm_st *vm,
|
|
|
struct js_builtin_info_st *builtin_info,
|
|
|
void *instance_context,
|
|
|
struct js_node_st *result_return,
|
|
|
struct js_node_st *args);
|
|
|
|
|
|
/*
|
|
|
* Function to call method <method> from the object. Function must return
|
|
|
* JS_PROPERTY_FOUND if the method was found or JS_PROPERTY_UNKNOWN
|
|
|
* otherwise.
|
|
|
*/
|
|
|
typedef int (*JSBuiltinMethod) (struct js_vm_st *vm,
|
|
|
struct js_builtin_info_st *builtin_info,
|
|
|
void *instance_context,
|
|
|
JSSymbol method,
|
|
|
struct js_node_st *result_return,
|
|
|
struct js_node_st *args);
|
|
|
|
|
|
/*
|
|
|
* Function to load and set property <property> of object. If <set>
|
|
|
* is true, property <property> should be set to value <node>. Otherwise
|
|
|
* function should return the value of property <property> in <node>.
|
|
|
* Function must return JS_PROPERTY_FOUND if the property was found or
|
|
|
* JS_PROPERTY_UNKNOWN otherwise.
|
|
|
*/
|
|
|
typedef int (*JSBuiltinProperty) (struct js_vm_st *vm,
|
|
|
struct js_builtin_info_st *builtin_info,
|
|
|
void *instance_context,
|
|
|
JSSymbol property, int set,
|
|
|
struct js_node_st *node);
|
|
|
|
|
|
typedef void (*JSBuiltinNew) (struct js_vm_st *vm,
|
|
|
struct js_builtin_info_st *builtin_info,
|
|
|
struct js_node_st *args,
|
|
|
struct js_node_st *result_return);
|
|
|
|
|
|
typedef void (*JSBuiltinDelete) (struct js_builtin_info_st *builtin_info,
|
|
|
void *instance_context);
|
|
|
|
|
|
typedef void (*JSBuiltinMark) (struct js_builtin_info_st *builtin_info,
|
|
|
void *instance_context);
|
|
|
|
|
|
typedef void (*JSBuiltinObjectCtxDelete) (void *obj_context);
|
|
|
|
|
|
struct js_builtin_info_st
|
|
|
{
|
|
|
JSHeapDestroyableCB destroy;
|
|
|
|
|
|
JSBuiltinGlobalMethod global_method_proc;
|
|
|
JSBuiltinMethod method_proc;
|
|
|
JSBuiltinProperty property_proc;
|
|
|
JSBuiltinNew new_proc;
|
|
|
JSBuiltinDelete delete_proc;
|
|
|
JSBuiltinMark mark_proc;
|
|
|
|
|
|
void *obj_context;
|
|
|
JSBuiltinObjectCtxDelete obj_context_delete;
|
|
|
|
|
|
struct js_object_st *prototype;
|
|
|
};
|
|
|
|
|
|
typedef struct js_builtin_info_st JSBuiltinInfo;
|
|
|
|
|
|
/* Builtin object / class. */
|
|
|
struct js_builtin_st
|
|
|
{
|
|
|
JSHeapDestroyableCB destroy;
|
|
|
|
|
|
JSBuiltinInfo *info;
|
|
|
void *instance_context;
|
|
|
|
|
|
struct js_object_st *prototype;
|
|
|
};
|
|
|
|
|
|
typedef struct js_builtin_st JSBuiltin;
|
|
|
|
|
|
/* String. */
|
|
|
struct js_string_st
|
|
|
{
|
|
|
/* Flags. */
|
|
|
unsigned int staticp : 1;
|
|
|
|
|
|
unsigned char *data;
|
|
|
unsigned int len;
|
|
|
|
|
|
struct js_object_st *prototype;
|
|
|
};
|
|
|
|
|
|
typedef struct js_string_st JSString;
|
|
|
|
|
|
/* Array. */
|
|
|
struct js_array_st
|
|
|
{
|
|
|
unsigned int length;
|
|
|
struct js_node_st *data;
|
|
|
|
|
|
struct js_object_st *prototype;
|
|
|
};
|
|
|
|
|
|
typedef struct js_array_st JSArray;
|
|
|
|
|
|
/* Function. */
|
|
|
struct js_function_st
|
|
|
{
|
|
|
void *implementation;
|
|
|
struct js_object_st *prototype;
|
|
|
};
|
|
|
|
|
|
typedef struct js_function_st JSFunction;
|
|
|
|
|
|
/* Node. */
|
|
|
struct js_node_st
|
|
|
{
|
|
|
JSNodeType type;
|
|
|
|
|
|
union
|
|
|
{
|
|
|
unsigned int vboolean;
|
|
|
|
|
|
JSString *vstring;
|
|
|
|
|
|
long vinteger;
|
|
|
double vfloat;
|
|
|
|
|
|
struct js_object_st *vobject;
|
|
|
|
|
|
JSArray *varray;
|
|
|
|
|
|
/* Internal values. */
|
|
|
|
|
|
JSSymbol vsymbol;
|
|
|
|
|
|
JSBuiltin *vbuiltin;
|
|
|
|
|
|
JSFunction *vfunction;
|
|
|
|
|
|
void *iptr;
|
|
|
|
|
|
struct
|
|
|
{
|
|
|
JSUInt32 argc;
|
|
|
JSUInt32 delta;
|
|
|
} args_fix;
|
|
|
|
|
|
struct
|
|
|
{
|
|
|
JSUInt32 a;
|
|
|
JSUInt32 b;
|
|
|
} copy;
|
|
|
} u;
|
|
|
};
|
|
|
|
|
|
typedef struct js_node_st JSNode;
|
|
|
|
|
|
|
|
|
/* Object. */
|
|
|
|
|
|
/* Hash node for object's properties. */
|
|
|
struct js_object_prop_hash_bucket_st
|
|
|
{
|
|
|
struct js_object_prop_hash_bucket_st *next;
|
|
|
unsigned char *data;
|
|
|
unsigned int len;
|
|
|
unsigned int value;
|
|
|
};
|
|
|
|
|
|
typedef struct js_object_prop_hash_bucket_st JSObjectPropHashBucket;
|
|
|
|
|
|
/* The attribute flags for object's properties. */
|
|
|
#define JS_ATTRIB_READONLY 1
|
|
|
#define JS_ATTRIB_DONTENUM 2
|
|
|
#define JS_ATTRIB_DONTDELETE 4
|
|
|
#define JS_ATTRIB_Internal 8
|
|
|
|
|
|
/* Object's property. */
|
|
|
struct js_property_st
|
|
|
{
|
|
|
JSSymbol name;
|
|
|
JSNode value;
|
|
|
unsigned int attributes;
|
|
|
};
|
|
|
|
|
|
typedef struct js_property_st JSProperty;
|
|
|
|
|
|
struct js_object_st
|
|
|
{
|
|
|
JSObjectPropHashBucket **hash;
|
|
|
unsigned int *hash_lengths;
|
|
|
unsigned int num_props; /* Number of properties in this object. */
|
|
|
JSProperty *props;
|
|
|
};
|
|
|
|
|
|
typedef struct js_object_st JSObject;
|
|
|
|
|
|
|
|
|
/* Byte code. */
|
|
|
|
|
|
typedef enum
|
|
|
{
|
|
|
JS_BCST_CODE = 0,
|
|
|
JS_BCST_CONSTANTS = 1,
|
|
|
JS_BCST_SYMTAB = 2,
|
|
|
JS_BCST_DEBUG = 3
|
|
|
} JSBCSectionType;
|
|
|
|
|
|
struct js_bc_sect_st
|
|
|
{
|
|
|
JSBCSectionType type;
|
|
|
unsigned int length;
|
|
|
void *data; /* <length> bytes of data */
|
|
|
};
|
|
|
|
|
|
typedef struct js_bc_sect_st JSBCSect;
|
|
|
|
|
|
struct js_bc_st
|
|
|
{
|
|
|
unsigned int num_sects;
|
|
|
JSBCSect *sects;
|
|
|
};
|
|
|
|
|
|
typedef struct js_bc_st JSByteCode;
|
|
|
|
|
|
/* Debug information. */
|
|
|
#define JS_DI_FILENAME 1
|
|
|
#define JS_DI_LINENUMBER 2
|
|
|
|
|
|
/* Heap block. */
|
|
|
struct js_heap_block_st
|
|
|
{
|
|
|
struct js_heap_block_st *next;
|
|
|
unsigned int size;
|
|
|
/* <size> bytes of data follows the structure. */
|
|
|
};
|
|
|
|
|
|
typedef struct js_heap_block_st JSHeapBlock;
|
|
|
|
|
|
/* Heap memory block. */
|
|
|
|
|
|
#define JS_MEM_DEBUG 0
|
|
|
|
|
|
/* All allocated blocks have this header. */
|
|
|
struct js_heap_memory_block_st
|
|
|
{
|
|
|
#if JS_MEM_DEBUG
|
|
|
JSUIntAlign magic;
|
|
|
#endif
|
|
|
|
|
|
JSUIntAlign flag_mark : 1;
|
|
|
JSUIntAlign flag_destroyable : 1;
|
|
|
JSUIntAlign size : (sizeof (JSUIntAlign) * 8 - 2);
|
|
|
/* <size> bytes of data follows this header. */
|
|
|
};
|
|
|
|
|
|
typedef struct js_heap_memory_block_st JSHeapMemoryBlock;
|
|
|
|
|
|
/*
|
|
|
* When the block is on the freelist, it has this header. The first
|
|
|
* sizeof (void *) bytes of the block's data is used to hold the
|
|
|
* freelist next pointer.
|
|
|
*/
|
|
|
struct js_heap_freelist_block_st
|
|
|
{
|
|
|
JSHeapMemoryBlock block;
|
|
|
JSHeapMemoryBlock *next;
|
|
|
};
|
|
|
|
|
|
typedef struct js_heap_freelist_block_st JSHeapFreelistBlock;
|
|
|
|
|
|
|
|
|
/* Parsed symbol table entry. */
|
|
|
struct js_symtab_entry_st
|
|
|
{
|
|
|
char *name;
|
|
|
unsigned int offset;
|
|
|
};
|
|
|
|
|
|
typedef struct js_symtab_entry_st JSSymtabEntry;
|
|
|
|
|
|
|
|
|
/*
|
|
|
* Entry points to different byte-code instruction dispatcher functions.
|
|
|
* Each dispatcher must implement these.
|
|
|
*/
|
|
|
|
|
|
typedef int (*JSVMExecute) (struct js_vm_st *vm, JSByteCode *bc,
|
|
|
JSSymtabEntry *symtab,
|
|
|
unsigned int num_symtab_entries,
|
|
|
unsigned int consts_offset,
|
|
|
unsigned int anonymous_function_offset,
|
|
|
unsigned char *debug_info,
|
|
|
unsigned int debug_info_len,
|
|
|
JSNode *object, JSNode *func,
|
|
|
unsigned int argc, JSNode *argv);
|
|
|
|
|
|
typedef const char *(*JSVMFuncName) (struct js_vm_st *vm, void *pc);
|
|
|
|
|
|
typedef const char *(*JSVMDebugPosition) (struct js_vm_st *vm,
|
|
|
unsigned int *linenum_return);
|
|
|
|
|
|
|
|
|
/* Virtual Machine. */
|
|
|
|
|
|
#define JS_HASH_TABLE_SIZE 256
|
|
|
|
|
|
struct js_hash_bucket_st
|
|
|
{
|
|
|
struct js_hash_bucket_st *next;
|
|
|
char *name;
|
|
|
union
|
|
|
{
|
|
|
void *data;
|
|
|
unsigned int ui;
|
|
|
} u;
|
|
|
};
|
|
|
|
|
|
typedef struct js_hash_bucket_st JSHashBucket;
|
|
|
|
|
|
/* Error handler frame. */
|
|
|
struct js_error_handler_frame_st
|
|
|
{
|
|
|
struct js_error_handler_frame_st *next;
|
|
|
jmp_buf error_jmp;
|
|
|
|
|
|
/* The value thrown by the throw operand. */
|
|
|
JSNode thrown;
|
|
|
|
|
|
/* Saved state for the `try_push' operand. */
|
|
|
JSNode *sp;
|
|
|
JSNode *fp;
|
|
|
void *pc;
|
|
|
JSInt32 pc_delta;
|
|
|
};
|
|
|
|
|
|
typedef struct js_error_handler_frame_st JSErrorHandlerFrame;
|
|
|
|
|
|
struct js_vm_st
|
|
|
{
|
|
|
/* Options for the virtual machine. */
|
|
|
unsigned int verbose; /* verbosity has different levels. */
|
|
|
|
|
|
unsigned int stacktrace_on_error : 1;
|
|
|
unsigned int verbose_stacktrace : 1;
|
|
|
unsigned int warn_undef : 1;
|
|
|
|
|
|
/* Security flags. */
|
|
|
unsigned long security;
|
|
|
|
|
|
/* The default system streams. */
|
|
|
JSIOStream *s_stdin;
|
|
|
JSIOStream *s_stdout;
|
|
|
JSIOStream *s_stderr;
|
|
|
|
|
|
/* The byte-code instruction dispatcher. */
|
|
|
JSVMDispatchMethod dispatch_method;
|
|
|
const char *dispatch_method_name;
|
|
|
JSVMExecute dispatch_execute;
|
|
|
JSVMFuncName dispatch_func_name;
|
|
|
JSVMDebugPosition dispatch_debug_position;
|
|
|
|
|
|
/* Constants pool. */
|
|
|
JSNode *consts;
|
|
|
unsigned int num_consts;
|
|
|
unsigned int consts_alloc;
|
|
|
|
|
|
/*
|
|
|
* Global symbols (both functions and variables). <globals_hash> is
|
|
|
* a name-to-index mapping between symbol names and their positions
|
|
|
* in <globals>.
|
|
|
*/
|
|
|
JSHashBucket *globals_hash[JS_HASH_TABLE_SIZE];
|
|
|
JSNode *globals;
|
|
|
unsigned int num_globals;
|
|
|
unsigned int globals_alloc;
|
|
|
|
|
|
/* The next anonymous function id. */
|
|
|
unsigned int anonymous_function_next_id;
|
|
|
|
|
|
/* Stack. */
|
|
|
JSNode *stack;
|
|
|
unsigned int stack_size;
|
|
|
JSNode *sp; /* Fuzzy stack pointer. */
|
|
|
|
|
|
void *pc; /* Fuzzy program counter. */
|
|
|
|
|
|
/* Builtin objects for the primitive datatypes. */
|
|
|
JSBuiltinInfo *prim[JS_IPTR + 1];
|
|
|
|
|
|
/* Some commonly used symbols. */
|
|
|
struct
|
|
|
{
|
|
|
JSSymbol s___proto__;
|
|
|
JSSymbol s_prototype;
|
|
|
JSSymbol s_toSource;
|
|
|
JSSymbol s_toString;
|
|
|
JSSymbol s_valueOf;
|
|
|
} syms;
|
|
|
|
|
|
/* Heap. */
|
|
|
|
|
|
JSHeapBlock *heap;
|
|
|
JSHeapMemoryBlock *heap_freelists[JS_NUM_HEAP_FREELISTS];
|
|
|
unsigned long heap_size;
|
|
|
|
|
|
/* Information for the garbage collector. */
|
|
|
struct
|
|
|
{
|
|
|
unsigned long trigger;
|
|
|
unsigned long bytes_allocated;
|
|
|
unsigned long bytes_free;
|
|
|
unsigned long count;
|
|
|
} gc;
|
|
|
|
|
|
/* Error handler frames. */
|
|
|
JSErrorHandlerFrame *error_handler;
|
|
|
|
|
|
/* Buffer for the error message. Sorry, we don't support long errors ;-) */
|
|
|
char error[1024];
|
|
|
|
|
|
/*
|
|
|
* The result from the latest evaluation. This is set when the
|
|
|
* js_vm_execute(), js_vm_apply(), or js_vm_call_method() functions
|
|
|
* return to the caller.
|
|
|
*/
|
|
|
JSNode exec_result;
|
|
|
|
|
|
/* Event callback hook. */
|
|
|
int (*hook) (int event, void *context);
|
|
|
void *hook_context;
|
|
|
unsigned int hook_operand_count;
|
|
|
unsigned int hook_operand_count_trigger;
|
|
|
|
|
|
/* How many file descriptors can be allocated. */
|
|
|
unsigned long fd_count;
|
|
|
|
|
|
#if PROFILING
|
|
|
|
|
|
/* Byte-code operand profiling support. */
|
|
|
|
|
|
unsigned int prof_count[256];
|
|
|
unsigned char prof_op;
|
|
|
|
|
|
#endif /* PROFILING */
|
|
|
};
|
|
|
|
|
|
typedef struct js_vm_st JSVirtualMachine;
|
|
|
|
|
|
|
|
|
/*
|
|
|
* Global variables.
|
|
|
*/
|
|
|
|
|
|
extern unsigned char js_latin1_tolower[256];
|
|
|
extern unsigned char js_latin1_toupper[256];
|
|
|
|
|
|
/*
|
|
|
* Prototypes for global functions.
|
|
|
*/
|
|
|
|
|
|
/*
|
|
|
* Memory allocation routines. If the allocation request fails, the
|
|
|
* error recovery is performed according to the argument <vm>. If
|
|
|
* <vm> is not NULL, an error message is formatted to vm->error and an
|
|
|
* error is raise with js_vm_error(). If the <vm> is NULL, the
|
|
|
* functions will return value NULL. It is an error to call these
|
|
|
* functions with a non-NULL <vm> that has no error handler
|
|
|
* initialized.
|
|
|
*/
|
|
|
|
|
|
#ifndef JS_DEBUG_MEMORY_LEAKS
|
|
|
#define JS_DEBUG_MEMORY_LEAKS 0
|
|
|
#endif /* not JS_DEBUG_MEMORY_LEAKS */
|
|
|
|
|
|
#if JS_DEBUG_MEMORY_LEAKS
|
|
|
|
|
|
#define js_malloc(vm, size) js_malloc_i ((vm), (size), \
|
|
|
__FILE__, __LINE__)
|
|
|
#define js_calloc(vm, num, size) js_calloc_i ((vm), (num), (size), \
|
|
|
__FILE__, __LINE__)
|
|
|
#define js_realloc(vm, ptr, size) js_realloc_i ((vm), (ptr), (size), \
|
|
|
__FILE__, __LINE__)
|
|
|
#define js_strdup(vm, str) js_strdup_i ((vm), (str), \
|
|
|
__FILE__, __LINE__)
|
|
|
|
|
|
void *js_malloc_i (JSVirtualMachine *vm, size_t size, char *, int);
|
|
|
void *js_calloc_i (JSVirtualMachine *vm, size_t num, size_t size, char *, int);
|
|
|
void *js_realloc_i (JSVirtualMachine *vm, void *ptr, size_t size, char *, int);
|
|
|
void js_free (void *ptr);
|
|
|
char *js_strdup_i (JSVirtualMachine *vm, const char *str, char *, int);
|
|
|
|
|
|
#else /* not JS_DEBUG_MEMORY_LEAKS */
|
|
|
|
|
|
void *js_malloc (JSVirtualMachine *vm, size_t size);
|
|
|
void *js_calloc (JSVirtualMachine *vm, size_t num, size_t size);
|
|
|
void *js_realloc (JSVirtualMachine *vm, void *ptr, size_t size);
|
|
|
void js_free (void *ptr);
|
|
|
char *js_strdup (JSVirtualMachine *vm, const char *str);
|
|
|
|
|
|
#endif /* not JS_DEBUG_MEMORY_LEAKS */
|
|
|
|
|
|
|
|
|
/* Byte code. */
|
|
|
|
|
|
JSByteCode *js_bc_read_file (FILE *fp);
|
|
|
|
|
|
JSByteCode *js_bc_read_data (unsigned char *data, unsigned int datalen);
|
|
|
|
|
|
void js_bc_free (JSByteCode *bc);
|
|
|
|
|
|
|
|
|
/* I/O streams. */
|
|
|
|
|
|
/* Allocate one I/O stream handle. */
|
|
|
JSIOStream *js_iostream_new ();
|
|
|
|
|
|
JSIOStream *js_iostream_file (FILE *fp, int readp, int writep, int do_close);
|
|
|
|
|
|
JSIOStream *js_iostream_pipe (FILE *fp, int readp);
|
|
|
|
|
|
size_t js_iostream_read (JSIOStream *stream, void *ptr, size_t size);
|
|
|
|
|
|
size_t js_iostream_write (JSIOStream *stream, void *ptr, size_t size);
|
|
|
|
|
|
int js_iostream_flush (JSIOStream *stream);
|
|
|
|
|
|
int js_iostream_unget (JSIOStream *stream, int byte);
|
|
|
|
|
|
int js_iostream_close (JSIOStream *stream);
|
|
|
|
|
|
int js_iostream_seek (JSIOStream *stream, long offset, int whence);
|
|
|
|
|
|
long js_iostream_get_position (JSIOStream *stream);
|
|
|
|
|
|
long js_iostream_get_length (JSIOStream *stream);
|
|
|
|
|
|
void js_iostream_fill_buffer (JSIOStream *stream);
|
|
|
|
|
|
|
|
|
/* Virtual machine. */
|
|
|
|
|
|
JSVirtualMachine *js_vm_create (unsigned int stack_size,
|
|
|
JSVMDispatchMethod dispatch_method,
|
|
|
unsigned int verbose, int stacktrace_on_error,
|
|
|
JSIOStream *s_stdin, JSIOStream *s_stdout,
|
|
|
JSIOStream *s_stderr);
|
|
|
|
|
|
void js_vm_destroy (JSVirtualMachine *vm);
|
|
|
|
|
|
/*
|
|
|
* Execute byte code <bc>. Function returns 1 if the operation was
|
|
|
* successful or 0 if any errors were encountered. In case of errors,
|
|
|
* the error message is stored at vm->error.
|
|
|
*/
|
|
|
int js_vm_execute (JSVirtualMachine *vm, JSByteCode *bc);
|
|
|
|
|
|
/*
|
|
|
* Apply function <func_name> to arguments <argc, argv>. If
|
|
|
* function's name <func_name> is NULL, then <func> must specify function
|
|
|
* to which arguments are applied.
|
|
|
*/
|
|
|
int js_vm_apply (JSVirtualMachine *vm, char *func_name, JSNode *func,
|
|
|
unsigned int argc, JSNode *argv);
|
|
|
|
|
|
/*
|
|
|
* Call method <method_name> from object <objet> with arguments <argc, argv>.
|
|
|
*/
|
|
|
int js_vm_call_method (JSVirtualMachine *vm, JSNode *object,
|
|
|
const char *method_name, unsigned int argc,
|
|
|
JSNode *argv);
|
|
|
|
|
|
/* Map program counter to the source file line. */
|
|
|
const char *js_vm_debug_position (JSVirtualMachine *vm,
|
|
|
unsigned int *linenum_return);
|
|
|
|
|
|
/* Fetch the function name from the program counter value. */
|
|
|
const char *js_vm_func_name (JSVirtualMachine *vm, void *pc);
|
|
|
|
|
|
/* Intern symbol <name, len> to virtual machine and return its JSSymbol id. */
|
|
|
JSSymbol js_vm_intern_with_len (JSVirtualMachine *vm, const char *name,
|
|
|
unsigned int len);
|
|
|
|
|
|
/* Intern symbol <name> to virtual machine and return its JSSymbol id. */
|
|
|
static inline JSSymbol
|
|
|
js_vm_intern (JSVirtualMachine *vm, const char *name)
|
|
|
{
|
|
|
return js_vm_intern_with_len (vm, name, strlen (name));
|
|
|
}
|
|
|
|
|
|
/* Return the name of symbol <sym>. */
|
|
|
const char *js_vm_symname (JSVirtualMachine *vm, JSSymbol sym);
|
|
|
|
|
|
/*
|
|
|
* ToPrimitive(). Convert node <n> to its primitive value and return
|
|
|
* the result in <result_return>.
|
|
|
*/
|
|
|
void js_vm_to_primitive (JSVirtualMachine *vm, const JSNode *n,
|
|
|
JSNode *result_return, JSNodeType preferred_type);
|
|
|
|
|
|
/*
|
|
|
* ToString(). Convert node <n> to its string presentations and
|
|
|
* return the result in <result_return>.
|
|
|
*/
|
|
|
void js_vm_to_string (JSVirtualMachine *vm, const JSNode *n,
|
|
|
JSNode *result_return);
|
|
|
|
|
|
/*
|
|
|
* ToNumber(). Convert node <n> to its number presentations and
|
|
|
* return the result in <result_return>.
|
|
|
*/
|
|
|
void js_vm_to_number (JSVirtualMachine *vm, const JSNode *n,
|
|
|
JSNode *result_return);
|
|
|
|
|
|
/* ToObject(). Convert node <n> to object according to its type. */
|
|
|
void js_vm_to_object (JSVirtualMachine *vm, const JSNode *n,
|
|
|
JSNode *result_return);
|
|
|
|
|
|
/*
|
|
|
* ToInt32(). Convert node <n> to its signed 32 bit integer
|
|
|
* presentation and return the result.
|
|
|
*/
|
|
|
JSInt32 js_vm_to_int32 (JSVirtualMachine *vm, JSNode *n);
|
|
|
|
|
|
/*
|
|
|
* ToBoolean(). Convert node <n> to a boolean value and return the
|
|
|
* result.
|
|
|
*/
|
|
|
int js_vm_to_boolean (JSVirtualMachine *vm, JSNode *n);
|
|
|
|
|
|
|
|
|
/*
|
|
|
* Raise an error. The error message must have been saved to vm->error
|
|
|
* before this function is called. The function never returns.
|
|
|
*/
|
|
|
void js_vm_error (JSVirtualMachine *vm);
|
|
|
|
|
|
/*
|
|
|
* Count a hash value for <data_len> bytes of data <data>. The resulting
|
|
|
* hash value should be re-mapped to the correct range, for example,
|
|
|
* with the mod operand.
|
|
|
*/
|
|
|
static inline unsigned int
|
|
|
js_count_hash (const char *data, unsigned int data_len)
|
|
|
{
|
|
|
unsigned int val = 0, i;
|
|
|
|
|
|
for (i = 0; i < data_len; i++)
|
|
|
val = (val << 5) ^ (unsigned char) data[i]
|
|
|
^ (val >> 16) ^ (val >> 7);
|
|
|
|
|
|
return val;
|
|
|
}
|
|
|
|
|
|
|
|
|
/* Prototypes for the different instruction dispatcher implementations. */
|
|
|
|
|
|
#if ALL_DISPATCHERS
|
|
|
|
|
|
int js_vm_switch0_exec (JSVirtualMachine *vm, JSByteCode *bc,
|
|
|
JSSymtabEntry *symtab,
|
|
|
unsigned int num_symtab_entries,
|
|
|
unsigned int consts_offset,
|
|
|
unsigned int anonymous_function_offset,
|
|
|
unsigned char *debug_info,
|
|
|
unsigned int debug_info_len,
|
|
|
JSNode *object, JSNode *func,
|
|
|
unsigned int argc, JSNode *argv);
|
|
|
|
|
|
const char *js_vm_switch0_func_name (JSVirtualMachine *vm, void *pc);
|
|
|
|
|
|
const char *js_vm_switch0_debug_position (JSVirtualMachine *vm,
|
|
|
unsigned int *linenum_return);
|
|
|
|
|
|
#endif /* ALL_DISPATCHERS */
|
|
|
|
|
|
int js_vm_switch_exec (JSVirtualMachine *vm, JSByteCode *bc,
|
|
|
JSSymtabEntry *symtab,
|
|
|
unsigned int num_symtab_entries,
|
|
|
unsigned int consts_offset,
|
|
|
unsigned int anonymous_function_offset,
|
|
|
unsigned char *debug_info, unsigned int debug_info_len,
|
|
|
JSNode *object, JSNode *func,
|
|
|
unsigned int argc, JSNode *argv);
|
|
|
|
|
|
const char *js_vm_switch_func_name (JSVirtualMachine *vm, void *pc);
|
|
|
|
|
|
const char *js_vm_switch_debug_position (JSVirtualMachine *vm,
|
|
|
unsigned int *linenum_return);
|
|
|
|
|
|
int js_vm_jumps_exec (JSVirtualMachine *vm, JSByteCode *bc,
|
|
|
JSSymtabEntry *symtab,
|
|
|
unsigned int num_symtab_entries,
|
|
|
unsigned int consts_offset,
|
|
|
unsigned int anonymous_function_offset,
|
|
|
unsigned char *debug_info, unsigned int debug_info_len,
|
|
|
JSNode *object, JSNode *func,
|
|
|
unsigned int argc, JSNode *argv);
|
|
|
|
|
|
const char *js_vm_jumps_func_name (JSVirtualMachine *vm, void *pc);
|
|
|
|
|
|
const char *js_vm_jumps_debug_position (JSVirtualMachine *vm,
|
|
|
unsigned int *linenum_return);
|
|
|
|
|
|
|
|
|
/* Heap. */
|
|
|
|
|
|
void *js_vm_alloc (JSVirtualMachine *vm, unsigned int size);
|
|
|
|
|
|
void *js_vm_alloc_destroyable (JSVirtualMachine *vm, unsigned int size);
|
|
|
|
|
|
void *js_vm_realloc (JSVirtualMachine *vm, void *ptr, unsigned int new_size);
|
|
|
|
|
|
void js_vm_free (JSVirtualMachine *vm, void *ptr);
|
|
|
|
|
|
void js_vm_garbage_collect (JSVirtualMachine *vm, JSNode *fp, JSNode *sp);
|
|
|
|
|
|
void js_vm_clear_heap (JSVirtualMachine *vm);
|
|
|
|
|
|
void js_vm_mark (JSNode *node);
|
|
|
|
|
|
int js_vm_mark_ptr (void *ptr);
|
|
|
|
|
|
int js_vm_is_marked_ptr (void *ptr);
|
|
|
|
|
|
/* Function. */
|
|
|
|
|
|
static inline JSFunction *
|
|
|
js_vm_make_function (JSVirtualMachine *vm, void *implementation)
|
|
|
{
|
|
|
JSFunction *f = (JSFunction *) js_vm_alloc (vm, sizeof (*f));
|
|
|
|
|
|
f->implementation = implementation;
|
|
|
f->prototype = (JSObject *) NULL;
|
|
|
|
|
|
return f;
|
|
|
}
|
|
|
|
|
|
|
|
|
/* Built-in. */
|
|
|
|
|
|
/* Create a new built-in info. */
|
|
|
JSBuiltinInfo *js_vm_builtin_info_create (JSVirtualMachine *vm);
|
|
|
|
|
|
/* Create a new builtin object with <info, instance_context> to <result>. */
|
|
|
void js_vm_builtin_create (JSVirtualMachine *vm, JSNode *result,
|
|
|
JSBuiltinInfo *info, void *instance_context);
|
|
|
|
|
|
/* Array. */
|
|
|
|
|
|
static inline void
|
|
|
js_vm_make_array (JSVirtualMachine *vm, JSNode *n, unsigned int length)
|
|
|
{
|
|
|
unsigned int i;
|
|
|
|
|
|
n->type = JS_ARRAY;
|
|
|
n->u.varray = (JSArray *) js_vm_alloc (vm, sizeof (*n->u.varray));
|
|
|
n->u.varray->prototype = NULL;
|
|
|
n->u.varray->length = length;
|
|
|
n->u.varray->data = (JSNode *) js_vm_alloc (vm, length * sizeof (JSNode));
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
n->u.varray->data[i].type = JS_UNDEFINED;
|
|
|
}
|
|
|
|
|
|
static inline void
|
|
|
js_vm_expand_array (JSVirtualMachine *vm, JSNode *n, unsigned int length)
|
|
|
{
|
|
|
if (n->u.varray->length < length)
|
|
|
{
|
|
|
n->u.varray->data = (JSNode *) js_vm_realloc (vm, n->u.varray->data,
|
|
|
length * sizeof (JSNode));
|
|
|
for (; n->u.varray->length < length; n->u.varray->length++)
|
|
|
n->u.varray->data[n->u.varray->length].type = JS_UNDEFINED;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* File. */
|
|
|
|
|
|
/* Enter file <fp> to the system. */
|
|
|
void js_builtin_File_new (JSVirtualMachine *vm, JSNode *result_return,
|
|
|
char *path, JSIOStream *stream, int dont_close);
|
|
|
|
|
|
/* RegExp. */
|
|
|
|
|
|
/*
|
|
|
* Create a new regular expression node from <source, sourcelen> according
|
|
|
* to <flags>. The argument <immutable> defines whether the created
|
|
|
* regexp is immutable. The new regexp is returned in <result_return>.
|
|
|
* If the <info> is NULL, the function will resolve it. Otherwise the given
|
|
|
* value is used.
|
|
|
*/
|
|
|
void js_builtin_RegExp_new (JSVirtualMachine *vm, char *source,
|
|
|
unsigned int source_len, unsigned int flags,
|
|
|
int immutable, JSBuiltinInfo *info,
|
|
|
JSNode *result_return);
|
|
|
|
|
|
/*
|
|
|
* Do search-replace for the string <data, datalen> by replacing
|
|
|
* matches of <regexp> with <repl, repl_len>. The resulting string is
|
|
|
* returned in <result_return>
|
|
|
*/
|
|
|
void js_builtin_RegExp_replace (JSVirtualMachine *vm, char *data,
|
|
|
unsigned int datalen, JSNode *regexp,
|
|
|
char *repl, unsigned int repl_len,
|
|
|
JSNode *result_return);
|
|
|
|
|
|
/*
|
|
|
* Do regexp match against <data, datalen>. Format the result array
|
|
|
* to <result_return>.
|
|
|
*/
|
|
|
void js_builtin_RegExp_match (JSVirtualMachine *vm, char *data,
|
|
|
unsigned int datalen, JSNode *regexp,
|
|
|
JSNode *result_return);
|
|
|
|
|
|
/*
|
|
|
* Do regexp search against <data, datalen>. Return the start index of
|
|
|
* the match in <result_return>.
|
|
|
*/
|
|
|
void js_builtin_RegExp_search (JSVirtualMachine *vm, char *data,
|
|
|
unsigned int datalen, JSNode *regexp,
|
|
|
JSNode *result_return);
|
|
|
|
|
|
/*
|
|
|
* Split the string <data, datalen> by regular expression <regexp>.
|
|
|
* Function returns an array containing the substrings.
|
|
|
*/
|
|
|
void js_builtin_RegExp_split (JSVirtualMachine *vm, char *data,
|
|
|
unsigned int datalen, JSNode *regexp,
|
|
|
unsigned int limit, JSNode *result_return);
|
|
|
|
|
|
/* Object. */
|
|
|
|
|
|
JSObject *js_vm_object_new (JSVirtualMachine *vm);
|
|
|
|
|
|
void js_vm_object_mark (JSObject *obj);
|
|
|
|
|
|
int js_vm_object_load_property (JSVirtualMachine *vm, JSObject *obj,
|
|
|
JSSymbol prop, JSNode *value_return);
|
|
|
|
|
|
void js_vm_object_store_property (JSVirtualMachine *vm, JSObject *obj,
|
|
|
JSSymbol prop, JSNode *value);
|
|
|
|
|
|
void js_vm_object_delete_property (JSVirtualMachine *vm, JSObject *obj,
|
|
|
JSSymbol prop);
|
|
|
|
|
|
void js_vm_object_load_array (JSVirtualMachine *vm, JSObject *obj, JSNode *sel,
|
|
|
JSNode *value_return);
|
|
|
|
|
|
void js_vm_object_store_array (JSVirtualMachine *vm, JSObject *obj,
|
|
|
JSNode *sel, JSNode *value);
|
|
|
|
|
|
void js_vm_object_delete_array (JSVirtualMachine *vm, JSObject *obj,
|
|
|
JSNode *sel);
|
|
|
|
|
|
int js_vm_object_nth (JSVirtualMachine *vm, JSObject *obj, int nth,
|
|
|
JSNode *value_return);
|
|
|
|
|
|
|
|
|
/* Debug. */
|
|
|
|
|
|
void js_vm_stacktrace (JSVirtualMachine *vm, unsigned int num_frames);
|
|
|
|
|
|
|
|
|
/* Strings. */
|
|
|
|
|
|
static inline void
|
|
|
js_vm_make_string (JSVirtualMachine *vm, JSNode *n, const char *data,
|
|
|
unsigned int data_len)
|
|
|
{
|
|
|
n->type = JS_STRING;
|
|
|
n->u.vstring = (JSString *) js_vm_alloc (vm, sizeof (*n->u.vstring));
|
|
|
n->u.vstring->staticp = 0;
|
|
|
n->u.vstring->prototype = NULL;
|
|
|
n->u.vstring->len = data_len;
|
|
|
n->u.vstring->data = (unsigned char *) js_vm_alloc (vm, data_len);
|
|
|
if (data)
|
|
|
memcpy (n->u.vstring->data, data, data_len);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
js_vm_make_static_string (JSVirtualMachine *vm, JSNode *n, const char *data,
|
|
|
unsigned int data_len)
|
|
|
{
|
|
|
n->type = JS_STRING;
|
|
|
n->u.vstring = (JSString *) js_vm_alloc (vm, sizeof (*n->u.vstring));
|
|
|
n->u.vstring->staticp = 1;
|
|
|
n->u.vstring->prototype = NULL;
|
|
|
n->u.vstring->len = data_len;
|
|
|
n->u.vstring->data = (unsigned char *) data;
|
|
|
}
|
|
|
|
|
|
|
|
|
static inline int
|
|
|
js_compare_strings (JSNode *a, JSNode *b)
|
|
|
{
|
|
|
unsigned int i;
|
|
|
|
|
|
for (i = 0; i < a->u.vstring->len && i < b->u.vstring->len; i++)
|
|
|
{
|
|
|
if (a->u.vstring->data[i] < b->u.vstring->data[i])
|
|
|
return -1;
|
|
|
if (a->u.vstring->data[i] > b->u.vstring->data[i])
|
|
|
return 1;
|
|
|
}
|
|
|
if (a->u.vstring->len < b->u.vstring->len)
|
|
|
return -1;
|
|
|
if (a->u.vstring->len > b->u.vstring->len)
|
|
|
return 1;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
static inline char *
|
|
|
js_string_to_c_string (JSVirtualMachine *vm, const JSNode *a)
|
|
|
{
|
|
|
char *cp;
|
|
|
|
|
|
cp = (char *) js_malloc (vm, a->u.vstring->len + 1);
|
|
|
memcpy (cp, a->u.vstring->data, a->u.vstring->len);
|
|
|
cp[a->u.vstring->len] = '\0';
|
|
|
|
|
|
return cp;
|
|
|
}
|
|
|
|
|
|
|
|
|
/* Dynamic loading. */
|
|
|
|
|
|
/*
|
|
|
* Try to open shared library <filename>. If the opening was
|
|
|
* successful, a handle to the library is returned. Otherwise, the
|
|
|
* function returns NULL, and an error message is returned in
|
|
|
* <error_return>. The argument <error_return_len> specifies the
|
|
|
* maximum length of the error message the function should return.
|
|
|
*/
|
|
|
void *js_dl_open (const char *filename, char *error_return,
|
|
|
unsigned int error_return_len);
|
|
|
|
|
|
/*
|
|
|
* Try to fetch the address of the symbol <symbol> from shared library
|
|
|
* <library>.
|
|
|
*/
|
|
|
void *js_dl_sym (void *library, char *symbol, char *error_return,
|
|
|
unsigned int error_return_len);
|
|
|
|
|
|
|
|
|
/* Misc helper functions. */
|
|
|
|
|
|
unsigned long js_crc32 (const unsigned char *s, unsigned int len);
|
|
|
|
|
|
|
|
|
/*
|
|
|
* Definitions for the JavaScript part of the JavaScript interp.
|
|
|
*/
|
|
|
|
|
|
/* Flags for the compiler. See `jsc/entry.js'. */
|
|
|
|
|
|
#define JSC_FLAG_VERBOSE 0x00000001
|
|
|
#define JSC_FLAG_ANNOTATE_ASSEMBLER 0x00000002
|
|
|
#define JSC_FLAG_GENERATE_DEBUG_INFO 0x00000004
|
|
|
#define JSC_FLAG_GENERATE_EXECUTABLE_BC_FILES 0x00000008
|
|
|
|
|
|
#define JSC_FLAG_OPTIMIZE_PEEPHOLE 0x00000020
|
|
|
#define JSC_FLAG_OPTIMIZE_JUMPS 0x00000040
|
|
|
#define JSC_FLAG_OPTIMIZE_BC_SIZE 0x00000080
|
|
|
#define JSC_FLAG_OPTIMIZE_HEAVY 0x00000100
|
|
|
|
|
|
#define JSC_FLAG_OPTIMIZE_MASK 0x0000fff0
|
|
|
|
|
|
#define JSC_FLAG_WARN_UNUSED_ARGUMENT 0x00010000
|
|
|
#define JSC_FLAG_WARN_UNUSED_VARIABLE 0x00020000
|
|
|
#define JSC_FLAG_WARN_SHADOW 0x00040000
|
|
|
#define JSC_FLAG_WARN_WITH_CLOBBER 0x00080000
|
|
|
#define JSC_FLAG_WARN_MISSING_SEMICOLON 0x00100000
|
|
|
#define JSC_FLAG_WARN_STRICT_ECMA 0x00200000
|
|
|
#define JSC_FLAG_WARN_DEPRECATED 0x00400000
|
|
|
|
|
|
#define JSC_FLAG_WARN_MASK 0xffff0000
|
|
|
|
|
|
/* JavaScript interpreter handle. */
|
|
|
struct js_interp_st
|
|
|
{
|
|
|
JSInterpOptions options;
|
|
|
JSVirtualMachine *vm;
|
|
|
};
|
|
|
|
|
|
/* Declaration for the JS compiler byte-code. */
|
|
|
extern const unsigned char js_compiler_bytecode[];
|
|
|
extern unsigned int js_compiler_bytecode_len;
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
#endif /* not JSINT_H */
|
|
|
|