Ejemplo n.º 1
0
public class ErlPort {

  static EAtom am_spawn = EAtom.intern("spawn");
  static EAtom am_spawn_driver = EAtom.intern("spawn_driver");
  static EAtom am_spawn_executable = EAtom.intern("spawn_executable");

  @BIF
  static EPort open_port(EProc proc, EObject portName, EObject portSetting) {

    ETuple t;
    if ((t = portName.testTuple()) == null) throw ERT.badarg(portName, portSetting);

    ETuple2 name;
    if ((name = ETuple2.cast(t)) == null) throw ERT.badarg(portName, portSetting);

    if (name.elem1 == am_spawn) {
      throw new ErlangError(ERT.AM_NOT_IMPLEMENTED, portName, portSetting);

    } else if (name.elem1 == am_spawn_driver) {
      throw new NotImplemented();

    } else if (name.elem1 == am_spawn_executable) {
      ETask<? extends EPort> task = new EExecDriverTask(proc, name, portSetting);

      return task.self();
    }

    throw ERT.badarg(portName, portSetting);
  }
}
Ejemplo n.º 2
0
public class ErlProc {

  private static Logger log = Logger.getLogger("erjang.module.proc");

  private static final EAtom am_smp_support = EAtom.intern("smp_support");
  private static final EAtom am_process_limit = EAtom.intern("process_limit");
  private static final EAtom am_fullsweep_after = EAtom.intern("fullsweep_after");
  private static final EAtom am_schedulers = EAtom.intern("schedulers");
  private static final EAtom am_schedulers_online = EAtom.intern("schedulers_online");
  private static final EAtom am_break_ignored = EAtom.intern("break_ignored");
  private static final EAtom am_threads = EAtom.intern("threads");
  public static final EAtom am_process = EAtom.intern("process");
  private static final EAtom am_wordsize = EAtom.intern("wordsize");
  private static final EAtom am_thread_pool_size = EAtom.intern("thread_pool_size");
  private static final EAtom am_os_type = EAtom.intern("os_type");
  private static final EAtom am_win32 = EAtom.intern("win32");
  private static final EAtom am_unix = EAtom.intern("unix");
  private static final EAtom am_version = EAtom.intern("version");
  private static final EAtom am_undefined = EAtom.intern("undefined");
  private static final EAtom am_heap = EAtom.intern("heap");
  private static final EAtom am_non_heap = EAtom.intern("non_heap");
  private static final EAtom am_jvm = EAtom.intern("jvm");
  private static final EAtom am_allocated_areas = EAtom.intern("allocated_areas");
  private static final EAtom am_otp_release = EAtom.intern("otp_release");
  private static final EAtom am_driver_version = EAtom.intern("driver_version");
  private static final EAtom am_global_heaps_size = EAtom.intern("global_heaps_size");
  private static final EAtom am_process_count = EAtom.intern("process_count");
  private static final EAtom am_system_architecture = EAtom.intern("system_architecture");
  private static final EAtom am_logical_processors = EAtom.intern("logical_processors");
  private static final EAtom am_hipe_architecture = EAtom.intern("hipe_architecture");
  private static final EAtom am_machine = EAtom.intern("machine");
  private static final EAtom am_link = EAtom.intern("link");
  private static final EAtom am_monitor = EAtom.intern("monitor");
  private static final EAtom am_priority = EAtom.intern("priority");
  private static final EAtom am_system_version = EAtom.intern("system_version");
  public static final EAtom am_flush = EAtom.intern("flush");
  public static final EAtom am_shutdown = EAtom.intern("shutdown");
  private static final EAtom am_ets_alloc = EAtom.intern("ets_alloc");
  private static final EAtom am_error_checker = EAtom.intern("error_checker");
  private static final EAtom am_debug_compiled = EAtom.intern("debug_compiled");
  private static final EAtom am_lock_checking = EAtom.intern("lock_checking");
  private static final EAtom am_compat_rel = EAtom.intern("compat_rel");

  @BIF
  public static EObject process_info(EObject pid, EObject what) {
    EPID p = pid.testPID();
    if (p == null) throw ERT.badarg(pid, what);
    // TODO: validate WHAT locally before going remote?
    return p.process_info(what);
  }

  @BIF
  public static EObject process_info(EObject pid) {
    EPID p = pid.testPID();
    if (p == null) throw ERT.badarg(pid);
    return p.process_info();
  }

