Esempio n. 1
0
void LIRGenerator::do_CheckCast(CheckCast* x) {
  LIRItem obj(x->obj(), this);

  CodeEmitInfo* patching_info = NULL;
  if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check())) {
    // must do this before locking the destination register as an oop register,
    // and before the obj is loaded (the latter is for deoptimization)
    patching_info = state_for(x, x->state_before());
  }
  obj.load_item();

  // info for exceptions
  CodeEmitInfo* info_for_exception = state_for(x);

  CodeStub* stub;
  if (x->is_incompatible_class_change_check()) {
    assert(patching_info == NULL, "can't patch this");
    stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception);
  } else {
    stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
  }
  LIR_Opr reg = rlock_result(x);
  LIR_Opr tmp3 = LIR_OprFact::illegalOpr;
  if (!x->klass()->is_loaded() || UseCompressedOops) {
    tmp3 = new_register(objectType);
  }
  __ checkcast(reg, obj.result(), x->klass(),
               new_register(objectType), new_register(objectType), tmp3,
               x->direct_compare(), info_for_exception, patching_info, stub,
               x->profiled_method(), x->profiled_bci());
}
Esempio n. 2
0
trivium_keystream *new_keystream()
{
  trivium_keystream *ks;
  if ( (ks = (trivium_keystream *) calloc(1, sizeof(trivium_keystream))) == NULL)
    return NULL;

  /* A:93,B:84,C:111 */
  if ((ks->srA = new_register(93)) == NULL) {
    free(ks);
    return NULL;
  }

  if ( (ks->srB = new_register(84)) == NULL ) {
    del_register(ks->srA);
    free(ks);
    return NULL;
  }

  if ( (ks->srC = new_register(111)) == NULL ) {
    del_register(ks->srB);
    del_register(ks->srA);
    free(ks);
    return NULL;
  }
  
  return ks;
}
Esempio n. 3
0
void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data,
                                     BasicType type, bool is_volatile) {
  if (is_volatile && type == T_LONG) {
    LIR_Address* addr = new LIR_Address(src, offset, T_DOUBLE);
    LIR_Opr tmp = new_register(T_DOUBLE);
    LIR_Opr spill = new_register(T_DOUBLE);
    set_vreg_flag(spill, must_start_in_memory);
    __ move(data, spill);
    __ move(spill, tmp);
    __ move(tmp, addr);
  } else {
    LIR_Address* addr = new LIR_Address(src, offset, type);
    bool is_obj = (type == T_ARRAY || type == T_OBJECT);
    if (is_obj) {
      // Do the pre-write barrier, if any.
      pre_barrier(LIR_OprFact::address(addr), false, NULL);
      __ move(data, addr);
      assert(src->is_register(), "must be register");
      // Seems to be a precise address
      post_barrier(LIR_OprFact::address(addr), data);
    } else {
      __ move(data, addr);
    }
  }
}
void LIRGenerator::do_CheckCast(CheckCast* x) {
  // all values are spilled
  spill_values_on_stack(x->state());
  LIRItem obj(x->obj(), this);
  obj.set_destroys_register();
  CodeEmitInfo* patching_info = NULL;
  if (!x->klass()->is_loaded() || PatchALot) {
    // must do this before locking the destination register as an oop register,
    // and before the obj is loaded (the latter is for deoptimization)
    patching_info = state_for(x, x->state_before());
  }
  obj.load_item();
  RInfo in_reg = obj.result()->rinfo();

  // info for exceptions
  CodeEmitInfo* info_for_exception = state_for(x, x->state()->copy_locks());

  RInfo reg = rlock_result(x)->rinfo();
  RInfo tmp1 = new_register(objectType)->rinfo();
  RInfo tmp2 = new_register(objectType)->rinfo();

  if (patching_info != NULL) {
    patching_info->add_register_oop(in_reg);
  }
  emit()->checkcast_op(LIR_OprFact::rinfo(reg, T_OBJECT), obj.result(), x->klass(), tmp1, tmp2, x->direct_compare(), info_for_exception, patching_info);
}
Esempio n. 5
0
void LIRGenerator::do_MonitorEnter(MonitorEnter* x) {
  assert(x->is_pinned(),"");
  LIRItem obj(x->obj(), this);
  obj.load_item();

  set_no_result(x);

  // "lock" stores the address of the monitor stack slot, so this is not an oop
  LIR_Opr lock = new_register(T_INT);
  // Need a scratch register for biased locking on x86
  LIR_Opr scratch = LIR_OprFact::illegalOpr;
  if (UseBiasedLocking) {
    scratch = new_register(T_INT);
  }

  CodeEmitInfo* info_for_exception = NULL;
  if (x->needs_null_check()) {
    info_for_exception = state_for(x);
  }
  // this CodeEmitInfo must not have the xhandlers because here the
  // object is already locked (xhandlers expect object to be unlocked)
  CodeEmitInfo* info = state_for(x, x->state(), true);
  monitor_enter(obj.result(), lock, syncTempOpr(), scratch,
                        x->monitor_no(), info_for_exception, info);
}
  // returns a register suitable for doing pointer math
  LIR_Opr new_pointer_register() {
#ifdef _LP64
    return new_register(T_LONG);
#else
    return new_register(T_INT);
#endif
  }
