Ejemplo n.º 1
0
Archivo: genfun.c Proyecto: fydot/ponyc
static bool genfun_allocator(compile_t* c, gentype_t* g)
{
  // No allocator for primitive types or pointers.
  if((g->primitive != NULL) || is_pointer(g->ast))
    return true;

  const char* funname = genname_fun(g->type_name, "Alloc", NULL);
  LLVMTypeRef ftype = LLVMFunctionType(g->use_type, NULL, 0, false);
  LLVMValueRef fun = codegen_addfun(c, funname, ftype);
  codegen_startfun(c, fun, false);

  LLVMValueRef result;

  switch(g->underlying)
  {
    case TK_PRIMITIVE:
    case TK_CLASS:
      // Allocate the object or return the global instance.
      result = gencall_alloc(c, g);
      break;

    case TK_ACTOR:
      // Allocate the actor.
      result = gencall_create(c, g);
      break;

    default:
      assert(0);
      return false;
  }

  LLVMBuildRet(c->builder, result);
  codegen_finishfun(c);
  return true;
}
Ejemplo n.º 2
0
Archivo: reach.c Proyecto: DevL/ponyc
static void add_rmethod(reachable_method_stack_t** s,
  reachable_type_t* t, reachable_method_name_t* n, ast_t* typeargs)
{
  const char* name = genname_fun(NULL, n->name, typeargs);
  reachable_method_t* m = reach_method(n, name);

  if(m == NULL)
  {
    m = POOL_ALLOC(reachable_method_t);
    m->name = name;
    m->typeargs = ast_dup(typeargs);
    m->vtable_index = (uint32_t)-1;

    ast_t* fun = lookup(NULL, NULL, t->type, n->name);

    if(typeargs != NULL)
    {
      // Reify the method with its typeargs, if it has any.
      AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, can_error,
        body);

      ast_t* r_fun = reify(fun, typeparams, typeargs);
      ast_free_unattached(fun);
      fun = r_fun;
    }

    m->r_fun = ast_dup(fun);
    ast_free_unattached(fun);

    reachable_methods_put(&n->r_methods, m);

    // Put on a stack of reachable methods to trace.
    *s = reachable_method_stack_push(*s, m);
  }
}
Ejemplo n.º 3
0
Archivo: genfun.c Proyecto: fydot/ponyc
LLVMValueRef genfun_proto(compile_t* c, gentype_t* g, const char *name,
  ast_t* typeargs)
{
  ast_t* fun = get_fun(g, name, typeargs);
  LLVMValueRef func = get_prototype(c, g, name, typeargs, fun);

  // Disable debugloc on calls to methods that have no debug info.
  if(!ast_debug(fun))
    dwarf_location(&c->dwarf, NULL);

  switch(ast_id(fun))
  {
    case TK_NEW:
    case TK_BE:
      if(g->underlying == TK_ACTOR)
      {
        const char* fun_name = genname_fun(g->type_name, name, typeargs);
        const char* be_name = genname_be(fun_name);
        func = LLVMGetNamedFunction(c->module, be_name);
      }
      break;

    default: {}
  }

  ast_free_unattached(fun);
  return func;
}
Ejemplo n.º 4
0
Archivo: genfun.c Proyecto: fydot/ponyc
static LLVMValueRef get_sender(compile_t* c, gentype_t* g, const char* name,
  ast_t* typeargs)
{
  const char* fun_name = genname_fun(g->type_name, name, typeargs);
  const char* be_name = genname_be(fun_name);
  return LLVMGetNamedFunction(c->module, be_name);
}
Ejemplo n.º 5
0
reach_method_t* reach_method(reach_type_t* t, token_id cap,
  const char* name, ast_t* typeargs)
{
  reach_method_name_t* n = reach_method_name(t, name);

  if(n == NULL)
    return NULL;

  if((n->id == TK_FUN) && ((n->cap == TK_BOX) || (n->cap == TK_TAG)))
  {
    switch(cap)
    {
      case TK_ISO:
      case TK_TRN:
        cap = TK_REF;
        break;

      case TK_REF:
      case TK_VAL:
      case TK_BOX:
        break;

      default:
        cap = n->cap;
    }
  } else {
    cap = n->cap;
  }

  name = genname_fun(cap, n->name, typeargs);
  return reach_rmethod(n, name);
}
Ejemplo n.º 6
0
static LLVMValueRef get_prototype(compile_t* c, gentype_t* g, const char *name,
  ast_t* typeargs, ast_t* fun)
{
  // Behaviours and actor constructors also have sender functions.
  bool sender = false;

  switch(ast_id(fun))
  {
    case TK_NEW:
      sender = g->underlying == TK_ACTOR;
      break;

    case TK_BE:
      sender = true;
      break;

    default: {}
  }

  // Get a fully qualified name: starts with the type name, followed by the
  // type arguments, followed by the function name, followed by the function
  // level type arguments.
  const char* funname = genname_fun(g->type_name, name, typeargs);

  // If the function already exists, just return it.
  LLVMValueRef func = LLVMGetNamedFunction(c->module, funname);

  if(func != NULL)
    return func;

  LLVMTypeRef ftype = get_signature(c, g, fun);

  if(ftype == NULL)
    return NULL;

  // If the function exists now, just return it.
  func = LLVMGetNamedFunction(c->module, funname);

  if(func != NULL)
    return func;

  if(sender)
  {
    // Generate the sender prototype.
    const char* be_name = genname_be(funname);
    func = codegen_addfun(c, be_name, ftype);

    // Change the return type to void for the handler.
    size_t count = LLVMCountParamTypes(ftype);
    size_t buf_size = count *sizeof(LLVMTypeRef);
    LLVMTypeRef* tparams = (LLVMTypeRef*)pool_alloc_size(buf_size);
    LLVMGetParamTypes(ftype, tparams);

    ftype = LLVMFunctionType(c->void_type, tparams, (int)count, false);
    pool_free_size(buf_size, tparams);
  }

  // Generate the function prototype.
  return codegen_addfun(c, funname, ftype);
}
Ejemplo n.º 7
0
static void print_method(compile_t* c, printbuf_t* buf, reachable_type_t* t,
  const char* name, ast_t* typeargs)
{
  const char* funname = genname_fun(t->name, name, typeargs);
  LLVMValueRef func = LLVMGetNamedFunction(c->module, funname);

  if(func == NULL)
    return;

  // Get a reified function.
  ast_t* fun = get_fun(t->ast, name, typeargs);

  if(fun == NULL)
    return;

  AST_GET_CHILDREN(fun, cap, id, typeparams, params, rtype, can_error, body,
    docstring);

  // Print the docstring if we have one.
  if(ast_id(docstring) == TK_STRING)
  {
    printbuf(buf,
      "/*\n"
      "%s"
      "*/\n",
      ast_name(docstring)
      );
  }

  // Print the function signature.
  print_type_name(c, buf, rtype);
  printbuf(buf, " %s", funname);

  switch(ast_id(fun))
  {
    case TK_NEW:
    case TK_BE:
    {
      ast_t* def = (ast_t*)ast_data(t->ast);

      if(ast_id(def) == TK_ACTOR)
        printbuf(buf, "__send");

      break;
    }

    default: {}
  }

  printbuf(buf, "(");
  print_type_name(c, buf, t->ast);
  printbuf(buf, " self");

  print_params(c, buf, params);

  printbuf(buf, ");\n\n");
  ast_free_unattached(fun);
}
Ejemplo n.º 8
0
static LLVMValueRef make_vtable(compile_t* c, gentype_t* g)
{
  uint32_t vtable_size = genfun_vtable_size(c, g);

  if(vtable_size == 0)
    return LLVMConstArray(c->void_ptr, NULL, 0);

  size_t buf_size = vtable_size * sizeof(LLVMValueRef);
  LLVMValueRef* vtable = (LLVMValueRef*)pool_alloc_size(buf_size);
  memset(vtable, 0, buf_size);

  reachable_type_t* t = reach_type(c->reachable, g->type_name);

  size_t i = HASHMAP_BEGIN;
  reachable_method_name_t* n;

  while((n = reachable_method_names_next(&t->methods, &i)) != NULL)
  {
    size_t j = HASHMAP_BEGIN;
    reachable_method_t* m;

    while((m = reachable_methods_next(&n->r_methods, &j)) != NULL)
    {
      const char* fullname = genname_fun(t->name, n->name, m->typeargs);
      token_id t = ast_id(m->r_fun);

      switch(t)
      {
        case TK_NEW:
        case TK_BE:
          if(g->underlying == TK_ACTOR)
            fullname = genname_be(fullname);
          break;

        default: {}
      }

      uint32_t index = m->vtable_index;
      assert(index != (uint32_t)-1);
      assert(vtable[index] == NULL);

      if(g->primitive != NULL)
        vtable[index] = make_unbox_function(c, g, fullname, t);
      else
        vtable[index] = make_function_ptr(c, fullname, c->void_ptr);
    }
  }

  for(uint32_t i = 0; i < vtable_size; i++)
  {
    if(vtable[i] == NULL)
      vtable[i] = LLVMConstNull(c->void_ptr);
  }

  LLVMValueRef r = LLVMConstArray(c->void_ptr, vtable, vtable_size);
  pool_free_size(buf_size, vtable);
  return r;
}
Ejemplo n.º 9
0
static void genfun_dwarf(compile_t* c, gentype_t* g, const char *name,
  ast_t* typeargs, ast_t* fun)
{
  if(!codegen_hassource(c))
    return;

  // Get the function.
  const char* funname = genname_fun(g->type_name, name, typeargs);
  LLVMValueRef func = LLVMGetNamedFunction(c->module, funname);
  assert(func != NULL);

  // Count the parameters, including the receiver.
  ast_t* params = ast_childidx(fun, 3);
  size_t count = ast_childcount(params) + 1;

  size_t buf_size = (count + 1) * sizeof(const char*);
  const char** pnames = (const char**)pool_alloc_size(buf_size);
  count = 0;

  // Return value type name and receiver type name.
  pnames[count++] = genname_type(ast_childidx(fun, 4));
  pnames[count++] = g->type_name;

  // Get a type name for each parameter.
  ast_t* param = ast_child(params);

  while(param != NULL)
  {
    ast_t* ptype = ast_childidx(param, 1);
    pnames[count++] = genname_type(ptype);
    param = ast_sibling(param);
  }

  // Dwarf the method type
  dwarf_method(&c->dwarf, fun, name, funname, pnames, count, func);

  // Dwarf the receiver pointer.
  LLVMBasicBlockRef entry = LLVMGetEntryBasicBlock(codegen_fun(c));
  LLVMValueRef argument = codegen_getlocal(c, stringtab("this"));

  dwarf_this(&c->dwarf, fun, g->type_name, entry, argument);

  // Dwarf locals for parameters
  param = ast_child(params);
  size_t index = 1;

  while(param != NULL)
  {
    argument = codegen_getlocal(c, ast_name(ast_child(param)));
    dwarf_parameter(&c->dwarf, param, pnames[index + 1], entry, argument,
      index);
    param = ast_sibling(param);
    index++;
  }

  pool_free_size(buf_size, pnames);
}
Ejemplo n.º 10
0
reachable_method_t* reach_method_instance(reachable_method_name_t* n,
  ast_t* typeargs)
{
  const char* name = n->name;

  if(typeargs != NULL)
    name = genname_fun(NULL, n->name, typeargs);

  reachable_method_t k;
  k.name = name;
  return reachable_methods_get(&n->r_methods, &k);
}
Ejemplo n.º 11
0
Archivo: genfun.c Proyecto: fydot/ponyc
LLVMTypeRef genfun_sig(compile_t* c, gentype_t* g, const char *name,
  ast_t* typeargs)
{
  // If the function already exists, return its type.
  const char* funname = genname_fun(g->type_name, name, typeargs);
  LLVMValueRef func = LLVMGetNamedFunction(c->module, funname);

  if(func != NULL)
    return LLVMGetElementType(LLVMTypeOf(func));

  ast_t* fun = get_fun(g, name, typeargs);
  LLVMTypeRef type = get_signature(c, g, fun);
  ast_free_unattached(fun);
  return type;
}
Ejemplo n.º 12
0
static reach_method_t* add_rmethod(reach_t* r, reach_type_t* t,
  reach_method_name_t* n, token_id cap, ast_t* typeargs, pass_opt_t* opt)
{
  const char* name = genname_fun(cap, n->name, typeargs);
  reach_method_t* m = reach_rmethod(n, name);

  if(m != NULL)
    return m;

  m = POOL_ALLOC(reach_method_t);
  memset(m, 0, sizeof(reach_method_t));
  m->name = name;
  m->cap = cap;
  m->typeargs = ast_dup(typeargs);
  m->vtable_index = (uint32_t)-1;

  ast_t* r_ast = set_cap_and_ephemeral(t->ast, cap, TK_NONE);
  ast_t* fun = lookup(NULL, NULL, r_ast, n->name);
  ast_free_unattached(r_ast);

  if(typeargs != NULL)
  {
    // Reify the method with its typeargs, if it has any.
    AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, can_error,
      body);

    fun = reify(fun, typeparams, typeargs, opt, false);
  }

  m->r_fun = fun;
  set_method_types(r, m, opt);
  m->mangled_name = make_mangled_name(m);
  m->full_name = make_full_name(t, m);

  // Add to both tables.
  reach_methods_put(&n->r_methods, m);
  reach_mangled_put(&n->r_mangled, m);

  // Put on a stack of reachable methods to trace.
  r->stack = reach_method_stack_push(r->stack, m);

  // Add the method to any subtypes.
  add_rmethod_to_subtypes(r, t, n, m, opt);

  return m;
}
Ejemplo n.º 13
0
Archivo: genfun.c Proyecto: fydot/ponyc
static uint32_t vtable_index(compile_t* c, const char* type_name,
  const char* name, ast_t* typeargs)
{
  reachable_type_t* t = reach_type(c->reachable, type_name);

  if(t == NULL)
    return -1;

  reachable_method_name_t* n = reach_method_name(t, name);

  if(n == NULL)
    return -1;

  if(typeargs != NULL)
    name = genname_fun(NULL, name, typeargs);

  reachable_method_t* m = reach_method(n, name);

  if(m == NULL)
    return -1;

  assert(m->vtable_index != (uint32_t)-1);
  return m->vtable_index;
}
Ejemplo n.º 14
0
Archivo: genexe.c Proyecto: volth/ponyc
static void gen_main(compile_t* c, gentype_t* main_g, gentype_t* env_g)
{
  LLVMTypeRef params[3];
  params[0] = c->i32;
  params[1] = LLVMPointerType(LLVMPointerType(c->i8, 0), 0);
  params[2] = LLVMPointerType(LLVMPointerType(c->i8, 0), 0);

  LLVMTypeRef ftype = LLVMFunctionType(c->i32, params, 3, false);
  LLVMValueRef func = LLVMAddFunction(c->module, "main", ftype);

  codegen_startfun(c, func, false);

  LLVMValueRef args[3];
  args[0] = LLVMGetParam(func, 0);
  LLVMSetValueName(args[0], "argc");

  args[1] = LLVMGetParam(func, 1);
  LLVMSetValueName(args[1], "argv");

  args[2] = LLVMGetParam(func, 2);
  LLVMSetValueName(args[1], "envp");

  // Initialise the pony runtime with argc and argv, getting a new argc.
  args[0] = gencall_runtime(c, "pony_init", args, 2, "argc");

  // Create the main actor and become it.
  LLVMValueRef main_actor = create_main(c, main_g);

  // Create an Env on the main actor's heap.
  const char* env_name = "Env";
  const char* env_create = genname_fun(env_name, "_create", NULL);

  LLVMValueRef env_args[4];
  env_args[0] = gencall_alloc(c, env_g);
  env_args[1] = LLVMBuildZExt(c->builder, args[0], c->i64, "");
  env_args[2] = args[1];
  env_args[3] = args[2];

  LLVMValueRef env = gencall_runtime(c, env_create, env_args, 4, "env");
  LLVMSetInstructionCallConv(env, GEN_CALLCONV);

  // Run primitive initialisers using the main actor's heap.
  primitive_call(c, stringtab("_init"), env);

  // Create a type for the message.
  LLVMTypeRef f_params[4];
  f_params[0] = c->i32;
  f_params[1] = c->i32;
  f_params[2] = c->void_ptr;
  f_params[3] = LLVMTypeOf(env);
  LLVMTypeRef msg_type = LLVMStructTypeInContext(c->context, f_params, 4,
    false);
  LLVMTypeRef msg_type_ptr = LLVMPointerType(msg_type, 0);

  // Allocate the message, setting its size and ID.
  uint32_t index = genfun_vtable_index(c, main_g, stringtab("create"), NULL);

  size_t msg_size = LLVMABISizeOfType(c->target_data, msg_type);
  args[0] = LLVMConstInt(c->i32, pool_index(msg_size), false);
  args[1] = LLVMConstInt(c->i32, index, false);
  LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", args, 2, "");
  LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, "");

  // Set the message contents.
  LLVMValueRef env_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, 3, "");
  LLVMBuildStore(c->builder, env, env_ptr);

  // Trace the message.
  gencall_runtime(c, "pony_gc_send", NULL, 0, "");
  const char* env_trace = genname_trace(env_name);

  args[0] = LLVMBuildBitCast(c->builder, env, c->object_ptr, "");
  args[1] = LLVMGetNamedFunction(c->module, env_trace);
  gencall_runtime(c, "pony_traceobject", args, 2, "");
  gencall_runtime(c, "pony_send_done", NULL, 0, "");

  // Send the message.
  args[0] = main_actor;
  args[1] = msg;
  gencall_runtime(c, "pony_sendv", args, 2, "");

  // Start the runtime.
  LLVMValueRef zero = LLVMConstInt(c->i32, 0, false);
  LLVMValueRef rc = gencall_runtime(c, "pony_start", &zero, 1, "");

  // Run primitive finalisers. We create a new main actor as a context to run
  // the finalisers in, but we do not initialise or schedule it.
  LLVMValueRef final_actor = create_main(c, main_g);
  primitive_call(c, stringtab("_final"), NULL);
  args[0] = final_actor;
  gencall_runtime(c, "pony_destroy", args, 1, "");

  // Return the runtime exit code.
  LLVMBuildRet(c->builder, rc);

  codegen_finishfun(c);

  // External linkage for main().
  LLVMSetLinkage(func, LLVMExternalLinkage);
}