diff options
Diffstat (limited to 'linden/indra/lscript/lscript_execute/lscript_execute.cpp')
-rw-r--r-- | linden/indra/lscript/lscript_execute/lscript_execute.cpp | 985 |
1 files changed, 642 insertions, 343 deletions
diff --git a/linden/indra/lscript/lscript_execute/lscript_execute.cpp b/linden/indra/lscript/lscript_execute/lscript_execute.cpp index 643f3f6..3adfe32 100644 --- a/linden/indra/lscript/lscript_execute/lscript_execute.cpp +++ b/linden/indra/lscript/lscript_execute/lscript_execute.cpp | |||
@@ -31,6 +31,7 @@ | |||
31 | 31 | ||
32 | #include "linden_common.h" | 32 | #include "linden_common.h" |
33 | 33 | ||
34 | #include <algorithm> | ||
34 | #include <sstream> | 35 | #include <sstream> |
35 | 36 | ||
36 | #include "lscript_execute.h" | 37 | #include "lscript_execute.h" |
@@ -43,9 +44,9 @@ | |||
43 | void (*binary_operations[LST_EOF][LST_EOF])(U8 *buffer, LSCRIPTOpCodesEnum opcode); | 44 | void (*binary_operations[LST_EOF][LST_EOF])(U8 *buffer, LSCRIPTOpCodesEnum opcode); |
44 | void (*unary_operations[LST_EOF])(U8 *buffer, LSCRIPTOpCodesEnum opcode); | 45 | void (*unary_operations[LST_EOF])(U8 *buffer, LSCRIPTOpCodesEnum opcode); |
45 | 46 | ||
46 | char* LSCRIPTRunTimeFaultStrings[LSRF_EOF] = /*Flawfinder: ignore*/ | 47 | const char* LSCRIPTRunTimeFaultStrings[LSRF_EOF] = /*Flawfinder: ignore*/ |
47 | { | 48 | { |
48 | "invalid", // LSRF_INVALID, | 49 | "Invalid", // LSRF_INVALID, |
49 | "Math Error", // LSRF_MATH, | 50 | "Math Error", // LSRF_MATH, |
50 | "Stack-Heap Collision", // LSRF_STACK_HEAP_COLLISION, | 51 | "Stack-Heap Collision", // LSRF_STACK_HEAP_COLLISION, |
51 | "Bounds Check Error", // LSRF_BOUND_CHECK_ERROR, | 52 | "Bounds Check Error", // LSRF_BOUND_CHECK_ERROR, |
@@ -55,13 +56,11 @@ char* LSCRIPTRunTimeFaultStrings[LSRF_EOF] = /*Flawfinder: ignore*/ | |||
55 | "Hit Sandbox Limit", // LSRF_SANDBOX, | 56 | "Hit Sandbox Limit", // LSRF_SANDBOX, |
56 | "Chat Overrun", // LSRF_CHAT_OVERRUN, | 57 | "Chat Overrun", // LSRF_CHAT_OVERRUN, |
57 | "Too Many Listens", // LSRF_TOO_MANY_LISTENS, | 58 | "Too Many Listens", // LSRF_TOO_MANY_LISTENS, |
58 | "Lists may not contain lists" // LSRF_NESTING_LISTS, | 59 | "Lists may not contain lists", // LSRF_NESTING_LISTS, |
60 | "CLI Exception" // LSRF_CLI | ||
59 | }; | 61 | }; |
60 | 62 | ||
61 | //static | 63 | LLScriptExecuteLSL2::LLScriptExecuteLSL2(LLFILE *fp) |
62 | S64 LLScriptExecute::sGlobalInstructionCount = 0; | ||
63 | |||
64 | LLScriptExecute::LLScriptExecute(LLFILE *fp) | ||
65 | { | 64 | { |
66 | U8 sizearray[4]; | 65 | U8 sizearray[4]; |
67 | S32 filesize; | 66 | S32 filesize; |
@@ -84,19 +83,26 @@ LLScriptExecute::LLScriptExecute(LLFILE *fp) | |||
84 | init(); | 83 | init(); |
85 | } | 84 | } |
86 | 85 | ||
87 | LLScriptExecute::LLScriptExecute(U8 *buffer) | 86 | LLScriptExecuteLSL2::LLScriptExecuteLSL2(const U8* bytecode, U32 bytecode_size) |
88 | { | 87 | { |
89 | mBuffer = buffer; | 88 | mBuffer = new U8[TOP_OF_MEMORY]; |
90 | 89 | memset(mBuffer + bytecode_size, 0, TOP_OF_MEMORY - bytecode_size); | |
90 | S32 src_offset = 0; | ||
91 | S32 dest_offset = 0; | ||
92 | bytestream2bytestream(mBuffer, dest_offset, bytecode, src_offset, bytecode_size); | ||
93 | mBytecodeSize = bytecode_size; | ||
94 | mBytecode = new U8[mBytecodeSize]; | ||
95 | memcpy(mBytecode, bytecode, mBytecodeSize); | ||
91 | init(); | 96 | init(); |
92 | } | 97 | } |
93 | 98 | ||
94 | LLScriptExecute::~LLScriptExecute() | 99 | LLScriptExecuteLSL2::~LLScriptExecuteLSL2() |
95 | { | 100 | { |
96 | delete [] mBuffer; | 101 | delete[] mBuffer; |
102 | delete[] mBytecode; | ||
97 | } | 103 | } |
98 | 104 | ||
99 | void LLScriptExecute::init() | 105 | void LLScriptExecuteLSL2::init() |
100 | { | 106 | { |
101 | S32 i, j; | 107 | S32 i, j; |
102 | 108 | ||
@@ -270,7 +276,7 @@ void LLScriptExecute::init() | |||
270 | 276 | ||
271 | 277 | ||
272 | // Utility routine for when there's a boundary error parsing bytecode | 278 | // Utility routine for when there's a boundary error parsing bytecode |
273 | void LLScriptExecute::recordBoundaryError( const LLUUID &id ) | 279 | void LLScriptExecuteLSL2::recordBoundaryError( const LLUUID &id ) |
274 | { | 280 | { |
275 | set_fault(mBuffer, LSRF_BOUND_CHECK_ERROR); | 281 | set_fault(mBuffer, LSRF_BOUND_CHECK_ERROR); |
276 | llwarns << "Script boundary error for ID " << id << llendl; | 282 | llwarns << "Script boundary error for ID " << id << llendl; |
@@ -278,7 +284,7 @@ void LLScriptExecute::recordBoundaryError( const LLUUID &id ) | |||
278 | 284 | ||
279 | 285 | ||
280 | // set IP to the event handler with some error checking | 286 | // set IP to the event handler with some error checking |
281 | void LLScriptExecute::setStateEventOpcoodeStartSafely( S32 state, LSCRIPTStateEventType event, const LLUUID &id ) | 287 | void LLScriptExecuteLSL2::setStateEventOpcoodeStartSafely( S32 state, LSCRIPTStateEventType event, const LLUUID &id ) |
282 | { | 288 | { |
283 | S32 opcode_start = get_state_event_opcoode_start( mBuffer, state, event ); | 289 | S32 opcode_start = get_state_event_opcoode_start( mBuffer, state, event ); |
284 | if ( opcode_start == -1 ) | 290 | if ( opcode_start == -1 ) |
@@ -296,12 +302,474 @@ void LLScriptExecute::setStateEventOpcoodeStartSafely( S32 state, LSCRIPTStateEv | |||
296 | 302 | ||
297 | S32 lscript_push_variable(LLScriptLibData *data, U8 *buffer); | 303 | S32 lscript_push_variable(LLScriptLibData *data, U8 *buffer); |
298 | 304 | ||
299 | U32 LLScriptExecute::run(BOOL b_print, const LLUUID &id, char **errorstr, BOOL &state_transition) | 305 | void LLScriptExecuteLSL2::resumeEventHandler(BOOL b_print, const LLUUID &id, F32 time_slice) |
306 | { | ||
307 | // call opcode run function pointer with buffer and IP | ||
308 | mInstructionCount++; | ||
309 | S32 value = get_register(mBuffer, LREG_IP); | ||
310 | S32 tvalue = value; | ||
311 | S32 opcode = safe_instruction_bytestream2byte(mBuffer, tvalue); | ||
312 | mExecuteFuncs[opcode](mBuffer, value, b_print, id); | ||
313 | set_ip(mBuffer, value); | ||
314 | add_register_fp(mBuffer, LREG_ESR, -0.1f); | ||
315 | // lsa_print_heap(mBuffer); | ||
316 | |||
317 | if (b_print) | ||
318 | { | ||
319 | lsa_print_heap(mBuffer); | ||
320 | printf("ip: 0x%X\n", get_register(mBuffer, LREG_IP)); | ||
321 | printf("sp: 0x%X\n", get_register(mBuffer, LREG_SP)); | ||
322 | printf("bp: 0x%X\n", get_register(mBuffer, LREG_BP)); | ||
323 | printf("hr: 0x%X\n", get_register(mBuffer, LREG_HR)); | ||
324 | printf("hp: 0x%X\n", get_register(mBuffer, LREG_HP)); | ||
325 | } | ||
326 | |||
327 | // NOTE: Babbage: all mExecuteFuncs return false. | ||
328 | } | ||
329 | |||
330 | void LLScriptExecuteLSL2::callEventHandler(LSCRIPTStateEventType event, S32 major_version, const LLUUID &id, F32 time_slice) | ||
331 | { | ||
332 | // push a zero to be popped | ||
333 | lscript_push(mBuffer, 0); | ||
334 | // push sp as current bp | ||
335 | S32 sp = get_register(mBuffer, LREG_SP); | ||
336 | lscript_push(mBuffer, sp); | ||
337 | |||
338 | // Update current handler and current events registers. | ||
339 | set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); | ||
340 | U64 current_events = get_event_register(mBuffer, LREG_CE, major_version); | ||
341 | current_events &= ~LSCRIPTStateBitField[event]; | ||
342 | set_event_register(mBuffer, LREG_CE, current_events, major_version); | ||
343 | |||
344 | // now, push any additional stack space | ||
345 | U32 current_state = get_register(mBuffer, LREG_CS); | ||
346 | S32 additional_size = get_event_stack_size(mBuffer, current_state, event); | ||
347 | lscript_pusharge(mBuffer, additional_size); | ||
348 | |||
349 | // now set the bp correctly | ||
350 | sp = get_register(mBuffer, LREG_SP); | ||
351 | sp += additional_size; | ||
352 | set_bp(mBuffer, sp); | ||
353 | |||
354 | // set IP to the function | ||
355 | S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, event); | ||
356 | set_ip(mBuffer, opcode_start); | ||
357 | } | ||
358 | |||
359 | //void callStateExitHandler() | ||
360 | //{ | ||
361 | // // push a zero to be popped | ||
362 | // lscript_push(mBuffer, 0); | ||
363 | // // push sp as current bp | ||
364 | // S32 sp = get_register(mBuffer, LREG_SP); | ||
365 | // lscript_push(mBuffer, sp); | ||
366 | // | ||
367 | // // now, push any additional stack space | ||
368 | // S32 additional_size = get_event_stack_size(mBuffer, current_state, LSTT_STATE_EXIT); | ||
369 | // lscript_pusharge(mBuffer, additional_size); | ||
370 | // | ||
371 | // sp = get_register(mBuffer, LREG_SP); | ||
372 | // sp += additional_size; | ||
373 | // set_bp(mBuffer, sp); | ||
374 | // | ||
375 | // // set IP to the event handler | ||
376 | // S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, LSTT_STATE_EXIT); | ||
377 | // set_ip(mBuffer, opcode_start); | ||
378 | //} | ||
379 | // | ||
380 | //void callStateEntryHandler() | ||
381 | //{ | ||
382 | // // push a zero to be popped | ||
383 | // lscript_push(mBuffer, 0); | ||
384 | // // push sp as current bp | ||
385 | // S32 sp = get_register(mBuffer, LREG_SP); | ||
386 | // lscript_push(mBuffer, sp); | ||
387 | // | ||
388 | // event = return_first_event((S32)LSCRIPTStateBitField[LSTT_STATE_ENTRY]); | ||
389 | // set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); | ||
390 | // current_events &= ~LSCRIPTStateBitField[event]; | ||
391 | // set_event_register(mBuffer, LREG_CE, current_events, major_version); | ||
392 | // | ||
393 | // // now, push any additional stack space | ||
394 | // S32 additional_size = get_event_stack_size(mBuffer, current_state, event) - size; | ||
395 | // lscript_pusharge(mBuffer, additional_size); | ||
396 | // | ||
397 | // // now set the bp correctly | ||
398 | // sp = get_register(mBuffer, LREG_SP); | ||
399 | // sp += additional_size + size; | ||
400 | // set_bp(mBuffer, sp); | ||
401 | // // set IP to the function | ||
402 | // S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, event); | ||
403 | // set_ip(mBuffer, opcode_start); | ||
404 | //} | ||
405 | |||
406 | void LLScriptExecuteLSL2::callQueuedEventHandler(LSCRIPTStateEventType event, S32 major_version, const LLUUID &id, F32 time_slice) | ||
407 | { | ||
408 | LLScriptDataCollection* eventdata; | ||
409 | |||
410 | for (eventdata = mEventData.mEventDataList.getFirstData(); eventdata; eventdata = mEventData.mEventDataList.getNextData()) | ||
411 | { | ||
412 | if (eventdata->mType == event) | ||
413 | { | ||
414 | // push a zero to be popped | ||
415 | lscript_push(mBuffer, 0); | ||
416 | // push sp as current bp | ||
417 | S32 sp = get_register(mBuffer, LREG_SP); | ||
418 | lscript_push(mBuffer, sp); | ||
419 | |||
420 | // Update current handler and current events registers. | ||
421 | set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); | ||
422 | U64 current_events = get_event_register(mBuffer, LREG_CE, major_version); | ||
423 | current_events &= ~LSCRIPTStateBitField[event]; | ||
424 | set_event_register(mBuffer, LREG_CE, current_events, major_version); | ||
425 | |||
426 | // push any arguments that need to be pushed onto the stack | ||
427 | // last piece of data will be type LST_NULL | ||
428 | LLScriptLibData *data = eventdata->mData; | ||
429 | U32 size = 0; | ||
430 | while (data->mType) | ||
431 | { | ||
432 | size += lscript_push_variable(data, mBuffer); | ||
433 | data++; | ||
434 | } | ||
435 | // now, push any additional stack space | ||
436 | U32 current_state = get_register(mBuffer, LREG_CS); | ||
437 | S32 additional_size = get_event_stack_size(mBuffer, current_state, event) - size; | ||
438 | lscript_pusharge(mBuffer, additional_size); | ||
439 | |||
440 | // now set the bp correctly | ||
441 | sp = get_register(mBuffer, LREG_SP); | ||
442 | sp += additional_size + size; | ||
443 | set_bp(mBuffer, sp); | ||
444 | |||
445 | // set IP to the function | ||
446 | S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, event); | ||
447 | set_ip(mBuffer, opcode_start); | ||
448 | |||
449 | mEventData.mEventDataList.deleteCurrentData(); | ||
450 | break; | ||
451 | } | ||
452 | } | ||
453 | } | ||
454 | |||
455 | void LLScriptExecuteLSL2::callNextQueuedEventHandler(U64 event_register, S32 major_version, const LLUUID &id, F32 time_slice) | ||
456 | { | ||
457 | LLScriptDataCollection* eventdata = mEventData.getNextEvent(); | ||
458 | if (eventdata) | ||
459 | { | ||
460 | LSCRIPTStateEventType event = eventdata->mType; | ||
461 | |||
462 | // make sure that we can actually handle this one | ||
463 | if (LSCRIPTStateBitField[event] & event_register) | ||
464 | { | ||
465 | // push a zero to be popped | ||
466 | lscript_push(mBuffer, 0); | ||
467 | // push sp as current bp | ||
468 | S32 sp = get_register(mBuffer, LREG_SP); | ||
469 | lscript_push(mBuffer, sp); | ||
470 | |||
471 | // Update current handler and current events registers. | ||
472 | set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); | ||
473 | U64 current_events = get_event_register(mBuffer, LREG_CE, major_version); | ||
474 | current_events &= ~LSCRIPTStateBitField[event]; | ||
475 | set_event_register(mBuffer, LREG_CE, current_events, major_version); | ||
476 | |||
477 | // push any arguments that need to be pushed onto the stack | ||
478 | // last piece of data will be type LST_NULL | ||
479 | LLScriptLibData *data = eventdata->mData; | ||
480 | U32 size = 0; | ||
481 | while (data->mType) | ||
482 | { | ||
483 | size += lscript_push_variable(data, mBuffer); | ||
484 | data++; | ||
485 | } | ||
486 | |||
487 | // now, push any additional stack space | ||
488 | U32 current_state = get_register(mBuffer, LREG_CS); | ||
489 | S32 additional_size = get_event_stack_size(mBuffer, current_state, event) - size; | ||
490 | lscript_pusharge(mBuffer, additional_size); | ||
491 | |||
492 | // now set the bp correctly | ||
493 | sp = get_register(mBuffer, LREG_SP); | ||
494 | sp += additional_size + size; | ||
495 | set_bp(mBuffer, sp); | ||
496 | |||
497 | // set IP to the function | ||
498 | S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, event); | ||
499 | set_ip(mBuffer, opcode_start); | ||
500 | } | ||
501 | else | ||
502 | { | ||
503 | llwarns << "Shit, somehow got an event that we're not registered for!" << llendl; | ||
504 | } | ||
505 | delete eventdata; | ||
506 | } | ||
507 | } | ||
508 | |||
509 | U64 LLScriptExecuteLSL2::nextState() | ||
510 | { | ||
511 | // copy NS to CS | ||
512 | S32 next_state = get_register(mBuffer, LREG_NS); | ||
513 | set_register(mBuffer, LREG_CS, next_state); | ||
514 | |||
515 | // copy new state's handled events into ER (SR + CS*4 + 4) | ||
516 | return get_handled_events(mBuffer, next_state); | ||
517 | } | ||
518 | |||
519 | //virtual | ||
520 | void LLScriptExecuteLSL2::addEvent(LLScriptDataCollection* event) | ||
521 | { | ||
522 | mEventData.addEventData(event); | ||
523 | } | ||
524 | |||
525 | //virtual | ||
526 | void LLScriptExecuteLSL2::removeEventType(LSCRIPTStateEventType event_type) | ||
527 | { | ||
528 | mEventData.removeEventType(event_type); | ||
529 | } | ||
530 | |||
531 | //virtual | ||
532 | F32 LLScriptExecuteLSL2::getSleep() const | ||
533 | { | ||
534 | return get_register_fp(mBuffer, LREG_SLR); | ||
535 | } | ||
536 | |||
537 | //virtual | ||
538 | void LLScriptExecuteLSL2::setSleep(F32 value) | ||
539 | { | ||
540 | set_register_fp(mBuffer, LREG_SLR, value); | ||
541 | } | ||
542 | |||
543 | //virtual | ||
544 | U64 LLScriptExecuteLSL2::getCurrentHandler(S32 version) | ||
545 | { | ||
546 | return get_event_register(mBuffer, LREG_IE, version); | ||
547 | } | ||
548 | |||
549 | //virtual | ||
550 | F32 LLScriptExecuteLSL2::getEnergy() const | ||
551 | { | ||
552 | return get_register_fp(mBuffer, LREG_ESR); | ||
553 | } | ||
554 | |||
555 | //virtual | ||
556 | void LLScriptExecuteLSL2::setEnergy(F32 value) | ||
557 | { | ||
558 | set_register_fp(mBuffer, LREG_ESR, value); | ||
559 | } | ||
560 | |||
561 | //virtual | ||
562 | U32 LLScriptExecuteLSL2::getFreeMemory() | ||
563 | { | ||
564 | return get_register(mBuffer, LREG_SP) - get_register(mBuffer, LREG_HP); | ||
565 | } | ||
566 | |||
567 | //virtual | ||
568 | S32 LLScriptExecuteLSL2::getParameter() | ||
569 | { | ||
570 | return get_register(mBuffer, LREG_PR); | ||
571 | } | ||
572 | |||
573 | //virtual | ||
574 | void LLScriptExecuteLSL2::setParameter(S32 value) | ||
575 | { | ||
576 | set_register(mBuffer, LREG_PR, value); | ||
577 | } | ||
578 | |||
579 | |||
580 | S32 LLScriptExecuteLSL2::writeState(U8 **dest, U32 header_size, U32 footer_size) | ||
581 | { | ||
582 | // data format: | ||
583 | // 4 bytes of size of Registers, Name and Description, and Global Variables | ||
584 | // Registers, Name and Description, and Global Variables data | ||
585 | // 4 bytes of size of Heap | ||
586 | // Heap data | ||
587 | // 4 bytes of stack size | ||
588 | // Stack data | ||
589 | |||
590 | S32 registers_size = get_register(mBuffer, LREG_GFR); | ||
591 | |||
592 | if (get_register(mBuffer, LREG_HP) > TOP_OF_MEMORY) | ||
593 | reset_hp_to_safe_spot(mBuffer); | ||
594 | |||
595 | S32 heap_size = get_register(mBuffer, LREG_HP) - get_register(mBuffer, LREG_HR); | ||
596 | S32 stack_size = get_register(mBuffer, LREG_TM) - get_register(mBuffer, LREG_SP); | ||
597 | S32 total_size = registers_size + LSCRIPTDataSize[LST_INTEGER] + | ||
598 | heap_size + LSCRIPTDataSize[LST_INTEGER] + | ||
599 | stack_size + LSCRIPTDataSize[LST_INTEGER]; | ||
600 | |||
601 | // actually allocate data | ||
602 | delete[] *dest; | ||
603 | *dest = new U8[header_size + total_size + footer_size]; | ||
604 | memset(*dest, 0, header_size + total_size + footer_size); | ||
605 | S32 dest_offset = header_size; | ||
606 | S32 src_offset = 0; | ||
607 | |||
608 | // registers | ||
609 | integer2bytestream(*dest, dest_offset, registers_size); | ||
610 | |||
611 | // llinfos << "Writing CE: " << getCurrentEvents() << llendl; | ||
612 | bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, registers_size); | ||
613 | |||
614 | // heap | ||
615 | integer2bytestream(*dest, dest_offset, heap_size); | ||
616 | |||
617 | src_offset = get_register(mBuffer, LREG_HR); | ||
618 | bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, heap_size); | ||
619 | |||
620 | // stack | ||
621 | integer2bytestream(*dest, dest_offset, stack_size); | ||
622 | |||
623 | src_offset = get_register(mBuffer, LREG_SP); | ||
624 | bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, stack_size); | ||
625 | |||
626 | return total_size; | ||
627 | } | ||
628 | |||
629 | S32 LLScriptExecuteLSL2::writeBytecode(U8 **dest) | ||
630 | { | ||
631 | // data format: | ||
632 | // registers through top of heap | ||
633 | // Heap data | ||
634 | S32 total_size = get_register(mBuffer, LREG_HP); | ||
635 | |||
636 | // actually allocate data | ||
637 | delete [] *dest; | ||
638 | *dest = new U8[total_size]; | ||
639 | S32 dest_offset = 0; | ||
640 | S32 src_offset = 0; | ||
641 | |||
642 | bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, total_size); | ||
643 | |||
644 | return total_size; | ||
645 | } | ||
646 | |||
647 | S32 LLScriptExecuteLSL2::readState(U8 *src) | ||
648 | { | ||
649 | // first, blitz heap and stack | ||
650 | S32 hr = get_register(mBuffer, LREG_HR); | ||
651 | S32 tm = get_register(mBuffer, LREG_TM); | ||
652 | memset(mBuffer + hr, 0, tm - hr); | ||
653 | |||
654 | S32 src_offset = 0; | ||
655 | S32 dest_offset = 0; | ||
656 | S32 size; | ||
657 | |||
658 | // read register size | ||
659 | size = bytestream2integer(src, src_offset); | ||
660 | |||
661 | // copy data into register area | ||
662 | bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size); | ||
663 | // llinfos << "Read CE: " << getCurrentEvents() << llendl; | ||
664 | if (get_register(mBuffer, LREG_TM) != TOP_OF_MEMORY) | ||
665 | { | ||
666 | llwarns << "Invalid state. Top of memory register does not match" | ||
667 | << " constant." << llendl; | ||
668 | reset_hp_to_safe_spot(mBuffer); | ||
669 | return -1; | ||
670 | } | ||
671 | |||
672 | // read heap size | ||
673 | size = bytestream2integer(src, src_offset); | ||
674 | |||
675 | // set dest offset | ||
676 | dest_offset = get_register(mBuffer, LREG_HR); | ||
677 | |||
678 | if (dest_offset + size > TOP_OF_MEMORY) | ||
679 | { | ||
680 | reset_hp_to_safe_spot(mBuffer); | ||
681 | return -1; | ||
682 | } | ||
683 | |||
684 | // copy data into heap area | ||
685 | bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size); | ||
686 | |||
687 | // read stack size | ||
688 | size = bytestream2integer(src, src_offset); | ||
689 | |||
690 | // set dest offset | ||
691 | dest_offset = get_register(mBuffer, LREG_SP); | ||
692 | |||
693 | if (dest_offset + size > TOP_OF_MEMORY) | ||
694 | { | ||
695 | reset_hp_to_safe_spot(mBuffer); | ||
696 | return -1; | ||
697 | } | ||
698 | |||
699 | // copy data into heap area | ||
700 | bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size); | ||
701 | |||
702 | // Return offset to first byte after read data. | ||
703 | return src_offset; | ||
704 | } | ||
705 | |||
706 | void LLScriptExecuteLSL2::reset() | ||
707 | { | ||
708 | LLScriptExecute::reset(); | ||
709 | |||
710 | const U8 *src = getBytecode(); | ||
711 | S32 size = getBytecodeSize(); | ||
712 | |||
713 | if (!src) | ||
714 | return; | ||
715 | |||
716 | // first, blitz heap and stack | ||
717 | S32 hr = get_register(mBuffer, LREG_HR); | ||
718 | S32 tm = get_register(mBuffer, LREG_TM); | ||
719 | memset(mBuffer + hr, 0, tm - hr); | ||
720 | |||
721 | S32 dest_offset = 0; | ||
722 | S32 src_offset = 0; | ||
723 | |||
724 | bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size); | ||
725 | } | ||
726 | |||
727 | LLScriptExecute::LLScriptExecute() : | ||
728 | mReset(FALSE) | ||
729 | { | ||
730 | } | ||
731 | |||
732 | void LLScriptExecute::reset() | ||
733 | { | ||
734 | mReset = FALSE; | ||
735 | } | ||
736 | |||
737 | bool LLScriptExecute::isYieldDue() const | ||
738 | { | ||
739 | if(mReset) | ||
740 | { | ||
741 | return true; | ||
742 | } | ||
743 | |||
744 | if(getSleep() > 0.f) | ||
745 | { | ||
746 | return true; | ||
747 | } | ||
748 | |||
749 | if(isFinished()) | ||
750 | { | ||
751 | return true; | ||
752 | } | ||
753 | |||
754 | if(isStateChangePending()) | ||
755 | { | ||
756 | return true; | ||
757 | } | ||
758 | |||
759 | return false; | ||
760 | } | ||
761 | |||
762 | // Run smallest number of instructions possible: | ||
763 | // a single instruction for LSL2, a segment between save tests for Mono | ||
764 | void LLScriptExecute::runInstructions(BOOL b_print, const LLUUID &id, | ||
765 | const char **errorstr, | ||
766 | BOOL &state_transition, | ||
767 | U32& events_processed, | ||
768 | F32 quanta) | ||
300 | { | 769 | { |
301 | // is there a fault? | 770 | // is there a fault? |
302 | // if yes, print out message and exit | 771 | // if yes, print out message and exit |
303 | state_transition = FALSE; | 772 | S32 value = getVersion(); |
304 | S32 value = get_register(mBuffer, LREG_VN); | ||
305 | S32 major_version = 0; | 773 | S32 major_version = 0; |
306 | if (value == LSL2_VERSION1_END_NUMBER) | 774 | if (value == LSL2_VERSION1_END_NUMBER) |
307 | { | 775 | { |
@@ -313,323 +781,151 @@ U32 LLScriptExecute::run(BOOL b_print, const LLUUID &id, char **errorstr, BOOL & | |||
313 | } | 781 | } |
314 | else | 782 | else |
315 | { | 783 | { |
316 | set_fault(mBuffer, LSRF_VERSION_MISMATCH); | 784 | setFault(LSRF_VERSION_MISMATCH); |
317 | } | 785 | } |
318 | value = get_register(mBuffer, LREG_FR); | 786 | value = getFaults(); |
319 | if (value) | 787 | if (value > LSRF_INVALID && value < LSRF_EOF) |
320 | { | 788 | { |
321 | if (b_print) | 789 | if (b_print) |
322 | { | 790 | { |
323 | printf("Error!\n"); | 791 | printf("Error!\n"); |
324 | } | 792 | } |
325 | *errorstr = LSCRIPTRunTimeFaultStrings[value]; | 793 | *errorstr = LSCRIPTRunTimeFaultStrings[value]; |
326 | return NO_DELETE_FLAG; | 794 | return; |
327 | } | 795 | } |
328 | else | 796 | else |
329 | { | 797 | { |
330 | *errorstr = NULL; | 798 | *errorstr = NULL; |
331 | } | 799 | } |
332 | 800 | ||
333 | // Get IP | 801 | if (! isFinished()) |
334 | // is IP nonzero? | ||
335 | value = get_register(mBuffer, LREG_IP); | ||
336 | |||
337 | if (value) | ||
338 | { | 802 | { |
339 | // if yes, we're in opcodes, execute the next opcode by: | 803 | resumeEventHandler(b_print, id, quanta); |
340 | // call opcode run function pointer with buffer and IP | 804 | return; |
341 | mInstructionCount++; | ||
342 | sGlobalInstructionCount++; | ||
343 | S32 tvalue = value; | ||
344 | S32 opcode = safe_instruction_bytestream2byte(mBuffer, tvalue); | ||
345 | S32 b_ret_val = mExecuteFuncs[opcode](mBuffer, value, b_print, id); | ||
346 | set_ip(mBuffer, value); | ||
347 | add_register_fp(mBuffer, LREG_ESR, -0.1f); | ||
348 | // lsa_print_heap(mBuffer); | ||
349 | |||
350 | if (b_print) | ||
351 | { | ||
352 | lsa_print_heap(mBuffer); | ||
353 | printf("ip: 0x%X\n", get_register(mBuffer, LREG_IP)); | ||
354 | printf("sp: 0x%X\n", get_register(mBuffer, LREG_SP)); | ||
355 | printf("bp: 0x%X\n", get_register(mBuffer, LREG_BP)); | ||
356 | printf("hr: 0x%X\n", get_register(mBuffer, LREG_HR)); | ||
357 | printf("hp: 0x%X\n", get_register(mBuffer, LREG_HP)); | ||
358 | } | ||
359 | // update IP | ||
360 | if (b_ret_val) | ||
361 | { | ||
362 | return DELETE_FLAG | CREDIT_MONEY_FLAG; | ||
363 | } | ||
364 | else | ||
365 | { | ||
366 | return NO_DELETE_FLAG; | ||
367 | } | ||
368 | } | 805 | } |
369 | else | 806 | else |
370 | { | 807 | { |
371 | // make sure that IE is zero | 808 | // make sure that IE is zero |
372 | set_event_register(mBuffer, LREG_IE, 0, major_version); | 809 | setCurrentHandler(0, major_version); |
373 | 810 | ||
374 | // if no, we're in a state and waiting for an event | 811 | // if no, we're in a state and waiting for an event |
375 | S32 next_state = get_register(mBuffer, LREG_NS); | 812 | U64 current_events = getCurrentEvents(major_version); |
376 | S32 current_state = get_register(mBuffer, LREG_CS); | 813 | U64 event_register = getEventHandlers(major_version); |
377 | U64 current_events = get_event_register(mBuffer, LREG_CE, major_version); | 814 | |
378 | U64 event_register = get_event_register(mBuffer, LREG_ER, major_version); | 815 | // check NS to see if need to switch states (NS != CS) |
379 | // check NS to see if need to switch states (NS != CS) | 816 | if (isStateChangePending()) |
380 | if (next_state != current_state) | ||
381 | { | 817 | { |
382 | state_transition = TRUE; | 818 | state_transition = TRUE; |
819 | |||
383 | // ok, blow away any pending events | 820 | // ok, blow away any pending events |
384 | mEventData.mEventDataList.deleteAllData(); | 821 | deleteAllEvents(); |
385 | 822 | ||
386 | // if yes, check state exit flag is set | 823 | // if yes, check state exit flag is set |
387 | if (current_events & LSCRIPTStateBitField[LSTT_STATE_EXIT]) | 824 | if (current_events & LSCRIPTStateBitField[LSTT_STATE_EXIT]) |
388 | { | 825 | { |
389 | // if yes, clear state exit flag | 826 | // if yes, clear state exit flag |
390 | set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[LSTT_STATE_EXIT], major_version); | 827 | setCurrentHandler(LSCRIPTStateBitField[LSTT_STATE_EXIT], major_version); |
391 | current_events &= ~LSCRIPTStateBitField[LSTT_STATE_EXIT]; | 828 | current_events &= ~LSCRIPTStateBitField[LSTT_STATE_EXIT]; |
392 | set_event_register(mBuffer, LREG_CE, current_events, major_version); | 829 | setCurrentEvents(current_events, major_version); |
393 | // check state exit event handler | 830 | |
394 | // if there is a handler, call it | 831 | // check state exit event handler |
832 | // if there is a handler, call it | ||
395 | if (event_register & LSCRIPTStateBitField[LSTT_STATE_EXIT]) | 833 | if (event_register & LSCRIPTStateBitField[LSTT_STATE_EXIT]) |
396 | { | 834 | { |
397 | // push a zero to be popped | 835 | ++events_processed; |
398 | lscript_push(mBuffer, 0); | 836 | callEventHandler(LSTT_STATE_EXIT, major_version, id, quanta); |
399 | // push sp as current bp | 837 | return; |
400 | S32 sp = get_register(mBuffer, LREG_SP); | ||
401 | lscript_push(mBuffer, sp); | ||
402 | |||
403 | // now, push any additional stack space | ||
404 | S32 additional_size = get_event_stack_size(mBuffer, current_state, LSTT_STATE_EXIT); | ||
405 | if ( additional_size == -1 ) | ||
406 | { | ||
407 | recordBoundaryError( id ); | ||
408 | } | ||
409 | else | ||
410 | { | ||
411 | lscript_pusharge(mBuffer, additional_size); | ||
412 | |||
413 | sp = get_register(mBuffer, LREG_SP); | ||
414 | sp += additional_size; | ||
415 | set_bp(mBuffer, sp); | ||
416 | // set IP to the event handler | ||
417 | setStateEventOpcoodeStartSafely( current_state, LSTT_STATE_EXIT, id ); | ||
418 | } | ||
419 | return NO_DELETE_FLAG; | ||
420 | } | 838 | } |
421 | } | 839 | } |
422 | // if no handler or no state exit flag switch to new state | 840 | |
423 | // set state entry flag and clear other CE flags | 841 | // if no handler or no state exit flag switch to new state |
842 | // set state entry flag and clear other CE flags | ||
424 | current_events = LSCRIPTStateBitField[LSTT_STATE_ENTRY]; | 843 | current_events = LSCRIPTStateBitField[LSTT_STATE_ENTRY]; |
425 | set_event_register(mBuffer, LREG_CE, current_events, major_version); | 844 | setCurrentEvents(current_events, major_version); |
426 | // copy NS to CS | 845 | |
427 | set_register(mBuffer, LREG_CS, next_state); | 846 | U64 handled_events = nextState(); |
428 | // copy new state's handled events into ER (SR + CS*4 + 4) | 847 | setEventHandlers(handled_events, major_version); |
429 | U64 handled_events = get_handled_events(mBuffer, next_state); | ||
430 | set_event_register(mBuffer, LREG_ER, handled_events, major_version); | ||
431 | } | 848 | } |
432 | // check to see if any current events are covered by events handled by this state (CE & ER != 0) | 849 | |
433 | // now, we want to look like we were called like a function | 850 | // try to get next event from stack |
434 | // 0x0000: 00 00 00 00 (return ip) | ||
435 | // 0x0004: bp (current sp) | ||
436 | // 0x0008: parameters | ||
437 | // push sp | ||
438 | // add parameter size | ||
439 | // pop bp | ||
440 | // set ip | ||
441 | |||
442 | S32 size = 0; | ||
443 | // try to get next event from stack | ||
444 | BOOL b_done = FALSE; | 851 | BOOL b_done = FALSE; |
445 | LSCRIPTStateEventType event = LSTT_NULL; | 852 | LSCRIPTStateEventType event = LSTT_NULL; |
446 | LLScriptDataCollection *eventdata; | ||
447 | 853 | ||
448 | next_state = get_register(mBuffer, LREG_NS); | 854 | current_events = getCurrentEvents(major_version); |
449 | current_state = get_register(mBuffer, LREG_CS); | 855 | event_register = getEventHandlers(major_version); |
450 | current_events = get_event_register(mBuffer, LREG_CE, major_version); | ||
451 | event_register = get_event_register(mBuffer, LREG_ER, major_version); | ||
452 | 856 | ||
453 | // first, check to see if state_entry or onrez are raised and handled | 857 | // first, check to see if state_entry or onrez are raised and handled |
454 | if ( (current_events & LSCRIPTStateBitField[LSTT_STATE_ENTRY]) | 858 | if ((current_events & LSCRIPTStateBitField[LSTT_STATE_ENTRY]) |
455 | &&(current_events & event_register)) | 859 | &&(current_events & event_register)) |
456 | { | 860 | { |
457 | // ok, this is easy since there isn't any data waiting, just set it | 861 | ++events_processed; |
458 | // push a zero to be popped | 862 | callEventHandler(LSTT_STATE_ENTRY, major_version, id, quanta); |
459 | lscript_push(mBuffer, 0); | ||
460 | // push sp as current bp | ||
461 | S32 sp = get_register(mBuffer, LREG_SP); | ||
462 | lscript_push(mBuffer, sp); | ||
463 | |||
464 | event = return_first_event((S32)LSCRIPTStateBitField[LSTT_STATE_ENTRY]); | ||
465 | set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); | ||
466 | current_events &= ~LSCRIPTStateBitField[event]; | ||
467 | set_event_register(mBuffer, LREG_CE, current_events, major_version); | ||
468 | // now, push any additional stack space | ||
469 | S32 additional_size = get_event_stack_size(mBuffer, current_state, event); | ||
470 | if ( additional_size == -1 ) | ||
471 | { // b_done will be set, so we'll exit the loop at the bottom | ||
472 | recordBoundaryError( id ); | ||
473 | } | ||
474 | else | ||
475 | { | ||
476 | additional_size -= size; | ||
477 | lscript_pusharge(mBuffer, additional_size); | ||
478 | |||
479 | // now set the bp correctly | ||
480 | sp = get_register(mBuffer, LREG_SP); | ||
481 | sp += additional_size + size; | ||
482 | set_bp(mBuffer, sp); | ||
483 | // set IP to the function | ||
484 | setStateEventOpcoodeStartSafely( current_state, event, id ); | ||
485 | } | ||
486 | b_done = TRUE; | 863 | b_done = TRUE; |
487 | } | 864 | } |
488 | else if ( (current_events & LSCRIPTStateBitField[LSTT_REZ]) | 865 | else if ((current_events & LSCRIPTStateBitField[LSTT_REZ]) |
489 | &&(current_events & event_register)) | 866 | &&(current_events & event_register)) |
490 | { | 867 | { |
491 | for (eventdata = mEventData.mEventDataList.getFirstData(); eventdata; eventdata = mEventData.mEventDataList.getNextData()) | 868 | ++events_processed; |
492 | { | 869 | callQueuedEventHandler(LSTT_REZ, major_version, id, quanta); |
493 | if (eventdata->mType & LSCRIPTStateBitField[LSTT_REZ]) | 870 | b_done = TRUE; |
494 | { | ||
495 | // push a zero to be popped | ||
496 | lscript_push(mBuffer, 0); | ||
497 | // push sp as current bp | ||
498 | S32 sp = get_register(mBuffer, LREG_SP); | ||
499 | lscript_push(mBuffer, sp); | ||
500 | |||
501 | set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); | ||
502 | current_events &= ~LSCRIPTStateBitField[event]; | ||
503 | set_event_register(mBuffer, LREG_CE, current_events, major_version); | ||
504 | |||
505 | // push any arguments that need to be pushed onto the stack | ||
506 | // last piece of data will be type LST_NULL | ||
507 | LLScriptLibData *data = eventdata->mData; | ||
508 | while (data->mType) | ||
509 | { | ||
510 | size += lscript_push_variable(data, mBuffer); | ||
511 | data++; | ||
512 | } | ||
513 | // now, push any additional stack space | ||
514 | S32 additional_size = get_event_stack_size(mBuffer, current_state, event); | ||
515 | if ( additional_size == -1 ) | ||
516 | { // b_done will be set, so we'll exit the loop at the bottom | ||
517 | recordBoundaryError( id ); | ||
518 | } | ||
519 | else | ||
520 | { | ||
521 | additional_size -= size; | ||
522 | lscript_pusharge(mBuffer, additional_size); | ||
523 | |||
524 | // now set the bp correctly | ||
525 | sp = get_register(mBuffer, LREG_SP); | ||
526 | sp += additional_size + size; | ||
527 | set_bp(mBuffer, sp); | ||
528 | // set IP to the function | ||
529 | setStateEventOpcoodeStartSafely( current_state, event, id ); | ||
530 | mEventData.mEventDataList.deleteCurrentData(); | ||
531 | } | ||
532 | b_done = TRUE; | ||
533 | break; | ||
534 | } | ||
535 | } | ||
536 | } | 871 | } |
537 | 872 | ||
538 | while (!b_done) | 873 | while (!b_done) |
539 | { | 874 | { |
540 | eventdata = mEventData.getNextEvent(); | 875 | // Call handler for next queued event. |
541 | if (eventdata) | 876 | if(getEventCount() > 0) |
542 | { | 877 | { |
543 | event = eventdata->mType; | 878 | ++events_processed; |
544 | 879 | callNextQueuedEventHandler(event_register, major_version, id, quanta); | |
545 | // make sure that we can actually handle this one | 880 | b_done = TRUE; |
546 | if (LSCRIPTStateBitField[event] & event_register) | ||
547 | { | ||
548 | // push a zero to be popped | ||
549 | lscript_push(mBuffer, 0); | ||
550 | // push sp as current bp | ||
551 | S32 sp = get_register(mBuffer, LREG_SP); | ||
552 | lscript_push(mBuffer, sp); | ||
553 | |||
554 | set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); | ||
555 | current_events &= ~LSCRIPTStateBitField[event]; | ||
556 | set_event_register(mBuffer, LREG_CE, current_events, major_version); | ||
557 | |||
558 | // push any arguments that need to be pushed onto the stack | ||
559 | // last piece of data will be type LST_NULL | ||
560 | LLScriptLibData *data = eventdata->mData; | ||
561 | while (data->mType) | ||
562 | { | ||
563 | size += lscript_push_variable(data, mBuffer); | ||
564 | data++; | ||
565 | } | ||
566 | b_done = TRUE; | ||
567 | // now, push any additional stack space | ||
568 | S32 additional_size = get_event_stack_size(mBuffer, current_state, event); | ||
569 | if ( additional_size == -1 ) | ||
570 | { // b_done was just set, so we'll exit the loop at the bottom | ||
571 | recordBoundaryError( id ); | ||
572 | } | ||
573 | else | ||
574 | { | ||
575 | additional_size -= size; | ||
576 | lscript_pusharge(mBuffer, additional_size); | ||
577 | |||
578 | // now set the bp correctly | ||
579 | sp = get_register(mBuffer, LREG_SP); | ||
580 | sp += additional_size + size; | ||
581 | set_bp(mBuffer, sp); | ||
582 | // set IP to the function | ||
583 | setStateEventOpcoodeStartSafely( current_state, event, id ); | ||
584 | } | ||
585 | } | ||
586 | else | ||
587 | { | ||
588 | llwarns << "Shit, somehow got an event that we're not registered for!" << llendl; | ||
589 | } | ||
590 | delete eventdata; | ||
591 | } | 881 | } |
592 | else | 882 | else |
593 | { | 883 | { |
594 | // if no data waiting, do it the old way: | 884 | // if no data waiting, do it the old way: |
595 | U64 handled_current = current_events & event_register; | 885 | U64 handled_current = current_events & event_register; |
596 | if (handled_current) | 886 | if (handled_current) |
597 | { | 887 | { |
598 | // push a zero to be popped | ||
599 | lscript_push(mBuffer, 0); | ||
600 | // push sp as current bp | ||
601 | S32 sp = get_register(mBuffer, LREG_SP); | ||
602 | lscript_push(mBuffer, sp); | ||
603 | |||
604 | event = return_first_event((S32)handled_current); | 888 | event = return_first_event((S32)handled_current); |
605 | set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); | 889 | ++events_processed; |
606 | current_events &= ~LSCRIPTStateBitField[event]; | 890 | callEventHandler(event, major_version, id, quanta); |
607 | set_event_register(mBuffer, LREG_CE, current_events, major_version); | ||
608 | // now, push any additional stack space | ||
609 | S32 additional_size = get_event_stack_size(mBuffer, current_state, event); | ||
610 | if ( additional_size == -1 ) | ||
611 | { // b_done will be set, so we'll exit the loop at the bottom | ||
612 | recordBoundaryError( id ); | ||
613 | } | ||
614 | else | ||
615 | { | ||
616 | additional_size -= size; | ||
617 | lscript_pusharge(mBuffer, additional_size); | ||
618 | |||
619 | // now set the bp correctly | ||
620 | sp = get_register(mBuffer, LREG_SP); | ||
621 | sp += additional_size + size; | ||
622 | set_bp(mBuffer, sp); | ||
623 | // set IP to the function | ||
624 | setStateEventOpcoodeStartSafely( current_state, event, id ); | ||
625 | } | ||
626 | } | 891 | } |
627 | b_done = TRUE; | 892 | b_done = TRUE; |
628 | } | 893 | } |
629 | } // while (!b_done) | 894 | } |
630 | } // end of else ... in state processing code | 895 | } |
896 | } | ||
631 | 897 | ||
632 | return NO_DELETE_FLAG; | 898 | // Run for a single timeslice, or until a yield is due |
899 | F32 LLScriptExecute::runQuanta(BOOL b_print, const LLUUID &id, const char **errorstr, BOOL &state_transition, F32 quanta, U32& events_processed, LLTimer& timer) | ||
900 | { | ||
901 | U32 timer_checks = 0; | ||
902 | F32 inloop = 0; | ||
903 | |||
904 | // Loop while not finished, yield not due and time remaining | ||
905 | // NOTE: Default implementation does not do adaptive timer skipping | ||
906 | // to preserve current LSL behaviour and not break scripts that rely | ||
907 | // on current execution speed. | ||
908 | while(true) | ||
909 | { | ||
910 | runInstructions(b_print, id, errorstr, state_transition, | ||
911 | events_processed, quanta); | ||
912 | |||
913 | static const S32 lsl_timer_check_skip = 4; | ||
914 | if(isYieldDue()) | ||
915 | { | ||
916 | break; | ||
917 | } | ||
918 | else if(timer_checks++ == lsl_timer_check_skip) | ||
919 | { | ||
920 | inloop = timer.getElapsedTimeF32(); | ||
921 | if(inloop > quanta) | ||
922 | { | ||
923 | break; | ||
924 | } | ||
925 | timer_checks = 0; | ||
926 | } | ||
927 | } | ||
928 | return inloop; | ||
633 | } | 929 | } |
634 | 930 | ||
635 | BOOL run_noop(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | 931 | BOOL run_noop(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) |
@@ -2309,14 +2605,24 @@ void list_list_operation(U8 *buffer, LSCRIPTOpCodesEnum opcode) | |||
2309 | } | 2605 | } |
2310 | } | 2606 | } |
2311 | 2607 | ||
2608 | static U8 safe_op_index(U8 index) | ||
2609 | { | ||
2610 | if(index >= LST_EOF) | ||
2611 | { | ||
2612 | // Operations on LST_NULL will always be unknown_operation. | ||
2613 | index = LST_NULL; | ||
2614 | } | ||
2615 | return index; | ||
2616 | } | ||
2617 | |||
2312 | BOOL run_add(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | 2618 | BOOL run_add(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) |
2313 | { | 2619 | { |
2314 | if (b_print) | 2620 | if (b_print) |
2315 | printf("[0x%X]\tADD ", offset); | 2621 | printf("[0x%X]\tADD ", offset); |
2316 | offset++; | 2622 | offset++; |
2317 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); | 2623 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); |
2318 | U8 arg1 = arg >> 4; | 2624 | U8 arg1 = safe_op_index(arg >> 4); |
2319 | U8 arg2 = arg & 0xf; | 2625 | U8 arg2 = safe_op_index(arg & 0xf); |
2320 | if (b_print) | 2626 | if (b_print) |
2321 | { | 2627 | { |
2322 | print_type(arg1); | 2628 | print_type(arg1); |
@@ -2334,8 +2640,8 @@ BOOL run_sub(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | |||
2334 | printf("[0x%X]\tSUB ", offset); | 2640 | printf("[0x%X]\tSUB ", offset); |
2335 | offset++; | 2641 | offset++; |
2336 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); | 2642 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); |
2337 | U8 arg1 = arg >> 4; | 2643 | U8 arg1 = safe_op_index(arg >> 4); |
2338 | U8 arg2 = arg & 0xf; | 2644 | U8 arg2 = safe_op_index(arg & 0xf); |
2339 | if (b_print) | 2645 | if (b_print) |
2340 | { | 2646 | { |
2341 | print_type(arg1); | 2647 | print_type(arg1); |
@@ -2352,8 +2658,8 @@ BOOL run_mul(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | |||
2352 | printf("[0x%X]\tMUL ", offset); | 2658 | printf("[0x%X]\tMUL ", offset); |
2353 | offset++; | 2659 | offset++; |
2354 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); | 2660 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); |
2355 | U8 arg1 = arg >> 4; | 2661 | U8 arg1 = safe_op_index(arg >> 4); |
2356 | U8 arg2 = arg & 0xf; | 2662 | U8 arg2 = safe_op_index(arg & 0xf); |
2357 | if (b_print) | 2663 | if (b_print) |
2358 | { | 2664 | { |
2359 | print_type(arg1); | 2665 | print_type(arg1); |
@@ -2370,8 +2676,8 @@ BOOL run_div(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | |||
2370 | printf("[0x%X]\tDIV ", offset); | 2676 | printf("[0x%X]\tDIV ", offset); |
2371 | offset++; | 2677 | offset++; |
2372 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); | 2678 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); |
2373 | U8 arg1 = arg >> 4; | 2679 | U8 arg1 = safe_op_index(arg >> 4); |
2374 | U8 arg2 = arg & 0xf; | 2680 | U8 arg2 = safe_op_index(arg & 0xf); |
2375 | if (b_print) | 2681 | if (b_print) |
2376 | { | 2682 | { |
2377 | print_type(arg1); | 2683 | print_type(arg1); |
@@ -2388,8 +2694,8 @@ BOOL run_mod(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | |||
2388 | printf("[0x%X]\tMOD ", offset); | 2694 | printf("[0x%X]\tMOD ", offset); |
2389 | offset++; | 2695 | offset++; |
2390 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); | 2696 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); |
2391 | U8 arg1 = arg >> 4; | 2697 | U8 arg1 = safe_op_index(arg >> 4); |
2392 | U8 arg2 = arg & 0xf; | 2698 | U8 arg2 = safe_op_index(arg & 0xf); |
2393 | if (b_print) | 2699 | if (b_print) |
2394 | { | 2700 | { |
2395 | print_type(arg1); | 2701 | print_type(arg1); |
@@ -2407,8 +2713,8 @@ BOOL run_eq(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | |||
2407 | printf("[0x%X]\tEQ ", offset); | 2713 | printf("[0x%X]\tEQ ", offset); |
2408 | offset++; | 2714 | offset++; |
2409 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); | 2715 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); |
2410 | U8 arg1 = arg >> 4; | 2716 | U8 arg1 = safe_op_index(arg >> 4); |
2411 | U8 arg2 = arg & 0xf; | 2717 | U8 arg2 = safe_op_index(arg & 0xf); |
2412 | if (b_print) | 2718 | if (b_print) |
2413 | { | 2719 | { |
2414 | print_type(arg1); | 2720 | print_type(arg1); |
@@ -2425,8 +2731,8 @@ BOOL run_neq(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | |||
2425 | printf("[0x%X]\tNEQ ", offset); | 2731 | printf("[0x%X]\tNEQ ", offset); |
2426 | offset++; | 2732 | offset++; |
2427 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); | 2733 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); |
2428 | U8 arg1 = arg >> 4; | 2734 | U8 arg1 = safe_op_index(arg >> 4); |
2429 | U8 arg2 = arg & 0xf; | 2735 | U8 arg2 = safe_op_index(arg & 0xf); |
2430 | if (b_print) | 2736 | if (b_print) |
2431 | { | 2737 | { |
2432 | print_type(arg1); | 2738 | print_type(arg1); |
@@ -2443,8 +2749,8 @@ BOOL run_leq(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | |||
2443 | printf("[0x%X]\tLEQ ", offset); | 2749 | printf("[0x%X]\tLEQ ", offset); |
2444 | offset++; | 2750 | offset++; |
2445 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); | 2751 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); |
2446 | U8 arg1 = arg >> 4; | 2752 | U8 arg1 = safe_op_index(arg >> 4); |
2447 | U8 arg2 = arg & 0xf; | 2753 | U8 arg2 = safe_op_index(arg & 0xf); |
2448 | if (b_print) | 2754 | if (b_print) |
2449 | { | 2755 | { |
2450 | print_type(arg1); | 2756 | print_type(arg1); |
@@ -2461,8 +2767,8 @@ BOOL run_geq(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | |||
2461 | printf("[0x%X]\tGEQ ", offset); | 2767 | printf("[0x%X]\tGEQ ", offset); |
2462 | offset++; | 2768 | offset++; |
2463 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); | 2769 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); |
2464 | U8 arg1 = arg >> 4; | 2770 | U8 arg1 = safe_op_index(arg >> 4); |
2465 | U8 arg2 = arg & 0xf; | 2771 | U8 arg2 = safe_op_index(arg & 0xf); |
2466 | if (b_print) | 2772 | if (b_print) |
2467 | { | 2773 | { |
2468 | print_type(arg1); | 2774 | print_type(arg1); |
@@ -2479,8 +2785,8 @@ BOOL run_less(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | |||
2479 | printf("[0x%X]\tLESS ", offset); | 2785 | printf("[0x%X]\tLESS ", offset); |
2480 | offset++; | 2786 | offset++; |
2481 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); | 2787 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); |
2482 | U8 arg1 = arg >> 4; | 2788 | U8 arg1 = safe_op_index(arg >> 4); |
2483 | U8 arg2 = arg & 0xf; | 2789 | U8 arg2 = safe_op_index(arg & 0xf); |
2484 | if (b_print) | 2790 | if (b_print) |
2485 | { | 2791 | { |
2486 | print_type(arg1); | 2792 | print_type(arg1); |
@@ -2497,8 +2803,8 @@ BOOL run_greater(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | |||
2497 | printf("[0x%X]\tGREATER ", offset); | 2803 | printf("[0x%X]\tGREATER ", offset); |
2498 | offset++; | 2804 | offset++; |
2499 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); | 2805 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); |
2500 | U8 arg1 = arg >> 4; | 2806 | U8 arg1 = safe_op_index(arg >> 4); |
2501 | U8 arg2 = arg & 0xf; | 2807 | U8 arg2 = safe_op_index(arg & 0xf); |
2502 | if (b_print) | 2808 | if (b_print) |
2503 | { | 2809 | { |
2504 | print_type(arg1); | 2810 | print_type(arg1); |
@@ -2640,13 +2946,12 @@ void quaternion_operation(U8 *buffer, LSCRIPTOpCodesEnum opcode) | |||
2640 | } | 2946 | } |
2641 | } | 2947 | } |
2642 | 2948 | ||
2643 | |||
2644 | BOOL run_neg(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | 2949 | BOOL run_neg(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) |
2645 | { | 2950 | { |
2646 | if (b_print) | 2951 | if (b_print) |
2647 | printf("[0x%X]\tNEG ", offset); | 2952 | printf("[0x%X]\tNEG ", offset); |
2648 | offset++; | 2953 | offset++; |
2649 | U8 arg = safe_instruction_bytestream2byte(buffer, offset); | 2954 | U8 arg = safe_op_index(safe_instruction_bytestream2byte(buffer, offset)); |
2650 | if (b_print) | 2955 | if (b_print) |
2651 | { | 2956 | { |
2652 | print_type(arg); | 2957 | print_type(arg); |
@@ -3675,56 +3980,50 @@ BOOL run_print(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) | |||
3675 | } | 3980 | } |
3676 | 3981 | ||
3677 | 3982 | ||
3678 | void lscript_run(char *filename, BOOL b_debug) | 3983 | void lscript_run(const std::string& filename, BOOL b_debug) |
3679 | { | 3984 | { |
3680 | LLTimer timer; | 3985 | LLTimer timer; |
3681 | if (filename == NULL) | 3986 | |
3987 | const char *error; | ||
3988 | BOOL b_state; | ||
3989 | LLScriptExecuteLSL2 *execute = NULL; | ||
3990 | |||
3991 | if (filename.empty()) | ||
3682 | { | 3992 | { |
3683 | llerrs << "filename is NULL" << llendl; | 3993 | llerrs << "filename is NULL" << llendl; |
3684 | // Just reporting error is likely not enough. Need | 3994 | // Just reporting error is likely not enough. Need |
3685 | // to check how to abort or error out gracefully | 3995 | // to check how to abort or error out gracefully |
3686 | // from this function. XXXTBD | 3996 | // from this function. XXXTBD |
3687 | } | 3997 | } |
3688 | else | 3998 | LLFILE* file = LLFile::fopen(filename, "r"); /* Flawfinder: ignore */ |
3999 | if(file) | ||
3689 | { | 4000 | { |
3690 | char *error; | 4001 | execute = new LLScriptExecuteLSL2(file); |
3691 | BOOL b_state; | 4002 | fclose(file); |
3692 | LLScriptExecute *execute = NULL; | 4003 | } |
3693 | 4004 | if (execute) | |
3694 | LLFILE* file = LLFile::fopen(filename, "r"); | 4005 | { |
3695 | if (file) | 4006 | timer.reset(); |
3696 | { | 4007 | F32 time_slice = 3600.0f; // 1 hr. |
3697 | execute = new LLScriptExecute(file); | 4008 | U32 events_processed = 0; |
3698 | // note: LLScriptExecute() closes file for us | 4009 | |
3699 | } | 4010 | do { |
3700 | file = LLFile::fopen(filename, "r"); | 4011 | LLTimer timer2; |
3701 | if (file) | 4012 | execute->runQuanta(b_debug, LLUUID::null, &error, b_state, |
3702 | { | 4013 | time_slice, events_processed, timer2); |
3703 | LLFILE* fp = LLFile::fopen("lscript.parse", "w"); /*Flawfinder: ignore*/ | 4014 | } while (!execute->isFinished()); |
3704 | LLScriptLSOParse *parse = new LLScriptLSOParse(file); | 4015 | |
3705 | parse->printData(fp); | 4016 | F32 time = timer.getElapsedTimeF32(); |
3706 | delete parse; | 4017 | F32 ips = execute->mInstructionCount / time; |
3707 | fclose(file); | 4018 | llinfos << execute->mInstructionCount << " instructions in " << time << " seconds" << llendl; |
3708 | fclose(fp); | 4019 | llinfos << ips/1000 << "K instructions per second" << llendl; |
3709 | } | 4020 | printf("ip: 0x%X\n", get_register(execute->mBuffer, LREG_IP)); |
3710 | file = LLFile::fopen(filename, "r"); | 4021 | printf("sp: 0x%X\n", get_register(execute->mBuffer, LREG_SP)); |
3711 | if (file && execute) | 4022 | printf("bp: 0x%X\n", get_register(execute->mBuffer, LREG_BP)); |
3712 | { | 4023 | printf("hr: 0x%X\n", get_register(execute->mBuffer, LREG_HR)); |
3713 | timer.reset(); | 4024 | printf("hp: 0x%X\n", get_register(execute->mBuffer, LREG_HP)); |
3714 | while (!execute->run(b_debug, LLUUID::null, &error, b_state)) | 4025 | delete execute; |
3715 | ; | 4026 | fclose(file); |
3716 | F32 time = timer.getElapsedTimeF32(); | ||
3717 | F32 ips = execute->mInstructionCount / time; | ||
3718 | llinfos << execute->mInstructionCount << " instructions in " << time << " seconds" << llendl; | ||
3719 | llinfos << ips/1000 << "K instructions per second" << llendl; | ||
3720 | printf("ip: 0x%X\n", get_register(execute->mBuffer, LREG_IP)); | ||
3721 | printf("sp: 0x%X\n", get_register(execute->mBuffer, LREG_SP)); | ||
3722 | printf("bp: 0x%X\n", get_register(execute->mBuffer, LREG_BP)); | ||
3723 | printf("hr: 0x%X\n", get_register(execute->mBuffer, LREG_HR)); | ||
3724 | printf("hp: 0x%X\n", get_register(execute->mBuffer, LREG_HP)); | ||
3725 | delete execute; | ||
3726 | fclose(file); | ||
3727 | } | ||
3728 | } | 4027 | } |
3729 | } | 4028 | } |
3730 | 4029 | ||