📄 js.c
字号:
/*
* JavaScript interpreter main glue.
* 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: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/src/js.c,v $
* $Id: js.c 21681 2006-04-21 15:00:24Z peterw $
*/
#include "js.h"
#include "jsint.h"
/*
* Types and definitions.
*/
/* Context for js_global_method_stub. */
struct js_global_method_context_st
{
JSGlobalMethodProc proc;
void *context;
JSFreeProc free_proc;
JSInterpPtr interp;
};
typedef struct js_global_method_context_st JSGlobalMethodContext;
/* Context for user I/O function streams. */
struct js_user_io_func_ctx_st
{
JSIOFunc func;
void *context;
long position;
};
typedef struct js_user_io_func_ctx_st JSUserIOFuncCtx;
struct js_method_reg_st
{
JSSymbol sym;
char *name;
unsigned int flags;
JSMethodProc method;
};
typedef struct js_method_reg_st JSMethodReg;
struct js_property_reg_st
{
JSSymbol sym;
char *name;
unsigned int flags;
JSPropertyProc property;
};
typedef struct js_property_reg_st JSPropertyReg;
/* The class handle. */
struct js_class_st
{
char *name;
JSInterpPtr interp;
/* Flags. */
unsigned int no_auto_destroy : 1;
unsigned int interned : 1;
void *class_context;
JSFreeProc class_context_destructor;
JSConstructor constructor;
unsigned int num_methods;
JSMethodReg *methods;
unsigned int num_properties;
JSPropertyReg *properties;
};
/* Object instance context. */
struct js_object_instance_ctx_st
{
void *instance_context;
JSFreeProc instance_context_destructor;
};
typedef struct js_object_instance_ctx_st JSObjectInstanceCtx;
/*
* Prototypes for static functions.
*/
/* The module for JS' core global methods. */
static void js_core_globals (JSInterpPtr interp);
/*
* Helper function to evaluate source <source> with compiler function
* <compiler_function>.
*/
static int js_eval_source (JSInterpPtr interp, JSNode *source,
char *compiler_function);
/*
* Helper function to compile source <source> with compiler function
* <compiler_function>. If <assembler_file> is not NULL, the
* assembler listing of the compilation is saved to that file. If
* <byte_code_file> is not NULL, the byte_code data is saved to that
* file. If <bc_return> is not NULL, the resulting byte_code data is
* returned in it as a JavaScript string node.
*/
static int js_compile_source (JSInterpPtr interp, JSNode *source,
char *compiler_function, char *assembler_file,
char *byte_code_file, JSNode *bc_return);
/*
* The stub function for global methods, created with the
* js_create_global_method() API function.
*/
static void js_global_method_stub (JSVirtualMachine *vm,
JSBuiltinInfo *builtin_info,
void *instance_context,
JSNode *result_return,
JSNode *args);
/*
* Destructor for the global methods, created with the
* js_create_global_method() API function.
*/
static void js_global_method_delete (JSBuiltinInfo *builtin_info,
void *instance_context);
static JSIOStream *iostream_iofunc (JSIOFunc func, void *context,
int readp, int writep);
/*
* Global functions.
*/
const JSCharPtr
js_version ()
{
return VERSION;
}
void
js_init_default_options (JSInterpOptions *options)
{
memset (options, 0, sizeof (*options));
options->stack_size = 2048;
options->dispatch_method = JS_VM_DISPATCH_JUMPS;
options->warn_undef = 1;
options->optimize_peephole = 1;
options->optimize_jumps_to_jumps = 1;
options->fd_count = (unsigned long) -1;
}
JSInterpPtr
js_create_interp (JSInterpOptions *options)
{
JSInterpPtr interp = NULL;
JSByteCode *bc;
JSInterpOptions default_options;
JSIOStream *s_stdin = NULL;
JSIOStream *s_stdout = NULL;
JSIOStream *s_stderr = NULL;
/*
* Sanity check to assure that the js.h and jsint.h APIs share a
* same view to the world.
*/
assert (sizeof (JSNode) == sizeof (JSType));
interp = js_calloc (NULL, 1, sizeof (*interp));
if (interp == NULL)
return NULL;
if (options == NULL)
{
js_init_default_options (&default_options);
options = &default_options;
}
memcpy (&interp->options, options, sizeof (*options));
/* The default system streams. */
if (options->s_stdin)
s_stdin = iostream_iofunc (options->s_stdin, options->s_context, 1, 0);
else
s_stdin = js_iostream_file (stdin, 1, 0, 0);
if (s_stdin == NULL)
goto error_out;
if (options->s_stdout)
s_stdout = iostream_iofunc (options->s_stdout, options->s_context, 0, 1);
else
s_stdout = js_iostream_file (stdout, 0, 1, 0);
if (s_stdout == NULL)
goto error_out;
s_stdout->autoflush = 1;
if (options->s_stderr)
s_stderr = iostream_iofunc (options->s_stderr, options->s_context, 0, 1);
else
s_stderr = js_iostream_file (stderr, 0, 1, 0);
if (s_stderr == NULL)
goto error_out;
s_stderr->autoflush = 1;
/* Create virtual machine. */
interp->vm = js_vm_create (options->stack_size,
options->dispatch_method,
options->verbose,
options->stacktrace_on_error,
s_stdin, s_stdout, s_stderr);
if (interp->vm == NULL)
goto error_out;
/* Set some options. */
interp->vm->warn_undef = options->warn_undef;
/* Set the security options. */
if (options->secure_builtin_file)
interp->vm->security |= JS_VM_SECURE_FILE;
if (options->secure_builtin_system)
interp->vm->security |= JS_VM_SECURE_SYSTEM;
/* Set the event hook. */
interp->vm->hook = options->hook;
interp->vm->hook_context = options->hook_context;
interp->vm->hook_operand_count_trigger = options->hook_operand_count_trigger;
/* The file descriptor limit. */
interp->vm->fd_count = options->fd_count;
if (!options->no_compiler)
{
int result;
/* Define compiler to the virtual machine. */
bc = js_bc_read_data (js_compiler_bytecode, js_compiler_bytecode_len);
if (bc == NULL)
goto error_out;
result = js_vm_execute (interp->vm, bc);
js_bc_free (bc);
if (!result)
goto error_out;
}
/* Initialize our extensions. */
if (!js_define_module (interp, js_core_globals))
goto error_out;
/* Ok, we'r done. */
#if 0
#if JS_DEBUG_MEMORY_LEAKS
/* Let's see how much memory an empty interpreter takes. */
js_alloc_dump_blocks ();
#endif /* JS_DEBUG_MEMORY_LEAKS */
#endif
return interp;
/*
* Error handling.
*/
error_out:
if (interp)
{
if (interp->vm)
js_vm_destroy (interp->vm);
js_free (interp);
}
if (s_stdin)
js_iostream_close (s_stdin);
if (s_stdout)
js_iostream_close (s_stdout);
if (s_stderr)
js_iostream_close (s_stderr);
return NULL;
}
void
js_destroy_interp (JSInterpPtr interp)
{
js_vm_destroy (interp->vm);
js_free (interp);
#if 0
#if JS_DEBUG_MEMORY_LEAKS
/* Let's see how much memory we leak. */
js_alloc_dump_blocks ();
#endif /* JS_DEBUG_MEMORY_LEAKS */
#endif
}
const JSCharPtr
js_error_message (JSInterpPtr interp)
{
return interp->vm->error;
}
void
js_result (JSInterpPtr interp, JSType *result_return)
{
memcpy (result_return, &interp->vm->exec_result, sizeof (*result_return));
}
int
js_eval (JSInterpPtr interp, char *code)
{
JSNode source;
js_vm_make_static_string (interp->vm, &source, code, strlen (code));
return js_eval_source (interp, &source, "JSC$compile_string");
}
int
js_eval_data (JSInterpPtr interp, char *data, unsigned int datalen)
{
JSNode source;
js_vm_make_static_string (interp->vm, &source, data, datalen);
return js_eval_source (interp, &source, "JSC$compile_string");
}
int
js_eval_file (JSInterpPtr interp, char *filename)
{
char *cp;
int result;
cp = strrchr (filename, '.');
if (cp && strcmp (cp, ".jsc") == 0)
{
run_bytecode:
result = js_execute_byte_code_file (interp, filename);
}
else if (cp && strcmp (cp, ".js") == 0)
{
try_javascript:
result = js_eval_javascript_file (interp, filename);
}
else
{
FILE *fp;
/* Must look into the file. */
fp = fopen (filename, "r");
if (fp)
{
int ch;
if ((ch = getc (fp)) == '#')
{
/* Skip the first sh-command line. */
while ((ch = getc (fp)) != EOF && ch != '\n')
;
if (ch == EOF)
{
fclose (fp);
goto try_javascript;
}
}
else
ungetc (ch, fp);
/* Check if we can read the file magic. */
ch = getc (fp);
if (ch == 0xc0)
{
ch = getc (fp);
if (ch == 0x01)
{
ch = getc (fp);
if (ch == 'J')
{
ch = getc (fp);
if (ch == 'S')
{
/* Got it. We find a valid byte-code file magic. */
fclose (fp);
goto run_bytecode;
}
}
}
}
fclose (fp);
/* FALLTHROUGH */
}
/*
* If nothing else helps, we assume that the file contains JavaScript
* source code that must be compiled.
*/
goto try_javascript;
}
return result;
}
int
js_eval_javascript_file (JSInterpPtr interp, char *filename)
{
JSNode source;
js_vm_make_static_string (interp->vm, &source, filename, strlen (filename));
return js_eval_source (interp, &source, "JSC$compile_file");
}
int
js_execute_byte_code_file (JSInterpPtr interp, char *filename)
{
JSByteCode *bc;
FILE *fp;
int result;
fp = fopen (filename, "rb");
if (fp == NULL)
{
/* Let's borrow vm's error buffer. */
sprintf (interp->vm->error, "couldn't open byte-code file \"%s\": %s",
filename, strerror (errno));
return 0;
}
bc = js_bc_read_file (fp);
fclose (fp);
if (bc == NULL)
/* XXX Error message. */
return 0;
/* Execute it. */
result = js_vm_execute (interp->vm, bc);
js_bc_free (bc);
return result;
}
int
js_apply (JSInterpPtr interp, char *name, unsigned int argc, JSType *argv)
{
JSNode *args;
unsigned int ui;
int result;
args = js_malloc (NULL, (argc + 1) * sizeof (JSNode));
if (args == NULL)
{
sprintf (interp->vm->error, "VM: out of memory");
return 0;
}
/* Set the argument count. */
args[0].type = JS_INTEGER;
args[0].u.vinteger = argc;
/* Set the arguments. */
for (ui = 0; ui < argc; ui++)
JS_COPY (&args[ui + 1], (JSNode *) &argv[ui]);
/* Call it. */
result = js_vm_apply (interp->vm, name, NULL, argc + 1, args);
js_free (args);
return result;
}
int
js_compile (JSInterpPtr interp, char *input_file, char *assembler_file,
char *byte_code_file)
{
JSNode source;
js_vm_make_static_string (interp->vm, &source, input_file,
strlen (input_file));
return js_compile_source (interp, &source, "JSC$compile_file",
assembler_file, byte_code_file, NULL);
}
int
js_compile_to_byte_code (JSInterpPtr interp, char *input_file,
unsigned char **bc_return,
unsigned int *bc_len_return)
{
JSNode source;
int result;
js_vm_make_static_string (interp->vm, &source, input_file,
strlen (input_file));
result = js_compile_source (interp, &source, "JSC$compile_file",
NULL, NULL, &source);
if (result == 0)
return 0;
/* Pass the data to the caller. */
*bc_return = source.u.vstring->data;
*bc_len_return = source.u.vstring->len;
return result;
}
int
js_compile_data_to_byte_code (JSInterpPtr interp, char *data,
unsigned int datalen,
unsigned char **bc_return,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -