@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) --lib -o $$@ $$< && touch $$@
-$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_RUNTIME): \
- rt/$(2)/$$(CFG_RUNTIME)
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_RUSTLLVM): \
rustllvm/$(2)/$$(CFG_RUSTLLVM)
@$$(call E, cp: $$@)
endef
+# The stage0 (snapshot) compiler produces binaries that expect the
+# snapshot runtime. Therefore, the stage1 compiler and libraries
+# (which are produced by stage0) should use the runtime from the
+# snapshot. The stage2 compiler and libraries (which are produced by
+# stage1) will be the first that are expecting to run against the
+# runtime as defined in the working directory.
+#
+# Arguments are the same as for TARGET_BASE_STAGE_N
+define TARGET_RT_FROM_SNAPSHOT
+
+$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_RUNTIME): \
+ $$(HLIB$(1)_H_$(3))/$$(CFG_RUNTIME)
+ @$$(call E, cp: $$@)
+ $$(Q)cp $$< $$@
+
+endef
+
+# This rule copies from the runtime for the working directory. It
+# applies to targets produced by stage1 or later. See comment on
+# previous rule.
+#
+# Arguments are the same as for TARGET_BASE_STAGE_N
+define TARGET_RT_FROM_WD
+
+$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_RUNTIME): \
+ rt/$(2)/$$(CFG_RUNTIME)
+ @$$(call E, cp: $$@)
+ $$(Q)cp $$< $$@
+
+endef
+
# In principle, each host can build each target:
$(foreach source,$(CFG_TARGET_TRIPLES), \
$(foreach target,$(CFG_TARGET_TRIPLES), \
- $(eval $(call TARGET_STAGE_N,0,$(source),$(target))) \
- $(eval $(call TARGET_STAGE_N,1,$(source),$(target))) \
- $(eval $(call TARGET_STAGE_N,2,$(source),$(target))) \
- $(eval $(call TARGET_STAGE_N,3,$(source),$(target)))))
+ $(eval $(call TARGET_STAGE_N,0,$(target),$(source))) \
+ $(eval $(call TARGET_STAGE_N,1,$(target),$(source))) \
+ $(eval $(call TARGET_STAGE_N,2,$(target),$(source))) \
+ $(eval $(call TARGET_STAGE_N,3,$(target),$(source)))))
+
+$(eval $(call TARGET_RT_FROM_SNAPSHOT,0,$(CFG_HOST_TRIPLE),$(CFG_HOST_TRIPLE)))
+
+$(foreach source,$(CFG_TARGET_TRIPLES), \
+ $(foreach target,$(CFG_TARGET_TRIPLES), \
+ $(eval $(call TARGET_RT_FROM_WD,1,$(target),$(source))) \
+ $(eval $(call TARGET_RT_FROM_WD,2,$(target),$(source))) \
+ $(eval $(call TARGET_RT_FROM_WD,3,$(target),$(source)))))
-> @block_ctxt {
// Easy cases:
alt ck {
- ty::closure_block. { ret bcx; }
- ty::closure_shared. { ret incr_refcnt_of_boxed(bcx, Load(bcx, cboxptr)); }
+ ty::closure_block. {
+ ret bcx;
+ }
+ ty::closure_shared. {
+ ret incr_refcnt_of_boxed(bcx, Load(bcx, cboxptr));
+ }
ty::closure_send. { /* hard case: */ }
}
// Copy in the type parameters.
check type_is_tup_like(l_bcx, cboxptr_ty);
let {bcx: l_bcx, val: param_record} =
- GEP_tup_like(l_bcx, cboxptr_ty, llclosure, [0, abi::cbox_elt_ty_params]);
+ GEP_tup_like(l_bcx, cboxptr_ty, llclosure,
+ [0, abi::cbox_elt_ty_params]);
let off = 0;
for param in param_bounds {
let dsc = Load(l_bcx, GEPi(l_bcx, param_record, [0, off])),
#include "rust_internal.h"
+#include "rust_util.h"
#include <cstdio>
struct
#include "rust_internal.h"
#include "rust_scheduler.h"
#include "rust_task.h"
+#include "rust_util.h"
#if !defined(__WIN32__)
#include <sys/time.h>
return rust_scheduler::get_task();
}
-struct fn_env_pair {
- spawn_fn f;
- rust_boxed_closure *env;
-};
-
extern "C" CDECL void
start_task(rust_task_id id, fn_env_pair *f) {
rust_task *task = rust_scheduler::get_task();
~rust_timer();
};
-#include "rust_util.h"
-
typedef void CDECL (glue_fn)(void *, void *,
const type_desc **, void *);
typedef void CDECL (cmp_glue_fn)(void *, void *,
uint8_t *resources;
};
+struct rust_opaque_closure;
+
+// The type of functions that we spawn, which fall into two categories:
+// - the main function: has a NULL environment, but uses the void* arg
+// - unique closures of type fn~(): have a non-NULL environment, but
+// no arguments (and hence the final void*) is harmless
+typedef void (*CDECL spawn_fn)(void*, rust_opaque_closure*, void *);
+
+// corresponds to the layout of a fn(), fn@(), fn~() etc
+struct fn_env_pair {
+ spawn_fn f;
+ rust_opaque_closure *env;
+};
+
+// corresponds the closures generated in trans_closure.rs
+struct rust_opaque_closure {
+ intptr_t ref_count;
+ const type_desc *td;
+ // The size/types of these will vary per closure, so they
+ // cannot be statically expressed. See trans_closure.rs:
+ const type_desc *captured_tds[0];
+ // struct bound_data;
+};
+
struct type_desc {
// First part of type_desc is known to compiler.
// first_param = &descs[1] if dynamic, null if static.
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
#include "rust_internal.h"
+#include "rust_util.h"
#define KLOG_(...) \
KLOG(this, kern, __VA_ARGS__)
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
#include <cassert>
#include <pthread.h>
#include "rust_internal.h"
+#include "rust_util.h"
#include "globals.h"
#ifndef _WIN32
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
// Constructs type parameters from a function shape. This is a bit messy,
// because it requires that the function shape have a specific format.
type_param *
-type_param::from_fn_shape(const uint8_t *sp, ptr dp, arena &arena) {
- const type_desc *tydesc = bump_dp<const type_desc *>(dp);
- const type_desc **tydescs = (const type_desc **)dp;
- unsigned n_tydescs = tydesc->n_obj_params & 0x7fffffff;
- for (unsigned i = 0; i < n_tydescs; i++)
- bump_dp<const type_desc*>(dp);
- return make(tydescs, n_tydescs, arena);
+type_param::from_fn_shape(rust_opaque_closure *env, arena &arena) {
+ unsigned n_tydescs = env->td->n_obj_params & 0x7fffffff;
+ return make(env->captured_tds, n_tydescs, arena);
}
// Constructs type parameters from an object shape. This is also a bit messy,
#include <iostream>
#include "rust_internal.h"
+#include "rust_util.h"
// ISAAC pollutes our namespace.
#undef align
const type_param *params; // subparameters
// Constructs type parameters from a function shape.
- static type_param *from_fn_shape(const uint8_t *sp, ptr dp, arena &arena);
+ static type_param *from_fn_shape(rust_opaque_closure *env, arena &arena);
// Creates type parameters from an object shape description.
static type_param *from_obj_shape(const uint8_t *sp, ptr dp,
arena &arena);
template<typename T,typename U>
void
data<T,U>::walk_fn_contents(ptr &dp) {
- dp += sizeof(void *); // Skip over the code pointer.
-
- uint8_t *box_ptr = bump_dp<uint8_t *>(dp);
- if (!box_ptr)
+ fn_env_pair pair = bump_dp<fn_env_pair>(dp);
+ if (!pair.env)
return;
- type_desc *subtydesc =
- *reinterpret_cast<type_desc **>(box_ptr + sizeof(void *));
- ptr closure_dp(box_ptr + sizeof(void *));
-
arena arena;
- type_param *params = type_param::from_fn_shape(subtydesc->shape,
- closure_dp, arena);
-
- closure_dp += sizeof(void *);
- T sub(*static_cast<T *>(this), subtydesc->shape, params,
- subtydesc->shape_tables, closure_dp);
+ type_param *params =
+ type_param::from_fn_shape(pair.env, arena);
+ const type_desc *closure_td = pair.env->td;
+ ptr closure_dp((uintptr_t)pair.env);
+ T sub(*static_cast<T *>(this), closure_td->shape, params,
+ closure_td->shape_tables, closure_dp);
sub.align = true;
sub.walk();
}
struct spawn_args {
rust_task *task;
spawn_fn f;
- rust_boxed_closure *envptr;
+ rust_opaque_closure *envptr;
void *argptr;
};
failed = true;
}
- rust_boxed_closure* boxed_env = (rust_boxed_closure*)a->envptr;
- if(boxed_env) {
+ rust_opaque_closure* env = a->envptr;
+ if(env) {
// free the environment.
- const type_desc *td = boxed_env->closure.td;
- td->drop_glue(NULL, NULL, td->first_param, &boxed_env->closure);
- upcall_shared_free(boxed_env);
+ const type_desc *td = env->td;
+ LOG(task, task, "Freeing env %p with td %p", env, td);
+ td->drop_glue(NULL, NULL, td->first_param, env);
+ upcall_shared_free(env);
}
// The cleanup work needs lots of stack
void
rust_task::start(spawn_fn spawnee_fn,
- rust_boxed_closure *envptr,
+ rust_opaque_closure *envptr,
void *argptr)
{
LOG(this, task, "starting task from fn 0x%" PRIxPTR
rust_port_id port;
};
-struct rust_closure {
- const type_desc *td;
- // ... see trans_closure.rs for full description ...
-};
-
-struct rust_boxed_closure {
- intptr_t ref_count;
- rust_closure closure;
-};
-
-typedef void (*CDECL spawn_fn)(void*, rust_boxed_closure*, void *);
-
struct rust_box;
struct stk_seg {
~rust_task();
void start(spawn_fn spawnee_fn,
- rust_boxed_closure *env,
+ rust_opaque_closure *env,
void *args);
void start();
bool running();
#include "rust_scheduler.h"
#include "rust_unwind.h"
#include "rust_upcall.h"
+#include "rust_util.h"
#include <stdint.h>
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
return true;
}
-void task_entry(void *, rust_boxed_closure *, void *) {
+void task_entry(void *, rust_opaque_closure *, void *) {
printf("task entry\n");
}
#[test]
fn spawn_polymorphic() {
- fn foo<send T>(x: T) { log(error, x); }
+ fn foo<T:send>(x: T) { log(error, x); }
task::spawn {|| foo(true);};
task::spawn {|| foo(42);};
}