  @BIF
  public static EObject display(EProc proc, EObject obj) {
    ERT.getOutputStream().println(obj);
    return ERT.TRUE;
  }

  @BIF
  public static ESeq get_stacktrace(EProc proc) {
    ErlangException ex = proc.getLastException();
    return ex != null ? ex.getTrace() : ERT.NIL;
  }

  @BIF
  public static EObject erase(EProc proc, EObject key) {
    return proc.erase(key);
  }

  @BIF
  public static EObject erase(EProc proc) {
    return proc.erase();
  }

  @BIF
  public static EObject register(EObject name, EObject pid) {
    EAtom aname;
    EHandle handle = pid.testHandle();
    if ((aname = name.testAtom()) == null || handle == null) throw ERT.badarg(name, pid);
    ERT.register(aname, handle);
    return ERT.TRUE;
  }

  @BIF
  public static EObject unregister(EObject name) {
    EAtom aname;
    if ((aname = name.testAtom()) == null || !ERT.unregister(aname)) throw ERT.badarg(name);
    return ERT.TRUE;
  }

  @BIF
  public static EObject spawn_link(EProc proc, EObject mod, EObject fun, EObject args)
      throws Pausable {

    EAtom m = mod.testAtom();
    EAtom f = fun.testAtom();
    ESeq a = args.testSeq();

    if (m == null || f == null || a == null) throw ERT.badarg(mod, fun, args);

    EProc p2 = new EProc(proc.group_leader(), m, f, a);

    proc.link_to(p2);

    ERT.run(p2);

    return p2.self_handle();
  }

  @BIF
  public static EObject spawn_opt(EProc self, EObject tup) throws Pausable {
    ETuple t;
    EAtom m;
    EAtom f;
    ESeq a;
    ESeq o;
    if ((t = tup.testTuple()) == null
        || t.arity() != 4
        || (m = t.elm(1).testAtom()) == null
        || (f = t.elm(2).testAtom()) == null
        || (a = t.elm(3).testSeq()) == null
        || (o = t.elm(4).testSeq()) == null) throw ERT.badarg(tup);

    boolean link = false;
    boolean monitor = false;
    EAtom priority = null;

    for (; !o.isNil(); o = o.tail()) {
      EObject val = o.head();

      ETuple2 t2;
      if (val == am_link) {
        link = true;
      } else if (val == am_monitor) {
        monitor = true;
      } else if ((t2 = ETuple2.cast(val)) != null) {

        if (t2.elm(1) == am_priority) {
          EAtom am = t2.elm(2).testAtom();
          if (am != null) priority = am;
        }

        // ignore full_sweep_after and min_heap_size
      }
    }

    EProc p2 = new EProc(self.group_leader(), m, f, a);

    if (link) {
      self.link_to(p2);
    }

    if (priority != null) {
      // may throw badarg!
      p2.process_flag(am_priority, priority);
    }

    ERef ref = null;
    if (monitor) {
      ref = ERT.getLocalNode().createRef();

      if (!self.monitor(p2.self_handle(), p2.self_handle(), ref)) {
        throw new InternalError("cannot monitor new process?");
        // self.mbox_send(ETuple.make(ERT.am_DOWN, ref, p2.self_handle(), ERT.am_noproc));
      }
    }

    ERT.run(p2);

    if (monitor) {
      return new ETuple2(p2.self_handle(), ref);
    } else {
      return p2.self_handle();
    }
  }

  @BIF
  public static EObject spawn(EProc proc, EObject mod, EObject fun, EObject args) {

    EAtom m = mod.testAtom();
    EAtom f = fun.testAtom();
    ESeq a = args.testSeq();

    if (m == null || f == null || a == null) throw ERT.badarg(mod, fun, args);

    EProc p2 = new EProc(proc.group_leader(), m, f, a);

    ERT.run(p2);

    return p2.self_handle();
  }

  @BIF
  public static EObject halt(EProc proc) {
    return halt(proc, null);
  }

  @BIF
  public static EObject halt(EProc proc, EObject value) {
    int exitCode = 1;
    String message = null;
    if (value != null) {
      ESmall val = value.testSmall();
      if (val != null) {
        exitCode = val.value;
      }

      EString str = value.testString();
      if (str != null) {
        message = str.stringValue();
      }
    }

    /*
    // TODO: create crash file
    if (message != null) {
    	log.severe("halting system: " + message);
    }
    else {
    	log.info("halting system");
    }
    */
    ERT.shutdown();

    throw new ErlangHalt();
  }

