1 /*
2 * Copyright 2001-2004 David Abrahams.
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * http://www.boost.org/LICENSE_1_0.txt)
6 */
7
8 #include "jam.h"
9 #include "modules.h"
10
11 #include "hash.h"
12 #include "lists.h"
13 #include "native.h"
14 #include "object.h"
15 #include "parse.h"
16 #include "rules.h"
17 #include "jam_strings.h"
18 #include "variable.h"
19
20 #include <assert.h>
21 #include <string.h>
22
23 static struct hash * module_hash = 0;
24 static module_t root;
25
26
bindmodule(OBJECT * name)27 module_t * bindmodule( OBJECT * name )
28 {
29 if ( !name )
30 return &root;
31
32 {
33 PROFILE_ENTER( BINDMODULE );
34
35 module_t * m;
36 int found;
37
38 if ( !module_hash )
39 module_hash = hashinit( sizeof( module_t ), "modules" );
40
41 m = (module_t *)hash_insert( module_hash, name, &found );
42 if ( !found )
43 {
44 m->name = object_copy( name );
45 m->variables = 0;
46 m->variable_indices = 0;
47 m->num_fixed_variables = 0;
48 m->fixed_variables = 0;
49 m->rules = 0;
50 m->imported_modules = 0;
51 m->class_module = 0;
52 m->native_rules = 0;
53 m->user_module = 0;
54 }
55
56 PROFILE_EXIT( BINDMODULE );
57
58 return m;
59 }
60 }
61
62
63 /*
64 * demand_rules() - Get the module's "rules" hash on demand.
65 */
demand_rules(module_t * m)66 struct hash * demand_rules( module_t * m )
67 {
68 if ( !m->rules )
69 m->rules = hashinit( sizeof( RULE ), "rules" );
70 return m->rules;
71 }
72
73
74 /*
75 * delete_module() - wipe out the module's rules and variables.
76 */
77
delete_rule_(void * xrule,void * data)78 static void delete_rule_( void * xrule, void * data )
79 {
80 rule_free( (RULE *)xrule );
81 }
82
83
delete_native_rule(void * xrule,void * data)84 static void delete_native_rule( void * xrule, void * data )
85 {
86 native_rule_t * rule = (native_rule_t *)xrule;
87 object_free( rule->name );
88 if ( rule->procedure )
89 function_free( rule->procedure );
90 }
91
92
delete_imported_modules(void * xmodule_name,void * data)93 static void delete_imported_modules( void * xmodule_name, void * data )
94 {
95 object_free( *(OBJECT * *)xmodule_name );
96 }
97
98
99 static void free_fixed_variable( void * xvar, void * data );
100
delete_module(module_t * m)101 void delete_module( module_t * m )
102 {
103 /* Clear out all the rules. */
104 if ( m->rules )
105 {
106 hashenumerate( m->rules, delete_rule_, (void *)0 );
107 hash_free( m->rules );
108 m->rules = 0;
109 }
110
111 if ( m->native_rules )
112 {
113 hashenumerate( m->native_rules, delete_native_rule, (void *)0 );
114 hash_free( m->native_rules );
115 m->native_rules = 0;
116 }
117
118 if ( m->variables )
119 {
120 var_done( m );
121 m->variables = 0;
122 }
123
124 if ( m->fixed_variables )
125 {
126 int i;
127 for ( i = 0; i < m->num_fixed_variables; ++i )
128 {
129 list_free( m->fixed_variables[ i ] );
130 }
131 BJAM_FREE( m->fixed_variables );
132 m->fixed_variables = 0;
133 }
134
135 if ( m->variable_indices )
136 {
137 hashenumerate( m->variable_indices, &free_fixed_variable, (void *)0 );
138 hash_free( m->variable_indices );
139 m->variable_indices = 0;
140 }
141
142 if ( m->imported_modules )
143 {
144 hashenumerate( m->imported_modules, delete_imported_modules, (void *)0 );
145 hash_free( m->imported_modules );
146 m->imported_modules = 0;
147 }
148 }
149
150
151 struct module_stats
152 {
153 OBJECT * module_name;
154 struct hashstats rules_stats[ 1 ];
155 struct hashstats variables_stats[ 1 ];
156 struct hashstats variable_indices_stats[ 1 ];
157 struct hashstats imported_modules_stats[ 1 ];
158 };
159
160
module_stat(struct hash * hp,OBJECT * module,const char * name)161 static void module_stat( struct hash * hp, OBJECT * module, const char * name )
162 {
163 if ( hp )
164 {
165 struct hashstats stats[ 1 ];
166 string id[ 1 ];
167 hashstats_init( stats );
168 string_new( id );
169 string_append( id, object_str( module ) );
170 string_push_back( id, ' ' );
171 string_append( id, name );
172
173 hashstats_add( stats, hp );
174 hashstats_print( stats, id->value );
175
176 string_free( id );
177 }
178 }
179
180
class_module_stat(struct hashstats * stats,OBJECT * module,const char * name)181 static void class_module_stat( struct hashstats * stats, OBJECT * module, const char * name )
182 {
183 if ( stats->item_size )
184 {
185 string id[ 1 ];
186 string_new( id );
187 string_append( id, object_str( module ) );
188 string_append( id, " object " );
189 string_append( id, name );
190
191 hashstats_print( stats, id->value );
192
193 string_free( id );
194 }
195 }
196
197
stat_module(void * xmodule,void * data)198 static void stat_module( void * xmodule, void * data )
199 {
200 module_t *m = (module_t *)xmodule;
201
202 if ( DEBUG_MEM || DEBUG_PROFILE )
203 {
204 struct hash * class_info = (struct hash *)data;
205 if ( m->class_module )
206 {
207 int found;
208 struct module_stats * ms = (struct module_stats *)hash_insert( class_info, m->class_module->name, &found );
209 if ( !found )
210 {
211 ms->module_name = m->class_module->name;
212 hashstats_init( ms->rules_stats );
213 hashstats_init( ms->variables_stats );
214 hashstats_init( ms->variable_indices_stats );
215 hashstats_init( ms->imported_modules_stats );
216 }
217
218 hashstats_add( ms->rules_stats, m->rules );
219 hashstats_add( ms->variables_stats, m->variables );
220 hashstats_add( ms->variable_indices_stats, m->variable_indices );
221 hashstats_add( ms->imported_modules_stats, m->imported_modules );
222 }
223 else
224 {
225 module_stat( m->rules, m->name, "rules" );
226 module_stat( m->variables, m->name, "variables" );
227 module_stat( m->variable_indices, m->name, "fixed variables" );
228 module_stat( m->imported_modules, m->name, "imported modules" );
229 }
230 }
231
232 delete_module( m );
233 object_free( m->name );
234 }
235
print_class_stats(void * xstats,void * data)236 static void print_class_stats( void * xstats, void * data )
237 {
238 struct module_stats * stats = (struct module_stats *)xstats;
239 class_module_stat( stats->rules_stats, stats->module_name, "rules" );
240 class_module_stat( stats->variables_stats, stats->module_name, "variables" );
241 class_module_stat( stats->variable_indices_stats, stats->module_name, "fixed variables" );
242 class_module_stat( stats->imported_modules_stats, stats->module_name, "imported modules" );
243 }
244
245
delete_module_(void * xmodule,void * data)246 static void delete_module_( void * xmodule, void * data )
247 {
248 module_t *m = (module_t *)xmodule;
249
250 delete_module( m );
251 object_free( m->name );
252 }
253
254
modules_done()255 void modules_done()
256 {
257 if ( DEBUG_MEM || DEBUG_PROFILE )
258 {
259 struct hash * class_hash = hashinit( sizeof( struct module_stats ), "object info" );
260 hashenumerate( module_hash, stat_module, (void *)class_hash );
261 hashenumerate( class_hash, print_class_stats, (void *)0 );
262 hash_free( class_hash );
263 }
264 hashenumerate( module_hash, delete_module_, (void *)0 );
265 hashdone( module_hash );
266 module_hash = 0;
267 delete_module( &root );
268 }
269
root_module()270 module_t * root_module()
271 {
272 return &root;
273 }
274
275
import_module(LIST * module_names,module_t * target_module)276 void import_module( LIST * module_names, module_t * target_module )
277 {
278 PROFILE_ENTER( IMPORT_MODULE );
279
280 struct hash * h;
281 LISTITER iter;
282 LISTITER end;
283
284 if ( !target_module->imported_modules )
285 target_module->imported_modules = hashinit( sizeof( char * ), "imported"
286 );
287 h = target_module->imported_modules;
288
289 iter = list_begin( module_names );
290 end = list_end( module_names );
291 for ( ; iter != end; iter = list_next( iter ) )
292 {
293 int found;
294 OBJECT * const s = list_item( iter );
295 OBJECT * * const ss = (OBJECT * *)hash_insert( h, s, &found );
296 if ( !found )
297 *ss = object_copy( s );
298 }
299
300 PROFILE_EXIT( IMPORT_MODULE );
301 }
302
303
add_module_name(void * r_,void * result_)304 static void add_module_name( void * r_, void * result_ )
305 {
306 OBJECT * * const r = (OBJECT * *)r_;
307 LIST * * const result = (LIST * *)result_;
308 *result = list_push_back( *result, object_copy( *r ) );
309 }
310
311
imported_modules(module_t * module)312 LIST * imported_modules( module_t * module )
313 {
314 LIST * result = L0;
315 if ( module->imported_modules )
316 hashenumerate( module->imported_modules, add_module_name, &result );
317 return result;
318 }
319
320
321 FUNCTION * function_bind_variables( FUNCTION *, module_t *, int * counter );
322 FUNCTION * function_unbind_variables( FUNCTION * );
323
324 struct fixed_variable
325 {
326 OBJECT * key;
327 int n;
328 };
329
330 struct bind_vars_t
331 {
332 module_t * module;
333 int counter;
334 };
335
336
free_fixed_variable(void * xvar,void * data)337 static void free_fixed_variable( void * xvar, void * data )
338 {
339 object_free( ( (struct fixed_variable *)xvar )->key );
340 }
341
342
bind_variables_for_rule(void * xrule,void * xdata)343 static void bind_variables_for_rule( void * xrule, void * xdata )
344 {
345 RULE * rule = (RULE *)xrule;
346 struct bind_vars_t * data = (struct bind_vars_t *)xdata;
347 if ( rule->procedure && rule->module == data->module )
348 rule->procedure = function_bind_variables( rule->procedure,
349 data->module, &data->counter );
350 }
351
352
module_bind_variables(struct module_t * m)353 void module_bind_variables( struct module_t * m )
354 {
355 if ( m != root_module() && m->rules )
356 {
357 struct bind_vars_t data;
358 data.module = m;
359 data.counter = m->num_fixed_variables;
360 hashenumerate( m->rules, &bind_variables_for_rule, &data );
361 module_set_fixed_variables( m, data.counter );
362 }
363 }
364
365
module_add_fixed_var(struct module_t * m,OBJECT * name,int * counter)366 int module_add_fixed_var( struct module_t * m, OBJECT * name, int * counter )
367 {
368 struct fixed_variable * v;
369 int found;
370
371 assert( !m->class_module );
372
373 if ( !m->variable_indices )
374 m->variable_indices = hashinit( sizeof( struct fixed_variable ), "variable index table" );
375
376 v = (struct fixed_variable *)hash_insert( m->variable_indices, name, &found );
377 if ( !found )
378 {
379 v->key = object_copy( name );
380 v->n = (*counter)++;
381 }
382
383 return v->n;
384 }
385
386
387 LIST * var_get_and_clear_raw( module_t * m, OBJECT * name );
388
load_fixed_variable(void * xvar,void * data)389 static void load_fixed_variable( void * xvar, void * data )
390 {
391 struct fixed_variable * var = (struct fixed_variable *)xvar;
392 struct module_t * m = (struct module_t *)data;
393 if ( var->n >= m->num_fixed_variables )
394 m->fixed_variables[ var->n ] = var_get_and_clear_raw( m, var->key );
395 }
396
397
module_set_fixed_variables(struct module_t * m,int n_variables)398 void module_set_fixed_variables( struct module_t * m, int n_variables )
399 {
400 /* Reallocate */
401 struct hash * variable_indices;
402 LIST * * fixed_variables = (LIST * *)BJAM_MALLOC( n_variables * sizeof( LIST * ) );
403 if ( m->fixed_variables )
404 {
405 memcpy( fixed_variables, m->fixed_variables, m->num_fixed_variables * sizeof( LIST * ) );
406 BJAM_FREE( m->fixed_variables );
407 }
408 m->fixed_variables = fixed_variables;
409 variable_indices = m->class_module
410 ? m->class_module->variable_indices
411 : m->variable_indices;
412 if ( variable_indices )
413 hashenumerate( variable_indices, &load_fixed_variable, m );
414 m->num_fixed_variables = n_variables;
415 }
416
417
module_get_fixed_var(struct module_t * m_,OBJECT * name)418 int module_get_fixed_var( struct module_t * m_, OBJECT * name )
419 {
420 struct fixed_variable * v;
421 struct module_t * m = m_;
422
423 if ( m->class_module )
424 m = m->class_module;
425
426 if ( !m->variable_indices )
427 return -1;
428
429 v = (struct fixed_variable *)hash_find( m->variable_indices, name );
430 return v && v->n < m_->num_fixed_variables ? v->n : -1;
431 }
432