2 % (c) Parade/AQUA Projects, Glasgow University, 1995
3 % Kevin Hammond, February 15th. 1995
5 % This is for GUM and GrAnSim.
7 %************************************************************************
9 \section[Unpack.lc]{Unpacking closures which have been exported to remote processors}
11 %************************************************************************
13 This module defines routines for unpacking closures in the parallel runtime
16 In the case of GrAnSim, this module defines routines for *simulating* the
17 unpacking of closures as it is done in the parallel runtime system.
24 EXTDATA_RO(FetchMe_info);
30 static globalAddr *PendingGABuffer; /* HWL; init in main; */
33 InitPendingGABuffer(size)
37 = (globalAddr *) stgMallocBytes((size-PACK_HDR_SIZE)*2*sizeof(globalAddr), "InitPendingGABuffer");
41 @CommonUp@ commons up two closures which we have discovered to be
42 variants of the same object. One is made an indirection to the other.
46 CommonUp(P_ src, P_ dst)
51 switch (INFO_TYPE(INFO_PTR(src))) {
52 case INFO_SPEC_RBH_TYPE:
53 bqe = (P_) SPEC_RBH_BQ(src);
55 case INFO_GEN_RBH_TYPE:
56 bqe = (P_) GEN_RBH_BQ(src);
58 case INFO_FETCHME_TYPE:
59 bqe = PrelBase_Z91Z93_closure;
62 bqe = (P_) FMBQ_ENTRIES(src);
65 /* Don't common up anything else */
69 /* Note that UPD_IND does *not* awaken the bq */
71 ASSERT(!IS_BIG_MOTHER(INFO_PTR(dst)));
72 if (IS_MUTABLE(INFO_PTR(bqe)))
73 AwakenBlockingQueue(bqe);
78 @UnpackGraph@ unpacks the graph contained in a message buffer. It
79 returns a pointer to the new graph. The @gamap@ parameter is set to
80 point to an array of (oldGA,newGA) pairs which were created as a
81 result of unpacking the buffer; @nGAs@ is set to the number of GA
82 pairs which were created.
84 The format of graph in the pack buffer is as defined in @Pack.lc@.
88 UnpackGraph(buffer, gamap, nGAs)
93 W_ size, ptrs, nonptrs, vhs;
95 P_ bufptr = buffer + PACK_HDR_SIZE;
100 P_ closure, existing;
104 P_ graphroot, graph, parent;
105 W_ pptr = 0, pptrs = 0, pvhs;
111 InitPackBuffer(); /* in case it isn't already init'd */
113 gaga = PendingGABuffer;
117 /* Unpack the header */
122 graph = AllocateHeap(bufsize);
123 ASSERT(graph != NULL);
129 /* This is where we will ultimately save the closure's address */
132 /* First, unpack the next GA or PLC */
133 ga.weight = *bufptr++;
136 ga.loc.gc.gtid = *bufptr++;
137 ga.loc.gc.slot = *bufptr++;
139 ga.loc.plc = (P_) *bufptr++;
141 /* Now unpack the closure body, if there is one */
143 /* No more to unpack; just set closure to local address */
145 fprintf(stderr, "Unpacked PLC at %x \n", ga.loc.plc);
147 closure = ga.loc.plc;
148 } else if (isOffset(&ga)) {
149 /* No more to unpack; just set closure to cached address */
150 ASSERT(parent != NULL);
151 closure = (P_) buffer[ga.loc.gc.slot];
154 /* Now we have to build something. */
159 * Close your eyes. You don't want to see where we're looking. You
160 * can't get closure info until you've unpacked the variable header,
161 * but you don't know how big it is until you've got closure info.
162 * So...we trust that the closure in the buffer is organized the
163 * same way as they will be in the heap...at least up through the
164 * end of the variable header.
166 ip = get_closure_info(bufptr, &size, &ptrs, &nonptrs, &vhs, str);
168 /* Fill in the fixed header */
169 for (i = 0; i < FIXED_HS; i++)
170 graph[i] = *bufptr++;
172 if (INFO_TYPE(ip) == INFO_FETCHME_TYPE)
173 size = ptrs = nonptrs = vhs = 0;
175 /* Fill in the packed variable header */
176 for (i = 0; i < vhs; i++)
177 graph[FIXED_HS + i] = *bufptr++;
179 /* Pointers will be filled in later */
181 /* Fill in the packed non-pointers */
182 for (i = 0; i < nonptrs; i++)
183 graph[FIXED_HS + i + vhs + ptrs] = *bufptr++;
185 /* Indirections are never packed */
186 ASSERT(INFO_PTR(graph) != (W_) Ind_info_TO_USE);
188 /* Add to queue for processing */
192 * Common up the new closure with any existing closure having the same
196 if ((existing = GALAlookup(&ga)) == NULL) {
198 /* Just keep the new object */
200 fprintf(stderr, "Unpacking new (%x, %d, %x)\n",
201 ga.loc.gc.gtid, ga.loc.gc.slot, ga.weight);
204 newGA = setRemoteGA(graph, &ga, rtsTrue);
205 if (INFO_TYPE(ip) == INFO_FETCHME_TYPE)
206 FETCHME_GA(closure) = newGA;
208 /* Two closures, one global name. Someone loses */
209 oldip = (P_) INFO_PTR(existing);
211 if ((INFO_TYPE(oldip) == INFO_FETCHME_TYPE || IS_BLACK_HOLE(oldip)) &&
212 INFO_TYPE(ip) != INFO_FETCHME_TYPE) {
214 /* What we had wasn't worth keeping */
216 CommonUp(existing, graph);
220 * Either we already had something worthwhile by this name or
221 * the new thing is just another FetchMe. However, the thing we
222 * just unpacked has to be left as-is, or the child unpacking
223 * code will fail. Remember that the way pointer words are
224 * filled in depends on the info pointers of the parents being
225 * the same as when they were packed.
228 fprintf(stderr, "Unpacking old (%x, %d, %x), keeping %#lx\n",
229 ga.loc.gc.gtid, ga.loc.gc.slot, ga.weight, existing);
233 /* Pool the total weight in the stored ga */
234 (void) addWeight(&ga);
237 /* Sort out the global address mapping */
238 if ((IS_THUNK(ip) && IS_UPDATABLE(ip)) ||
239 (IS_MUTABLE(ip) && INFO_TYPE(ip) != INFO_FETCHME_TYPE)) {
240 /* Make up new GAs for single-copy closures */
241 globalAddr *newGA = MakeGlobal(closure, rtsTrue);
243 ASSERT(closure == graph);
245 /* Create an old GA to new GA mapping */
247 splitWeight(gaga, newGA);
248 ASSERT(gaga->weight == 1L << (BITS_IN(unsigned) - 1));
251 graph += FIXED_HS + (size < MIN_UPD_SIZE ? MIN_UPD_SIZE : size);
255 * Set parent pointer to point to chosen closure. If we're at the top of
256 * the graph (our parent is NULL), then we want to arrange to return the
257 * chosen closure to our caller (possibly in place of the allocated graph
263 parent[FIXED_HS + pvhs + pptr] = (W_) closure;
265 /* Save closure pointer for resolving offsets */
266 *slotptr = (W_) closure;
268 /* Locate next parent pointer */
270 while (pptr + 1 > pptrs) {
271 parent = DeQueueClosure();
276 (void) get_closure_info(parent, &size, &pptrs, &nonptrs,
281 } while (parent != NULL);
283 ASSERT(bufsize == 0 || graph - 1 <= SAVE_Hp);
285 *gamap = PendingGABuffer;
286 *nGAs = (gaga - PendingGABuffer) / 2;
288 /* ToDo: are we *certain* graphroot has been set??? WDP 95/07 */
295 In general no actual unpacking should be necessary. We just have to walk
296 over the graph and set the bitmasks appropriately. -- HWL
300 /* This code fakes the unpacking of a somewhat virtual buffer */
305 W_ size, ptrs, nonptrs, vhs;
306 P_ bufptr, closurestart;
308 P_ closure, existing;
310 W_ bufsize, unpackedsize;
311 P_ graphroot, graph, parent;
312 W_ pptr = 0, pptrs = 0, pvhs;
317 bufptr = buffer + PACK_HDR_SIZE;
320 # if defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */
321 if (buffer[PACK_FLAG_LOCN] != MAGIC_PACK_FLAG) {
322 fprintf(stderr,"Qagh: no magic flag at start of packet @ 0x%lx\n",
328 tso = buffer[PACK_TSO_LOCN];
330 /* Unpack the header */
331 unpackedsize = buffer[PACK_UNPACKED_SIZE_LOCN];
332 bufsize = buffer[PACK_SIZE_LOCN];
334 # if defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */
335 if ( RTSflags.GranFlags.debug & 0x100 )
336 fprintf(stderr,"\nUnpacking buffer @ 0x%x (root @ 0x%x, PE %d,size
337 = %d), demanded by TSO 0x%x (%d)(PE %d)\n",
338 buffer,graphroot,where_is(graphroot), bufsize, tso, TSO_ID(tso), where_is(tso));
342 closurestart = bufptr;
343 closure = *bufptr++; /* that's all we need for GrAnSim -- HWL */
345 /* Actually only ip is needed; rest is useful for TESTING -- HWL */
346 ip = get_closure_info(closure,
347 &size, &ptrs, &nonptrs, &vhs, str);
349 # if defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */
350 if ( RTSflags.GranFlags.debug & 0x100 )
351 fprintf(stderr,"(0x%x): Bitmask changed [%s]: 0x%x ",
352 closure, (IS_NF(INFO_PTR(closure)) ? "NF" : "__"),
356 if ( (INFO_TYPE(ip) == INFO_SPEC_RBH_TYPE) ||
357 (INFO_TYPE(ip) == INFO_GEN_RBH_TYPE) ) {
358 PROCS(closure) = PE_NUMBER(CurrentProc); /* Move node */
359 # if defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */
360 if ( RTSflags.GranFlags.debug & 0x100 ) {
361 fprintf(stderr," ---> 0x%x\n", PROCS(closure));
362 fprintf(stderr,"< Converting RBH @ 0x%x into an updatable
367 convertFromRBH(closure); /* In GUM that's done by convertToFetchMe */
368 } else if (IS_BLACK_HOLE(ip)) {
369 PROCS(closure) |= PE_NUMBER(CurrentProc); /* Copy node */
370 } else if ( (PROCS(closure) & PE_NUMBER(CurrentProc)) == 0 ) {
371 if (IS_NF(ip)) /* Old: || IS_BQ(node) */
372 PROCS(closure) |= PE_NUMBER(CurrentProc); /* Copy node */
374 PROCS(closure) = PE_NUMBER(CurrentProc); /* Move node */
377 # if defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */
378 if ( RTSflags.GranFlags.debug & 0x100 )
379 fprintf(stderr," ---> 0x%x\n", PROCS(closure));
382 } while (bufptr<(buffer+bufsize)) ; /* (parent != NULL); */
384 /* In GrAnSim we allocate pack buffers dynamically! -- HWL */