Esempio n. 7
0
void LIRGenerator::do_MonitorExit(MonitorExit* x) {
  assert(x->is_pinned(),"");

  LIRItem obj(x->obj(), this);
  obj.dont_load_item();

  LIR_Opr lock = new_register(T_INT);
  LIR_Opr obj_temp = new_register(T_INT);
  set_no_result(x);
  monitor_exit(obj_temp, lock, syncTempOpr(), LIR_OprFact::illegalOpr, x->monitor_no());
}
void LIRGenerator::do_MonitorExit(MonitorExit* x) {
  spill_values_on_stack(x->state());
  assert(x->is_root(),"");

  LIRItem obj(x->obj(), this);
  obj.dont_load_item();

  RInfo lock = new_register(T_INT)->rinfo();
  RInfo obj_temp = new_register(T_INT)->rinfo();
  set_no_result(x);
  emit()->monitor_exit(obj_temp, lock, syncTempRInfo(), x->monitor_no());
}
void LIRGenerator::increment_counter(LIR_Address* addr, int step) {
  LIR_Opr temp = new_register(T_INT);
  __ move(addr, temp);
  LIR_Opr c = LIR_OprFact::intConst(step);
  if (Assembler::is_simm13(step)) {
    __ add(temp, c, temp);
  } else {
    LIR_Opr temp2 = new_register(T_INT);
    __ move(c, temp2);
    __ add(temp, temp2, temp);
  }
  __ move(temp, addr);
}
Esempio n. 10
0
void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset,
                                     BasicType type, bool is_volatile) {
  if (is_volatile && type == T_LONG) {
    LIR_Address* addr = new LIR_Address(src, offset, T_DOUBLE);
    LIR_Opr tmp = new_register(T_DOUBLE);
    __ load(addr, tmp);
    LIR_Opr spill = new_register(T_LONG);
    set_vreg_flag(spill, must_start_in_memory);
    __ move(tmp, spill);
    __ move(spill, dst);
  } else {
    LIR_Address* addr = new LIR_Address(src, offset, type);
    __ load(addr, dst);
  }
}
Esempio n. 11
0
LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr,
                                              BasicType type, bool needs_card_mark) {
  int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(type);

  LIR_Address* addr;
  if (index_opr->is_constant()) {
    int elem_size = type2aelembytes(type);
    addr = new LIR_Address(array_opr,
                           offset_in_bytes + index_opr->as_jint() * elem_size, type);
  } else {
#ifdef _LP64
    if (index_opr->type() == T_INT) {
      LIR_Opr tmp = new_register(T_LONG);
      __ convert(Bytecodes::_i2l, index_opr, tmp);
      index_opr = tmp;
    }
#endif // _LP64
    addr =  new LIR_Address(array_opr,
                            index_opr,
                            LIR_Address::scale(type),
                            offset_in_bytes, type);
  }
  if (needs_card_mark) {
    // This store will need a precise card mark, so go ahead and
    // compute the full adddres instead of computing once for the
    // store and again for the card mark.
    LIR_Opr tmp = new_pointer_register();
    __ leal(LIR_OprFact::address(addr), tmp);
    return new LIR_Address(tmp, type);
  } else {
    return addr;
  }
}
Esempio n. 12
0
void Top10::AddScore(string name, unsigned int score, unsigned int kills) {
	
	//Create a temporal register
	Score new_register(name, score, kills);
			
	//Insert the register
	scores.push_back(new_register);

	//Debug :: Print the list
	//PrintScores();	//*****************************//
		
	//Sort the list
	scores.sort();
	
	//Debug :: Print the list
	//PrintScores();	//*****************************//
	
	//Removes the las element
	scores.pop_back();
	
	//Debug :: Print the list
	//PrintScores();	//*****************************//
	
	//Save the score to a file
	SaveScores();
	
}
Esempio n. 13
0
void LIRGenerator::do_Convert(Convert* x) {
  // flags that vary for the different operations and different SSE-settings
  bool fixed_input, fixed_result, round_result, needs_stub;

  switch (x->op()) {
    case Bytecodes::_i2l: // fall through
    case Bytecodes::_l2i: // fall through
    case Bytecodes::_i2b: // fall through
    case Bytecodes::_i2c: // fall through
    case Bytecodes::_i2s: fixed_input = false;       fixed_result = false;       round_result = false;      needs_stub = false; break;

    case Bytecodes::_f2d: fixed_input = UseSSE == 1; fixed_result = false;       round_result = false;      needs_stub = false; break;
    case Bytecodes::_d2f: fixed_input = false;       fixed_result = UseSSE == 1; round_result = UseSSE < 1; needs_stub = false; break;
    case Bytecodes::_i2f: fixed_input = false;       fixed_result = false;       round_result = UseSSE < 1; needs_stub = false; break;
    case Bytecodes::_i2d: fixed_input = false;       fixed_result = false;       round_result = false;      needs_stub = false; break;
    case Bytecodes::_f2i: fixed_input = false;       fixed_result = false;       round_result = false;      needs_stub = true;  break;
    case Bytecodes::_d2i: fixed_input = false;       fixed_result = false;       round_result = false;      needs_stub = true;  break;
    case Bytecodes::_l2f: fixed_input = false;       fixed_result = UseSSE >= 1; round_result = UseSSE < 1; needs_stub = false; break;
    case Bytecodes::_l2d: fixed_input = false;       fixed_result = UseSSE >= 2; round_result = UseSSE < 2; needs_stub = false; break;
    case Bytecodes::_f2l: fixed_input = true;        fixed_result = true;        round_result = false;      needs_stub = false; break;
    case Bytecodes::_d2l: fixed_input = true;        fixed_result = true;        round_result = false;      needs_stub = false; break;
    default: ShouldNotReachHere();
  }

  LIRItem value(x->value(), this);
  value.load_item();
  LIR_Opr input = value.result();
  LIR_Opr result = rlock(x);

  // arguments of lir_convert
  LIR_Opr conv_input = input;
  LIR_Opr conv_result = result;
  ConversionStub* stub = NULL;

  if (fixed_input) {
    conv_input = fixed_register_for(input->type());
    __ move(input, conv_input);
  }

  assert(fixed_result == false || round_result == false, "cannot set both");
  if (fixed_result) {
    conv_result = fixed_register_for(result->type());
  } else if (round_result) {
    result = new_register(result->type());
    set_vreg_flag(result, must_start_in_memory);
  }

  if (needs_stub) {
    stub = new ConversionStub(x->op(), conv_input, conv_result);
  }

  __ convert(x->op(), conv_input, conv_result, stub);

  if (result != conv_result) {
    __ move(conv_result, result);
  }

  assert(result->is_virtual(), "result must be virtual register");
  set_result(x, result);
}
// _ishl, _lshl, _ishr, _lshr, _iushr, _lushr
void LIRGenerator::do_ShiftOp(ShiftOp* x) {
  // count must always be in ecx
  LIRItem value(x->x(), this);
  LIRItem count(x->y(), this);
  value.set_destroys_register();
  ValueTag elemType = x->type()->tag();
  bool must_load_count = !count.is_constant() || elemType == longTag;
  if (must_load_count) {
    // count for long must be in register
    count.load_item();
  } else {
    count.dont_load_item();
  }
  value.load_item();
  RInfo tmp;
  if (elemType == intTag && count.is_register()) {
    // in case we cache the count, we want always to have a register free
    // (without caching, the count may be loaded in ecx; with the caching count,
    // the count register may not be ecx
    tmp = new_register(T_INT)->rinfo();
  }
  RInfo reg = rlock_result(x)->rinfo();

  emit()->shift_op(x->op(), reg, value.result(), count.result(), tmp);
}
  // return a cached temporary operand
  LIR_Opr get_temp(int i, BasicType type) {
    if (i < FrameMap::pd_max_temp_vregs) {
      assert0(_temp_vregs[i]->type_register() == type);
return _temp_vregs[i];
    } else {
return new_register(type);
    }
  }