  @BIF
  public static EObject unlink(EProc self, EObject pid) throws Pausable {
    EHandle h = EHandle.cast(pid);
    if (h != null) {
      self.unlink(h);
    }
    return pid;
  }

  @BIF
  public static EObject link(EProc self, EObject pid) throws Pausable {
    EHandle h = EHandle.cast(pid);
    if (h == null) throw ERT.badarg(pid);
    self.link_to(h);
    return ERT.TRUE;
  }

  @BIF
  public static EObject monitor(EProc self, EObject how, EObject object) throws Pausable {
    if (how != am_process) throw ERT.badarg(how, object);

    // case 1: object is a PID
    EHandle h = EHandle.cast(object);
    if (h != null) {
      ERef ref = ERT.getLocalNode().createRef();
      if (!self.monitor(h, h, ref)) {
        self.mbox_send(ETuple.make(ERT.am_DOWN, ref, am_process, object, ERT.am_noproc));
      }
      return ref;
    }

    // case 2: object is a name
    EAtom name;
    if (h == null && (name = object.testAtom()) != null) {
      ERef ref = ERT.getLocalNode().createRef();
      boolean success = false;

      object = new ETuple2(name, ErlDist.node());

      if ((h = ERT.whereis(name).testHandle()) != null) {
        success = self.monitor(h, object, ref);
      }

      if (!success) {
        self.mbox_send(ETuple.make(ERT.am_DOWN, ref, am_process, object, ERT.am_noproc));
      }

      return ref;
    }

    // case 3: object is {name, node}
    ETuple tup;
    EAtom node;
    if ((tup = object.testTuple()) != null
        && tup.arity() == 2
        && (name = tup.elm(1).testAtom()) != null
        && (node = tup.elm(2).testAtom()) != null) {
      if (node == ErlDist.node()) {

        ERef ref = ERT.getLocalNode().createRef();
        boolean success = false;

        if ((h = ERT.whereis(name).testHandle()) != null) {
          success = self.monitor(h, object, ref);
        }

        if (!success) {
          self.mbox_send(ETuple.make(ERT.am_DOWN, ref, am_process, object, ERT.am_noproc));
        }

        return ref;

      } else {

        EPeer peer = (EPeer) EPeer.get(node);
        if (peer != null) {
          ERef ref = ERT.getLocalNode().createRef();
          self.monitor(tup, ref);
          peer.dsig_monitor(self.self_handle(), name, ref);
          return ref;
        }

        return ErlDist.dmonitor_p2_trap.invoke(self, new EObject[] {how, object});
      }
    }

    throw ERT.badarg(how, object);
  }

  @Import(module = "erlang", fun = "flush_monitor_message", arity = 2)
  static EFun flush_monitor_message = null;

  @BIF
  public static EObject demonitor(EProc self, EObject ref) throws Pausable {
    return demonitor(self, ref, ERT.NIL);
  }

  /* TODO: Split option parsing from the action; used the action
   * part more directly in demonitor/1.
   * TODO: Support the 'info' option.
   */
  @BIF
  public static EObject demonitor(EProc self, EObject ref, EObject options) throws Pausable {
    return demonitor((ETask<?>) self, ref, options);
  }

  public static EObject demonitor(ETask<?> self, EObject ref, EObject options) throws Pausable {
    ERef r = ref.testReference();

    ESeq o = options.testSeq();

    if (r == null || o == null) throw ERT.badarg(ref, options);

    boolean flush = (!o.isNil() && o.head() == am_flush);

    EObject found = self.demonitor(r);

    if (found == null) {
      return ERT.FALSE;
    }

    EHandle h;
    ETuple tup;
    EAtom name;
    EAtom node;
    if ((h = found.testHandle()) != null) {
      h.remove_monitor(self.self_handle(), r, flush);
    } else if ((tup = found.testTuple()) != null
        && tup.arity() == 2
        && (name = tup.elm(1).testAtom()) != null
        && (node = tup.elm(2).testAtom()) != null) {

      EAbstractNode n = EAbstractNode.get_or_connect(self, node);
      if (n != null) {
        n.dsig_demonitor(self.self_handle(), r, name);
      }
    }

    if (flush && (self instanceof EProc)) {
      flush_monitor_message.invoke((EProc) self, new EObject[] {ref, ERT.am_ok});
    }

    return ERT.TRUE;
  }

