コード例 #1
0
ファイル: prim.cpp プロジェクト: sebkirche/strongtalk
oop primitive_desc::eval(oop* a) {
  const bool reverseArgs = true;	// change this when changing primitive calling convention
  oop res;
  if (reverseArgs) {
    switch (number_of_parameters()) {
      case  0: res = ((prim_fntype0)_fn)(); break;
      case  1: res = ((prim_fntype1)_fn)(a[0]); break;
      case  2: res = ((prim_fntype2)_fn)(a[1], a[0]); break;
      case  3: res = ((prim_fntype3)_fn)(a[2], a[1], a[0]); break;
      case  4: res = ((prim_fntype4)_fn)(a[3], a[2], a[1], a[0]); break;
      case  5: res = ((prim_fntype5)_fn)(a[4], a[3], a[2], a[1], a[0]); break;
      case  6: res = ((prim_fntype6)_fn)(a[5], a[4], a[3], a[2], a[1], a[0]); break;
      case  7: res = ((prim_fntype7)_fn)(a[6], a[5], a[4], a[3], a[2], a[1], a[0]); break;
      case  8: res = ((prim_fntype8)_fn)(a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0]); break;
      case  9: res = ((prim_fntype9)_fn)(a[8], a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0]); break;
      default: ShouldNotReachHere();
    }
  } else {
    switch (number_of_parameters()) {
      case  0: res = ((prim_fntype0)_fn)(); break;
      case  1: res = ((prim_fntype1)_fn)(a[0]); break;
      case  2: res = ((prim_fntype2)_fn)(a[0], a[1]); break;
      case  3: res = ((prim_fntype3)_fn)(a[0], a[1], a[2]); break;
      case  4: res = ((prim_fntype4)_fn)(a[0], a[1], a[2], a[3]); break;
      case  5: res = ((prim_fntype5)_fn)(a[0], a[1], a[2], a[3], a[4]); break;
      case  6: res = ((prim_fntype6)_fn)(a[0], a[1], a[2], a[3], a[4], a[5]); break;
      case  7: res = ((prim_fntype7)_fn)(a[0], a[1], a[2], a[3], a[4], a[5], a[6]); break;
      case  8: res = ((prim_fntype8)_fn)(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break;
      case  9: res = ((prim_fntype9)_fn)(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); break;
      default: ShouldNotReachHere();
    }
  }
  return res;
}
コード例 #2
0
ファイル: prim.cpp プロジェクト: sebkirche/strongtalk
void primitive_desc::print() {
  std->print("%48s %d %s%s%s%s%s%s%s%s%s",
             name(), 
             number_of_parameters(),
	     has_receiver()           ? "R" : "_",
             can_fail()               ? "F" : "_",
	     can_scavenge()           ? "S" : "_",
	     can_walk_stack()         ? "W" : "_",
	     can_perform_NLR()        ? "N" : "_",
	     can_be_constant_folded() ? "C" : "_",
	     can_invoke_delta()       ? "D" : "_",
	     is_internal()            ? "I" : "_",
	     needs_delta_fp_code()    ? "P" : "_");
  switch(group()) {
    case IntComparisonPrimitive:   std->print(", smi compare");           break;
    case IntArithmeticPrimitive:   std->print(", smi arith");             break;
    case FloatComparisonPrimitive: std->print(", double compare");        break;
    case FloatArithmeticPrimitive: std->print(", double arith");          break;
    case ByteArrayPrimitive:       std->print(", byte array op.");        break;
    case DoubleByteArrayPrimitive: std->print(", double-byte array op."); break;
    case ObjArrayPrimitive:        std->print(", array op.");             break;
    case BlockPrimitive: 	   std->print(", block/context");         break;
    case NormalPrimitive:                                                 break;
    default: fatal("Unknown primitive group");
  }
  std->cr();
}
コード例 #3
0
PrimInliner::PrimInliner(NodeBuilder* gen, primitive_desc* pdesc, MethodInterval* failure_block) {
  assert(pdesc, "must have a primitive desc to inline");
  _gen		= gen;
  _pdesc	= pdesc;
  _failure_block= failure_block;

  _scope	= gen->_scope;
  _bci		= gen->bci();	  // bci of primitive call
  _exprStack	= gen->_exprStack;
  _cannotFail   = true;
  _params	= new GrowableArray<Expr*>(number_of_parameters(), number_of_parameters(), NULL);
  _usingUncommonTrap = false;

  // get parameters
  int i = number_of_parameters();
  int first = _exprStack->length() - i;
  while (i-- > 0) {
    _params->at_put(i, _exprStack->at(first + i));
  }

// %hack: assertion fails
//  assert(_pdesc->can_fail() == (failure_block != NULL), "primitive desc & primitive usage inconsistent");
}
コード例 #4
0
Expr* PrimInliner::tryConstantFold() {
  // Returns the result if the primitive call has been constant folded
  // successfully; returns NULL otherwise.
  // Note: The result may be a marked oop - which has to be unmarked
  // before using it - and which indicates that the primitive will fail
  // always.
  if (!_pdesc->can_be_constant_folded()) {
    // check for Symbol>>at: before declaring failure
    if ((equal(_pdesc->name(), "primitiveIndexedByteAt:ifFail:") ||
         equal(_pdesc->name(), "primitiveIndexedByteCharacterAt:ifFail:")) &&
        parameter(0)->hasKlass() && parameter(0)->klass() == Universe::symbolKlassObj()) {
      // the at: primitive can be constant-folded for symbols
      // what if the receiver is a constant string? unfortunately, Smalltalk has
      // "assignable constants" like Fortran...
    } else {
      return NULL;
    }
  }
  // get parameters
  int i = number_of_parameters();
  oop* args = NEW_RESOURCE_ARRAY(oop, i);
  while (i > 0) {
    i--;
    Expr* arg = parameter(i);
    if (!arg->isConstantExpr()) return NULL;
    args[i] = arg->constant();
  }
  // all parameters are constants, so call primitive
  oop res = _pdesc->eval(args);
  if (res->is_mark()) {
    // primitive failed
    return primitiveFailure(unmarkSymbol(res));
  } else if (res->is_mem() && !res->is_old()) {
    // must tenure result because nmethods aren't scavenged
    if (res->is_double()) {
      res = oopFactory::clone_double_to_oldspace(doubleOop(res));
    } else {
      // don't know how to tenure non-doubles
      warning("const folding: primitive %s is returning non-tenured object", _pdesc->name());
      return NULL;
    }
  }
  ConstPReg* constResult = new_ConstPReg(_scope, res);
  SAPReg* result = new SAPReg(_scope);
  _gen->append(NodeFactory::new_AssignNode(constResult, result));
  if (CompilerDebug) cout(PrintInlining)->print("%*sconstant-folding %s --> %#x\n", _scope->depth + 2, "", _pdesc->name(), res);
  assert(!constResult->constant->is_mark(), "result must not be marked");
  return new ConstantExpr(res, constResult, _gen->current());
}
コード例 #5
0
ファイル: code_block.cpp プロジェクト: harold/factor
template<typename Iterator> void factor_vm::iterate_relocations(code_block *compiled, Iterator &iter)
{
	if(compiled->relocation != F)
	{
		byte_array *relocation = untag<byte_array>(compiled->relocation);

		cell index = 0;
		cell length = array_capacity(relocation) / sizeof(relocation_entry);

		for(cell i = 0; i < length; i++)
		{
			relocation_entry rel = relocation->data<relocation_entry>()[i];
			iter(rel,index,compiled);
			index += number_of_parameters(relocation_type_of(rel));			
		}
	}
}
コード例 #6
0
symbolOop PrimInliner::failureSymbolForArg(int i) {
  assert(i >= 0 && i < number_of_parameters(), "bad index");
  switch (i) {
    case  0: return vmSymbols::receiver_has_wrong_type();
    case  1: return vmSymbols::first_argument_has_wrong_type();
    case  2: return vmSymbols::second_argument_has_wrong_type();
    case  3: return vmSymbols::third_argument_has_wrong_type();
    case  4: return vmSymbols::fourth_argument_has_wrong_type();
    case  5: return vmSymbols::fifth_argument_has_wrong_type();
    case  6: return vmSymbols::sixth_argument_has_wrong_type();
    case  7: return vmSymbols::seventh_argument_has_wrong_type();
    case  8: return vmSymbols::eighth_argument_has_wrong_type();
    case  9: return vmSymbols::ninth_argument_has_wrong_type();
    case 10: return vmSymbols::tenth_argument_has_wrong_type();
    default: return vmSymbols::argument_has_wrong_type();
  }
}
コード例 #7
0
Expr* PrimInliner::tryTypeCheck() {
  // Check if we have enough type information to prove that the primitive is going to fail;
  // if so, directly compile failure block (important for mixed-mode arithmetic).
  // Returns the failure result if the primitive call has been proven
  // to fail; returns NULL otherwise.
  // Should extend code to do general type compatibility test (including MergeExprs, e.g. for 
  // booleans) -- fix this later.  -Urs 11/95
  int num = number_of_parameters();
  for (int i = 0; i < num; i++) {
    Expr* a = parameter(i);
    if (a->hasKlass()) {
      Expr* primArgType = _pdesc->parameter_klass(i, a->preg(), NULL);
      if (primArgType && primArgType->hasKlass() && (a->klass() != primArgType->klass())) {
        // types differ -> primitive must fail
	return primitiveFailure(failureSymbolForArg(i));
      }
    }
  }
  return NULL;
}
コード例 #8
0
ファイル: prim.cpp プロジェクト: sebkirche/strongtalk
char* primitive_desc::parameter_type(int index) const {
  assert((0 <= index) && (index < number_of_parameters()), "illegal parameter index");
  return _types[1 + index];
}
コード例 #9
0
Expr* PrimInliner::tryInline() {
  // Returns the failure result or the result of the primitive (if the
  // primitive can't fail) if the primitive has been inlined; returns
  // NULL otherwise. If the primitive has been inlined but can't fail,
  // the bci in the MethodDecoder is set to the first instruction after
  // the failure block.
  // NB: The comparisons below should be replaced with pointer comparisons
  // comparing with the appropriate vmSymbol. Should fix this at some point.
  char* name  = _pdesc->name();
  Expr* res = NULL;
  switch (_pdesc->group()) {
    case IntArithmeticPrimitive:
      if (number_of_parameters() == 2) {
        Expr* x = parameter(0);
        Expr* y = parameter(1);
        if (equal(name, "primitiveAdd:ifFail:"))			{ res = smi_ArithmeticOp(tAddArithOp, x, y);	break; }
        if (equal(name, "primitiveSubtract:ifFail:"))			{ res = smi_ArithmeticOp(tSubArithOp, x, y);	break; }
        if (equal(name, "primitiveMultiply:ifFail:"))			{ res = smi_ArithmeticOp(tMulArithOp, x, y);	break; }
        if (equal(name, "primitiveDiv:ifFail:"))			{ res = smi_Div(x, y);				break; }
        if (equal(name, "primitiveMod:ifFail:"))			{ res = smi_Mod(x, y);				break; }
        if (equal(name, "primitiveBitAnd:ifFail:"))			{ res = smi_BitOp(tAndArithOp, x, y);		break; }
        if (equal(name, "primitiveBitOr:ifFail:"))			{ res = smi_BitOp(tOrArithOp , x, y);		break; }
        if (equal(name, "primitiveBitXor:ifFail:"))			{ res = smi_BitOp(tXOrArithOp, x, y);		break; }
        if (equal(name, "primitiveRawBitShift:ifFail:"))		{ res = smi_Shift(x, y);			break; }
      }
      break;
    case IntComparisonPrimitive:
      if (number_of_parameters() == 2) {
        Expr* x = parameter(0);
        Expr* y = parameter(1);
        if (equal(name, "primitiveSmallIntegerEqual:ifFail:"))		{ res = smi_Comparison(EQBranchOp, x, y);	break; }
        if (equal(name, "primitiveSmallIntegerNotEqual:ifFail:"))	{ res = smi_Comparison(NEBranchOp, x, y);	break; }
        if (equal(name, "primitiveLessThan:ifFail:"))			{ res = smi_Comparison(LTBranchOp, x, y);	break; }
        if (equal(name, "primitiveLessThanOrEqual:ifFail:"))		{ res = smi_Comparison(LEBranchOp, x, y);	break; }
        if (equal(name, "primitiveGreaterThan:ifFail:"))		{ res = smi_Comparison(GTBranchOp, x, y);	break; }
        if (equal(name, "primitiveGreaterThanOrEqual:ifFail:"))		{ res = smi_Comparison(GEBranchOp, x, y);	break; }
      }
      break;
    case FloatArithmeticPrimitive:
      break;
    case FloatComparisonPrimitive:
      break;
    case ObjArrayPrimitive:
      if (equal(name, "primitiveIndexedObjectSize"))			{ res = array_size();						break; }
      if (equal(name, "primitiveIndexedObjectAt:ifFail:"))		{ res = array_at_ifFail(ArrayAtNode::object_at);		break; }
      if (equal(name, "primitiveIndexedObjectAt:put:ifFail:"))		{ res = array_at_put_ifFail(ArrayAtPutNode::object_at_put);	break; }
      break;
    case ByteArrayPrimitive:
      if (equal(name, "primitiveIndexedByteSize"))			{ res = array_size();						break; }
      if (equal(name, "primitiveIndexedByteAt:ifFail:"))		{ res = array_at_ifFail(ArrayAtNode::byte_at);			break; }
      if (equal(name, "primitiveIndexedByteAt:put:ifFail:"))		{ res = array_at_put_ifFail(ArrayAtPutNode::byte_at_put);	break; }
      break;
    case DoubleByteArrayPrimitive:
      if (equal(name, "primitiveIndexedDoubleByteSize"))		{ res = array_size();						break; }
      if (equal(name, "primitiveIndexedDoubleByteAt:ifFail:"))		{ res = array_at_ifFail(ArrayAtNode::double_byte_at);		break; }
      if (equal(name, "primitiveIndexedDoubleByteCharacterAt:ifFail:"))	{ res = array_at_ifFail(ArrayAtNode::character_at);		break; }
      if (equal(name, "primitiveIndexedDoubleByteAt:put:ifFail:"))	{ res = array_at_put_ifFail(ArrayAtPutNode::double_byte_at_put);break; }
      break;
    case BlockPrimitive:
      if (strncmp(name, "primitiveValue", 14) == 0) 			{ res = block_primitiveValue();		break; }
      break;
    case NormalPrimitive:
      if (strncmp(name, "primitiveNew", 12) == 0) 			{ res = obj_new();			break; }
      if (equal(name, "primitiveShallowCopyIfFail:ifFail:"))		{ res = obj_shallowCopy();		break; }
      if (equal(name, "primitiveEqual:"))				{ res = obj_equal();			break; }
      if (equal(name, "primitiveClass"))				{ res = obj_class(true);		break; }
      if (equal(name, "primitiveClassOf:"))				{ res = obj_class(false);		break; }
      if (equal(name, "primitiveHash"))					{ res = obj_hash(true);			break; }
      if (equal(name, "primitiveHashOf:"))				{ res = obj_hash(false);		break; }
      if (equal(name, "primitiveProxyByteAt:ifFail:"))			{ res = proxy_byte_at();		break; }
      if (equal(name, "primitiveProxyByteAt:put:ifFail:"))		{ res = proxy_byte_at_put();		break; }
      break;
   default:
      fatal1("bad primitive group %d", _pdesc->group());
      break;
  }
 
  if (CompilerDebug) {
    cout(PrintInlining && (res != NULL))->print("%*sinlining %s %s\n", _scope->depth + 2, "", _pdesc->name(),
						_usingUncommonTrap ? "(unc. failure)" : (_cannotFail ? "(cannot fail)" :  ""));
  }
  if (!_usingUncommonTrap && !_cannotFail) theCompiler->reporter->report_prim_failure(_pdesc);
  return res;
}