Esempio n. 16
0
LIR_Opr LIRGenerator::getThreadPointer() {
#ifdef _LP64
  return FrameMap::as_pointer_opr(r15_thread);
#else
  LIR_Opr result = new_register(T_INT);
  __ get_thread(result);
  return result;
#endif //
}
LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
                                            int shift, int disp, BasicType type) {
  assert(base->is_register(), "must be");

  // accumulate fixed displacements
  if (index->is_constant()) {
    disp += index->as_constant_ptr()->as_jint() << shift;
    index = LIR_OprFact::illegalOpr;
  }

  if (index->is_register()) {
    // apply the shift and accumulate the displacement
    if (shift > 0) {
      LIR_Opr tmp = new_register(T_INT);
      __ shift_left(index, shift, tmp);
      index = tmp;
    }
    if (disp != 0) {
      LIR_Opr tmp = new_register(T_INT);
      if (Assembler::is_simm13(disp)) {
        __ add(tmp, LIR_OprFact::intConst(disp), tmp);
        index = tmp;
      } else {
        __ move(LIR_OprFact::intConst(disp), tmp);
        __ add(tmp, index, tmp);
        index = tmp;
      }
      disp = 0;
    }
  } else if (disp != 0 && !Assembler::is_simm13(disp)) {
    // index is illegal so replace it with the displacement loaded into a register
    index = new_register(T_INT);
    __ move(LIR_OprFact::intConst(disp), index);
    disp = 0;
  }

  // at this point we either have base + index or base + displacement
  if (disp == 0) {
    return new LIR_Address(base, index, type);
  } else {
    assert(Assembler::is_simm13(disp), "must be");
    return new LIR_Address(base, disp, type);
  }
}
Esempio n. 18
0
void LIRGenerator::do_InstanceOf(InstanceOf* x) {
  LIRItem obj(x->obj(), this);

  // result and test object may not be in same register
  LIR_Opr reg = rlock_result(x);
  CodeEmitInfo* patching_info = NULL;
  if ((!x->klass()->is_loaded() || PatchALot)) {
    // must do this before locking the destination register as an oop register
    patching_info = state_for(x, x->state_before());
  }
  obj.load_item();
  LIR_Opr tmp3 = LIR_OprFact::illegalOpr;
  if (!x->klass()->is_loaded() || UseCompressedOops) {
    tmp3 = new_register(objectType);
  }
  __ instanceof(reg, obj.result(), x->klass(),
                new_register(objectType), new_register(objectType), tmp3,
                x->direct_compare(), patching_info, x->profiled_method(), x->profiled_bci());
}
Esempio n. 19
0
void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address,
                                        CodeEmitInfo* info) {
  if (address->type() == T_LONG) {
    address = new LIR_Address(address->base(),
                              address->index(), address->scale(),
                              address->disp(), T_DOUBLE);
    // Transfer the value atomically by using FP moves.  This means
    // the value has to be moved between CPU and FPU registers.  It
    // always has to be moved through spill slot since there's no
    // quick way to pack the value into an SSE register.
    LIR_Opr temp_double = new_register(T_DOUBLE);
    LIR_Opr spill = new_register(T_LONG);
    set_vreg_flag(spill, must_start_in_memory);
    __ move(value, spill);
    __ volatile_move(spill, temp_double, T_LONG);
    __ volatile_move(temp_double, LIR_OprFact::address(address), T_LONG, info);
  } else {
    __ store(value, address, info);
  }
}
Esempio n. 20
0
monitorclient::monitorclient(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::monitorclient)
{
    ui->setupUi(this);
    TcpClientSocket =new QTcpSocket(this);
    connect(TcpClientSocket,SIGNAL(readyRead()),this,SLOT(readMessage()));
    connect(TcpClientSocket,SIGNAL(error(QAbstractSocket::SocketError)),
             this,SLOT(displayError(QAbstractSocket::SocketError)));
    connect(ui->LandingButton,SIGNAL(clicked()),this,SLOT(landing()));
    connect(ui->RegisterButton,SIGNAL(clicked()),this,SLOT(new_register()));
}
LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr,
                                              BasicType type, bool needs_card_mark) {
  int elem_size = type2aelembytes(type);
  int shift = exact_log2(elem_size);

  LIR_Opr base_opr;
  int offset = arrayOopDesc::base_offset_in_bytes(type);

  if (index_opr->is_constant()) {
    int i = index_opr->as_constant_ptr()->as_jint();
    int array_offset = i * elem_size;
    if (Assembler::is_simm13(array_offset + offset)) {
      base_opr = array_opr;
      offset = array_offset + offset;
    } else {
      base_opr = new_pointer_register();
      if (Assembler::is_simm13(array_offset)) {
        __ add(array_opr, LIR_OprFact::intptrConst(array_offset), base_opr);
      } else {
        __ move(LIR_OprFact::intptrConst(array_offset), base_opr);
        __ add(base_opr, array_opr, base_opr);
      }
    }
  } else {
#ifdef _LP64
    if (index_opr->type() == T_INT) {
      LIR_Opr tmp = new_register(T_LONG);
      __ convert(Bytecodes::_i2l, index_opr, tmp);
      index_opr = tmp;
    }
#endif

    base_opr = new_pointer_register();
    assert (index_opr->is_register(), "Must be register");
    if (shift > 0) {
      __ shift_left(index_opr, shift, base_opr);
      __ add(base_opr, array_opr, base_opr);
    } else {
      __ add(index_opr, array_opr, base_opr);
    }
  }
  if (needs_card_mark) {
    LIR_Opr ptr = new_pointer_register();
    __ add(base_opr, LIR_OprFact::intptrConst(offset), ptr);
    return new LIR_Address(ptr, 0, type);
  } else {
    return new LIR_Address(base_opr, offset, type);
  }
}
void LIRGenerator::do_MonitorEnter(MonitorEnter* x) {
  spill_values_on_stack(x->state());
  assert(x->is_root(),"");
  LIRItem obj(x->obj(), this);
  obj.load_item();
  set_no_result(x);

  RInfo lock = new_register(T_OBJECT)->rinfo();

  CodeEmitInfo* info_for_exception = NULL;
  if (x->needs_null_check()) {
    info_for_exception = state_for(x, x->lock_stack_before());
  }
  CodeEmitInfo* info = state_for(x, x->state());
  emit()->monitor_enter(obj.get_register(), lock, syncTempRInfo(), norinfo, x->monitor_no(), info_for_exception, info);
}
Esempio n. 23
0
void LIRGenerator::do_NewInstance(NewInstance* x) {
#ifndef PRODUCT
  if (PrintNotLoaded && !x->klass()->is_loaded()) {
    tty->print_cr("   ###class not loaded at new bci %d", x->printable_bci());
  }
#endif
  CodeEmitInfo* info = state_for(x, x->state());
  LIR_Opr reg = result_register_for(x->type());
  LIR_Opr klass_reg = new_register(objectType);
  new_instance(reg, x->klass(),
                       FrameMap::rcx_oop_opr,
                       FrameMap::rdi_oop_opr,
                       FrameMap::rsi_oop_opr,
                       LIR_OprFact::illegalOpr,
                       FrameMap::rdx_oop_opr, info);
  LIR_Opr result = rlock_result(x);
  __ move(reg, result);
}
void LIRGenerator::do_ArrayCopy(Intrinsic* x) {
  spill_values_on_stack(x->state());
  assert(x->number_of_arguments() == 5, "wrong type");
  LIRItem src(x->argument_at(0), this);
  LIRItem src_pos(x->argument_at(1), this);
  LIRItem dst(x->argument_at(2), this);
  LIRItem dst_pos(x->argument_at(3), this);
  LIRItem length(x->argument_at(4), this);

  src.load_item();
  src_pos.load_item();
  dst.load_item();
  dst_pos.load_item();
  length.load_item();
  RInfo tmp = new_register(T_INT)->rinfo();
  set_no_result(x);

  CodeEmitInfo* info = state_for(x, x->state()); // we may want to have stack (deoptimization?)
  emit()->arraycopy(src.result(), src_pos.result(), dst.result(), dst_pos.result(), length.result(), tmp, false, NULL, info); // does add_safepoint
}
void LIRGenerator::do_InstanceOf(InstanceOf* x) {
  spill_values_on_stack(x->state());
  LIRItem obj(x->obj(), this);
  obj.set_destroys_register();
  // result and test object may not be in same register
  RInfo reg = rlock_result(x)->rinfo();
  CodeEmitInfo* patching_info = NULL;
  if ((!x->klass()->is_loaded() || PatchALot)) {
    // must do this before locking the destination register as an oop register
    patching_info = state_for(x, x->state_before());
  }
  obj.load_item();
  // do not include tmp in the oop map
  if (patching_info != NULL) {
    // object must be part of the oop map
    patching_info->add_register_oop(obj.result()->rinfo());
  }
  RInfo tmp = new_register(objectType)->rinfo();
  emit()->instanceof_op(LIR_OprFact::rinfo(reg, T_OBJECT), obj.result(), x->klass(), tmp, obj.result()->rinfo(), x->direct_compare(), patching_info);
}
Esempio n. 26
0
void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
                                       CodeEmitInfo* info) {
  if (address->type() == T_LONG) {
    address = new LIR_Address(address->base(),
                              address->index(), address->scale(),
                              address->disp(), T_DOUBLE);
    // Transfer the value atomically by using FP moves.  This means
    // the value has to be moved between CPU and FPU registers.  In
    // SSE0 and SSE1 mode it has to be moved through spill slot but in
    // SSE2+ mode it can be moved directly.
    LIR_Opr temp_double = new_register(T_DOUBLE);
    __ volatile_move(LIR_OprFact::address(address), temp_double, T_LONG, info);
    __ volatile_move(temp_double, result, T_LONG);
    if (UseSSE < 2) {
      // no spill slot needed in SSE2 mode because xmm->cpu register move is possible
      set_vreg_flag(result, must_start_in_memory);
    }
  } else {
    __ load(address, result, info);
  }
}
 LIR_Opr new_register(ValueType* type)          { return new_register(as_BasicType(type)); }
 LIR_Opr new_register(Value value)              { return new_register(as_BasicType(value->type())); }
 // returns a register suitable for doing pointer math
 LIR_Opr new_pointer_register() {
   return new_register(T_LONG);
 }