  @BIF
  public static EAtom exit(EProc proc, EObject p, EObject reason) throws Pausable {

    //		System.err.println(proc.self_handle() + ":: erlang:exit(" + p + ", " + reason + ")");

    EHandle pid = p.testHandle();

    if (pid == null) throw ERT.badarg(p, reason);

    if (pid == proc.self_handle()) {
      throw new ErlangExit(reason, proc.self_handle());
    }

    pid.exit_signal(proc.self_handle(), reason, true);

    return ERT.TRUE;
  }

  @BIF
  public static EObject exit(EProc self, EObject a1) {
    throw new ErlangExit(a1, self.self_handle());
  }

  @BIF
  public static ERef make_ref(EProc proc) {
    return ERT.getLocalNode().createRef();
  }

  @BIF
  static EObject group_leader(EProc proc) {
    return proc.group_leader();
  }

  @BIF
  static EObject group_leader(EObject group_leader, EObject pid) {
    EPID p = pid.testPID();
    EPID gl = group_leader.testPID();

    if (p == null || gl == null) throw ERT.badarg(group_leader, pid);

    p.set_group_leader(gl);

    return ERT.TRUE;
  }

  static EAtom am_allocator = EAtom.intern("allocator");
  static EAtom am_heap_type = EAtom.intern("heap_type");
  static EAtom am_shared = EAtom.intern("shared");

  private static EAtom am_build_type = EAtom.intern("build_type");

  @BIF
  static EObject system_info(EProc proc, EObject type) {

    if (type == am_machine) {
      // we report BEAM so that the compiler emits BEAM files
      return EString.fromString("BEAM");
    } else if (type == am_smp_support) {
      return ERT.TRUE;
    } else if (type == am_schedulers) {
      return ERT.box(ERT.threadPoolSize());
    } else if (type == am_process_limit) {
      return ERT.box(ERT.processLimit());
    } else if (type == am_fullsweep_after) {
      return ERT.box(65535);
    } else if (type == am_schedulers_online) {
      return ERT.box(Math.max(1, ERT.threadPoolSize()));
    } else if (type == am_threads) {
      return ERT.box(true);
    } else if (type == am_thread_pool_size) {
      return ERT.box(ERT.asyncThreadPoolSize());
    } else if (type == am_break_ignored) {
      return ERT.box(false);
    } else if (type == am_compat_rel) {
      // we return same value as R14
      return new ESmall(14);
    }

    ETuple2 tup;
    if (type == am_allocated_areas) {

      ECons res = ERT.NIL;

      List<MemoryPoolMXBean> bean2 = ManagementFactory.getMemoryPoolMXBeans();

      if (bean2 == null) {

        MemoryMXBean bean = ManagementFactory.getMemoryMXBean();
        if (bean != null) {

          MemoryUsage mu = bean.getHeapMemoryUsage();
          res = res.cons(ETuple.make(am_heap, ERT.box(mu.getCommitted()), ERT.box(mu.getUsed())));

          mu = bean.getNonHeapMemoryUsage();
          res =
              res.cons(ETuple.make(am_non_heap, ERT.box(mu.getCommitted()), ERT.box(mu.getUsed())));
        }

        return res;
      }

      for (MemoryPoolMXBean mb : bean2) {

        String name = mb.getName();
        MemoryUsage mu = mb.getUsage();
        if (mu == null) continue;

        String name2 = (mb.getType() == MemoryType.HEAP ? "heap:" : "non_heap:") + name;

        res =
            res.cons(
                ETuple.make(
                    EAtom.intern(name2), ERT.box(mu.getCommitted()), ERT.box(mu.getUsed())));
      }

      return res;

    } else if (type == am_allocator) {
      return am_jvm;

    } else if (type == am_heap_type) {
      return am_shared;

    } else if (type == am_smp_support) {
      return ERT.TRUE;

    } else if (type == am_thread_pool_size) {
      // TODO: hook up to thread pool
      return new ESmall(ERT.threadPoolSize());

    } else if (type == am_os_type) {
      String os = System.getProperty("os.name");
      if (os.startsWith("Windows")) {
        return ETuple.make(am_win32, new EString(os));
      } else {
        return ETuple.make(am_unix, new EString(os));
      }

    } else if (type == am_threads) {
      return ERT.TRUE;

    } else if (type == am_version) {
      String erts_version = ERT.runtime_info.erts_version;
      // remove prefix
      String prefix = "erts-";
      if (erts_version.startsWith(prefix)) {
        erts_version = erts_version.substring(prefix.length());
      }
      return EString.fromString(erts_version);

    } else if (type == am_otp_release) {
      return new EString(ERT.runtime_info.otp_version);
    } else if (type == am_logical_processors) {
      // TODO: be smarter somehow
      return ERT.box(Runtime.getRuntime().availableProcessors());

    } else if (type == am_global_heaps_size) {
      return ERT.box(Runtime.getRuntime().totalMemory());

    } else if (type == am_process_count) {
      return ERT.box(EProc.process_count());

    } else if (type == am_system_architecture) {
      return new EString(Main.SYSTEM_ARCHITECTURE);

    } else if (type == am_driver_version) {
      // TODO: be smarter somehow
      return new EString(Main.DRIVER_VERSION);

    } else if (type == am_wordsize) {
      return new ESmall(4);

    } else if (type == am_debug_compiled || type == am_lock_checking) {
      throw ERT.badarg(type);

    } else if (type == am_hipe_architecture) {
      return am_undefined;

    } else if (type == am_build_type) {
      return EAtom.intern("opt");

    } else if (type == am_system_version) {
      return new EString("Erjang [" + ERT.runtime_info.erts_version + "]");

    } else if ((tup = ETuple2.cast(type)) != null) {

      if (tup.elem1 == am_allocator) {
        if (tup.elem2 == am_ets_alloc) {
          return ERT.FALSE;
        }
      } else if (tup.elem1 == am_error_checker) {
        throw ERT.badarg(type);
      }

      return am_undefined;

    } else {
      log.info("erlang:system_info(" + type + ") unknown");
      throw ERT.badarg(type);
    }
  }

