diff options
author | Dave Hiller <daveh@lindenlab.com> | 2008-07-31 12:15:15 +0000 |
---|---|---|
committer | Dave Hiller <daveh@lindenlab.com> | 2008-07-31 12:15:15 +0000 |
commit | 9a7d68cfce5f71cf9d89536431d72941dc369749 (patch) | |
tree | f7e0ce093abef0fcc7737cac63bc2a8dbf11b729 /indra | |
parent | f0f2a416911ba8de9ac1e08cd90720c0d789bb2e (diff) |
svn merge -r93014:93396 svn+ssh://svn.lindenlab.com/svn/linden/branches/mono-r93014-qar633 dataserver-is-deprecated
Diffstat (limited to 'indra')
49 files changed, 3525 insertions, 1101 deletions
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 22f6c5bd42..27ba04558e 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -17,6 +17,7 @@ set(cmake_SOURCE_FILES CURL.cmake CMakeCopyIfDifferent.cmake CopyWinLibs.cmake + CSharpMacros.cmake DirectX.cmake ELFIO.cmake EXPAT.cmake @@ -25,6 +26,7 @@ set(cmake_SOURCE_FILES FindCARes.cmake FindELFIO.cmake FindGooglePerfTools.cmake + FindMono.cmake FindMySQL.cmake FindOpenJPEG.cmake FindXmlRpcEpi.cmake @@ -55,6 +57,7 @@ set(cmake_SOURCE_FILES LLXML.cmake LScript.cmake Linking.cmake + MonoEmbed.cmake Mozlib.cmake MySQL.cmake NDOF.cmake diff --git a/indra/cmake/CSharpMacros.cmake b/indra/cmake/CSharpMacros.cmake new file mode 100644 index 0000000000..a4dd815043 --- /dev/null +++ b/indra/cmake/CSharpMacros.cmake @@ -0,0 +1,142 @@ +# - This is a support module for easy Mono/C# handling with CMake +# It defines the following macros: +# +# ADD_CS_LIBRARY (<target> <source>) +# ADD_CS_EXECUTABLE (<target> <source>) +# INSTALL_GAC (<target>) +# +# Note that the order of the arguments is important. +# +# You can optionally set the variable CS_FLAGS to tell the macros whether +# to pass additional flags to the compiler. This is particularly useful to +# set assembly references, unsafe code, etc... These flags are always reset +# after the target was added so you don't have to care about that. +# +# copyright (c) 2007 Arno Rehn arno@arnorehn.de +# +# Redistribution and use is allowed according to the terms of the GPL license. + + +# ----- support macros ----- +MACRO(GET_CS_LIBRARY_TARGET_DIR) + IF (NOT LIBRARY_OUTPUT_PATH) + SET(CS_LIBRARY_TARGET_DIR ${CMAKE_CURRENT_BINARY_DIR}) + ELSE (NOT LIBRARY_OUTPUT_PATH) + SET(CS_LIBRARY_TARGET_DIR ${LIBRARY_OUTPUT_PATH}) + ENDIF (NOT LIBRARY_OUTPUT_PATH) +ENDMACRO(GET_CS_LIBRARY_TARGET_DIR) + +MACRO(GET_CS_EXECUTABLE_TARGET_DIR) + IF (NOT EXECUTABLE_OUTPUT_PATH) + SET(CS_EXECUTABLE_TARGET_DIR ${CMAKE_CURRENT_BINARY_DIR}) + ELSE (NOT EXECUTABLE_OUTPUT_PATH) + SET(CS_EXECUTABLE_TARGET_DIR ${EXECUTABLE_OUTPUT_PATH}) + ENDIF (NOT EXECUTABLE_OUTPUT_PATH) +ENDMACRO(GET_CS_EXECUTABLE_TARGET_DIR) + +MACRO(MAKE_PROPER_FILE_LIST) + FOREACH(file ${ARGN}) + # first assume it's a relative path + FILE(GLOB globbed ${CMAKE_CURRENT_SOURCE_DIR}/${file}) + IF(globbed) + FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${file} native) + ELSE(globbed) + FILE(TO_NATIVE_PATH ${file} native) + ENDIF(globbed) + SET(proper_file_list ${proper_file_list} ${native}) + SET(native "") + ENDFOREACH(file) +ENDMACRO(MAKE_PROPER_FILE_LIST) +# ----- end support macros ----- + +MACRO(ADD_CS_LIBRARY target) + GET_CS_LIBRARY_TARGET_DIR() + + SET(target_DLL "${CS_LIBRARY_TARGET_DIR}/${target}.dll") + MAKE_PROPER_FILE_LIST(${ARGN}) + FILE(RELATIVE_PATH relative_path ${CMAKE_BINARY_DIR} ${target_DLL}) + + SET(target_KEY "${CMAKE_CURRENT_SOURCE_DIR}/${target}.key") + SET(target_CS_FLAGS "${CS_FLAGS}") + IF(${target}_CS_FLAGS) + LIST(APPEND target_CS_FLAGS ${${target}_CS_FLAGS}) + ENDIF(${target}_CS_FLAGS) + IF(EXISTS ${target_KEY}) + LIST(APPEND target_CS_FLAGS -keyfile:${target_KEY}) + ENDIF(EXISTS ${target_KEY}) + + FOREACH(ref ${${target}_REFS}) + SET(ref_DLL ${CMAKE_CURRENT_BINARY_DIR}/${ref}.dll) + IF(EXISTS ${ref_DLL}) + LIST(APPEND target_CS_FLAGS -r:${ref_DLL}) + ELSE(EXISTS ${ref_DLL}) + LIST(APPEND target_CS_FLAGS -r:${ref}) + ENDIF(EXISTS ${ref_DLL}) + ENDFOREACH(ref ${${target}_REFS}) + + ADD_CUSTOM_COMMAND (OUTPUT ${target_DLL} + COMMAND ${MCS_EXECUTABLE} ${target_CS_FLAGS} -out:${target_DLL} -target:library ${proper_file_list} + MAIN_DEPENDENCY ${proper_file_list} + DEPENDS ${ARGN} + COMMENT "Building ${relative_path}") + ADD_CUSTOM_TARGET (${target} ALL DEPENDS ${target_DLL}) + + FOREACH(ref ${${target}_REFS}) + GET_TARGET_PROPERTY(is_target ${ref} TYPE) + IF(is_target) + ADD_DEPENDENCIES(${target} ${ref}) + ENDIF(is_target) + ENDFOREACH(ref ${${target}_REFS}) + + SET(relative_path "") + SET(proper_file_list "") +ENDMACRO(ADD_CS_LIBRARY) + +MACRO(ADD_CS_EXECUTABLE target) + GET_CS_EXECUTABLE_TARGET_DIR() + + # Seems like cmake doesn't like the ".exe" ending for custom commands. + # If we call it ${target}.exe, 'make' will later complain about a missing rule. + # Create a fake target instead. + SET(target_EXE "${CS_EXECUTABLE_TARGET_DIR}/${target}.exe") + SET(target_TOUCH "${CS_EXECUTABLE_TARGET_DIR}/${target}.exe-built") + GET_DIRECTORY_PROPERTY(clean ADDITIONAL_MAKE_CLEAN_FILES) + LIST(APPEND clean ${target}.exe) + SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${clean}") + MAKE_PROPER_FILE_LIST(${ARGN}) + FILE(RELATIVE_PATH relative_path ${CMAKE_BINARY_DIR} ${target_EXE}) + SET(target_CS_FLAGS "${CS_FLAGS}") + + FOREACH(ref ${${target}_REFS}) + SET(ref_DLL ${CMAKE_CURRENT_SOURCE_DIR}/${ref}.dll) + IF(EXISTS ${ref_DLL}) + LIST(APPEND target_CS_FLAGS -r:${ref_DLL}) + ELSE(EXISTS ${ref_DLL}) + LIST(APPEND target_CS_FLAGS -r:${ref}) + ENDIF(EXISTS ${ref_DLL}) + ENDFOREACH(ref ${${target}_REFS}) + + ADD_CUSTOM_COMMAND (OUTPUT "${target_TOUCH}" + COMMAND ${MCS_EXECUTABLE} ${target_CS_FLAGS} -out:${target_EXE} ${proper_file_list} + COMMAND ${CMAKE_COMMAND} -E touch ${target_TOUCH} + MAIN_DEPENDENCY ${ARGN} + DEPENDS ${ARGN} + COMMENT "Building ${relative_path}") + ADD_CUSTOM_TARGET ("${target}" ALL DEPENDS "${target_TOUCH}") + + FOREACH(ref ${${target}_REFS}) + GET_TARGET_PROPERTY(is_target ${ref} TYPE) + IF(is_target) + ADD_DEPENDENCIES(${target} ${ref}) + ENDIF(is_target) + ENDFOREACH(ref ${${target}_REFS}) + + SET(relative_path "") + SET(proper_file_list "") +ENDMACRO(ADD_CS_EXECUTABLE) + +MACRO(INSTALL_GAC target) + GET_CS_LIBRARY_TARGET_DIR() + + INSTALL(CODE "EXECUTE_PROCESS(COMMAND ${GACUTIL_EXECUTABLE} -i ${CS_LIBRARY_TARGET_DIR}/${target}.dll -package 2.0)") +ENDMACRO(INSTALL_GAC target) diff --git a/indra/cmake/CopyBackToSource.cmake b/indra/cmake/CopyBackToSource.cmake new file mode 100644 index 0000000000..d217df9aec --- /dev/null +++ b/indra/cmake/CopyBackToSource.cmake @@ -0,0 +1,16 @@ +# -*- cmake -*- +# Copies a binary back to the source directory + +MACRO(COPY_BACK_TO_SOURCE target) + GET_TARGET_PROPERTY(FROM ${target} LOCATION) + SET(TO ${CMAKE_CURRENT_SOURCE_DIR}) + #MESSAGE("TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${FROM} ${TO}") + ADD_CUSTOM_COMMAND( + TARGET ${target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${FROM} ${TO} + DEPENDS ${FROM} + COMMENT "Copying ${target} to ${CMAKE_CURRENT_BINARY_DIR}" + ) +ENDMACRO(COPY_BACK_TO_SOURCE) + + diff --git a/indra/cmake/FindMono.cmake b/indra/cmake/FindMono.cmake new file mode 100644 index 0000000000..f0a0705481 --- /dev/null +++ b/indra/cmake/FindMono.cmake @@ -0,0 +1,68 @@ +# - Try to find the mono, mcs, gmcs and gacutil +# +# defines +# +# MONO_FOUND - system has mono, mcs, gmcs and gacutil +# MONO_PATH - where to find 'mono' +# MCS_PATH - where to find 'mcs' +# GMCS_PATH - where to find 'gmcs' +# GACUTIL_PATH - where to find 'gacutil' +# +# copyright (c) 2007 Arno Rehn arno@arnorehn.de +# +# Redistribution and use is allowed according to the terms of the GPL license. +# Removed the check for gmcs + +FIND_PROGRAM (MONO_EXECUTABLE mono + "C:/Program Files/Mono-1.9.1/bin" + "C:/Program Files/Mono-1.2.6/bin" + /bin + /usr/bin + /usr/local/bin +) +FIND_PROGRAM (MCS_EXECUTABLE mcs + "C:/Program Files/Mono-1.9.1/bin" + "C:/Program Files/Mono-1.2.6/bin" + /bin + /usr/bin + /usr/local/bin +) +FIND_PROGRAM (GMCS_EXECUTABLE gmcs + "C:/Program Files/Mono-1.9.1/bin" + "C:/Program Files/Mono-1.2.6/bin" + /bin + /usr/bin + /usr/local/bin +) +FIND_PROGRAM (GACUTIL_EXECUTABLE gacutil + "C:/Program Files/Mono-1.9.1/bin" + "C:/Program Files/Mono-1.2.6/bin" + /bin + /usr/bin + /usr/local/bin +) +FIND_PROGRAM (ILASM_EXECUTABLE + ilasm + NO_DEFAULT_PATH + PATHS "C:/Program Files/Mono-1.9.1/bin" "C:/Apps/Mono-1.2.6/bin" "C:/Program Files/Mono-1.2.6/bin" /bin /usr/bin /usr/local/bin +) + +SET (MONO_FOUND FALSE) + +IF (MONO_EXECUTABLE AND MCS_EXECUTABLE AND GACUTIL_EXECUTABLE) + SET (MONO_FOUND TRUE) +ENDIF (MONO_EXECUTABLE AND MCS_EXECUTABLE AND GACUTIL_EXECUTABLE) + +IF (MONO_FOUND) + IF (NOT Mono_FIND_QUIETLY) + MESSAGE(STATUS "Found mono: ${MONO_EXECUTABLE}") + MESSAGE(STATUS "Found mcs: ${MCS_EXECUTABLE}") + MESSAGE(STATUS "Found gacutil: ${GACUTIL_EXECUTABLE}") + ENDIF (NOT Mono_FIND_QUIETLY) +ELSE (MONO_FOUND) + IF (Mono_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find one or more of the following programs: mono, mcs, gacutil") + ENDIF (Mono_FIND_REQUIRED) +ENDIF (MONO_FOUND) + +MARK_AS_ADVANCED(MONO_EXECUTABLE MCS_EXECUTABLE GACUTIL_EXECUTABLE) diff --git a/indra/cmake/LScript.cmake b/indra/cmake/LScript.cmake index 227e4aaeda..86bfcb7440 100644 --- a/indra/cmake/LScript.cmake +++ b/indra/cmake/LScript.cmake @@ -3,11 +3,14 @@ set(LSCRIPT_INCLUDE_DIRS ${LIBS_OPEN_DIR}/lscript ${LIBS_OPEN_DIR}/lscript/lscript_compile - ${LIBS_OPEN_DIR}/lscript/lscript_execute + ${LIBS_OPEN_DIR}/lscript/lscript_execute + ${LIBS_OPEN_DIR}/lscript/lscript_execute_mono ) set(LSCRIPT_LIBRARIES lscript_compile - lscript_execute + lscript_execute lscript_library ) + +set(LSCRIPT_EXECUTE_MONO_LIBRARIES lscript_execute_mono)
\ No newline at end of file diff --git a/indra/cmake/MonoDeps.cmake b/indra/cmake/MonoDeps.cmake new file mode 100644 index 0000000000..52d5491563 --- /dev/null +++ b/indra/cmake/MonoDeps.cmake @@ -0,0 +1,48 @@ +# -*- cmake -*- + +set(MONO_PREBUILT_LIBRARIES_DIR ${LIBS_PREBUILT_DIR}/mono/1.0) + +set(MONO_PREBUILT_LIBRARIES + Iesi.Collections.dll + Iesi.Collections.pdb + Mono.CompilerServices.SymbolWriter.dll + Mono.PEToolkit.dll + Mono.PEToolkit.pdb + Mono.Security.dll + PEAPI.dll + RAIL.dll + RAIL.pdb + ) + + set(MONO_CORE_LIBRARIES + System.dll + System.Xml.dll + mscorlib.dll) + +if(WINDOWS) + set(MONO_DEPENDENCIES + DomainCreator + DomainRegister + LslLibrary + LslUserScript + Script + ScriptTypes + TestFormat + UserScript + UThread + UThreadInjector + ) +else(WINDOWS) + set(MONO_DEPENDENCIES + DomainCreator_POST_BUILD + DomainRegister_POST_BUILD + LslLibrary_POST_BUILD + LslUserScript_POST_BUILD + Script_POST_BUILD + ScriptTypes_POST_BUILD + TestFormat_POST_BUILD + UserScript_POST_BUILD + UThread_POST_BUILD + UThreadInjector_POST_BUILD + ) +endif(WINDOWS) diff --git a/indra/cmake/MonoEmbed.cmake b/indra/cmake/MonoEmbed.cmake new file mode 100644 index 0000000000..a310cd9bac --- /dev/null +++ b/indra/cmake/MonoEmbed.cmake @@ -0,0 +1,57 @@ +# -*- cmake -*- + +include(Prebuilt) +use_prebuilt_binary(libmono) + +SET(GLIB_2_0 glib-2.0) + +if (WINDOWS) + SET(MONO_LIB mono) +else (WINDOWS) + SET(MONO_LIB mono) + SET(M_LIBRARIES m) + SET(GTHREAD_2_0 gthread-2.0) +endif(WINDOWS) + + +IF (DARWIN) + + FIND_LIBRARY(MONO_LIBRARY NAMES Mono) + # Find_file doesnt work as expected. Hardcode relative to Mono.framework. + #FIND_FILE(GLIB_CONFIG glibconfig.h ${MONO_LIBRARY}) + #FIND_FILE(MONO_GLIB_LIBRARY glib.h ${MONO_LIBRARY}) + SET(MONO_GLIB_LIBRARY ${MONO_LIBRARY}/Headers/glib-2.0/) + SET(GLIB_CONFIG ${MONO_LIBRARY}/Libraries/glib-2.0/include/) + SET(MONO_LIB_DIRECTORY ${MONO_LIBRARY}/Libraries) + + IF (MONO_LIBRARY AND MONO_GLIB_LIBRARY AND GLIB_CONFIG) + MESSAGE("-- Found Mono for embedding") + INCLUDE_DIRECTORIES(${MONO_GLIB_LIBRARY} ${GLIB_CONFIG}) + LINK_DIRECTORIES(${MONO_LIB_DIRECTORY}) + ELSE (MONO_LIBRARY AND MONO_GLIB_LIBRARY AND GLIB_CONFIG) + MESSAGE("-- Mono not found for embedding") + MESSAGE(${MONO_LIBRARY}) + MESSAGE(${MONO_GLIB_LIBRARY}) + MESSAGE(${GLIB_CONFIG}) + ENDIF (MONO_LIBRARY AND MONO_GLIB_LIBRARY AND GLIB_CONFIG) + +ELSE (DARWIN) + + SET(MONO_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) + SET(GLIB_2_0_PLATFORM_INCLUDE_DIR + ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0) + SET(GLIB_2_0_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/glib-2.0) + + INCLUDE_DIRECTORIES( + ${MONO_INCLUDE_DIR} + ${GLIB_2_0_PLATFORM_INCLUDE_DIR} + ${GLIB_2_0_INCLUDE_DIR}) + +ENDIF (DARWIN) + +SET(MONO_LIBRARIES + ${MONO_LIB} + ${M_LIBRARIES} + ${GLIB_2_0} + ${GTHREAD_2_0} +) diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 368c85acb0..08dcef2538 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -128,7 +128,7 @@ const char* LLAssetType::mAssetTypeNames[LLAssetType::AT_COUNT] = "jpeg", "animatn", "gesture", - "simstate", + "simstate" }; // This table is meant for decoding to human readable form. Put any @@ -158,7 +158,7 @@ const char* LLAssetType::mAssetTypeHumanNames[LLAssetType::AT_COUNT] = "jpeg image", "animation", "gesture", - "simstate", + "simstate" }; ///---------------------------------------------------------------------------- diff --git a/indra/llcommon/llstatenums.h b/indra/llcommon/llstatenums.h index a82996b852..45c4fa986b 100644 --- a/indra/llcommon/llstatenums.h +++ b/indra/llcommon/llstatenums.h @@ -63,7 +63,8 @@ enum LL_SIM_STAT_SIMPHYSICSSTEPMS, LL_SIM_STAT_SIMPHYSICSSHAPEMS, LL_SIM_STAT_SIMPHYSICSOTHERMS, - LL_SIM_STAT_SIMPHYSICSMEMORY + LL_SIM_STAT_SIMPHYSICSMEMORY, + LL_SIM_STAT_SCRIPT_EPS, }; #endif diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 2937edd853..7a6add6282 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -122,7 +122,7 @@ namespace { public: RawInjector(const U8* data, S32 size) : mData(data), mSize(size) {} - virtual ~RawInjector() {} + virtual ~RawInjector() {delete mData;} const char* contentType() { return "application/octet-stream"; } @@ -153,16 +153,21 @@ namespace LLBufferStream ostream(channels, buffer.get()); llifstream fstream(mFilename, std::iostream::binary | std::iostream::out); - fstream.seekg(0, std::ios::end); - U32 fileSize = fstream.tellg(); - fstream.seekg(0, std::ios::beg); - char* fileBuffer; - fileBuffer = new char [fileSize]; - fstream.read(fileBuffer, fileSize); - ostream.write(fileBuffer, fileSize); - fstream.close(); - eos = true; - return STATUS_DONE; + if(fstream.is_open()) + { + fstream.seekg(0, std::ios::end); + U32 fileSize = fstream.tellg(); + fstream.seekg(0, std::ios::beg); + char* fileBuffer; + fileBuffer = new char [fileSize]; + fstream.read(fileBuffer, fileSize); + ostream.write(fileBuffer, fileSize); + fstream.close(); + eos = true; + return STATUS_DONE; + } + + return STATUS_ERROR; } const std::string mFilename; @@ -402,7 +407,7 @@ void LLHTTPClient::post(const std::string& url, const LLSD& body, ResponderPtr r request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, timeout); } -void LLHTTPClient::post(const std::string& url, const U8* data, S32 size, ResponderPtr responder, const F32 timeout) +void LLHTTPClient::postRaw(const std::string& url, const U8* data, S32 size, ResponderPtr responder, const F32 timeout) { request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, timeout); } diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 57895aeec9..af79662be9 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -72,8 +72,12 @@ public: static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); static void post(const std::string& url, const LLSD& body, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); - static void post(const std::string& url, const U8* data, S32 size, ResponderPtr responder, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + + /** Takes ownership of data and deletes it when sent */ + static void postRaw(const std::string& url, const U8* data, S32 size, ResponderPtr responder, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + static void postFile(const std::string& url, const std::string& filename, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + # static void postFile(const std::string& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index aa9964d46b..972a184a62 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -94,8 +94,8 @@ const U32 REGION_FLAGS_ABUSE_EMAIL_TO_ESTATE_OWNER = (1 << 27); const U32 REGION_FLAGS_ALLOW_VOICE = (1 << 28); const U32 REGION_FLAGS_BLOCK_PARCEL_SEARCH = (1 << 29); -const U32 REGION_FLAGS_DENY_AGEUNVERIFIED = (1 << 30); - +const U32 REGION_FLAGS_DENY_AGEUNVERIFIED = (1 << 30); +const U32 REGION_FLAGS_SKIP_MONO_SCRIPTS = (1 << 31); const U32 REGION_FLAGS_DEFAULT = REGION_FLAGS_ALLOW_LANDMARK | REGION_FLAGS_ALLOW_SET_HOME | diff --git a/indra/llmessage/llsdmessagereader.cpp b/indra/llmessage/llsdmessagereader.cpp index b7d0267423..5fb3708859 100755 --- a/indra/llmessage/llsdmessagereader.cpp +++ b/indra/llmessage/llsdmessagereader.cpp @@ -71,14 +71,20 @@ LLSD getLLSD(const LLSD& input, const char* block, const char* var, S32 blocknum } if(! input[block].isArray()) { - llerrs << "block " << block << " not found" << llendl; + // NOTE: babbage: need to return default for missing blocks to allow + // backwards/forwards compatibility - handlers must cope with default + // values. + llwarns << "block " << block << " not found" << llendl; return LLSD(); } LLSD result = input[block][blocknum][var]; if(result.isUndefined()) { - llerrs << "var " << var << " not found" << llendl; + // NOTE: babbage: need to return default for missing vars to allow + // backwards/forwards compatibility - handlers must cope with default + // values. + llwarns << "var " << var << " not found" << llendl; } return result; } diff --git a/indra/lscript/CMakeLists.txt b/indra/lscript/CMakeLists.txt index d3e3dc1103..c655aef4d9 100644 --- a/indra/lscript/CMakeLists.txt +++ b/indra/lscript/CMakeLists.txt @@ -11,7 +11,8 @@ set(lscript_HEADER_FILES lscript_rt_interface.h ) -add_subdirectory (lscript_compile) -add_subdirectory (lscript_execute) -add_subdirectory (lscript_library) +add_subdirectory(lscript_compile) +add_subdirectory(lscript_execute) + +add_subdirectory(lscript_library) diff --git a/indra/lscript/lscript_byteconvert.h b/indra/lscript/lscript_byteconvert.h index 89f3cc4a21..b5e09602c7 100644 --- a/indra/lscript/lscript_byteconvert.h +++ b/indra/lscript/lscript_byteconvert.h @@ -415,7 +415,7 @@ inline void set_fault(const U8 *stream, LSCRIPTRunTimeFaults fault) reset_hp_to_safe_spot(stream); // lsa_print_heap((U8 *)stream); } - fr = LSCRIPTRunTimeFaultBits[fault]; + fr = fault; set_register((U8 *)stream, LREG_FR, fr); } } diff --git a/indra/lscript/lscript_byteformat.h b/indra/lscript/lscript_byteformat.h index 6edf2b740d..474e8a67a6 100644 --- a/indra/lscript/lscript_byteformat.h +++ b/indra/lscript/lscript_byteformat.h @@ -512,26 +512,12 @@ typedef enum e_lscript_runtime_faults LSRF_CHAT_OVERRUN, LSRF_TOO_MANY_LISTENS, LSRF_NESTING_LISTS, + LSRF_CLI, LSRF_EOF } LSCRIPTRunTimeFaults; extern const char* LSCRIPTRunTimeFaultStrings[LSRF_EOF]; /*Flawfinder: ignore*/ -const S32 LSCRIPTRunTimeFaultBits[LSRF_EOF] = -{ - 0, // LSRF_INVALID - 1, // LSRF_MATH - 2, // LSRF_STACK_HEAP_COLLISION - 3, // LSREF_BOUND_CHECK_ERROR - 4, // LSREF_HEAP_ERROR - 5, // LSREF_VERSION_MISMATCH - 6, // LSREF_MISSING_INVENTORY - 7, // LSRF_SANDBOX - 8, // LSRF_CHAT_OVERRUN - 9, // LSRF_TOO_MANY_LISTENS - 10, // LSRF_NESTING_LISTS -}; - typedef enum e_lscript_runtime_permissions { SCRIPT_PERMISSION_DEBIT, diff --git a/indra/lscript/lscript_compile/indra.l b/indra/lscript/lscript_compile/indra.l index 14f8acb551..09008379a2 100644 --- a/indra/lscript/lscript_compile/indra.l +++ b/indra/lscript/lscript_compile/indra.l @@ -676,7 +676,7 @@ int yyerror(const char *fmt, ...) //#define EMIT_CIL_ASSEMBLER BOOL lscript_compile(const char* src_filename, const char* dst_filename, - const char* err_filename, BOOL is_god_like) + const char* err_filename, BOOL compile_to_mono, const char* class_name, BOOL is_god_like) { BOOL b_parse_ok = FALSE; BOOL b_dummy = FALSE; @@ -718,6 +718,8 @@ BOOL lscript_compile(const char* src_filename, const char* dst_filename, } gScriptp->mGodLike = is_god_like; + + gScriptp->setClassName(class_name); gScopeStringTable = new LLStringTable(16384); #ifdef EMERGENCY_DEBUG_PRINTOUTS @@ -733,34 +735,25 @@ BOOL lscript_compile(const char* src_filename, const char* dst_filename, #ifdef EMERGENCY_DEBUG_PRINTOUTS gScriptp->recurse(yyout, 0, 0, LSCP_EMIT_ASSEMBLY, LSPRUNE_INVALID, b_dummy, NULL, type, type, b_dummy_count, NULL, NULL, 0, NULL, 0, NULL); #endif -#ifdef EMIT_CIL_ASSEMBLER - const char* cil_output_file_name = dst_filename? dst_filename : "lscript.cil"; - LLFILE* cilout = LLFile::fopen(cil_output_file_name, "w"); - if(NULL == cilout) + if(TRUE == compile_to_mono) { - fprintf(yyout, "Error opening cil output file %s\n", cil_output_file_name); + gScriptp->recurse(yyout, 0, 0, LSCP_EMIT_CIL_ASSEMBLY, LSPRUNE_INVALID, b_dummy, NULL, type, type, b_dummy_count, NULL, NULL, 0, NULL, 0, NULL); } else { - gScriptp->recurse(cilout, 0, 0, LSCP_EMIT_CIL_ASSEMBLY, LSPRUNE_INVALID, b_dummy, NULL, type, type, b_dummy_count, NULL, NULL, 0, NULL, 0, NULL); - if(fclose(cilout) == EOF) - { - fprintf(yyout, "Error closing cil output file %s\n", cil_output_file_name); - } + gScriptp->recurse(yyout, 0, 0, LSCP_EMIT_BYTE_CODE, LSPRUNE_INVALID, b_dummy, NULL, type, type, b_dummy_count, NULL, NULL, 0, NULL, 0, NULL); } -#endif - gScriptp->recurse(yyout, 0, 0, LSCP_EMIT_BYTE_CODE, LSPRUNE_INVALID, b_dummy, NULL, type, type, b_dummy_count, NULL, NULL, 0, NULL, 0, NULL); } delete gScopeStringTable; gScopeStringTable = NULL; #ifdef EMERGENCY_DEBUG_PRINTOUTS fclose(compfile); #endif + fclose(yyout); } - fclose(yyout); + fclose(yyin); } - fclose(yyin); delete gAllocationManager; delete gScopeStringTable; @@ -768,13 +761,15 @@ BOOL lscript_compile(const char* src_filename, const char* dst_filename, } -BOOL lscript_compile(char *filename, BOOL is_god_like = FALSE) +BOOL lscript_compile(char *filename, BOOL compile_to_mono, BOOL is_god_like = FALSE) { char src_filename[MAX_STRING]; sprintf(src_filename, "%s.lsl", filename); char err_filename[MAX_STRING]; sprintf(err_filename, "%s.out", filename); - return lscript_compile(src_filename, NULL, err_filename, is_god_like); + char class_name[MAX_STRING]; + sprintf(class_name, "%s", filename); + return lscript_compile(src_filename, NULL, err_filename, compile_to_mono, class_name, is_god_like); } diff --git a/indra/lscript/lscript_compile/lscript_error.cpp b/indra/lscript/lscript_compile/lscript_error.cpp index 309eb07dc2..5299d8c7e9 100644 --- a/indra/lscript/lscript_compile/lscript_error.cpp +++ b/indra/lscript/lscript_compile/lscript_error.cpp @@ -72,7 +72,10 @@ const char* gErrorText[LSERROR_EOF] = /*Flawfinder: ignore*/ "Use of vector or quaternion method on incorrect type", "Lists can't be included in lists", "Unitialized variables can't be included in lists", - "Declaration requires a new scope -- use { and }" + "Declaration requires a new scope -- use { and }", + "CIL assembler failed", + "Bytecode transformer failed", + "Bytecode verification failed" }; void LLScriptGenerateErrorText::writeWarning(LLFILE *fp, LLScriptFilePosition *pos, LSCRIPTWarnings warning) @@ -98,3 +101,8 @@ void LLScriptGenerateErrorText::writeError(LLFILE *fp, S32 line, S32 col, LSCRIP fprintf(fp, "(%d, %d) : ERROR : %s\n", line, col, gErrorText[error]); mTotalErrors++; } + +std::string getLScriptErrorString(LSCRIPTErrors error) +{ + return gErrorText[error]; +} diff --git a/indra/lscript/lscript_compile/lscript_error.h b/indra/lscript/lscript_compile/lscript_error.h index 8c9e35d56b..50276c2006 100644 --- a/indra/lscript/lscript_compile/lscript_error.h +++ b/indra/lscript/lscript_compile/lscript_error.h @@ -124,6 +124,9 @@ typedef enum e_lscript_errors LSERROR_NO_LISTS_IN_LISTS, LSERROR_NO_UNITIALIZED_VARIABLES_IN_LISTS, LSERROR_NEED_NEW_SCOPE, + LSERROR_CIL_ASSEMBLER_FAILED = 16, // Mono build error. + LSERROR_BYTECODE_TRANSFORM_FAILED = 17, // Mono build error. + LSERROR_BYTECODE_VERIFICATION_FAILED, // Mono build error. LSERROR_EOF } LSCRIPTErrors; @@ -147,6 +150,8 @@ public: S32 mTotalWarnings; }; +std::string getLScriptErrorString(LSCRIPTErrors error); + extern LLScriptGenerateErrorText gErrorToText; #endif diff --git a/indra/lscript/lscript_compile/lscript_tree.cpp b/indra/lscript/lscript_compile/lscript_tree.cpp index 3a93f7b896..aabf0a3c38 100644 --- a/indra/lscript/lscript_compile/lscript_tree.cpp +++ b/indra/lscript/lscript_compile/lscript_tree.cpp @@ -43,7 +43,8 @@ //#define LSL_INCLUDE_DEBUG_INFO -void print_cil_box(LLFILE* fp, LSCRIPTType type) + +static void print_cil_box(LLFILE* fp, LSCRIPTType type) { switch(type) { @@ -51,24 +52,28 @@ void print_cil_box(LLFILE* fp, LSCRIPTType type) fprintf(fp, "box [mscorlib]System.Int32\n"); break; case LST_FLOATINGPOINT: - fprintf(fp, "box [mscorlib]System.Double\n"); + fprintf(fp, "box [mscorlib]System.Single\n"); break; case LST_STRING: + // System.String is not a System.ValueType, + // so does not need to be boxed. + break; case LST_KEY: - fprintf(fp, "box [mscorlib]System.String\n"); + fprintf(fp, "box [ScriptTypes]LindenLab.SecondLife.Key\n"); break; case LST_VECTOR: - fprintf(fp, "box [LScriptLibrary]LLVector\n"); + fprintf(fp, "box [ScriptTypes]LindenLab.SecondLife.Vector\n"); break; case LST_QUATERNION: - fprintf(fp, "box [LScriptLibrary]LLQuaternion\n"); + fprintf(fp, "box [ScriptTypes]LindenLab.SecondLife.Quaternion\n"); break; default: + llassert(false); break; } } -void print_cil_type(LLFILE* fp, LSCRIPTType type) +static void print_cil_type(LLFILE* fp, LSCRIPTType type) { switch(type) { @@ -79,14 +84,16 @@ void print_cil_type(LLFILE* fp, LSCRIPTType type) fprintf(fp, "float32"); break; case LST_STRING: - case LST_KEY: fprintf(fp, "string"); + break; + case LST_KEY: + fprintf(fp, "valuetype [ScriptTypes]LindenLab.SecondLife.Key"); break; case LST_VECTOR: - fprintf(fp, "valuetype [LScriptLibrary]LLVector"); + fprintf(fp, "class [ScriptTypes]LindenLab.SecondLife.Vector"); break; case LST_QUATERNION: - fprintf(fp, "valuetype [LScriptLibrary]LLQuaternion"); + fprintf(fp, "class [ScriptTypes]LindenLab.SecondLife.Quaternion"); break; case LST_LIST: fprintf(fp, "class [mscorlib]System.Collections.ArrayList"); @@ -189,6 +196,7 @@ void LLScriptConstantInteger::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPT break; case LSCP_EMIT_CIL_ASSEMBLY: fprintf(fp, "ldc.i4 %d\n", mValue); + type = mType; break; default: break; @@ -236,7 +244,13 @@ void LLScriptConstantFloat::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo } break; case LSCP_EMIT_CIL_ASSEMBLY: - fprintf(fp, "ldc.r8 %5.5f\n", mValue); // NOTE: Precision? + { + double v = (double)mValue; + U8 * p = (U8 *)&v; // See ECMA-335 Partition VI, Appendix C.4.6 Examples, line 4 + fprintf(fp, "ldc.r8 (%02x %02x %02x %02x %02x %02x %02x %02x)\n", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + type = mType; + } + break; default: break; } @@ -247,16 +261,34 @@ S32 LLScriptConstantFloat::getSize() return LSCRIPTDataSize[LST_FLOATINGPOINT]; } -void print_escape_quotes(LLFILE* fp, const char* str) +void print_escaped(LLFILE* fp, const char* str) { putc('"', fp); for(const char* c = str; *c != '\0'; ++c) { - if(*c == '"') + switch(*c) { - putc('\\', fp); + case '"': + putc('\\', fp); + putc(*c, fp); + break; + case '\n': + putc('\\', fp); + putc('n', fp); + break; + case '\t': + putc(' ', fp); + putc(' ', fp); + putc(' ', fp); + putc(' ', fp); + break; + case '\\': + putc('\\', fp); + putc('\\', fp); + break; + default: + putc(*c, fp); } - putc(*c, fp); } putc('"', fp); } @@ -293,7 +325,7 @@ void LLScriptConstantString::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC case LSCP_TO_STACK: { chunk->addByte(LSCRIPTOpCodes[LOPC_PUSHARGS]); - chunk->addBytes(mValue, (S32)strlen(mValue) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(mValue, (S32)strlen(mValue) + 1); type = mType; } break; @@ -304,7 +336,7 @@ void LLScriptConstantString::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC break; case LSCP_EMIT_CIL_ASSEMBLY: fprintf(fp, "ldstr "); - print_escape_quotes(fp, mValue); + print_escaped(fp, mValue); fprintf(fp, "\n"); default: break; @@ -313,10 +345,9 @@ void LLScriptConstantString::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC S32 LLScriptConstantString::getSize() { - return (S32)strlen(mValue) + 1; /*Flawfinder: ignore*/ + return (S32)strlen(mValue) + 1; } - void LLScriptIdentifier::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -388,7 +419,7 @@ void LLScriptIdentifier::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi } break; case LSCP_EMIT_CIL_ASSEMBLY: - fprintf(fp, "%s", mName); + fprintf(fp, "'%s'", mName); break; default: break; @@ -428,6 +459,12 @@ S32 LLScriptSimpleAssignable::getSize() return 0; } +static void print_cil_member(LLFILE* fp, LLScriptIdentifier *ident) +{ + print_cil_type(fp, ident->mScopeEntry->mType); + fprintf(fp, " %s::'%s'\n", gScriptp->getClassName(), ident->mScopeEntry->mIdentifier); +} + void LLScriptSAIdentifier::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -497,6 +534,19 @@ void LLScriptSAIdentifier::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom } } break; + + case LSCP_EMIT_CIL_ASSEMBLY: + { + fprintf(fp, "ldarg.0\n"); + fprintf(fp, "ldfld "); + print_cil_member(fp, mIdentifier); + fprintf(fp, "\n"); + if (mNextp) + { + mNextp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + } + break; + } default: mIdentifier->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); if (mNextp) @@ -553,7 +603,8 @@ S32 LLScriptSAConstant::getSize() return mConstant->getSize(); } -void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetType) + +static void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetType) { switch(srcType) { @@ -567,9 +618,8 @@ void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetType) fprintf(fp, "call string class [mscorlib]System.Convert::ToString(int32)\n"); break; case LST_LIST: - fprintf(fp, "box [mscorlib]System.Int32\n"); - fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LScriptLibrary]LScriptInternal::CreateList()\n"); - fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LScriptLibrary]LScriptInternal::AddReturnList(object, class [mscorlib]System.Collections.ArrayList)\n"); + print_cil_box(fp, LST_INTEGER); + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList(object)\n"); break; default: break; @@ -582,10 +632,11 @@ void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetType) fprintf(fp, "conv.i4\n"); break; case LST_STRING: - fprintf(fp, "call string class [mscorlib]System.Convert::ToString(float32)\n"); + fprintf(fp, "call string [LslLibrary]LindenLab.SecondLife.LslRunTime::ToString(float32)\n"); break; case LST_LIST: - fprintf(fp, "call class [mscorlib]System.Collections.ArrayList [LScriptLibrary]LScriptInternal::CreateList(object)\n"); + print_cil_box(fp, LST_FLOATINGPOINT); + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList(object)\n"); break; default: break; @@ -595,19 +646,22 @@ void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetType) switch(targetType) { case LST_INTEGER: - fprintf(fp, "call int32 valuetype [mscorlib]System.Int32::Parse(string)\n"); + fprintf(fp, "call int32 [LslLibrary]LindenLab.SecondLife.LslRunTime::StringToInt(string)\n"); break; case LST_FLOATINGPOINT: - fprintf(fp, "call float64 valuetype [mscorlib]System.Double::Parse(string)\n"); + fprintf(fp, "call float32 [LslLibrary]LindenLab.SecondLife.LslRunTime::StringToFloat(string)\n"); break; + case LST_KEY: + fprintf(fp, "call valuetype [ScriptTypes]LindenLab.SecondLife.Key class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateKey'(string)\n"); + break; case LST_LIST: - fprintf(fp, "call class [mscorlib]System.Collections.ArrayList [LScriptLibrary]LScriptInternal::CreateList(object)\n"); + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList(object)\n"); break; case LST_VECTOR: - fprintf(fp, "call valuetype [LScriptLibrary]LLVector valuetype [LScriptLibrary]LLVector::'Parse'(string)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'ParseVector'(string)\n"); break; case LST_QUATERNION: - fprintf(fp, "call valuetype [LScriptLibrary]LLQuaternion valuetype [LScriptLibrary]LLQuaternion::'Parse'(string)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Quaternion class [LslUserScript]LindenLab.SecondLife.LslUserScript::'ParseQuaternion'(string)\n"); break; default: break; @@ -619,9 +673,11 @@ void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetType) case LST_KEY: break; case LST_STRING: + fprintf(fp, "call string [LslUserScript]LindenLab.SecondLife.LslUserScript::'ToString'(valuetype [ScriptTypes]LindenLab.SecondLife.Key)\n"); break; case LST_LIST: - fprintf(fp, "call class [mscorlib]System.Collections.ArrayList [LScriptLibrary]LScriptInternal::CreateList(object)\n"); + print_cil_box(fp, LST_KEY); + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList(object)\n"); break; default: break; @@ -633,10 +689,11 @@ void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetType) case LST_VECTOR: break; case LST_STRING: - fprintf(fp, "call string valuetype [LScriptLibrary]LLVector::'ToString'(valuetype [LScriptLibrary]LLVector)\n"); + fprintf(fp, "call string [LslUserScript]LindenLab.SecondLife.LslUserScript::'ToString'(valuetype [ScriptTypes]LindenLab.SecondLife.Vector)\n"); break; case LST_LIST: - fprintf(fp, "call class [mscorlib]System.Collections.ArrayList [LScriptLibrary]LScriptInternal::CreateList(object)\n"); + print_cil_box(fp, LST_VECTOR); + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList(object)\n"); break; default: break; @@ -648,10 +705,11 @@ void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetType) case LST_QUATERNION: break; case LST_STRING: - fprintf(fp, "call string valuetype [LScriptLibrary]LLQuaternion::'ToString'(valuetype [LScriptLibrary]LLQuaternion)\n"); + fprintf(fp, "call string [LslUserScript]LindenLab.SecondLife.LslUserScript::'ToString'(valuetype [ScriptTypes]LindenLab.SecondLife.Quaternion)\n"); break; case LST_LIST: - fprintf(fp, "call class [mscorlib]System.Collections.ArrayList [LScriptLibrary]LScriptInternal::CreateList(object)\n"); + print_cil_box(fp, LST_QUATERNION); + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList(object)\n"); break; default: break; @@ -663,7 +721,7 @@ void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetType) case LST_LIST: break; case LST_STRING: - fprintf(fp, "call string [LScriptLibrary]LScriptInternal::ListToString(class [mscorlib]System.Collections.ArrayList)\n"); + fprintf(fp, "call string [LslLibrary]LindenLab.SecondLife.LslRunTime::ListToString(class [mscorlib]System.Collections.ArrayList)\n"); break; default: break; @@ -674,10 +732,57 @@ void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetType) } } -bool is_SA_constant_integer(LLScriptSimpleAssignable* sa) +static void print_cil_numeric_cast(LLFILE* fp, LSCRIPTType currentArg, LSCRIPTType otherArg) { - // HACK: Downcast based on type. - return (sa->mType == LSSAT_CONSTANT && ((LLScriptSAConstant*) sa)->mConstant->mType == LST_INTEGER); + if((currentArg == LST_INTEGER) && ((otherArg == LST_FLOATINGPOINT) || (otherArg == LST_VECTOR))) + { + print_cil_cast(fp, LST_INTEGER, LST_FLOATINGPOINT); + } +} + +static void print_cil_assignment_cast(LLFILE* fp, LSCRIPTType src, + LSCRIPTType dest) +{ + if (LST_STRING == src && LST_KEY == dest) + { + print_cil_cast(fp, src, dest); + } + else if(LST_KEY == src && LST_STRING == dest) + { + print_cil_cast(fp, src, dest); + } + else + { + print_cil_numeric_cast(fp, src, dest); + } +} + +// HACK! Babbage: should be converted to virtual on LSCRIPTSimpleAssignableType to avoid downcasts. +LSCRIPTType get_type(LLScriptSimpleAssignable* sa) +{ + LSCRIPTType result = LST_NULL; + switch(sa->mType) + { + case LSSAT_IDENTIFIER: + result = ((LLScriptSAIdentifier*) sa)->mIdentifier->mScopeEntry->mType; + break; + case LSSAT_CONSTANT: + result = ((LLScriptSAConstant*) sa)->mConstant->mType; + break; + case LSSAT_VECTOR_CONSTANT: + result = LST_VECTOR; + break; + case LSSAT_QUATERNION_CONSTANT: + result = LST_QUATERNION; + break; + case LSSAT_LIST_CONSTANT: + result = LST_LIST; + break; + default: + result = LST_UNDEFINED; + break; + } + return result; } void LLScriptSAVector::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) @@ -786,23 +891,23 @@ void LLScriptSAVector::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompile // Load arguments. mEntry1->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - if(is_SA_constant_integer(mEntry1)) + if(LST_INTEGER == get_type(mEntry1)) { print_cil_cast(fp, LST_INTEGER, LST_FLOATINGPOINT); } mEntry2->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - if(is_SA_constant_integer(mEntry3)) + if(LST_INTEGER == get_type(mEntry2)) { print_cil_cast(fp, LST_INTEGER, LST_FLOATINGPOINT); } mEntry3->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - if(is_SA_constant_integer(mEntry3)) + if(LST_INTEGER == get_type(mEntry3)) { print_cil_cast(fp, LST_INTEGER, LST_FLOATINGPOINT); } // Call named ctor, which leaves new Vector on stack, so it can be saved in to local or argument just like a primitive type. - fprintf(fp, "call valuetype [LScriptLibrary]LLVector valuetype [LScriptLibrary]LLVector::'create'(float32, float32, float32)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32)\n"); // Next. if (mNextp) @@ -952,28 +1057,28 @@ void LLScriptSAQuaternion::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom // Load arguments. mEntry1->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - if(is_SA_constant_integer(mEntry1)) + if(LST_INTEGER == get_type(mEntry1)) { print_cil_cast(fp, LST_INTEGER, LST_FLOATINGPOINT); } mEntry2->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - if(is_SA_constant_integer(mEntry2)) + if(LST_INTEGER == get_type(mEntry2)) { print_cil_cast(fp, LST_INTEGER, LST_FLOATINGPOINT); } mEntry3->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - if(is_SA_constant_integer(mEntry3)) + if(LST_INTEGER == get_type(mEntry3)) { print_cil_cast(fp, LST_INTEGER, LST_FLOATINGPOINT); } mEntry4->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - if(is_SA_constant_integer(mEntry4)) + if(LST_INTEGER == get_type(mEntry4)) { print_cil_cast(fp, LST_INTEGER, LST_FLOATINGPOINT); } // Call named ctor, which leaves new Vector on stack, so it can be saved in to local or argument just like a primitive type. - fprintf(fp, "call valuetype [LScriptLibrary]LLQuaternion valuetype [LScriptLibrary]LLQuaternion::'create'(float32, float32, float32, float32)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Quaternion class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateQuaternion'(float32, float32, float32, float32)\n"); // Next. if (mNextp) @@ -1049,6 +1154,40 @@ void LLScriptSAList::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa } } break; + case LSCP_EMIT_CIL_ASSEMBLY: + { + // Create list. + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()\n"); + + // Add elements. + LLScriptSimpleAssignable* current_entry = mEntryList; + LLScriptSimpleAssignable* next_entry = NULL; + while(NULL != current_entry) + { + next_entry = current_entry->mNextp; + + // Null mNextp pointer, so only current list element is processed. + current_entry->mNextp = NULL; + current_entry->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + + // Restore mNextp pointer. + current_entry->mNextp = next_entry; + + // Box element and store in list. + print_cil_box(fp, get_type(current_entry)); + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(class [mscorlib]System.Collections.ArrayList, object)\n"); + + // Process next element. + current_entry = next_entry; + } + + // Process next list. + if (mNextp) + { + mNextp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + } + } + break; default: if (mEntryList) mEntryList->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, ldata); @@ -1093,6 +1232,45 @@ void LLScriptGlobalVariable::gonext(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo } } +// Push initialised variable of type on to stack. +static void print_cil_init_variable(LLFILE* fp, LSCRIPTType type) +{ + switch(type) + { + case LST_INTEGER: + fprintf(fp, "ldc.i4.0\n"); + break; + case LST_FLOATINGPOINT: + fprintf(fp, "ldc.r8 0\n"); + break; + case LST_STRING: + fprintf(fp, "ldstr \"\"\n"); + break; + case LST_KEY: + fprintf(fp, "ldstr \"\"\n"); + fprintf(fp, "call valuetype [ScriptTypes]LindenLab.SecondLife.Key class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateKey'(string)\n"); + break; + case LST_VECTOR: + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32)\n"); + break; + case LST_QUATERNION: + fprintf(fp, "ldc.r8 1\n"); + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Quaternion class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateQuaternion'(float32, float32, float32, float32)\n"); + break; + case LST_LIST: + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()\n"); + break; + default: + break; + } +} + void LLScriptGlobalVariable::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -1164,7 +1342,7 @@ void LLScriptGlobalVariable::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC // it also includes the name of the variable as well as the type // plus 4 bytes of offset from it's apparent address to the actual data #ifdef LSL_INCLUDE_DEBUG_INFO - count += strlen(mIdentifier->mName) + 1 + 1 + 4; /*Flawfinder: ignore*/ + count += strlen(mIdentifier->mName) + 1 + 1 + 4; #else count += 1 + 1 + 4; #endif @@ -1187,7 +1365,7 @@ void LLScriptGlobalVariable::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC chunk->addBytes(&vtype, 1); // null terminated name #ifdef LSL_INCLUDE_DEBUG_INFO - chunk->addBytes(mIdentifier->mName, strlen(mIdentifier->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(mIdentifier->mName, strlen(mIdentifier->mName) + 1); #else chunk->addBytes(1); #endif @@ -1257,16 +1435,27 @@ void LLScriptGlobalVariable::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC case LSCP_EMIT_CIL_ASSEMBLY: // Initialisation inside ctor. + fprintf(fp, "ldarg.0\n"); if (mAssignable) { - fprintf(fp, "ldarg.0\n"); - mAssignable->recurse(fp, tabs, tabsize, LSCP_EMIT_CIL_ASSEMBLY, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "stfld "); - mType->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp," LSL::"); - mIdentifier->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "\n"); + // Initialise to value. + mAssignable->recurse(fp, tabs, tabsize, LSCP_EMIT_CIL_ASSEMBLY, + ptype, prunearg, scope, type, basetype, + count, chunk, heap, stacksize, entry, + entrycount, NULL); + print_cil_assignment_cast(fp, get_type(mAssignable), mType->mType); + } + else + { + // Initialise to zero. + print_cil_init_variable(fp, mType->mType); } + // Store value. + fprintf(fp, "stfld "); + mType->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp," %s::", gScriptp->getClassName()); + mIdentifier->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, "\n"); break; default: mType->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -1298,6 +1487,20 @@ S32 LLScriptEvent::getSize() printf("Event Base Class -- should never get here!\n"); return 0; } +static void checkForDuplicateHandler(LLFILE *fp, LLScriptFilePosition *pos, + LLScriptScope *scope, + const char* name) +{ + LLScriptScope *parent = scope->mParentScope; + if (parent->checkEntry((char*)name)) + { + gErrorToText.writeError(fp, pos, LSERROR_DUPLICATE_NAME); + } + else + { + parent->addEntry(((char*)name), LIT_HANDLER, LST_NULL); + } +} void LLScriptStateEntryEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { @@ -1314,11 +1517,14 @@ void LLScriptStateEntryEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPT case LSCP_EMIT_ASSEMBLY: fprintf(fp, "state_entry()\n"); break; + case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "state_entry"); + break; case LSCP_EMIT_BYTE_CODE: { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "state_entry"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); #endif } break; @@ -1347,6 +1553,9 @@ void LLScriptStateExitEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC fdotabs(fp, tabs, tabsize); fprintf(fp, "state_exit()\n"); break; + case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "state_exit"); + break; case LSCP_EMIT_ASSEMBLY: fprintf(fp, "state_exit()\n"); break; @@ -1354,7 +1563,7 @@ void LLScriptStateExitEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "state_exit"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); #endif } break; @@ -1388,6 +1597,7 @@ void LLScriptTouchStartEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPT break; break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "touch_start"); if (scope->checkEntry(mCount->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -1412,11 +1622,18 @@ void LLScriptTouchStartEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPT { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "touch_start"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mCount->mName, strlen(mCount->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mCount->mName, strlen(mCount->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "touch_start( int32 "); + mCount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; + break; default: mCount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -1446,6 +1663,7 @@ void LLScriptTouchEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi break; break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "touch"); if (scope->checkEntry(mCount->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -1470,11 +1688,18 @@ void LLScriptTouchEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "touch"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mCount->mName, strlen(mCount->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mCount->mName, strlen(mCount->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "touch( int32 "); + mCount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; + break; default: mCount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -1504,6 +1729,7 @@ void LLScriptTouchEndEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo break; break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "touch_end"); if (scope->checkEntry(mCount->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -1528,11 +1754,18 @@ void LLScriptTouchEndEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "touch_end"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mCount->mName, strlen(mCount->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mCount->mName, strlen(mCount->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "touch_end( int32 "); + mCount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; + break; default: mCount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -1562,6 +1795,7 @@ void LLScriptCollisionStartEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSC break; break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "collision_start"); if (scope->checkEntry(mCount->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -1586,11 +1820,17 @@ void LLScriptCollisionStartEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSC { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "collision_start"; - chunk->addBytes(name, (S32)strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mCount->mName, (S32)strlen(mCount->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, (S32)strlen(name) + 1); + chunk->addBytes(mCount->mName, (S32)strlen(mCount->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "collision_start( int32 "); + mCount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mCount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -1620,6 +1860,7 @@ void LLScriptCollisionEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC break; break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "collision"); if (scope->checkEntry(mCount->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -1644,11 +1885,16 @@ void LLScriptCollisionEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "collision"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mCount->mName, strlen(mCount->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mCount->mName, strlen(mCount->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fprintf(fp, "collision( int32 "); + mCount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mCount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -1678,6 +1924,7 @@ void LLScriptCollisionEndEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRI break; break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "collision_end"); if (scope->checkEntry(mCount->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -1702,11 +1949,17 @@ void LLScriptCollisionEndEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRI { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "collision_end"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mCount->mName, strlen(mCount->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mCount->mName, strlen(mCount->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "collision_end( int32 "); + mCount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mCount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -1735,6 +1988,7 @@ void LLScriptLandCollisionStartEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "land_collision_start"); if (scope->checkEntry(mPosition->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -1759,11 +2013,17 @@ void LLScriptLandCollisionStartEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "land_collision_start"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mPosition->mName, strlen(mPosition->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mPosition->mName, strlen(mPosition->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "land_collision_start( class [ScriptTypes]LindenLab.SecondLife.Vector "); + mPosition->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mPosition->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -1794,6 +2054,7 @@ void LLScriptLandCollisionEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCR fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "land_collision"); if (scope->checkEntry(mPosition->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -1818,11 +2079,17 @@ void LLScriptLandCollisionEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCR { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "land_collision"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mPosition->mName, strlen(mPosition->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mPosition->mName, strlen(mPosition->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "land_collision( class [ScriptTypes]LindenLab.SecondLife.Vector "); + mPosition->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mPosition->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -1852,6 +2119,7 @@ void LLScriptLandCollisionEndEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, L fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "land_collision_end"); if (scope->checkEntry(mPosition->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -1875,12 +2143,18 @@ void LLScriptLandCollisionEndEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, L case LSCP_EMIT_BYTE_CODE: { #ifdef LSL_INCLUDE_DEBUG_INFO - char name[] = "land_collision_end"; /*Flawfinder: ignore*/ - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mPosition->mName, strlen(mPosition->mName) + 1); /*Flawfinder: ignore*/ + char name[] = "land_collision_end"; + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mPosition->mName, strlen(mPosition->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "land_collision_end( class [ScriptTypes]LindenLab.SecondLife.Vector "); + mPosition->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mPosition->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -1910,6 +2184,7 @@ void LLScriptInventoryEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "changed"); if (scope->checkEntry(mChange->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -1934,11 +2209,17 @@ void LLScriptInventoryEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "changed"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mChange->mName, strlen(mChange->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mChange->mName, strlen(mChange->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "changed( int32 "); + mChange->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mChange->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -1967,6 +2248,7 @@ void LLScriptAttachEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "attach"); if (scope->checkEntry(mAttach->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -1991,11 +2273,17 @@ void LLScriptAttachEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "attach"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mAttach->mName, strlen(mAttach->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mAttach->mName, strlen(mAttach->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "attach( valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mAttach->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )\n"); + break; default: mAttach->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -2026,6 +2314,7 @@ void LLScriptDataserverEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPT fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "dataserver"); if (scope->checkEntry(mID->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -2061,12 +2350,20 @@ void LLScriptDataserverEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPT { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "dataserver"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mID->mName, strlen(mID->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mData->mName, strlen(mData->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mID->mName, strlen(mID->mName) + 1); + chunk->addBytes(mData->mName, strlen(mData->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "dataserver( valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mID->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", string "); + mData->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mID->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mData->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -2095,14 +2392,21 @@ void LLScriptTimerEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi case LSCP_EMIT_ASSEMBLY: fprintf(fp, "timer()\n"); break; + case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "timer"); + break; + case LSCP_EMIT_BYTE_CODE: { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "timer"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fprintf(fp, "timer()"); + break; default: break; } @@ -2126,14 +2430,21 @@ void LLScriptMovingStartEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIP fdotabs(fp, tabs, tabsize); fprintf(fp, "moving_start()\n"); break; + case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "moving_start"); + break; + case LSCP_EMIT_BYTE_CODE: { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "moving_start"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fprintf(fp, "moving_start()"); + break; default: break; } @@ -2157,14 +2468,21 @@ void LLScriptMovingEndEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC fdotabs(fp, tabs, tabsize); fprintf(fp, "moving_end()\n"); break; + case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "moving_end"); + break; + case LSCP_EMIT_BYTE_CODE: { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "moving_end"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fprintf(fp, "moving_end()"); + break; default: break; } @@ -2191,6 +2509,7 @@ void LLScriptRTPEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompile fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "run_time_perms"); if (scope->checkEntry(mRTPermissions->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -2215,11 +2534,18 @@ void LLScriptRTPEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompile { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "chat"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mRTPermissions->mName, strlen(mRTPermissions->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mRTPermissions->mName, strlen(mRTPermissions->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + // NOTE: Not replicating LSL2 bug by calling RTP event hander "chat" + fdotabs(fp, tabs, tabsize); + fprintf(fp, "run_time_perms( int32 "); + mRTPermissions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mRTPermissions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -2254,6 +2580,7 @@ void LLScriptChatEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompil fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "listen"); // note: this is actually listen in lsl source if (scope->checkEntry(mChannel->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -2311,14 +2638,26 @@ void LLScriptChatEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompil { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "chat"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mChannel->mName, strlen(mChannel->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mName->mName, strlen(mName->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mID->mName, strlen(mID->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mMessage->mName, strlen(mMessage->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mChannel->mName, strlen(mChannel->mName) + 1); + chunk->addBytes(mName->mName, strlen(mName->mName) + 1); + chunk->addBytes(mID->mName, strlen(mID->mName) + 1); + chunk->addBytes(mMessage->mName, strlen(mMessage->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "chat( int32 "); + mChannel->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", string "); + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mID->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", string "); + mMessage->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mChannel->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -2350,6 +2689,7 @@ void LLScriptSensorEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "sensor"); if (scope->checkEntry(mNumber->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -2374,11 +2714,17 @@ void LLScriptSensorEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "sensor"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mNumber->mName, strlen(mNumber->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mNumber->mName, strlen(mNumber->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "sensor( int32 "); + mNumber->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mNumber->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -2407,6 +2753,7 @@ void LLScriptObjectRezEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "object_rez"); if (scope->checkEntry(mID->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -2431,11 +2778,17 @@ void LLScriptObjectRezEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "sensor"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mID->mName, strlen(mID->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mID->mName, strlen(mID->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "object_rez( valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mID->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mID->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -2468,6 +2821,7 @@ void LLScriptControlEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "control"); if (scope->checkEntry(mName->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -2514,13 +2868,23 @@ void LLScriptControlEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "control"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mName->mName, strlen(mName->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mLevels->mName, strlen(mLevels->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mEdges->mName, strlen(mEdges->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mName->mName, strlen(mName->mName) + 1); + chunk->addBytes(mLevels->mName, strlen(mLevels->mName) + 1); + chunk->addBytes(mEdges->mName, strlen(mEdges->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "control( valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", int32 "); + mLevels->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", int32 "); + mEdges->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mLevels->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -2557,6 +2921,7 @@ void LLScriptLinkMessageEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIP fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "link_message"); if (scope->checkEntry(mSender->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -2614,14 +2979,26 @@ void LLScriptLinkMessageEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIP { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "link_message"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mSender->mName, strlen(mSender->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mNum->mName, strlen(mNum->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mStr->mName, strlen(mStr->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mID->mName, strlen(mID->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mSender->mName, strlen(mSender->mName) + 1); + chunk->addBytes(mNum->mName, strlen(mNum->mName) + 1); + chunk->addBytes(mStr->mName, strlen(mStr->mName) + 1); + chunk->addBytes(mID->mName, strlen(mID->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "link_message( int32 "); + mSender->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", int32 "); + mNum->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", string "); + mStr->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mID->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mSender->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mNum->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -2663,6 +3040,7 @@ void LLScriptRemoteEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "remote_event"); if (scope->checkEntry(mType->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -2742,16 +3120,32 @@ void LLScriptRemoteEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "remote_event"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mType->mName, strlen(mType->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mChannel->mName, strlen(mChannel->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mMessageID->mName, strlen(mMessageID->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mSender->mName, strlen(mSender->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mIntVal->mName, strlen(mIntVal->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mStrVal->mName, strlen(mStrVal->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mType->mName, strlen(mType->mName) + 1); + chunk->addBytes(mChannel->mName, strlen(mChannel->mName) + 1); + chunk->addBytes(mMessageID->mName, strlen(mMessageID->mName) + 1); + chunk->addBytes(mSender->mName, strlen(mSender->mName) + 1); + chunk->addBytes(mIntVal->mName, strlen(mIntVal->mName) + 1); + chunk->addBytes(mStrVal->mName, strlen(mStrVal->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "remote_event( int32 "); + mType->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mChannel->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mMessageID->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", string "); + mSender->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", int32 "); + mIntVal->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", string "); + mStrVal->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mType->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mChannel->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -2784,7 +3178,7 @@ void LLScriptHTTPResponseEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRI mRequestId->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, ", integer "); mStatus->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, ", list "); + fprintf(fp, ", class [mscorlib]System.Collections.ArrayList "); mMetadata->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, ", string "); mBody->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -2792,6 +3186,7 @@ void LLScriptHTTPResponseEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRI break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "http_response"); if (scope->checkEntry(mRequestId->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -2857,15 +3252,26 @@ void LLScriptHTTPResponseEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRI { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "http_response"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mRequestId->mName, strlen(mRequestId->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mStatus->mName, strlen(mStatus->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mMetadata->mName, strlen(mMetadata->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mBody->mName, strlen(mBody->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mRequestId->mName, strlen(mRequestId->mName) + 1); + chunk->addBytes(mStatus->mName, strlen(mStatus->mName) + 1); + chunk->addBytes(mMetadata->mName, strlen(mMetadata->mName) + 1); + chunk->addBytes(mBody->mName, strlen(mBody->mName) + 1); #endif } break; - + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "http_response( valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mRequestId->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", int32 "); + mStatus->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", class [mscorlib]System.Collections.ArrayList "); + mMetadata->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", string "); + mBody->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )\n"); + break; default: mRequestId->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mStatus->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -2900,6 +3306,7 @@ void LLScriptMoneyEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "money"); if (scope->checkEntry(mName->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -2935,12 +3342,20 @@ void LLScriptMoneyEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "money"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mName->mName, strlen(mName->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mAmount->mName, strlen(mAmount->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mName->mName, strlen(mName->mName) + 1); + chunk->addBytes(mAmount->mName, strlen(mAmount->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "money( valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", int32 "); + mAmount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mAmount->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -2978,6 +3393,7 @@ void LLScriptEmailEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "email"); if (scope->checkEntry(mTime->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -3046,15 +3462,29 @@ void LLScriptEmailEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "email"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mTime->mName, strlen(mTime->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mAddress->mName, strlen(mAddress->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mSubject->mName, strlen(mSubject->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mBody->mName, strlen(mBody->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mNumber->mName, strlen(mNumber->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mTime->mName, strlen(mTime->mName) + 1); + chunk->addBytes(mAddress->mName, strlen(mAddress->mName) + 1); + chunk->addBytes(mSubject->mName, strlen(mSubject->mName) + 1); + chunk->addBytes(mBody->mName, strlen(mBody->mName) + 1); + chunk->addBytes(mNumber->mName, strlen(mNumber->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "email( string "); + mTime->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", string "); + mAddress->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", string "); + mSubject->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", string "); + mBody->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", int32 "); + mNumber->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mTime->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mAddress->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -3087,6 +3517,7 @@ void LLScriptRezEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompile fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "rez"); if (scope->checkEntry(mStartParam->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -3111,11 +3542,17 @@ void LLScriptRezEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompile { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "rez"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mStartParam->mName, strlen(mStartParam->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mStartParam->mName, strlen(mStartParam->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "rez( int32 "); + mStartParam->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mStartParam->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -3143,14 +3580,20 @@ void LLScriptNoSensorEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo case LSCP_EMIT_ASSEMBLY: fprintf(fp, "no_sensor()\n"); break; - case LSCP_EMIT_BYTE_CODE: + case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "no_sensor"); + break; + case LSCP_EMIT_BYTE_CODE: { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "no_sensor"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fprintf(fp, "no_sensor()"); + break; default: break; } @@ -3181,6 +3624,7 @@ void LLScriptAtTarget::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompile fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "at_target"); if (scope->checkEntry(mTargetNumber->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -3226,14 +3670,24 @@ void LLScriptAtTarget::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompile case LSCP_EMIT_BYTE_CODE: { #ifdef LSL_INCLUDE_DEBUG_INFO - char name[] = "at_target"; /*Flawfinder: ignore*/ - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mTargetNumber->mName, strlen(mTargetNumber->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mTargetPosition->mName, strlen(mTargetPosition->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mOurPosition->mName, strlen(mOurPosition->mName) + 1); /*Flawfinder: ignore*/ + char name[] = "at_target"; + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mTargetNumber->mName, strlen(mTargetNumber->mName) + 1); + chunk->addBytes(mTargetPosition->mName, strlen(mTargetPosition->mName) + 1); + chunk->addBytes(mOurPosition->mName, strlen(mOurPosition->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "at_target( int32 "); + mTargetNumber->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", class [ScriptTypes]LindenLab.SecondLife.Vector "); + mTargetPosition->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", class [ScriptTypes]LindenLab.SecondLife.Vector "); + mOurPosition->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mTargetNumber->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mTargetPosition->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -3265,14 +3719,21 @@ void LLScriptNotAtTarget::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp case LSCP_EMIT_ASSEMBLY: fprintf(fp, "not_at_target()\n"); break; + case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "not_at_target"); + break; + case LSCP_EMIT_BYTE_CODE: { #ifdef LSL_INCLUDE_DEBUG_INFO - char name[] = "not_at_target"; /*Flawfinder: ignore*/ - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ + char name[] = "not_at_target"; + chunk->addBytes(name, strlen(name) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fprintf(fp, "not_at_target()"); + break; default: break; } @@ -3294,7 +3755,7 @@ void LLScriptAtRotTarget::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp case LSCP_PRETTY_PRINT: case LSCP_EMIT_ASSEMBLY: fdotabs(fp, tabs, tabsize); - fprintf(fp, "at_target( integer "); + fprintf(fp, "at_rot_target( integer "); mTargetNumber->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, ", quaternion "); mTargetRotation->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -3303,6 +3764,7 @@ void LLScriptAtRotTarget::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp fprintf(fp, " )\n"); break; case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "at_rot_target"); if (scope->checkEntry(mTargetNumber->mName)) { gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); @@ -3349,13 +3811,23 @@ void LLScriptAtRotTarget::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "at_rot_target"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mTargetNumber->mName, strlen(mTargetNumber->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mTargetRotation->mName, strlen(mTargetRotation->mName) + 1); /*Flawfinder: ignore*/ - chunk->addBytes(mOurRotation->mName, strlen(mOurRotation->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mTargetNumber->mName, strlen(mTargetNumber->mName) + 1); + chunk->addBytes(mTargetRotation->mName, strlen(mTargetRotation->mName) + 1); + chunk->addBytes(mOurRotation->mName, strlen(mOurRotation->mName) + 1); #endif } break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "at_rot_target( int32 "); + mTargetNumber->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", class [ScriptTypes]LindenLab.SecondLife.Quaternion "); + mTargetRotation->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", class [ScriptTypes]LindenLab.SecondLife.Quaternion "); + mOurRotation->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; default: mTargetNumber->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mTargetRotation->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -3391,10 +3863,17 @@ void LLScriptNotAtRotTarget::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTC { #ifdef LSL_INCLUDE_DEBUG_INFO char name[] = "not_at_rot_target"; - chunk->addBytes(name, strlen(name) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(name, strlen(name) + 1); #endif } break; + case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "not_at_rot_target"); + break; + + case LSCP_EMIT_CIL_ASSEMBLY: + fprintf(fp, "not_at_rot_target()"); + break; default: break; } @@ -3563,6 +4042,25 @@ S32 LLScriptForExpressionList::getSize() return 0; } +// CIL code generation requires both caller and callee scope entries, so cannot use normal recurse signature. +// TODO: Refactor general purpose recurse calls in to pass specific virtuals using visitor pattern to select method by pass and node type. +static void print_cil_func_expression_list(LLScriptFuncExpressionList* self, LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata, LLScriptScopeEntry *callee_entry) +{ + self->mFirstp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + LSCRIPTType argtype = callee_entry->mFunctionArgs.getType(entrycount); + if (argtype != self->mFirstp->mReturnType) + { + print_cil_cast(fp, self->mFirstp->mReturnType, argtype); + } + entrycount++; + if (self->mSecondp) + { + llassert(LET_FUNC_EXPRESSION_LIST == self->mSecondp->mType); + print_cil_func_expression_list((LLScriptFuncExpressionList*) self->mSecondp, fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL, callee_entry); + + } +} + void LLScriptFuncExpressionList::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -3660,31 +4158,6 @@ void LLScriptFuncExpressionList::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCR } } break; - /* TODO: Fix conflict between global/local variable determination needing caller scope and cast determination here needs callee scope... - case LSCP_EMIT_CIL_ASSEMBLY: - { - mFirstp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - LSCRIPTType argtype = entry->mFunctionArgs.getType(entrycount); - if (argtype != mFirstp->mReturnType) - { - print_cil_cast(fp, mFirstp->mReturnType, argtype); - } - entrycount++; - if (mSecondp) - { - mSecondp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - if (mSecondp->mReturnType) - { - argtype = entry->mFunctionArgs.getType(entrycount); - if (argtype != mSecondp->mReturnType) - { - print_cil_cast(fp, mFirstp->mReturnType, argtype); - } - } - } - } - break; - */ default: mFirstp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); if (mSecondp) @@ -3753,8 +4226,13 @@ void LLScriptListExpressionList::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCR } break; case LSCP_EMIT_CIL_ASSEMBLY: - // Evaluate expressions in reverse order so first expression is on top of stack. - // Results can then be popped and appended to list to result in list with correct order. + mFirstp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + if (mFirstp->mType != LET_LIST_EXPRESSION_LIST) + { + // Box value. + print_cil_box(fp, mFirstp->mReturnType); + ++count; + } if (mSecondp) { mSecondp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -3762,18 +4240,9 @@ void LLScriptListExpressionList::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCR { // Box value. print_cil_box(fp, mSecondp->mReturnType); - ++count; } } - mFirstp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - if (mFirstp->mType != LET_LIST_EXPRESSION_LIST) - { - // Box value. - print_cil_box(fp, mFirstp->mReturnType); - - ++count; - } break; default: mFirstp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -3793,14 +4262,22 @@ S32 LLScriptListExpressionList::getSize() // Returns true if identifier is a parameter and false if identifier is a local variable within function_scope. bool is_parameter(LLScriptIdentifier* identifier, LLScriptScopeEntry* function_scope) { - // Function offset stores offset of first local. - // Compare variable offset with function offset to - // determine whether variable is local or parameter. - return (identifier->mScopeEntry->mOffset < function_scope->mOffset); + // Function stores offset of first local. + if(0 == function_scope->mOffset) + { + // Function offset 0 -> no parameters -> identifier is a local. + return false; + } + else + { + // Compare variable offset with function offset to + // determine whether variable is local or parameter. + return (identifier->mScopeEntry->mOffset < function_scope->mOffset); + } } // If assignment is to global variable, pushes this pointer on to stack. -void print_cil_load_address(LLFILE* fp, LLScriptExpression* exp, LLScriptScopeEntry* function_scope) +static void print_cil_load_address(LLFILE* fp, LLScriptExpression* exp, LLScriptScopeEntry* function_scope) { LLScriptLValue *lvalue = (LLScriptLValue *) exp; LLScriptIdentifier *ident = lvalue->mIdentifier; @@ -3811,7 +4288,7 @@ void print_cil_load_address(LLFILE* fp, LLScriptExpression* exp, LLScriptScopeEn fprintf(fp, "ldarg.0\n"); } - // If accessor, load address of object. + // If accessor, load value type address, consumed by ldfld. if(lvalue->mAccessor) { if(ident->mScopeEntry->mIDType == LIT_VARIABLE) @@ -3819,7 +4296,7 @@ void print_cil_load_address(LLFILE* fp, LLScriptExpression* exp, LLScriptScopeEn if(is_parameter(ident, function_scope)) { // Parameter, load by name. - fprintf(fp, "ldarga.s %s\n", ident->mScopeEntry->mIdentifier); + fprintf(fp, "ldarga.s '%s'\n", ident->mScopeEntry->mIdentifier); } else { @@ -3830,13 +4307,13 @@ void print_cil_load_address(LLFILE* fp, LLScriptExpression* exp, LLScriptScopeEn else if (ident->mScopeEntry->mIDType == LIT_GLOBAL) { fprintf(fp, "ldflda "); - print_cil_type(fp, ident->mScopeEntry->mType); - fprintf(fp, " LSL::%s\n", ident->mScopeEntry->mIdentifier); + print_cil_member(fp, ident); } } } -void print_cil_accessor(LLFILE* fp, LLScriptLValue *lvalue) +static void print_cil_accessor(LLFILE* fp, LLScriptLValue *lvalue) + { LLScriptIdentifier *ident = lvalue->mIdentifier; print_cil_type(fp, lvalue->mReturnType); @@ -3845,12 +4322,6 @@ void print_cil_accessor(LLFILE* fp, LLScriptLValue *lvalue) fprintf(fp, "::%s\n", lvalue->mAccessor->mName); } -void print_cil_member(LLFILE* fp, LLScriptIdentifier *ident) -{ - print_cil_type(fp, ident->mScopeEntry->mType); - fprintf(fp, " LSL::%s\n", ident->mScopeEntry->mIdentifier); -} - void LLScriptLValue::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -4106,7 +4577,7 @@ void LLScriptLValue::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa if(is_parameter(mIdentifier, entry)) { // Parameter, load by name. - fprintf(fp, "ldarg.s %s\n", mIdentifier->mScopeEntry->mIdentifier); + fprintf(fp, "ldarg.s '%s'\n", mIdentifier->mScopeEntry->mIdentifier); } else { @@ -4136,7 +4607,7 @@ S32 LLScriptLValue::getSize() return 0; } -void print_asignment(LLFILE *fp, LLScriptExpression *exp) +static void print_assignment(LLFILE *fp, LLScriptExpression *exp) { LLScriptLValue *lvalue = (LLScriptLValue *)exp; LLScriptIdentifier *ident = lvalue->mIdentifier; @@ -4164,7 +4635,7 @@ void print_asignment(LLFILE *fp, LLScriptExpression *exp) } } -void print_cil_asignment(LLFILE *fp, LLScriptExpression *exp, LLScriptScopeEntry* function_scope) +static void print_cil_assignment(LLFILE *fp, LLScriptExpression *exp, LLScriptScopeEntry* function_scope) { LLScriptLValue *lvalue = (LLScriptLValue *) exp; LLScriptIdentifier *ident = lvalue->mIdentifier; @@ -4191,7 +4662,7 @@ void print_cil_asignment(LLFILE *fp, LLScriptExpression *exp, LLScriptScopeEntry if(is_parameter(ident, function_scope)) { // Parameter, store by name. - fprintf(fp, "starg.s %s\n", ident->mScopeEntry->mIdentifier); + fprintf(fp, "starg.s '%s'\n", ident->mScopeEntry->mIdentifier); } else { @@ -4319,14 +4790,6 @@ void store2stack(LLScriptExpression *exp, LLScriptExpression *lv, LLScriptByteCo chunk->addInteger(address); } -void print_cil_numeric_cast(LLFILE* fp, LSCRIPTType currentArg, LSCRIPTType otherArg) -{ - if((currentArg == LST_INTEGER) && (otherArg == LST_FLOATINGPOINT)) - { - print_cil_cast(fp, LST_INTEGER, LST_FLOATINGPOINT); - } -} - void LLScriptAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -4344,7 +4807,7 @@ void LLScriptAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi { mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); print_cast(fp, mReturnType, mRightType); - print_asignment(fp, mLValue); + print_assignment(fp, mLValue); } break; case LSCP_TYPE: @@ -4370,8 +4833,8 @@ void LLScriptAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi { print_cil_load_address(fp, mLValue, entry); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - print_cil_numeric_cast(fp, mRightType, mReturnType); - print_cil_asignment(fp, mLValue, entry); + print_cil_assignment_cast(fp, mRightType, mReturnType); + print_cil_assignment(fp, mLValue, entry); } break; default: @@ -4387,8 +4850,15 @@ S32 LLScriptAssignment::getSize() return 0; } -void print_cil_add(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) +static void print_cil_add(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) { + if(LST_LIST == right_type && LST_LIST != left_type) + { + print_cil_box(fp, left_type); + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(class [mscorlib]System.Collections.ArrayList, object)\n"); + return; + } + switch(left_type) { case LST_INTEGER: @@ -4402,27 +4872,49 @@ void print_cil_add(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) case LST_KEY: // String concatenation. - fprintf(fp, "call string valuetype [mscorlib]System.String::Concat(string, string)"); + fprintf(fp, "call string valuetype [LslUserScript]LindenLab.SecondLife.LslUserScript::Add(string, string)\n"); break; case LST_VECTOR: // Vector addition. - // TODO: Inline (requires temporary variables, which must be identified in earlier pass). - fprintf(fp, "call valuetype [LScriptLibrary]LLVector valuetype [LScriptLibrary]LLVector::'add_vec'(valuetype [LScriptLibrary]LLVector, valuetype [LScriptLibrary]LLVector)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Add'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector)\n"); break; case LST_QUATERNION: // Rotation addition. - // TODO: Inline (requires temporary variables, which must be identified in earlier pass). - fprintf(fp, "call valuetype [LScriptLibrary]LLQuaternion valuetype [LScriptLibrary]LLQuaternion::'add_quat'(valuetype [LScriptLibrary]LLQuaternion, valuetype [LScriptLibrary]LLQuaternion)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Quaternion class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Add'(class [ScriptTypes]LindenLab.SecondLife.Quaternion, class [ScriptTypes]LindenLab.SecondLife.Quaternion)\n"); break; case LST_LIST: - print_cil_box(fp, right_type); - fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LScriptLibrary]LScriptInternal::AddReturnList(class [mscorlib]System.Collections.ArrayList, object)\n"); - break; + switch(right_type) + { + case LST_LIST: + // Concatenate lists. + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(class [mscorlib]System.Collections.ArrayList, class [mscorlib]System.Collections.ArrayList)\n"); + break; + case LST_INTEGER: + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList)\n"); + break; + case LST_FLOATINGPOINT: + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(float32, class [mscorlib]System.Collections.ArrayList)\n"); + break; + case LST_STRING: + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(string, class [mscorlib]System.Collections.ArrayList)\n"); + break; + case LST_KEY: + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(valuetype [ScriptTypes]LindenLab.SecondLife.Key, class [mscorlib]System.Collections.ArrayList)\n"); + break; + case LST_VECTOR: + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(valuetype [ScriptTypes]LindenLab.SecondLife.Vector, class [mscorlib]System.Collections.ArrayList)\n"); + break; + case LST_QUATERNION: + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(valuetype [ScriptTypes]LindenLab.SecondLife.Quaternion, class [mscorlib]System.Collections.ArrayList)\n"); + break; + default: + break; + } default: break; @@ -4447,7 +4939,7 @@ void LLScriptAddAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "ADD %s, %s\n", LSCRIPTTypeNames[mRightType], LSCRIPTTypeNames[mLeftType]); - print_asignment(fp, mLValue); + print_assignment(fp, mLValue); } break; case LSCP_TYPE: @@ -4475,12 +4967,12 @@ void LLScriptAddAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo case LSCP_EMIT_CIL_ASSEMBLY: { print_cil_load_address(fp, mLValue, entry); - mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - print_cil_numeric_cast(fp, mLValue->mReturnType, mRightSide->mReturnType); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); print_cil_numeric_cast(fp, mRightSide->mReturnType, mLValue->mReturnType); + mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLValue->mReturnType, mRightSide->mReturnType); print_cil_add(fp, mLValue->mReturnType, mRightSide->mReturnType); - print_cil_asignment(fp, mLValue, entry); + print_cil_assignment(fp, mLValue, entry); } break; default: @@ -4496,29 +4988,30 @@ S32 LLScriptAddAssignment::getSize() return 0; } -void print_cil_sub(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) +static void print_cil_sub(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) { switch(left_type) { case LST_INTEGER: + if(LST_INTEGER == right_type) + { + fprintf(fp, "call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32)\n"); + break; + } case LST_FLOATINGPOINT: - // Numeric subtraction. - fprintf(fp, "sub\n"); + fprintf(fp, "call float64 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(float64, float64)\n"); break; - case LST_VECTOR: // Vector subtraction. - // TODO: Inline (requires temporary variables, which must be identified in earlier pass). - fprintf(fp, "call valuetype [LScriptLibrary]LLVector valuetype [LScriptLibrary]LLVector::'subtract_vec'(valuetype [LScriptLibrary]LLVector, valuetype [LScriptLibrary]LLVector)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Subtract'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector)\n"); break; case LST_QUATERNION: // Rotation subtraction. - // TODO: Inline (requires temporary variables, which must be identified in earlier pass). - fprintf(fp, "call valuetype [LScriptLibrary]LLQuaternion valuetype [LScriptLibrary]LLQuaternion::'subtract_quat'(valuetype [LScriptLibrary]LLQuaternion, valuetype [LScriptLibrary]LLQuaternion)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Quaternion class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Subtract'(class [ScriptTypes]LindenLab.SecondLife.Quaternion, class [ScriptTypes]LindenLab.SecondLife.Quaternion)\n"); break; default: @@ -4546,7 +5039,7 @@ void LLScriptSubAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "SUB %s, %s\n", LSCRIPTTypeNames[mRightType], LSCRIPTTypeNames[mLeftType]); - print_asignment(fp, mLValue); + print_assignment(fp, mLValue); } break; case LSCP_TYPE: @@ -4574,12 +5067,12 @@ void LLScriptSubAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo case LSCP_EMIT_CIL_ASSEMBLY: { print_cil_load_address(fp, mLValue, entry); - mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - print_cil_numeric_cast(fp, mLValue->mReturnType, mRightSide->mReturnType); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); print_cil_numeric_cast(fp, mRightSide->mReturnType, mLValue->mReturnType); + mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLValue->mReturnType, mRightSide->mReturnType); print_cil_sub(fp, mLValue->mReturnType, mRightSide->mReturnType); - print_cil_asignment(fp, mLValue, entry); + print_cil_assignment(fp, mLValue, entry); } break; default: @@ -4595,41 +5088,93 @@ S32 LLScriptSubAssignment::getSize() return 0; } -void print_cil_mul(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) +static void print_cil_neg(LLFILE* fp, LSCRIPTType type) { - switch(left_type) + switch(type) { case LST_INTEGER: case LST_FLOATINGPOINT: + fprintf(fp, "neg\n"); + break; + case LST_VECTOR: + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Negate'(class [ScriptTypes]LindenLab.SecondLife.Vector)\n"); + break; + case LST_QUATERNION: + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Quaternion class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Negate'(class [ScriptTypes]LindenLab.SecondLife.Quaternion)\n"); + break; + default: + break; + } +} - // Numeric multiplication. - fprintf(fp, "mul\n"); +static void print_cil_mul(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) +{ + switch(left_type) + { + case LST_INTEGER: + + switch(right_type) + { + case LST_INTEGER: + case LST_FLOATINGPOINT: + + // Numeric multiplication. + fprintf(fp, "mul\n"); + break; + + case LST_VECTOR: + + // Vector scaling. + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Multiply'(class [ScriptTypes]LindenLab.SecondLife.Vector, float32)\n"); + break; + default: + break; + } break; - - case LST_VECTOR: + + case LST_FLOATINGPOINT: switch(right_type) { case LST_INTEGER: + case LST_FLOATINGPOINT: - print_cil_cast(fp, LST_INTEGER, LST_FLOATINGPOINT); + // Numeric multiplication. + fprintf(fp, "mul\n"); + break; + + case LST_VECTOR: + + // Vector scaling. + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Multiply'(class [ScriptTypes]LindenLab.SecondLife.Vector, float32)\n"); + break; + + default: + break; + } + break; + + case LST_VECTOR: + switch(right_type) + { + case LST_INTEGER: case LST_FLOATINGPOINT: // Vector scaling. - fprintf(fp, "call valuetype [LScriptLibrary]LLVector valuetype [LScriptLibrary]LLVector::'multiply_float'(valuetype [LScriptLibrary]LLVector, float32)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Multiply'(float32, class [ScriptTypes]LindenLab.SecondLife.Vector)\n"); break; case LST_VECTOR: // Dot product. - fprintf(fp, "call float32 valuetype [LScriptLibrary]LLVector::'multiply_vec'(valuetype [LScriptLibrary]LLVector, valuetype [LScriptLibrary]LLVector)\n"); + fprintf(fp, "call float32 class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Multiply'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector)\n"); break; case LST_QUATERNION: // Vector rotation. - fprintf(fp, "call valuetype [LScriptLibrary]LLVector valuetype [LScriptLibrary]LLVector::'multiply_quat'(valuetype [LScriptLibrary]LLVector, valuetype [LScriptLibrary]LLQuaternion)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Multiply'(class [ScriptTypes]LindenLab.SecondLife.Quaternion, class [ScriptTypes]LindenLab.SecondLife.Vector)\n"); break; default: @@ -4640,7 +5185,7 @@ void print_cil_mul(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) case LST_QUATERNION: // Rotation multiplication. - fprintf(fp, "call valuetype [LScriptLibrary]LLQuaternion valuetype [LScriptLibrary]LLQuaternion::'multiply_quat'(valuetype [LScriptLibrary]LLQuaternion, valuetype [LScriptLibrary]LLQuaternion)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Quaternion class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Multiply'(class [ScriptTypes]LindenLab.SecondLife.Quaternion, class [ScriptTypes]LindenLab.SecondLife.Quaternion)\n"); break; default: @@ -4668,7 +5213,7 @@ void LLScriptMulAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "MUL %s, %s\n", LSCRIPTTypeNames[mRightType], LSCRIPTTypeNames[mLeftType]); - print_asignment(fp, mLValue); + print_assignment(fp, mLValue); } break; case LSCP_TYPE: @@ -4677,7 +5222,7 @@ void LLScriptMulAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo mLeftType = type; mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightType = type; - if (!legal_binary_expression(mReturnType, mLeftType, mRightType, mType)) + if (!legal_binary_expression(mReturnType, mLeftType, mRightType, mType) /*|| !legal_assignment(mLValue->mReturnType, mReturnType)*/) { gErrorToText.writeError(fp, this, LSERROR_TYPE_MISMATCH); } @@ -4696,12 +5241,17 @@ void LLScriptMulAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo case LSCP_EMIT_CIL_ASSEMBLY: { print_cil_load_address(fp, mLValue, entry); - mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - print_cil_numeric_cast(fp, mLValue->mReturnType, mRightSide->mReturnType); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); print_cil_numeric_cast(fp, mRightSide->mReturnType, mLValue->mReturnType); + mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLValue->mReturnType, mRightSide->mReturnType); print_cil_mul(fp, mLValue->mReturnType, mRightSide->mReturnType); - print_cil_asignment(fp, mLValue, entry); + if((mLValue->mReturnType == LST_INTEGER) && + (mRightSide->mReturnType == LST_FLOATINGPOINT)) + { + print_cil_cast(fp, LST_FLOATINGPOINT, LST_INTEGER); + } + print_cil_assignment(fp, mLValue, entry); } break; default: @@ -4717,15 +5267,20 @@ S32 LLScriptMulAssignment::getSize() return 0; } -void print_cil_div(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) +static void print_cil_div(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) { switch(left_type) { case LST_INTEGER: + if(LST_INTEGER == right_type) + { + fprintf(fp, "call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Divide(int32, int32)\n"); + break; + } case LST_FLOATINGPOINT: - // Numeric addition. - fprintf(fp, "div\n"); + // Numeric division. + fprintf(fp, "call float64 [LslUserScript]LindenLab.SecondLife.LslUserScript::Divide(float64, float64)\n"); break; case LST_VECTOR: @@ -4733,19 +5288,16 @@ void print_cil_div(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) switch(right_type) { case LST_INTEGER: - - print_cil_cast(fp, LST_INTEGER, LST_FLOATINGPOINT); - case LST_FLOATINGPOINT: // Scale. - fprintf(fp, "call valuetype [LScriptLibrary]LLVector valuetype [LScriptLibrary]LLVector::'divide_float'(valuetype [LScriptLibrary]LLVector, float32)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Divide'(float32, class [ScriptTypes]LindenLab.SecondLife.Vector)\n"); break; case LST_QUATERNION: // Inverse rotation. - fprintf(fp, "call valuetype [LScriptLibrary]LLVector valuetype [LScriptLibrary]LLVector::'divide_quat'(valuetype [LScriptLibrary]LLVector, valuetype [LScriptLibrary]LLQuaternion)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Divide'(class [ScriptTypes]LindenLab.SecondLife.Quaternion, class [ScriptTypes]LindenLab.SecondLife.Vector)\n"); break; default: @@ -4755,7 +5307,7 @@ void print_cil_div(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) case LST_QUATERNION: - fprintf(fp, "call valuetype [LScriptLibrary]LLQuaternion valuetype [LScriptLibrary]LLQuaternion::'divide_quat'(valuetype [LScriptLibrary]LLQuaternion, valuetype [LScriptLibrary]LLQuaternion)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Quaternion class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Divide'(class [ScriptTypes]LindenLab.SecondLife.Quaternion, class [ScriptTypes]LindenLab.SecondLife.Quaternion)\n"); break; default: @@ -4783,7 +5335,7 @@ void LLScriptDivAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "DIV %s, %s\n", LSCRIPTTypeNames[mRightType], LSCRIPTTypeNames[mLeftType]); - print_asignment(fp, mLValue); + print_assignment(fp, mLValue); } break; case LSCP_TYPE: @@ -4811,12 +5363,12 @@ void LLScriptDivAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo case LSCP_EMIT_CIL_ASSEMBLY: { print_cil_load_address(fp, mLValue, entry); - mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - print_cil_numeric_cast(fp, mLValue->mReturnType, mRightSide->mReturnType); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); print_cil_numeric_cast(fp, mRightSide->mReturnType, mLValue->mReturnType); + mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLValue->mReturnType, mRightSide->mReturnType); print_cil_div(fp, mLValue->mReturnType, mRightSide->mReturnType); - print_cil_asignment(fp, mLValue, entry); + print_cil_assignment(fp, mLValue, entry); } break; default: @@ -4832,20 +5384,20 @@ S32 LLScriptDivAssignment::getSize() return 0; } -void print_cil_mod(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) +static void print_cil_mod(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) { switch(left_type) { case LST_INTEGER: // Numeric remainder. - fprintf(fp, "rem\n"); + fprintf(fp, "call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Modulo(int32, int32)\n"); break; case LST_VECTOR: // Vector cross product. - fprintf(fp, "call valuetype [LScriptLibrary]LLVector valuetype [LScriptLibrary]LLVector::'mod_vec'(valuetype [LScriptLibrary]LLVector, valuetype [LScriptLibrary]LLVector)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Modulo'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector)\n"); break; default: @@ -4873,7 +5425,7 @@ void LLScriptModAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "MOD %s, %s\n", LSCRIPTTypeNames[mRightType], LSCRIPTTypeNames[mLeftType]); - print_asignment(fp, mLValue); + print_assignment(fp, mLValue); } break; case LSCP_TYPE: @@ -4901,10 +5453,10 @@ void LLScriptModAssignment::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo case LSCP_EMIT_CIL_ASSEMBLY: { print_cil_load_address(fp, mLValue, entry); - mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + mLValue->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); print_cil_mod(fp, mLValue->mReturnType, mRightSide->mReturnType); - print_cil_asignment(fp, mLValue, entry); + print_cil_assignment(fp, mLValue, entry); } break; default: @@ -4920,9 +5472,10 @@ S32 LLScriptModAssignment::getSize() return 0; } -void print_cil_eq(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) +static void print_cil_eq(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) { - switch(left_type) + + switch(right_type) { case LST_INTEGER: case LST_FLOATINGPOINT: @@ -4932,26 +5485,36 @@ void print_cil_eq(LLFILE* fp, LSCRIPTType left_type, LSCRIPTType right_type) break; case LST_STRING: - case LST_KEY: - + // NOTE: babbage: strings and keys can be compared, so a cast + // may be required + print_cil_cast(fp, left_type, right_type); // String equality. fprintf(fp, "call bool valuetype [mscorlib]System.String::op_Equality(string, string)\n"); break; + + case LST_KEY: + // NOTE: babbage: strings and keys can be compared, so a cast + // may be required + print_cil_cast(fp, left_type, right_type); + + // Key equality. + fprintf(fp, "call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::'Equals'(valuetype [ScriptTypes]LindenLab.SecondLife.Key, valuetype [ScriptTypes]LindenLab.SecondLife.Key)\n"); + break; case LST_VECTOR: // Vector equality. - fprintf(fp, "call bool [LScriptLibrary]LLVector::'equals_vec'(valuetype [LScriptLibrary]LLVector, valuetype [LScriptLibrary]LLVector)\n"); + fprintf(fp, "call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::'Equals'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector)\n"); break; case LST_QUATERNION: // Rotation equality. - fprintf(fp, "call bool [LScriptLibrary]LLQuaternion::'equals_quat'(valuetype [LScriptLibrary]LLQuaternion, valuetype [LScriptLibrary]LLQuaternion)\n"); + fprintf(fp, "call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::'Equals'(class [ScriptTypes]LindenLab.SecondLife.Quaternion, class [ScriptTypes]LindenLab.SecondLife.Quaternion)\n"); break; case LST_LIST: - fprintf(fp, "call bool [LScriptLibrary]LScriptInternal::EqualsList(class [mscorlib]System.Collections.ArrayList, class [mscorlib]System.Collections.ArrayList)\n"); + fprintf(fp, "call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Equals(class [mscorlib]System.Collections.ArrayList, class [mscorlib]System.Collections.ArrayList)\n"); break; default: @@ -5002,10 +5565,10 @@ void LLScriptEquality::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompile } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); print_cil_numeric_cast(fp, mRightSide->mReturnType, mLeftSide->mReturnType); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); print_cil_eq(fp, mLeftSide->mReturnType, mRightSide->mReturnType); break; default: @@ -5063,10 +5626,19 @@ void LLScriptNotEquals::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompil break; case LSCP_EMIT_CIL_ASSEMBLY: mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mRightSide->mReturnType, mLeftSide->mReturnType); mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "ceq\n"); - fprintf(fp, "ldc.i4.0\n"); - fprintf(fp, "ceq\n"); // Compare result of first compare equal with 0 to get compare not equal. + print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); + if (LST_LIST == mLeftSide->mReturnType) + { + fprintf(fp, "call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::NotEquals(class [mscorlib]System.Collections.ArrayList, class [mscorlib]System.Collections.ArrayList)\n"); + } + else + { + print_cil_eq(fp, mLeftSide->mReturnType, mRightSide->mReturnType); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); // Compare result of first compare equal with 0 to get compare not equal. + } break; default: mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -5081,6 +5653,14 @@ S32 LLScriptNotEquals::getSize() return 0; } +static void print_cil_lte(LLFILE* fp) +{ + // NOTE: LSL pushes operands backwards, so <= becomes >= + fprintf(fp, "clt\n"); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); +} + void LLScriptLessEquals::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -5122,11 +5702,11 @@ void LLScriptLessEquals::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "cgt\n"); // Test greater than. - fprintf(fp, "ldc.i4.0\n"); // Use (b == 0) implementation of boolean not. - fprintf(fp, "ceq\n"); // Apply boolean not to greater than. If not greater than, then less or equal. + print_cil_numeric_cast(fp, mRightSide->mReturnType, mLeftSide->mReturnType); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); + print_cil_lte(fp); break; default: mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -5141,6 +5721,14 @@ S32 LLScriptLessEquals::getSize() return 0; } +static void print_cil_gte(LLFILE* fp) +{ + // NOTE: LSL pushes operands backwards, so >= becomes <= + fprintf(fp, "cgt\n"); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); +} + void LLScriptGreaterEquals::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -5182,11 +5770,11 @@ void LLScriptGreaterEquals::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "clt\n"); // Test less than. - fprintf(fp, "ldc.i4.0\n"); // Use (b == 0) implementation of boolean not. - fprintf(fp, "ceq\n"); // Apply boolean not to less than. If not less than, then greater or equal. + print_cil_numeric_cast(fp, mRightSide->mReturnType, mLeftSide->mReturnType); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); + print_cil_gte(fp); break; default: mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -5201,6 +5789,12 @@ S32 LLScriptGreaterEquals::getSize() return 0; } +static void print_cil_lt(LLFILE* fp) +{ + // NOTE: LSL pushes operands backwards, so < becomes > + fprintf(fp, "cgt\n"); +} + void LLScriptLessThan::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -5242,9 +5836,11 @@ void LLScriptLessThan::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompile } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "clt\n"); + print_cil_numeric_cast(fp, mRightSide->mReturnType, mLeftSide->mReturnType); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); + print_cil_lt(fp); break; default: mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -5259,6 +5855,12 @@ S32 LLScriptLessThan::getSize() return 0; } +static void print_cil_gt(LLFILE* fp) +{ + // NOTE: LSL pushes operands backwards, so > becomes < + fprintf(fp, "clt\n"); +} + void LLScriptGreaterThan::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -5300,9 +5902,11 @@ void LLScriptGreaterThan::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "cgt\n"); + print_cil_numeric_cast(fp, mRightSide->mReturnType, mLeftSide->mReturnType); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); + print_cil_gt(fp); break; default: mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -5358,10 +5962,10 @@ void LLScriptPlus::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); print_cil_numeric_cast(fp, mRightSide->mReturnType, mLeftSide->mReturnType); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); print_cil_add(fp, mLeftSide->mReturnType, mRightSide->mReturnType); break; default: @@ -5418,10 +6022,10 @@ void LLScriptMinus::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePas } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); print_cil_numeric_cast(fp, mRightSide->mReturnType, mLeftSide->mReturnType); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); print_cil_sub(fp, mLeftSide->mReturnType, mRightSide->mReturnType); break; default: @@ -5478,10 +6082,10 @@ void LLScriptTimes::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePas } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); print_cil_numeric_cast(fp, mRightSide->mReturnType, mLeftSide->mReturnType); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); print_cil_mul(fp, mLeftSide->mReturnType, mRightSide->mReturnType); break; default: @@ -5538,10 +6142,10 @@ void LLScriptDivide::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); print_cil_numeric_cast(fp, mRightSide->mReturnType, mLeftSide->mReturnType); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_numeric_cast(fp, mLeftSide->mReturnType, mRightSide->mReturnType); print_cil_div(fp, mLeftSide->mReturnType, mRightSide->mReturnType); break; default: @@ -5598,8 +6202,8 @@ void LLScriptMod::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); print_cil_mod(fp, mLeftSide->mReturnType, mRightSide->mReturnType); break; default: @@ -5654,8 +6258,8 @@ void LLScriptBitAnd::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "and\n"); break; default: @@ -5710,8 +6314,8 @@ void LLScriptBitOr::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePas } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "or\n"); break; default: @@ -5766,8 +6370,8 @@ void LLScriptBitXor::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "xor\n"); break; default: @@ -5822,9 +6426,15 @@ void LLScriptBooleanAnd::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "and\n"); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); + fprintf(fp, "or\n"); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); break; default: mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -5881,6 +6491,10 @@ void LLScriptBooleanOr::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompil mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "or\n"); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); break; default: mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -5934,9 +6548,9 @@ void LLScriptShiftLeft::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompil } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "shl\n"); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, "call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::ShiftLeft(int32, int32)\n"); break; default: mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -5991,9 +6605,9 @@ void LLScriptShiftRight::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi } break; case LSCP_EMIT_CIL_ASSEMBLY: - mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mRightSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "shr\n"); + mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, "call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::ShiftRight(int32, int32)\n"); break; default: mLeftSide->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -6076,6 +6690,12 @@ void LLScriptUnaryMinus::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompi chunk->addByte(typebyte); } break; + case LSCP_EMIT_CIL_ASSEMBLY: + { + mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_neg(fp, mLeftType); + } + break; default: mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -6219,7 +6839,7 @@ void LLScriptPreIncrement::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom { fprintf(fp, "Unexpected Type\n"); } - print_asignment(fp, mExpression); + print_assignment(fp, mExpression); } break; case LSCP_TYPE: @@ -6266,21 +6886,21 @@ void LLScriptPreIncrement::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom print_cil_load_address(fp, mExpression, entry); if (mReturnType == LST_INTEGER) { - fprintf(fp, "ldc.i4.1\n"); mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, "ldc.i4.1\n"); fprintf(fp, "add\n"); } else if (mReturnType == LST_FLOATINGPOINT) { - fprintf(fp, "ldc.r8.1\n"); mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, "ldc.r8 1\n"); fprintf(fp, "add\n"); } else { fprintf(fp, "Unexpected Type\n"); } - print_cil_asignment(fp, mExpression, entry); + print_cil_assignment(fp, mExpression, entry); } break; default: @@ -6327,7 +6947,7 @@ void LLScriptPreDecrement::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom { fprintf(fp, "Unexpected Type\n"); } - print_asignment(fp, mExpression); + print_assignment(fp, mExpression); } break; case LSCP_TYPE: @@ -6374,21 +6994,21 @@ void LLScriptPreDecrement::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom print_cil_load_address(fp, mExpression, entry); if (mReturnType == LST_INTEGER) { - fprintf(fp, "ldc.i4.1\n"); mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, "ldc.i4.1\n"); fprintf(fp, "sub\n"); } else if (mReturnType == LST_FLOATINGPOINT) { - fprintf(fp, "ldc.r8.1\n"); mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, "ldc.r8 1\n"); fprintf(fp, "sub\n"); } else { fprintf(fp, "Unexpected Type\n"); } - print_cil_asignment(fp, mExpression, entry); + print_cil_assignment(fp, mExpression, entry); } break; default: @@ -6555,7 +7175,7 @@ void LLScriptVectorInitializer::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRI print_cil_cast(fp, mExpression3->mReturnType, LST_FLOATINGPOINT); } // Call named ctor, which leaves new Vector on stack, so it can be saved in to local or argument just like a primitive type. - fprintf(fp, "call valuetype [LScriptLibrary]LLVector valuetype [LScriptLibrary]LLVector::'create'(float32, float32, float32)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32)\n"); break; default: mExpression1->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -6696,7 +7316,7 @@ void LLScriptQuaternionInitializer::recurse(LLFILE *fp, S32 tabs, S32 tabsize, L } // Call named ctor, which leaves new Vector on stack, so it can be saved in to local or argument just like a primitive type. - fprintf(fp, "call valuetype [LScriptLibrary]LLQuaternion valuetype [LScriptLibrary]LLQuaternion::'create'(float32, float32, float32, float32)\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Quaternion class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateQuaternion'(float32, float32, float32, float32)\n"); break; default: mExpression1->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -6743,14 +7363,15 @@ void LLScriptListInitializer::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPT mReturnType = type = LST_LIST; break; case LSCP_TO_STACK: + { if (mExpressionList) { pass = LSCP_TO_STACK; - count = 0; - mExpressionList->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + U64 list_element_count = 0; + mExpressionList->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, list_element_count, chunk, heap, stacksize, entry, entrycount, NULL); chunk->addByte(LSCRIPTOpCodes[LOPC_STACKTOL]); - chunk->addInteger((S32)count); - count = 0; + chunk->addInteger((S32)list_element_count); + } else { @@ -6758,26 +7379,26 @@ void LLScriptListInitializer::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPT chunk->addInteger(0); } break; + } case LSCP_EMIT_CIL_ASSEMBLY: - + { // Push boxed elements on stack. - count = 0; + U64 list_element_count = 0; if (mExpressionList) { - mExpressionList->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + mExpressionList->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, list_element_count, chunk, heap, stacksize, entry, entrycount, NULL); } - // Create list on stack, consuming first boxed element. - fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LScriptLibrary]LScriptInternal::CreateList()\n"); + // Create list on stack. + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()\n"); - // Call AddReturnList to add remaining boxed expressions. - for(U64 i = 0; i < count; i++) + // Call Prepend to add remaining boxed expressions. + for(U64 i = 0; i < list_element_count; i++) { - fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LScriptLibrary]LScriptInternal::AddReturnList(object, class [mscorlib]System.Collections.ArrayList)\n"); + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList)\n"); } - count = 0; - break; + } default: if (mExpressionList) { @@ -6824,7 +7445,7 @@ void LLScriptPostIncrement::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo { fprintf(fp, "Unexpected Type\n"); } - print_asignment(fp, mExpression); + print_assignment(fp, mExpression); fprintf(fp, "%s\n", LSCRIPTTypePop[mReturnType]); } break; @@ -6893,24 +7514,34 @@ void LLScriptPostIncrement::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo break; case LSCP_EMIT_CIL_ASSEMBLY: { + // Push original value on to stack. + mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + + // Load address if needed for store. print_cil_load_address(fp, mExpression, entry); + + // Load value again. + // TODO: Work out if sideeffects can result in 2 evaluations of expression giving different values. + // Original LSL2 uses this method, so any bugs due to side effects will probably be identical ;-) mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp,"dup\n"); // Copy expression result to use as increment operand. if (mReturnType == LST_INTEGER) { fprintf(fp, "ldc.i4.1\n"); } else if (mReturnType == LST_FLOATINGPOINT) { - fprintf(fp, "ldc.r8.1\n"); + fprintf(fp, "ldc.r8 1\n"); } else { fprintf(fp, "Unexpected Type\n"); } fprintf(fp, "add\n"); - print_cil_asignment(fp, mExpression, entry); - fprintf(fp, "pop\n"); // Pop assignment result to leave original expression result on stack. TODO: Optimise away redundant pop/dup pairs. + print_cil_assignment(fp, mExpression, entry); + + // Pop assignment result to leave original expression result on stack. + // TODO: Optimise away redundant pop/dup pairs. + fprintf(fp, "pop\n"); } break; default: @@ -6956,7 +7587,7 @@ void LLScriptPostDecrement::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo { fprintf(fp, "Unexpected Type\n"); } - print_asignment(fp, mExpression); + print_assignment(fp, mExpression); fprintf(fp, "%s\n", LSCRIPTTypePop[mReturnType]); } break; @@ -7025,24 +7656,34 @@ void LLScriptPostDecrement::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCo break; case LSCP_EMIT_CIL_ASSEMBLY: { + // Push original value on to stack. + mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + + // Load address if needed for store. print_cil_load_address(fp, mExpression, entry); + + // Load value again. + // TODO: Work out if sideeffects can result in 2 evaluations of expression giving different values. + // Original LSL2 uses this method, so any bugs due to side effects will probably be identical ;-) mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp,"dup\n"); // Copy expression result to use as decrement operand. if (mReturnType == LST_INTEGER) { fprintf(fp, "ldc.i4.1\n"); } else if (mReturnType == LST_FLOATINGPOINT) { - fprintf(fp, "ldc.r8.1\n"); + fprintf(fp, "ldc.r8 1\n"); } else { fprintf(fp, "Unexpected Type\n"); } fprintf(fp, "sub\n"); - print_cil_asignment(fp, mExpression, entry); - fprintf(fp, "pop\n"); // Pop assignment result to leave original expression result on stack. TODO: Optimise away redundant pop/dup pairs. + print_cil_assignment(fp, mExpression, entry); + + // Pop assignment result to leave original expression result on stack. + // TODO: Optimise away redundant pop/dup pairs. + fprintf(fp, "pop\n"); } break; default: @@ -7058,16 +7699,19 @@ S32 LLScriptPostDecrement::getSize() } // Generate arg list. -void print_cil_arg_list(LLFILE *fp, LLScriptFuncExpressionList* exp_list) +static void print_cil_arg_list(LLFILE *fp, LLScriptArgString& args) { - // Print first argument. - print_cil_type(fp, exp_list->mFirstp->mReturnType); - - // Recursively print next arguments. - if(exp_list->mSecondp != NULL) + int i = 0; + bool finished = (i >= args.getNumber()); + while(! finished) { - fprintf(fp, ", "); - print_cil_arg_list(fp, (LLScriptFuncExpressionList*) exp_list->mSecondp); + print_cil_type(fp, args.getType(i)); + ++i; + finished = (i >= args.getNumber()); + if(! finished) + { + fprintf(fp, ", "); + } } } @@ -7146,7 +7790,7 @@ void LLScriptFunctionCall::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom gErrorToText.writeError(fp, this, LSERROR_FUNCTION_TYPE_ERROR); } } - else if (argcount != strlen(mIdentifier->mScopeEntry->mFunctionArgs.mString)) /*Flawfinder: ignore*/ + else if (argcount != strlen(mIdentifier->mScopeEntry->mFunctionArgs.mString)) { gErrorToText.writeError(fp, this, LSERROR_FUNCTION_TYPE_ERROR); } @@ -7217,13 +7861,15 @@ void LLScriptFunctionCall::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom // Load args on to stack. if (mExpressionList) { - mExpressionList->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry /* Needed for is_parameter calls */, 0, NULL); + //mExpressionList->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry /* Needed for is_parameter calls */, 0, NULL); + llassert(LET_FUNC_EXPRESSION_LIST == mExpressionList->mType); + print_cil_func_expression_list((LLScriptFuncExpressionList*) mExpressionList, fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry /* Caller entry needed for is_parameter calls */, 0, NULL, mIdentifier->mScopeEntry /* Callee entry needed for argument casting */); } // Make call. if (! library_call) { - fprintf(fp, "callvirt instance "); + fprintf(fp, "call instance "); } else { @@ -7233,16 +7879,18 @@ void LLScriptFunctionCall::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom fprintf(fp, " class "); if (library_call) { - fprintf(fp, "[LScriptLibrary]LScriptLibrary"); + fprintf(fp, "[LslLibrary]LindenLab.SecondLife.Library::'"); } else { - fprintf(fp, "LSL"); + // Prefix function name with g to distinguish from + // event handlers. + fprintf(fp, gScriptp->getClassName()); + fprintf(fp, "::'g"); } - fprintf(fp, "::"); - mIdentifier->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "("); - if (mExpressionList) {print_cil_arg_list(fp, (LLScriptFuncExpressionList*) mExpressionList);} + fprintf(fp, mIdentifier->mName); + fprintf(fp, "'("); + print_cil_arg_list(fp, mIdentifier->mScopeEntry->mFunctionArgs); fprintf(fp, ")\n"); } break; @@ -7287,6 +7935,11 @@ void LLScriptPrint::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePas chunk->addByte(LSCRIPTOpCodes[LOPC_PRINT]); chunk->addByte(LSCRIPTTypeByte[mLeftType]); break; + case LSCP_EMIT_CIL_ASSEMBLY: + mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_cast(fp, mLeftType, LST_STRING); + fprintf(fp, "call void class [LslLibrary]LindenLab.SecondLife.Library::Print(string)"); + break; default: mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -7404,8 +8057,19 @@ void LLScriptStatementSequence::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRI mFirstp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); if (prunearg) { + // babbage: only warn on first dead code block found. + if(ptype != LSPRUNE_DEAD_CODE) + { + gErrorToText.writeWarning(fp, this, LSWARN_DEAD_CODE); + } + + // babbage: set prune type to LSPRUNE_DEAD_CODE to mask other + // prune errors. ptype = LSPRUNE_DEAD_CODE; - gErrorToText.writeWarning(fp, this, LSWARN_DEAD_CODE); + + // babbage: reset prunearg, to track whether return needed at + // end of dead code path as CIL always needs a return/throw. + prunearg = FALSE; } mSecondp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); break; @@ -7444,10 +8108,7 @@ void LLScriptNOOP::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass fprintf(fp, ";\n"); break; case LSCP_PRUNE: - if (ptype == LSPRUNE_DEAD_CODE) - prunearg = TRUE; - else - prunearg = FALSE; + prunearg = FALSE; break; default: break; @@ -7462,7 +8123,7 @@ void add_exit_pops(LLScriptByteCodeChunk *chunk, LLScriptScopeEntry *entry) if (entry->mLocals.mString) { - number = (S32)strlen(entry->mLocals.mString); /*Flawfinder: ignore*/ + number = (S32)strlen(entry->mLocals.mString); for (i = number - 1; i >= 0; i--) { switch(entry->mLocals.getType(i)) @@ -7495,7 +8156,7 @@ void add_exit_pops(LLScriptByteCodeChunk *chunk, LLScriptScopeEntry *entry) if (entry->mFunctionArgs.mString) { - number = (S32)strlen(entry->mFunctionArgs.mString); /*Flawfinder: ignore*/ + number = (S32)strlen(entry->mFunctionArgs.mString); for (i = number - 1; i >= 0; i--) { switch(entry->mFunctionArgs.getType(i)) @@ -7534,7 +8195,7 @@ void print_exit_pops(LLFILE *fp, LLScriptScopeEntry *entry) if (entry->mLocals.mString) { - number = (S32)strlen(entry->mLocals.mString); /*Flawfinder: ignore*/ + number = (S32)strlen(entry->mLocals.mString); for (i = number - 1; i >= 0; i--) { fprintf(fp, "%s", LSCRIPTTypePop[entry->mLocals.getType(i)]); @@ -7543,7 +8204,7 @@ void print_exit_pops(LLFILE *fp, LLScriptScopeEntry *entry) if (entry->mFunctionArgs.mString) { - number = (S32)strlen(entry->mFunctionArgs.mString); /*Flawfinder: ignore*/ + number = (S32)strlen(entry->mFunctionArgs.mString); for (i = number - 1; i >= 0; i--) { fprintf(fp, "%s", LSCRIPTTypePop[entry->mFunctionArgs.getType(i)]); @@ -7583,10 +8244,7 @@ void LLScriptStateChange::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp { gErrorToText.writeError(fp, this, LSERROR_STATE_CHANGE_IN_GLOBAL); } - if (ptype == LSPRUNE_DEAD_CODE) - prunearg = TRUE; - else - prunearg = FALSE; + prunearg = FALSE; break; case LSCP_SCOPE_PASS2: { @@ -7610,10 +8268,10 @@ void LLScriptStateChange::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp } break; case LSCP_EMIT_CIL_ASSEMBLY: - fprintf(fp, "ldstr \""); - mIdentifier->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "\"\n"); - fprintf(fp, "call void class [LScriptLibrary]LScriptInternal::change_state(string)\n"); + fprintf(fp, "ldarg.0\n"); + fprintf(fp, "ldstr \"%s\"\n", mIdentifier->mName); + fprintf(fp, "call instance void class [LslUserScript]LindenLab.SecondLife.LslUserScript::ChangeState(string)\n"); + fprintf(fp, "ret\n"); break; default: mIdentifier->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -7647,10 +8305,7 @@ void LLScriptJump::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass fprintf(fp, "\n"); break; case LSCP_PRUNE: - if (ptype == LSPRUNE_DEAD_CODE) - prunearg = TRUE; - else - prunearg = FALSE; + prunearg = FALSE; break; case LSCP_SCOPE_PASS2: { @@ -7820,6 +8475,10 @@ void LLScriptReturn::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa mType = basetype; } } + else if (basetype != LST_NULL) + { + gErrorToText.writeError(fp, this, LSERROR_TYPE_MISMATCH); + } break; case LSCP_EMIT_BYTE_CODE: if (mExpression) @@ -7863,6 +8522,7 @@ void LLScriptReturn::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa if (mExpression) { mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_cast(fp, mExpression->mReturnType, mType); } fprintf(fp, "ret\n"); break; @@ -7902,10 +8562,7 @@ void LLScriptExpressionStatement::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSC } break; case LSCP_PRUNE: - if (ptype == LSPRUNE_DEAD_CODE) - prunearg = TRUE; - else - prunearg = FALSE; + prunearg = FALSE; break; case LSCP_EMIT_BYTE_CODE: mExpression->recurse(fp, tabs, tabsize, LSCP_TO_STACK, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -7951,6 +8608,58 @@ S32 LLScriptIf::getSize() return 0; } +static void print_cil_if_test(LLFILE* fp, LSCRIPTType type) +{ + switch(type) + { + case LST_INTEGER: + break; + case LST_FLOATINGPOINT: + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "ceq\n"); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); + break; + case LST_VECTOR: + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32)\n"); + fprintf(fp, "call bool [LslUserScript]LindenLab.SecondLife.LslUserScript::'Equals'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector)\n"); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); + break; + case LST_QUATERNION: + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "ldc.r8 0\n"); + fprintf(fp, "ldc.r8 1\n"); + fprintf(fp, "call class [ScriptTypes]LindenLab.SecondLife.Quaternion class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateQuaternion'(float32, float32, float32, float32)\n"); + fprintf(fp, "call bool [LslUserScript]LindenLab.SecondLife.LslUserScript::'Equals'(class [ScriptTypes]LindenLab.SecondLife.Quaternion, class [ScriptTypes]LindenLab.SecondLife.Quaternion)\n"); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); + break; + case LST_KEY: + fprintf(fp, "call bool [LslUserScript]LindenLab.SecondLife.LslUserScript::'IsNonNullUuid'(valuetype [ScriptTypes]LindenLab.SecondLife.Key)\n"); + break; + case LST_STRING: + fprintf(fp, "ldstr \"\"\n"); + fprintf(fp, "call bool string::op_Equality(string, string)\n"); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); + break; + case LST_LIST: + fprintf(fp, "call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()\n"); + fprintf(fp, "call bool [LslUserScript]LindenLab.SecondLife.LslUserScript::Equals(class [mscorlib]System.Collections.ArrayList, class [mscorlib]System.Collections.ArrayList)\n"); + fprintf(fp, "ldc.i4.0\n"); + fprintf(fp, "ceq\n"); + break; + default: + break; + } + +} + void LLScriptIf::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -7976,10 +8685,7 @@ void LLScriptIf::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass p } break; case LSCP_PRUNE: - if (ptype == LSPRUNE_DEAD_CODE) - prunearg = TRUE; - else - prunearg = FALSE; + prunearg = FALSE; break; case LSCP_TYPE: mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -8004,6 +8710,7 @@ void LLScriptIf::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass p { S32 tjump = gTempJumpCount++; mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_if_test(fp, mExpression->mReturnType); fprintf(fp, "brfalse LabelTempJump%d\n", tjump); mStatement->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "LabelTempJump%d:\n", tjump); @@ -8093,6 +8800,7 @@ void LLScriptIfElse::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa S32 tjump1 = gTempJumpCount++; S32 tjump2 = gTempJumpCount++; mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_if_test(fp, mExpression->mReturnType); fprintf(fp, "brfalse LabelTempJump%d\n", tjump1); mStatement1->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "br LabelTempJump%d\n", tjump2); @@ -8155,10 +8863,7 @@ void LLScriptFor::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass } break; case LSCP_PRUNE: - if (ptype == LSPRUNE_DEAD_CODE) - prunearg = TRUE; - else - prunearg = FALSE; + prunearg = FALSE; break; case LSCP_TYPE: if(mSequence) @@ -8203,6 +8908,7 @@ void LLScriptFor::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass mSequence->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "LabelTempJump%d:\n", tjump1); mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_if_test(fp, mExpression->mReturnType); fprintf(fp, "brfalse LabelTempJump%d\n", tjump2); if(mStatement) mStatement->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -8257,10 +8963,7 @@ void LLScriptDoWhile::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompileP } break; case LSCP_PRUNE: - if (ptype == LSPRUNE_DEAD_CODE) - prunearg = TRUE; - else - prunearg = FALSE; + prunearg = FALSE; break; case LSCP_TYPE: mStatement->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -8287,6 +8990,7 @@ void LLScriptDoWhile::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompileP fprintf(fp, "LabelTempJump%d:\n", tjump1); mStatement->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_if_test(fp, mExpression->mReturnType); fprintf(fp, "brtrue LabelTempJump%d\n", tjump1); } break; @@ -8331,10 +9035,7 @@ void LLScriptWhile::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePas } break; case LSCP_PRUNE: - if (ptype == LSPRUNE_DEAD_CODE) - prunearg = TRUE; - else - prunearg = FALSE; + prunearg = FALSE; break; case LSCP_TYPE: mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -8367,6 +9068,7 @@ void LLScriptWhile::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePas S32 tjump2 = gTempJumpCount++; fprintf(fp, "LabelTempJump%d:\n", tjump1); mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + print_cil_if_test(fp, mExpression->mReturnType); fprintf(fp, "brfalse LabelTempJump%d\n", tjump2); mStatement->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, "br LabelTempJump%d\n", tjump1); @@ -8429,10 +9131,7 @@ void LLScriptDeclaration::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp } break; case LSCP_PRUNE: - if (ptype == LSPRUNE_DEAD_CODE) - prunearg = TRUE; - else - prunearg = FALSE; + prunearg = FALSE; break; case LSCP_SCOPE_PASS1: // Check to see if a declaration is valid here. @@ -8604,24 +9303,13 @@ void LLScriptDeclaration::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp if (mExpression) { mExpression->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - if (mIdentifier->mScopeEntry->mIDType == LIT_VARIABLE) - { - if(is_parameter(mIdentifier, entry)) - { - // Parameter, store by name. - fprintf(fp, "starg.s %s\n", mIdentifier->mScopeEntry->mIdentifier); - } - else - { - // Local, store by index. - fprintf(fp, "stloc.s %d\n", mIdentifier->mScopeEntry->mCount); - } - } - else if (mIdentifier->mScopeEntry->mIDType == LIT_GLOBAL) - { - gErrorToText.writeError(fp, this, LSERROR_UNDEFINED_NAME); - } + print_cil_cast(fp, mExpression->mReturnType, mIdentifier->mScopeEntry->mType); + } + else + { + print_cil_init_variable(fp, mIdentifier->mScopeEntry->mType); } + fprintf(fp, "stloc.s %d\n", mIdentifier->mScopeEntry->mCount); break; default: if (mExpression) @@ -8751,7 +9439,7 @@ S32 LLScriptEventHandler::getSize() U64 gCurrentHandler = 0; -void print_cil_local_init(LLFILE* fp, LLScriptScopeEntry* scopeEntry) +static void print_cil_local_init(LLFILE* fp, LLScriptScopeEntry* scopeEntry) { if(scopeEntry->mLocals.getNumber() > 0) { @@ -8956,6 +9644,10 @@ void LLScriptEventHandler::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom // first determine resource counts for globals count = 0; mEventp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + + // Store offset of first local as with global functions, so locals and arguments can be distinguished with is_parameter when compiling to CIL. + mScopeEntry->mOffset = (S32) count; + if (mStatement) { entrycount = 0; @@ -9024,8 +9716,11 @@ void LLScriptEventHandler::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom // Method signature prefix. fprintf(fp, ".method public hidebysig instance default void "); - // Mangle event handler name by prefixing it with state name. Allows state changing by finding handlers prefixed with new state name. - fprintf(fp, entry->mIdentifier); /*Flawfinder: ignore*/ + // Mangle event handler name by prefixing it with state name. + // Allows state changing by finding handlers prefixed with new + // state name. Prefix disambiguates functions and event handlers. + fprintf(fp, "e"); + fprintf(fp, entry->mIdentifier); // Handler name and arguments. mEventp->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -9047,7 +9742,11 @@ void LLScriptEventHandler::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom } // Function footer. - fprintf(fp, "\nret\n"); // TODO: Check whether return needed? + if (mbNeedTrailingReturn) + { + // TODO: throw exception? + fprintf(fp, "ret\n"); + } fprintf(fp, "}\n"); break; @@ -9161,7 +9860,7 @@ void LLScriptFunctionDec::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp chunk->addBytes(&typereturn, 1); // name #ifdef LSL_INCLUDE_DEBUG_INFO - chunk->addBytes(mIdentifier->mName, strlen(mIdentifier->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(mIdentifier->mName, strlen(mIdentifier->mName) + 1); #else chunk->addBytes(1); #endif @@ -9176,6 +9875,10 @@ void LLScriptFunctionDec::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp mType->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); fprintf(fp, " "); mIdentifier->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + if(NULL != mNextp) + { + fprintf(fp, ","); + } break; default: mType->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); @@ -9398,7 +10101,7 @@ void LLScriptGlobalFunctions::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPT // null terminated function name #ifdef LSL_INCLUDE_DEBUG_INFO - chunk->addBytes(mIdentifier->mName, strlen(mIdentifier->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(mIdentifier->mName, strlen(mIdentifier->mName) + 1); #else chunk->addBytes(1); #endif @@ -9444,11 +10147,13 @@ void LLScriptGlobalFunctions::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPT break; case LSCP_EMIT_CIL_ASSEMBLY: { - // Function header. + // Function header. Prefix function name with g to distinguish + // from event handlers. fprintf(fp, ".method public hidebysig instance default "); print_cil_type(fp, mType ? mType->mType : LST_NULL); - fprintf(fp, " "); - mIdentifier->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " 'g"); + fprintf(fp, mIdentifier->mName); + fprintf(fp, "'"); if (mParameters) { fprintf(fp, "( "); @@ -9473,6 +10178,7 @@ void LLScriptGlobalFunctions::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPT // Function footer. if (mbNeedTrailingReturn) { + // TODO: throw exception? fprintf(fp, "ret\n"); } fprintf(fp, "}\n"); @@ -9587,10 +10293,12 @@ void LLScriptState::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePas { mIdentifier->mScopeEntry = scope->addEntry(mIdentifier->mName, LIT_STATE, LST_NULL); } + mStateScope = new LLScriptScope(gScopeStringTable); + mStateScope->addParentScope(scope); // now do the events if (mEvent) { - mEvent->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + mEvent->recurse(fp, tabs, tabsize, pass, ptype, prunearg, mStateScope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); } break; case LSCP_SCOPE_PASS2: @@ -9649,7 +10357,7 @@ void LLScriptState::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePas // null terminated state name #ifdef LSL_INCLUDE_DEBUG_INFO - chunk->addBytes(mIdentifier->mName, strlen(mIdentifier->mName) + 1); /*Flawfinder: ignore*/ + chunk->addBytes(mIdentifier->mName, strlen(mIdentifier->mName) + 1); #else chunk->addBytes(1); #endif @@ -9693,6 +10401,38 @@ void LLScriptState::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePas gonext(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); } +// Converts string to a valid CIL class name and stores the result +// in the supplied buffer, which should be at least 32 chars long. +// If the string starts with a UUID, all characters in the UUID are included +// in the generated name. +void to_class_name(char* buffer, const char* string) +{ + strcpy(buffer, "LSL-"); + strcat(buffer, string); + char* current_char = buffer; + while((*current_char) != 0) + { + if(isalnum(*current_char)) + { + ++current_char; + } + else if((*current_char) == '-') + { + (*current_char) = '_'; + ++current_char; + } + else + { + (*current_char) = 0; + } + } +} + +void LLScriptScript::setClassName(const char* class_name) +{ + to_class_name(mClassName, class_name); +} + S32 LLScriptScript::getSize() { return 0; @@ -9704,6 +10444,7 @@ LLScriptScript::LLScriptScript(LLScritpGlobalStorage *globals, mStates(states), mGlobalScope(NULL), mGlobals(NULL), mGlobalFunctions(NULL), mGodLike(FALSE) { const char DEFAULT_BYTECODE_FILENAME[] = "lscript.lso"; + mBytecodeDest = DEFAULT_BYTECODE_FILENAME; LLScriptGlobalVariable *tvar; LLScriptGlobalFunctions *tfunc; @@ -9753,13 +10494,11 @@ void LLScriptScript::setBytecodeDest(const char* dst_filename) mBytecodeDest = ll_safe_string(dst_filename); } -void print_cil_globals(LLFILE* fp, LLScriptGlobalVariable* global) +static void print_cil_globals(LLFILE* fp, LLScriptGlobalVariable* global) { - fprintf(fp, ".field private "); + fprintf(fp, ".field public "); print_cil_type(fp, global->mType->mType); - fprintf(fp, " "); - fprintf(fp, global->mIdentifier->mName); /*Flawfinder: ignore*/ - fprintf(fp, "\n"); + fprintf(fp, " '%s'\n", global->mIdentifier->mName); if(NULL != global->mNextp) { print_cil_globals(fp, global->mNextp); @@ -9946,72 +10685,66 @@ void LLScriptScript::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa } break; case LSCP_EMIT_CIL_ASSEMBLY: + { + LLFILE *bcfp = LLFile::fopen(mBytecodeDest, "wb"); - // Output dependencies. - fprintf(fp, ".assembly extern mscorlib {.ver 1:0:5000:0}\n"); - fprintf(fp, ".assembly extern LScriptLibrary {.ver 0:0:0:0}\n"); + // Output dependencies. + fprintf(bcfp, ".assembly extern mscorlib {.ver 1:0:5000:0}\n"); + fprintf(bcfp, ".assembly extern LslLibrary {.ver 0:1:0:0}\n"); + fprintf(bcfp, ".assembly extern LslUserScript {.ver 0:1:0:0}\n"); + fprintf(bcfp, ".assembly extern ScriptTypes {.ver 0:1:0:0}\n"); - // Output assembly name. - fprintf(fp, ".assembly 'lsl' {.ver 0:0:0:0}\n"); + // Output assembly name. + fprintf(bcfp, ".assembly '%s' {.ver 0:0:0:0}\n", gScriptp->getClassName()); - // Output class header. - fprintf(fp, ".class public auto ansi beforefieldinit LSL extends [mscorlib]System.Object\n"); - fprintf(fp, "{\n"); + // Output class header. + fprintf(bcfp, ".class public auto ansi serializable beforefieldinit %s extends [LslUserScript]LindenLab.SecondLife.LslUserScript\n", gScriptp->getClassName()); + fprintf(bcfp, "{\n"); - // Output globals as members. - if(NULL != mGlobals) - { - print_cil_globals(fp, mGlobals); - } - - // Output "runtime". Only needed to allow stand alone execution. Not needed when compiling to DLL and using embedded runtime. - fprintf(fp, ".method public static hidebysig default void Main () cil managed\n"); - fprintf(fp, "{\n"); - fprintf(fp, ".entrypoint\n"); - fprintf(fp, ".maxstack 2\n"); - fprintf(fp, ".locals init (class LSL V_0)\n"); - fprintf(fp, "newobj instance void class LSL::.ctor()\n"); - fprintf(fp, "stloc.0\n"); - fprintf(fp, "ldloc.0\n"); - fprintf(fp, "callvirt instance void class LSL::defaultstate_entry()\n"); - fprintf(fp, "ret\n"); - fprintf(fp, "}\n"); + // Output globals as members. + if(NULL != mGlobals) + { + print_cil_globals(bcfp, mGlobals); + } - // Output ctor header. - fprintf(fp, ".method public hidebysig specialname rtspecialname instance default void .ctor () cil managed\n"); - fprintf(fp, "{\n"); - fprintf(fp, ".maxstack 500\n"); + // Output ctor header. + fprintf(bcfp, ".method public hidebysig specialname rtspecialname instance default void .ctor () cil managed\n"); + fprintf(bcfp, "{\n"); + fprintf(bcfp, ".maxstack 500\n"); - // Initialise globals as members in ctor. - if (mGlobals) - { - fdotabs(fp, tabs, tabsize); - mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "\n"); - } + // Initialise globals as members in ctor. + if (mGlobals) + { + fdotabs(bcfp, tabs, tabsize); + mGlobals->recurse(bcfp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(bcfp, "\n"); + } - // Output ctor footer. - fprintf(fp, "ldarg.0\n"); - fprintf(fp, "call instance void valuetype [mscorlib]System.Object::.ctor()\n"); - fprintf(fp, "ret\n"); - fprintf(fp, "}\n"); + // Output ctor footer. + fprintf(bcfp, "ldarg.0\n"); + fprintf(bcfp, "call instance void [LslUserScript]LindenLab.SecondLife.LslUserScript::.ctor()\n"); + fprintf(bcfp, "ret\n"); + fprintf(bcfp, "}\n"); - // Output functions as methods. - if (mGlobalFunctions) - { - fdotabs(fp, tabs, tabsize); - mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "\n"); - } + // Output functions as methods. + if (mGlobalFunctions) + { + fdotabs(bcfp, tabs, tabsize); + mGlobalFunctions->recurse(bcfp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(bcfp, "\n"); + } - // Output states as name mangled methods. - fdotabs(fp, tabs, tabsize); - mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); - fprintf(fp, "\n"); + // Output states as name mangled methods. + fdotabs(bcfp, tabs, tabsize); + mStates->recurse(bcfp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(bcfp, "\n"); - // Output class footer. - fprintf(fp, "}\n"); + // Output class footer. + fprintf(bcfp, "}\n"); + // Close file. + fclose(bcfp); + } break; default: if (mGlobals) diff --git a/indra/lscript/lscript_compile/lscript_tree.h b/indra/lscript/lscript_compile/lscript_tree.h index 4c25c097d8..57228dd24c 100644 --- a/indra/lscript/lscript_compile/lscript_tree.h +++ b/indra/lscript/lscript_compile/lscript_tree.h @@ -2197,11 +2197,11 @@ public: void recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata); S32 getSize(); - LSCRIPTStateType mType; - LLScriptIdentifier *mIdentifier; - LLScriptEventHandler *mEvent; - LLScriptState *mNextp; - + LSCRIPTStateType mType; + LLScriptIdentifier *mIdentifier; + LLScriptEventHandler *mEvent; + LLScriptState *mNextp; + LLScriptScope *mStateScope; }; class LLScritpGlobalStorage : public LLScriptFilePosition @@ -2262,6 +2262,9 @@ public: void setBytecodeDest(const char* dst_filename); + void setClassName(const char* class_name); + const char* getClassName() {return mClassName;} + LLScriptState *mStates; LLScriptScope *mGlobalScope; LLScriptGlobalVariable *mGlobals; @@ -2270,6 +2273,7 @@ public: private: std::string mBytecodeDest; + char mClassName[MAX_STRING]; }; class LLScriptAllocationManager diff --git a/indra/lscript/lscript_compile/lscript_typecheck.cpp b/indra/lscript/lscript_compile/lscript_typecheck.cpp index 1030e8c70d..bfa5a66c7b 100644 --- a/indra/lscript/lscript_compile/lscript_typecheck.cpp +++ b/indra/lscript/lscript_compile/lscript_typecheck.cpp @@ -66,7 +66,13 @@ LSCRIPTType implicit_casts(LSCRIPTType left_side, LSCRIPTType right_side) { // shouldn't be doing an operation on void types case LST_NULL: - return LST_NULL; + switch(right_side) + { + case LST_NULL: + return LST_NULL; + default: + return LST_UNDEFINED; + } // shouldn't be doing an operation on undefined types case LST_UNDEFINED: return LST_UNDEFINED; diff --git a/indra/lscript/lscript_execute.h b/indra/lscript/lscript_execute.h index dd1aa97e71..f46256eb5e 100644 --- a/indra/lscript/lscript_execute.h +++ b/indra/lscript/lscript_execute.h @@ -367,20 +367,158 @@ public: class LLScriptExecute { public: - LLScriptExecute(LLFILE *fp); - LLScriptExecute(U8 *buffer); - ~LLScriptExecute(); + LLScriptExecute(); + virtual ~LLScriptExecute() {;} + + virtual S32 getVersion() = 0; + virtual void deleteAllEvents() = 0; + virtual void addEvent(LLScriptDataCollection* event) = 0; + virtual U32 getEventCount() = 0; + virtual void removeEventType(LSCRIPTStateEventType event_type) = 0; + virtual S32 getFaults() = 0; + virtual void setFault(LSCRIPTRunTimeFaults fault) = 0; + virtual U32 getFreeMemory() = 0; + virtual S32 getParameter() = 0; + virtual void setParameter(S32 value) = 0; + virtual F32 getSleep() const = 0; + virtual void setSleep(F32 value) = 0; + virtual F32 getEnergy() const = 0; + virtual void setEnergy(F32 value) = 0; + virtual U64 getCurrentEvents(S32 version) = 0; + virtual void setCurrentEvents(U64 value, S32 version) = 0; + virtual U64 getEventHandlers(S32 version) = 0; + virtual void setEventHandlers(U64 value, S32 version) = 0; + virtual U64 getCurrentHandler(S32 version) = 0; + virtual void setCurrentHandler(U64 value, S32 version) = 0; + virtual BOOL isFinished() const = 0; + virtual BOOL isStateChangePending() const = 0; + virtual S32 writeState(U8 **dest, U32 header_size, U32 footer_size) = 0; // Allocate memory for header, state and footer return size of state. + virtual U32 getEventsSavedSize() = 0; // Returns 0 if events are written with state. + virtual S32 writeEvents(U8 *dest) = 0; // Must write and return exactly the number of bytes returned by getEventsSavedSize. + virtual void readEvents(U8* src, S32& offset) = 0; + virtual S32 readState(U8 *src) = 0; // Returns number of bytes read. + virtual void reset(); + virtual const U8* getBytecode() const = 0; + virtual U32 getBytecodeSize() const = 0; + virtual bool isMono() const = 0; + virtual void error() {;} // Processing that must be performed when error flag is set and so run is not called. + + // Run current event handler for a maximum of time_slice seconds. + // Updates current handler and current events registers. + virtual void resumeEventHandler(BOOL b_print, const LLUUID &id, F32 time_slice) = 0; + + // Run handler for event for a maximum of time_slice seconds. + // Updates current handler and current events registers. + virtual void callEventHandler(LSCRIPTStateEventType event, S32 major_version, const LLUUID &id, F32 time_slice) = 0;; + + // Run handler for next queued event for maximum of time_slice seconds. + // Updates current handler and current events registers. + // Removes processed event from queue. + virtual void callNextQueuedEventHandler(U64 event_register, S32 major_version, const LLUUID &id, F32 time_slice) = 0; + + // Run handler for event for a maximum of time_slice seconds. + // Updates current handler and current events registers. + // Removes processed event from queue. + virtual void callQueuedEventHandler(LSCRIPTStateEventType event, S32 major_version, const LLUUID &id, F32 time_slice) = 0; + + // Switch to next state. + // Returns new set of handled events. + virtual U64 nextState() = 0; + + // Returns time taken. + virtual F32 runQuanta(BOOL b_print, const LLUUID &id, + const char **errorstr, + BOOL &state_transition, F32 quanta, + U32& events_processed, LLTimer& timer); + + // Run smallest possible amount of code: an instruction for LSL2, a segment + // between save tests for Mono + void runInstructions(BOOL b_print, const LLUUID &id, + const char **errorstr, + BOOL &state_transition, U32& events_processed, + F32 quanta); + + bool isYieldDue() const; + + void setReset(BOOL b) {mReset = b;} + BOOL getReset() const { return mReset; } + +private: + + BOOL mReset; +}; + +class LLScriptExecuteLSL2 : public LLScriptExecute +{ +public: + LLScriptExecuteLSL2(LLFILE *fp); + LLScriptExecuteLSL2(const U8* bytecode, U32 bytecode_size); + virtual ~LLScriptExecuteLSL2(); + + virtual S32 getVersion() {return get_register(mBuffer, LREG_VN);} + virtual void deleteAllEvents() {mEventData.mEventDataList.deleteAllData();} + virtual void addEvent(LLScriptDataCollection* event); + virtual U32 getEventCount() {return mEventData.mEventDataList.getLength();} + virtual void removeEventType(LSCRIPTStateEventType event_type); + virtual S32 getFaults() {return get_register(mBuffer, LREG_FR);} + virtual void setFault(LSCRIPTRunTimeFaults fault) {set_fault(mBuffer, fault);} + virtual U32 getFreeMemory(); + virtual S32 getParameter(); + virtual void setParameter(S32 value); + virtual F32 getSleep() const; + virtual void setSleep(F32 value); + virtual F32 getEnergy() const; + virtual void setEnergy(F32 value); + virtual U64 getCurrentEvents(S32 version) {return get_event_register(mBuffer, LREG_CE, version);} + virtual void setCurrentEvents(U64 value, S32 version) {return set_event_register(mBuffer, LREG_CE, value, version);} + virtual U64 getEventHandlers(S32 version) {return get_event_register(mBuffer, LREG_ER, version);} + virtual void setEventHandlers(U64 value, S32 version) {set_event_register(mBuffer, LREG_ER, value, version);} + virtual U64 getCurrentHandler(S32 version); + virtual void setCurrentHandler(U64 value, S32 version) {return set_event_register(mBuffer, LREG_IE, value, version);} + virtual BOOL isFinished() const {return get_register(mBuffer, LREG_IP) == 0;} + virtual BOOL isStateChangePending() const {return get_register(mBuffer, LREG_CS) != get_register(mBuffer, LREG_NS);} + virtual S32 writeState(U8 **dest, U32 header_size, U32 footer_size); // Not including Events. + virtual U32 getEventsSavedSize() {return mEventData.getSavedSize();} + virtual S32 writeEvents(U8 *dest) {return mEventData.write2bytestream(dest);} + virtual void readEvents(U8* src, S32& offset) {mEventData.set(src, offset);} + virtual S32 writeBytecode(U8 **dest); + virtual S32 readState(U8 *src); + virtual void reset(); + virtual const U8* getBytecode() const {return mBytecode;} + virtual U32 getBytecodeSize() const {return mBytecodeSize;} + virtual bool isMono() const {return false;} + + // Run current event handler for a maximum of time_slice seconds. + // Updates current handler and current events registers. + virtual void resumeEventHandler(BOOL b_print, const LLUUID &id, F32 time_slice); + + // Run handler for event for a maximum of time_slice seconds. + // Updates current handler and current events registers. + virtual void callEventHandler(LSCRIPTStateEventType event, S32 major_version, const LLUUID &id, F32 time_slice); + + // Run handler for next queued event for maximum of time_slice seconds. + // Updates current handler and current events registers. + // Removes processed event from queue. + virtual void callNextQueuedEventHandler(U64 event_register, S32 major_version, const LLUUID &id, F32 time_slice); + + // Run handler for event for a maximum of time_slice seconds. + // Updates current handler and current events registers. + // Removes processed event from queue. + virtual void callQueuedEventHandler(LSCRIPTStateEventType event, S32 major_version, const LLUUID &id, F32 time_slice); + + // Switch to next state. + // Returns new set of handled events. + virtual U64 nextState(); void init(); - U32 run(BOOL b_print, const LLUUID &id, const char **errorstr, BOOL &state_transition); BOOL (*mExecuteFuncs[0x100])(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id); U32 mInstructionCount; U8 *mBuffer; LLScriptEventData mEventData; - - static S64 sGlobalInstructionCount; + U8* mBytecode; // Initial state and bytecode. + U32 mBytecodeSize; private: void recordBoundaryError( const LLUUID &id ); diff --git a/indra/lscript/lscript_execute/lscript_execute.cpp b/indra/lscript/lscript_execute/lscript_execute.cpp index aa73025b7f..e863c1668e 100644 --- a/indra/lscript/lscript_execute/lscript_execute.cpp +++ b/indra/lscript/lscript_execute/lscript_execute.cpp @@ -31,6 +31,7 @@ #include "linden_common.h" +#include <algorithm> #include <sstream> #include "lscript_execute.h" @@ -45,7 +46,7 @@ void (*unary_operations[LST_EOF])(U8 *buffer, LSCRIPTOpCodesEnum opcode); const char* LSCRIPTRunTimeFaultStrings[LSRF_EOF] = /*Flawfinder: ignore*/ { - "invalid", // LSRF_INVALID, + "Invalid", // LSRF_INVALID, "Math Error", // LSRF_MATH, "Stack-Heap Collision", // LSRF_STACK_HEAP_COLLISION, "Bounds Check Error", // LSRF_BOUND_CHECK_ERROR, @@ -55,13 +56,11 @@ const char* LSCRIPTRunTimeFaultStrings[LSRF_EOF] = /*Flawfinder: ignore*/ "Hit Sandbox Limit", // LSRF_SANDBOX, "Chat Overrun", // LSRF_CHAT_OVERRUN, "Too Many Listens", // LSRF_TOO_MANY_LISTENS, - "Lists may not contain lists" // LSRF_NESTING_LISTS, + "Lists may not contain lists", // LSRF_NESTING_LISTS, + "CLI Exception" // LSRF_CLI }; -//static -S64 LLScriptExecute::sGlobalInstructionCount = 0; - -LLScriptExecute::LLScriptExecute(LLFILE *fp) +LLScriptExecuteLSL2::LLScriptExecuteLSL2(LLFILE *fp) { U8 sizearray[4]; S32 filesize; @@ -84,19 +83,26 @@ LLScriptExecute::LLScriptExecute(LLFILE *fp) init(); } -LLScriptExecute::LLScriptExecute(U8 *buffer) +LLScriptExecuteLSL2::LLScriptExecuteLSL2(const U8* bytecode, U32 bytecode_size) { - mBuffer = buffer; - + mBuffer = new U8[TOP_OF_MEMORY]; + memset(mBuffer + bytecode_size, 0, TOP_OF_MEMORY - bytecode_size); + S32 src_offset = 0; + S32 dest_offset = 0; + bytestream2bytestream(mBuffer, dest_offset, bytecode, src_offset, bytecode_size); + mBytecodeSize = bytecode_size; + mBytecode = new U8[mBytecodeSize]; + memcpy(mBytecode, bytecode, mBytecodeSize); init(); } -LLScriptExecute::~LLScriptExecute() +LLScriptExecuteLSL2::~LLScriptExecuteLSL2() { - delete [] mBuffer; + delete[] mBuffer; + delete[] mBytecode; } -void LLScriptExecute::init() +void LLScriptExecuteLSL2::init() { S32 i, j; @@ -270,7 +276,7 @@ void LLScriptExecute::init() // Utility routine for when there's a boundary error parsing bytecode -void LLScriptExecute::recordBoundaryError( const LLUUID &id ) +void LLScriptExecuteLSL2::recordBoundaryError( const LLUUID &id ) { set_fault(mBuffer, LSRF_BOUND_CHECK_ERROR); llwarns << "Script boundary error for ID " << id << llendl; @@ -278,7 +284,7 @@ void LLScriptExecute::recordBoundaryError( const LLUUID &id ) // set IP to the event handler with some error checking -void LLScriptExecute::setStateEventOpcoodeStartSafely( S32 state, LSCRIPTStateEventType event, const LLUUID &id ) +void LLScriptExecuteLSL2::setStateEventOpcoodeStartSafely( S32 state, LSCRIPTStateEventType event, const LLUUID &id ) { S32 opcode_start = get_state_event_opcoode_start( mBuffer, state, event ); if ( opcode_start == -1 ) @@ -296,12 +302,474 @@ void LLScriptExecute::setStateEventOpcoodeStartSafely( S32 state, LSCRIPTStateEv S32 lscript_push_variable(LLScriptLibData *data, U8 *buffer); -U32 LLScriptExecute::run(BOOL b_print, const LLUUID &id, const char **errorstr, BOOL &state_transition) +void LLScriptExecuteLSL2::resumeEventHandler(BOOL b_print, const LLUUID &id, F32 time_slice) +{ + // call opcode run function pointer with buffer and IP + mInstructionCount++; + S32 value = get_register(mBuffer, LREG_IP); + S32 tvalue = value; + S32 opcode = safe_instruction_bytestream2byte(mBuffer, tvalue); + mExecuteFuncs[opcode](mBuffer, value, b_print, id); + set_ip(mBuffer, value); + add_register_fp(mBuffer, LREG_ESR, -0.1f); + // lsa_print_heap(mBuffer); + + if (b_print) + { + lsa_print_heap(mBuffer); + printf("ip: 0x%X\n", get_register(mBuffer, LREG_IP)); + printf("sp: 0x%X\n", get_register(mBuffer, LREG_SP)); + printf("bp: 0x%X\n", get_register(mBuffer, LREG_BP)); + printf("hr: 0x%X\n", get_register(mBuffer, LREG_HR)); + printf("hp: 0x%X\n", get_register(mBuffer, LREG_HP)); + } + + // NOTE: Babbage: all mExecuteFuncs return false. +} + +void LLScriptExecuteLSL2::callEventHandler(LSCRIPTStateEventType event, S32 major_version, const LLUUID &id, F32 time_slice) +{ + // push a zero to be popped + lscript_push(mBuffer, 0); + // push sp as current bp + S32 sp = get_register(mBuffer, LREG_SP); + lscript_push(mBuffer, sp); + + // Update current handler and current events registers. + set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); + U64 current_events = get_event_register(mBuffer, LREG_CE, major_version); + current_events &= ~LSCRIPTStateBitField[event]; + set_event_register(mBuffer, LREG_CE, current_events, major_version); + + // now, push any additional stack space + U32 current_state = get_register(mBuffer, LREG_CS); + S32 additional_size = get_event_stack_size(mBuffer, current_state, event); + lscript_pusharge(mBuffer, additional_size); + + // now set the bp correctly + sp = get_register(mBuffer, LREG_SP); + sp += additional_size; + set_bp(mBuffer, sp); + + // set IP to the function + S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, event); + set_ip(mBuffer, opcode_start); +} + +//void callStateExitHandler() +//{ +// // push a zero to be popped +// lscript_push(mBuffer, 0); +// // push sp as current bp +// S32 sp = get_register(mBuffer, LREG_SP); +// lscript_push(mBuffer, sp); +// +// // now, push any additional stack space +// S32 additional_size = get_event_stack_size(mBuffer, current_state, LSTT_STATE_EXIT); +// lscript_pusharge(mBuffer, additional_size); +// +// sp = get_register(mBuffer, LREG_SP); +// sp += additional_size; +// set_bp(mBuffer, sp); +// +// // set IP to the event handler +// S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, LSTT_STATE_EXIT); +// set_ip(mBuffer, opcode_start); +//} +// +//void callStateEntryHandler() +//{ +// // push a zero to be popped +// lscript_push(mBuffer, 0); +// // push sp as current bp +// S32 sp = get_register(mBuffer, LREG_SP); +// lscript_push(mBuffer, sp); +// +// event = return_first_event((S32)LSCRIPTStateBitField[LSTT_STATE_ENTRY]); +// set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); +// current_events &= ~LSCRIPTStateBitField[event]; +// set_event_register(mBuffer, LREG_CE, current_events, major_version); +// +// // now, push any additional stack space +// S32 additional_size = get_event_stack_size(mBuffer, current_state, event) - size; +// lscript_pusharge(mBuffer, additional_size); +// +// // now set the bp correctly +// sp = get_register(mBuffer, LREG_SP); +// sp += additional_size + size; +// set_bp(mBuffer, sp); +// // set IP to the function +// S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, event); +// set_ip(mBuffer, opcode_start); +//} + +void LLScriptExecuteLSL2::callQueuedEventHandler(LSCRIPTStateEventType event, S32 major_version, const LLUUID &id, F32 time_slice) +{ + LLScriptDataCollection* eventdata; + + for (eventdata = mEventData.mEventDataList.getFirstData(); eventdata; eventdata = mEventData.mEventDataList.getNextData()) + { + if (eventdata->mType == event) + { + // push a zero to be popped + lscript_push(mBuffer, 0); + // push sp as current bp + S32 sp = get_register(mBuffer, LREG_SP); + lscript_push(mBuffer, sp); + + // Update current handler and current events registers. + set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); + U64 current_events = get_event_register(mBuffer, LREG_CE, major_version); + current_events &= ~LSCRIPTStateBitField[event]; + set_event_register(mBuffer, LREG_CE, current_events, major_version); + + // push any arguments that need to be pushed onto the stack + // last piece of data will be type LST_NULL + LLScriptLibData *data = eventdata->mData; + U32 size = 0; + while (data->mType) + { + size += lscript_push_variable(data, mBuffer); + data++; + } + // now, push any additional stack space + U32 current_state = get_register(mBuffer, LREG_CS); + S32 additional_size = get_event_stack_size(mBuffer, current_state, event) - size; + lscript_pusharge(mBuffer, additional_size); + + // now set the bp correctly + sp = get_register(mBuffer, LREG_SP); + sp += additional_size + size; + set_bp(mBuffer, sp); + + // set IP to the function + S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, event); + set_ip(mBuffer, opcode_start); + + mEventData.mEventDataList.deleteCurrentData(); + break; + } + } +} + +void LLScriptExecuteLSL2::callNextQueuedEventHandler(U64 event_register, S32 major_version, const LLUUID &id, F32 time_slice) +{ + LLScriptDataCollection* eventdata = mEventData.getNextEvent(); + if (eventdata) + { + LSCRIPTStateEventType event = eventdata->mType; + + // make sure that we can actually handle this one + if (LSCRIPTStateBitField[event] & event_register) + { + // push a zero to be popped + lscript_push(mBuffer, 0); + // push sp as current bp + S32 sp = get_register(mBuffer, LREG_SP); + lscript_push(mBuffer, sp); + + // Update current handler and current events registers. + set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); + U64 current_events = get_event_register(mBuffer, LREG_CE, major_version); + current_events &= ~LSCRIPTStateBitField[event]; + set_event_register(mBuffer, LREG_CE, current_events, major_version); + + // push any arguments that need to be pushed onto the stack + // last piece of data will be type LST_NULL + LLScriptLibData *data = eventdata->mData; + U32 size = 0; + while (data->mType) + { + size += lscript_push_variable(data, mBuffer); + data++; + } + + // now, push any additional stack space + U32 current_state = get_register(mBuffer, LREG_CS); + S32 additional_size = get_event_stack_size(mBuffer, current_state, event) - size; + lscript_pusharge(mBuffer, additional_size); + + // now set the bp correctly + sp = get_register(mBuffer, LREG_SP); + sp += additional_size + size; + set_bp(mBuffer, sp); + + // set IP to the function + S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, event); + set_ip(mBuffer, opcode_start); + } + else + { + llwarns << "Shit, somehow got an event that we're not registered for!" << llendl; + } + delete eventdata; + } +} + +U64 LLScriptExecuteLSL2::nextState() +{ + // copy NS to CS + S32 next_state = get_register(mBuffer, LREG_NS); + set_register(mBuffer, LREG_CS, next_state); + + // copy new state's handled events into ER (SR + CS*4 + 4) + return get_handled_events(mBuffer, next_state); +} + +//virtual +void LLScriptExecuteLSL2::addEvent(LLScriptDataCollection* event) +{ + mEventData.addEventData(event); +} + +//virtual +void LLScriptExecuteLSL2::removeEventType(LSCRIPTStateEventType event_type) +{ + mEventData.removeEventType(event_type); +} + +//virtual +F32 LLScriptExecuteLSL2::getSleep() const +{ + return get_register_fp(mBuffer, LREG_SLR); +} + +//virtual +void LLScriptExecuteLSL2::setSleep(F32 value) +{ + set_register_fp(mBuffer, LREG_SLR, value); +} + +//virtual +U64 LLScriptExecuteLSL2::getCurrentHandler(S32 version) +{ + return get_event_register(mBuffer, LREG_IE, version); +} + +//virtual +F32 LLScriptExecuteLSL2::getEnergy() const +{ + return get_register_fp(mBuffer, LREG_ESR); +} + +//virtual +void LLScriptExecuteLSL2::setEnergy(F32 value) +{ + set_register_fp(mBuffer, LREG_ESR, value); +} + +//virtual +U32 LLScriptExecuteLSL2::getFreeMemory() +{ + return get_register(mBuffer, LREG_SP) - get_register(mBuffer, LREG_HP); +} + +//virtual +S32 LLScriptExecuteLSL2::getParameter() +{ + return get_register(mBuffer, LREG_PR); +} + +//virtual +void LLScriptExecuteLSL2::setParameter(S32 value) +{ + set_register(mBuffer, LREG_PR, value); +} + + +S32 LLScriptExecuteLSL2::writeState(U8 **dest, U32 header_size, U32 footer_size) +{ + // data format: + // 4 bytes of size of Registers, Name and Description, and Global Variables + // Registers, Name and Description, and Global Variables data + // 4 bytes of size of Heap + // Heap data + // 4 bytes of stack size + // Stack data + + S32 registers_size = get_register(mBuffer, LREG_GFR); + + if (get_register(mBuffer, LREG_HP) > TOP_OF_MEMORY) + reset_hp_to_safe_spot(mBuffer); + + S32 heap_size = get_register(mBuffer, LREG_HP) - get_register(mBuffer, LREG_HR); + S32 stack_size = get_register(mBuffer, LREG_TM) - get_register(mBuffer, LREG_SP); + S32 total_size = registers_size + LSCRIPTDataSize[LST_INTEGER] + + heap_size + LSCRIPTDataSize[LST_INTEGER] + + stack_size + LSCRIPTDataSize[LST_INTEGER]; + + // actually allocate data + delete[] *dest; + *dest = new U8[header_size + total_size + footer_size]; + memset(*dest, 0, header_size + total_size + footer_size); + S32 dest_offset = header_size; + S32 src_offset = 0; + + // registers + integer2bytestream(*dest, dest_offset, registers_size); + + // llinfos << "Writing CE: " << getCurrentEvents() << llendl; + bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, registers_size); + + // heap + integer2bytestream(*dest, dest_offset, heap_size); + + src_offset = get_register(mBuffer, LREG_HR); + bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, heap_size); + + // stack + integer2bytestream(*dest, dest_offset, stack_size); + + src_offset = get_register(mBuffer, LREG_SP); + bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, stack_size); + + return total_size; +} + +S32 LLScriptExecuteLSL2::writeBytecode(U8 **dest) +{ + // data format: + // registers through top of heap + // Heap data + S32 total_size = get_register(mBuffer, LREG_HP); + + // actually allocate data + delete [] *dest; + *dest = new U8[total_size]; + S32 dest_offset = 0; + S32 src_offset = 0; + + bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, total_size); + + return total_size; +} + +S32 LLScriptExecuteLSL2::readState(U8 *src) +{ + // first, blitz heap and stack + S32 hr = get_register(mBuffer, LREG_HR); + S32 tm = get_register(mBuffer, LREG_TM); + memset(mBuffer + hr, 0, tm - hr); + + S32 src_offset = 0; + S32 dest_offset = 0; + S32 size; + + // read register size + size = bytestream2integer(src, src_offset); + + // copy data into register area + bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size); +// llinfos << "Read CE: " << getCurrentEvents() << llendl; + if (get_register(mBuffer, LREG_TM) != TOP_OF_MEMORY) + { + llwarns << "Invalid state. Top of memory register does not match" + << " constant." << llendl; + reset_hp_to_safe_spot(mBuffer); + return -1; + } + + // read heap size + size = bytestream2integer(src, src_offset); + + // set dest offset + dest_offset = get_register(mBuffer, LREG_HR); + + if (dest_offset + size > TOP_OF_MEMORY) + { + reset_hp_to_safe_spot(mBuffer); + return -1; + } + + // copy data into heap area + bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size); + + // read stack size + size = bytestream2integer(src, src_offset); + + // set dest offset + dest_offset = get_register(mBuffer, LREG_SP); + + if (dest_offset + size > TOP_OF_MEMORY) + { + reset_hp_to_safe_spot(mBuffer); + return -1; + } + + // copy data into heap area + bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size); + + // Return offset to first byte after read data. + return src_offset; +} + +void LLScriptExecuteLSL2::reset() +{ + LLScriptExecute::reset(); + + const U8 *src = getBytecode(); + S32 size = getBytecodeSize(); + + if (!src) + return; + + // first, blitz heap and stack + S32 hr = get_register(mBuffer, LREG_HR); + S32 tm = get_register(mBuffer, LREG_TM); + memset(mBuffer + hr, 0, tm - hr); + + S32 dest_offset = 0; + S32 src_offset = 0; + + bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size); +} + +LLScriptExecute::LLScriptExecute() : + mReset(FALSE) +{ +} + +void LLScriptExecute::reset() +{ + mReset = FALSE; +} + +bool LLScriptExecute::isYieldDue() const +{ + if(mReset) + { + return true; + } + + if(getSleep() > 0.f) + { + return true; + } + + if(isFinished()) + { + return true; + } + + if(isStateChangePending()) + { + return true; + } + + return false; +} + +// Run smallest number of instructions possible: +// a single instruction for LSL2, a segment between save tests for Mono +void LLScriptExecute::runInstructions(BOOL b_print, const LLUUID &id, + const char **errorstr, + BOOL &state_transition, + U32& events_processed, + F32 quanta) { // is there a fault? // if yes, print out message and exit - state_transition = FALSE; - S32 value = get_register(mBuffer, LREG_VN); + S32 value = getVersion(); S32 major_version = 0; if (value == LSL2_VERSION1_END_NUMBER) { @@ -313,323 +781,151 @@ U32 LLScriptExecute::run(BOOL b_print, const LLUUID &id, const char **errorstr, } else { - set_fault(mBuffer, LSRF_VERSION_MISMATCH); + setFault(LSRF_VERSION_MISMATCH); } - value = get_register(mBuffer, LREG_FR); - if (value) + value = getFaults(); + if (value > LSRF_INVALID && value < LSRF_EOF) { if (b_print) { printf("Error!\n"); } *errorstr = LSCRIPTRunTimeFaultStrings[value]; - return NO_DELETE_FLAG; + return; } else { *errorstr = NULL; } - // Get IP - // is IP nonzero? - value = get_register(mBuffer, LREG_IP); - - if (value) + if (! isFinished()) { - // if yes, we're in opcodes, execute the next opcode by: - // call opcode run function pointer with buffer and IP - mInstructionCount++; - sGlobalInstructionCount++; - S32 tvalue = value; - S32 opcode = safe_instruction_bytestream2byte(mBuffer, tvalue); - S32 b_ret_val = mExecuteFuncs[opcode](mBuffer, value, b_print, id); - set_ip(mBuffer, value); - add_register_fp(mBuffer, LREG_ESR, -0.1f); - // lsa_print_heap(mBuffer); - - if (b_print) - { - lsa_print_heap(mBuffer); - printf("ip: 0x%X\n", get_register(mBuffer, LREG_IP)); - printf("sp: 0x%X\n", get_register(mBuffer, LREG_SP)); - printf("bp: 0x%X\n", get_register(mBuffer, LREG_BP)); - printf("hr: 0x%X\n", get_register(mBuffer, LREG_HR)); - printf("hp: 0x%X\n", get_register(mBuffer, LREG_HP)); - } - // update IP - if (b_ret_val) - { - return DELETE_FLAG | CREDIT_MONEY_FLAG; - } - else - { - return NO_DELETE_FLAG; - } + resumeEventHandler(b_print, id, quanta); + return; } else { // make sure that IE is zero - set_event_register(mBuffer, LREG_IE, 0, major_version); - - // if no, we're in a state and waiting for an event - S32 next_state = get_register(mBuffer, LREG_NS); - S32 current_state = get_register(mBuffer, LREG_CS); - U64 current_events = get_event_register(mBuffer, LREG_CE, major_version); - U64 event_register = get_event_register(mBuffer, LREG_ER, major_version); - // check NS to see if need to switch states (NS != CS) - if (next_state != current_state) + setCurrentHandler(0, major_version); + + // if no, we're in a state and waiting for an event + U64 current_events = getCurrentEvents(major_version); + U64 event_register = getEventHandlers(major_version); + + // check NS to see if need to switch states (NS != CS) + if (isStateChangePending()) { state_transition = TRUE; + // ok, blow away any pending events - mEventData.mEventDataList.deleteAllData(); + deleteAllEvents(); - // if yes, check state exit flag is set + // if yes, check state exit flag is set if (current_events & LSCRIPTStateBitField[LSTT_STATE_EXIT]) { - // if yes, clear state exit flag - set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[LSTT_STATE_EXIT], major_version); + // if yes, clear state exit flag + setCurrentHandler(LSCRIPTStateBitField[LSTT_STATE_EXIT], major_version); current_events &= ~LSCRIPTStateBitField[LSTT_STATE_EXIT]; - set_event_register(mBuffer, LREG_CE, current_events, major_version); - // check state exit event handler - // if there is a handler, call it + setCurrentEvents(current_events, major_version); + + // check state exit event handler + // if there is a handler, call it if (event_register & LSCRIPTStateBitField[LSTT_STATE_EXIT]) { - // push a zero to be popped - lscript_push(mBuffer, 0); - // push sp as current bp - S32 sp = get_register(mBuffer, LREG_SP); - lscript_push(mBuffer, sp); - - // now, push any additional stack space - S32 additional_size = get_event_stack_size(mBuffer, current_state, LSTT_STATE_EXIT); - if ( additional_size == -1 ) - { - recordBoundaryError( id ); - } - else - { - lscript_pusharge(mBuffer, additional_size); - - sp = get_register(mBuffer, LREG_SP); - sp += additional_size; - set_bp(mBuffer, sp); - // set IP to the event handler - setStateEventOpcoodeStartSafely( current_state, LSTT_STATE_EXIT, id ); - } - return NO_DELETE_FLAG; + ++events_processed; + callEventHandler(LSTT_STATE_EXIT, major_version, id, quanta); + return; } } - // if no handler or no state exit flag switch to new state - // set state entry flag and clear other CE flags + + // if no handler or no state exit flag switch to new state + // set state entry flag and clear other CE flags current_events = LSCRIPTStateBitField[LSTT_STATE_ENTRY]; - set_event_register(mBuffer, LREG_CE, current_events, major_version); - // copy NS to CS - set_register(mBuffer, LREG_CS, next_state); - // copy new state's handled events into ER (SR + CS*4 + 4) - U64 handled_events = get_handled_events(mBuffer, next_state); - set_event_register(mBuffer, LREG_ER, handled_events, major_version); + setCurrentEvents(current_events, major_version); + + U64 handled_events = nextState(); + setEventHandlers(handled_events, major_version); } -// check to see if any current events are covered by events handled by this state (CE & ER != 0) -// now, we want to look like we were called like a function -// 0x0000: 00 00 00 00 (return ip) -// 0x0004: bp (current sp) -// 0x0008: parameters -// push sp -// add parameter size -// pop bp -// set ip - - S32 size = 0; -// try to get next event from stack + + // try to get next event from stack BOOL b_done = FALSE; LSCRIPTStateEventType event = LSTT_NULL; - LLScriptDataCollection *eventdata; - next_state = get_register(mBuffer, LREG_NS); - current_state = get_register(mBuffer, LREG_CS); - current_events = get_event_register(mBuffer, LREG_CE, major_version); - event_register = get_event_register(mBuffer, LREG_ER, major_version); + current_events = getCurrentEvents(major_version); + event_register = getEventHandlers(major_version); // first, check to see if state_entry or onrez are raised and handled - if ( (current_events & LSCRIPTStateBitField[LSTT_STATE_ENTRY]) + if ((current_events & LSCRIPTStateBitField[LSTT_STATE_ENTRY]) &&(current_events & event_register)) { - // ok, this is easy since there isn't any data waiting, just set it - // push a zero to be popped - lscript_push(mBuffer, 0); -// push sp as current bp - S32 sp = get_register(mBuffer, LREG_SP); - lscript_push(mBuffer, sp); - - event = return_first_event((S32)LSCRIPTStateBitField[LSTT_STATE_ENTRY]); - set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); - current_events &= ~LSCRIPTStateBitField[event]; - set_event_register(mBuffer, LREG_CE, current_events, major_version); -// now, push any additional stack space - S32 additional_size = get_event_stack_size(mBuffer, current_state, event); - if ( additional_size == -1 ) - { // b_done will be set, so we'll exit the loop at the bottom - recordBoundaryError( id ); - } - else - { - additional_size -= size; - lscript_pusharge(mBuffer, additional_size); - -// now set the bp correctly - sp = get_register(mBuffer, LREG_SP); - sp += additional_size + size; - set_bp(mBuffer, sp); -// set IP to the function - setStateEventOpcoodeStartSafely( current_state, event, id ); - } + ++events_processed; + callEventHandler(LSTT_STATE_ENTRY, major_version, id, quanta); b_done = TRUE; } - else if ( (current_events & LSCRIPTStateBitField[LSTT_REZ]) - &&(current_events & event_register)) + else if ((current_events & LSCRIPTStateBitField[LSTT_REZ]) + &&(current_events & event_register)) { - for (eventdata = mEventData.mEventDataList.getFirstData(); eventdata; eventdata = mEventData.mEventDataList.getNextData()) - { - if (eventdata->mType & LSCRIPTStateBitField[LSTT_REZ]) - { - // push a zero to be popped - lscript_push(mBuffer, 0); - // push sp as current bp - S32 sp = get_register(mBuffer, LREG_SP); - lscript_push(mBuffer, sp); - - set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); - current_events &= ~LSCRIPTStateBitField[event]; - set_event_register(mBuffer, LREG_CE, current_events, major_version); - - // push any arguments that need to be pushed onto the stack - // last piece of data will be type LST_NULL - LLScriptLibData *data = eventdata->mData; - while (data->mType) - { - size += lscript_push_variable(data, mBuffer); - data++; - } - // now, push any additional stack space - S32 additional_size = get_event_stack_size(mBuffer, current_state, event); - if ( additional_size == -1 ) - { // b_done will be set, so we'll exit the loop at the bottom - recordBoundaryError( id ); - } - else - { - additional_size -= size; - lscript_pusharge(mBuffer, additional_size); - - // now set the bp correctly - sp = get_register(mBuffer, LREG_SP); - sp += additional_size + size; - set_bp(mBuffer, sp); - // set IP to the function - setStateEventOpcoodeStartSafely( current_state, event, id ); - mEventData.mEventDataList.deleteCurrentData(); - } - b_done = TRUE; - break; - } - } + ++events_processed; + callQueuedEventHandler(LSTT_REZ, major_version, id, quanta); + b_done = TRUE; } while (!b_done) { - eventdata = mEventData.getNextEvent(); - if (eventdata) + // Call handler for next queued event. + if(getEventCount() > 0) { - event = eventdata->mType; - - // make sure that we can actually handle this one - if (LSCRIPTStateBitField[event] & event_register) - { - // push a zero to be popped - lscript_push(mBuffer, 0); - // push sp as current bp - S32 sp = get_register(mBuffer, LREG_SP); - lscript_push(mBuffer, sp); - - set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); - current_events &= ~LSCRIPTStateBitField[event]; - set_event_register(mBuffer, LREG_CE, current_events, major_version); - - // push any arguments that need to be pushed onto the stack - // last piece of data will be type LST_NULL - LLScriptLibData *data = eventdata->mData; - while (data->mType) - { - size += lscript_push_variable(data, mBuffer); - data++; - } - b_done = TRUE; - // now, push any additional stack space - S32 additional_size = get_event_stack_size(mBuffer, current_state, event); - if ( additional_size == -1 ) - { // b_done was just set, so we'll exit the loop at the bottom - recordBoundaryError( id ); - } - else - { - additional_size -= size; - lscript_pusharge(mBuffer, additional_size); - - // now set the bp correctly - sp = get_register(mBuffer, LREG_SP); - sp += additional_size + size; - set_bp(mBuffer, sp); - // set IP to the function - setStateEventOpcoodeStartSafely( current_state, event, id ); - } - } - else - { - llwarns << "Shit, somehow got an event that we're not registered for!" << llendl; - } - delete eventdata; + ++events_processed; + callNextQueuedEventHandler(event_register, major_version, id, quanta); + b_done = TRUE; } else { -// if no data waiting, do it the old way: + // if no data waiting, do it the old way: U64 handled_current = current_events & event_register; if (handled_current) { - // push a zero to be popped - lscript_push(mBuffer, 0); - // push sp as current bp - S32 sp = get_register(mBuffer, LREG_SP); - lscript_push(mBuffer, sp); - event = return_first_event((S32)handled_current); - set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version); - current_events &= ~LSCRIPTStateBitField[event]; - set_event_register(mBuffer, LREG_CE, current_events, major_version); - // now, push any additional stack space - S32 additional_size = get_event_stack_size(mBuffer, current_state, event); - if ( additional_size == -1 ) - { // b_done will be set, so we'll exit the loop at the bottom - recordBoundaryError( id ); - } - else - { - additional_size -= size; - lscript_pusharge(mBuffer, additional_size); - - // now set the bp correctly - sp = get_register(mBuffer, LREG_SP); - sp += additional_size + size; - set_bp(mBuffer, sp); - // set IP to the function - setStateEventOpcoodeStartSafely( current_state, event, id ); - } + ++events_processed; + callEventHandler(event, major_version, id, quanta); } b_done = TRUE; } - } // while (!b_done) - } // end of else ... in state processing code + } + } +} + +// Run for a single timeslice, or until a yield is due +F32 LLScriptExecute::runQuanta(BOOL b_print, const LLUUID &id, const char **errorstr, BOOL &state_transition, F32 quanta, U32& events_processed, LLTimer& timer) +{ + U32 timer_checks = 0; + F32 inloop = 0; - return NO_DELETE_FLAG; + // Loop while not finished, yield not due and time remaining + // NOTE: Default implementation does not do adaptive timer skipping + // to preserve current LSL behaviour and not break scripts that rely + // on current execution speed. + while(true) + { + runInstructions(b_print, id, errorstr, state_transition, + events_processed, quanta); + + static const S32 lsl_timer_check_skip = 4; + if(isYieldDue()) + { + break; + } + else if(timer_checks++ == lsl_timer_check_skip) + { + inloop = timer.getElapsedTimeF32(); + if(inloop > quanta) + { + break; + } + timer_checks = 0; + } + } + return inloop; } BOOL run_noop(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) @@ -3687,6 +3983,11 @@ BOOL run_print(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) void lscript_run(const std::string& filename, BOOL b_debug) { LLTimer timer; + + const char *error; + BOOL b_state; + LLScriptExecuteLSL2 *execute = NULL; + if (filename.empty()) { llerrs << "filename is NULL" << llendl; @@ -3694,47 +3995,35 @@ void lscript_run(const std::string& filename, BOOL b_debug) // to check how to abort or error out gracefully // from this function. XXXTBD } - else + LLFILE* file = LLFile::fopen(filename, "r"); /* Flawfinder: ignore */ + if(file) { - const char *error; - BOOL b_state; - LLScriptExecute *execute = NULL; - - LLFILE* file = LLFile::fopen(filename, "r"); - if (file) - { - execute = new LLScriptExecute(file); - // note: LLScriptExecute() closes file for us - } - file = LLFile::fopen(filename, "r"); - if (file) - { - std::string parsefile("lscript.parse"); - LLFILE* fp = LLFile::fopen(parsefile, "w"); /*Flawfinder: ignore*/ - LLScriptLSOParse *parse = new LLScriptLSOParse(file); - parse->printData(fp); - delete parse; - fclose(file); - fclose(fp); - } - file = LLFile::fopen(filename, "r"); - if (file && execute) - { - timer.reset(); - while (!execute->run(b_debug, LLUUID::null, &error, b_state)) - ; - F32 time = timer.getElapsedTimeF32(); - F32 ips = execute->mInstructionCount / time; - llinfos << execute->mInstructionCount << " instructions in " << time << " seconds" << llendl; - llinfos << ips/1000 << "K instructions per second" << llendl; - printf("ip: 0x%X\n", get_register(execute->mBuffer, LREG_IP)); - printf("sp: 0x%X\n", get_register(execute->mBuffer, LREG_SP)); - printf("bp: 0x%X\n", get_register(execute->mBuffer, LREG_BP)); - printf("hr: 0x%X\n", get_register(execute->mBuffer, LREG_HR)); - printf("hp: 0x%X\n", get_register(execute->mBuffer, LREG_HP)); - delete execute; - fclose(file); - } + execute = new LLScriptExecuteLSL2(file); + fclose(file); + } + if (execute) + { + timer.reset(); + F32 time_slice = 3600.0f; // 1 hr. + U32 events_processed = 0; + + do { + LLTimer timer2; + execute->runQuanta(b_debug, LLUUID::null, &error, b_state, + time_slice, events_processed, timer2); + } while (!execute->isFinished()); + + F32 time = timer.getElapsedTimeF32(); + F32 ips = execute->mInstructionCount / time; + llinfos << execute->mInstructionCount << " instructions in " << time << " seconds" << llendl; + llinfos << ips/1000 << "K instructions per second" << llendl; + printf("ip: 0x%X\n", get_register(execute->mBuffer, LREG_IP)); + printf("sp: 0x%X\n", get_register(execute->mBuffer, LREG_SP)); + printf("bp: 0x%X\n", get_register(execute->mBuffer, LREG_BP)); + printf("hr: 0x%X\n", get_register(execute->mBuffer, LREG_HR)); + printf("hp: 0x%X\n", get_register(execute->mBuffer, LREG_HP)); + delete execute; + fclose(file); } } diff --git a/indra/lscript/lscript_library.h b/indra/lscript/lscript_library.h index 74356256ae..a9db30670a 100644 --- a/indra/lscript/lscript_library.h +++ b/indra/lscript/lscript_library.h @@ -146,9 +146,9 @@ public: return FALSE; } - S32 getListLength() + S32 getListLength() const { - LLScriptLibData *data = this; + const LLScriptLibData *data = this; S32 retval = 0; while (data->mListp) { diff --git a/indra/lscript/lscript_library/lscript_library.cpp b/indra/lscript/lscript_library/lscript_library.cpp index b99bd64f2a..54d0154798 100644 --- a/indra/lscript/lscript_library/lscript_library.cpp +++ b/indra/lscript/lscript_library/lscript_library.cpp @@ -398,9 +398,8 @@ void LLScriptLibrary::init() addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetCameraPos", "v", "", "vector llGetCameraPos()\nGets current camera position for agent task has permissions for.")); addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetCameraRot", "q", "", "rotation llGetCameraRot()\nGets current camera orientation for agent task has permissions for.")); - addFunction(new LLScriptLibraryFunction(10.f, 2.f, dummy_func, "llSetPrimURL", NULL, "s", "llSetPrimURL(string url)\nUpdates the URL for the web page shown on the sides of the object.")); + addFunction(new LLScriptLibraryFunction(10.f, 20.f, dummy_func, "llSetPrimURL", NULL, "s", "llSetPrimURL(string url)\nUpdates the URL for the web page shown on the sides of the object.")); addFunction(new LLScriptLibraryFunction(10.f, 20.f, dummy_func, "llRefreshPrimURL", NULL, "", "llRefreshPrimURL()\nReloads the web page shown on the sides of the object.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llEscapeURL", "s", "s", "string llEscapeURL(string url)\nReturns and escaped/encoded version of url, replacing spaces with %20 etc.")); addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llUnescapeURL", "s", "s", "string llUnescapeURL(string url)\nReturns and unescaped/unencoded version of url, replacing %20 with spaces etc.")); @@ -458,24 +457,6 @@ void LLScriptLibrary::init() // existing scripts will crash. } - //Ventrella Follow Cam Script Stuff - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamPitch", NULL, "f", "llSetCamPitch(-45 to 80)\n(Adjusts the angular amount that the camera aims straight ahead vs. straight down, maintaining the same distance. Analogous to 'incidence'.")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamVerticalOffset", NULL, "f", "llSetCamVerticalOffset(-2 to 2)\nAdjusts the vertical position of the camera focus position relative to the subject")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamPositionLag", NULL, "f", "llSetCamPositionLag(0 to 3) \nHow much the camera lags as it tries to move towards its 'ideal' position")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamFocusLag", NULL, "f", "llSetCamFocusLag(0 to 3)\nHow much the camera lags as it tries to aim towards the subject")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamDistance", NULL, "f", "llSetCamDistance(0.5 to 10)\nSets how far away the camera wants to be from its subject")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamBehindnessAngle", NULL, "f", "llSetCamBehindnessAngle(0 to 180)\nSets the angle in degrees within which the camera is not constrained by changes in subject rotation")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamBehindnessLag", NULL, "f", "llSetCamBehindnessLag(0 to 3)\nSets how strongly the camera is forced to stay behind the target if outside of behindness angle")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamPositionThreshold", NULL, "f", "llSetCamPositionThreshold(0 to 4)\nSets the radius of a sphere around the camera's ideal position within which it is not affected by subject motion")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamFocusThreshold", NULL, "f", "llSetCamFocusThreshold(0 to 4)\nSets the radius of a sphere around the camera's subject position within which its focus is not affected by subject motion")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamScriptControl", NULL, "i", "llSetCamScriptControl(TRUE or FALSE)\nTurns on or off scripted control of the camera")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamPosition", NULL, "v", "llSetCamPosition(vector)\nSets the position of the camera")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamFocus", NULL, "v", "llSetCamFocus(vector focus)\nSets the focus (target position) of the camera")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamPositionLocked", NULL, "i", "llSetCamPositionLocked(TRUE or FALSE)\nLocks the camera position so it will not move")); - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCamFocusLocked", NULL, "i", "llSetCamFocusLocked(TRUE or FALSE)\nLocks the camera focus so it will not move")); - - //addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetForSale", "i", "ii", "integer llSetForSale(integer selltype, integer price)\nSets this object for sale in mode selltype for price. Returns TRUE if successfully set for sale.")); - LLScriptLibraryFunction::LLScriptLibraryFunction(F32 eu, F32 st, void (*exec_func)(LLScriptLibData *, LLScriptLibData *, const LLUUID &), const char *name, const char *ret_type, const char *args, const char *desc, BOOL god_only) : mEnergyUse(eu), mSleepTime(st), mExecFunc(exec_func), mName(name), mReturnType(ret_type), mArgs(args), mGodOnly(god_only) { diff --git a/indra/lscript/lscript_rt_interface.h b/indra/lscript/lscript_rt_interface.h index 3e05212c67..14559ab3e8 100644 --- a/indra/lscript/lscript_rt_interface.h +++ b/indra/lscript/lscript_rt_interface.h @@ -32,9 +32,9 @@ #ifndef LL_LSCRIPT_RT_INTERFACE_H #define LL_LSCRIPT_RT_INTERFACE_H -BOOL lscript_compile(char *filename, BOOL is_god_like = FALSE); +BOOL lscript_compile(char *filename, BOOL compile_to_mono, BOOL is_god_like = FALSE); BOOL lscript_compile(const char* src_filename, const char* dst_filename, - const char* err_filename, BOOL is_god_like = FALSE); + const char* err_filename, BOOL compile_to_mono, const char* class_name, BOOL is_god_like = FALSE); void lscript_run(const std::string& filename, BOOL b_debug); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index e65721e124..0fea3076c3 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -66,6 +66,7 @@ set(viewer_SOURCE_FILES llanimstatelabels.cpp llappviewer.cpp llassetuploadresponders.cpp + llassetuploadqueue.cpp llaudiosourcevo.cpp llbbox.cpp llbox.cpp @@ -454,6 +455,7 @@ set(viewer_HEADER_FILES llappearance.h llappviewer.h llassetuploadresponders.h + llassetuploadqueue.h llaudiosourcevo.h llbbox.h llbox.h diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings index 7272173fed..881483e892 100644 --- a/indra/newview/English.lproj/InfoPlist.strings +++ b/indra/newview/English.lproj/InfoPlist.strings @@ -1,5 +1,6 @@ /* Localized versions of Info.plist keys */ CFBundleName = "Second Life"; -CFBundleShortVersionString = "Second Life version 1.20.6.86975"; -CFBundleGetInfoString = "Second Life version 1.20.6.86975, Copyright 2004-2008 Linden Research, Inc."; +CFBundleShortVersionString = "Second Life version 1.20.9.87416"; +CFBundleGetInfoString = "Second Life version 1.20.9.87416, Copyright 2004-2008 Linden Research, Inc."; + diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist index fa50503545..b889d45b9e 100644 --- a/indra/newview/Info-SecondLife.plist +++ b/indra/newview/Info-SecondLife.plist @@ -32,7 +32,7 @@ </dict> </array> <key>CFBundleVersion</key> - <string>1.20.6.86975</string> + <string>1.20.9.87416</string> <key>CSResourcesFileMapped</key> <true/> </dict> diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp new file mode 100644 index 0000000000..c52c189d56 --- /dev/null +++ b/indra/newview/llassetuploadqueue.cpp @@ -0,0 +1,194 @@ +/** + * @file llassetupload.cpp + * @brief Serializes asset upload request + * Copyright (c) 2007, Linden Research, Inc. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llassetuploadqueue.h" +#include "llviewerregion.h" +#include "llviewerobjectlist.h" + +#include "llassetuploadresponders.h" +#include "llsd.h" +#include <iostream> + +class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder +{ +public: + + LLAssetUploadChainResponder(const LLSD& post_data, + const std::string& file_name, + const LLUUID& queue_id, + U8* data, + U32 data_size, + std::string script_name, + LLAssetUploadQueueSupplier *supplier) : + LLUpdateTaskInventoryResponder(post_data, file_name, queue_id, LLAssetType::AT_LSL_TEXT), + mSupplier(supplier), + mData(data), + mDataSize(data_size), + mScriptName(script_name) + { + } + + virtual ~LLAssetUploadChainResponder() + { + if(mSupplier) + { + LLAssetUploadQueue *queue = mSupplier->get(); + if (queue) + { + // Give ownership of supplier back to queue. + queue->mSupplier = mSupplier; + mSupplier = NULL; + } + } + delete mSupplier; + delete mData; + } + + virtual void error(U32 statusNum, const std::string& reason) + { + llwarns << "Error: " << reason << llendl; + LLUpdateTaskInventoryResponder::error(statusNum, reason); + LLAssetUploadQueue *queue = mSupplier->get(); + if (queue) + { + queue->request(&mSupplier); + } + } + + virtual void result(const LLSD& content) + { + LLUpdateTaskInventoryResponder::result(content); + LLAssetUploadQueue *queue = mSupplier->get(); + if (queue) + { + // Responder is reused across 2 phase upload, + // so only start next upload after 2nd phase complete. + std::string state = content["state"]; + if(state == "complete") + { + queue->request(&mSupplier); + } + } + } + + virtual void uploadUpload(const LLSD& content) + { + std::string uploader = content["uploader"]; + + mSupplier->log(std::string("Compiling " + mScriptName).c_str()); + llinfos << "Compiling " << llendl; + + // postRaw takes ownership of mData and will delete it. + LLHTTPClient::postRaw(uploader, mData, mDataSize, this); + mData = NULL; + mDataSize = 0; + } + + virtual void uploadComplete(const LLSD& content) + { + // Bytecode save completed + if (content["compiled"]) + { + mSupplier->log("Compilation succeeded"); + llinfos << "Compiled!" << llendl; + } + else + { + LLSD compile_errors = content["errors"]; + for(LLSD::array_const_iterator line = compile_errors.beginArray(); + line < compile_errors.endArray(); line++) + { + mSupplier->log(line->asString()); + llinfos << content["errors"] << llendl; + } + } + LLUpdateTaskInventoryResponder::uploadComplete(content); + } + + LLAssetUploadQueueSupplier *mSupplier; + U8* mData; + U32 mDataSize; + std::string mScriptName; +}; + + +LLAssetUploadQueue::LLAssetUploadQueue(LLAssetUploadQueueSupplier *supplier) : + mSupplier(supplier) +{ +} + +//virtual +LLAssetUploadQueue::~LLAssetUploadQueue() +{ + delete mSupplier; +} + +// Takes ownership of supplier. +void LLAssetUploadQueue::request(LLAssetUploadQueueSupplier** supplier) +{ + if (mQueue.empty()) + return; + + UploadData data = mQueue.front(); + mQueue.pop_front(); + + LLSD body; + body["task_id"] = data.mTaskId; + body["item_id"] = data.mItemId; + body["is_script_running"] = data.mIsRunning; + body["target"] = data.mIsTargetMono? "mono" : "lsl2"; + + std::string url = ""; + LLViewerObject* object = gObjectList.findObject(data.mTaskId); + if (object) + { + url = object->getRegion()->getCapability("UpdateScriptTaskInventory"); + LLHTTPClient::post(url, body, + new LLAssetUploadChainResponder( + body, data.mFilename, data.mQueueId, + data.mData, data.mDataSize, data.mScriptName, *supplier)); + } + + *supplier = NULL; +} + +void LLAssetUploadQueue::queue(const std::string& filename, + const LLUUID& task_id, + const LLUUID& item_id, + BOOL is_running, + BOOL is_target_mono, + const LLUUID& queue_id, + U8* script_data, + U32 data_size, + std::string script_name) +{ + UploadData data; + data.mTaskId = task_id; + data.mItemId = item_id; + data.mIsRunning = is_running; + data.mIsTargetMono = is_target_mono; + data.mQueueId = queue_id; + data.mFilename = filename; + data.mData = script_data; + data.mDataSize = data_size; + data.mScriptName = script_name; + + mQueue.push_back(data); + + if(mSupplier) + { + request(&mSupplier); + } +} + +LLAssetUploadQueueSupplier::~LLAssetUploadQueueSupplier() +{ +} diff --git a/indra/newview/llassetuploadqueue.h b/indra/newview/llassetuploadqueue.h new file mode 100644 index 0000000000..6e4caa1b0f --- /dev/null +++ b/indra/newview/llassetuploadqueue.h @@ -0,0 +1,74 @@ +/** + * @file llassetuploadqueue.h + * @brief Serializes asset upload request + * Copyright (c) 2007, Linden Research, Inc. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * $/LicenseInfo$ + */ + +#ifndef LL_LLASSETUPLOADQUEUE_H +#define LL_LLASSETUPLOADQUEUE_H + +#include "lluuid.h" + +#include <string> +#include <deque> + +class LLAssetUploadQueueSupplier; + +class LLAssetUploadQueue +{ +public: + + // Takes ownership of supplier. + LLAssetUploadQueue(LLAssetUploadQueueSupplier* supplier); + virtual ~LLAssetUploadQueue(); + + void queue(const std::string& filename, + const LLUUID& task_id, + const LLUUID& item_id, + BOOL is_running, + BOOL is_target_mono, + const LLUUID& queue_id, + U8* data, + U32 data_size, + std::string script_name); + + bool isEmpty() const {return mQueue.empty();} + +private: + + friend class LLAssetUploadChainResponder; + + struct UploadData + { + std::string mFilename; + LLUUID mTaskId; + LLUUID mItemId; + BOOL mIsRunning; + BOOL mIsTargetMono; + LLUUID mQueueId; + U8* mData; + U32 mDataSize; + std::string mScriptName; + }; + + // Ownership of mSupplier passed to currently waiting responder + // and returned to queue when no requests in progress. + LLAssetUploadQueueSupplier* mSupplier; + std::deque<UploadData> mQueue; + + // Passes on ownership of mSupplier if request is made. + void request(LLAssetUploadQueueSupplier** supplier); +}; + +class LLAssetUploadQueueSupplier +{ +public: + virtual ~LLAssetUploadQueueSupplier(); + virtual LLAssetUploadQueue* get() const = 0; + virtual void log(std::string message) const = 0; +}; + +#endif // LL_LLASSETUPLOADQUEUE_H diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 3d91384f48..962066471f 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -34,6 +34,7 @@ #include "llassetuploadresponders.h" #include "llagent.h" +#include "llcompilequeue.h" #include "llfloaterbuycurrency.h" #include "lleconomy.h" #include "llfilepicker.h" @@ -73,11 +74,12 @@ LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, } LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, - const std::string& file_name) + const std::string& file_name, + LLAssetType::EType asset_type) : LLHTTPClient::Responder(), mPostData(post_data), - mAssetType(LLAssetType::AT_NONE), - mFileName(file_name) + mFileName(file_name), + mAssetType(asset_type) { } @@ -182,8 +184,8 @@ LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data { } -LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name) -: LLAssetUploadResponder(post_data, file_name) +LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name, LLAssetType::EType asset_type) +: LLAssetUploadResponder(post_data, file_name, asset_type) { } @@ -301,8 +303,9 @@ LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& pos } LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data, - const std::string& file_name) -: LLAssetUploadResponder(post_data, file_name) + const std::string& file_name, + LLAssetType::EType asset_type) +: LLAssetUploadResponder(post_data, file_name, asset_type) { } @@ -410,8 +413,17 @@ LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_ } LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data, - const std::string& file_name) -: LLAssetUploadResponder(post_data, file_name) + const std::string& file_name, + LLAssetType::EType asset_type) +: LLAssetUploadResponder(post_data, file_name, asset_type) +{ +} + +LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data, + const std::string& file_name, + const LLUUID& queue_id, + LLAssetType::EType asset_type) +: LLAssetUploadResponder(post_data, file_name, asset_type), mQueueId(queue_id) { } @@ -422,35 +434,16 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) LLUUID item_id = mPostData["item_id"]; LLUUID task_id = mPostData["task_id"]; - LLViewerObject* object = gObjectList.findObject(task_id); - if (!object) - { - llwarns << "LLUpdateTaskInventoryResponder::uploadComplete task " << task_id - << " no longer exist." << llendl; - return; - } - LLViewerInventoryItem* item = (LLViewerInventoryItem*)object->getInventoryObject(item_id); - if (!item) - { - llwarns << "LLUpdateTaskInventoryResponder::uploadComplete item " - << item_id << " is no longer in task " << task_id - << "'s inventory." << llendl; - return; - } - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); - // Update Viewer inventory - object->updateViewerInventoryAsset(new_item, content["new_asset"]); dialog_refresh_all(); - LLInventoryType::EType inventory_type = new_item->getInventoryType(); - switch(inventory_type) + switch(mAssetType) { - case LLInventoryType::IT_NOTECARD: + case LLAssetType::AT_NOTECARD: { // Update the UI with the new asset. LLPreviewNotecard* nc; - nc = (LLPreviewNotecard*)LLPreview::find(new_item->getUUID()); + nc = (LLPreviewNotecard*)LLPreview::find(item_id); if(nc) { // *HACK: we have to delete the asset in the VFS so @@ -470,28 +463,39 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) } } break; - case LLInventoryType::IT_LSL: + case LLAssetType::AT_LSL_TEXT: { - LLLiveLSLEditor* preview = LLLiveLSLEditor::find(item_id, task_id); - if (preview) + if(mQueueId.notNull()) { - // Bytecode save completed - if (content["compiled"]) + LLFloaterCompileQueue* queue = + (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId); + if(NULL != queue) { - preview->callbackLSLCompileSucceeded( - task_id, - item_id, - mPostData["is_script_running"]); + queue->removeItemByItemID(item_id); } - else + } + else + { + LLLiveLSLEditor* preview = LLLiveLSLEditor::find(item_id, task_id); + if (preview) { - preview->callbackLSLCompileFailed(content["errors"]); + // Bytecode save completed + if (content["compiled"]) + { + preview->callbackLSLCompileSucceeded( + task_id, + item_id, + mPostData["is_script_running"]); + } + else + { + preview->callbackLSLCompileFailed(content["errors"]); + } } } } break; - case LLInventoryType::IT_WEARABLE: - default: - break; + default: + break; } } diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index 25f3f4c3b1..dc4f6e7bf0 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -42,7 +42,9 @@ public: LLAssetUploadResponder(const LLSD& post_data, const LLUUID& vfile_id, LLAssetType::EType asset_type); - LLAssetUploadResponder(const LLSD& post_data, const std::string& file_name); + LLAssetUploadResponder(const LLSD& post_data, + const std::string& file_name, + LLAssetType::EType asset_type); ~LLAssetUploadResponder(); virtual void error(U32 statusNum, const std::string& reason); virtual void result(const LLSD& content); @@ -52,8 +54,8 @@ public: protected: LLSD mPostData; - LLUUID mVFileID; LLAssetType::EType mAssetType; + LLUUID mVFileID; std::string mFileName; }; @@ -63,7 +65,8 @@ public: LLNewAgentInventoryResponder(const LLSD& post_data, const LLUUID& vfile_id, LLAssetType::EType asset_type); - LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name); + LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name, + LLAssetType::EType asset_type); virtual void uploadComplete(const LLSD& content); }; @@ -74,7 +77,8 @@ public: const LLUUID& vfile_id, LLAssetType::EType asset_type); LLUpdateAgentInventoryResponder(const LLSD& post_data, - const std::string& file_name); + const std::string& file_name, + LLAssetType::EType asset_type); virtual void uploadComplete(const LLSD& content); }; @@ -85,8 +89,17 @@ public: const LLUUID& vfile_id, LLAssetType::EType asset_type); LLUpdateTaskInventoryResponder(const LLSD& post_data, - const std::string& file_name); + const std::string& file_name, + LLAssetType::EType asset_type); + LLUpdateTaskInventoryResponder(const LLSD& post_data, + const std::string& file_name, + const LLUUID& queue_id, + LLAssetType::EType asset_type); + virtual void uploadComplete(const LLSD& content); + +private: + LLUUID mQueueId; }; #endif // LL_LLASSETUPLOADRESPONDER_H diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index 3ab340f66a..30d5dc206f 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -42,6 +42,8 @@ #include "llcompilequeue.h" #include "llagent.h" +#include "llassetuploadqueue.h" +#include "llassetuploadresponders.h" #include "llchat.h" #include "llviewerwindow.h" #include "llviewerobject.h" @@ -72,20 +74,15 @@ const std::string RUN_START_STRING("set running"); const std::string NOT_RUN_QUEUE_TITLE("Set Not Running Progress"); const std::string NOT_RUN_START_STRING("set not running"); -struct LLCompileQueueData -{ - LLUUID mQueueID; - LLUUID mOldAssetID; - LLCompileQueueData(const LLUUID& q_id, const LLUUID& old_asset_id) : - mQueueID(q_id), mOldAssetID(old_asset_id) {} -}; - struct LLScriptQueueData { LLUUID mQueueID; std::string mScriptName; - LLScriptQueueData(const LLUUID& q_id, const std::string& name) : - mQueueID(q_id), mScriptName(name) {} + LLUUID mTaskId; + LLUUID mItemId; + LLScriptQueueData(const LLUUID& q_id, const std::string& name, const LLUUID& task_id, const LLUUID& item_id) : + mQueueID(q_id), mScriptName(name), mTaskId(task_id), mItemId(item_id) {} + }; ///---------------------------------------------------------------------------- @@ -105,7 +102,8 @@ LLFloaterScriptQueue::LLFloaterScriptQueue(const std::string& name, RESIZE_YES, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, DRAG_ON_TOP, MINIMIZE_YES, CLOSE_YES) { - + mID.generate(); + LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_queue.xml"); childSetAction("close",onCloseBtn,this); @@ -113,11 +111,8 @@ LLFloaterScriptQueue::LLFloaterScriptQueue(const std::string& name, setTitle(title); - if (!getHost()) - { - LLRect curRect = getRect(); - translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); - } + LLRect curRect = getRect(); + translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); mStartString = start_string; mDone = FALSE; @@ -279,14 +274,57 @@ BOOL LLFloaterScriptQueue::popNext() ///---------------------------------------------------------------------------- // static -LLFloaterCompileQueue* LLFloaterCompileQueue::create() +LLFloaterCompileQueue* LLFloaterCompileQueue::create(BOOL mono) { S32 left, top; gFloaterView->getNewFloaterPosition(&left, &top); LLRect rect = gSavedSettings.getRect("CompileOutputRect"); rect.translate(left - rect.mLeft, top - rect.mTop); LLFloaterCompileQueue* new_queue = new LLFloaterCompileQueue("queue", rect); - new_queue->open(); /*Flawfinder: ignore*/ + + class LLCompileFloaterUploadQueueSupplier : public LLAssetUploadQueueSupplier + { + public: + + LLCompileFloaterUploadQueueSupplier(const LLUUID& queue_id) : + mQueueId(queue_id) + { + } + + virtual LLAssetUploadQueue* get() const + { + LLFloaterCompileQueue* queue = + (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId); + + if(NULL == queue) + { + return NULL; + } + + return queue->mUploadQueue; + } + + virtual void log(std::string message) const + { + LLFloaterCompileQueue* queue = + (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId); + + if(NULL == queue) + { + return; + } + + LLScrollListCtrl* list = queue->getChild<LLScrollListCtrl>("queue output"); + list->addCommentText(message.c_str()); + } + + private: + LLUUID mQueueId; + }; + + new_queue->mUploadQueue = new LLAssetUploadQueue(new LLCompileFloaterUploadQueueSupplier(new_queue->getID())); + new_queue->mMono = mono; + new_queue->open(); return new_queue; } @@ -304,7 +342,7 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, // find all of the lsl, leaving off duplicates. We'll remove // all matching asset uuids on compilation success. - typedef std::map<LLUUID, LLPointer<LLInventoryItem> > uuid_item_map; + typedef std::multimap<LLUUID, LLPointer<LLInventoryItem> > uuid_item_map; uuid_item_map asset_item_map; InventoryObjectList::const_iterator it = inv->begin(); @@ -315,17 +353,12 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, { LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); // Check permissions before allowing the user to retrieve data. - if (item->getPermissions().allowModifyBy(gAgent.getID()) && - item->getPermissions().allowCopyBy(gAgent.getID()) ) + if (item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID()) && + item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID()) ) { LLPointer<LLViewerInventoryItem> script = new LLViewerInventoryItem(item); mCurrentScripts.put(script); - - if (!asset_item_map.count(item->getAssetUUID())) - { - // No entry, put in an entry for this supposedly permissive script - asset_item_map[item->getAssetUUID()] = item; - } + asset_item_map.insert(std::make_pair(item->getAssetUUID(), item)); } } } @@ -342,7 +375,10 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, for(iter = asset_item_map.begin(); iter != asset_item_map.end(); iter++) { LLInventoryItem *itemp = iter->second; - LLScriptQueueData* datap = new LLScriptQueueData(getID(), itemp->getName()); + LLScriptQueueData* datap = new LLScriptQueueData(getID(), + itemp->getName(), + viewer_object->getID(), + itemp->getUUID()); //llinfos << "ITEM NAME 2: " << names.get(i) << llendl; gAssetStorage->getInvItemAsset(viewer_object->getRegion()->getHost(), @@ -359,7 +395,6 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, } } - // This is the callback for when each script arrives // static void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, @@ -382,31 +417,58 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, std::string uuid_str; asset_id.toString(uuid_str); filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str) + llformat(".%s",LLAssetType::lookup(type)); - - LLFILE *fp = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/ - if (fp) + + const bool is_running = true; + LLViewerObject* object = gObjectList.findObject(data->mTaskId); + if (object) { - const S32 buf_size = 65536; - U8 copy_buf[buf_size]; - while (file.read(copy_buf, buf_size)) /*Flawfinder: ignore*/ + std::string url = object->getRegion()->getCapability("UpdateScriptTaskInventory"); + if(!url.empty()) + { + // Read script source in to buffer. + U32 script_size = file.getSize(); + U8* script_data = new U8[script_size]; + file.read(script_data, script_size); + + queue->mUploadQueue->queue(filename, data->mTaskId, + data->mItemId, is_running, queue->mMono, queue->getID(), + script_data, script_size, data->mScriptName); + } + else { - if (fwrite(copy_buf, file.getLastBytesRead(), 1, fp) < 1) + // It's now in the file, now compile it. + buffer = std::string("Downloaded, now compiling: ") + data->mScriptName; // *TODO: Translate + + // Write script to local file for compilation. + LLFILE *fp = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/ + if (fp) { - // return a bad file error if we can't write the whole thing - status = LL_ERR_CANNOT_OPEN_FILE; + const S32 buf_size = 65536; + U8 copy_buf[buf_size]; + + while (file.read(copy_buf, buf_size)) /*Flawfinder: ignore*/ + { + if (fwrite(copy_buf, file.getLastBytesRead(), 1, fp) < 1) + { + // return a bad file error if we can't write the whole thing + status = LL_ERR_CANNOT_OPEN_FILE; + } + } + + fclose(fp); + } + else + { + llerrs << "Unable to find object to compile" << llendl; } - } - fclose(fp); + // TODO: babbage: No compile if no cap. + queue->compile(filename, data->mItemId); + + // Delete it after we're done compiling? + LLFile::remove(filename); + } } - - // *TODO: translate - // It's now in the file, now compile it. - buffer = std::string("Downloaded, now compiling: ") + data->mScriptName; // *TODO: Translate - queue->compile(filename, asset_id); - - // Delete it after we're done compiling? - LLFile::remove(filename); } else { @@ -430,9 +492,9 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, } llwarns << "Problem downloading script asset." << llendl; - if(queue) queue->removeItemByAssetID(asset_id); + if(queue) queue->removeItemByItemID(data->mItemId); } - if(queue) + if(queue && (buffer.size() > 0)) { LLScrollListCtrl* list = queue->getChild<LLScrollListCtrl>("queue output"); list->addCommentText(buffer); @@ -462,9 +524,8 @@ void LLFloaterCompileQueue::onSaveBytecodeComplete(const LLUUID& asset_id, void* (LLFloaterScriptQueue::findInstance(data->mQueueID)); if(queue && (0 == status) && data) { - queue->updateAssetID(data->mOldAssetID, asset_id); - queue->saveItemByAssetID(asset_id); - queue->removeItemByAssetID(asset_id); + queue->saveItemByItemID(data->mItemId); + queue->removeItemByItemID(data->mItemId); } else { @@ -479,7 +540,7 @@ void LLFloaterCompileQueue::onSaveBytecodeComplete(const LLUUID& asset_id, void* // compile the file given and save it out. void LLFloaterCompileQueue::compile(const std::string& filename, - const LLUUID& asset_id) + const LLUUID& item_id) { LLUUID new_asset_id; LLTransactionID tid; @@ -496,29 +557,34 @@ void LLFloaterCompileQueue::compile(const std::string& filename, gAssetStorage->storeAssetData(filename, tid, LLAssetType::AT_LSL_TEXT, &onSaveTextComplete, NULL, FALSE); - if(!lscript_compile(filename.c_str(), dst_filename.c_str(), err_filename.c_str(), gAgent.isGodlike())) + + const BOOL compile_to_mono = FALSE; + if(!lscript_compile(filename.c_str(), dst_filename.c_str(), + err_filename.c_str(), compile_to_mono, + uuid_string.c_str(), gAgent.isGodlike())) { llwarns << "compile failed" << llendl; - removeItemByAssetID(asset_id); + removeItemByItemID(item_id); } else { llinfos << "compile successful." << llendl; - // Save the bytecode - LLCompileQueueData* data = new LLCompileQueueData(mID, asset_id); - gAssetStorage->storeAssetData(dst_filename, tid, - LLAssetType::AT_LSL_BYTECODE, - &onSaveBytecodeComplete, - (void*)data, FALSE); + + // Save LSL bytecode + LLCompileQueueData* data = new LLCompileQueueData(mID, item_id); + gAssetStorage->storeAssetData(dst_filename, new_asset_id, + LLAssetType::AT_LSL_BYTECODE, + &LLFloaterCompileQueue::onSaveBytecodeComplete, + (void*)data, FALSE); } } -void LLFloaterCompileQueue::removeItemByAssetID(const LLUUID& asset_id) +void LLFloaterCompileQueue::removeItemByItemID(const LLUUID& asset_id) { llinfos << "LLFloaterCompileQueue::removeItemByAssetID()" << llendl; for(S32 i = 0; i < mCurrentScripts.count(); ) { - if(asset_id == mCurrentScripts.get(i)->getAssetUUID()) + if(asset_id == mCurrentScripts.get(i)->getUUID()) { mCurrentScripts.remove(i); } @@ -533,7 +599,21 @@ void LLFloaterCompileQueue::removeItemByAssetID(const LLUUID& asset_id) } } -void LLFloaterCompileQueue::saveItemByAssetID(const LLUUID& asset_id) +const LLInventoryItem* LLFloaterCompileQueue::findItemByItemID(const LLUUID& asset_id) const +{ + LLInventoryItem* result = NULL; + S32 count = mCurrentScripts.count(); + for(S32 i = 0; i < count; ++i) + { + if(asset_id == mCurrentScripts.get(i)->getUUID()) + { + result = mCurrentScripts.get(i); + } + } + return result; +} + +void LLFloaterCompileQueue::saveItemByItemID(const LLUUID& asset_id) { llinfos << "LLFloaterCompileQueue::saveItemByAssetID()" << llendl; LLViewerObject* viewer_object = gObjectList.findObject(mCurrentObjectID); @@ -542,7 +622,7 @@ void LLFloaterCompileQueue::saveItemByAssetID(const LLUUID& asset_id) S32 count = mCurrentScripts.count(); for(S32 i = 0; i < count; ++i) { - if(asset_id == mCurrentScripts.get(i)->getAssetUUID()) + if(asset_id == mCurrentScripts.get(i)->getUUID()) { // *FIX: this auto-resets active to TRUE. That might // be a bad idea. @@ -556,20 +636,6 @@ void LLFloaterCompileQueue::saveItemByAssetID(const LLUUID& asset_id) } } -// find old_asst_id, and set the asset id to new_asset_id -void LLFloaterCompileQueue::updateAssetID(const LLUUID& old_asset_id, - const LLUUID& new_asset_id) -{ - S32 count = mCurrentScripts.count(); - for(S32 i = 0; i < count; ++i) - { - if(old_asset_id == mCurrentScripts.get(i)->getAssetUUID()) - { - mCurrentScripts.get(i)->setAssetUUID(new_asset_id); - } - } -} - ///---------------------------------------------------------------------------- /// Class LLFloaterResetQueue ///---------------------------------------------------------------------------- @@ -582,7 +648,8 @@ LLFloaterResetQueue* LLFloaterResetQueue::create() LLRect rect = gSavedSettings.getRect("CompileOutputRect"); rect.translate(left - rect.mLeft, top - rect.mTop); LLFloaterResetQueue* new_queue = new LLFloaterResetQueue("queue", rect); - new_queue->open(); /*Flawfinder: ignore*/ + gFloaterView->addChild(new_queue); + new_queue->open(); return new_queue; } diff --git a/indra/newview/llcompilequeue.h b/indra/newview/llcompilequeue.h index be7bbd5ceb..68e9a27266 100644 --- a/indra/newview/llcompilequeue.h +++ b/indra/newview/llcompilequeue.h @@ -64,6 +64,9 @@ public: // start() returns TRUE if the queue has started, otherwise FALSE. BOOL start(); + // find an instance by ID. Return NULL if it does not exist. + static LLFloaterScriptQueue* findInstance(const LLUUID& id); + protected: LLFloaterScriptQueue(const std::string& name, const LLRect& rect, const std::string& title, const std::string& start_string); @@ -92,9 +95,6 @@ protected: // Get this instances ID. const LLUUID& getID() const { return mID; } - - // find an instance by ID. Return NULL if it does not exist. - static LLFloaterScriptQueue* findInstance(const LLUUID& id); protected: // UI @@ -118,12 +118,29 @@ protected: // This script queue will recompile each script. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +struct LLCompileQueueData +{ + LLUUID mQueueID; + LLUUID mItemId; + LLCompileQueueData(const LLUUID& q_id, const LLUUID& item_id) : + mQueueID(q_id), mItemId(item_id) {} +}; + +class LLAssetUploadQueue; + class LLFloaterCompileQueue : public LLFloaterScriptQueue { public: // Use this method to create a compile queue. Once created, it // will be responsible for it's own destruction. - static LLFloaterCompileQueue* create(); + static LLFloaterCompileQueue* create(BOOL mono); + + static void onSaveBytecodeComplete(const LLUUID& asset_id, + void* user_data, + S32 status); + + // remove any object in mScriptScripts with the matching uuid. + void removeItemByItemID(const LLUUID& item_id); protected: LLFloaterCompileQueue(const std::string& name, const LLRect& rect); @@ -139,6 +156,7 @@ protected: void* user_data, S32 status, LLExtStat ext_status); static void onSaveTextComplete(const LLUUID& asset_id, void* user_data, S32 status, LLExtStat ext_status); + static void onSaveBytecodeComplete(const LLUUID& asset_id, void* user_data, S32 status, LLExtStat ext_status); @@ -149,14 +167,18 @@ protected: // remove any object in mScriptScripts with the matching uuid. void removeItemByAssetID(const LLUUID& asset_id); - // save the items indicatd by the asset id. - void saveItemByAssetID(const LLUUID& asset_id); + // save the items indicated by the item id. + void saveItemByItemID(const LLUUID& item_id); - // find old_asst_id, and set the asset id to new_asset_id - void updateAssetID(const LLUUID& old_asset_id, const LLUUID& new_asset_id); + // find InventoryItem given item id. + const LLInventoryItem* findItemByItemID(const LLUUID& item_id) const; protected: LLViewerInventoryItem::item_array_t mCurrentScripts; + +private: + BOOL mMono; // Compile to mono. + LLAssetUploadQueue* mUploadQueue; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp index 3c1b89d04b..2d0723f1eb 100644 --- a/indra/newview/llfloatertopobjects.cpp +++ b/indra/newview/llfloatertopobjects.cpp @@ -170,6 +170,7 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) F32 score; std::string name_buf; std::string owner_buf; + F32 mono_score; msg->getU32Fast(_PREHASH_ReportData, _PREHASH_TaskLocalID, task_local_id, block); msg->getUUIDFast(_PREHASH_ReportData, _PREHASH_TaskID, task_id, block); @@ -192,6 +193,7 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) element["columns"][0]["column"] = "score"; element["columns"][0]["value"] = llformat("%0.3f", score); element["columns"][0]["font"] = "SANSSERIF"; + element["columns"][1]["column"] = "name"; element["columns"][1]["value"] = name_buf; element["columns"][1]["font"] = "SANSSERIF"; @@ -205,6 +207,14 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) element["columns"][3]["value"] = formatted_time((time_t)time_stamp); element["columns"][3]["font"] = "SANSSERIF"; + if (mCurrentMode == STAT_REPORT_TOP_SCRIPTS) + { + msg->getF32Fast(_PREHASH_ReportData, "MonoScore", mono_score, block); + element["columns"][4]["column"] = "Mono Time"; + element["columns"][4]["value"] = llformat("%0.3f", mono_score); + element["columns"][4]["font"] = "SANSSERIF"; + } + list->addElement(element); mObjectListData.append(element); diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 75e8f52cfc..71733e5cd7 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -139,6 +139,12 @@ const S32 TEXT_EDIT_COLUMN_HEIGHT = 16; const S32 MAX_HISTORY_COUNT = 10; const F32 LIVE_HELP_REFRESH_TIME = 1.f; +static bool have_script_upload_cap(LLUUID& object_id) +{ + LLViewerObject* object = gObjectList.findObject(object_id); + return object && (! object->getRegion()->getCapability("UpdateScriptTaskInventory").empty()); +} + /// --------------------------------------------------------------------------- /// LLFloaterScriptSearch /// --------------------------------------------------------------------------- @@ -173,7 +179,7 @@ private: LLFloaterScriptSearch* LLFloaterScriptSearch::sInstance = NULL; LLFloaterScriptSearch::LLFloaterScriptSearch(std::string title, LLRect rect, LLScriptEdCore* editor_core) - : LLFloater(std::string("script search"),rect,title), mEditorCore(editor_core) + : LLFloater("script search",rect,title), mEditorCore(editor_core) { LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_search.xml"); @@ -306,14 +312,15 @@ LLScriptEdCore::LLScriptEdCore( mUserdata( userdata ), mForceClose( FALSE ), mLastHelpToken(NULL), - mLiveHelpHistorySize(0) + mLiveHelpHistorySize(0), + mEnableSave(FALSE) { setFollowsAll(); setBorderVisible(FALSE); LLUICtrlFactory::getInstance()->buildPanel(this, "floater_script_ed_panel.xml"); - + mErrorList = getChild<LLScrollListCtrl>("lsl errors"); mFunctions = getChild<LLComboBox>( "Insert..."); @@ -439,13 +446,13 @@ BOOL LLScriptEdCore::hasChanged(void* userdata) LLScriptEdCore* self = (LLScriptEdCore*)userdata; if (!self || !self->mEditor) return FALSE; - return !self->mEditor->isPristine(); + return !self->mEditor->isPristine() || self->mEnableSave; } void LLScriptEdCore::draw() { - BOOL script_changed = !mEditor->isPristine(); - childSetEnabled("Save_btn", script_changed); + BOOL script_changed = hasChanged(this); + childSetEnabled("Save_btn", script_changed); if( mEditor->hasFocus() ) { @@ -594,7 +601,7 @@ void LLScriptEdCore::addHelpItemToHistory(const std::string& help_string) BOOL LLScriptEdCore::canClose() { - if(mForceClose || mEditor->isPristine()) + if(mForceClose || !hasChanged(this)) { return TRUE; } @@ -1133,7 +1140,9 @@ void LLPreviewLSL::callbackLSLCompileFailed(const LLSD& compile_errors) line++) { LLSD row; - row["columns"][0]["value"] = line->asString(); + std::string error_message = line->asString(); + LLStringUtil::stripNonprintable(error_message); + row["columns"][0]["value"] = error_message; row["columns"][0]["font"] = "OCRA"; mScriptEd->mErrorList->addElement(row); } @@ -1247,7 +1256,7 @@ void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save) void LLPreviewLSL::saveIfNeeded() { // llinfos << "LLPreviewLSL::saveIfNeeded()" << llendl; - if(mScriptEd->mEditor->isPristine()) + if(!LLScriptEdCore::hasChanged(mScriptEd)) { return; } @@ -1305,7 +1314,8 @@ void LLPreviewLSL::uploadAssetViaCaps(const std::string& url, llinfos << "Update Agent Inventory via capability" << llendl; LLSD body; body["item_id"] = item_id; - LLHTTPClient::post(url, body, new LLUpdateAgentInventoryResponder(body, filename)); + body["target"] = "lsl2"; + LLHTTPClient::post(url, body, new LLUpdateAgentInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); } void LLPreviewLSL::uploadAssetLegacy(const std::string& filename, @@ -1326,9 +1336,12 @@ void LLPreviewLSL::uploadAssetLegacy(const std::string& filename, std::string dst_filename = llformat("%s.lso", filepath.c_str()); std::string err_filename = llformat("%s.out", filepath.c_str()); + const BOOL compile_to_mono = FALSE; if(!lscript_compile(filename.c_str(), dst_filename.c_str(), err_filename.c_str(), + compile_to_mono, + asset_id.asString().c_str(), gAgent.isGodlike())) { llinfos << "Compile failed!" << llendl; @@ -1601,7 +1614,8 @@ LLLiveLSLEditor::LLLiveLSLEditor(const std::string& name, mAskedForRunningInfo(FALSE), mHaveRunningInfo(FALSE), mCloseAfterSave(FALSE), - mPendingUploads(0) + mPendingUploads(0), + mIsModifiable(FALSE) { @@ -1615,13 +1629,14 @@ LLLiveLSLEditor::LLLiveLSLEditor(const std::string& name, LLLiveLSLEditor::sInstances.addData(mItemID ^ mObjectID, this); - - LLCallbackMap::map_t factory_map; factory_map["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this); LLUICtrlFactory::getInstance()->buildFloater(this,"floater_live_lsleditor.xml", &factory_map); - + + mMonoCheckbox = getChild<LLCheckBoxCtrl>("mono"); + childSetCommitCallback("mono", &LLLiveLSLEditor::onMonoCheckboxClicked, this); + childSetEnabled("mono", FALSE); childSetCommitCallback("running", LLLiveLSLEditor::onRunningCheckboxClicked, this); childSetEnabled("running", FALSE); @@ -1633,7 +1648,6 @@ LLLiveLSLEditor::LLLiveLSLEditor(const std::string& name, mScriptEd->mEditor->makePristine(); loadAsset(is_new); mScriptEd->mEditor->setFocus(TRUE); - if (!getHost()) { @@ -1677,7 +1691,9 @@ void LLLiveLSLEditor::callbackLSLCompileFailed(const LLSD& compile_errors) line++) { LLSD row; - row["columns"][0]["value"] = line->asString(); + std::string error_message = line->asString(); + LLStringUtil::stripNonprintable(error_message); + row["columns"][0]["value"] = error_message; row["columns"][0]["font"] = "OCRA"; mScriptEd->mErrorList->addElement(row); } @@ -1712,6 +1728,7 @@ void LLLiveLSLEditor::loadAsset(BOOL is_new) mScriptEd->mEditor->setText(getString("not_allowed")); mScriptEd->mEditor->makePristine(); mScriptEd->mEditor->setEnabled(FALSE); + mScriptEd->enableSave(FALSE); mAssetStatus = PREVIEW_ASSET_LOADED; } else if(item && mItem.notNull()) @@ -1745,12 +1762,14 @@ void LLLiveLSLEditor::loadAsset(BOOL is_new) mAssetStatus = PREVIEW_ASSET_LOADED; } - if(item - && !gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), - GP_OBJECT_MANIPULATE)) + mIsModifiable = item && gAgent.allowOperation(PERM_MODIFY, + item->getPermissions(), + GP_OBJECT_MANIPULATE); + if(!mIsModifiable) { mScriptEd->mEditor->setEnabled(FALSE); } + // This is commented out, because we don't completely // handle script exports yet. /* @@ -1784,8 +1803,7 @@ void LLLiveLSLEditor::loadAsset(BOOL is_new) else { mScriptEd->mEditor->setText(std::string(HELLO_LSL)); - //mScriptEd->mEditor->setText(LLStringUtil::null); - //mScriptEd->mEditor->makePristine(); + mScriptEd->enableSave(FALSE); LLPermissions perm; perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, gAgent.getGroupID()); perm.initMasks(PERM_ALL, PERM_ALL, PERM_NONE, PERM_NONE, PERM_MOVE | PERM_TRANSFER); @@ -1955,22 +1973,43 @@ void LLLiveLSLEditor::draw() { LLViewerObject* object = gObjectList.findObject(mObjectID); LLCheckBoxCtrl* runningCheckbox = getChild<LLCheckBoxCtrl>( "running"); - if(object && mAskedForRunningInfo && mHaveRunningInfo) + if(object && mAskedForRunningInfo && mHaveRunningInfo) { if(object->permAnyOwner()) { runningCheckbox->setLabel(getString("script_running")); runningCheckbox->setEnabled(TRUE); + + if(object->permAnyOwner()) + { + runningCheckbox->setLabel(getString("script_running")); + runningCheckbox->setEnabled(TRUE); + } + else + { + runningCheckbox->setLabel(getString("public_objects_can_not_run")); + runningCheckbox->setEnabled(FALSE); + // *FIX: Set it to false so that the ui is correct for + // a box that is released to public. It could be + // incorrect after a release/claim cycle, but will be + // correct after clicking on it. + runningCheckbox->set(FALSE); + mMonoCheckbox->set(FALSE); + } } else { runningCheckbox->setLabel(getString("public_objects_can_not_run")); runningCheckbox->setEnabled(FALSE); + // *FIX: Set it to false so that the ui is correct for // a box that is released to public. It could be // incorrect after a release/claim cycle, but will be // correct after clicking on it. runningCheckbox->set(FALSE); + mMonoCheckbox->setEnabled(FALSE); + // object may have fallen out of range. + mHaveRunningInfo = FALSE; } } else if(!object) @@ -2044,7 +2083,7 @@ void LLLiveLSLEditor::saveIfNeeded() } // Don't need to save if we're pristine - if(mScriptEd->mEditor->isPristine()) + if(!LLScriptEdCore::hasChanged(mScriptEd)) { return; } @@ -2052,6 +2091,7 @@ void LLLiveLSLEditor::saveIfNeeded() mPendingUploads = 0; // save the script + mScriptEd->enableSave(FALSE); mScriptEd->mEditor->makePristine(); mScriptEd->mErrorList->deleteAllItems(); @@ -2091,7 +2131,7 @@ void LLLiveLSLEditor::saveIfNeeded() fp = NULL; // save it out to asset server - std::string url = gAgent.getRegion()->getCapability("UpdateScriptTaskInventory"); + std::string url = object->getRegion()->getCapability("UpdateScriptTaskInventory"); getWindow()->incBusyCount(); mPendingUploads++; BOOL is_running = getChild<LLCheckBoxCtrl>( "running")->get(); @@ -2117,8 +2157,9 @@ void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url, body["task_id"] = task_id; body["item_id"] = item_id; body["is_script_running"] = is_running; + body["target"] = monoChecked() ? "mono" : "lsl2"; LLHTTPClient::post(url, body, - new LLUpdateTaskInventoryResponder(body, filename)); + new LLUpdateTaskInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); } void LLLiveLSLEditor::uploadAssetLegacy(const std::string& filename, @@ -2141,9 +2182,12 @@ void LLLiveLSLEditor::uploadAssetLegacy(const std::string& filename, std::string err_filename = llformat("%s.out", filepath.c_str()); LLFILE *fp; + const BOOL compile_to_mono = FALSE; if(!lscript_compile(filename.c_str(), dst_filename.c_str(), err_filename.c_str(), + compile_to_mono, + asset_id.asString().c_str(), gAgent.isGodlike())) { // load the error file into the error scrolllist @@ -2384,6 +2428,11 @@ void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**) msg->getBOOLFast(_PREHASH_Script, _PREHASH_Running, running); LLCheckBoxCtrl* runningCheckbox = instance->getChild<LLCheckBoxCtrl>("running"); runningCheckbox->set(running); + BOOL mono; + msg->getBOOLFast(_PREHASH_Script, "Mono", mono); + LLCheckBoxCtrl* monoCheckbox = instance->getChild<LLCheckBoxCtrl>("mono"); + monoCheckbox->setEnabled(instance->getIsModifiable() && have_script_upload_cap(object_id)); + monoCheckbox->set(mono); } } @@ -2398,3 +2447,19 @@ void LLLiveLSLEditor::reshape(S32 width, S32 height, BOOL called_from_parent) gSavedSettings.setRect("PreviewScriptRect", getRect()); } } + +void LLLiveLSLEditor::onMonoCheckboxClicked(LLUICtrl*, void* userdata) +{ + LLLiveLSLEditor* self = static_cast<LLLiveLSLEditor*>(userdata); + self->mMonoCheckbox->setEnabled(have_script_upload_cap(self->mObjectID)); + self->mScriptEd->enableSave(self->getIsModifiable()); +} + +BOOL LLLiveLSLEditor::monoChecked() const +{ + if(NULL != mMonoCheckbox) + { + return mMonoCheckbox->getValue()? TRUE : FALSE; + } + return FALSE; +} diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index aec4bb2ab7..ca1c527cb2 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -118,13 +118,14 @@ public: void selectFirstError(); virtual BOOL handleKeyHere(KEY key, MASK mask); + + void enableSave(BOOL b) {mEnableSave = b;} protected: void deleteBridges(); void setHelpPage(const std::string& help_string); void updateDynamicHelp(BOOL immediate = FALSE); void addHelpItemToHistory(const std::string& help_string); - static void onErrorList(LLUICtrl*, void* user_data); virtual const char *getTitleName() const { return "Script"; } @@ -147,6 +148,7 @@ private: LLKeywordToken* mLastHelpToken; LLFrameTimer mLiveHelpTimer; S32 mLiveHelpHistorySize; + BOOL mEnableSave; }; @@ -184,8 +186,9 @@ protected: void* user_data, S32 status, LLExtStat ext_status); static void onSaveComplete(const LLUUID& uuid, void* user_data, S32 status, LLExtStat ext_status); static void onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status); +public: static LLPreviewLSL* getInstance(const LLUUID& uuid); - +protected: static void* createScriptEdPanel(void* userdata); @@ -195,6 +198,7 @@ protected: LLScriptEdCore* mScriptEd; // Can safely close only after both text and bytecode are uploaded S32 mPendingUploads; + }; @@ -277,6 +281,15 @@ protected: S32 mPendingUploads; static LLMap<LLUUID, LLLiveLSLEditor*> sInstances; + BOOL getIsModifiable() const { return mIsModifiable; } // Evaluated on load assert + +private: + + static void onMonoCheckboxClicked(LLUICtrl*, void* userdata); + BOOL monoChecked() const; + + LLCheckBoxCtrl* mMonoCheckbox; + BOOL mIsModifiable; }; #endif // LL_LLPREVIEWSCRIPT_H diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index e37de3b2de..d24c738f2c 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3381,13 +3381,13 @@ void init_stat_view() stat_barp->mDisplayBar = FALSE; stat_barp->mDisplayMean = FALSE; - stat_barp = sim_statviewp->addStat("Script Perf", &(LLViewerStats::getInstance()->mSimLSLIPS)); - stat_barp->setUnitLabel(" ips"); + stat_barp = sim_statviewp->addStat("Script Events", &(LLViewerStats::getInstance()->mSimScriptEPS)); + stat_barp->setUnitLabel(" eps"); stat_barp->mPrecision = 0; stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 100000.f; - stat_barp->mTickSpacing = 25000.f; - stat_barp->mLabelSpacing = 50000.f; + stat_barp->mMaxBar = 20000.f; + stat_barp->mTickSpacing = 2500.f; + stat_barp->mLabelSpacing = 5000.f; stat_barp->mPerSec = FALSE; stat_barp->mDisplayBar = FALSE; stat_barp->mDisplayMean = FALSE; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index a095c9e159..771a71c5c5 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -6160,9 +6160,13 @@ class LLToolsSelectedScriptAction : public view_listener_t { std::string action = userdata.asString(); LLFloaterScriptQueue* queue = NULL; - if (action == "compile") + if (action == "compile mono") { - queue = LLFloaterCompileQueue::create(); + queue = LLFloaterCompileQueue::create(TRUE); + } + if (action == "compile lsl") + { + queue = LLFloaterCompileQueue::create(FALSE); } else if (action == "reset") { @@ -6405,16 +6409,36 @@ BOOL enable_more_than_one_selected(void* ) return (LLSelectMgr::getInstance()->getSelection()->getObjectCount() > 1); } +static bool is_editable_selected() +{ + return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); +} + class LLEditableSelected : public view_listener_t { bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) { - bool new_value = (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); + gMenuHolder->findControl(userdata["control"].asString())->setValue(is_editable_selected()); return true; } }; +class LLEditableSelectedMono : public view_listener_t +{ + bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) + { + LLViewerRegion* region = gAgent.getRegion(); + if(region && gMenuHolder && gMenuHolder->findControl(userdata["control"].asString())) + { + bool have_cap = (! region->getCapability("UpdateScriptTaskInventory").empty()); + bool selected = is_editable_selected() && have_cap; + gMenuHolder->findControl(userdata["control"].asString())->setValue(selected); + return true; + } + return false; + } +}; + class LLToolsEnableTakeCopy : public view_listener_t { bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) @@ -7842,4 +7866,5 @@ void initialize_menus() addMenu(new LLSomethingSelected(), "SomethingSelected"); addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD"); addMenu(new LLEditableSelected(), "EditableSelected"); + addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index a082d6f1b5..d440491661 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3464,8 +3464,8 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data) case LL_SIM_STAT_NUMSCRIPTSACTIVE: LLViewerStats::getInstance()->mSimActiveScripts.addValue(stat_value); break; - case LL_SIM_STAT_LSLIPS: - LLViewerStats::getInstance()->mSimLSLIPS.addValue(stat_value); + case LL_SIM_STAT_SCRIPT_EPS: + LLViewerStats::getInstance()->mSimScriptEPS.addValue(stat_value); break; case LL_SIM_STAT_INPPS: LLViewerStats::getInstance()->mSimInPPS.addValue(stat_value); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 1aa7d2c3ff..8745a73e79 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -2145,7 +2145,7 @@ void LLViewerObject::deleteInventoryItem(const LLUUID& item_id) } void LLViewerObject::doUpdateInventory( - LLViewerInventoryItem* item, + LLPointer<LLViewerInventoryItem>& item, U8 key, bool is_new) { @@ -2217,7 +2217,8 @@ void LLViewerObject::doUpdateInventory( --mInventorySerialNum; } } - LLViewerInventoryItem* new_item = new LLViewerInventoryItem(item); + LLViewerInventoryItem* oldItem = item; + LLViewerInventoryItem* new_item = new LLViewerInventoryItem(oldItem); new_item->setPermissions(perm); mInventory->push_front(new_item); doInventoryCallback(); @@ -2608,6 +2609,21 @@ void LLViewerObject::updateInventory( doUpdateInventory(task_item, key, is_new); } +void LLViewerObject::updateInventoryLocal(LLInventoryItem* item, U8 key) +{ + LLPointer<LLViewerInventoryItem> task_item = + new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(), + item->getAssetUUID(), item->getType(), + item->getInventoryType(), + item->getName(), item->getDescription(), + item->getSaleInfo(), item->getFlags(), + item->getCreationDate()); + + // do the internal logic + const bool is_new = false; + doUpdateInventory(task_item, key, is_new); +} + LLInventoryObject* LLViewerObject::getInventoryObject(const LLUUID& item_id) { LLInventoryObject* rv = NULL; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index a143589ee9..1fd4a29238 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -384,6 +384,7 @@ public: // manager, so do no call updateInventory() from the selection // manager until we have better iterators. void updateInventory(LLViewerInventoryItem* item, U8 key, bool is_new); + void updateInventoryLocal(LLInventoryItem* item, U8 key); // Update without messaging. LLInventoryObject* getInventoryObject(const LLUUID& item_id); void getInventoryContents(InventoryObjectList& objects); LLInventoryObject* getInventoryRoot(); @@ -540,7 +541,7 @@ protected: // do the update/caching logic. called by saveScript and // updateInventory. - void doUpdateInventory(LLViewerInventoryItem* item, U8 key, bool is_new); + void doUpdateInventory(LLPointer<LLViewerInventoryItem>& item, U8 key, bool is_new); static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp); diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index ccd3110758..446f8f026a 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -63,7 +63,7 @@ public: LLStat mSimFPS; LLStat mSimPhysicsFPS; LLStat mSimAgentUPS; - LLStat mSimLSLIPS; + LLStat mSimScriptEPS; LLStat mSimFrameMsec; LLStat mSimNetMsec; diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc index 20a572c8e0..a39bb9faf6 100644 --- a/indra/newview/res/viewerRes.rc +++ b/indra/newview/res/viewerRes.rc @@ -231,8 +231,8 @@ TOOLMEDIAOPEN CURSOR "toolmediaopen.cur" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,19,1,83014 - PRODUCTVERSION 1,19,1,83014 + FILEVERSION 1,20,9,87416 + PRODUCTVERSION 1,20,9,87416 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -249,12 +249,12 @@ BEGIN BEGIN VALUE "CompanyName", "Linden Lab" VALUE "FileDescription", "Second Life" - VALUE "FileVersion", "1.19.1.83014" + VALUE "FileVersion", "1.20.9.87416" VALUE "InternalName", "Second Life" VALUE "LegalCopyright", "Copyright © 2001-2008, Linden Research, Inc." VALUE "OriginalFilename", "SecondLife.exe" VALUE "ProductName", "Second Life" - VALUE "ProductVersion", "1.19.1.83014" + VALUE "ProductVersion", "1.20.9.87416" END END BLOCK "VarFileInfo" diff --git a/indra/test/llassetuploadqueue_tut.cpp b/indra/test/llassetuploadqueue_tut.cpp new file mode 100644 index 0000000000..7c4b8a0c9c --- /dev/null +++ b/indra/test/llassetuploadqueue_tut.cpp @@ -0,0 +1,178 @@ +/** + * @file asset_upload_queue_tut.cpp + * @brief Tests for newview/llassetuploadqueue.cpp + * Copyright (c) 2007, Linden Research, Inc. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lltut.h" + +#include "mock_http_client.h" +#include "../newview/llassetuploadqueue.cpp" + +// Mock implementation. +LLAssetUploadResponder::LLAssetUploadResponder(const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type) +{ +} + +LLAssetUploadResponder::LLAssetUploadResponder(const LLSD& post_data, const std::string& file_name) +{ +} + +LLAssetUploadResponder::~LLAssetUploadResponder() +{ +} + +void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason) +{ +} + +void LLAssetUploadResponder::result(const LLSD& content) +{ +} + +void LLAssetUploadResponder::uploadUpload(const LLSD& content) +{ +} + +void LLAssetUploadResponder::uploadComplete(const LLSD& content) +{ +} + +void LLAssetUploadResponder::uploadFailure(const LLSD& content) +{ +} + +LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type) : + LLAssetUploadResponder(post_data, vfile_id, asset_type) +{ +} + +LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data, + const std::string& file_name) : + LLAssetUploadResponder(post_data, file_name) +{ +} + +LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data, + const std::string& file_name, + const LLUUID& queue_id) : + LLAssetUploadResponder(post_data, file_name) +{ +} + +void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) +{ +} + +namespace tut +{ + class asset_upload_queue_test_data : public MockHttpClient {}; + typedef test_group<asset_upload_queue_test_data> asset_upload_queue_test; + typedef asset_upload_queue_test::object asset_upload_queue_object; + tut::asset_upload_queue_test asset_upload_queue("asset_upload_queue"); + + void queue(LLAssetUploadQueue& q, const std::string& filename) + { + LLUUID task_id; + LLUUID item_id; + BOOL is_running = FALSE; + BOOL is_target_mono = TRUE; + LLUUID queue_id; + q.queue(filename, task_id, item_id, is_running, is_target_mono, queue_id); + } + + class LLTestSupplier : public LLAssetUploadQueueSupplier + { + public: + + void set(LLAssetUploadQueue* queue) {mQueue = queue;} + + virtual LLAssetUploadQueue* get() const + { + return mQueue; + } + + private: + LLAssetUploadQueue* mQueue; + }; + + template<> template<> + void asset_upload_queue_object::test<1>() + { + setupTheServer(); + reset(); + LLTestSupplier* supplier = new LLTestSupplier(); + LLAssetUploadQueue q("http://localhost:8888/test/success", supplier); + supplier->set(&q); + queue(q, "foo.bar"); + ensure("upload queue not empty before request", q.isEmpty()); + runThePump(10); + ensure("upload queue not empty after request", q.isEmpty()); + } + + template<> template<> + void asset_upload_queue_object::test<2>() + { + reset(); + LLTestSupplier* supplier = new LLTestSupplier(); + LLAssetUploadQueue q("http://localhost:8888/test/error", supplier); + supplier->set(&q); + queue(q, "foo.bar"); + ensure("upload queue not empty before request", q.isEmpty()); + runThePump(10); + ensure("upload queue not empty after request", q.isEmpty()); + } + + template<> template<> + void asset_upload_queue_object::test<3>() + { + reset(); + LLTestSupplier* supplier = new LLTestSupplier(); + LLAssetUploadQueue q("http://localhost:8888/test/timeout", supplier); + supplier->set(&q); + queue(q, "foo.bar"); + ensure("upload queue not empty before request", q.isEmpty()); + runThePump(10); + ensure("upload queue not empty after request", q.isEmpty()); + } + + template<> template<> + void asset_upload_queue_object::test<4>() + { + reset(); + LLTestSupplier* supplier = new LLTestSupplier(); + LLAssetUploadQueue q("http://localhost:8888/test/success", supplier); + supplier->set(&q); + queue(q, "foo.bar"); + queue(q, "baz.bar"); + ensure("upload queue empty before request", !q.isEmpty()); + runThePump(10); + ensure("upload queue not empty before request", q.isEmpty()); + runThePump(10); + ensure("upload queue not empty after request", q.isEmpty()); + } + + template<> template<> + void asset_upload_queue_object::test<5>() + { + reset(); + LLTestSupplier* supplier = new LLTestSupplier(); + LLAssetUploadQueue q("http://localhost:8888/test/success", supplier); + supplier->set(&q); + queue(q, "foo.bar"); + runThePump(10); + ensure("upload queue not empty before request", q.isEmpty()); + queue(q, "baz.bar"); + ensure("upload queue not empty after request", q.isEmpty()); + runThePump(10); + killServer(); + } +} diff --git a/indra/test/mock_http_client.cpp b/indra/test/mock_http_client.cpp new file mode 100644 index 0000000000..6b273ee7b5 --- /dev/null +++ b/indra/test/mock_http_client.cpp @@ -0,0 +1,66 @@ +/** + * @file mock_http_client.cpp + * @brief Framework for testing HTTP requests + * Copyright (c) 2007, Linden Research, Inc. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llsdhttpserver.h" +#include "lliohttpserver.h" + +namespace tut +{ + class SuccessNode : public LLHTTPNode + { + public: + void get(ResponsePtr r, const LLSD& context) const + { + LLSD result; + result["state"] = "complete"; + result["test"] = "test"; + r->result(result); + } + void post(ResponsePtr r, const LLSD& context, const LLSD& input) const + { + LLSD result; + result["state"] = "complete"; + result["test"] = "test"; + r->result(result); + } + }; + + class ErrorNode : public LLHTTPNode + { + public: + void get(ResponsePtr r, const LLSD& context) const + { r->status(599, "Intentional error"); } + void post(ResponsePtr r, const LLSD& context, const LLSD& input) const + { r->status(input["status"], input["reason"]); } + }; + + class TimeOutNode : public LLHTTPNode + { + public: + void get(ResponsePtr r, const LLSD& context) const + { + /* do nothing, the request will eventually time out */ + } + }; + + LLSD storage; + + class LLSDStorageNode : public LLHTTPNode + { + public: + LLSD get() const{ return storage; } + LLSD put(const LLSD& value) const{ storage = value; return LLSD(); } + }; + + LLHTTPRegistration<LLSDStorageNode> gStorageNode("/test/storage"); + LLHTTPRegistration<SuccessNode> gSuccessNode("/test/success"); + LLHTTPRegistration<ErrorNode> gErrorNode("/test/error"); + LLHTTPRegistration<TimeOutNode> gTimeOutNode("/test/timeout"); +} diff --git a/indra/test/mock_http_client.h b/indra/test/mock_http_client.h new file mode 100644 index 0000000000..6476ea3783 --- /dev/null +++ b/indra/test/mock_http_client.h @@ -0,0 +1,174 @@ +/** + * @file mock_http_client.cpp + * @brief Framework for testing HTTP requests + * Copyright (c) 2007, Linden Research, Inc. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * $/LicenseInfo$ + */ + +#include "llsdhttpserver.h" +#include "lliohttpserver.h" +#include "llhttpclient.h" +#include "llformat.h" +#include "llpipeutil.h" +#include "llpumpio.h" + +namespace tut +{ + struct MockHttpClient + { + public: + MockHttpClient() + { + apr_pool_create(&mPool, NULL); + mServerPump = new LLPumpIO(mPool); + mClientPump = new LLPumpIO(mPool); + + LLHTTPClient::setPump(*mClientPump); + } + + ~MockHttpClient() + { + delete mServerPump; + delete mClientPump; + apr_pool_destroy(mPool); + } + + void setupTheServer() + { + LLHTTPNode& root = LLIOHTTPServer::create(mPool, *mServerPump, 8888); + + LLHTTPStandardServices::useServices(); + LLHTTPRegistrar::buildAllServices(root); + } + + void runThePump(float timeout = 100.0f) + { + LLTimer timer; + timer.setTimerExpirySec(timeout); + + while(!mSawCompleted && !timer.hasExpired()) + { + if (mServerPump) + { + mServerPump->pump(); + mServerPump->callback(); + } + if (mClientPump) + { + mClientPump->pump(); + mClientPump->callback(); + } + } + } + + void killServer() + { + delete mServerPump; + mServerPump = NULL; + } + + private: + apr_pool_t* mPool; + LLPumpIO* mServerPump; + LLPumpIO* mClientPump; + + + protected: + void ensureStatusOK() + { + if (mSawError) + { + std::string msg = + llformat("error() called when not expected, status %d", + mStatus); + fail(msg); + } + } + + void ensureStatusError() + { + if (!mSawError) + { + fail("error() wasn't called"); + } + } + + LLSD getResult() + { + return mResult; + } + + protected: + bool mSawError; + U32 mStatus; + std::string mReason; + bool mSawCompleted; + LLSD mResult; + bool mResultDeleted; + + class Result : public LLHTTPClient::Responder + { + protected: + Result(MockHttpClient& client) + : mClient(client) + { + } + + public: + static boost::intrusive_ptr<Result> build(MockHttpClient& client) + { + return boost::intrusive_ptr<Result>(new Result(client)); + } + + ~Result() + { + mClient.mResultDeleted = true; + } + + virtual void error(U32 status, const std::string& reason) + { + mClient.mSawError = true; + mClient.mStatus = status; + mClient.mReason = reason; + } + + virtual void result(const LLSD& content) + { + mClient.mResult = content; + } + + virtual void completed( + U32 status, const std::string& reason, + const LLSD& content) + { + LLHTTPClient::Responder::completed(status, reason, content); + + mClient.mSawCompleted = true; + } + + private: + MockHttpClient& mClient; + }; + + friend class Result; + + protected: + + void reset() + { + mSawError = false; + mStatus = 0; + mSawCompleted = false; + mResult.clear(); + mResultDeleted = false; + } + + LLHTTPClient::ResponderPtr newResult() + { + reset(); + return Result::build(*this); + } + }; +} |