⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vm.c

📁 一个类似windows
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * Common parts for the JavaScript virtual machine.
 * Copyright (c) 1998 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/ksrc/vm.c,v $
 * $Id: vm.c 21681 2006-04-21 15:00:24Z peterw $
 */

#include "jsint.h"
#include "kjs.h"

/*
 * Types and definitions.
 */

/*
 * Collect garbage if we allocated more than GC_TRIGGER bytes of
 * memory since the last gc.
 */
#if SIZEOF_INT == 2
#define GC_TRIGGER (1L * 1024L * 1024L)
#else
#define GC_TRIGGER (2 * 1024 * 1024)
#endif

/*
 * Prototypes for static functions.
 */

static void intern_builtins (PKJS kjs);


/*
 * Global functions.
 */

JSVirtualMachine *
js_vm_create (PKJS kjs,
	      unsigned int stack_size, 
	      JSVMDispatchMethod dispatch_method,
	      unsigned int verbose, 
	      int stacktrace_on_error,
	      JSIOStream *s_stdin, 
	      JSIOStream *s_stdout, 
	      JSIOStream *s_stderr)
{
  JSVirtualMachine *vm;

  kjs->vm = vm = js_calloc (NULL, 1, sizeof (*vm));
  if (vm == NULL)
    return NULL;

  vm->verbose = verbose;
  vm->stacktrace_on_error = stacktrace_on_error;
  vm->warn_undef = 1;

  /* Set the system streams. */
  vm->s_stdin = s_stdin;
  vm->s_stdout = s_stdout;
  vm->s_stderr = s_stderr;

  /* Resolve the dispatch method. */
  switch (dispatch_method)
    {
    case JS_VM_DISPATCH_SWITCH_BASIC:
#if ALL_DISPATCHERS
      vm->dispatch_method 		= dispatch_method;
      vm->dispatch_method_name		= "switch-basic";
      vm->dispatch_execute 		= js_vm_switch0_exec;
      vm->dispatch_func_name		= js_vm_switch0_func_name;
      vm->dispatch_debug_position 	= js_vm_switch0_debug_position;
#endif
      break;

    case JS_VM_DISPATCH_JUMPS:
#if __GNUC__ && !DISABLE_JUMPS
      vm->dispatch_method		= dispatch_method;
      vm->dispatch_method_name		= "jumps";
      vm->dispatch_execute		= js_vm_jumps_exec;
      vm->dispatch_func_name		= js_vm_jumps_func_name;
      vm->dispatch_debug_position	= js_vm_jumps_debug_position;
#endif /* not (__GNUC__ && !DISABLE_JUMPS) */
      break;

    case JS_VM_DISPATCH_SWITCH:
      /* This is the default, let the default catcher handle us. */
      break;
    }

  if (vm->dispatch_execute == NULL)
    {
      /* Set the default that is the optimized switch. */
      vm->dispatch_method		= JS_VM_DISPATCH_SWITCH;
      vm->dispatch_method_name		= "switch";
      vm->dispatch_execute		= js_vm_switch_exec;
      vm->dispatch_func_name		= js_vm_switch_func_name;
      vm->dispatch_debug_position	= js_vm_switch_debug_position;
    }

  vm->stack_size = stack_size;
  vm->stack = js_malloc (NULL, vm->stack_size * sizeof (*vm->stack));
  if (vm->stack == NULL)
    {
      js_free (vm);
      return NULL;
    }

  /* Set the initial stack pointer. */
  vm->sp = vm->stack + vm->stack_size - 1;

  vm->gc.trigger = GC_TRIGGER;

  /* We need a toplevel here. */
  {
    JSErrorHandlerFrame handler;
    int result = 1;

    memset (&handler, 0, sizeof (handler));
    handler.next = vm->error_handler;
    vm->error_handler = &handler;

    if (setjmp (vm->error_handler->error_jmp))
      /* An error occurred. */
      result = 0;
    else
      {
	/* Intern some commonly used symbols. */
	vm->syms.s___proto__	= js_vm_intern (vm, "__proto__");
	vm->syms.s_prototype	= js_vm_intern (vm, "prototype");
	vm->syms.s_toSource	= js_vm_intern (vm, "toSource");
	vm->syms.s_toString	= js_vm_intern (vm, "toString");
	vm->syms.s_valueOf	= js_vm_intern (vm, "valueOf");

	/* Intern system built-in objects. */
	intern_builtins (kjs);
      }

    /* Pop the error handler. */
    vm->error_handler = vm->error_handler->next;

    if (result == 0)
      {
	/* Argh, the initialization failed. */
	js_vm_destroy (vm);
	return NULL;
      }
  }

  return vm;
}