  @BIF
  static EAtom module_loaded(EObject mod) {
    EAtom m;
    if ((m = mod.testAtom()) == null) throw ERT.badarg(mod);
    return EModuleManager.module_loaded(m) ? ERT.TRUE : ERT.FALSE;
  }

  @BIF
  static ESeq processes() {
    return EProc.processes();
  }

  @BIF
  public static EAtom is_process_alive(EObject p) {
    EPID pid = p.testPID();
    if (pid == null) throw ERT.badarg(p);
    return ERT.box(pid.is_alive());
  }

  @BIF
  public static EObject suspend_process(EObject a1, EObject a2) {
    throw new NotImplemented();
  }

  @BIF
  public static EAtom check_process_code(EObject pid_arg, EObject mod_arg) {
    EPID pid = pid_arg.testPID();
    EAtom mod = mod_arg.testAtom();

    if (pid == null || mod == null) {
      throw ERT.badarg(pid_arg, mod_arg);
    }

    log.log(Level.FINE, "check_process_code not implemented (" + pid + ", " + mod + ")");

    return ERT.FALSE;
  }

  @BIF
  public static EAtom purge_module(EObject mod_arg) {

    log.log(Level.FINE, "purge_module not implemented (" + mod_arg + ")");

    return ERT.TRUE;
  }

