/*
 * The builtin VM object.
 * 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: /home/cvs/entity/libentitynjs/b_vm.c,v $
 * $Id: b_vm.c,v 1.4 2000/07/25 05:25:58 imain Exp $
 */

/*
 * Class:
 *
 * - static methods:
 *
 *   VM.garbageCollect ()
 *   VM.stackTrace ()
 *
 * - properties:		type		mutable
 *
 *   VM.dispatchMethod		string
 *   VM.fdCount                 integer
 *   VM.gcCount			integer
 *   VM.gcTrigger		integer		yes
 *   VM.heapAllocated		integer
 *   VM.heapFree		integer
 *   VM.heapSize		integer
 *   VM.numConstants		integer
 *   VM.numGlobals		integer
 *   VM.stackSize		integer
 *   VM.stacktraceOnError	boolean		yes
 *   VM.verbose			integer 	yes
 *   VM.verboseStacktrace	boolean		yes
 *   VM.version			string
 *   VM.versionMajor		integer
 *   VM.versionMinor		integer
 *   VM.versionPatch		integer
 *   VM.warnUndef		boolean		yes
 */

#include "njs/internal.h"

/*
 * Types and definitions.
 */

struct vm_ctx_st
{
  JSSymbol s_garbageCollect;
  JSSymbol s_stackTrace;

  JSSymbol s_dispatchMethod;
  JSSymbol s_fdCount;
  JSSymbol s_gcCount;
  JSSymbol s_gcTrigger;
  JSSymbol s_heapAllocated;
  JSSymbol s_heapFree;
  JSSymbol s_heapSize;
  JSSymbol s_numConstants;
  JSSymbol s_numGlobals;
  JSSymbol s_stackSize;
  JSSymbol s_stacktraceOnError;
  JSSymbol s_verbose;
  JSSymbol s_verboseStacktrace;
  JSSymbol s_version;
  JSSymbol s_versionMajor;
  JSSymbol s_versionMinor;
  JSSymbol s_versionPatch;
  JSSymbol s_warnUndef;
};

typedef struct vm_ctx_st VMCtx;


/*
 * Static functions.
 */

/* Method proc */
static int
method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
	void *instance_context, JSSymbol method, JSNode *result_return,
	JSNode *args)
{
  VMCtx *ctx = builtin_info->obj_context;

  /* The default return value is undefined. */
  result_return->type = JS_UNDEFINED;

  if (method == ctx->s_garbageCollect)
    {
      if (args->u.vinteger != 0)
	goto argument_error;

      /* Ok, let's trigger a garbage collection. */
      vm->gc.bytes_allocated = vm->gc.trigger + 1;
    }
  /* ********************************************************************** */
  else if (method == ctx->s_stackTrace)
    {
      unsigned int limit;

      if (args->u.vinteger == 0)
	limit = -1;
      else if (args->u.vinteger == 1)
	{
	  if (args[1].type != JS_INTEGER)
	    goto argument_type_error;

	  limit = args[1].u.vinteger;
	}
      else
	goto argument_error;

      js_vm_stacktrace (vm, limit);
    }
  /* ********************************************************************** */
  else if (method == vm->syms.s_toString)
    {
      if (args->u.vinteger != 0)
	goto argument_error;

      js_vm_make_static_string (vm, result_return, "VM", 2);
    }
  /* ********************************************************************** */
  else
    return JS_PROPERTY_UNKNOWN;

  return JS_PROPERTY_FOUND;


  /*
   * Error handling.
   */

 argument_error:
  js_vm_set_err (vm, "VM.%s(): illegal amout of arguments",
	   js_vm_symname (vm, method));
  js_vm_error (vm);

 argument_type_error:
  js_vm_set_err (vm, "VM.%s(): illegal argument",
	   js_vm_symname (vm, method));
  js_vm_error (vm);

  /* NOTREACHED */
  return 0;
}

