aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/lscript/lscript_execute/lscript_heapruntime.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/lscript/lscript_execute/lscript_heapruntime.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/lscript/lscript_execute/lscript_heapruntime.cpp')
-rw-r--r--linden/indra/lscript/lscript_execute/lscript_heapruntime.cpp520
1 files changed, 520 insertions, 0 deletions
diff --git a/linden/indra/lscript/lscript_execute/lscript_heapruntime.cpp b/linden/indra/lscript/lscript_execute/lscript_heapruntime.cpp
new file mode 100644
index 0000000..791fa1b
--- /dev/null
+++ b/linden/indra/lscript/lscript_execute/lscript_heapruntime.cpp
@@ -0,0 +1,520 @@
1/**
2 * @file lscript_heapruntime.cpp
3 * @brief classes to manage script heap at runtime
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#if 0
29
30#include "linden_common.h"
31
32#include "lscript_heapruntime.h"
33#include "lscript_execute.h"
34
35
36/*
37 String Heap Format
38 Byte Description
39 0x0 - 0xnn Single byte string including null terminator
40
41 List Heap Format
42 Byte Description
43 0x0 Next Entry Type
44 0: End of list
45 1: Integer
46 2: Floating point
47 3: String
48 4: Vector
49 5: Quaternion
50 6: List
51 0x1 - 0x4 Integer, Floating Point, String Address, List Address
52 or
53 0x1 - 0xd Vector
54 or
55 0x1 - 0x11 Quaternion
56 . . .
57
58 Heap Block Format
59 Byte Description
60 0x0 - 0x3 Offset to Next Block
61 0x4 - 0x7 Object Reference Count
62 0x8 Block Type
63 0: Empty
64 3: String
65 6: List
66 0x9 - 0xM Object Data
67
68 Heap Management
69
70 Adding Data
71
72 1) Set last empty spot to zero.
73 2) Go to start of the heap (HR).
74 3) Get next 4 bytes of offset.
75 4) If zero, we've reached the end of used memory. If empty spot is zero go to step 9. Otherwise set base offset to 0 and go to step 9.
76 5) Skip 4 bytes.
77 6) Get next 1 byte of entry type.
78 7) If zero, this spot is empty. If empty spot is zero, set empty spot to this address and go to step 9. Otherwise, coalesce with last empty spot and then go to step 9.
79 8) Skip forward by offset and go to step 3.
80 9) If the spot is empty, check to see if the size needed == offset - 9.
81 10) If it does, let's drop our data into this spot. Set reference count to 1. Set entry type appropriately and copy the data in.
82 11) If size needed < offset - 9 then we can stick in data and add in an empty block.
83 12) Otherwise, we need to keep looking. Go to step 3.
84
85 Increasing reference counts
86
87 Decreasing reference counts
88 1) Set entry type to 0.
89 2) If offset is non-zero and the next entry is empty, coalesce. Go to step 2.
90
91 What increases reference count:
92 Initial creation sets reference count to 1.
93 Storing the reference increases reference count by 1.
94 Pushing the reference increases reference count by 1.
95 Duplicating the reference increases reference count by 1.
96
97 What decreases the reference count:
98 Popping the reference decreases reference count by 1.
99 */
100
101
102LLScriptHeapRunTime::LLScriptHeapRunTime()
103: mLastEmpty(0), mBuffer(NULL), mCurrentPosition(0), mStackPointer(0), mHeapRegister(0), mbPrint(FALSE)
104{
105}
106
107LLScriptHeapRunTime::~LLScriptHeapRunTime()
108{
109}
110
111S32 LLScriptHeapRunTime::addData(char *string)
112{
113 if (!mBuffer)
114 return 0;
115
116 S32 size = strlen(string) + 1;
117 S32 block_offset = findOpenBlock(size + HEAP_BLOCK_HEADER_SIZE);
118
119 if (mCurrentPosition)
120 {
121 S32 offset = mCurrentPosition;
122 if (offset + block_offset + HEAP_BLOCK_HEADER_SIZE + LSCRIPTDataSize[LST_INTEGER] >= mStackPointer)
123 {
124 set_fault(mBuffer, LSRF_STACK_HEAP_COLLISION);
125 return 0;
126 }
127 // cool, we've found a spot!
128 // set offset
129 integer2bytestream(mBuffer, offset, block_offset);
130 // set reference count
131 integer2bytestream(mBuffer, offset, 1);
132 // set type
133 *(mBuffer + offset++) = LSCRIPTTypeByte[LST_STRING];
134 // plug in data
135 char2bytestream(mBuffer, offset, string);
136 if (mbPrint)
137 printf("0x%X created ref count %d\n", mCurrentPosition - mHeapRegister, 1);
138
139 // now, zero out next offset to prevent "trouble"
140 // offset = mCurrentPosition + size + HEAP_BLOCK_HEADER_SIZE;
141 // integer2bytestream(mBuffer, offset, 0);
142 }
143 return mCurrentPosition;
144}
145
146S32 LLScriptHeapRunTime::addData(U8 *list)
147{
148 if (!mBuffer)
149 return 0;
150 return 0;
151}
152
153S32 LLScriptHeapRunTime::catStrings(S32 address1, S32 address2)
154{
155 if (!mBuffer)
156 return 0;
157
158 S32 dataaddress1 = address1 + 2*LSCRIPTDataSize[LST_INTEGER] + 1;
159 S32 dataaddress2 = address2 + 2*LSCRIPTDataSize[LST_INTEGER] + 1;
160
161 S32 toffset1 = dataaddress1;
162 safe_heap_bytestream_count_char(mBuffer, toffset1);
163
164 S32 toffset2 = dataaddress2;
165 safe_heap_bytestream_count_char(mBuffer, toffset2);
166
167 // calculate new string size
168 S32 size1 = toffset1 - dataaddress1;
169 S32 size2 = toffset2 - dataaddress2;
170 S32 newbuffer = size1 + size2 - 1;
171
172 char *temp = new char[newbuffer];
173
174 // get the strings
175 bytestream2char(temp, mBuffer, dataaddress1);
176 bytestream2char(temp + size1 - 1, mBuffer, dataaddress2);
177
178 decreaseRefCount(address1);
179 decreaseRefCount(address2);
180
181 S32 retaddress = addData(temp);
182
183 return retaddress;
184}
185
186S32 LLScriptHeapRunTime::cmpStrings(S32 address1, S32 address2)
187{
188 if (!mBuffer)
189 return 0;
190
191 S32 dataaddress1 = address1 + 2*LSCRIPTDataSize[LST_INTEGER] + 1;
192 S32 dataaddress2 = address2 + 2*LSCRIPTDataSize[LST_INTEGER] + 1;
193
194 S32 toffset1 = dataaddress1;
195 safe_heap_bytestream_count_char(mBuffer, toffset1);
196
197 S32 toffset2 = dataaddress2;
198 safe_heap_bytestream_count_char(mBuffer, toffset2);
199
200 // calculate new string size
201 S32 size1 = toffset1 - dataaddress1;
202 S32 size2 = toffset2 - dataaddress2;
203
204 if (size1 != size2)
205 {
206 return llmin(size1, size2);
207 }
208 else
209 {
210 return strncmp((char *)(mBuffer + dataaddress1), (char *)(mBuffer + dataaddress2), size1);
211 }
212}
213
214void LLScriptHeapRunTime::removeData(S32 address)
215{
216 if (!mBuffer)
217 return;
218
219 S32 toffset = address;
220 // read past offset (relying on function side effect
221 bytestream2integer(mBuffer, toffset);
222
223 // make sure that reference count is 0
224 integer2bytestream(mBuffer, toffset, 0);
225 // show the block as empty
226 *(mBuffer + toffset) = 0;
227
228 // now, clean up the heap
229 S32 clean = mHeapRegister;
230 S32 tclean;
231 S32 clean_offset;
232
233 S32 nclean;
234 S32 tnclean;
235 S32 next_offset;
236
237 U8 type;
238 U8 ntype;
239
240 for(;;)
241 {
242 tclean = clean;
243 clean_offset = bytestream2integer(mBuffer, tclean);
244 // is this block, empty?
245 tclean += LSCRIPTDataSize[LST_INTEGER];
246 type = *(mBuffer + tclean);
247
248 if (!clean_offset)
249 {
250 if (!type)
251 {
252 // we're done! if our block is empty, we can pull in the HP and zero out our offset
253 set_register(mBuffer, LREG_HP, clean);
254 }
255 return;
256 }
257
258
259 if (!type)
260 {
261 // if we're empty, try to coalesce with the next one
262 nclean = clean + clean_offset;
263 tnclean = nclean;
264 next_offset = bytestream2integer(mBuffer, tnclean);
265 tnclean += LSCRIPTDataSize[LST_INTEGER];
266 ntype = *(mBuffer + tnclean);
267
268 if (!next_offset)
269 {
270 // we're done! if our block is empty, we can pull in the HP and zero out our offset
271 tclean = clean;
272 integer2bytestream(mBuffer, tclean, 0);
273 set_register(mBuffer, LREG_HP, clean);
274 return;
275 }
276
277 if (!ntype)
278 {
279 // hooray! we can coalesce
280 tclean = clean;
281 integer2bytestream(mBuffer, tclean, clean_offset + next_offset);
282 // don't skip forward so that we can keep coalescing on next pass through the loop
283 }
284 else
285 {
286 clean += clean_offset;
287 }
288 }
289 else
290 {
291 // if not, move on to the next block
292 clean += clean_offset;
293 }
294 }
295}
296
297void LLScriptHeapRunTime::coalesce(S32 address1, S32 address2)
298{
299 // we need to bump the base offset by the second block's
300 S32 toffset = address1;
301 S32 offset1 = bytestream2integer(mBuffer, toffset);
302 offset1 += bytestream2integer(mBuffer, address2);
303
304 integer2bytestream(mBuffer, address1, offset1);
305}
306
307void LLScriptHeapRunTime::split(S32 address1, S32 size)
308{
309 S32 toffset = address1;
310 S32 oldoffset = bytestream2integer(mBuffer, toffset);
311
312 // add new offset and zero out reference count and block used
313 S32 newoffset = oldoffset - size;
314 S32 newblockpos = address1 + size;
315
316 // set new offset
317 integer2bytestream(mBuffer, newblockpos, newoffset);
318 // zero out reference count
319 integer2bytestream(mBuffer, newblockpos, 0);
320 // mark as empty
321 *(mBuffer + newblockpos) = 0;
322
323 // now, change the offset of the original block
324 integer2bytestream(mBuffer, address1, size + HEAP_BLOCK_HEADER_SIZE);
325}
326
327/*
328
329 For reference count changes, strings are easy. For lists, we'll need to go through the lists reducing
330 the reference counts for any included strings and lists
331
332 */
333
334void LLScriptHeapRunTime::increaseRefCount(S32 address)
335{
336 if (!mBuffer)
337 return;
338
339 if (!address)
340 {
341 // unused temp string entry
342 return;
343 }
344
345 // get current reference count
346 S32 toffset = address + 4;
347 S32 count = bytestream2integer(mBuffer, toffset);
348
349 count++;
350
351 if (mbPrint)
352 printf("0x%X inc ref count %d\n", address - mHeapRegister, count);
353
354 // see which type it is
355 U8 type = *(mBuffer + toffset);
356
357 if (type == LSCRIPTTypeByte[LST_STRING])
358 {
359 toffset = address + 4;
360 integer2bytestream(mBuffer, toffset, count);
361 }
362 // TO DO: put list stuff here!
363 else
364 {
365 set_fault(mBuffer, LSRF_HEAP_ERROR);
366 }
367}
368
369void LLScriptHeapRunTime::decreaseRefCount(S32 address)
370{
371 if (!mBuffer)
372 return;
373
374 if (!address)
375 {
376 // unused temp string entry
377 return;
378 }
379
380 // get offset
381 S32 toffset = address;
382 // read past offset (rely on function side effect)
383 bytestream2integer(mBuffer, toffset);
384
385 // get current reference count
386 S32 count = bytestream2integer(mBuffer, toffset);
387
388 // see which type it is
389 U8 type = *(mBuffer + toffset);
390
391 if (type == LSCRIPTTypeByte[LST_STRING])
392 {
393 count--;
394
395 if (mbPrint)
396 printf("0x%X dec ref count %d\n", address - mHeapRegister, count);
397
398 toffset = address + 4;
399 integer2bytestream(mBuffer, toffset, count);
400 if (!count)
401 {
402 // we can blow this one away
403 removeData(address);
404 }
405 }
406 // TO DO: put list stuff here!
407 else
408 {
409 set_fault(mBuffer, LSRF_HEAP_ERROR);
410 }
411}
412
413// if we're going to assign a variable, we need to decrement the reference count of what we were pointing at (if anything)
414void LLScriptHeapRunTime::releaseLocal(S32 address)
415{
416 S32 hr = get_register(mBuffer, LREG_HR);
417 address = lscript_local_get(mBuffer, address);
418 if ( (address >= hr)
419 &&(address < hr + get_register(mBuffer, LREG_HP)))
420 {
421 decreaseRefCount(address);
422 }
423}
424
425void LLScriptHeapRunTime::releaseGlobal(S32 address)
426{
427 // NOTA BENE: Global strings are referenced relative to the HR while local strings aren't
428 S32 hr = get_register(mBuffer, LREG_HR);
429 address = lscript_global_get(mBuffer, address) + hr;
430 if ( (address >= hr)
431 &&(address < hr + get_register(mBuffer, LREG_HP)))
432 {
433 decreaseRefCount(address);
434 }
435}
436
437
438// we know the following function has "unreachable code"
439// don't remind us every friggin' time we compile. . .
440
441#if defined(_MSC_VER)
442# pragma warning(disable: 4702) // unreachable code
443#endif
444
445S32 LLScriptHeapRunTime::findOpenBlock(S32 size)
446{
447 S32 offset;
448 S32 toffset;
449 U8 blocktype;
450
451 while(1)
452 {
453 if (mCurrentPosition + size >= mStackPointer)
454 {
455 set_fault(mBuffer, LSRF_STACK_HEAP_COLLISION);
456 mCurrentPosition = 0;
457 }
458
459 toffset = mCurrentPosition;
460 offset = bytestream2integer(mBuffer, toffset);
461 if (!offset)
462 {
463 // we've reached the end of Heap, return this location if we'll fit
464 // do we need to coalesce with last empty space?
465 if (mLastEmpty)
466 {
467 // ok, that everything from mLastEmpty to us is empty, so we don't need a block
468 // zero out the last empty's offset and return it
469 mCurrentPosition = mLastEmpty;
470 integer2bytestream(mBuffer, mLastEmpty, 0);
471 mLastEmpty = 0;
472 }
473 // now, zero out next offset to prevent "trouble"
474 offset = mCurrentPosition + size;
475 integer2bytestream(mBuffer, offset, 0);
476
477 // set HP to appropriate value
478 set_register(mBuffer, LREG_HP, mCurrentPosition + size);
479 return size;
480 }
481
482 // ok, is this slot empty?
483 toffset += LSCRIPTDataSize[LST_INTEGER];
484
485 blocktype = *(mBuffer + toffset++);
486
487 if (!blocktype)
488 {
489 // Empty block, do we need to coalesce?
490 if (mLastEmpty)
491 {
492 coalesce(mLastEmpty, mCurrentPosition);
493 mCurrentPosition = mLastEmpty;
494 toffset = mCurrentPosition;
495 offset = bytestream2integer(mBuffer, toffset);
496 }
497
498 // do we fit in this block?
499 if (offset >= size)
500 {
501 // do we need to split the block? (only split if splitting will leave > HEAP_BLOCK_SPLIT_THRESHOLD bytes of free space)
502 if (offset - HEAP_BLOCK_SPLIT_THRESHOLD >= size)
503 {
504 split(mCurrentPosition, size);
505 return size;
506 }
507 else
508 return offset;
509 }
510 }
511 // nothing found, keep looking
512 mCurrentPosition += offset;
513 }
514 // fake return to prevent warnings
515 mCurrentPosition = 0;
516 return 0;
517}
518
519LLScriptHeapRunTime gRunTime;
520#endif