-
Notifications
You must be signed in to change notification settings - Fork 55
/
Copy pathmercury_ho_call.h
205 lines (180 loc) · 8.98 KB
/
mercury_ho_call.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// vim: ts=4 sw=4 expandtab ft=c
// Copyright (C) 1999-2003, 2005-2006 The University of Melbourne.
// Copyright (C) 2014, 2016, 2018 The Mercury team.
// This file is distributed under the terms specified in COPYING.LIB.
// mercury_ho_call.h - defines the structure of closures.
//
// The places in the system that know about the layouts of closures are
//
// compiler/unify_gen.m (unify_gen__generate_construction_2)
// runtime/mercury_ho_call.[ch]
//
// Any changes here will need to be reflected in the other places as well.
#ifndef MERCURY_HO_CALL_H
#define MERCURY_HO_CALL_H
#include "mercury_stack_layout.h" // for MR_ClosureId etc
#include "mercury_type_info.h" // for MR_PseudoTypeInfo
#include "mercury_types.h" // for MR_Closure
#ifndef MR_HIGHLEVEL_CODE
#include "mercury_goto.h" // for MR_declare_entry
#ifdef MR_DO_CALL_STATS
#include <stdio.h> // for FILE
#endif
#endif
// A closure layout structure identifies a procedure, and contains
// the information required to identify the types of the arguments
// in any closure that calls that procedure. It is represented as a
// vector of words containing
//
// a pointer to an MR_ClosureId structure
// a pointer to information about the locations of typeinfos
// for the type parameters of the procedure
// (NULL if there are no type parameters)
// one word giving the number of arguments of the procedure (M)
// M words giving pseudotypeinfos for the arguments
//
// A closure that refers to the procedure may not (and probably will not)
// contain values for all the arguments of the procedure, but the closure
// layout structure has information about all arguments. This is to make
// the creation of a closure from another closure by adding some more
// hidden arguments as fast as possible.
//
// Without float registers, there is no problem in finding out which
// pseudotypeinfo describes which hidden argument, because if the closure
// contains n hidden arguments, these must be the first n arguments of the
// procedure. With float registers, the hidden arguments are reordered so that
// float register arguments come after the regular register arguments. To tell
// if an argument is passed via a float register, check if the pseudotypeinfo
// is MR_FLOAT_CTOR_ADDR. If a float argument is passed via a regular register,
// the pseudotypeinfo must be replaced by the type_ctor_info for
// private_builtin.float_box.
//
// The typeinfo and typeclassinfo arguments describing the actual types bound
// to type vars are always at the start of the argument list. A closure can
// contain arg i but not arg j only if i < j; this means that if a closure
// contains a non-typeinfo argument j, it also contains all the typeinfo
// and typeclassinfo arguments of the procedure and therefore (directly or
// indirectly) all the typeinfos that may be referred to in the pseudotypeinfo
// for argument j. (If we ever allow code to take the address of a procedure
// whose signature includes an existential type, we may have to rethink this.)
//
// The MR_Live_Lvals inside MR_TypeParamLocns, which encode the locations
// of the typeinfos for the type variables in the signature of the procedure,
// assume that argument i is in register ri. While this will be true at the
// time of the call, code that wants to manipulate the closure as an
// independent entity will have to substitute the argument vector in the
// closure itself for the register file.
//
// Note that if a module is compiled without typeinfo liveness, then closures
// will not have any layout information. This will be indicated by the value
// of num_all_args being negative, which says that the only field of this
// structure containing valid information is proc_id.
//
// The Dyn_Link variant is for closures created by browser/dl.m. The closure_id
// field of such closures will contain an invalid proc_id (which you can tell
// from the negative arity) and a creation context that is also different from
// other closures: instead of specifying the source context where the closure
// is created, it puts a sequence number into the field that normally contains
// the line number.
typedef struct MR_Closure_Layout_Struct {
MR_ClosureId *MR_closure_id;
MR_TypeParamLocns *MR_closure_type_params;
MR_Integer MR_closure_num_all_args;
MR_PseudoTypeInfo MR_closure_arg_pseudo_type_info[MR_VARIABLE_SIZED];
} MR_Closure_Layout;
typedef struct MR_Closure_Dyn_Link_Layout_Struct {
MR_ClosureId *MR_closure_dl_id;
MR_TypeParamLocns *MR_closure_dl_type_params;
MR_Integer MR_closure_dl_num_all_args;
} MR_Closure_Dyn_Link_Layout;
// A closure is a vector of words containing:
//
// one word pointing to the closure layout structure of the procedure
// one word pointing to the code of the procedure
// one word giving the number of hidden arguments: (R | F<<16)
// R words representing the R hidden regular register arguments
// F words representing the F hidden float register arguments (in boxed form)
//
// The num_hidden_args_rf field holds the number of arguments to place into
// regular registers in the lower 16-bits, and the number of arguments to place
// into float registers in the high bits. If float registers are not used
// then F = 0 so num_hidden_args_rf = R.
//
// The reason why the closure layout pointer is first is that most operations
// on closures do not need to access that word, and this way it does not
// have be brought into the cache.
//
// Note that the arguments are numbered from one, but the array subscripts
// start at zero. To prevent this from being a problem, we use a deliberately
// ugly name for the field containing the array, and provide a nicer way of
// referring to the array via a macro. The arguments of this macro number
// the arguments from one.
struct MR_Closure_Struct {
MR_Closure_Layout *MR_closure_layout;
MR_Code *MR_closure_code;
MR_Unsigned MR_closure_num_hidden_args_rf;
MR_Word MR_closure_hidden_args_0[MR_VARIABLE_SIZED];
};
// in mercury_types.h: typedef struct MR_Closure_Struct MR_Closure;
#if !defined(MR_HIGHLEVEL_CODE) && defined(MR_BOXED_FLOAT)
#define MR_MAY_REORDER_CLOSURE_HIDDEN_ARGS
#define MR_closure_num_hidden_r_args(c) \
((c)->MR_closure_num_hidden_args_rf & 0xffff)
#define MR_closure_num_hidden_f_args(c) \
((c)->MR_closure_num_hidden_args_rf >> 16)
#else
#define MR_closure_num_hidden_r_args(c) \
((c)->MR_closure_num_hidden_args_rf)
#define MR_closure_num_hidden_f_args(c) 0
#endif
#define MR_closure_hidden_args(i) MR_closure_hidden_args_0[(i) - 1]
#ifndef MR_HIGHLEVEL_CODE
#ifdef MR_DO_CALL_STATS
extern void MR_print_hidden_arg_stats(FILE *fp);
#endif
#endif
// Build a closure for the given procedure address.
// This is used by browser/dl.m.
// MR_make_closure allocates heap, so call MR_{save,restore}_transient_hp()
// around calls to it.
extern MR_Closure *MR_make_closure(MR_Code *address);
#ifdef MR_HIGHLEVEL_CODE
// Function declarations.
MR_bool MR_CALL mercury__builtin__unify_2_p_0(MR_Mercury_Type_Info,
MR_Box, MR_Box);
void MR_CALL mercury__builtin__compare_3_p_0(MR_Mercury_Type_Info,
MR_Comparison_Result *, MR_Box, MR_Box);
void MR_CALL mercury__builtin__compare_3_p_1(MR_Mercury_Type_Info,
MR_Comparison_Result *, MR_Box, MR_Box);
void MR_CALL mercury__builtin__compare_3_p_2(MR_Mercury_Type_Info,
MR_Comparison_Result *, MR_Box, MR_Box);
void MR_CALL mercury__builtin__compare_3_p_3(MR_Mercury_Type_Info,
MR_Comparison_Result *, MR_Box, MR_Box);
void MR_CALL mercury__builtin__compare_representation_3_p_0(
MR_Mercury_Type_Info, MR_Comparison_Result *,
MR_Box, MR_Box);
#else // ! MR_HIGHLEVEL_CODE
MR_declare_entry(mercury__builtin__unify_2_0);
MR_declare_entry(mercury__builtin__compare_3_0);
MR_declare_entry(mercury__builtin__compare_3_1);
MR_declare_entry(mercury__builtin__compare_3_2);
MR_declare_entry(mercury__builtin__compare_3_3);
MR_declare_entry(mercury__builtin__compare_representation_3_0);
#endif // MR_HIGHLEVEL_CODE
// Special predicates implemented in the standard library
// The structure is initialized by init_runtime_hooks in builtin.m.
typedef struct MR_SpecialPredHooks_Struct {
#ifdef MR_HIGHLEVEL_CODE
MR_bool MR_CALL (*MR_unify_tuple_pred)(MR_Word ti, MR_Word x, MR_Word y);
void MR_CALL (*MR_compare_tuple_pred)(MR_Word ti, MR_Word *res,
MR_Word x, MR_Word y);
void MR_CALL (*MR_compare_rep_tuple_pred)(MR_Word ti, MR_Word *res,
MR_Word x, MR_Word y);
#else
MR_Code *MR_unify_tuple_pred;
MR_Code *MR_compare_tuple_pred;
MR_Code *MR_compare_rep_tuple_pred;
#endif
} MR_SpecialPredHooks;
extern MR_SpecialPredHooks MR_special_pred_hooks;
#endif // not MERCURY_HO_CALL_H