/* Property proc. */
static int
property (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
	  void *instance_context, JSSymbol property, int set, JSNode *node)
{
  VMCtx *ctx = builtin_info->obj_context;

  if (property == ctx->s_dispatchMethod)
    {
      if (set)
	goto immutable;

      js_vm_make_static_string (vm, node,
				vm->dispatch_method_name,
				strlen (vm->dispatch_method_name));
    }
  /* ***************************************************************** */
  else if (property == ctx->s_fdCount)
    {
      if (set)&2
	    build_libtool_libs=no
	    build_old_libs=yes
	  fi
	else
	  # Don't allow undefined symbols.
	  allow_undefined_flag="$no_undefined_flag"
	fi

	dependency_libs="$deplibs"
	case "$host" in
	*-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*)
	  # these systems don't actually have a c library (as such)!
	  ;;
	*-*-freebsd*)
	  # FreeBSD doesn't need this...
	  ;;
	*)
	  # Add libc to deplibs on all other systems.
	  deplibs="$deplibs -lc"
	  ;;
	esac
      fi

      if test -n "$rpath$xrpath"; then
	# If the user specified any rpath flags, then add them.
	for libdir in $rpath $xrpath; do
	  # This is the magic to use -rpath.
	  case "$compile_rpath " in
	  *" $libdir "*) ;;
	  *) compile_rpath="$compile_rpath $libdir" ;;
	  esac
	  case "$finalize_rpath " in
	  *" $libdir "*) ;;
	  *) finalize_rpath="$finalize_rpath $libdir" ;;
	  esac
	done
      fi

      # Now hardcode the library paths
      rpath=
      hardcode_libdirs=
      for libdir in $compile_rpath; do
	if test -n "$hardcode_libdir_flag_spec"; then
	  if test -n "$hardcode_libdir_separator"; then
	    if test -z "$hardcode_libdirs"; then
	      hardcode_libdirs="$libdir"
	    else
	      # Just accumulate the unique libdirs.
	      case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in
	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
		;;
	      *)
		hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
		;;
	      esac
	    fi
	  else
	    eval flag=\"$hardcode_libdir_flag_spec\"
	    rpath="$rpath $flag"
	  fi
	elif test -n "$runpath_var"; then
	  case "$perm_rpath " in
	  *" $libdir "*) ;;
	  *) perm_rpath="$perm_rpath $libdir" ;;
	  esac
	fi
      done
      # Substitute the hardcoded libdirs into the rpath.
      if test -n "$hardcode_libdir_separator" &&
	 test -n "$hardcode_libdirs"; then
	libdir="$hardcode_libdirs"
	eval rpath=\" $hardcode_libdir_flag_spec\"
      fi
      compile_rpath="$rpath"

      rpath=
      hardcode_libdirs=
      for libdir in $finalize_rpath; do
	if test -n "$hardcode_libdir_flag_spec"; then
	  if test -n "$hardcode_libdir_separator"; then
	    if test -z "$hardcode_libdirs"; then
	      hardcode_libdirs="$libdir"
	    else
	      # Just accumulate the unique libdirs.
	      case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in
	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
		;;
	      *)
		hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
		;;
	      esac
	    fi
	  else
	    eval flag=\"$hardcode_libdir_flag_spec\"
	    rpath="$rpath $flag"
	  fi
	elif test -n "$runpath_var"; then
	  case "$finalize_perm_rpath " in
	  *" $libdir "*) ;;
	  *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
	  esac
	fi
      done
      # Substitute the hardcoded libdirs into the rpath.
      if test -n "$hardcode_libdir_separator" &&
	 test -n "$hardcode_libdirs"; then
	libdir="$hardcode_libdirs"
	eval rpath=\" $hardcode_libdir_flag_spec\"
      fi
      finalize_rpath="$rpath"

      # Create the output directory, or remove our outputs if we need to.
      if test -d $output_objdir; then
	$show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*"
	$run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*
      else
	$show "$mkdir $output_objdir"
	$run $mkdir $output_objdir
	status=$?
	if test $status -ne 0 && test ! -d $output_objdir; then
	  exit $status
	fi
      fi

      # Now set the variable> vm->gc.trigger;
	}
    }
  /* ***************************************************************** */
  else if (property == ctx->s_heapAllocated)
    {
      if (set)
	goto immutable;

      node->type = JS_INTEGER;
      node->u.vinteger = vm->gc.bytes_allocated;
    }
  /* ***************************************************************** */
  else if (property == ctx->s_heapFree)
    {
      if (set)
	goto immutable;

      node->type = JS_INTEGER;
      node->u.vinteger = vm->gc.bytes_free;
    }
  /* ***************************************************************** */
  else if (property == ctx->s_heapSize)
    {
      if (set)
	goto immutable;

      node->type = JS_INTEGER;
      node->u.vinteger = vm->heap_size;
    }
  /* ***************************************************************** */
  else if (property == ctx->s_numConstants)
    {
      if (set)
	goto immutable;

      node->type = JS_INTEGER;
      node->u.vinteger = vm->num_consts;
    }
  /* ***************************************************************** */
  else if (property == ctx->s_numGlobals)
    {
      if (set)
	goto immutable;

      node->type = JS_INTEGER;
      node->u.vinteger = vm->num_globals;
    }
  /* ***************************************************************** */
  else if (property == ctx->s_stackSize)
    {
      if (set)
	goto immutable;

      node->type = JS_INTEGER;
      node->u.vinteger = vm->stack_size;
    }
  /* ***************************************************************** */
  else if (property == ctx->s_stacktraceOnError)
    {
      if (set)
	{
	  if (node->type != JS_BOOLEAN)
	    goto value_error;
	  vm->stacktrace_on_error = node->u.vboolean;
	}
      else
	{
	  node->type = JS_BOOLEAN;
	  node->u.vboolean = vm->stacktrace_on_error;
	}
    }
  /* ***************************************************************** */
  else if (property == ctx->s_verbose)
    {
      if (set)
	{
	  if (node->type != JS_INTEGER)
	    goto value_error;
	  vm->verbose = node->u.vinteger;
	}
      else
	{
	  node->type = JS_INTEGER;
	  node->u.vinteger = vm->verbose;
	}
    }
  /* ***************************************************************** */
  else if (property == ctx->s_verboseStacktrace)
    {
      if (set)
	{
	  if (node->type != JS_BOOLEAN)
	    goto value_error;
	  vm->verbose_stacktrace = node->u.vboolean;
	}
      else
	{
	  node->type = JS_BOOLEAN;
	  node->u.vboolean = vm->verbose_stacktrace;
	}
    }
  /* ***************************************************************** */
  else if (property == ctx->s_version)
    {
      if (set)
	goto immutable;

      js_vm_make_static_string (vm, node, VERSION, strlen (VERSION));
    }
  /* ***************************************************************** */
  else if (property == ctx->s_versionMajor)
    {
      if (set)
	goto immutable;

      node->type = JS_INTEGER;
      node->u.vinteger = atoi (VERSION);
    }
  /* ***************************************************************** */
  else if (property == ctx->s_versionMinor)
    {
      if (set)
	goto immutable;

      node->type = JS_INTEGER;
      node->u.vinteger = atoi (VERSION + 2);
    }
  /* ***************************************************************** */
  else if (property == ctx->s_versionPatch)
    {
      if (set)
	goto immutable;

      node->type = JS_INTEGER;
      node->u.vinteger = atoi (VERSION + 4);
    }
  /* ***************************************************************** */
  else if (property == ctx->s_warnUndef)
    {
      if (set)
	{
	  if (node->type != JS_INTEGER)
	    goto value_error;
	  vm->warn_undef = node->u.vinteger != 0;
	}
      else
	{
	  node->type = JS_INTEGER;
	  node->u.vinteger = vm->warn_undef;
	}
    }
  /* ***************************************************************** */
  else
    {
      if (!set)
	node->type = JS_UNDEFINED;

      return JS_PROPERTY_UNKNOWN;
    }

  return JS_PROPERTY_FOUND;


  /*
   * Error handling.
   */

 value_error:
  js_vm_set_err (vm, "VM.%s: illegal value",
	   js_vm_symname (vm, property));
  js_vm_error (vm);

 immutable:
  js_vm_set_err (vm, "VM.%s: immutable property",
	   js_vm_symname (vm, property));
  js_vm_error (vm);

  /* NOTREACHED. */
  return 0;
}


