From e12b16cde7ecc4075a105f4e4b128f63c0c03c8d Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Mon, 14 May 2012 17:57:39 -0700 Subject: [PATCH] Instantiate per-type iface-based visit_glue when intrinsic ifaces present. --- src/rustc/back/abi.rs | 2 +- src/rustc/middle/trans/base.rs | 41 +++++++++++++- src/rustc/middle/trans/common.rs | 8 ++- src/rustc/middle/trans/native.rs | 76 ++++++++----------------- src/rustc/middle/trans/reflect.rs | 93 +++++++++++++++++++++++++++++++ src/rustc/rustc.rc | 1 + 6 files changed, 161 insertions(+), 60 deletions(-) create mode 100644 src/rustc/middle/trans/reflect.rs diff --git a/src/rustc/back/abi.rs b/src/rustc/back/abi.rs index 70606d9f885a..3808621096fb 100644 --- a/src/rustc/back/abi.rs +++ b/src/rustc/back/abi.rs @@ -39,7 +39,7 @@ const tydesc_field_align: uint = 2u; const tydesc_field_take_glue: uint = 3u; const tydesc_field_drop_glue: uint = 4u; const tydesc_field_free_glue: uint = 5u; -const tydesc_field_unused: uint = 6u; +const tydesc_field_visit_glue: uint = 6u; const tydesc_field_sever_glue: uint = 7u; const tydesc_field_mark_glue: uint = 8u; const tydesc_field_unused2: uint = 9u; diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 0136570a68ab..769fee50d4f9 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -470,7 +470,8 @@ fn declare_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info { align: llalign, mut take_glue: none, mut drop_glue: none, - mut free_glue: none}; + mut free_glue: none, + mut visit_glue: none}; log(debug, "--- declare_tydesc " + ty_to_str(ccx.tcx, t)); ret inf; } @@ -552,6 +553,11 @@ fn emit_tydescs(ccx: @crate_ctxt) { none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) } some(v) { ccx.stats.n_real_glues += 1u; v } }; + let visit_glue = + alt ti.visit_glue { + none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) } + some(v) { ccx.stats.n_real_glues += 1u; v } + }; let shape = shape_of(ccx, key, []); let shape_tables = @@ -566,7 +572,7 @@ fn emit_tydescs(ccx: @crate_ctxt) { take_glue, // take_glue drop_glue, // drop_glue free_glue, // free_glue - C_null(T_ptr(T_i8())), // unused + visit_glue, // visit_glue C_null(glue_fn_ty), // sever_glue C_null(glue_fn_ty), // mark_glue C_null(glue_fn_ty), // unused @@ -632,6 +638,20 @@ fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) { Store(cx, rc, rc_ptr); } +fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) { + let _icx = bcx.insn_ctxt("make_visit_glue"); + let mut bcx = bcx; + alt bcx.ccx().intrinsic_ifaces.find("visit_ty") { + some(iid) { + bcx = reflect::emit_calls_to_iface_visit_ty(bcx, t, v, iid); + } + none { + } + } + build_return(bcx); +} + + fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) { // v is a pointer to the actual box component of the type here. The // ValueRef will have the wrong type here (make_generic_glue is casting @@ -1065,7 +1085,23 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint, ty_to_str(ccx.tcx, ti.ty)); } } + } else if field == abi::tydesc_field_visit_glue { + alt ti.free_glue { + some(_) { } + none { + #debug("+++ lazily_emit_tydesc_glue VISIT %s", + ty_to_str(ccx.tcx, ti.ty)); + let glue_fn = + declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), "visit"); + ti.visit_glue = some(glue_fn); + make_generic_glue(ccx, ti.ty, glue_fn, + make_visit_glue, "visit"); + #debug("--- lazily_emit_tydesc_glue VISIT %s", + ty_to_str(ccx.tcx, ti.ty)); + } + } } + } } } @@ -5056,6 +5092,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt, tn: tn, externs: str_hash::(), intrinsics: intrinsics, + intrinsic_ifaces: reflect::find_intrinsic_ifaces(crate), item_vals: int_hash::(), exp_map: emap, reachable: reachable, diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs index 72e982ba4450..ad2b86f395b4 100644 --- a/src/rustc/middle/trans/common.rs +++ b/src/rustc/middle/trans/common.rs @@ -33,7 +33,8 @@ type tydesc_info = align: ValueRef, mut take_glue: option, mut drop_glue: option, - mut free_glue: option}; + mut free_glue: option, + mut visit_glue: option}; /* * A note on nomenclature of linking: "upcall", "extern" and "native". @@ -70,6 +71,7 @@ type crate_ctxt = { tn: type_names, externs: hashmap, intrinsics: hashmap, + intrinsic_ifaces: hashmap, item_vals: hashmap, exp_map: resolve::exp_map, reachable: reachable::map, @@ -572,8 +574,8 @@ fn T_tydesc(targ_cfg: @session::config) -> TypeRef { let int_type = T_int(targ_cfg); let elems = [tydescpp, int_type, int_type, - glue_fn_ty, glue_fn_ty, glue_fn_ty, - T_ptr(T_i8()), glue_fn_ty, glue_fn_ty, glue_fn_ty, T_ptr(T_i8()), + glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty, + glue_fn_ty, glue_fn_ty, glue_fn_ty, T_ptr(T_i8()), T_ptr(T_i8()), T_ptr(T_i8()), int_type, int_type]; set_struct_body(tydesc, elems); ret tydesc; diff --git a/src/rustc/middle/trans/native.rs b/src/rustc/middle/trans/native.rs index f5b1a59d15fa..ed5b769ce50d 100644 --- a/src/rustc/middle/trans/native.rs +++ b/src/rustc/middle/trans/native.rs @@ -835,70 +835,38 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::native_item, fcx.llretptr); } "visit_ty" { - - // signature: fn visit_ty(tv: V); - let tp_ty = substs.tys[0]; let vp_ty = substs.tys[1]; let visitor = get_param(decl, first_real_arg); - let (tyname, args) = alt ty::get(tp_ty).struct { - ty::ty_bot { ("bot", []) } - ty::ty_nil { ("nil", []) } - ty::ty_bool { ("bool", []) } - ty::ty_int(ast::ty_i) { ("int", []) } - ty::ty_int(ast::ty_char) { ("char", []) } - ty::ty_int(ast::ty_i8) { ("i8", []) } - ty::ty_int(ast::ty_i16) { ("i16", []) } - ty::ty_int(ast::ty_i32) { ("i32", []) } - ty::ty_int(ast::ty_i64) { ("i64", []) } - ty::ty_uint(ast::ty_u) { ("uint", []) } - ty::ty_uint(ast::ty_u8) { ("u8", []) } - ty::ty_uint(ast::ty_u16) { ("u16", []) } - ty::ty_uint(ast::ty_u32) { ("u32", []) } - ty::ty_uint(ast::ty_u64) { ("u64", []) } - ty::ty_float(ast::ty_f) { ("float", []) } - ty::ty_float(ast::ty_f32) { ("f32", []) } - ty::ty_float(ast::ty_f64) { ("f64", []) } - ty::ty_str { ("str", []) } - _ { - bcx.sess().unimpl("trans::native::visit_ty on " - + ty_to_str(ccx.tcx, tp_ty)); - } - }; - - let mth_name = "visit_" + tyname; - let dest = ignore; - alt impl::find_vtable_in_fn_ctxt(substs, 1u, /* n_param */ 0u /* n_bound */ ) { - typeck::vtable_static(impl_did, impl_substs, sub_origins) { - let mth_id = impl::method_with_name(ccx, impl_did, mth_name); - let mth_ty = ty::lookup_item_type(ccx.tcx, mth_id).ty; - // FIXME: is this safe? There is no callee AST node, - // we're synthesizing it. - let callee_id = (-1) as ast::node_id; - let get_lval = {|bcx| - let lval = lval_static_fn_inner(bcx, mth_id, callee_id, - impl_substs, - some(sub_origins)); - {env: self_env(visitor, vp_ty, none) with lval} - }; - bcx = trans_call_inner(bcx, mth_ty, ty::mk_bool(ccx.tcx), - get_lval, arg_vals(args), dest); + typeck::vtable_iface(iid, _) { + bcx = reflect::emit_calls_to_iface_visit_ty(bcx, tp_ty, + visitor, iid); } - typeck::vtable_iface(iid, _tps) { - let methods = ty::iface_methods(ccx.tcx, iid); - let mth_idx = option::get(ty::method_idx(mth_name, *methods)); - let mth_ty = ty::mk_fn(ccx.tcx, methods[mth_idx].fty); - let get_lval = {|bcx| - impl::trans_iface_callee(bcx, visitor, mth_ty, mth_idx) - }; - bcx = trans_call_inner(bcx, mth_ty, ty::mk_bool(ccx.tcx), - get_lval, arg_vals(args), dest); + // This case is a slightly weird and possibly redundant path in + // which we monomorphize the reflection interface. FIXME: + // possibly remove this, it might be overkill. + typeck::vtable_static(impl_did, impl_substs, sub_origins) { + reflect::visit_ty_steps(bcx, tp_ty) {|mth_name, args| + let mth_id = impl::method_with_name(ccx, impl_did, mth_name); + let mth_ty = ty::lookup_item_type(ccx.tcx, mth_id).ty; + // FIXME: is this safe? There is no callee AST node, + // we're synthesizing it. + let callee_id = (-1) as ast::node_id; + let get_lval = {|bcx| + let lval = lval_static_fn_inner(bcx, mth_id, callee_id, + impl_substs, + some(sub_origins)); + {env: self_env(visitor, vp_ty, none) with lval} + }; + bcx = trans_call_inner(bcx, mth_ty, ty::mk_bool(ccx.tcx), + get_lval, arg_vals(args), ignore); + } } _ { diff --git a/src/rustc/middle/trans/reflect.rs b/src/rustc/middle/trans/reflect.rs new file mode 100644 index 000000000000..b1650ef465bf --- /dev/null +++ b/src/rustc/middle/trans/reflect.rs @@ -0,0 +1,93 @@ +import std::map::{hashmap,str_hash}; +import driver::session::session; +import lib::llvm::{TypeRef, ValueRef}; +import syntax::ast; +import back::abi; +import common::*; +import build::*; +import base::*; +import type_of::*; +import ast::def_id; +import util::ppaux::ty_to_str; + +fn visit_ty_steps(bcx: block, t: ty::t, + step: fn(tyname: str, args: [ValueRef]) -> T) -> T { + alt ty::get(t).struct { + ty::ty_bot { step("visit_bot", []) } + ty::ty_nil { step("visit_nil", []) } + ty::ty_bool { step("visit_bool", []) } + ty::ty_int(ast::ty_i) { step("visit_int", []) } + ty::ty_int(ast::ty_char) { step("visit_char", []) } + ty::ty_int(ast::ty_i8) { step("visit_i8", []) } + ty::ty_int(ast::ty_i16) { step("visit_i16", []) } + ty::ty_int(ast::ty_i32) { step("visit_i32", []) } + ty::ty_int(ast::ty_i64) { step("visit_i64", []) } + ty::ty_uint(ast::ty_u) { step("visit_uint", []) } + ty::ty_uint(ast::ty_u8) { step("visit_u8", []) } + ty::ty_uint(ast::ty_u16) { step("visit_u16", []) } + ty::ty_uint(ast::ty_u32) { step("visit_u32", []) } + ty::ty_uint(ast::ty_u64) { step("visit_u64", []) } + ty::ty_float(ast::ty_f) { step("visit_float", []) } + ty::ty_float(ast::ty_f32) { step("visit_f32", []) } + ty::ty_float(ast::ty_f64) { step("visit_f64", []) } + ty::ty_str { step("visit_str", []) } + _ { + bcx.sess().unimpl("trans::reflect::visit_ty_args on " + + ty_to_str(bcx.ccx().tcx, t)); + } + } +} + +// Emit a sequence of calls to visit_ty::visit_foo +fn emit_calls_to_iface_visit_ty(bcx: block, t: ty::t, + visitor_val: ValueRef, + visitor_iid: def_id) -> block { + let tcx = bcx.tcx(); + visit_ty_steps(bcx, t) {|mth_name, args| + let methods = ty::iface_methods(tcx, visitor_iid); + let mth_idx = option::get(ty::method_idx(mth_name, *methods)); + let mth_ty = ty::mk_fn(tcx, methods[mth_idx].fty); + let get_lval = {|bcx| + impl::trans_iface_callee(bcx, visitor_val, mth_ty, mth_idx) + }; + trans_call_inner(bcx, mth_ty, ty::mk_bool(tcx), + get_lval, arg_vals(args), ignore) + } +} + + +fn find_intrinsic_ifaces(crate: @ast::crate) + -> hashmap { + + let ifaces : hashmap = str_hash(); + + // FIXME: hooking into the "intrinsic" root module is crude. + // there ought to be a better approach. Attributes? + + for crate.node.module.items.each {|crate_item| + if crate_item.ident == "intrinsic" { + alt crate_item.node { + ast::item_mod(m) { + for m.items.each {|intrinsic_item| + alt intrinsic_item.node { + ast::item_iface(_, _, _) { + let def_id = { crate: ast::local_crate, + node: intrinsic_item.id }; + ifaces.insert(intrinsic_item.ident, + def_id); + } + _ { } + } + } + } + _ { } + } + break; + } + } + + // Assert whatever ifaces we are expecting to get from mod intrinsic. + // assert ifaces.contains_key("visit_ty"); + + ret ifaces; +} \ No newline at end of file diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc index 41635f8fec77..21623f45f5c6 100644 --- a/src/rustc/rustc.rc +++ b/src/rustc/rustc.rc @@ -42,6 +42,7 @@ mod middle { mod tvec; mod impl; mod native; + mod reflect; mod shape; mod debuginfo; mod type_use;