  @BIF
  public static EObject hibernate(EProc self, EObject a1, EObject a2, EObject a3) {

    EAtom m = a1.testAtom();
    EAtom f = a2.testAtom();
    ESeq a = a3.testSeq();

    if (m == null || f == null || a == null) {
      throw ERT.badarg(a1, a2, a3);
    }

    int arity = a.length();

    EFun target = EModuleManager.resolve(new FunID(m, f, arity));

    if (target == null) {
      throw new ErlangUndefined(m, f, new ESmall(arity));
    }

    self.tail = target;
    a = a.reverse();
    switch (arity) {
      default:
        throw new NotImplemented("hibernate w/" + arity + " args");
      case 7:
        self.arg6 = a.head();
        a = a.tail();
      case 6:
        self.arg5 = a.head();
        a = a.tail();
      case 5:
        self.arg4 = a.head();
        a = a.tail();
      case 4:
        self.arg3 = a.head();
        a = a.tail();
      case 3:
        self.arg2 = a.head();
        a = a.tail();
      case 2:
        self.arg1 = a.head();
        a = a.tail();
      case 1:
        self.arg0 = a.head(); // a = a.tail();
      case 0:
    }

    throw ErjangHibernateException.INSTANCE;
  }
}
Ejemplo n.º 3
0
  @BIF
  static EObject system_info(EProc proc, EObject type) {

    if (type == am_machine) {
      // we report BEAM so that the compiler emits BEAM files
      return EString.fromString("BEAM");
    } else if (type == am_smp_support) {
      return ERT.TRUE;
    } else if (type == am_schedulers) {
      return ERT.box(ERT.threadPoolSize());
    } else if (type == am_process_limit) {
      return ERT.box(ERT.processLimit());
    } else if (type == am_fullsweep_after) {
      return ERT.box(65535);
    } else if (type == am_schedulers_online) {
      return ERT.box(Math.max(1, ERT.threadPoolSize()));
    } else if (type == am_threads) {
      return ERT.box(true);
    } else if (type == am_thread_pool_size) {
      return ERT.box(ERT.asyncThreadPoolSize());
    } else if (type == am_break_ignored) {
      return ERT.box(false);
    } else if (type == am_compat_rel) {
      // we return same value as R14
      return new ESmall(14);
    }

    ETuple2 tup;
    if (type == am_allocated_areas) {

      ECons res = ERT.NIL;

      List<MemoryPoolMXBean> bean2 = ManagementFactory.getMemoryPoolMXBeans();

      if (bean2 == null) {

        MemoryMXBean bean = ManagementFactory.getMemoryMXBean();
        if (bean != null) {

          MemoryUsage mu = bean.getHeapMemoryUsage();
          res = res.cons(ETuple.make(am_heap, ERT.box(mu.getCommitted()), ERT.box(mu.getUsed())));

          mu = bean.getNonHeapMemoryUsage();
          res =
              res.cons(ETuple.make(am_non_heap, ERT.box(mu.getCommitted()), ERT.box(mu.getUsed())));
        }

        return res;
      }

      for (MemoryPoolMXBean mb : bean2) {

        String name = mb.getName();
        MemoryUsage mu = mb.getUsage();
        if (mu == null) continue;

        String name2 = (mb.getType() == MemoryType.HEAP ? "heap:" : "non_heap:") + name;

        res =
            res.cons(
                ETuple.make(
                    EAtom.intern(name2), ERT.box(mu.getCommitted()), ERT.box(mu.getUsed())));
      }

      return res;

    } else if (type == am_allocator) {
      return am_jvm;

    } else if (type == am_heap_type) {
      return am_shared;

    } else if (type == am_smp_support) {
      return ERT.TRUE;

    } else if (type == am_thread_pool_size) {
      // TODO: hook up to thread pool
      return new ESmall(ERT.threadPoolSize());

    } else if (type == am_os_type) {
      String os = System.getProperty("os.name");
      if (os.startsWith("Windows")) {
        return ETuple.make(am_win32, new EString(os));
      } else {
        return ETuple.make(am_unix, new EString(os));
      }

    } else if (type == am_threads) {
      return ERT.TRUE;

    } else if (type == am_version) {
      String erts_version = ERT.runtime_info.erts_version;
      // remove prefix
      String prefix = "erts-";
      if (erts_version.startsWith(prefix)) {
        erts_version = erts_version.substring(prefix.length());
      }
      return EString.fromString(erts_version);

    } else if (type == am_otp_release) {
      return new EString(ERT.runtime_info.otp_version);
    } else if (type == am_logical_processors) {
      // TODO: be smarter somehow
      return ERT.box(Runtime.getRuntime().availableProcessors());

    } else if (type == am_global_heaps_size) {
      return ERT.box(Runtime.getRuntime().totalMemory());

    } else if (type == am_process_count) {
      return ERT.box(EProc.process_count());

    } else if (type == am_system_architecture) {
      return new EString(Main.SYSTEM_ARCHITECTURE);

    } else if (type == am_driver_version) {
      // TODO: be smarter somehow
      return new EString(Main.DRIVER_VERSION);

    } else if (type == am_wordsize) {
      return new ESmall(4);

    } else if (type == am_debug_compiled || type == am_lock_checking) {
      throw ERT.badarg(type);

    } else if (type == am_hipe_architecture) {
      return am_undefined;

    } else if (type == am_build_type) {
      return EAtom.intern("opt");

    } else if (type == am_system_version) {
      return new EString("Erjang [" + ERT.runtime_info.erts_version + "]");

    } else if ((tup = ETuple2.cast(type)) != null) {

      if (tup.elem1 == am_allocator) {
        if (tup.elem2 == am_ets_alloc) {
          return ERT.FALSE;
        }
      } else if (tup.elem1 == am_error_checker) {
        throw ERT.badarg(type);
      }

      return am_undefined;

    } else {
      log.info("erlang:system_info(" + type + ") unknown");
      throw ERT.badarg(type);
    }
  }