/*
 * Global functions.
 */

void
js_builtin_VM (JSVirtualMachine *vm)
{
  JSNode *n;
  JSBuiltinInfo *info;
  VMCtx *ctx;

  ctx = js_calloc (vm, 1, sizeof (*ctx));

  ctx->s_garbageCollect		= js_vm_intern (vm, "garbageCollect");
  ctx->s_stackTrace		= js_vm_intern (vm, "stackTrace");

  ctx->s_dispatchMethod		= js_vm_intern (vm, "dispatchMethod");
  ctx->s_fdCount		= js_vm_intern (vm, "fdCount");
  ctx->s_gcCount		= js_vm_intern (vm, "gcCount");
  ctx->s_gcTrigger		= js_vm_intern (vm, "gcTrigger");
  ctx->s_heapAllocated		= js_vm_intern (vm, "heapAllocated");
  ctx->s_heapFree		= js_vm_intern (vm, "heapFree");
  ctx->s_heapSize		= js_vm_intern (vm, "heapSize");
  ctx->s_numConstants		= js_vm_intern (vm, "numConstants");
  ctx->s_numGlobals		= js_vm_intern (vm, "numGlobals");
  ctx->s_stackSize		= js_vm_intern (vm, "stackSize");
  ctx->s_stacktraceOnError	= js_vm_intern (vm, "stacktraceOnError");
  ctx->s_verbose		= js_vm_intern (vm, "verbose");
  ctx->s_verboseStacktrace	= js_vm_intern (vm, "verboseStacktrace");
  ctx->s_version		= js_vm_intern (vm, "version");
  ctx->s_versionMajor		= js_vm_intern (vm, "versionMajor");
  ctx->s_versionMinor		= js_vm_intern (vm, "versionMinor");
  ctx->s_versionPatch		= js_vm_intern (vm, "versionPatch");
  ctx->s_warnUndef		= js_vm_intern (vm, "warnUndef");

  /* Object information. */

  info = js_vm_builtin_info_create (vm);

  info->method_proc 		= method;
  info->property_proc 		= property;
  info->obj_context 		= ctx;
  info->obj_context_delete	= js_free;

  /* Define it. */
  n = &vm->globals[js_vm_intern (vm, "VM")];
  js_vm_builtin_create (vm, n, info, NULL);
}




syntax highlighted by Code2HTML, v. 0.9.1