void
js_vm_destroy (JSVirtualMachine *vm)
{
  int i;
  JSHeapBlock *hb, *hb2;
  JSErrorHandlerFrame *f, *f2;
  JSHashBucket *hashb, *hashb_next;

  /* Free all objects from the heap. */
  js_vm_clear_heap (vm);

  /* Free the constants. */

  for (i = 0; i < vm->num_consts; i++)
    if (vm->consts[i].type == JS_STRING)
      js_free (vm->consts[i].u.vstring->data);
  js_free (vm->consts);

  /* Free the globals. */

  for (i = 0; i < JS_HASH_TABLE_SIZE; i++)
    for (hashb = vm->globals_hash[i]; hashb; hashb = hashb_next)
      {
	hashb_next = hashb->next;
	js_free (hashb->name);
	js_free (hashb);
      }
  js_free (vm->globals);

  /* Stack. */
  js_free (vm->stack);

  /* Heap blocks. */
  for (hb = vm->heap; hb; hb = hb2)
    {
      hb2 = hb->next;
      js_free (hb);
    }

  /* Error handlers. */
  for (f = vm->error_handler; f; f = f2)
    {
      f2 = f->next;
      js_free (f);
    }

#if PROFILING
#define NUM_OPS 68

  /* Dump profiling data to the stderr. */
  {
    unsigned int total = 0;
    int i;

    /* Count total interrupts. */
    for (i = 0; i <= NUM_OPS; i++)
      total += vm->prof_count[i];

    /* Dump individual statistics. */
    for (i = 0; i <= NUM_OPS; i++)
      {
	char buf[512];

	sprintf (buf, "%d\t%u\t%.2f%s",
		 i, vm->prof_count[i],
		 (double) vm->prof_count[i] / total * 100,
		 JS_HOST_LINE_BREAK);

	js_iostream_write (vm->s_stderr);
      }
  }
#endif /* PROFILING */

  /* Flush and free the default system streams. */

  js_iostream_close (vm->s_stdin);
  js_iostream_close (vm->s_stdout);
  js_iostream_close (vm->s_stderr);

  /* And finally, the VM handle. */
  js_free (vm);
}

#if PROFILING
/*
 * The support stuffs for the byte-code operand profiling.
 */

static JSVirtualMachine *profiling_vm = NULL;

static void
sig_alarm (int sig)
{
  if (profiling_vm && profiling_vm->prof_op < 100)
    profiling_vm->prof_count[profiling_vm->prof_op]++;

  signal (sig, sig_alarm);
}

/* Turn on the byte-code operand profiling. */
#define PROFILING_ON()			\
      profiling_vm = vm;		\
      vm->prof_op = 255;		\
      signal (SIGALRM, sig_alarm);	\
      ualarm (1, 1)

/* Turn off the byte-code operand profiling. */
#define PROFILING_OFF()			\
      vm->prof_op = 255;		\
      ualarm (0, 0);			\
      signal (SIGALRM, SIG_IGN);	\
      profiling_vm = NULL

#else /* not PROFILING */

#define PROFILING_ON()
#define PROFILING_OFF()

#endif /* not PROFILING */

