RexxEnvelope.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.oorexx.org/license.html */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 /******************************************************************************/
39 /* REXX Kernel RexxEnvelope.cpp */
40 /* */
41 /* Primitive Envelope Class */
42 /* */
43 /******************************************************************************/
44 
45 #include <stdlib.h>
46 #include "RexxCore.h"
47 #include "StackClass.hpp"
48 #include "StringClass.hpp"
49 #include "BufferClass.hpp"
50 #include "RexxSmartBuffer.hpp"
51 #include "ArrayClass.hpp"
52 #include "RexxEnvelope.hpp"
53 #include "MethodClass.hpp"
54 #include "ActivityManager.hpp"
55 
57 /******************************************************************************/
58 /* Function: Initialize a REXX envelope object */
59 /******************************************************************************/
60 {
61 }
62 
63 void RexxEnvelope::live(size_t liveMark)
64 /******************************************************************************/
65 /* Function: Normal garbage collection live marking */
66 /* */
67 /* NOTE: Do not mark flattenStack */
68 /******************************************************************************/
69 {
70  memory_mark(this->home);
71  memory_mark(this->receiver);
72  memory_mark(this->duptable);
73  memory_mark(this->savetable);
74  memory_mark(this->buffer);
75  memory_mark(this->rehashtable);
76 
77 }
78 
79 void RexxEnvelope::liveGeneral(int reason)
80 /******************************************************************************/
81 /* Function: Generalized object marking */
82 /* */
83 /* NOTE: Do not mark flattenStack */
84 /******************************************************************************/
85 {
92 }
93 
94 
96  void *newThisVoid, /* current pointer to flattening obj */
97  size_t newSelf, /* offset of the flattening object */
98  void *objRefVoid) /* object to process */
99 /******************************************************************************/
100 /* Function: This method does the copy buffer, */
101 /******************************************************************************/
102 {
103  RexxObject **newThis = (RexxObject **)newThisVoid;
104  RexxObject **objRef = (RexxObject **)objRefVoid;
105 
106  RexxObject *obj = *objRef;
107 
108  /* See if object has already been */
109  size_t objOffset = this->queryObj(obj); /* flattened. */
110  // if this object has not been previously flattened, we need to
111  // copy the object into the buffer and add the offset to the table.
112  if (objOffset == 0)
113  {
114  // this is the sart of the buffer
115  char *flattenBuffer = this->bufferStart();
116  // this is the offset to the reference we're working with. If the
117  // buffer needs to reallocate after a copy, we need to be able to
118  // locate this later
119  size_t referenceOffset = (char *)objRef - flattenBuffer;
120 
121  // if this is a proxied object, we need to convert it to a proxy and
122  // copy that object into the buffer and the reference table
123  if (obj->isProxyObject())
124  {
125  // get a proxy and make sure it's in our protection table
126  RexxObject *proxyObj = obj->makeProxy(this);
127  savetable->put(proxyObj, proxyObj);
128 
129  // copy the proxy to the buffer and add it to the dup table
130  // using the original object as the index.
131  objOffset = this->copyBuffer(proxyObj);
132  // it's not likely, but we might get a dup of the
133  // proxy object too. Add it to our resolution table.
134  this->associateObject(proxyObj, objOffset);
135  }
136  else
137  {
138 
139  // non-proxied object. This gets copied to the buffer
140  // directly and added to the dup table
141  objOffset = this->copyBuffer(obj);
142  }
143  // regardless of how we handle this, add an association for the object to the offset
144  this->associateObject(obj, objOffset);
145  // We're pushing an object offset on to our live stack, so we want to make sure our debug traps
146  // don't try to process this.
148  this->flattenStack->fastPush((RexxObject *)objOffset);
150  // if the buffer reallocated, we need to update the updating object pointer too.
151  char *newBuffer = this->bufferStart();
152  if (newBuffer != flattenBuffer)
153  {
154  *newThis = (RexxObject *) (newBuffer + newSelf);
155  }
156  // and update the reference with the offset
157  *(RexxObject **)(newBuffer + referenceOffset) = (RexxObject *)objOffset;
158  }
159  else
160  {
161  // no copying means no reallocation...we just replace the
162  // original object reference with the offset value
163  *objRef = (RexxObject *)objOffset;
164  }
165 }
166 
167 
169  RexxObject *_receiver) /* the receiver object */
170 /******************************************************************************/
171 /* Function: Pack an envelope item */
172 /******************************************************************************/
173 {
174  RexxObject *flattenObj; /* flattened object */
175  RexxObject *newSelf; /* the flattened envelope */
176  RexxObject *firstObject; /* first object to flatten */
177 
178  OrefSet(this, this->receiver, _receiver);
179  // create a save table to protect any objects (such as proxy
180  // objects) we create during flattening.
181  OrefSet(this, this->savetable, new_identity_table());
182  OrefSet(this, this->duptable, new_identity_table());
183  // this is a bit of a hack, but necessary. This allows us to store
184  // object offsets into a hashtable without having the hashtable
185  // attempt to mark the references.
188  // get a flatten stack from the memory object
190  // push unique terminator onto stack
192 
193  // First, put a header into the buffer. This is necessary because without
194  // it, the envelope object would be at 0 offset into the buffer, which is not
195  // distinguishable from OREF_NULL when the objects are unpacked from buffer.
196 
197 
198  // the header is just a dummy minimal object instance. We don't bother adding
199  // this to the dup table, as it won't ever be duped.
200  this->copyBuffer(TheObjectClass->newObject());
201  // we start the flattening process with the received object
202  firstObject = this->receiver;
203 
204  this->currentOffset = this->copyBuffer(firstObject);
205  // make sure we add this to the dup table in case it's self-referential at any point
206  associateObject(firstObject, this->currentOffset);
207  /* point to the copied one */
208  newSelf = (RexxObject *)(this->bufferStart() + this->currentOffset);
209 
210  // ok, keep flattening until will find our marker object on the stack
211  newSelf->flatten(this); /* start the flatten process. */
212 
213  for (flattenObj = this->flattenStack->fastPop();
214  flattenObj != OREF_NULL;
215  flattenObj = this->flattenStack->fastPop())
216  {
217  // the popped object is actuall an object offset. We need to convert this into a
218  // real object pointer
219  this->currentOffset = (size_t)flattenObj;
220  flattenObj = (RexxObject *)(this->bufferStart() + this->currentOffset);
221  // and flatten the next object
222  flattenObj->flatten(this); /* let this obj flatten its refs */
223  }
224  memoryObject.returnFlattenStack(); /* done with the flatten stack */
225  // now unwrap the smart buffer and fix the length of the real buffer
226  // behind it to the size we've written to it.
227  RexxBuffer *letter = buffer->getBuffer();
228  letter->setDataLength(buffer->getDataLength());
229  return letter;
230 }
231 
232 /**
233  * Perform an in-place unflatten operation on an object
234  * in a buffer.
235  *
236  * @param sourceBuffer
237  * The buffer containing the flattened object.
238  * @param startPointer
239  * The starting data location in the buffer.
240  * @param dataLength The length of the data to unflatten
241  */
242 void RexxEnvelope::puff(RexxBuffer *sourceBuffer, char *startPointer, size_t dataLength)
243 {
244  size_t primitiveTypeNum = 0; /* primitive behaviour type number */
245 
246  char *bufferPointer = startPointer; /* copy the starting point */
247  /* point to end of buffer */
248  char *endPointer = (char *)startPointer + dataLength;
249  RexxObject *puffObject = OREF_NULL;
250 
251  /* Set objoffset to the real address of the new objects. This tells */
252  /* mark_general to fix the object's refs and set their live flags. */
253  memoryObject.setObjectOffset((size_t)bufferPointer);
254  /* Now traverse the buffer fixing all of the behaviour pointers of the objects. */
255  while (bufferPointer < endPointer)
256  {
257  puffObject = (RexxObject *)bufferPointer;
258 
259  /* a non-primitive behaviour */
260  /* These are actually in flattened */
261  /* storgage. */
262  if (puffObject->isNonPrimitive())
263  {
264  /* Yes, lets get the behaviour Object*/
265  RexxBehaviour *objBehav = (RexxBehaviour *)(((uintptr_t)puffObject->behaviour) + sourceBuffer->getData());
266  /* Resolve the static behaviour info */
267  objBehav->resolveNonPrimitiveBehaviour();
268  /* Set this objects behaviour. */
269  puffObject->behaviour = objBehav;
270  /* get the behaviour's type number */
271  primitiveTypeNum = objBehav->getClassType();
272 
273  }
274  else
275  {
276  // convert this from a type number to the actuall class. This will unnormalize the
277  // type number to the different object classes.
279  primitiveTypeNum = puffObject->behaviour->getClassType();
280  }
281  /* Force fix-up of */
282  /*VirtualFunctionTable, */
283  ((RexxObject *)bufferPointer)->setVirtualFunctions(RexxMemory::virtualFunctionTable[primitiveTypeNum]);
284  puffObject->setObjectLive(memoryObject.markWord); /* Then Mark this object as live. */
285  /* Mark other referenced objs */
286  /* Note that this flavor of */
287  /* mark_general should update the */
288  /* mark fields in the objects. */
289  puffObject->liveGeneral(UNFLATTENINGOBJECT);
290  /* Point to next object in image. */
291  bufferPointer += puffObject->getObjectSize();
292  }
293  memoryObject.setObjectOffset(0); /* all done with the fixups! */
294 
295  // Prepare to reveal the objects in the buffer.
296  // the first object in the buffer is a dummy added
297  // for padding. We need to step past that one to the
298  // beginning of the real unflattened objects
299  OrefSet(this, this->receiver, (RexxObject *)(startPointer + ((RexxObject *)startPointer)->getObjectSize()));
300  /* chop off end of buffer to reveal */
301  /* its contents to memory obj */
302 
303  // this is the location of the next object after the buffer
304  char *nextObject = ((char *)sourceBuffer) + sourceBuffer->getObjectSize();
305  // this is the size of any tailing buffer portion after the last unflattened object.
306  size_t tailSize = nextObject - endPointer;
307 
308  // puffObject is the last object we processed. Add any tail data size on to that object
309  // so we don't create an invalid gap in the heap.
310  puffObject->setObjectSize(puffObject->getObjectSize() + tailSize);
311  // now adjust the front portion of the buffer object to reveal all of the
312  // unflattened data.
313  sourceBuffer->setObjectSize((char *)startPointer - (char *)sourceBuffer + ((RexxObject *)startPointer)->getObjectSize());
314 
315  // move past the header to the real unflattened data
316  bufferPointer = (char *)this->receiver;
317  /* Set envelope to the real address of the new objects. This tells */
318  /* mark_general to send unflatten to run any proxies. */
319  memoryObject.setEnvelope(this); /* tell memory to send unflatten */
320 
321  /* Now traverse the buffer running any proxies. */
322  while (bufferPointer < endPointer)
323  {
324  puffObject = (RexxObject *)bufferPointer;
325  // Since a GC could happen at anytime we need to check to make sure the object
326  // we are going now unflatten is still alive, since all who reference it may have already
327  // run and gotten the info from it and no longer reference it.
328  if (puffObject->isObjectLive(memoryObject.markWord))
329  {
330  // Note that this flavor of liveGeneral will run any proxies
331  // created by unflatten and fixup the refs to them.
332  puffObject->liveGeneral(UNFLATTENINGOBJECT);
333  }
334 
335  // Point to next object in image.
336  bufferPointer += puffObject->getObjectSize();
337  }
338 
339  // Tell memory we're done unflattening
341  // Before we run the method we need to give any tables a chance to rehash...
342  this->rehash();
343 }
344 
346  RexxObject *obj) /* object to check */
347 /******************************************************************************/
348 /* Function: Check to see if we've already flattened an object */
349 /******************************************************************************/
350 {
351  return (size_t)this->duptable->get(obj);
352 }
353 
355  RexxObject *obj) /* object to copy */
356 /******************************************************************************/
357 /* Function: Copy an object into our flatten buffer */
358 /******************************************************************************/
359 {
360  // copy the object into the buffer, which might cause the buffer to
361  // resize itself.
362  size_t objOffset = this->buffer->copyData((void *)obj, obj->getObjectSize());
363  // get a reference to the copied object
364  RexxObject *newObj = (RexxObject *) (this->buffer->getBuffer()->getData() + objOffset);
365  // if this is a non-primative behaviour, we need to flatten it as well. The
366  // offset is tagged as being a non-primitive behaviour that needs later inflating.
367  if (newObj->behaviour->isNonPrimitive())
368  {
369  void *behavPtr = &newObj->behaviour;
370 
371  this->flattenReference(&newObj, objOffset, (RexxObject **)behavPtr);
372  }
373  else
374  {
375  // transient classes should never be flattened. This is a problem if we encounter one
376  if (newObj->behaviour->isTransientClass())
377  {
379  }
380 
381  // just replace the behaviour with its normalized type number. This will be used
382  // to restore it later.
383  newObj->behaviour = newObj->behaviour->getSavedPrimitiveBehaviour();
384  }
385  // if we flattened an object from oldspace, we just copied everything. Make sure
386  // this is no longer marked as oldspace
387  newObj->setNewSpace();
388  // the offset is what we need
389  return objOffset;
390 }
391 
392 
394 /******************************************************************************/
395 /* Function: Rehash flattened tables */
396 /******************************************************************************/
397 {
398  HashLink i; /* loop index */
399  RexxTable * index; /* table to flatten */
400 
401  if (this->rehashtable != OREF_NULL)
402  {/* tables to rehash here? */
403  /* Before we run the method we need */
404  /* to give the tables a chance to */
405  /* rehash... */
406  for (i = this->rehashtable->first(); (index = (RexxTable *)this->rehashtable->index(i)) != OREF_NULL; i = this->rehashtable->next(i))
407  {
408  index->reHash(); /* rehash the table */
409  }
410  }
411 }
412 
414 /******************************************************************************/
415 /* Return the start of the envelope buffer */
416 /******************************************************************************/
417 {
418  return this->buffer->getBuffer()->getData();
419 }
420 
422  RexxObject *o, /* original object */
423  size_t flattenOffset) /* new proxy object */
424 /******************************************************************************/
425 /* Function: Map an object to a flattened proxy object */
426 /******************************************************************************/
427 {
428  // we just add this to the duptable under the original object
429  // reference value.
430  this->duptable->addOffset(flattenOffset, o);
431 }
432 
434  RexxObject *obj) /* table object to rehash */
435 /******************************************************************************/
436 /* Function: Add an object to the rehash table for later processing */
437 /******************************************************************************/
438 {
439  /* the following table will be used */
440  /* by the table_unflatten method. */
441  /* */
442  /* Every table that gets unflattened */
443  /* place itself in this table. Once */
444  /* every object has been unflattened */
445  /* we traverse this table and allow */
446  /* the hashtables to re-hash their */
447  /* since some hash value may have */
448  /* change */
449  if (this->rehashtable == OREF_NULL) /* first table added? */
450  {
451  /* create the table now */
452  OrefSet(this, this->rehashtable, new_identity_table());
453  }
454  /* use put to make sure we only get */
455  /* a single version of each table */
456  this->rehashtable->put(TheNilObject, obj);
457 }
458 
459 
460 void *RexxEnvelope::operator new(size_t size)
461 /******************************************************************************/
462 /* Function: Create a new translator object */
463 /******************************************************************************/
464 {
465  /* Get new object */
466  return new_object(sizeof(RexxEnvelope), T_Envelope);
467 }
468 
void reportException(wholenumber_t error)
@ T_Envelope
RexxIdentityTable * new_identity_table()
#define OREF_NULL
Definition: RexxCore.h:61
#define TheObjectClass
Definition: RexxCore.h:166
#define OrefSet(o, r, v)
Definition: RexxCore.h:101
#define TheNilObject
Definition: RexxCore.h:191
#define DEFAULT_ENVELOPE_BUFFER
#define Error_Interpretation
size_t HashLink
RexxMemory memoryObject
Definition: RexxMemory.cpp:86
#define memory_mark(oref)
Definition: RexxMemory.hpp:450
RexxObject * new_object(size_t s)
Definition: RexxMemory.hpp:436
#define memory_mark_general(oref)
Definition: RexxMemory.hpp:451
@ UNFLATTENINGOBJECT
Definition: RexxMemory.hpp:119
static RexxBehaviour * restoreSavedPrimitiveBehaviour(RexxBehaviour *b)
RexxBehaviour * getSavedPrimitiveBehaviour()
bool isTransientClass()
void resolveNonPrimitiveBehaviour()
size_t getClassType()
void setDataLength(size_t l)
Definition: BufferClass.hpp:55
virtual char * getData()
size_t currentOffset
RexxObject * home
void liveGeneral(int reason)
RexxBuffer * pack(RexxObject *)
RexxIdentityTable * savetable
size_t queryObj(RexxObject *)
RexxObject * receiver
RexxStack * flattenStack
RexxIdentityTable * duptable
void associateObject(RexxObject *, size_t)
void live(size_t)
void puff(RexxBuffer *, char *, size_t length)
void addTable(RexxObject *obj)
char * bufferStart()
void flattenReference(void *, size_t, void *)
size_t copyBuffer(RexxObject *)
RexxIdentityTable * rehashtable
RexxSmartBuffer * buffer
RexxHashTable * contents
RexxObject * index(HashLink pos)
virtual RexxObject * put(RexxObject *, RexxObject *)
virtual RexxObject * get(RexxObject *key)
void setObjectSize(size_t s)
virtual RexxObject * makeProxy(RexxEnvelope *)
void setObjectLive(size_t markword)
bool isObjectLive(size_t mark)
RexxBehaviour * behaviour
void setEnvelope(RexxEnvelope *)
static void * virtualFunctionTable[]
Definition: RexxMemory.hpp:301
RexxStack * getFlattenStack()
size_t markWord
Definition: RexxMemory.hpp:304
void returnFlattenStack()
void setObjectOffset(size_t offset)
void disableOrefChecks()
Definition: RexxMemory.hpp:267
void enableOrefChecks()
Definition: RexxMemory.hpp:268
void flatten(RexxEnvelope *)
Definition: ObjectClass.cpp:95
void liveGeneral(int reason)
Definition: ObjectClass.cpp:87
size_t copyData(void *, size_t)
RexxBuffer * getBuffer()
void fastPush(RexxObject *element)
Definition: StackClass.hpp:70
RexxObject * fastPop()
Definition: StackClass.hpp:72
void reHash()
Definition: TableClass.cpp:179
RexxObject * addOffset(size_t, RexxObject *)
Definition: TableClass.cpp:64
UINT_PTR uintptr_t