Esempio n. 30
0
static int login_query(void)
{
#ifndef ENABLE_SSH
	char uname[IDLEN + 2];
	char passbuf[PASSLEN];
	int attempts;
	int recover; // For giveupBBS
	bool auth = false;
#endif // ENABLE_SSH

	// Deny new logins if too many users online.
	int online = session_count_online();
#ifndef ENABLE_SSH
	if (online >= MAXACTIVE) {
		ansimore("etc/loginfull", NA);
		return -1;
	}
#endif // ENABLE_SSH

	ansimore2("etc/issue", false, 0, 0);
	screen_printf("\033[1;35m欢迎光临\033[1;40;33m【 %s 】 \033[m"
			"[\033[1;33;41m Add '.' after YourID to login for BIG5 \033[m]\n",
			BBSNAME_UTF8);

	int peak = session_get_online_record();
	if (peak < online) {
		session_set_online_record(online);
		peak = online;
	}

	screen_printf("\033[1;32m目前已有帐号: [\033[1;36m%d\033[32m/\033[36m%d\033[32m] "
			"\033[32m目前站上人数: [\033[36m%d\033[32m/\033[36m%d\033[1;32m]\n",
			get_user_count(), MAXUSERS, online, MAXACTIVE);
	visitlog(peak);

#ifndef ENABLE_SSH
	attempts = 0;
	while (!auth) {
		if (attempts++ >= LOGINATTEMPTS) {
			ansimore("etc/goodbye", NA);
			return -1;
		}
		//% getdata(0, 0, "\033[1;33m请输入帐号\033[m"
		getdata(0, 0, "\033[1;33m\xc7\xeb\xca\xe4\xc8\xeb\xd5\xca\xba\xc5\033[m"
				//% "(试用请输入'\033[1;36mguest\033[m', "
				"(\xca\xd4\xd3\xc3\xc7\xeb\xca\xe4\xc8\xeb'\033[1;36mguest\033[m', "
				//% "注册请输入'\033[1;31mnew\033[m'): ",
				"\xd7\xa2\xb2\xe1\xc7\xeb\xca\xe4\xc8\xeb'\033[1;31mnew\033[m'): ",
				uname, IDLEN + 1, DOECHO, YEA);
		if (strcaseeq(uname, "guest") && (online > MAXACTIVE - 10)) {
			ansimore("etc/loginfull", NA);
			return -1;
		}
		if (strcaseeq(uname, "new")) {
			memset(&currentuser, 0, sizeof(currentuser));
			new_register();
			terminal_flush();
			exit(1);
		} else if (*uname == '\0')
			;
		else if (!dosearchuser(uname, &currentuser, &usernum)) {
			screen_printf("\033[1;31m经查证,无此 ID。\033[m\n");
		} else if (strcaseeq(uname, "guest")) {
			currentuser.userlevel = 0;
			break;
		} else {
			//% getdata(0, 0, "\033[1;37m请输入密码: \033[m", passbuf, PASSLEN,
			getdata(0, 0, "\033[1;37m\xc7\xeb\xca\xe4\xc8\xeb\xc3\xdc\xc2\xeb: \033[m", passbuf, PASSLEN,
					NOECHO, YEA);
			passbuf[8] = '\0';
			switch (bbs_auth(uname, passbuf)) {
				case BBS_EWPSWD:
					screen_printf("\033[1;31m密码输入错误...\033[m\n");
					break;
				case BBS_EGIVEUP:
					recover = chk_giveupbbs();
					screen_printf("\033[33m您正在戒网,离戒网结束还有%d天\033[m\n",
							recover - fb_time() / 3600 / 24);
					return -1;
				case BBS_ESUICIDE:
					screen_printf("\033[32m您已经自杀\033[m\n");
					return -1;
				case BBS_EBANNED:
					screen_printf("\033[32m本帐号已停机。请到 "
							"\033[36mNotice\033[32m版 查询原因\033[m\n");
					return -1;
				case BBS_ELFREQ:
					screen_printf("登录过于频繁,请稍候再来\n");
					return -1;
				case 0:
					auth = true;
					break;
				default:
					auth = false;
					break;
			}
			memset(passbuf, 0, PASSLEN - 1);
		}
	}
#else // ENABLE_SSH
	//% 欢迎使用ssh方式访问本站,请按任意键继续
	presskeyfor("\033[1;33m\xbb\xb6\xd3\xad\xca\xb9\xd3\xc3ssh\xb7\xbd\xca\xbd\xb7\xc3\xce\xca\xb1\xbe\xd5\xbe\xa3\xac\xc7\xeb\xb0\xb4\xc8\xce\xd2\xe2\xbc\xfc\xbc\xcc\xd0\xf8", -1);
#endif // ENABLE_SSH

	if (multi_user_check() == -1)
		return -1;

	sethomepath(genbuf, currentuser.userid);
	mkdir(genbuf, 0755);
	login_start_time = time(NULL);
	return 0;
}