int
js_vm_execute (JSVirtualMachine *vm, JSByteCode *bc)
{
  int i, sect;
  unsigned int ui;
  char *cp;
  unsigned int consts_offset;
  char buf[256];
  JSSymtabEntry *symtab = NULL;
  unsigned int num_symtab_entries = 0;
  unsigned int code_len = 0;
  JSNode *saved_sp;
  JSErrorHandlerFrame *handler, *saved_handler;
  int result = 1;
  unsigned char *debug_info;
  unsigned int debug_info_len;
  unsigned int anonymous_function_offset;

  /* We need a toplevel over the whole function. */

  saved_sp = vm->sp;
  saved_handler = vm->error_handler;

  handler = js_calloc (NULL, 1, sizeof (*handler));
  if (handler == NULL)
    {
      sprintf (vm->error, "VM: out of memory");
      return 0;
    }
  handler->next = vm->error_handler;
  vm->error_handler = handler;

  if (setjmp (vm->error_handler->error_jmp))
    {
      /* Ok, we had an error down there somewhere. */
      result = 0;
    }
  else
    {
      /* The main stuffs for the execute. */

      /* Process constants. */
      consts_offset = vm->num_consts;
      anonymous_function_offset = vm->anonymous_function_next_id;

      for (sect = 0; sect < bc->num_sects; sect++)
	if (bc->sects[sect].type == JS_BCST_CONSTANTS)
	  {
	    cp = bc->sects[sect].data;

	    for (ui = 0; ui < bc->sects[sect].length;)
	      {
		JSNode *c;

		/* Check that we still have space for this constant. */
		if (vm->num_consts >= vm->consts_alloc)
		  {
		    vm->consts = js_realloc (vm, vm->consts,
					     (vm->consts_alloc + 1024)
					     * sizeof (JSNode));
		    vm->consts_alloc += 1024;
		  }
		c = &vm->consts[vm->num_consts++];

		/*  Process this constant. */
		c->type = (JSNodeType) cp[ui++];
		switch (c->type)
		  {
		  case JS_NULL:
		    break;

		  case JS_BOOLEAN:
		    c->u.vboolean = cp[ui++];
		    break;

		  case JS_STRING:
		    c->u.vstring = js_vm_alloc (vm, sizeof (*c->u.vstring));
		    c->u.vstring->staticp = 1;
		    c->u.vstring->prototype = NULL;

		    JS_BC_READ_INT32 (cp + ui, c->u.vstring->len);
		    ui += 4;

		    c->u.vstring->data = js_malloc (vm, c->u.vstring->len + 1);
		    memcpy (c->u.vstring->data, cp + ui, c->u.vstring->len);
		    c->u.vstring->data[c->u.vstring->len] = '\0';

		    ui += c->u.vstring->len;
		    break;

		  case JS_INTEGER:
		    JS_BC_READ_INT32 (cp + ui, c->u.vinteger);
		    ui += 4;
		    break;

		  case JS_FLOAT:
		    memcpy (&c->u.vfloat, cp + ui, 8);
		    ui += 8;
		    break;

		  case JS_SYMBOL:
		    for (i = 0; cp[ui]; ui++, i++)
		      buf[i] = cp[ui];
		    buf[i] = '\0';

		    /* Eat the trailing '\0' from the data. */
		    ui++;

		    if (buf[0] == '.' && buf[1] == 'F' && buf[2] == ':')
		      sprintf (buf + 3, "%u",
			       vm->anonymous_function_next_id++);

		    /* Intern symbol. */
		    c->u.vsymbol = js_vm_intern (vm, buf);
		    break;

		  case JS_BUILTIN:
		    /* Regular expression. */
		    {
		      unsigned char flags;
		      unsigned int length;

		      flags = cp[ui++];

		      JS_BC_READ_INT32 (cp + ui, length);
		      ui += 4;

		      js_builtin_RegExp_new (vm, cp + ui, length, flags, 1,
					     NULL, c);
		      ui += length;
		    }
		    break;

		  case JS_NAN:
		    /* Nothing here. */
		    break;

		  default:
		  case JS_IPTR:
		    sprintf (buf,
			     "js_vm_execute(): unknown constant type %d%s",
			     c->type,
			     JS_HOST_LINE_BREAK);

		    js_iostream_write (vm->s_stderr, buf, strlen (buf));
		    js_iostream_flush (vm->s_stderr);

		    abort ();
		    break;
		  }
	      }

	    /* All done with the constants. */
	    break;
	  }

      /* Check how long the code section is. */
      for (sect = 0; sect < bc->num_sects; sect++)
	if (bc->sects[sect].type == JS_BCST_CODE)
	  {
	    code_len = bc->sects[sect].length;
	    break;
	  }

      /* Process symbol table. */
      for (sect = 0; sect < bc->num_sects; sect++)
	if (bc->sects[sect].type == JS_BCST_SYMTAB)
	  {
	    JSSymtabEntry *se;
	    char buf[257];

	    cp = bc->sects[sect].data;

	    /* The number of symbols. */
	    JS_BC_READ_INT32 (cp, num_symtab_entries);

	    symtab = js_calloc (vm, num_symtab_entries + 1, sizeof (*symtab));

	    /* Make the terminator by hand. */
	    symtab[num_symtab_entries].offset = code_len;

	    /* Enter symbols. */
	    se = symtab;
	    for (ui = 4; ui < bc->sects[sect].length; se++)
	      {
		for (i = 0; cp[ui]; ui++, i++)
		  buf[i] = cp[ui];
		buf[i] = '\0';

		se->name = js_strdup (vm, buf);
		ui++;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -