Merge remote-tracking branch 'origin/master' into refactor_shaders
Conflicts: src/tracks/track_object_presentation.cpp
This commit is contained in:
commit
a51d56a6e5
@ -121,9 +121,15 @@ elseif(MSVC)
|
||||
endif()
|
||||
|
||||
|
||||
# Build the angelscript library
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/lib/angelscript/projects/cmake")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/lib/angelscript/include")
|
||||
# Build the angelscript library if not in system
|
||||
find_package(Angelscript)
|
||||
if(ANGELSCRIPT_FOUND)
|
||||
include_directories(${Angelscript_INCLUDE_DIRS})
|
||||
else()
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/lib/angelscript/projects/cmake")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/lib/angelscript/include")
|
||||
set(Angelscript_LIBRARIES angelscript)
|
||||
endif()
|
||||
|
||||
# OpenAL
|
||||
if(APPLE)
|
||||
@ -310,7 +316,7 @@ target_link_libraries(supertuxkart
|
||||
enet
|
||||
glew
|
||||
stkirrlicht
|
||||
angelscript
|
||||
${Angelscript_LIBRARIES}
|
||||
${CURL_LIBRARIES}
|
||||
${OGGVORBIS_LIBRARIES}
|
||||
${OPENAL_LIBRARY}
|
||||
|
33
cmake/FindAngelscript.cmake
Normal file
33
cmake/FindAngelscript.cmake
Normal file
@ -0,0 +1,33 @@
|
||||
# - Try to find angelscript
|
||||
# Once done this will define
|
||||
#
|
||||
# ANGELSCRIPT_FOUND - system has angelscript
|
||||
# Angelscript_INCLUDE_DIRS - the angelscript include directory
|
||||
# Angelscript_LIBRARIES - the libraries needed to use angelscript
|
||||
#
|
||||
|
||||
FIND_PATH(Angelscript_INCLUDE_DIRS angelscript.h
|
||||
PATHS
|
||||
/usr/local
|
||||
/usr
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(Angelscript_LIBRARY
|
||||
NAMES angelscript
|
||||
PATHS
|
||||
/usr/local
|
||||
/usr
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set ANGELSCRIPT_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Angelscript DEFAULT_MSG Angelscript_LIBRARY Angelscript_INCLUDE_DIRS)
|
||||
|
||||
IF (ANGELSCRIPT_FOUND)
|
||||
SET(Angelscript_LIBRARIES ${Angelscript_LIBRARY})
|
||||
ENDIF (ANGELSCRIPT_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(Angelscript_LIBRARY Angelscript_LIBRARIES Angelscript_INCLUDE_DIRS)
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 154 KiB |
@ -17,6 +17,9 @@
|
||||
<card contains="Gallium" os="linux" version="<10.3" disable="DriverRecentEnough"/>
|
||||
<card contains="Gallium" os="linux" version="<10.6" disable="GeometryShader4"/>
|
||||
<card contains="Gallium" os="linux" disable="TextureCompressionS3TC"/>
|
||||
<card contains="Radeon" version="<14.300" disable="DriverRecentEnough"/>
|
||||
<!-- On osx radeon appears to have different version numbers, e.g.
|
||||
1.32.20 -->
|
||||
<card contains="Radeon" os="linux" version="<14.300" disable="DriverRecentEnough"/>
|
||||
<card contains="Radeon" os="windows" version="<14.300" disable="DriverRecentEnough"/>
|
||||
</graphical-restrictions>
|
||||
|
||||
|
17
data/gui/scripting_console.stkgui
Normal file
17
data/gui/scripting_console.stkgui
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<stkgui>
|
||||
<div x="2%" y="10%" width="96%" height="80%" layout="vertical-row" >
|
||||
|
||||
<label raw_text="Run script"/>
|
||||
|
||||
<textbox id="textfield" width="75%" I18N="In the 'add new grand prix' dialog" align="center"/>
|
||||
|
||||
<spacer height="20" width="20" />
|
||||
|
||||
<div align="center" height="fit" width="100%" layout="horizontal-row">
|
||||
<button id="run" raw_text="Run" align="center" proportion="1"/>
|
||||
<spacer height="20" width="20" />
|
||||
<button id="close" raw_text="Close" align="center" proportion="1"/>
|
||||
</div>
|
||||
</div>
|
||||
</stkgui>
|
@ -17,11 +17,13 @@ XML_FILE_LIST="`find ./data ../stk-assets/tracks ../stk-assets/karts \
|
||||
-name '*.grandprix' -or \
|
||||
-name '*.stkgui' \
|
||||
`"
|
||||
ANGELSCRIPT_FILE_LIST="`find ./data ../stk-assets/tracks -name '*.as'`"
|
||||
|
||||
echo "--------------------"
|
||||
echo " Source Files :"
|
||||
echo "--------------------"
|
||||
echo $CPP_FILE_LIST
|
||||
echo $ANGELSCRIPT_FILE_LIST
|
||||
|
||||
echo "--------------------"
|
||||
echo " XML Files :"
|
||||
@ -37,18 +39,22 @@ echo "---------------------------"
|
||||
echo " Generating .pot file..."
|
||||
|
||||
# XML Files
|
||||
xgettext -d supertuxkart -s --keyword=_ --add-comments="I18N:" \
|
||||
xgettext -d supertuxkart --keyword=_ --add-comments="I18N:" \
|
||||
-p ./data/po -o supertuxkart.pot \
|
||||
--no-location --from-code=UTF-8 ./data/po/gui_strings.h \
|
||||
--package-name=supertuxkart
|
||||
|
||||
# C++ Files
|
||||
xgettext -j -d supertuxkart -s --keyword=_ --keyword=N_ --keyword=_LTR \
|
||||
xgettext -j -d supertuxkart --keyword=_ --keyword=N_ --keyword=_LTR \
|
||||
--keyword=_C:1c,2 --keyword=_P:1,2 \
|
||||
--keyword=_CP:1c,2,3 --add-comments="I18N:" \
|
||||
-p ./data/po -o supertuxkart.pot $CPP_FILE_LIST \
|
||||
--package-name=supertuxkart
|
||||
|
||||
# Angelscript files (xgettext doesn't support AS so pretend it's c++)
|
||||
xgettext -j -d supertuxkart -s --keyword="translate" --add-comments="I18N:" \
|
||||
-p ./data/po -o supertuxkart.pot $ANGELSCRIPT_FILE_LIST \
|
||||
--package-name=supertuxkart --language=c++
|
||||
|
||||
|
||||
echo " Done"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,116 +1,155 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE)
|
||||
cmake_policy(SET CMP0003 NEW)
|
||||
|
||||
project(angelscript)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared library" OFF)
|
||||
|
||||
if(APPLE)
|
||||
option(BUILD_FRAMEWORK "Build Framework bundle for OSX" OFF)
|
||||
endif()
|
||||
|
||||
set(ANGELSCRIPT_VERSION_MAJOR 2)
|
||||
set(ANGELSCRIPT_VERSION_MINOR 30)
|
||||
set(ANGELSCRIPT_VERSION_PATCH 0)
|
||||
set(PROJECT_VERSION ${ANGELSCRIPT_VERSION_MAJOR}.${ANGELSCRIPT_VERSION_MINOR}.${ANGELSCRIPT_VERSION_PATCH})
|
||||
|
||||
find_package(Threads)
|
||||
|
||||
set(ANGELSCRIPT_HEADERS
|
||||
../../include/angelscript.h
|
||||
../../source/as_array.h
|
||||
../../source/as_builder.h
|
||||
../../source/as_bytecode.h
|
||||
../../source/as_callfunc.h
|
||||
../../source/as_compiler.h
|
||||
../../source/as_config.h
|
||||
../../source/as_configgroup.h
|
||||
../../source/as_context.h
|
||||
../../source/as_criticalsection.h
|
||||
../../source/as_datatype.h
|
||||
../../source/as_debug.h
|
||||
../../source/as_generic.h
|
||||
../../source/as_map.h
|
||||
../../source/as_memory.h
|
||||
../../source/as_module.h
|
||||
../../source/as_objecttype.h
|
||||
../../source/as_outputbuffer.h
|
||||
../../source/as_parser.h
|
||||
../../source/as_property.h
|
||||
../../source/as_restore.h
|
||||
../../source/as_scriptcode.h
|
||||
../../source/as_scriptengine.h
|
||||
../../source/as_scriptfunction.h
|
||||
../../source/as_scriptnode.h
|
||||
../../source/as_scriptobject.h
|
||||
../../source/as_string.h
|
||||
../../source/as_string_util.h
|
||||
../../source/as_texts.h
|
||||
../../source/as_thread.h
|
||||
../../source/as_tokendef.h
|
||||
../../source/as_tokenizer.h
|
||||
../../source/as_typeinfo.h
|
||||
../../source/as_variablescope.h
|
||||
)
|
||||
|
||||
set(ANGELSCRIPT_SOURCE
|
||||
../../source/as_atomic.cpp
|
||||
../../source/as_builder.cpp
|
||||
../../source/as_bytecode.cpp
|
||||
../../source/as_callfunc.cpp
|
||||
../../source/as_callfunc_x86.cpp
|
||||
../../source/as_callfunc_x64_gcc.cpp
|
||||
../../source/as_callfunc_x64_msvc.cpp
|
||||
../../source/as_callfunc_x64_mingw.cpp
|
||||
../../source/as_compiler.cpp
|
||||
../../source/as_configgroup.cpp
|
||||
../../source/as_context.cpp
|
||||
../../source/as_datatype.cpp
|
||||
../../source/as_gc.cpp
|
||||
../../source/as_generic.cpp
|
||||
../../source/as_globalproperty.cpp
|
||||
../../source/as_memory.cpp
|
||||
../../source/as_module.cpp
|
||||
../../source/as_objecttype.cpp
|
||||
../../source/as_outputbuffer.cpp
|
||||
../../source/as_parser.cpp
|
||||
../../source/as_restore.cpp
|
||||
../../source/as_scriptcode.cpp
|
||||
../../source/as_scriptengine.cpp
|
||||
../../source/as_scriptfunction.cpp
|
||||
../../source/as_scriptnode.cpp
|
||||
../../source/as_scriptobject.cpp
|
||||
../../source/as_string.cpp
|
||||
../../source/as_string_util.cpp
|
||||
../../source/as_thread.cpp
|
||||
../../source/as_tokenizer.cpp
|
||||
../../source/as_typeinfo.cpp
|
||||
../../source/as_variablescope.cpp
|
||||
../../source/as_atomic.cpp
|
||||
../../source/as_builder.cpp
|
||||
../../source/as_bytecode.cpp
|
||||
../../source/as_callfunc.cpp
|
||||
../../source/as_callfunc_x86.cpp
|
||||
../../source/as_callfunc_x64_gcc.cpp
|
||||
../../source/as_callfunc_x64_msvc.cpp
|
||||
../../source/as_callfunc_x64_mingw.cpp
|
||||
../../source/as_compiler.cpp
|
||||
../../source/as_configgroup.cpp
|
||||
../../source/as_context.cpp
|
||||
../../source/as_datatype.cpp
|
||||
../../source/as_gc.cpp
|
||||
../../source/as_generic.cpp
|
||||
../../source/as_globalproperty.cpp
|
||||
../../source/as_memory.cpp
|
||||
../../source/as_module.cpp
|
||||
../../source/as_objecttype.cpp
|
||||
../../source/as_outputbuffer.cpp
|
||||
../../source/as_parser.cpp
|
||||
../../source/as_restore.cpp
|
||||
../../source/as_scriptcode.cpp
|
||||
../../source/as_scriptengine.cpp
|
||||
../../source/as_scriptfunction.cpp
|
||||
../../source/as_scriptnode.cpp
|
||||
../../source/as_scriptobject.cpp
|
||||
../../source/as_string.cpp
|
||||
../../source/as_string_util.cpp
|
||||
../../source/as_thread.cpp
|
||||
../../source/as_tokenizer.cpp
|
||||
../../source/as_typeinfo.cpp
|
||||
../../source/as_variablescope.cpp
|
||||
)
|
||||
|
||||
if(MSVC AND CMAKE_CL_64)
|
||||
enable_language(ASM_MASM)
|
||||
if(CMAKE_ASM_MASM_COMPILER_WORKS)
|
||||
set(ANGELSCRIPT_SOURCE ${ANGELSCRIPT_SOURCE} ../../source/as_callfunc_x64_msvc_asm.asm)
|
||||
else()
|
||||
message(FATAL ERROR "MSVC x86_64 target requires a working assembler")
|
||||
endif()
|
||||
enable_language(ASM_MASM)
|
||||
if(CMAKE_ASM_MASM_COMPILER_WORKS)
|
||||
set(ANGELSCRIPT_SOURCE ${ANGELSCRIPT_SOURCE} ../../source/as_callfunc_x64_msvc_asm.asm)
|
||||
else()
|
||||
message(FATAL ERROR "MSVC x86_64 target requires a working assembler")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
enable_language(ASM)
|
||||
if(CMAKE_ASM_COMPILER_WORKS)
|
||||
set(ANGELSCRIPT_SOURCE ${ANGELSCRIPT_SOURCE} ../../source/as_callfunc_arm.cpp ../../source/as_callfunc_arm_gcc.S)
|
||||
else()
|
||||
message(FATAL ERROR "Android target requires a working assembler")
|
||||
endif(CMAKE_ASM_COMPILER_WORKS)
|
||||
enable_language(ASM)
|
||||
if(CMAKE_ASM_COMPILER_WORKS)
|
||||
set(ANGELSCRIPT_SOURCE ${ANGELSCRIPT_SOURCE} ../../source/as_callfunc_arm.cpp ../../source/as_callfunc_arm_gcc.S)
|
||||
else()
|
||||
message(FATAL ERROR "Android target requires a working assembler")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(ANGELSCRIPT_HEADERS
|
||||
../../include/angelscript.h
|
||||
../../source/as_array.h
|
||||
../../source/as_builder.h
|
||||
../../source/as_bytecode.h
|
||||
../../source/as_callfunc.h
|
||||
../../source/as_compiler.h
|
||||
../../source/as_config.h
|
||||
../../source/as_configgroup.h
|
||||
../../source/as_context.h
|
||||
../../source/as_criticalsection.h
|
||||
../../source/as_datatype.h
|
||||
../../source/as_debug.h
|
||||
../../source/as_generic.h
|
||||
../../source/as_map.h
|
||||
../../source/as_memory.h
|
||||
../../source/as_module.h
|
||||
../../source/as_objecttype.h
|
||||
../../source/as_outputbuffer.h
|
||||
../../source/as_parser.h
|
||||
../../source/as_property.h
|
||||
../../source/as_restore.h
|
||||
../../source/as_scriptcode.h
|
||||
../../source/as_scriptengine.h
|
||||
../../source/as_scriptfunction.h
|
||||
../../source/as_scriptnode.h
|
||||
../../source/as_scriptobject.h
|
||||
../../source/as_string.h
|
||||
../../source/as_string_util.h
|
||||
../../source/as_texts.h
|
||||
../../source/as_thread.h
|
||||
../../source/as_tokendef.h
|
||||
../../source/as_tokenizer.h
|
||||
../../source/as_typeinfo.h
|
||||
../../source/as_variablescope.h
|
||||
)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../include)
|
||||
|
||||
add_definitions("-D_CRT_SECURE_NO_WARNINGS -DANGELSCRIPT_EXPORT -D_LIB")
|
||||
if(MSVC)
|
||||
set(CMAKE_DEBUG_POSTFIX "d")
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
add_definitions(-DANGELSCRIPT_EXPORT -D_LIB)
|
||||
|
||||
# Fix x64 issues on Linux
|
||||
if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" AND NOT APPLE)
|
||||
add_definitions(-fPIC)
|
||||
add_definitions(-fPIC)
|
||||
endif()
|
||||
|
||||
add_library(angelscript STATIC ${ANGELSCRIPT_SOURCE} ${ANGELSCRIPT_HEADERS})
|
||||
if(NOT BUILD_FRAMEWORK)
|
||||
set(ANGELSCRIPT_LIBRARY_NAME angelscript)
|
||||
else()
|
||||
set(ANGELSCRIPT_LIBRARY_NAME Angelscript) # OS X frameworks should have capitalized name
|
||||
set(BUILD_SHARED_LIBS TRUE)
|
||||
endif()
|
||||
|
||||
#set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../lib)
|
||||
add_library(${ANGELSCRIPT_LIBRARY_NAME} ${ANGELSCRIPT_SOURCE} ${ANGELSCRIPT_HEADERS})
|
||||
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../lib)
|
||||
target_link_libraries(${ANGELSCRIPT_LIBRARY_NAME} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
#find_package(Threads)
|
||||
#target_link_libraries(Angelscript ${CMAKE_THREAD_LIBS_INIT})
|
||||
set_target_properties(${ANGELSCRIPT_LIBRARY_NAME} PROPERTIES VERSION ${PROJECT_VERSION})
|
||||
|
||||
#if(MSVC)
|
||||
# set_target_properties(Angelscript PROPERTIES COMPILE_FLAGS "/MP")
|
||||
#endif(MSVC)
|
||||
if(BUILD_FRAMEWORK)
|
||||
set_target_properties(${ANGELSCRIPT_LIBRARY_NAME} PROPERTIES
|
||||
FRAMEWORK TRUE
|
||||
FRAMEWORK_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_FRAMEWORK_IDENTIFIER com.angelcode.Angelscript
|
||||
MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION}
|
||||
MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
XCODE_ATTRIBUTE_INSTALL_PATH "@rpath"
|
||||
PUBLIC_HEADER ../../include/angelscript.h
|
||||
)
|
||||
endif()
|
||||
|
||||
#set(RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../../bin)
|
||||
if(MSVC)
|
||||
set_target_properties(${ANGELSCRIPT_LIBRARY_NAME} PROPERTIES COMPILE_FLAGS "/MP")
|
||||
endif()
|
||||
|
||||
set(RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../../bin)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -47,46 +47,46 @@ template <class T> class asCArray
|
||||
public:
|
||||
asCArray();
|
||||
asCArray(const asCArray<T> &);
|
||||
asCArray(size_t reserve);
|
||||
asCArray(asUINT reserve);
|
||||
~asCArray();
|
||||
|
||||
void Allocate(size_t numElements, bool keepData);
|
||||
void AllocateNoConstruct(size_t numElements, bool keepData);
|
||||
size_t GetCapacity() const;
|
||||
void Allocate(asUINT numElements, bool keepData);
|
||||
void AllocateNoConstruct(asUINT numElements, bool keepData);
|
||||
asUINT GetCapacity() const;
|
||||
|
||||
void PushLast(const T &element);
|
||||
T PopLast();
|
||||
|
||||
bool SetLength(size_t numElements);
|
||||
bool SetLengthNoConstruct(size_t numElements);
|
||||
size_t GetLength() const;
|
||||
bool SetLength(asUINT numElements);
|
||||
bool SetLengthNoConstruct(asUINT numElements);
|
||||
asUINT GetLength() const;
|
||||
|
||||
void Copy(const T*, size_t count);
|
||||
void Copy(const T*, asUINT count);
|
||||
asCArray<T> &operator =(const asCArray<T> &);
|
||||
void SwapWith(asCArray<T> &other);
|
||||
|
||||
const T &operator [](size_t index) const;
|
||||
T &operator [](size_t index);
|
||||
const T &operator [](asUINT index) const;
|
||||
T &operator [](asUINT index);
|
||||
T *AddressOf();
|
||||
const T *AddressOf() const;
|
||||
|
||||
void Concatenate(const asCArray<T> &);
|
||||
bool Concatenate(const asCArray<T> &);
|
||||
void Concatenate(T*, unsigned int count);
|
||||
|
||||
bool Exists(const T &element) const;
|
||||
int IndexOf(const T &element) const;
|
||||
void RemoveIndex(size_t index); // Removes the entry without reordering the array
|
||||
void RemoveIndex(asUINT index); // Removes the entry without reordering the array
|
||||
void RemoveValue(const T &element); // Removes the value without reordering the array
|
||||
void RemoveIndexUnordered(size_t index); // Removes the entry without keeping the order
|
||||
void RemoveIndexUnordered(asUINT index); // Removes the entry without keeping the order
|
||||
|
||||
bool operator==(const asCArray<T> &) const;
|
||||
bool operator!=(const asCArray<T> &) const;
|
||||
|
||||
protected:
|
||||
T *array;
|
||||
size_t length;
|
||||
size_t maxLength;
|
||||
char buf[8];
|
||||
asUINT length; // 32bits is enough for all uses of this array
|
||||
asUINT maxLength;
|
||||
char buf[2*4*AS_PTR_SIZE]; // Avoid dynamically allocated memory for tiny arrays
|
||||
};
|
||||
|
||||
// Implementation
|
||||
@ -122,7 +122,7 @@ asCArray<T>::asCArray(const asCArray<T> ©)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
asCArray<T>::asCArray(size_t reserve)
|
||||
asCArray<T>::asCArray(asUINT reserve)
|
||||
{
|
||||
array = 0;
|
||||
length = 0;
|
||||
@ -139,13 +139,13 @@ asCArray<T>::~asCArray(void)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
size_t asCArray<T>::GetLength() const
|
||||
asUINT asCArray<T>::GetLength() const
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T &asCArray<T>::operator [](size_t index) const
|
||||
const T &asCArray<T>::operator [](asUINT index) const
|
||||
{
|
||||
asASSERT(index < length);
|
||||
|
||||
@ -153,7 +153,7 @@ const T &asCArray<T>::operator [](size_t index) const
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T &asCArray<T>::operator [](size_t index)
|
||||
T &asCArray<T>::operator [](asUINT index)
|
||||
{
|
||||
asASSERT(index < length);
|
||||
|
||||
@ -189,7 +189,7 @@ T asCArray<T>::PopLast()
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void asCArray<T>::Allocate(size_t numElements, bool keepData)
|
||||
void asCArray<T>::Allocate(asUINT numElements, bool keepData)
|
||||
{
|
||||
// We have 4 situations
|
||||
// 1. The previous array is 8 bytes or smaller and the new array is also 8 bytes or smaller
|
||||
@ -200,7 +200,7 @@ void asCArray<T>::Allocate(size_t numElements, bool keepData)
|
||||
T *tmp = 0;
|
||||
if( numElements )
|
||||
{
|
||||
if( sizeof(T)*numElements <= 8 )
|
||||
if( sizeof(T)*numElements <= sizeof(buf) )
|
||||
// Use the internal buffer
|
||||
tmp = reinterpret_cast<T*>(buf);
|
||||
else
|
||||
@ -217,20 +217,20 @@ void asCArray<T>::Allocate(size_t numElements, bool keepData)
|
||||
if( array == tmp )
|
||||
{
|
||||
// Construct only the newly allocated elements
|
||||
for( size_t n = length; n < numElements; n++ )
|
||||
for( asUINT n = length; n < numElements; n++ )
|
||||
new (&tmp[n]) T();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Construct all elements
|
||||
for( size_t n = 0; n < numElements; n++ )
|
||||
for( asUINT n = 0; n < numElements; n++ )
|
||||
new (&tmp[n]) T();
|
||||
}
|
||||
}
|
||||
|
||||
if( array )
|
||||
{
|
||||
size_t oldLength = length;
|
||||
asUINT oldLength = length;
|
||||
|
||||
if( array == tmp )
|
||||
{
|
||||
@ -243,7 +243,7 @@ void asCArray<T>::Allocate(size_t numElements, bool keepData)
|
||||
length = 0;
|
||||
|
||||
// Call the destructor for elements that are no longer used
|
||||
for( size_t n = length; n < oldLength; n++ )
|
||||
for( asUINT n = length; n < oldLength; n++ )
|
||||
array[n].~T();
|
||||
}
|
||||
else
|
||||
@ -253,14 +253,14 @@ void asCArray<T>::Allocate(size_t numElements, bool keepData)
|
||||
if( length > numElements )
|
||||
length = numElements;
|
||||
|
||||
for( size_t n = 0; n < length; n++ )
|
||||
for( asUINT n = 0; n < length; n++ )
|
||||
tmp[n] = array[n];
|
||||
}
|
||||
else
|
||||
length = 0;
|
||||
|
||||
// Call the destructor for all elements
|
||||
for( size_t n = 0; n < oldLength; n++ )
|
||||
for( asUINT n = 0; n < oldLength; n++ )
|
||||
array[n].~T();
|
||||
|
||||
if( array != reinterpret_cast<T*>(buf) )
|
||||
@ -273,7 +273,7 @@ void asCArray<T>::Allocate(size_t numElements, bool keepData)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void asCArray<T>::AllocateNoConstruct(size_t numElements, bool keepData)
|
||||
void asCArray<T>::AllocateNoConstruct(asUINT numElements, bool keepData)
|
||||
{
|
||||
// We have 4 situations
|
||||
// 1. The previous array is 8 bytes or smaller and the new array is also 8 bytes or smaller
|
||||
@ -284,7 +284,7 @@ void asCArray<T>::AllocateNoConstruct(size_t numElements, bool keepData)
|
||||
T *tmp = 0;
|
||||
if( numElements )
|
||||
{
|
||||
if( sizeof(T)*numElements <= 8 )
|
||||
if( sizeof(T)*numElements <= sizeof(buf) )
|
||||
// Use the internal buffer
|
||||
tmp = reinterpret_cast<T*>(buf);
|
||||
else
|
||||
@ -333,13 +333,13 @@ void asCArray<T>::AllocateNoConstruct(size_t numElements, bool keepData)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
size_t asCArray<T>::GetCapacity() const
|
||||
asUINT asCArray<T>::GetCapacity() const
|
||||
{
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool asCArray<T>::SetLength(size_t numElements)
|
||||
bool asCArray<T>::SetLength(asUINT numElements)
|
||||
{
|
||||
if( numElements > maxLength )
|
||||
{
|
||||
@ -356,7 +356,7 @@ bool asCArray<T>::SetLength(size_t numElements)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool asCArray<T>::SetLengthNoConstruct(size_t numElements)
|
||||
bool asCArray<T>::SetLengthNoConstruct(asUINT numElements)
|
||||
{
|
||||
if( numElements > maxLength )
|
||||
{
|
||||
@ -373,7 +373,7 @@ bool asCArray<T>::SetLengthNoConstruct(size_t numElements)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void asCArray<T>::Copy(const T *data, size_t count)
|
||||
void asCArray<T>::Copy(const T *data, asUINT count)
|
||||
{
|
||||
if( maxLength < count )
|
||||
{
|
||||
@ -385,7 +385,7 @@ void asCArray<T>::Copy(const T *data, size_t count)
|
||||
}
|
||||
}
|
||||
|
||||
for( size_t n = 0; n < count; n++ )
|
||||
for( asUINT n = 0; n < count; n++ )
|
||||
array[n] = data[n];
|
||||
|
||||
length = count;
|
||||
@ -403,8 +403,8 @@ template <class T>
|
||||
void asCArray<T>::SwapWith(asCArray<T> &other)
|
||||
{
|
||||
T *tmpArray = array;
|
||||
size_t tmpLength = length;
|
||||
size_t tmpMaxLength = maxLength;
|
||||
asUINT tmpLength = length;
|
||||
asUINT tmpMaxLength = maxLength;
|
||||
char tmpBuf[sizeof(buf)];
|
||||
memcpy(tmpBuf, buf, sizeof(buf));
|
||||
|
||||
@ -430,7 +430,7 @@ bool asCArray<T>::operator ==(const asCArray<T> &other) const
|
||||
{
|
||||
if( length != other.length ) return false;
|
||||
|
||||
for( size_t n = 0; n < length; n++ )
|
||||
for( asUINT n = 0; n < length; n++ )
|
||||
if( array[n] != other.array[n] )
|
||||
return false;
|
||||
|
||||
@ -443,16 +443,28 @@ bool asCArray<T>::operator !=(const asCArray<T> &other) const
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
// Returns false if the concatenation wasn't successful due to out of memory
|
||||
template <class T>
|
||||
void asCArray<T>::Concatenate(const asCArray<T> &other)
|
||||
bool asCArray<T>::Concatenate(const asCArray<T> &other)
|
||||
{
|
||||
if( maxLength < length + other.length )
|
||||
{
|
||||
Allocate(length + other.length, true);
|
||||
if( maxLength < length + other.length )
|
||||
{
|
||||
// Out of memory
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for( size_t n = 0; n < other.length; n++ )
|
||||
for( asUINT n = 0; n < other.length; n++ )
|
||||
array[length+n] = other.array[n];
|
||||
|
||||
length += other.length;
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@ -471,18 +483,18 @@ bool asCArray<T>::Exists(const T &e) const
|
||||
template <class T>
|
||||
int asCArray<T>::IndexOf(const T &e) const
|
||||
{
|
||||
for( size_t n = 0; n < length; n++ )
|
||||
for( asUINT n = 0; n < length; n++ )
|
||||
if( array[n] == e ) return static_cast<int>(n);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void asCArray<T>::RemoveIndex(size_t index)
|
||||
void asCArray<T>::RemoveIndex(asUINT index)
|
||||
{
|
||||
if( index < length )
|
||||
{
|
||||
for( size_t n = index; n < length-1; n++ )
|
||||
for( asUINT n = index; n < length-1; n++ )
|
||||
array[n] = array[n+1];
|
||||
|
||||
PopLast();
|
||||
@ -492,7 +504,7 @@ void asCArray<T>::RemoveIndex(size_t index)
|
||||
template <class T>
|
||||
void asCArray<T>::RemoveValue(const T &e)
|
||||
{
|
||||
for( size_t n = 0; n < length; n++ )
|
||||
for( asUINT n = 0; n < length; n++ )
|
||||
{
|
||||
if( array[n] == e )
|
||||
{
|
||||
@ -503,7 +515,7 @@ void asCArray<T>::RemoveValue(const T &e)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void asCArray<T>::RemoveIndexUnordered(size_t index)
|
||||
void asCArray<T>::RemoveIndexUnordered(asUINT index)
|
||||
{
|
||||
if( index == length - 1 )
|
||||
PopLast();
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -45,21 +45,37 @@ asCAtomic::asCAtomic()
|
||||
|
||||
asDWORD asCAtomic::get() const
|
||||
{
|
||||
// A very high ref count is highly unlikely. It most likely a problem with
|
||||
// memory that has been overwritten or is being accessed after it was deleted.
|
||||
asASSERT(value < 1000000);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void asCAtomic::set(asDWORD val)
|
||||
{
|
||||
// A very high ref count is highly unlikely. It most likely a problem with
|
||||
// memory that has been overwritten or is being accessed after it was deleted.
|
||||
asASSERT(value < 1000000);
|
||||
|
||||
value = val;
|
||||
}
|
||||
|
||||
asDWORD asCAtomic::atomicInc()
|
||||
{
|
||||
// A very high ref count is highly unlikely. It most likely a problem with
|
||||
// memory that has been overwritten or is being accessed after it was deleted.
|
||||
asASSERT(value < 1000000);
|
||||
|
||||
return asAtomicInc((int&)value);
|
||||
}
|
||||
|
||||
asDWORD asCAtomic::atomicDec()
|
||||
{
|
||||
// A very high ref count is highly unlikely. It most likely a problem with
|
||||
// memory that has been overwritten or is being accessed after it was deleted.
|
||||
asASSERT(value < 1000000);
|
||||
|
||||
return asAtomicDec((int&)value);
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -51,6 +51,11 @@
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
#ifdef AS_NO_COMPILER
|
||||
// Forward declare the structure, as it is part of some function signatures used even without the compiler
|
||||
struct sGlobalVariableDescription;
|
||||
#endif
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
|
||||
struct sFunctionDescription
|
||||
@ -72,6 +77,7 @@ struct sGlobalVariableDescription
|
||||
asCString name;
|
||||
asCGlobalProperty *property;
|
||||
asCDataType datatype;
|
||||
asSNameSpace *ns;
|
||||
int index;
|
||||
bool isCompiled;
|
||||
bool isPureConstant;
|
||||
@ -160,14 +166,16 @@ protected:
|
||||
void WriteError(const asCString &scriptname, const asCString &msg, int r, int c);
|
||||
void WriteError(const asCString &msg, asCScriptCode *file, asCScriptNode *node);
|
||||
void WriteWarning(const asCString &scriptname, const asCString &msg, int r, int c);
|
||||
void WriteWarning(const asCString &msg, asCScriptCode *file, asCScriptNode *node);
|
||||
|
||||
bool DoesGlobalPropertyExist(const char *prop, asSNameSpace *ns, asCGlobalProperty **outProp = 0, sGlobalVariableDescription **outDesc = 0, bool *isAppProp = 0);
|
||||
asCGlobalProperty *GetGlobalProperty(const char *prop, asSNameSpace *ns, bool *isCompiled, bool *isPureConstant, asQWORD *constantValue, bool *isAppProp);
|
||||
int ValidateDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func);
|
||||
asCString GetCleanExpressionString(asCScriptNode *n, asCScriptCode *file);
|
||||
|
||||
asSNameSpace *GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next);
|
||||
asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script);
|
||||
asCString GetScopeFromNode(asCScriptNode *n, asCScriptCode *script, asCScriptNode **next = 0);
|
||||
asSNameSpace *GetParentNameSpace(asSNameSpace *ns);
|
||||
|
||||
asCObjectType *GetObjectType(const char *type, asSNameSpace *ns);
|
||||
asCScriptFunction *GetFuncDef(const char *type);
|
||||
@ -175,15 +183,6 @@ protected:
|
||||
asCDataType CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope = false, asCObjectType *currentType = 0);
|
||||
asCDataType ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlag, bool *autoHandle);
|
||||
|
||||
struct preMessage_t
|
||||
{
|
||||
bool isSet;
|
||||
asCString message;
|
||||
asCString scriptname;
|
||||
int r;
|
||||
int c;
|
||||
} preMessage;
|
||||
|
||||
int numErrors;
|
||||
int numWarnings;
|
||||
bool silent;
|
||||
@ -195,6 +194,7 @@ protected:
|
||||
protected:
|
||||
friend class asCCompiler;
|
||||
|
||||
int CheckForConflictsDueToDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func, asCObjectType *objType);
|
||||
int GetNamespaceAndNameFromNode(asCScriptNode *n, asCScriptCode *script, asSNameSpace *implicitNs, asSNameSpace *&outNs, asCString &outName);
|
||||
int RegisterMixinClass(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
sMixinClass *GetMixinClass(const char *name, asSNameSpace *ns);
|
||||
@ -204,7 +204,7 @@ protected:
|
||||
void AddInterfaceFromMixinToClass(sClassDeclaration *decl, asCScriptNode *errNode, sMixinClass *mixin);
|
||||
|
||||
int RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *object = 0, bool isInterface = false, bool isGlobalFunction = false, asSNameSpace *ns = 0, bool isExistingShared = false, bool isMixin = false);
|
||||
int RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray<asCString> ¶meterNames, asCArray<asCDataType> ¶meterTypes, asCArray<asETypeModifiers> &inOutFlags, asCArray<asCString *> &defaultArgs, bool isConstMethod, bool isConstructor, bool isDestructor, bool isPrivate, bool isOverride, bool isFinal, bool isShared);
|
||||
int RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray<asCString> ¶meterNames, asCArray<asCDataType> ¶meterTypes, asCArray<asETypeModifiers> &inOutFlags, asCArray<asCString *> &defaultArgs, bool isConstMethod, bool isConstructor, bool isDestructor, bool isPrivate, bool isProtected, bool isOverride, bool isFinal, bool isShared);
|
||||
int RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file, asCObjectType *object = 0, bool isInterface = false, bool isGlobalFunction = false, asSNameSpace *ns = 0, bool isExistingShared = false);
|
||||
int RegisterImportedFunction(int funcID, asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
int RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
@ -215,11 +215,11 @@ protected:
|
||||
int RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
void CompleteFuncDef(sFuncDef *funcDef);
|
||||
void CompileInterfaces();
|
||||
void CompileClasses();
|
||||
void GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray<asCString> ¶meterNames, asCArray<asCDataType> ¶meterTypes, asCArray<asETypeModifiers> &inOutFlags, asCArray<asCString *> &defaultArgs, bool &isConstMethod, bool &isConstructor, bool &isDestructor, bool &isPrivate, bool &isOverride, bool &isFinal, bool &isShared, asSNameSpace *implicitNamespace);
|
||||
void CompileClasses(asUINT originalNumTempl);
|
||||
void GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray<asCString> ¶meterNames, asCArray<asCDataType> ¶meterTypes, asCArray<asETypeModifiers> &inOutFlags, asCArray<asCString *> &defaultArgs, bool &isConstMethod, bool &isConstructor, bool &isDestructor, bool &isPrivate, bool &isProtected, bool &isOverride, bool &isFinal, bool &isShared, asSNameSpace *implicitNamespace);
|
||||
bool DoesMethodExist(asCObjectType *objType, int methodId, asUINT *methodIndex = 0);
|
||||
void AddDefaultConstructor(asCObjectType *objType, asCScriptCode *file);
|
||||
asCObjectProperty *AddPropertyToClass(sClassDeclaration *c, const asCString &name, const asCDataType &type, bool isPrivate, asCScriptCode *file = 0, asCScriptNode *node = 0);
|
||||
asCObjectProperty *AddPropertyToClass(sClassDeclaration *c, const asCString &name, const asCDataType &type, bool isPrivate, bool isProtected, bool isInherited, asCScriptCode *file = 0, asCScriptNode *node = 0);
|
||||
int CreateVirtualFunction(asCScriptFunction *func, int idx);
|
||||
void ParseScripts();
|
||||
void RegisterTypesFromScript(asCScriptNode *node, asCScriptCode *script, asSNameSpace *ns);
|
||||
@ -232,7 +232,8 @@ protected:
|
||||
asCObjectProperty *GetObjectProperty(asCDataType &obj, const char *prop);
|
||||
asCScriptFunction *GetFunctionDescription(int funcId);
|
||||
void GetFunctionDescriptions(const char *name, asCArray<int> &funcs, asSNameSpace *ns);
|
||||
void GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray<int> &methods, bool objIsConst, const asCString &scope = "");
|
||||
void GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray<int> &methods, bool objIsConst, const asCString &scope = "", asCScriptNode *errNode = 0, asCScriptCode *script = 0);
|
||||
void EvaluateTemplateInstances(asUINT startIdx, bool keepSilent);
|
||||
|
||||
asCArray<asCScriptCode *> scripts;
|
||||
asCArray<sFunctionDescription *> functions;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -864,7 +864,6 @@ void asCByteCode::OptimizeLocally(const asCArray<int> &tempVariableOffsets)
|
||||
|
||||
instr = GoForward(curr);
|
||||
}
|
||||
|
||||
}
|
||||
else if( currOp == asBC_RDSPtr )
|
||||
{
|
||||
@ -1553,6 +1552,7 @@ int asCByteCode::GetSize()
|
||||
|
||||
void asCByteCode::AddCode(asCByteCode *bc)
|
||||
{
|
||||
if( bc == this ) return;
|
||||
if( bc->first )
|
||||
{
|
||||
if( first == 0 )
|
||||
@ -2037,7 +2037,14 @@ void asCByteCode::PostProcess()
|
||||
DeleteInstruction(curr);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef AS_DEBUG
|
||||
// If the stackSize is negative, then there is a problem with the bytecode.
|
||||
// If AS_DEBUG is turned on, this same check is done in DebugOutput.
|
||||
asASSERT( instr->stackSize >= 0 || asBCInfo[instr->op].type == asBCTYPE_INFO );
|
||||
#endif
|
||||
instr = instr->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2079,7 +2086,9 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
fprintf(file, "Variables: \n");
|
||||
for( n = 0; n < func->scriptData->variables.GetLength(); n++ )
|
||||
{
|
||||
fprintf(file, " %.3d: %s %s\n", func->scriptData->variables[n]->stackOffset, func->scriptData->variables[n]->type.Format().AddressOf(), func->scriptData->variables[n]->name.AddressOf());
|
||||
int idx = func->scriptData->objVariablePos.IndexOf(func->scriptData->variables[n]->stackOffset);
|
||||
bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false;
|
||||
fprintf(file, " %.3d: %s%s %s\n", func->scriptData->variables[n]->stackOffset, isOnHeap ? "(heap) " : "", func->scriptData->variables[n]->type.Format(func->nameSpace).AddressOf(), func->scriptData->variables[n]->name.AddressOf());
|
||||
}
|
||||
asUINT offset = 0;
|
||||
if( func->objectType )
|
||||
@ -2099,7 +2108,11 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
}
|
||||
}
|
||||
if( !found )
|
||||
fprintf(file, " %.3d: %s {noname param}\n", offset, func->parameterTypes[n].Format().AddressOf());
|
||||
{
|
||||
int idx = func->scriptData->objVariablePos.IndexOf(offset);
|
||||
bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false;
|
||||
fprintf(file, " %.3d: %s%s {noname param}\n", offset, isOnHeap ? "(heap) " : "", func->parameterTypes[n].Format(func->nameSpace).AddressOf());
|
||||
}
|
||||
|
||||
offset -= func->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
@ -2115,10 +2128,20 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
}
|
||||
}
|
||||
if( !found )
|
||||
fprintf(file, " %.3d: %s {noname}\n", func->scriptData->objVariablePos[n], func->scriptData->objVariableTypes[n]->name.AddressOf());
|
||||
{
|
||||
if( func->scriptData->objVariableTypes[n] )
|
||||
{
|
||||
int idx = func->scriptData->objVariablePos.IndexOf(func->scriptData->objVariablePos[n]);
|
||||
bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false;
|
||||
fprintf(file, " %.3d: %s%s {noname}\n", func->scriptData->objVariablePos[n], isOnHeap ? "(heap) " : "", func->scriptData->objVariableTypes[n]->name.AddressOf());
|
||||
}
|
||||
else
|
||||
fprintf(file, " %.3d: null handle {noname}\n", func->scriptData->objVariablePos[n]);
|
||||
}
|
||||
}
|
||||
fprintf(file, "\n\n");
|
||||
|
||||
bool invalidStackSize = false;
|
||||
int pos = 0;
|
||||
asUINT lineIndex = 0;
|
||||
asCByteInstruction *instr = first;
|
||||
@ -2131,10 +2154,19 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
lineIndex += 2;
|
||||
}
|
||||
|
||||
fprintf(file, "%5d ", pos);
|
||||
pos += instr->GetSize();
|
||||
if( instr->GetSize() > 0 )
|
||||
{
|
||||
fprintf(file, "%5d ", pos);
|
||||
pos += instr->GetSize();
|
||||
|
||||
fprintf(file, "%3d %c ", int(instr->stackSize + func->scriptData->variableSpace), instr->marked ? '*' : ' ');
|
||||
fprintf(file, "%3d %c ", int(instr->stackSize + func->scriptData->variableSpace), instr->marked ? '*' : ' ');
|
||||
if( instr->stackSize < 0 )
|
||||
invalidStackSize = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(file, " ");
|
||||
}
|
||||
|
||||
switch( asBCInfo[instr->op].type )
|
||||
{
|
||||
@ -2182,7 +2214,10 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
switch( instr->op )
|
||||
{
|
||||
case asBC_OBJTYPE:
|
||||
fprintf(file, " %-8s 0x%x\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg));
|
||||
{
|
||||
asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg);
|
||||
fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), ot->GetName());
|
||||
}
|
||||
break;
|
||||
|
||||
case asBC_PshC4:
|
||||
@ -2229,6 +2264,16 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
break;
|
||||
|
||||
case asBCTYPE_QW_ARG:
|
||||
switch( instr->op )
|
||||
{
|
||||
case asBC_OBJTYPE:
|
||||
{
|
||||
asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg);
|
||||
fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), ot->GetName());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef __GNUC__
|
||||
#ifdef _LP64
|
||||
fprintf(file, " %-8s 0x%lx (i:%ld, f:%g)\n", asBCInfo[instr->op].name, *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
@ -2238,6 +2283,7 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
#else
|
||||
fprintf(file, " %-8s 0x%I64x (i:%I64d, f:%g)\n", asBCInfo[instr->op].name, *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case asBCTYPE_wW_QW_ARG:
|
||||
@ -2257,7 +2303,8 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
if( instr->op == asBC_ALLOC )
|
||||
{
|
||||
asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg);
|
||||
fprintf(file, " %-8s 0x%x, %d (type:%s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName());
|
||||
asCScriptFunction *func = engine->scriptFunctions[instr->wArg[0]];
|
||||
fprintf(file, " %-8s 0x%x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName(), func ? func->GetDeclaration() : "{no func}");
|
||||
}
|
||||
else
|
||||
fprintf(file, " %-8s %u, %d\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1));
|
||||
@ -2271,14 +2318,15 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
if( instr->op == asBC_ALLOC )
|
||||
{
|
||||
asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
|
||||
asCScriptFunction *func = engine->scriptFunctions[instr->wArg[0]];
|
||||
#ifdef __GNUC__
|
||||
#ifdef AS_64BIT_PTR
|
||||
fprintf(file, " %-8s 0x%lx, %d (type:%s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName());
|
||||
fprintf(file, " %-8s 0x%lx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), func ? func->GetDeclaration() : "{no func}");
|
||||
#else
|
||||
fprintf(file, " %-8s 0x%llx, %d (type:%s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName());
|
||||
fprintf(file, " %-8s 0x%llx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), func ? func->GetDeclaration() : "{no func}");
|
||||
#endif
|
||||
#else
|
||||
fprintf(file, " %-8s 0x%I64x, %d (type:%s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName());
|
||||
fprintf(file, " %-8s 0x%I64x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), func ? func->GetDeclaration() : "{no func}");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -2333,6 +2381,11 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
// If the stackSize is negative then there is something wrong with the
|
||||
// bytecode, i.e. there is a bug in the compiler or in the optimizer. We
|
||||
// only check this here to have the bytecode available on file for verification
|
||||
asASSERT( !invalidStackSize );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -45,6 +45,14 @@
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// ref: Member Function Pointers and the Fastest Possible C++ Delegates
|
||||
// describes the structure of class method pointers for most compilers
|
||||
// http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible
|
||||
|
||||
// ref: The code comments for ItaniumCXXABI::EmitLoadOfMemberFunctionPointer in the LLVM compiler
|
||||
// describes the structure for class method pointers on Itanium and arm64 ABI
|
||||
// http://clang.llvm.org/doxygen/CodeGen_2ItaniumCXXABI_8cpp_source.html#l00937
|
||||
|
||||
int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *objForThiscall, asSSystemFunctionInterface *internal)
|
||||
{
|
||||
memset(internal, 0, sizeof(asSSystemFunctionInterface));
|
||||
@ -57,9 +65,9 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv,
|
||||
{
|
||||
if( ptr.flag == 1 && callConv != asCALL_GENERIC )
|
||||
return asWRONG_CALLING_CONV;
|
||||
else if( ptr.flag == 2 && (callConv == asCALL_GENERIC || callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL) )
|
||||
else if( ptr.flag == 2 && (callConv == asCALL_GENERIC || callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL || callConv == asCALL_THISCALL_OBJFIRST || callConv == asCALL_THISCALL_OBJLAST) )
|
||||
return asWRONG_CALLING_CONV;
|
||||
else if( ptr.flag == 3 && !(callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL) )
|
||||
else if( ptr.flag == 3 && !(callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL || callConv == asCALL_THISCALL_OBJFIRST || callConv == asCALL_THISCALL_OBJLAST) )
|
||||
return asWRONG_CALLING_CONV;
|
||||
}
|
||||
|
||||
@ -90,20 +98,44 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv,
|
||||
if( isMethod )
|
||||
{
|
||||
#ifndef AS_NO_CLASS_METHODS
|
||||
if( base == asCALL_THISCALL )
|
||||
if( base == asCALL_THISCALL || base == asCALL_THISCALL_OBJFIRST || base == asCALL_THISCALL_OBJLAST )
|
||||
{
|
||||
internal->callConv = ICC_THISCALL;
|
||||
internalCallConv thisCallConv;
|
||||
if( base == asCALL_THISCALL )
|
||||
{
|
||||
if( callConv != asCALL_THISCALL_ASGLOBAL && objForThiscall )
|
||||
return asINVALID_ARG;
|
||||
|
||||
thisCallConv = ICC_THISCALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
return asNOT_SUPPORTED;
|
||||
#else
|
||||
if( objForThiscall == 0 )
|
||||
return asINVALID_ARG;
|
||||
|
||||
internal->objForThiscall = objForThiscall;
|
||||
if( base == asCALL_THISCALL_OBJFIRST )
|
||||
thisCallConv = ICC_THISCALL_OBJFIRST;
|
||||
else //if( base == asCALL_THISCALL_OBJLAST )
|
||||
thisCallConv = ICC_THISCALL_OBJLAST;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal->callConv = thisCallConv;
|
||||
#ifdef GNU_STYLE_VIRTUAL_METHOD
|
||||
if( (size_t(ptr.ptr.f.func) & 1) )
|
||||
internal->callConv = ICC_VIRTUAL_THISCALL;
|
||||
internal->callConv = (internalCallConv)(thisCallConv + 2);
|
||||
#endif
|
||||
internal->baseOffset = ( int )MULTI_BASE_OFFSET(ptr);
|
||||
#if defined(AS_ARM) && defined(__GNUC__)
|
||||
#if defined(AS_ARM) && (defined(__GNUC__) || defined(AS_PSVITA))
|
||||
// As the least significant bit in func is used to switch to THUMB mode
|
||||
// on ARM processors, the LSB in the __delta variable is used instead of
|
||||
// the one in __pfn on ARM processors.
|
||||
if( (size_t(internal->baseOffset) & 1) )
|
||||
internal->callConv = ICC_VIRTUAL_THISCALL;
|
||||
internal->callConv = (internalCallConv)(thisCallConv + 2);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VIRTUAL_BASE_OFFSET
|
||||
@ -135,6 +167,49 @@ int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInter
|
||||
// Calculate the size needed for the parameters
|
||||
internal->paramSize = func->GetSpaceNeededForArguments();
|
||||
|
||||
// Prepare the clean up instructions for the function arguments
|
||||
internal->cleanArgs.SetLength(0);
|
||||
int offset = 0;
|
||||
for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
asCDataType &dt = func->parameterTypes[n];
|
||||
|
||||
if( dt.IsObject() && !dt.IsReference() )
|
||||
{
|
||||
asSTypeBehaviour *beh = &dt.GetObjectType()->beh;
|
||||
if( dt.GetObjectType()->flags & asOBJ_REF )
|
||||
{
|
||||
asASSERT( (dt.GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release );
|
||||
if( beh->release )
|
||||
{
|
||||
asSSystemFunctionInterface::SClean clean;
|
||||
clean.op = 0; // call release
|
||||
clean.ot = dt.GetObjectType();
|
||||
clean.off = short(offset);
|
||||
internal->cleanArgs.PushLast(clean);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asSSystemFunctionInterface::SClean clean;
|
||||
clean.op = 1; // call free
|
||||
clean.ot = dt.GetObjectType();
|
||||
clean.off = short(offset);
|
||||
|
||||
// Call the destructor then free the memory
|
||||
if( beh->destruct )
|
||||
clean.op = 2; // call destruct, then free
|
||||
|
||||
internal->cleanArgs.PushLast(clean);
|
||||
}
|
||||
}
|
||||
|
||||
if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() )
|
||||
offset += AS_PTR_SIZE;
|
||||
else
|
||||
offset += dt.GetSizeOnStackDWords();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -142,11 +217,14 @@ int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInter
|
||||
int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine)
|
||||
{
|
||||
#ifdef AS_MAX_PORTABILITY
|
||||
UNUSED_VAR(func);
|
||||
UNUSED_VAR(internal);
|
||||
UNUSED_VAR(engine);
|
||||
|
||||
// This should never happen, as when AS_MAX_PORTABILITY is on, all functions
|
||||
// are asCALL_GENERIC, which are prepared by PrepareSystemFunctionGeneric
|
||||
asASSERT(false);
|
||||
#endif
|
||||
|
||||
#else
|
||||
// References are always returned as primitive data
|
||||
if( func->returnType.IsReference() || func->returnType.IsObjectHandle() )
|
||||
{
|
||||
@ -162,7 +240,7 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
|
||||
// Only value types can be returned by value
|
||||
asASSERT( objType & asOBJ_VALUE );
|
||||
|
||||
if( !(objType & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT)) )
|
||||
if( !(objType & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) )
|
||||
{
|
||||
// If the return is by value then we need to know the true type
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
|
||||
@ -172,6 +250,13 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
|
||||
engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0);
|
||||
}
|
||||
else if( objType & asOBJ_APP_ARRAY )
|
||||
{
|
||||
// Array types are always returned in memory
|
||||
internal->hostReturnInMemory = true;
|
||||
internal->hostReturnSize = sizeof(void*)/4;
|
||||
internal->hostReturnFloat = false;
|
||||
}
|
||||
else if( objType & asOBJ_APP_CLASS )
|
||||
{
|
||||
internal->hostReturnFloat = false;
|
||||
@ -203,7 +288,13 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
|
||||
|
||||
#ifdef THISCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
if((internal->callConv == ICC_THISCALL ||
|
||||
#ifdef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
internal->callConv == ICC_VIRTUAL_THISCALL) &&
|
||||
#else
|
||||
internal->callConv == ICC_VIRTUAL_THISCALL ||
|
||||
internal->callConv == ICC_THISCALL_OBJFIRST ||
|
||||
internal->callConv == ICC_THISCALL_OBJLAST) &&
|
||||
#endif
|
||||
func->returnType.GetSizeInMemoryDWords() >= THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE)
|
||||
{
|
||||
internal->hostReturnInMemory = true;
|
||||
@ -242,7 +333,7 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
|
||||
|
||||
asCString str;
|
||||
str.Format(TXT_DONT_SUPPORT_RET_TYPE_s_BY_VAL, func->returnType.Format().AddressOf());
|
||||
str.Format(TXT_DONT_SUPPORT_RET_TYPE_s_BY_VAL, func->returnType.Format(func->nameSpace).AddressOf());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
|
||||
engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0);
|
||||
}
|
||||
@ -313,7 +404,7 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
|
||||
internal->takesObjByVal = true;
|
||||
|
||||
// Can't pass objects by value unless the application type is informed
|
||||
if( !(func->parameterTypes[n].GetObjectType()->flags & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT)) )
|
||||
if( !(func->parameterTypes[n].GetObjectType()->flags & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) )
|
||||
{
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
|
||||
|
||||
@ -350,29 +441,70 @@ int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *i
|
||||
}
|
||||
}
|
||||
|
||||
// Verify if the function has any registered autohandles
|
||||
internal->hasAutoHandles = false;
|
||||
for( n = 0; n < internal->paramAutoHandles.GetLength(); n++ )
|
||||
// Prepare the clean up instructions for the function arguments
|
||||
internal->cleanArgs.SetLength(0);
|
||||
int offset = 0;
|
||||
for( n = 0; n < func->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
if( internal->paramAutoHandles[n] )
|
||||
{
|
||||
internal->hasAutoHandles = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
asCDataType &dt = func->parameterTypes[n];
|
||||
|
||||
#if defined(COMPLEX_OBJS_PASSED_BY_REF) || defined(AS_LARGE_OBJS_PASSED_BY_REF)
|
||||
bool needFree = false;
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
if( dt.GetObjectType() && dt.GetObjectType()->flags & COMPLEX_MASK ) needFree = true;
|
||||
#endif
|
||||
#ifdef AS_LARGE_OBJS_PASSED_BY_REF
|
||||
if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ) needFree = true;
|
||||
#endif
|
||||
if( needFree &&
|
||||
dt.IsObject() &&
|
||||
!dt.IsObjectHandle() &&
|
||||
!dt.IsReference() )
|
||||
{
|
||||
asSSystemFunctionInterface::SClean clean;
|
||||
clean.op = 1; // call free
|
||||
clean.ot = dt.GetObjectType();
|
||||
clean.off = short(offset);
|
||||
|
||||
#ifndef AS_CALLEE_DESTROY_OBJ_BY_VAL
|
||||
// If the called function doesn't destroy objects passed by value we must do so here
|
||||
asSTypeBehaviour *beh = &dt.GetObjectType()->beh;
|
||||
if( beh->destruct )
|
||||
clean.op = 2; // call destruct, then free
|
||||
#endif
|
||||
|
||||
internal->cleanArgs.PushLast(clean);
|
||||
}
|
||||
#endif
|
||||
|
||||
if( n < internal->paramAutoHandles.GetLength() && internal->paramAutoHandles[n] )
|
||||
{
|
||||
asSSystemFunctionInterface::SClean clean;
|
||||
clean.op = 0; // call release
|
||||
clean.ot = dt.GetObjectType();
|
||||
clean.off = short(offset);
|
||||
internal->cleanArgs.PushLast(clean);
|
||||
}
|
||||
|
||||
if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() )
|
||||
offset += AS_PTR_SIZE;
|
||||
else
|
||||
offset += dt.GetSizeOnStackDWords();
|
||||
}
|
||||
#endif // !defined(AS_MAX_PORTABILITY)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef AS_MAX_PORTABILITY
|
||||
|
||||
int CallSystemFunction(int id, asCContext *context, void *objectPointer)
|
||||
int CallSystemFunction(int id, asCContext *context)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = engine->scriptFunctions[id]->sysFuncIntf;
|
||||
asCScriptFunction *func = engine->scriptFunctions[id];
|
||||
asSSystemFunctionInterface *sysFunc = func->sysFuncIntf;
|
||||
int callConv = sysFunc->callConv;
|
||||
if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD )
|
||||
return context->CallGeneric(id, objectPointer);
|
||||
return context->CallGeneric(func);
|
||||
|
||||
context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
|
||||
|
||||
@ -396,15 +528,15 @@ int CallSystemFunction(int id, asCContext *context, void *objectPointer)
|
||||
// args - This is the function arguments, which are packed as in AngelScript
|
||||
// retPointer - This points to a the memory buffer where the return object is to be placed, if the function returns the value in memory rather than in registers
|
||||
// retQW2 - This output parameter should be used if the function returns a value larger than 64bits in registers
|
||||
// secondObj - This is the object pointer that the proxy method should invoke its method on when the call convention is THISCALL_OBJFIRST/LAST
|
||||
//
|
||||
// Return value:
|
||||
//
|
||||
// The function should return the value that is returned in registers.
|
||||
//
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2);
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2, void *secondObj);
|
||||
|
||||
|
||||
int CallSystemFunction(int id, asCContext *context, void *objectPointer)
|
||||
int CallSystemFunction(int id, asCContext *context)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asCScriptFunction *descr = engine->scriptFunctions[id];
|
||||
@ -412,26 +544,24 @@ int CallSystemFunction(int id, asCContext *context, void *objectPointer)
|
||||
|
||||
int callConv = sysFunc->callConv;
|
||||
if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD )
|
||||
return context->CallGeneric(id, objectPointer);
|
||||
return context->CallGeneric(descr);
|
||||
|
||||
asQWORD retQW = 0;
|
||||
asQWORD retQW2 = 0;
|
||||
asDWORD *args = context->m_regs.stackPointer;
|
||||
void *retPointer = 0;
|
||||
void *obj = 0;
|
||||
int popSize = sysFunc->paramSize;
|
||||
|
||||
#ifdef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
void *obj = 0;
|
||||
void *secondObj = 0;
|
||||
|
||||
if( callConv >= ICC_THISCALL )
|
||||
{
|
||||
if( sysFunc->objForThiscall )
|
||||
{
|
||||
// This class method is being called as if it is a global function
|
||||
obj = sysFunc->objForThiscall;
|
||||
asASSERT( objectPointer == 0 );
|
||||
}
|
||||
else if( objectPointer )
|
||||
{
|
||||
obj = objectPointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -447,7 +577,7 @@ int CallSystemFunction(int id, asCContext *context, void *objectPointer)
|
||||
}
|
||||
|
||||
// Add the base offset for multiple inheritance
|
||||
#if defined(__GNUC__) && defined(AS_ARM)
|
||||
#if (defined(__GNUC__) && defined(AS_ARM)) || defined(AS_PSVITA)
|
||||
// On GNUC + ARM the lsb of the offset is used to indicate a virtual function
|
||||
// and the whole offset is thus shifted one bit left to keep the original
|
||||
// offset resolution
|
||||
@ -460,6 +590,72 @@ int CallSystemFunction(int id, asCContext *context, void *objectPointer)
|
||||
args += AS_PTR_SIZE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// TODO: clean-up: CallSystemFunctionNative should have two arguments for object pointers
|
||||
// objForThiscall is the object pointer that should be used for the thiscall
|
||||
// objForArg is the object pointer that should be passed as argument when using OBJFIRST or OBJLAST
|
||||
|
||||
// Used to save two object pointers with THISCALL_OBJLAST or THISCALL_OBJFIRST
|
||||
void *obj = 0;
|
||||
void *secondObj = 0;
|
||||
|
||||
if( callConv >= ICC_THISCALL )
|
||||
{
|
||||
bool continueCheck = true; // True if need check objectPointer or context stack for object
|
||||
int continueCheckIndex = 0; // Index into objectsPtrs to save the object if continueCheck
|
||||
|
||||
if( callConv >= ICC_THISCALL_OBJLAST )
|
||||
{
|
||||
asASSERT( sysFunc->objForThiscall != 0 );
|
||||
// This class method is being called as object method (sysFunc->objForThiscall must be set).
|
||||
obj = sysFunc->objForThiscall;
|
||||
continueCheckIndex = 1;
|
||||
}
|
||||
else if( sysFunc->objForThiscall )
|
||||
{
|
||||
// This class method is being called as if it is a global function
|
||||
obj = sysFunc->objForThiscall;
|
||||
continueCheck = false;
|
||||
}
|
||||
|
||||
if( continueCheck )
|
||||
{
|
||||
void *tempPtr = 0;
|
||||
|
||||
// The object pointer should be popped from the context stack
|
||||
popSize += AS_PTR_SIZE;
|
||||
|
||||
// Check for null pointer
|
||||
tempPtr = (void*)*(asPWORD*)(args);
|
||||
if( tempPtr == 0 )
|
||||
{
|
||||
context->SetInternalException(TXT_NULL_POINTER_ACCESS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add the base offset for multiple inheritance
|
||||
#if (defined(__GNUC__) && defined(AS_ARM)) || defined(AS_PSVITA)
|
||||
// On GNUC + ARM the lsb of the offset is used to indicate a virtual function
|
||||
// and the whole offset is thus shifted one bit left to keep the original
|
||||
// offset resolution
|
||||
tempPtr = (void*)(asPWORD(tempPtr) + (sysFunc->baseOffset>>1));
|
||||
#else
|
||||
tempPtr = (void*)(asPWORD(tempPtr) + sysFunc->baseOffset);
|
||||
#endif
|
||||
|
||||
// Skip the object pointer
|
||||
args += AS_PTR_SIZE;
|
||||
|
||||
if( continueCheckIndex )
|
||||
secondObj = tempPtr;
|
||||
else
|
||||
{
|
||||
asASSERT( obj == 0 );
|
||||
obj = tempPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
|
||||
if( descr->DoesReturnOnStack() )
|
||||
{
|
||||
@ -479,8 +675,9 @@ int CallSystemFunction(int id, asCContext *context, void *objectPointer)
|
||||
}
|
||||
|
||||
context->m_callingSystemFunction = descr;
|
||||
bool cppException = false;
|
||||
#ifdef AS_NO_EXCEPTIONS
|
||||
retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2);
|
||||
retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2, secondObj);
|
||||
#else
|
||||
// This try/catch block is to catch potential exception that may
|
||||
// be thrown by the registered function. The implementation of the
|
||||
@ -489,10 +686,12 @@ int CallSystemFunction(int id, asCContext *context, void *objectPointer)
|
||||
// executed in case of an exception.
|
||||
try
|
||||
{
|
||||
retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2);
|
||||
retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2, secondObj);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cppException = true;
|
||||
|
||||
// Convert the exception to a script exception so the VM can
|
||||
// properly report the error to the application and then clean up
|
||||
context->SetException(TXT_EXCEPTION_CAUGHT);
|
||||
@ -500,51 +699,6 @@ int CallSystemFunction(int id, asCContext *context, void *objectPointer)
|
||||
#endif
|
||||
context->m_callingSystemFunction = 0;
|
||||
|
||||
#if defined(COMPLEX_OBJS_PASSED_BY_REF) || defined(AS_LARGE_OBJS_PASSED_BY_REF)
|
||||
if( sysFunc->takesObjByVal )
|
||||
{
|
||||
// Need to free the complex objects passed by value, but that the
|
||||
// calling convention implicitly passes by reference behind the scene as the
|
||||
// calling function is the owner of that memory.
|
||||
|
||||
// args is pointing to the first real argument as used in CallSystemFunctionNative,
|
||||
// i.e. hidden arguments such as the object pointer and return address have already
|
||||
// been skipped.
|
||||
|
||||
int spos = 0;
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
bool needFree = false;
|
||||
asCDataType &dt = descr->parameterTypes[n];
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
if( dt.GetObjectType() && dt.GetObjectType()->flags & COMPLEX_MASK ) needFree = true;
|
||||
#endif
|
||||
#ifdef AS_LARGE_OBJS_PASSED_BY_REF
|
||||
if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ) needFree = true;
|
||||
#endif
|
||||
if( needFree &&
|
||||
dt.IsObject() &&
|
||||
!dt.IsObjectHandle() &&
|
||||
!dt.IsReference() )
|
||||
{
|
||||
void *obj = (void*)*(asPWORD*)&args[spos];
|
||||
spos += AS_PTR_SIZE;
|
||||
|
||||
#ifndef AS_CALLEE_DESTROY_OBJ_BY_VAL
|
||||
// If the called function doesn't destroy objects passed by value we must do so here
|
||||
asSTypeBehaviour *beh = &dt.GetObjectType()->beh;
|
||||
if( beh->destruct )
|
||||
engine->CallObjectMethod(obj, beh->destruct);
|
||||
#endif
|
||||
|
||||
engine->CallFree(obj);
|
||||
}
|
||||
else
|
||||
spos += dt.GetSizeOnStackDWords();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Store the returned value in our stack
|
||||
if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
|
||||
{
|
||||
@ -595,7 +749,7 @@ int CallSystemFunction(int id, asCContext *context, void *objectPointer)
|
||||
}
|
||||
}
|
||||
|
||||
if( context->m_status == asEXECUTION_EXCEPTION )
|
||||
if( context->m_status == asEXECUTION_EXCEPTION && !cppException )
|
||||
{
|
||||
// If the function raised a script exception it really shouldn't have
|
||||
// initialized the object. However, as it is a soft exception there is
|
||||
@ -663,27 +817,36 @@ int CallSystemFunction(int id, asCContext *context, void *objectPointer)
|
||||
context->m_regs.valueRegister = retQW;
|
||||
}
|
||||
|
||||
// Release autohandles in the arguments
|
||||
if( sysFunc->hasAutoHandles )
|
||||
// Clean up arguments
|
||||
const asUINT cleanCount = sysFunc->cleanArgs.GetLength();
|
||||
if( cleanCount )
|
||||
{
|
||||
args = context->m_regs.stackPointer;
|
||||
if( callConv >= ICC_THISCALL && !objectPointer )
|
||||
if( callConv >= ICC_THISCALL )
|
||||
args += AS_PTR_SIZE;
|
||||
|
||||
int spos = 0;
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf();
|
||||
for( asUINT n = 0; n < cleanCount; n++, clean++ )
|
||||
{
|
||||
if( sysFunc->paramAutoHandles[n] && *(asPWORD*)&args[spos] != 0 )
|
||||
void **addr = (void**)&args[clean->off];
|
||||
if( clean->op == 0 )
|
||||
{
|
||||
// Call the release method on the type
|
||||
engine->CallObjectMethod((void*)*(asPWORD*)&args[spos], descr->parameterTypes[n].GetObjectType()->beh.release);
|
||||
*(asPWORD*)&args[spos] = 0;
|
||||
if( *addr != 0 )
|
||||
{
|
||||
engine->CallObjectMethod(*addr, clean->ot->beh.release);
|
||||
*addr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
|
||||
spos += AS_PTR_SIZE;
|
||||
else
|
||||
spos += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
{
|
||||
asASSERT( clean->op == 1 || clean->op == 2 );
|
||||
asASSERT( *addr );
|
||||
|
||||
if( clean->op == 2 )
|
||||
engine->CallObjectMethod(*addr, clean->ot->beh.destruct);
|
||||
|
||||
engine->CallFree(*addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -46,6 +46,7 @@ BEGIN_AS_NAMESPACE
|
||||
class asCContext;
|
||||
class asCScriptEngine;
|
||||
class asCScriptFunction;
|
||||
class asCObjectType;
|
||||
struct asSSystemFunctionInterface;
|
||||
|
||||
int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *objForThiscall, asSSystemFunctionInterface *internal);
|
||||
@ -54,7 +55,7 @@ int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInter
|
||||
|
||||
int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine);
|
||||
|
||||
int CallSystemFunction(int id, asCContext *context, void *objectPointer);
|
||||
int CallSystemFunction(int id, asCContext *context);
|
||||
|
||||
inline asPWORD FuncPtrToUInt(asFUNCTION_t func)
|
||||
{
|
||||
@ -83,7 +84,15 @@ enum internalCallConv
|
||||
ICC_CDECL_OBJFIRST,
|
||||
ICC_CDECL_OBJFIRST_RETURNINMEM,
|
||||
ICC_GENERIC_METHOD,
|
||||
ICC_GENERIC_METHOD_RETURNINMEM // never used
|
||||
ICC_GENERIC_METHOD_RETURNINMEM, // never used
|
||||
ICC_THISCALL_OBJLAST,
|
||||
ICC_THISCALL_OBJLAST_RETURNINMEM,
|
||||
ICC_VIRTUAL_THISCALL_OBJLAST,
|
||||
ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM,
|
||||
ICC_THISCALL_OBJFIRST,
|
||||
ICC_THISCALL_OBJFIRST_RETURNINMEM,
|
||||
ICC_VIRTUAL_THISCALL_OBJFIRST,
|
||||
ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM
|
||||
};
|
||||
|
||||
struct asSSystemFunctionInterface
|
||||
@ -97,11 +106,18 @@ struct asSSystemFunctionInterface
|
||||
int hostReturnSize;
|
||||
int paramSize;
|
||||
bool takesObjByVal;
|
||||
asCArray<bool> paramAutoHandles;
|
||||
asCArray<bool> paramAutoHandles; // TODO: Should be able to remove this array. Perhaps the flags can be stored together with the inOutFlags in asCScriptFunction?
|
||||
bool returnAutoHandle;
|
||||
bool hasAutoHandles;
|
||||
void *objForThiscall;
|
||||
|
||||
struct SClean
|
||||
{
|
||||
asCObjectType *ot; // argument type for clean up
|
||||
short op; // clean up operation: 0 = release, 1 = free, 2 = destruct then free
|
||||
short off; // argument offset on the stack
|
||||
};
|
||||
asCArray<SClean> cleanArgs;
|
||||
|
||||
asSSystemFunctionInterface() {}
|
||||
|
||||
asSSystemFunctionInterface(const asSSystemFunctionInterface &in)
|
||||
@ -122,8 +138,8 @@ struct asSSystemFunctionInterface
|
||||
takesObjByVal = in.takesObjByVal;
|
||||
paramAutoHandles = in.paramAutoHandles;
|
||||
returnAutoHandle = in.returnAutoHandle;
|
||||
hasAutoHandles = in.hasAutoHandles;
|
||||
objForThiscall = in.objForThiscall;
|
||||
cleanArgs = in.cleanArgs;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -37,6 +37,8 @@
|
||||
// Written by Fredrik Ehnbom in June 2009, based on as_callfunc_x86.cpp
|
||||
//
|
||||
// The code was complemented to support Linux with ARM by Carlos Luna in December, 2012.
|
||||
//
|
||||
// Added support for functor methods by Jordi Oliveras Rovira in April, 2014.
|
||||
|
||||
|
||||
// This code has to conform to both AAPCS and the modified ABI for iOS
|
||||
@ -71,7 +73,7 @@ extern "C" asQWORD armFuncR0R1 (const asDWORD *, int, asFUNCTION_t, asDWORD
|
||||
extern "C" asQWORD armFuncObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD obj);
|
||||
extern "C" asQWORD armFuncR0ObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD obj);
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
@ -87,33 +89,45 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
// The return is made in memory
|
||||
callConv++;
|
||||
}
|
||||
bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST;
|
||||
|
||||
|
||||
asDWORD paramBuffer[64+2];
|
||||
// Android & Linux needs to align 64bit types on even registers, but this isn't done on iOS or Windows Phone
|
||||
// TODO: optimize runtime: There should be a check for this in PrepareSystemFunction() so this
|
||||
// doesn't have to be done for functions that don't have any 64bit types
|
||||
#if !defined(AS_ANDROID) && !defined(AS_LINUX)
|
||||
if( sysFunc->takesObjByVal )
|
||||
// In cases of thiscall methods, the callstack is configured as a standard thiscall
|
||||
// adding the secondObject as first or last element in callstack
|
||||
if( sysFunc->takesObjByVal || isThisCallMethod )
|
||||
#endif
|
||||
{
|
||||
#if defined(AS_ANDROID) || defined(AS_LINUX)
|
||||
// mask is used as a toggler to skip uneven registers.
|
||||
int mask = 1;
|
||||
|
||||
// Check for object pointer as first argument
|
||||
switch( callConv )
|
||||
if( isThisCallMethod )
|
||||
{
|
||||
case ICC_THISCALL:
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
mask = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
mask = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for object pointer as first argument
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_THISCALL:
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
mask = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for hidden address in case of return by value
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
mask = !mask;
|
||||
@ -122,6 +136,14 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
int spos = 0;
|
||||
int dpos = 2;
|
||||
|
||||
if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJFIRST &&
|
||||
callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) )
|
||||
{
|
||||
// Add the object pointer as the first parameter
|
||||
paramBuffer[dpos++] = (asDWORD)secondObject;
|
||||
paramSize++;
|
||||
}
|
||||
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
// TODO: runtime optimize: Declare a reference to descr->parameterTypes[n] so the array doesn't have to be access all the time
|
||||
@ -177,6 +199,15 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
}
|
||||
|
||||
if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJLAST &&
|
||||
callConv <= ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) )
|
||||
{
|
||||
// Add the object pointer as the last parameter
|
||||
paramBuffer[dpos++] = (asDWORD)secondObject;
|
||||
paramSize++;
|
||||
}
|
||||
|
||||
// Keep a free location at the beginning
|
||||
args = ¶mBuffer[2];
|
||||
}
|
||||
@ -193,9 +224,13 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
break;
|
||||
case ICC_THISCALL: // fall through
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_THISCALL_OBJFIRST:
|
||||
case ICC_THISCALL_OBJLAST:
|
||||
retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj);
|
||||
break;
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_THISCALL_OBJLAST_RETURNINMEM:
|
||||
#ifdef __GNUC__
|
||||
// On GNUC the address where the return value will be placed should be put in R0
|
||||
retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
|
||||
@ -208,11 +243,15 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
|
||||
break;
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(asFUNCTION_t**)obj;
|
||||
retQW = armFuncR0(args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj);
|
||||
break;
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(asFUNCTION_t**)obj;
|
||||
#ifdef __GNUC__
|
||||
@ -255,7 +294,7 @@ extern "C" asQWORD armFuncR0R1 (const asDWORD *, int, asFUNCTION_t, asDWORD
|
||||
extern "C" asQWORD armFuncObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD obj);
|
||||
extern "C" asQWORD armFuncR0ObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD obj);
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
@ -307,6 +346,8 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
callConv++;
|
||||
}
|
||||
|
||||
bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST;
|
||||
|
||||
// Linux needs to align 64bit types on even registers, but this isn't done on iOS or Windows Phone
|
||||
// TODO: optimize runtime: There should be a check for this in PrepareSystemFunction() so this
|
||||
// doesn't have to be done for functions that don't have any 64bit types
|
||||
@ -314,19 +355,26 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
// mask is used as a toggler to skip uneven registers.
|
||||
int mask = 1;
|
||||
|
||||
// Check for object pointer as first argument
|
||||
switch( callConv )
|
||||
if( isThisCallMethod )
|
||||
{
|
||||
case ICC_THISCALL:
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
mask = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
mask = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for object pointer as first argument
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_THISCALL:
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
mask = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check for hidden address in case of return by value
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
@ -336,10 +384,19 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
int spos = 0;
|
||||
int dpos = 2;
|
||||
|
||||
if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJFIRST &&
|
||||
callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) )
|
||||
{
|
||||
// Add the object pointer as the first parameter
|
||||
paramBuffer[dpos++] = (asDWORD)secondObject;
|
||||
paramSize++;
|
||||
}
|
||||
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
// TODO: runtime optimize: Declare a reference to descr->parameterTypes[n] so the array doesn't have to be access all the time
|
||||
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
|
||||
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() &&
|
||||
!(descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_ARRAY) )
|
||||
{
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
|
||||
@ -501,6 +558,21 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
}// else...
|
||||
}// Loop
|
||||
|
||||
if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJLAST &&
|
||||
callConv <= ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) )
|
||||
{
|
||||
if (paramSize < 4)
|
||||
{
|
||||
paramBuffer[dpos++] = (asDWORD)secondObject;
|
||||
paramSize++;
|
||||
}
|
||||
else
|
||||
{
|
||||
paramBuffer[stackPos++] = (asDWORD)secondObject;
|
||||
stackSize++;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep a free location at the beginning
|
||||
args = ¶mBuffer[2];
|
||||
}
|
||||
@ -519,9 +591,13 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
break;
|
||||
case ICC_THISCALL: // fall through
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_THISCALL_OBJFIRST:
|
||||
case ICC_THISCALL_OBJLAST:
|
||||
retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj);
|
||||
break;
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_THISCALL_OBJLAST_RETURNINMEM:
|
||||
// On GNUC the address where the return value will be placed should be put in R0
|
||||
retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
|
||||
break;
|
||||
@ -529,11 +605,15 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
|
||||
break;
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(asFUNCTION_t**)obj;
|
||||
retQW = armFuncR0(args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj);
|
||||
break;
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(asFUNCTION_t**)obj;
|
||||
// On GNUC the address where the return value will be placed should be put in R0
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -488,6 +488,7 @@ armFuncR0ObjLast:
|
||||
strge r7, [r6, #8]
|
||||
|
||||
str r5, [r6, #12] /* Put objlast in r6 + 12 */
|
||||
mov r5, #0
|
||||
|
||||
movge r5, #4 /* Set r5 with an offset of #4 if there´s one last arg that couldn´t be placed in r registers */
|
||||
add r5, r5, #4 /* Set r5 with an offset of + #4, so objlast can be loaded into the stack */
|
||||
@ -687,6 +688,12 @@ nomoreargsarmFuncR0R1:
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
#endif /* hard float abi */
|
||||
|
||||
#if defined(__linux__) && defined(__ELF__)
|
||||
/* ref: http://hardened.gentoo.org/gnu-stack.xml */
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* arm */
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
;
|
||||
; AngelCode Scripting Library
|
||||
; Copyright (c) 2003-2013 Andreas Jonsson
|
||||
; Copyright (c) 2003-2014 Andreas Jonsson
|
||||
;
|
||||
; This software is provided 'as-is', without any express or implied
|
||||
; warranty. In no event will the authors be held liable for any
|
||||
@ -29,7 +29,7 @@
|
||||
;
|
||||
|
||||
|
||||
; Assembly routines for the ARM call convention
|
||||
; Assembly routines for the ARM call convention used for Windows CE
|
||||
; Written by Fredrik Ehnbom in June 2009
|
||||
|
||||
; MSVC currently doesn't support inline assembly for the ARM platform
|
||||
|
480
lib/angelscript/source/as_callfunc_arm_vita.S
Normal file
480
lib/angelscript/source/as_callfunc_arm_vita.S
Normal file
@ -0,0 +1,480 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you
|
||||
must not claim that you wrote the original software. If you use
|
||||
this software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
The original version of this library can be located at:
|
||||
http://www.angelcode.com/angelscript/
|
||||
|
||||
Andreas Jonsson
|
||||
andreas@angelcode.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Assembly routines for the Playstation Vita SNC call convention.
|
||||
|
||||
This code was adapted from as_callfunc_arm_gcc (ARM, Linux hard float) by Brandon Bare on October 2014.
|
||||
*/
|
||||
|
||||
#ifdef __psp2__
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-a9
|
||||
.fpu neon
|
||||
|
||||
.section .text.armCallFunc
|
||||
.balign 2
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
.align 2
|
||||
|
||||
.global armFunc
|
||||
.global armFuncR0
|
||||
.global armFuncR0R1
|
||||
.global armFuncObjLast
|
||||
.global armFuncR0ObjLast
|
||||
|
||||
.type armFunc, %function
|
||||
.type armFuncR0, %function
|
||||
.type armFuncR0R1, %function
|
||||
.type armFuncObjLast, %function
|
||||
.type armFuncR0ObjLast, %function
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFunc:
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr} /* sp must be 8-byte alignment for ABI compliance, so the pushed registers must be even */
|
||||
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
|
||||
/* Load float and double args into d0-d7 and s0-s15 */
|
||||
add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */
|
||||
mov r8, #0
|
||||
vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */
|
||||
|
||||
/* If there are no arguments to set into r0-r3 */
|
||||
/* go check if there are arguments for the stack */
|
||||
beq stackargs
|
||||
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
ldrge r0, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
ldrge r1, [r6, #4]
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
ldrge r2, [r6, #8]
|
||||
cmp r7, #16
|
||||
|
||||
it ge
|
||||
ldrge r3, [r6, #12]
|
||||
|
||||
stackargs:
|
||||
ldr r5, [r6, #268] /* Load stack size into r5 */
|
||||
movs r7, r5 /* Load stack size into r7, checking for 0 args */
|
||||
|
||||
/* If there are no args for the stack, branch */
|
||||
beq nomoreargs
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
/* Ensure 8-byte stack alignment */
|
||||
mov r8, sp
|
||||
sub sp, sp, r7
|
||||
add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */
|
||||
|
||||
sub r12, sp, #8
|
||||
bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */
|
||||
sub r8, r8, r12
|
||||
mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */
|
||||
|
||||
stackargsloop:
|
||||
ldr r5, [r6], #4
|
||||
subs r7, r7, #4
|
||||
str r5, [sp], #4
|
||||
bne stackargsloop
|
||||
mov sp, r12
|
||||
|
||||
nomoreargs:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d7 to the address stored in r10 */
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
.fnend
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncObjLast:
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr} /* We´re storing r11 just to keep the stack aligned to an 8 byte boundary */
|
||||
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
|
||||
mov r0, r3 /* objlast. might get overwritten */
|
||||
mov r5, #0 /* This will hold an offset of #4 only if objlast couldn´t be placed into an "r" register */
|
||||
|
||||
/* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */
|
||||
add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */
|
||||
mov r8, #0
|
||||
vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */
|
||||
|
||||
/* If there are no arguments to set into r0-r3 */
|
||||
/* go check if there are arguments for the stack */
|
||||
beq stackargsFuncObjLast
|
||||
|
||||
mov r5, r3 /* store objlast in r5 temporarily */
|
||||
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
ldrge r0, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
ldrge r1, [r6,#4]
|
||||
|
||||
it lt
|
||||
movlt r1, r5
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
ldrge r2, [r6,#8]
|
||||
|
||||
it lt
|
||||
movlt r2, r5
|
||||
cmp r7, #16
|
||||
|
||||
it ge
|
||||
ldrge r3, [r6,#12]
|
||||
|
||||
ittt lt
|
||||
movlt r3, r5
|
||||
movlt r5, #0 /* If objlast got placed into a register, r5 = 0 */
|
||||
blt stackargsFuncObjLast /* If objlast got placed into a register, go to stackargsFuncObjLast */
|
||||
|
||||
str r5, [r6, #12] /* Put objlast in r6 + 12 */
|
||||
mov r5, #4 /* Set r5 with an offset of #4, so objlast can be loaded into the stack */
|
||||
|
||||
stackargsFuncObjLast:
|
||||
ldr r7, [r6, #268] /* Load stack size into r7 */
|
||||
add r7, r7, r5 /* Add the offset placed in r5 (could be #0 or #4) */
|
||||
cmp r7, #0 /* Check for 0 args */
|
||||
|
||||
/* If there are no args for the stack, branch */
|
||||
beq nomoreargsarmFuncObjLast
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
/* Ensure 8-byte stack alignment */
|
||||
mov r8, sp
|
||||
sub sp, sp, r7
|
||||
add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */
|
||||
|
||||
sub r12, sp, #8
|
||||
sub r6, r6, r5 /* r6 = r6 - r5 (r5 can be #0 or #4) */
|
||||
bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */
|
||||
sub r8, r8, r12
|
||||
mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */
|
||||
|
||||
stackargslooparmFuncObjLast:
|
||||
ldr r5, [r6], #4
|
||||
subs r7, r7, #4
|
||||
str r5, [sp], #4
|
||||
bne stackargslooparmFuncObjLast
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncObjLast:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */
|
||||
|
||||
pop {r4-r8, r10,r11, pc}
|
||||
|
||||
.fnend
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncR0ObjLast:
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr}
|
||||
|
||||
ldr r5, [sp,#32] /* objlast to temp reg */
|
||||
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
mov r1, r5 /* objlast. might get overwritten */
|
||||
mov r5, #0 /* This will hold an offset of #4 or #8 if objlast or one arg couldn´t be placed into an "r" register */
|
||||
|
||||
/* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */
|
||||
add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */
|
||||
mov r8, #0
|
||||
vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */
|
||||
|
||||
/* If there are no arguments to set into r0-r3 */
|
||||
/* go check if there are arguments for the stack */
|
||||
beq stackargsFuncR0ObjLast
|
||||
|
||||
mov r5, r1 /* store objlast in r5 temporarily */
|
||||
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
ldrge r1, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
ldrge r2, [r6,#4]
|
||||
|
||||
it lt
|
||||
movlt r2, r5
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
ldrge r3, [r6,#8]
|
||||
|
||||
ittt lt
|
||||
movlt r3, r5
|
||||
movlt r5, #0 /* If objlast got placed into a register, r5 = 0 */
|
||||
blt stackargsFuncR0ObjLast /* If objlast got placed into a register, go to stackargsFuncR0ObjLast */
|
||||
|
||||
cmp r7, #16 /* Else if we have one last arg set the offset accordingly and store the arg in the array */
|
||||
|
||||
itt ge
|
||||
ldrge r7, [r6, #12]
|
||||
strge r7, [r6, #8]
|
||||
|
||||
str r5, [r6, #12] /* Put objlast in r6 + 12 */
|
||||
mov r5, #0
|
||||
|
||||
it ge
|
||||
movge r5, #4 /* Set r5 with an offset of #4 if there´s one last arg that couldn´t be placed in r registers */
|
||||
add r5, r5, #4 /* Set r5 with an offset of + #4, so objlast can be loaded into the stack */
|
||||
|
||||
stackargsFuncR0ObjLast:
|
||||
ldr r7, [r6, #268] /* Load stack size into r7 */
|
||||
add r7, r7, r5 /* Add the offset placed in r5 (could be #0 or #4) */
|
||||
cmp r7, #0 /* Check for 0 args */
|
||||
|
||||
/* If there are no args for the stack, branch */
|
||||
beq nomoreargsarmFuncR0ObjLast
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
/* Ensure 8-byte stack alignment */
|
||||
mov r8, sp
|
||||
sub sp, sp, r7
|
||||
add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */
|
||||
|
||||
sub r12, sp, #8
|
||||
sub r6, r6, r5 /* r6 = r6 - r5 (r5 can be #0 or #4) */
|
||||
bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */
|
||||
sub r8, r8, r12
|
||||
mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */
|
||||
|
||||
stackargslooparmFuncR0ObjLast:
|
||||
ldr r5, [r6], #4
|
||||
subs r7, r7, #4
|
||||
str r5, [sp], #4
|
||||
bne stackargslooparmFuncR0ObjLast
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncR0ObjLast:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
.fnend
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncR0:
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr}
|
||||
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r11, #0 /* This will hold an offset of #4 only if the last arg that should have been placed into an "r" reg needs to go to the stack */
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
|
||||
/* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */
|
||||
add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */
|
||||
mov r8, #0
|
||||
vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */
|
||||
|
||||
/* If there are no arguments to set into r0-r3 */
|
||||
/* go check if there are arguments for the stack */
|
||||
beq stackargsarmFuncR0
|
||||
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
ldrge r1, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
ldrge r2, [r6, #4]
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
ldrge r3, [r6, #8]
|
||||
cmp r7, #16
|
||||
|
||||
it ge
|
||||
movge r11, #4 /* If there is still one arg to be placed, set the offset in r11 to #4 */
|
||||
|
||||
stackargsarmFuncR0:
|
||||
ldr r5, [r6, #268] /* Load stack size into r5 */
|
||||
add r5, r11 /* Add the offset placed in r11 (could be #0 or #4) */
|
||||
movs r7, r5 /* Load stack size into r7, checking for 0 args */
|
||||
|
||||
/* If there are no args for the stack, branch */
|
||||
beq nomoreargsarmFuncR0
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
/* Ensure 8-byte stack alignment */
|
||||
mov r8, sp
|
||||
sub sp, sp, r7
|
||||
add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */
|
||||
|
||||
sub r12, sp, #8
|
||||
sub r6, r6, r11 /* r6 = r6 - r11 (r11 can be #0 or #4) */
|
||||
bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */
|
||||
sub r8, r8, r12
|
||||
mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */
|
||||
|
||||
stackargslooparmFuncR0:
|
||||
ldr r5, [r6], #4
|
||||
subs r7, r7, #4
|
||||
str r5, [sp], #4
|
||||
bne stackargslooparmFuncR0
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncR0:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
.fnend
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncR0R1:
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr}
|
||||
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r11, #0 /* This will hold an offset of #4 or #8 only if the last arg (or last 2 args) that should have been placed into "r" regs need to go to the stack */
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
ldr r1, [sp, #32] /* r1 explicitly set too */
|
||||
|
||||
/* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */
|
||||
add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */
|
||||
mov r8, #0
|
||||
vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */
|
||||
|
||||
/* If there are no arguments to set into r2-r3 */
|
||||
/* go check if there are arguments for the stack */
|
||||
beq stackargsarmFuncR0R1
|
||||
|
||||
/* Load the first 2 arguments into r2-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
ldrge r2, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
ldrge r3, [r6, #4]
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
movge r11, #4 /* If there is a third arg to be placed, set the offset in r11 to #4 */
|
||||
|
||||
cmp r7, #16
|
||||
|
||||
it ge
|
||||
movge r11, #8 /* If there is a fourth arg to be placed, set the offset in r11 to #8 */
|
||||
|
||||
itt lt
|
||||
ldrlt r7, [r6, #8] /* Else copy the third arg to the correct place in the array */
|
||||
strlt r7, [r6, #12]
|
||||
|
||||
stackargsarmFuncR0R1:
|
||||
ldr r5, [r6, #268] /* Load stack size into r5 */
|
||||
add r5, r11 /* Add the offset placed in r11 (could be #0 or #4 or #8) */
|
||||
movs r7, r5 /* Load stack size into r7, checking for 0 args */
|
||||
|
||||
/* If there are no args for the stack, branch */
|
||||
beq nomoreargsarmFuncR0R1
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
/* Ensure 8-byte stack alignment */
|
||||
mov r8, sp
|
||||
sub sp, sp, r7
|
||||
add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */
|
||||
|
||||
sub r12, sp, #8
|
||||
sub r6, r6, r11 /* r6 = r6 - r11 (r11 can be #0 or #4 or #8) */
|
||||
bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */
|
||||
sub r8, r8, r12
|
||||
mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */
|
||||
|
||||
stackargslooparmFuncR0R1:
|
||||
ldr r5, [r6], #4
|
||||
subs r7, r7, #4
|
||||
str r5, [sp], #4
|
||||
bne stackargslooparmFuncR0R1
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncR0R1:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
.fnend
|
||||
|
||||
#endif
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -221,12 +221,14 @@ asQWORD GetReturnedDouble()
|
||||
return d;
|
||||
}
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
int callConv = sysFunc->callConv;
|
||||
|
||||
// TODO: Mips does not yet support THISCALL_OBJFIRST/LAST
|
||||
|
||||
asQWORD retQW = 0;
|
||||
|
||||
void *func = (void*)sysFunc->func;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -482,8 +482,10 @@ static asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD* pArg
|
||||
return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func );
|
||||
}
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/)
|
||||
{
|
||||
// TODO: PPC does not yet support THISCALL_OBJFIRST/LAST
|
||||
|
||||
// use a working array of types, we'll configure the final one in stackArgs
|
||||
asBYTE argsType[2*AS_PPC_MAX_ARGS + 1 + 1 + 1];
|
||||
memset( argsType, 0, sizeof(argsType));
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -547,8 +547,10 @@ inline bool IsVariableArgument( asCDataType type )
|
||||
return (type.GetTokenType() == ttQuestion) ? true : false;
|
||||
}
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/)
|
||||
{
|
||||
// TODO: PPC 64 does not yet support THISCALL_OBJFIRST/LAST
|
||||
|
||||
// use a working array of types, we'll configure the final one in stackArgs
|
||||
asBYTE argsType[AS_PPC_MAX_ARGS + 1 + 1 + 1];
|
||||
memset( argsType, 0, sizeof(argsType));
|
||||
@ -663,7 +665,8 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
|
||||
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() &&
|
||||
!(descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_ARRAY) )
|
||||
{
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -270,8 +270,10 @@ asQWORD GetReturnedDouble()
|
||||
return d;
|
||||
}
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/)
|
||||
{
|
||||
// TODO: SH4 does not yet support THISCALL_OBJFIRST/LAST
|
||||
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
int callConv = sysFunc->callConv;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -34,8 +34,14 @@
|
||||
* Author: Ionut "gargltk" Leonte <ileonte@bitdefender.com>
|
||||
*
|
||||
* Initial author: niteice
|
||||
*
|
||||
* Added support for functor methods by Jordi Oliveras Rovira in April, 2014.
|
||||
*/
|
||||
|
||||
// Useful references for the System V AMD64 ABI:
|
||||
// http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/
|
||||
// http://math-atlas.sourceforge.net/devel/assembly/abi_sysV_amd64.pdf
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
@ -73,6 +79,8 @@ static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, i
|
||||
|
||||
// Backup stack pointer in R15 that is guaranteed to maintain its value over function calls
|
||||
" movq %%rsp, %%r15 \n"
|
||||
// Make sure the stack unwind logic knows we've backed up the stack pointer in register r15
|
||||
" .cfi_def_cfa_register r15 \n"
|
||||
|
||||
// Skip the first 128 bytes on the stack frame, called "red zone",
|
||||
// that might be used by the compiler to store temporary values
|
||||
@ -124,6 +132,8 @@ static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, i
|
||||
|
||||
// Restore stack pointer
|
||||
" mov %%r15, %%rsp \n"
|
||||
// Inform the stack unwind logic that the stack pointer has been restored
|
||||
" .cfi_def_cfa_register rsp \n"
|
||||
|
||||
// Put return value in retQW1 and retQW2, using either RAX:RDX or XMM0:XMM1 depending on type of return value
|
||||
" movl %5, %%ecx \n"
|
||||
@ -152,7 +162,7 @@ static inline bool IsVariableArgument( asCDataType type )
|
||||
return ( type.GetTokenType() == ttQuestion ) ? true : false;
|
||||
}
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2)
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2, void *secondObject)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
@ -172,8 +182,17 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
callConv++;
|
||||
}
|
||||
|
||||
#ifdef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
// Determine the real function pointer in case of virtual method
|
||||
if ( obj && ( callConv == ICC_VIRTUAL_THISCALL || callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ) )
|
||||
#else
|
||||
if ( obj && ( callConv == ICC_VIRTUAL_THISCALL ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) )
|
||||
#endif
|
||||
{
|
||||
vftable = *((funcptr_t**)obj);
|
||||
func = vftable[FuncPtrToUInt(asFUNCTION_t(func)) >> 3];
|
||||
@ -195,6 +214,11 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
|
||||
break;
|
||||
}
|
||||
#ifndef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
case ICC_THISCALL_OBJLAST:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST:
|
||||
param_post = 2;
|
||||
#endif
|
||||
case ICC_THISCALL:
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
@ -206,6 +230,11 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
|
||||
break;
|
||||
}
|
||||
#ifndef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
case ICC_THISCALL_OBJLAST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM:
|
||||
param_post = 2;
|
||||
#endif
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
@ -219,6 +248,32 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
|
||||
break;
|
||||
}
|
||||
#ifndef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
case ICC_THISCALL_OBJFIRST:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST:
|
||||
{
|
||||
paramBuffer[0] = (asPWORD)obj;
|
||||
paramBuffer[1] = (asPWORD)secondObject;
|
||||
argsType[0] = x64INTARG;
|
||||
argsType[1] = x64INTARG;
|
||||
|
||||
argIndex = 2;
|
||||
break;
|
||||
}
|
||||
case ICC_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
{
|
||||
paramBuffer[0] = (asPWORD)retPointer;
|
||||
paramBuffer[1] = (asPWORD)obj;
|
||||
paramBuffer[2] = (asPWORD)secondObject;
|
||||
argsType[0] = x64INTARG;
|
||||
argsType[1] = x64INTARG;
|
||||
argsType[2] = x64INTARG;
|
||||
|
||||
argIndex = 3;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case ICC_CDECL_OBJLAST:
|
||||
param_post = 1;
|
||||
break;
|
||||
@ -337,7 +392,11 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
// For the CDECL_OBJ_LAST calling convention we need to add the object pointer as the last argument
|
||||
if( param_post )
|
||||
{
|
||||
#ifdef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
paramBuffer[argIndex] = (asPWORD)obj;
|
||||
#else
|
||||
paramBuffer[argIndex] = (asPWORD)(param_post > 1 ? secondObject : obj);
|
||||
#endif
|
||||
argsType[argIndex] = x64INTARG;
|
||||
argIndex++;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -31,6 +31,8 @@
|
||||
//
|
||||
// This code was adapted from as_callfunc_x64_msvc by _Vicious_ on August 20th, 2011.
|
||||
//
|
||||
// Added support for functor methods by Jordi Oliveras Rovira in April, 2014.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@ -165,7 +167,7 @@ static asQWORD GetReturnedDouble()
|
||||
return ret;
|
||||
}
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
@ -189,10 +191,16 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
allArgBuffer[paramSize++] = (asQWORD)retPointer;
|
||||
}
|
||||
|
||||
#ifdef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
if( callConv == ICC_THISCALL ||
|
||||
callConv == ICC_THISCALL_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM )
|
||||
#else
|
||||
// Optimization to avoid check 12 values (all ICC_ that contains THISCALL)
|
||||
if( (callConv >= ICC_THISCALL && callConv <= ICC_VIRTUAL_THISCALL_RETURNINMEM) ||
|
||||
(callConv >= ICC_THISCALL_OBJLAST && callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) )
|
||||
#endif
|
||||
{
|
||||
// Add the object pointer as the first parameter
|
||||
allArgBuffer[paramSize++] = (asQWORD)obj;
|
||||
@ -204,8 +212,28 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
// Add the object pointer as the first parameter
|
||||
allArgBuffer[paramSize++] = (asQWORD)obj;
|
||||
}
|
||||
#ifndef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
else if( callConv == ICC_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the first parameter
|
||||
allArgBuffer[paramSize++] = (asQWORD)secondObject;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
if( callConv == ICC_VIRTUAL_THISCALL ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM )
|
||||
#else
|
||||
if( callConv == ICC_VIRTUAL_THISCALL ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM )
|
||||
#endif
|
||||
{
|
||||
// Get the true function pointer from the virtual function table
|
||||
vftable = *(void***)obj;
|
||||
@ -287,6 +315,16 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
// Add the object pointer as the last parameter
|
||||
allArgBuffer[paramSize++] = (asQWORD)obj;
|
||||
}
|
||||
#ifndef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
else if( callConv == ICC_THISCALL_OBJLAST ||
|
||||
callConv == ICC_THISCALL_OBJLAST_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the last parameter
|
||||
allArgBuffer[paramSize++] = (asQWORD)secondObject;
|
||||
}
|
||||
#endif
|
||||
|
||||
retQW = CallX64(allArgBuffer, floatArgBuffer, paramSize*8, (asPWORD)func);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -28,6 +28,9 @@
|
||||
andreas@angelcode.com
|
||||
*/
|
||||
|
||||
//
|
||||
// Added support for thiscall methods by Jordi Oliveras Rovira in April, 2014.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@ -48,7 +51,7 @@ extern "C" asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, int pa
|
||||
extern "C" asDWORD GetReturnedFloat();
|
||||
extern "C" asQWORD GetReturnedDouble();
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
@ -62,10 +65,10 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
asQWORD floatArgBuffer[4];
|
||||
|
||||
int callConv = sysFunc->callConv;
|
||||
if( callConv == ICC_THISCALL ||
|
||||
callConv == ICC_THISCALL_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM )
|
||||
|
||||
// Optimization to avoid check 12 values (all ICC_ that contains THISCALL)
|
||||
if( (callConv >= ICC_THISCALL && callConv <= ICC_VIRTUAL_THISCALL_RETURNINMEM) ||
|
||||
(callConv >= ICC_THISCALL_OBJLAST && callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) )
|
||||
{
|
||||
// Add the object pointer as the first parameter
|
||||
allArgBuffer[paramSize++] = (asQWORD)obj;
|
||||
@ -86,9 +89,21 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
// Add the object pointer as the first parameter
|
||||
allArgBuffer[paramSize++] = (asQWORD)obj;
|
||||
}
|
||||
else if( callConv == ICC_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the first parameter
|
||||
allArgBuffer[paramSize++] = (asQWORD)secondObject;
|
||||
}
|
||||
|
||||
if( callConv == ICC_VIRTUAL_THISCALL ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM )
|
||||
callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Get the true function pointer from the virtual function table
|
||||
vftable = *(void***)obj;
|
||||
@ -100,10 +115,11 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
asUINT spos = 0;
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
|
||||
asCDataType &dt = descr->parameterTypes[n];
|
||||
if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() )
|
||||
{
|
||||
if( descr->parameterTypes[n].GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ||
|
||||
(descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK) )
|
||||
if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ||
|
||||
(dt.GetObjectType()->flags & COMPLEX_MASK) )
|
||||
{
|
||||
allArgBuffer[dpos++] = *(asQWORD*)&args[spos];
|
||||
spos += AS_PTR_SIZE;
|
||||
@ -112,18 +128,18 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
else
|
||||
{
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy(&allArgBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
|
||||
memcpy(&allArgBuffer[dpos], *(void**)(args+spos), dt.GetSizeInMemoryBytes());
|
||||
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+spos));
|
||||
spos += AS_PTR_SIZE;
|
||||
asUINT dwords = descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
asUINT dwords = dt.GetSizeInMemoryDWords();
|
||||
asUINT qwords = (dwords >> 1) + (dwords & 1);
|
||||
dpos += qwords;
|
||||
paramSize += qwords;
|
||||
}
|
||||
}
|
||||
else if( descr->parameterTypes[n].GetTokenType() == ttQuestion )
|
||||
else if( dt.GetTokenType() == ttQuestion )
|
||||
{
|
||||
// Copy the reference and the type id
|
||||
allArgBuffer[dpos++] = *(asQWORD*)&args[spos];
|
||||
@ -134,14 +150,14 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
else
|
||||
{
|
||||
// Copy the value directly
|
||||
asUINT dwords = descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
asUINT dwords = dt.GetSizeOnStackDWords();
|
||||
if( dwords > 1 )
|
||||
{
|
||||
allArgBuffer[dpos] = *(asQWORD*)&args[spos];
|
||||
|
||||
// Double arguments are moved to a separate buffer in order to be placed in the XMM registers,
|
||||
// though this is only done for first 4 arguments, the rest are placed on the stack
|
||||
if( paramSize < 4 && descr->parameterTypes[n].IsDoubleType() )
|
||||
if( paramSize < 4 && dt.IsDoubleType() )
|
||||
floatArgBuffer[dpos] = *(asQWORD*)&args[spos];
|
||||
|
||||
dpos++;
|
||||
@ -153,7 +169,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
|
||||
// Float arguments are moved to a separate buffer in order to be placed in the XMM registers,
|
||||
// though this is only done for first 4 arguments, the rest are placed on the stack
|
||||
if( paramSize < 4 && descr->parameterTypes[n].IsFloatType() )
|
||||
if( paramSize < 4 && dt.IsFloatType() )
|
||||
floatArgBuffer[dpos] = args[spos];
|
||||
|
||||
dpos++;
|
||||
@ -170,6 +186,14 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
// Add the object pointer as the last parameter
|
||||
allArgBuffer[paramSize++] = (asQWORD)obj;
|
||||
}
|
||||
else if( callConv == ICC_THISCALL_OBJLAST ||
|
||||
callConv == ICC_THISCALL_OBJLAST_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the last parameter
|
||||
allArgBuffer[paramSize++] = (asQWORD)secondObject;
|
||||
}
|
||||
|
||||
retQW = CallX64(allArgBuffer, floatArgBuffer, paramSize*8, (asPWORD)func);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -34,6 +34,8 @@
|
||||
//
|
||||
// These functions handle the actual calling of system functions
|
||||
//
|
||||
// Added support for functor methods by Jordi Oliveras Rovira in April, 2014.
|
||||
//
|
||||
|
||||
|
||||
|
||||
@ -87,7 +89,7 @@ asQWORD CallThisCallFunctionRetByRef(const void *, const asDWORD *, int, asFUNCT
|
||||
asDWORD GetReturnedFloat();
|
||||
asQWORD GetReturnedDouble();
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
@ -95,13 +97,30 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
asQWORD retQW = 0;
|
||||
|
||||
// Prepare the parameters
|
||||
int paramSize = sysFunc->paramSize;
|
||||
asDWORD paramBuffer[64];
|
||||
if( sysFunc->takesObjByVal )
|
||||
int callConv = sysFunc->callConv;
|
||||
|
||||
// Changed because need check for ICC_THISCALL_OBJFIRST or
|
||||
// ICC_THISCALL_OBJLAST if sysFunc->takesObjByVal (avoid copy code)
|
||||
// Check if is THISCALL_OBJ* calling convention (in this case needs to add secondObject pointer into stack).
|
||||
bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST;
|
||||
int paramSize = isThisCallMethod || sysFunc->takesObjByVal ? 0 : sysFunc->paramSize;
|
||||
|
||||
int dpos = 1;
|
||||
|
||||
if( isThisCallMethod &&
|
||||
(callConv >= ICC_THISCALL_OBJFIRST &&
|
||||
callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) )
|
||||
{
|
||||
// Add the object pointer as the first parameter
|
||||
paramBuffer[dpos++] = (asDWORD)secondObject;
|
||||
paramSize++;
|
||||
}
|
||||
|
||||
if( sysFunc->takesObjByVal || isThisCallMethod )
|
||||
{
|
||||
paramSize = 0;
|
||||
int spos = 0;
|
||||
int dpos = 1;
|
||||
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
|
||||
@ -146,9 +165,17 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
args = ¶mBuffer[1];
|
||||
}
|
||||
|
||||
if( isThisCallMethod &&
|
||||
(callConv >= ICC_THISCALL_OBJLAST &&
|
||||
callConv <= ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) )
|
||||
{
|
||||
// Add the object pointer as the last parameter
|
||||
paramBuffer[dpos++] = (asDWORD)secondObject;
|
||||
paramSize++;
|
||||
}
|
||||
|
||||
// Make the actual call
|
||||
asFUNCTION_t func = sysFunc->func;
|
||||
int callConv = sysFunc->callConv;
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
callConv++;
|
||||
|
||||
@ -176,14 +203,20 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
break;
|
||||
|
||||
case ICC_THISCALL:
|
||||
case ICC_THISCALL_OBJFIRST:
|
||||
case ICC_THISCALL_OBJLAST:
|
||||
retQW = CallThisCallFunction(obj, args, paramSize<<2, func);
|
||||
break;
|
||||
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_THISCALL_OBJLAST_RETURNINMEM:
|
||||
retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, func, retPointer);
|
||||
break;
|
||||
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST:
|
||||
{
|
||||
// Get virtual function table from the object pointer
|
||||
asFUNCTION_t *vftable = *(asFUNCTION_t**)obj;
|
||||
@ -192,6 +225,8 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
break;
|
||||
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM:
|
||||
{
|
||||
// Get virtual function table from the object pointer
|
||||
asFUNCTION_t *vftable = *(asFUNCTION_t**)obj;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -498,8 +498,10 @@ inline bool IsVariableArgument( asCDataType type )
|
||||
return (type.GetTokenType() == ttQuestion) ? true : false;
|
||||
}
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/)
|
||||
{
|
||||
// TODO: Xenon does not yet support THISCALL_OBJFIRST/LAST
|
||||
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
int callConv = sysFunc->callConv;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -103,6 +103,7 @@ struct asSExprContext
|
||||
property_handle = false;
|
||||
property_ref = false;
|
||||
methodName = "";
|
||||
enumValue = "";
|
||||
}
|
||||
bool IsClassMethod()
|
||||
{
|
||||
@ -143,6 +144,13 @@ struct asSOverloadCandidate
|
||||
asUINT cost;
|
||||
};
|
||||
|
||||
struct asSNamedArgument
|
||||
{
|
||||
asCString name;
|
||||
asSExprContext *ctx;
|
||||
asUINT match;
|
||||
};
|
||||
|
||||
enum EImplicitConv
|
||||
{
|
||||
asIC_IMPLICIT_CONV,
|
||||
@ -206,31 +214,34 @@ protected:
|
||||
int CompileFunctionCall(asCScriptNode *node, asSExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = "");
|
||||
void CompileConstructCall(asCScriptNode *node, asSExprContext *out);
|
||||
void CompileConversion(asCScriptNode *node, asSExprContext *out);
|
||||
int CompileOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out);
|
||||
void CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out);
|
||||
void CompileMathOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out);
|
||||
void CompileBitwiseOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out);
|
||||
void CompileComparisonOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out);
|
||||
void CompileBooleanOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out);
|
||||
bool CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out);
|
||||
int CompileOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileMathOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileBitwiseOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileComparisonOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileBooleanOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
bool CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, bool isHandle = false, eTokenType opToken = ttUnrecognizedToken);
|
||||
int CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *l, asSExprContext *r, asSExprContext *out, bool specificReturn = false, const asCDataType &returnType = asCDataType::CreatePrimitive(ttVoid, false));
|
||||
|
||||
void CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem);
|
||||
int CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode);
|
||||
int CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList);
|
||||
|
||||
int CallDefaultConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem = 0, bool derefDest = false);
|
||||
int CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem = 0, bool derefDest = false);
|
||||
int CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar = false, bool derefDestination = false);
|
||||
void CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc);
|
||||
int CompileArgumentList(asCScriptNode *node, asCArray<asSExprContext *> &args);
|
||||
int CompileDefaultArgs(asCScriptNode *node, asCArray<asSExprContext*> &args, asCScriptFunction *func);
|
||||
asUINT MatchFunctions(asCArray<int> &funcs, asCArray<asSExprContext*> &args, asCScriptNode *node, const char *name, asCObjectType *objectType = NULL, bool isConstMethod = false, bool silent = false, bool allowObjectConstruct = true, const asCString &scope = "");
|
||||
int CompileArgumentList(asCScriptNode *node, asCArray<asSExprContext *> &args, asCArray<asSNamedArgument> &namedArgs);
|
||||
int CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asSExprContext*> &args, int funcId, asCObjectType *type, asCArray<asSNamedArgument> *namedArgs = 0);
|
||||
asUINT MatchFunctions(asCArray<int> &funcs, asCArray<asSExprContext*> &args, asCScriptNode *node, const char *name, asCArray<asSNamedArgument> *namedArgs = NULL, asCObjectType *objectType = NULL, bool isConstMethod = false, bool silent = false, bool allowObjectConstruct = true, const asCString &scope = "");
|
||||
int CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional = false, bool noFunction = false, bool noGlobal = false, asCObjectType *objType = 0);
|
||||
void CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults);
|
||||
bool CompileInitialization(asCScriptNode *node, asCByteCode *bc, asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem);
|
||||
bool CompileAutoType(asCDataType &autoType, asSExprContext &compiledCtx, asCScriptNode *exprNode, asCScriptNode *errNode);
|
||||
bool CompileInitialization(asCScriptNode *node, asCByteCode *bc, asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asSExprContext *preCompiled = 0);
|
||||
void CompileInitAsCopy(asCDataType &type, int offset, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool derefDestination);
|
||||
|
||||
// Helper functions
|
||||
void ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node);
|
||||
int ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node);
|
||||
int ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, eTokenType op, asCScriptNode *errNode);
|
||||
int FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false);
|
||||
int FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false);
|
||||
void PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap = false);
|
||||
@ -241,16 +252,17 @@ protected:
|
||||
void Dereference(asSExprContext *ctx, bool generateCode);
|
||||
bool CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode = true);
|
||||
asUINT MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct = true);
|
||||
int MatchArgument(asCScriptFunction *desc, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct = true);
|
||||
void PerformFunctionCall(int funcId, asSExprContext *out, bool isConstructor = false, asCArray<asSExprContext*> *args = 0, asCObjectType *objTypeForConstruct = 0, bool useVariable = false, int varOffset = 0, int funcPtrVar = 0);
|
||||
void MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args, bool addOneToOffset);
|
||||
void MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asSExprContext*> &args, asCScriptNode *node, bool useVariable = false, int stackOffset = 0, int funcPtrVar = 0);
|
||||
void PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args);
|
||||
void AfterFunctionCall(int funcId, asCArray<asSExprContext*> &args, asSExprContext *ctx, bool deferAll);
|
||||
void ProcessDeferredParams(asSExprContext *ctx);
|
||||
void PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction = false, int refType = 0, bool isMakingCopy = false);
|
||||
int PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction = false, int refType = 0, bool isMakingCopy = false);
|
||||
void PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction = false, int refType = 0, bool isMakingCopy = false);
|
||||
bool IsLValue(asCTypeInfo &type);
|
||||
int DoAssignment(asSExprContext *out, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode);
|
||||
int DoAssignment(asSExprContext *out, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode);
|
||||
void MergeExprBytecode(asSExprContext *before, asSExprContext *after);
|
||||
void MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after);
|
||||
void FilterConst(asCArray<int> &funcs, bool removeConst = true);
|
||||
@ -275,6 +287,7 @@ protected:
|
||||
asUINT ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode);
|
||||
asUINT ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode);
|
||||
void ImplicitConversionConstant(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType);
|
||||
void ImplicitConvObjectToBestMathType(asSExprContext *ctx, asCScriptNode *node);
|
||||
|
||||
void LineInstr(asCByteCode *bc, size_t pos);
|
||||
|
||||
@ -284,7 +297,7 @@ protected:
|
||||
void Error(const asCString &msg, asCScriptNode *node);
|
||||
void Warning(const asCString &msg, asCScriptNode *node);
|
||||
void Information(const asCString &msg, asCScriptNode *node);
|
||||
void PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node);
|
||||
void PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node, asCObjectType *inType = 0);
|
||||
void AddVariableScope(bool isBreakScope = false, bool isContinueScope = false);
|
||||
void RemoveVariableScope();
|
||||
void FinalizeFunction();
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -101,6 +101,10 @@
|
||||
// if the new order of the member initialization caused null pointer exceptions in older
|
||||
// scripts (e.g. if a base class accessed members of a derived class through a virtual method).
|
||||
|
||||
// AS_USE_NAMESPACE
|
||||
// Adds the AngelScript namespace on the declarations.
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Library usage
|
||||
@ -140,12 +144,12 @@
|
||||
// STDCALL
|
||||
// This is used to declare a function to use the stdcall calling convention.
|
||||
|
||||
// AS_USE_NAMESPACE
|
||||
// Adds the AngelScript namespace on the declarations.
|
||||
|
||||
// AS_NO_MEMORY_H
|
||||
// Some compilers don't come with the memory.h header file.
|
||||
|
||||
// AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
// Defined if the support for functor methods hasn't been implemented on the platform.
|
||||
|
||||
|
||||
|
||||
//
|
||||
@ -166,6 +170,9 @@
|
||||
// Embarcadero C++Builder
|
||||
// __BORLANDC__ is defined
|
||||
|
||||
// Sun CC compiler
|
||||
// __SUNPRO_CC is defined
|
||||
|
||||
|
||||
|
||||
//
|
||||
@ -213,6 +220,9 @@
|
||||
// AS_BIG_ENDIAN
|
||||
// Define this for CPUs that use big endian memory layout, e.g. PPC
|
||||
|
||||
// AS_SPARC
|
||||
// Define this for SPARC CPU family
|
||||
|
||||
|
||||
|
||||
//
|
||||
@ -230,6 +240,7 @@
|
||||
// AS_XBOX - Microsoft XBox
|
||||
// AS_XBOX360 - Microsoft XBox 360
|
||||
// AS_PSP - Sony Playstation Portable
|
||||
// AS_PSVITA - Sony Playstation Vita
|
||||
// AS_PS2 - Sony Playstation 2
|
||||
// AS_PS3 - Sony Playstation 3
|
||||
// AS_DC - Sega Dreamcast
|
||||
@ -241,6 +252,7 @@
|
||||
// AS_HAIKU - Haiku
|
||||
// AS_ILLUMOS - Illumos like (OpenSolaris, OpenIndiana, NCP, etc)
|
||||
// AS_MARMALADE - Marmalade cross platform SDK (a layer on top of the OS)
|
||||
// AS_SUN - Sun UNIX
|
||||
|
||||
|
||||
|
||||
@ -339,6 +351,9 @@
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#define THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER
|
||||
|
||||
// Not implemented by default. Undefined with tested platforms.
|
||||
#define AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
|
||||
|
||||
// Embarcadero C++Builder
|
||||
#if defined(__BORLANDC__)
|
||||
@ -437,6 +452,7 @@
|
||||
#define THISCALL_CALLEE_POPS_ARGUMENTS
|
||||
#define STDCALL __stdcall
|
||||
#define AS_SIZEOF_BOOL 1
|
||||
#define COMPLEX_OBJS_PASSED_BY_REF
|
||||
|
||||
#define ASM_INTEL // Intel style for inline assembly on microsoft compilers
|
||||
|
||||
@ -452,14 +468,18 @@
|
||||
#else
|
||||
#if defined(_XBOX) || (defined(_M_IX86) && !defined(__LP64__))
|
||||
#define AS_X86
|
||||
#ifndef _XBOX
|
||||
// Not tested with xbox (only enabled if is Windows)
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#endif
|
||||
#elif defined(_M_X64)
|
||||
#define AS_X64_MSVC
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#define AS_CALLEE_DESTROY_OBJ_BY_VAL
|
||||
#define AS_LARGE_OBJS_PASSED_BY_REF
|
||||
#define AS_LARGE_OBJ_MIN_SIZE 3
|
||||
#define COMPLEX_OBJS_PASSED_BY_REF
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -468,18 +488,22 @@
|
||||
#define AS_CALLEE_DESTROY_OBJ_BY_VAL
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define COMPLEX_OBJS_PASSED_BY_REF
|
||||
#define COMPLEX_MASK asOBJ_APP_CLASS_ASSIGNMENT
|
||||
#define COMPLEX_RETURN_MASK asOBJ_APP_CLASS_ASSIGNMENT
|
||||
#define AS_SOFTFP
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_ARRAY)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_ARRAY)
|
||||
|
||||
// Windows CE uses softfp calling convention, while Windows RT uses hardfp calling convention
|
||||
// ref: http://stackoverflow.com/questions/16375355/what-is-the-windows-rt-on-arm-native-code-calling-convention
|
||||
#if defined(_WIN32_WCE)
|
||||
#define AS_SOFTFP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT)
|
||||
#define COMPLEX_MASK (asOBJ_APP_ARRAY)
|
||||
#endif
|
||||
|
||||
#ifndef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_ARRAY)
|
||||
#endif
|
||||
|
||||
#define UNREACHABLE_RETURN
|
||||
@ -511,13 +535,26 @@
|
||||
|
||||
// SN Systems ProDG
|
||||
#if defined(__SNC__) || defined(SNSYS)
|
||||
#define GNU_STYLE_VIRTUAL_METHOD
|
||||
#define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1))
|
||||
#define CALLEE_POPS_HIDDEN_RETURN_POINTER
|
||||
#define COMPLEX_OBJS_PASSED_BY_REF
|
||||
#define ASM_AT_N_T // AT&T style inline assembly
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR)
|
||||
|
||||
#ifdef __psp2__
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
|
||||
#else
|
||||
#define GNU_STYLE_VIRTUAL_METHOD
|
||||
#define ASM_AT_N_T // AT&T style inline assembly
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR)
|
||||
#endif
|
||||
|
||||
#define AS_SIZEOF_BOOL 1
|
||||
#define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d)
|
||||
|
||||
@ -541,11 +578,22 @@
|
||||
// Support native calling conventions on PS3
|
||||
#define AS_PS3
|
||||
#define AS_PPC_64
|
||||
#define AS_NO_MEMORY_H
|
||||
#define AS_NO_EXCEPTIONS
|
||||
#include <stdlib.h>
|
||||
// PSP
|
||||
#elif defined(__psp__)
|
||||
#define AS_NO_MEMORY_H
|
||||
#define AS_MIPS
|
||||
#define AS_PSP
|
||||
// PSVita
|
||||
#elif defined(__psp2__)
|
||||
#define AS_PSVITA
|
||||
#define AS_ARM
|
||||
#define AS_NO_MEMORY_H
|
||||
#define AS_NO_EXCEPTIONS
|
||||
#define AS_CALLEE_DESTROY_OBJ_BY_VAL
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#endif
|
||||
|
||||
#define UNREACHABLE_RETURN
|
||||
@ -555,16 +603,12 @@
|
||||
// Use the following command to determine predefined macros: echo . | g++ -dM -E -
|
||||
#if (defined(__GNUC__) && !defined(__SNC__)) || defined(EPPC) || defined(__CYGWIN__) // JWC -- use this instead for Wii
|
||||
#define GNU_STYLE_VIRTUAL_METHOD
|
||||
#if !defined( __amd64__ )
|
||||
#define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1))
|
||||
#else
|
||||
#define MULTI_BASE_OFFSET(x) (*((asQWORD*)(&x)+1))
|
||||
#endif
|
||||
#define MULTI_BASE_OFFSET(x) (*((asPWORD*)(&x)+1))
|
||||
#define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d)
|
||||
#define CALLEE_POPS_HIDDEN_RETURN_POINTER
|
||||
#define COMPLEX_OBJS_PASSED_BY_REF
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR)
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#define AS_NO_MEMORY_H
|
||||
#define AS_SIZEOF_BOOL 1
|
||||
#define STDCALL __attribute__((stdcall))
|
||||
@ -618,9 +662,9 @@
|
||||
#undef GNU_STYLE_VIRTUAL_METHOD
|
||||
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
|
||||
#define AS_CALLEE_DESTROY_OBJ_BY_VAL
|
||||
#endif
|
||||
@ -651,6 +695,7 @@
|
||||
#if (defined(_ARM_) || defined(__arm__))
|
||||
// iOS use ARM processor
|
||||
#define AS_ARM
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
@ -666,9 +711,9 @@
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
|
||||
#define COMPLEX_OBJS_PASSED_BY_REF
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
|
||||
// iOS uses soft-float ABI
|
||||
#define AS_SOFTFP
|
||||
@ -692,21 +737,23 @@
|
||||
#elif (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__)
|
||||
// Support native calling conventions on Mac OS X + Intel 32bit CPU
|
||||
#define AS_X86
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
|
||||
#elif defined(__LP64__) && !defined(__ppc__) && !defined(__PPC__) && !defined(__arm64__)
|
||||
// http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html#//apple_ref/doc/uid/TP40005035-SW1
|
||||
#define AS_X64_GCC
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#define HAS_128_BIT_PRIMITIVES
|
||||
#define SPLIT_OBJS_BY_MEMBER_TYPES
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#define AS_LARGE_OBJS_PASSED_BY_REF
|
||||
#define AS_LARGE_OBJ_MIN_SIZE 5
|
||||
// STDCALL is not available on 64bit Mac
|
||||
@ -720,9 +767,9 @@
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
|
||||
#elif (defined(__ppc__) || defined(__PPC__)) && defined(__LP64__)
|
||||
#define AS_PPC_64
|
||||
@ -740,13 +787,14 @@
|
||||
//#define STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
|
||||
#if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__)
|
||||
// Support native calling conventions on Intel 32bit CPU
|
||||
#define AS_X86
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
|
||||
// As of version 4.7 MinGW changed the ABI, presumably
|
||||
// to be better aligned with how MSVC works
|
||||
@ -760,6 +808,7 @@
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
#define AS_X64_MINGW
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#define AS_LARGE_OBJS_PASSED_BY_REF
|
||||
#define AS_LARGE_OBJ_MIN_SIZE 3
|
||||
#define COMPLEX_OBJS_PASSED_BY_REF
|
||||
@ -773,9 +822,9 @@
|
||||
#elif defined(__linux__) && !defined(ANDROID) && !defined(__ANDROID__)
|
||||
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
|
||||
#if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__)
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
@ -785,8 +834,10 @@
|
||||
// Support native calling conventions on Intel 32bit CPU
|
||||
#define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
|
||||
#define AS_X86
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#elif defined(__LP64__) && !defined(__arm64__)
|
||||
#define AS_X64_GCC
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#define HAS_128_BIT_PRIMITIVES
|
||||
#define SPLIT_OBJS_BY_MEMBER_TYPES
|
||||
#define AS_LARGE_OBJS_PASSED_BY_REF
|
||||
@ -797,6 +848,9 @@
|
||||
#elif defined(__ARMEL__) || defined(__arm__)
|
||||
#define AS_ARM
|
||||
|
||||
// TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S
|
||||
#define AS_NO_EXCEPTIONS
|
||||
|
||||
#undef STDCALL
|
||||
#define STDCALL
|
||||
|
||||
@ -825,6 +879,9 @@
|
||||
#define AS_SOFTFP
|
||||
#endif
|
||||
|
||||
// Tested with both hard float and soft float abi
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
|
||||
#elif defined(__mips__)
|
||||
#define AS_MIPS
|
||||
#define AS_BIG_ENDIAN
|
||||
@ -848,9 +905,9 @@
|
||||
#define AS_BSD
|
||||
#if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__)
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
|
||||
#define AS_X86
|
||||
#elif defined(__LP64__)
|
||||
@ -858,9 +915,9 @@
|
||||
#define HAS_128_BIT_PRIMITIVES
|
||||
#define SPLIT_OBJS_BY_MEMBER_TYPES
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#define AS_LARGE_OBJS_PASSED_BY_REF
|
||||
#define AS_LARGE_OBJ_MIN_SIZE 5
|
||||
#undef STDCALL
|
||||
@ -915,36 +972,47 @@
|
||||
#elif defined(ANDROID) || defined(__ANDROID__)
|
||||
#define AS_ANDROID
|
||||
|
||||
// Android NDK 9+ supports posix threads
|
||||
// Android 2.3+ supports posix threads
|
||||
#define AS_POSIX_THREADS
|
||||
|
||||
// Common configuration with Android arm and x86
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
|
||||
#undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
|
||||
#undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
|
||||
#undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
|
||||
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
|
||||
|
||||
#if (defined(_ARM_) || defined(__arm__))
|
||||
// Android ARM
|
||||
|
||||
#undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
|
||||
#undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
|
||||
#undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
|
||||
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
|
||||
|
||||
// The stdcall calling convention is not used on the arm cpu
|
||||
#undef STDCALL
|
||||
#define STDCALL
|
||||
|
||||
#undef GNU_STYLE_VIRTUAL_METHOD
|
||||
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
|
||||
#define AS_ARM
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#define AS_SOFTFP
|
||||
#define AS_CALLEE_DESTROY_OBJ_BY_VAL
|
||||
#elif (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__)
|
||||
// Android Intel x86 (same config as Linux x86). Tested with Intel x86 Atom System Image.
|
||||
|
||||
// Support native calling conventions on Intel 32bit CPU
|
||||
#define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
|
||||
#define AS_X86
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#endif
|
||||
|
||||
// Haiku OS
|
||||
@ -1001,6 +1069,39 @@
|
||||
#define UNREACHABLE_RETURN
|
||||
#endif
|
||||
|
||||
// Sun CC
|
||||
// Initial information provided by Andrey Bergman
|
||||
#if defined(__SUNPRO_CC)
|
||||
#if defined(__sparc)
|
||||
#define AS_SPARC
|
||||
#endif
|
||||
|
||||
#if defined(__sun)
|
||||
#define AS_SUN
|
||||
#endif
|
||||
|
||||
// Native calling conventions is not yet supported for Sun CC
|
||||
#if !defined(AS_MAX_PORTABILITY)
|
||||
#define AS_MAX_PORTABILITY
|
||||
#endif
|
||||
|
||||
// I presume Sun CC uses a similar structure of method pointers as gnuc
|
||||
#define MULTI_BASE_OFFSET(x) (*((asPWORD*)(&x)+1))
|
||||
|
||||
#if !defined(AS_SIZEOF_BOOL)
|
||||
#define AS_SIZEOF_BOOL 1 // sizeof(bool) == 1
|
||||
#endif
|
||||
#if !defined(UNREACHABLE_RETURN)
|
||||
#define UNREACHABLE_RETURN
|
||||
#endif
|
||||
#if !defined(STDCALL)
|
||||
#define STDCALL // There is no stdcall on Solaris/SunPro/SPARC
|
||||
#endif
|
||||
#if !defined(asVSNPRINTF)
|
||||
#define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// Detect target hardware
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -88,10 +88,29 @@ void asCConfigGroup::RefConfigGroup(asCConfigGroup *group)
|
||||
group->AddRef();
|
||||
}
|
||||
|
||||
void asCConfigGroup::AddReferencesForFunc(asCScriptEngine *engine, asCScriptFunction *func)
|
||||
{
|
||||
AddReferencesForType(engine, func->returnType.GetObjectType());
|
||||
for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
|
||||
AddReferencesForType(engine, func->parameterTypes[n].GetObjectType());
|
||||
}
|
||||
|
||||
void asCConfigGroup::AddReferencesForType(asCScriptEngine *engine, asCObjectType *type)
|
||||
{
|
||||
if( type == 0 ) return;
|
||||
|
||||
// Keep reference to other groups
|
||||
RefConfigGroup(engine->FindConfigGroupForObjectType(type));
|
||||
|
||||
// Keep track of which generated template instances the config group uses
|
||||
if( type->flags & asOBJ_TEMPLATE && engine->generatedTemplateTypes.Exists(type) && !generatedTemplateInstances.Exists(type) )
|
||||
generatedTemplateInstances.PushLast(type);
|
||||
}
|
||||
|
||||
bool asCConfigGroup::HasLiveObjects()
|
||||
{
|
||||
for( asUINT n = 0; n < objTypes.GetLength(); n++ )
|
||||
if( objTypes[n]->GetRefCount() != 0 )
|
||||
if( objTypes[n]->externalRefCount.get() != 0 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -123,7 +142,7 @@ void asCConfigGroup::RemoveConfiguration(asCScriptEngine *engine, bool notUsed)
|
||||
int index = engine->registeredGlobalFuncs.GetIndex(scriptFunctions[n]);
|
||||
if( index >= 0 )
|
||||
engine->registeredGlobalFuncs.Erase(index);
|
||||
scriptFunctions[n]->Release();
|
||||
scriptFunctions[n]->ReleaseInternal();
|
||||
if( engine->stringFactory == scriptFunctions[n] )
|
||||
engine->stringFactory = 0;
|
||||
}
|
||||
@ -141,27 +160,24 @@ void asCConfigGroup::RemoveConfiguration(asCScriptEngine *engine, bool notUsed)
|
||||
for( n = 0; n < funcDefs.GetLength(); n++ )
|
||||
{
|
||||
engine->registeredFuncDefs.RemoveValue(funcDefs[n]);
|
||||
funcDefs[n]->Release();
|
||||
funcDefs[n]->ReleaseInternal();
|
||||
engine->RemoveFuncdef(funcDefs[n]);
|
||||
funcDefs[n]->ReleaseInternal();
|
||||
}
|
||||
funcDefs.SetLength(0);
|
||||
|
||||
engine->ClearUnusedTypes();
|
||||
|
||||
// Remove object types (skip this if it is possible other groups are still using the types)
|
||||
if( !notUsed )
|
||||
{
|
||||
for( n = 0; n < objTypes.GetLength(); n++ )
|
||||
for( n = asUINT(objTypes.GetLength()); n-- > 0; )
|
||||
{
|
||||
asCObjectType *t = objTypes[n];
|
||||
asSMapNode<asSNameSpaceNamePair, asCObjectType*> *cursor;
|
||||
if( engine->allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(t->nameSpace, t->name)) &&
|
||||
cursor->value == t )
|
||||
{
|
||||
#ifdef AS_DEBUG
|
||||
ValidateNoUsage(engine, t);
|
||||
#endif
|
||||
|
||||
engine->allRegisteredTypes.Erase(cursor);
|
||||
|
||||
if( engine->defaultArrayObjectType == t )
|
||||
engine->defaultArrayObjectType = 0;
|
||||
|
||||
@ -174,21 +190,17 @@ void asCConfigGroup::RemoveConfiguration(asCScriptEngine *engine, bool notUsed)
|
||||
else
|
||||
engine->registeredObjTypes.RemoveValue(t);
|
||||
|
||||
asDELETE(t, asCObjectType);
|
||||
t->DestroyInternal();
|
||||
t->ReleaseInternal();
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx = engine->templateInstanceTypes.IndexOf(t);
|
||||
if( idx >= 0 )
|
||||
{
|
||||
#ifdef AS_DEBUG
|
||||
ValidateNoUsage(engine, t);
|
||||
#endif
|
||||
|
||||
engine->templateInstanceTypes.RemoveIndexUnordered(idx);
|
||||
t->templateSubTypes.SetLength(0);
|
||||
|
||||
asDELETE(t, asCObjectType);
|
||||
t->DestroyInternal();
|
||||
t->ReleaseInternal();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -201,57 +213,4 @@ void asCConfigGroup::RemoveConfiguration(asCScriptEngine *engine, bool notUsed)
|
||||
referencedConfigGroups.SetLength(0);
|
||||
}
|
||||
|
||||
#ifdef AS_DEBUG
|
||||
void asCConfigGroup::ValidateNoUsage(asCScriptEngine *engine, asCObjectType *type)
|
||||
{
|
||||
for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ )
|
||||
{
|
||||
asCScriptFunction *func = engine->scriptFunctions[n];
|
||||
if( func == 0 ) continue;
|
||||
|
||||
// Ignore factory, list factory, and members
|
||||
if( func->name == "_beh_3_" || func->name == "_beh_4_" || func->objectType == type )
|
||||
continue;
|
||||
|
||||
// Ignore function definitions too, as they aren't released until the engine is destroyed
|
||||
if( func->funcType == asFUNC_FUNCDEF )
|
||||
continue;
|
||||
|
||||
// Ignore functions whose object type has already reached refCount 0 as they are to be removed
|
||||
if( func->objectType && func->objectType->GetRefCount() == 0 )
|
||||
continue;
|
||||
|
||||
if( func->returnType.GetObjectType() == type )
|
||||
{
|
||||
asCString msg;
|
||||
// We can only use the function name here, because the types used by the function may have been deleted already
|
||||
msg.Format(TXT_TYPE_s_IS_STILL_USED_BY_FUNC_s, type->name.AddressOf(), func->GetDeclaration());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
|
||||
}
|
||||
else
|
||||
{
|
||||
for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ )
|
||||
{
|
||||
if( func->parameterTypes[p].GetObjectType() == type )
|
||||
{
|
||||
asCString msg;
|
||||
// We can only use the function name here, because the types used by the function may have been deleted already
|
||||
msg.Format(TXT_TYPE_s_IS_STILL_USED_BY_FUNC_s, type->name.AddressOf(), func->GetDeclaration());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check also usage of the type in global variables
|
||||
|
||||
// TODO: Check also usage of the type in local variables in script functions
|
||||
|
||||
// TODO: Check also usage of the type as members of classes
|
||||
|
||||
// TODO: Check also usage of the type as sub types in other types
|
||||
}
|
||||
#endif
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -63,9 +63,8 @@ public:
|
||||
bool HasLiveObjects();
|
||||
void RemoveConfiguration(asCScriptEngine *engine, bool notUsed = false);
|
||||
|
||||
#ifdef AS_DEBUG
|
||||
void ValidateNoUsage(asCScriptEngine *engine, asCObjectType *type);
|
||||
#endif
|
||||
void AddReferencesForFunc(asCScriptEngine *engine, asCScriptFunction *func);
|
||||
void AddReferencesForType(asCScriptEngine *engine, asCObjectType *type);
|
||||
|
||||
asCString groupName;
|
||||
int refCount;
|
||||
@ -75,6 +74,10 @@ public:
|
||||
asCArray<asCGlobalProperty*> globalProps;
|
||||
asCArray<asCConfigGroup*> referencedConfigGroups;
|
||||
asCArray<asCScriptFunction*> funcDefs;
|
||||
|
||||
// This array holds the generated template instances that are used
|
||||
// by the config group as part of function signature or property
|
||||
asCArray<asCObjectType*> generatedTemplateInstances;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -61,7 +61,6 @@ const int RESERVE_STACK = 2*AS_PTR_SIZE;
|
||||
// For each script function call we push 9 PTRs on the call stack
|
||||
const int CALLSTACK_FRAME_SIZE = 9;
|
||||
|
||||
|
||||
#if defined(AS_DEBUG)
|
||||
|
||||
class asCDebugStats
|
||||
@ -254,15 +253,27 @@ void asCContext::DetachEngine()
|
||||
{
|
||||
if( m_stackBlocks[n] )
|
||||
{
|
||||
#ifndef WIP_16BYTE_ALIGN
|
||||
asDELETEARRAY(m_stackBlocks[n]);
|
||||
#else
|
||||
asDELETEARRAYALIGNED(m_stackBlocks[n]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
m_stackBlocks.SetLength(0);
|
||||
m_stackBlockSize = 0;
|
||||
|
||||
// Clean the user data
|
||||
if( m_userData && m_engine->cleanContextFunc )
|
||||
m_engine->cleanContextFunc(this);
|
||||
for( asUINT n = 0; n < m_userData.GetLength(); n += 2 )
|
||||
{
|
||||
if( m_userData[n+1] )
|
||||
{
|
||||
for( asUINT c = 0; c < m_engine->cleanContextFuncs.GetLength(); c++ )
|
||||
if( m_engine->cleanContextFuncs[c].type == m_userData[n] )
|
||||
m_engine->cleanContextFuncs[c].cleanFunc(this);
|
||||
}
|
||||
}
|
||||
m_userData.SetLength(0);
|
||||
|
||||
// Clear engine pointer
|
||||
if( m_holdEngineRef )
|
||||
@ -277,17 +288,55 @@ asIScriptEngine *asCContext::GetEngine() const
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asCContext::SetUserData(void *data)
|
||||
void *asCContext::SetUserData(void *data, asPWORD type)
|
||||
{
|
||||
void *oldData = m_userData;
|
||||
m_userData = data;
|
||||
return oldData;
|
||||
// As a thread might add a new new user data at the same time as another
|
||||
// it is necessary to protect both read and write access to the userData member
|
||||
ACQUIREEXCLUSIVE(m_engine->engineRWLock);
|
||||
|
||||
// It is not intended to store a lot of different types of userdata,
|
||||
// so a more complex structure like a associative map would just have
|
||||
// more overhead than a simple array.
|
||||
for( asUINT n = 0; n < m_userData.GetLength(); n += 2 )
|
||||
{
|
||||
if( m_userData[n] == type )
|
||||
{
|
||||
void *oldData = reinterpret_cast<void*>(m_userData[n+1]);
|
||||
m_userData[n+1] = reinterpret_cast<asPWORD>(data);
|
||||
|
||||
RELEASEEXCLUSIVE(m_engine->engineRWLock);
|
||||
|
||||
return oldData;
|
||||
}
|
||||
}
|
||||
|
||||
m_userData.PushLast(type);
|
||||
m_userData.PushLast(reinterpret_cast<asPWORD>(data));
|
||||
|
||||
RELEASEEXCLUSIVE(m_engine->engineRWLock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asCContext::GetUserData() const
|
||||
void *asCContext::GetUserData(asPWORD type) const
|
||||
{
|
||||
return m_userData;
|
||||
// There may be multiple threads reading, but when
|
||||
// setting the user data nobody must be reading.
|
||||
ACQUIRESHARED(m_engine->engineRWLock);
|
||||
|
||||
for( asUINT n = 0; n < m_userData.GetLength(); n += 2 )
|
||||
{
|
||||
if( m_userData[n] == type )
|
||||
{
|
||||
RELEASESHARED(m_engine->engineRWLock);
|
||||
return reinterpret_cast<void*>(m_userData[n+1]);
|
||||
}
|
||||
}
|
||||
|
||||
RELEASESHARED(m_engine->engineRWLock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
@ -322,6 +371,16 @@ int asCContext::Prepare(asIScriptFunction *func)
|
||||
// Release the returned object (if any)
|
||||
CleanReturnObject();
|
||||
|
||||
// Release the object if it is a script object
|
||||
if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) )
|
||||
{
|
||||
asCScriptObject *obj = *(asCScriptObject**)&m_regs.stackFramePointer[0];
|
||||
if( obj )
|
||||
obj->Release();
|
||||
|
||||
*(asPWORD*)&m_regs.stackFramePointer[0] = 0;
|
||||
}
|
||||
|
||||
if( m_initialFunction && m_initialFunction == func )
|
||||
{
|
||||
// If the same function is executed again, we can skip a lot of the setup
|
||||
@ -437,6 +496,14 @@ int asCContext::Unprepare()
|
||||
// Release the returned object (if any)
|
||||
CleanReturnObject();
|
||||
|
||||
// Release the object if it is a script object
|
||||
if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) )
|
||||
{
|
||||
asCScriptObject *obj = *(asCScriptObject**)&m_regs.stackFramePointer[0];
|
||||
if( obj )
|
||||
obj->Release();
|
||||
}
|
||||
|
||||
// Release the initial function
|
||||
if( m_initialFunction )
|
||||
{
|
||||
@ -624,8 +691,15 @@ int asCContext::SetObject(void *obj)
|
||||
return asERROR;
|
||||
}
|
||||
|
||||
asASSERT( *(asPWORD*)&m_regs.stackFramePointer[0] == 0 );
|
||||
|
||||
*(asPWORD*)&m_regs.stackFramePointer[0] = (asPWORD)obj;
|
||||
|
||||
// TODO: This should be optional by having a flag where the application can chose whether it should be done or not
|
||||
// The flag could be named something like takeOwnership and have default value of true
|
||||
if( obj && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) )
|
||||
reinterpret_cast<asCScriptObject*>(obj)->AddRef();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -977,6 +1051,44 @@ int asCContext::SetArgObject(asUINT arg, void *obj)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asCContext::SetArgVarType(asUINT arg, void *ptr, int typeId)
|
||||
{
|
||||
if( m_status != asEXECUTION_PREPARED )
|
||||
return asCONTEXT_NOT_PREPARED;
|
||||
|
||||
if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
|
||||
{
|
||||
m_status = asEXECUTION_ERROR;
|
||||
return asINVALID_ARG;
|
||||
}
|
||||
|
||||
// Verify the type of the argument
|
||||
asCDataType *dt = &m_initialFunction->parameterTypes[arg];
|
||||
if( dt->GetTokenType() != ttQuestion )
|
||||
{
|
||||
m_status = asEXECUTION_ERROR;
|
||||
return asINVALID_TYPE;
|
||||
}
|
||||
|
||||
// Determine the position of the argument
|
||||
int offset = 0;
|
||||
if( m_initialFunction->objectType )
|
||||
offset += AS_PTR_SIZE;
|
||||
|
||||
// If function returns object by value an extra pointer is pushed on the stack
|
||||
if( m_returnValueSize )
|
||||
offset += AS_PTR_SIZE;
|
||||
|
||||
for( asUINT n = 0; n < arg; n++ )
|
||||
offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
|
||||
|
||||
// Set the typeId and pointer
|
||||
*(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)ptr;
|
||||
offset += AS_PTR_SIZE;
|
||||
*(int*)(&m_regs.stackFramePointer[offset]) = typeId;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: Instead of GetAddressOfArg, maybe we need a SetArgValue(int arg, void *value, bool takeOwnership) instead.
|
||||
|
||||
@ -1119,6 +1231,14 @@ int asCContext::Execute()
|
||||
SetInternalException(TXT_NULL_POINTER_ACCESS);
|
||||
}
|
||||
}
|
||||
else if( m_currentFunction->funcType == asFUNC_IMPORTED )
|
||||
{
|
||||
int funcId = m_engine->importedFunctions[m_currentFunction->id & ~FUNC_IMPORTED]->boundFunctionId;
|
||||
if( funcId > 0 )
|
||||
m_currentFunction = m_engine->scriptFunctions[funcId];
|
||||
else
|
||||
SetInternalException(TXT_UNBOUND_FUNCTION);
|
||||
}
|
||||
|
||||
if( m_currentFunction->funcType == asFUNC_SCRIPT )
|
||||
{
|
||||
@ -1132,7 +1252,7 @@ int asCContext::Execute()
|
||||
// The current function is an application registered function
|
||||
|
||||
// Call the function directly
|
||||
CallSystemFunction(m_currentFunction->id, this, 0);
|
||||
CallSystemFunction(m_currentFunction->id, this);
|
||||
|
||||
// Was the call successful?
|
||||
if( m_status == asEXECUTION_ACTIVE )
|
||||
@ -1174,13 +1294,12 @@ int asCContext::Execute()
|
||||
if( gcPosObjects > gcPreObjects )
|
||||
{
|
||||
// Execute as many steps as there were new objects created
|
||||
while( gcPosObjects-- > gcPreObjects )
|
||||
m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE);
|
||||
m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE, gcPosObjects - gcPreObjects);
|
||||
}
|
||||
else if( gcPosObjects > 0 )
|
||||
{
|
||||
// Execute at least one step, even if no new objects were created
|
||||
m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE);
|
||||
m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1430,22 +1549,46 @@ int asCContext::GetLineNumber(asUINT stackLevel, int *column, const char **secti
|
||||
// internal
|
||||
bool asCContext::ReserveStackSpace(asUINT size)
|
||||
{
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
// Pad size to a multiple of MAX_TYPE_ALIGNMENT.
|
||||
const asUINT remainder = size % MAX_TYPE_ALIGNMENT;
|
||||
if(remainder != 0)
|
||||
{
|
||||
size = size + (MAX_TYPE_ALIGNMENT - (size % MAX_TYPE_ALIGNMENT));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Make sure the first stack block is allocated
|
||||
if( m_stackBlocks.GetLength() == 0 )
|
||||
{
|
||||
m_stackBlockSize = m_engine->initialContextStackSize;
|
||||
asASSERT( m_stackBlockSize > 0 );
|
||||
|
||||
#ifndef WIP_16BYTE_ALIGN
|
||||
asDWORD *stack = asNEWARRAY(asDWORD,m_stackBlockSize);
|
||||
#else
|
||||
asDWORD *stack = asNEWARRAYALIGNED(asDWORD, m_stackBlockSize, MAX_TYPE_ALIGNMENT);
|
||||
#endif
|
||||
if( stack == 0 )
|
||||
{
|
||||
// Out of memory
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) );
|
||||
#endif
|
||||
|
||||
m_stackBlocks.PushLast(stack);
|
||||
m_stackIndex = 0;
|
||||
m_regs.stackPointer = m_stackBlocks[0] + m_stackBlockSize;
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
// Align the stack pointer. This is necessary as the m_stackBlockSize is not necessarily evenly divisable with the max alignment
|
||||
((asPWORD&)m_regs.stackPointer) &= ~(MAX_TYPE_ALIGNMENT-1);
|
||||
|
||||
asASSERT( isAligned(m_regs.stackPointer, MAX_TYPE_ALIGNMENT) );
|
||||
#endif
|
||||
}
|
||||
|
||||
// Check if there is enough space on the current stack block, otherwise move
|
||||
@ -1472,7 +1615,11 @@ bool asCContext::ReserveStackSpace(asUINT size)
|
||||
if( m_stackBlocks.GetLength() == m_stackIndex )
|
||||
{
|
||||
// Allocate the new stack block, with twice the size of the previous
|
||||
asDWORD *stack = asNEWARRAY(asDWORD,(m_stackBlockSize << m_stackIndex));
|
||||
#ifndef WIP_16BYTE_ALIGN
|
||||
asDWORD *stack = asNEWARRAY(asDWORD, (m_stackBlockSize << m_stackIndex));
|
||||
#else
|
||||
asDWORD *stack = asNEWARRAYALIGNED(asDWORD, (m_stackBlockSize << m_stackIndex), MAX_TYPE_ALIGNMENT);
|
||||
#endif
|
||||
if( stack == 0 )
|
||||
{
|
||||
// Out of memory
|
||||
@ -1484,6 +1631,11 @@ bool asCContext::ReserveStackSpace(asUINT size)
|
||||
SetInternalException(TXT_STACK_OVERFLOW);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) );
|
||||
#endif
|
||||
|
||||
m_stackBlocks.PushLast(stack);
|
||||
}
|
||||
|
||||
@ -1494,6 +1646,13 @@ bool asCContext::ReserveStackSpace(asUINT size)
|
||||
m_currentFunction->GetSpaceNeededForArguments() -
|
||||
(m_currentFunction->objectType ? AS_PTR_SIZE : 0) -
|
||||
(m_currentFunction->DoesReturnOnStack() ? AS_PTR_SIZE : 0);
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
// Align the stack pointer
|
||||
(asPWORD&)m_regs.stackPointer &= ~(MAX_TYPE_ALIGNMENT-1);
|
||||
|
||||
asASSERT( isAligned(m_regs.stackPointer, MAX_TYPE_ALIGNMENT) );
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1512,19 +1671,6 @@ void asCContext::CallScriptFunction(asCScriptFunction *func)
|
||||
m_currentFunction = func;
|
||||
m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf();
|
||||
|
||||
// Make sure there is space on the stack to execute the function
|
||||
asDWORD *oldStackPointer = m_regs.stackPointer;
|
||||
if( !ReserveStackSpace(func->scriptData->stackNeeded) )
|
||||
return;
|
||||
|
||||
// If a new stack block was allocated then we'll need to move
|
||||
// over the function arguments to the new block
|
||||
if( m_regs.stackPointer != oldStackPointer )
|
||||
{
|
||||
int numDwords = func->GetSpaceNeededForArguments() + (func->objectType ? AS_PTR_SIZE : 0) + (func->DoesReturnOnStack() ? AS_PTR_SIZE : 0);
|
||||
memcpy(m_regs.stackPointer, oldStackPointer, sizeof(asDWORD)*numDwords);
|
||||
}
|
||||
|
||||
PrepareScriptFunction();
|
||||
}
|
||||
|
||||
@ -1532,6 +1678,21 @@ void asCContext::PrepareScriptFunction()
|
||||
{
|
||||
asASSERT( m_currentFunction->scriptData );
|
||||
|
||||
// Make sure there is space on the stack to execute the function
|
||||
asDWORD *oldStackPointer = m_regs.stackPointer;
|
||||
if( !ReserveStackSpace(m_currentFunction->scriptData->stackNeeded) )
|
||||
return;
|
||||
|
||||
// If a new stack block was allocated then we'll need to move
|
||||
// over the function arguments to the new block.
|
||||
if( m_regs.stackPointer != oldStackPointer )
|
||||
{
|
||||
int numDwords = m_currentFunction->GetSpaceNeededForArguments() +
|
||||
(m_currentFunction->objectType ? AS_PTR_SIZE : 0) +
|
||||
(m_currentFunction->DoesReturnOnStack() ? AS_PTR_SIZE : 0);
|
||||
memcpy(m_regs.stackPointer, oldStackPointer, sizeof(asDWORD)*numDwords);
|
||||
}
|
||||
|
||||
// Update framepointer
|
||||
m_regs.stackFramePointer = m_regs.stackPointer;
|
||||
|
||||
@ -2329,7 +2490,7 @@ void asCContext::ExecuteNext()
|
||||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
l_sp += CallSystemFunction(i, this, 0);
|
||||
l_sp += CallSystemFunction(i, this);
|
||||
|
||||
// Update the program position after the call so that line number is correct
|
||||
l_bc += 2;
|
||||
@ -2361,9 +2522,9 @@ void asCContext::ExecuteNext()
|
||||
|
||||
case asBC_CALLBND:
|
||||
{
|
||||
// TODO: Clean-up: This code is very similar to asBC_CallPtr. Create a shared method for them
|
||||
// Get the function ID from the stack
|
||||
int i = asBC_INTARG(l_bc);
|
||||
l_bc += 2;
|
||||
|
||||
asASSERT( i >= 0 );
|
||||
asASSERT( i & FUNC_IMPORTED );
|
||||
@ -2376,6 +2537,9 @@ void asCContext::ExecuteNext()
|
||||
int funcId = m_engine->importedFunctions[i & ~FUNC_IMPORTED]->boundFunctionId;
|
||||
if( funcId == -1 )
|
||||
{
|
||||
// Need to update the program pointer for the exception handler
|
||||
m_regs.programPointer += 2;
|
||||
|
||||
// Tell the exception handler to clean up the arguments to this function
|
||||
m_needToCleanupArgs = true;
|
||||
SetInternalException(TXT_UNBOUND_FUNCTION);
|
||||
@ -2384,8 +2548,46 @@ void asCContext::ExecuteNext()
|
||||
else
|
||||
{
|
||||
asCScriptFunction *func = m_engine->GetScriptFunction(funcId);
|
||||
if( func->funcType == asFUNC_SCRIPT )
|
||||
{
|
||||
m_regs.programPointer += 2;
|
||||
CallScriptFunction(func);
|
||||
}
|
||||
else if( func->funcType == asFUNC_DELEGATE )
|
||||
{
|
||||
// Push the object pointer on the stack. There is always a reserved space for this so
|
||||
// we don't don't need to worry about overflowing the allocated memory buffer
|
||||
asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] );
|
||||
m_regs.stackPointer -= AS_PTR_SIZE;
|
||||
*(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate);
|
||||
|
||||
CallScriptFunction(func);
|
||||
// Call the delegated method
|
||||
if( func->funcForDelegate->funcType == asFUNC_SYSTEM )
|
||||
{
|
||||
m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this);
|
||||
|
||||
// Update program position after the call so the line number
|
||||
// is correct in case the system function queries it
|
||||
m_regs.programPointer += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_regs.programPointer += 2;
|
||||
|
||||
// TODO: run-time optimize: The true method could be figured out when creating the delegate
|
||||
CallInterfaceMethod(func->funcForDelegate);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asASSERT( func->funcType == asFUNC_SYSTEM );
|
||||
|
||||
m_regs.stackPointer += CallSystemFunction(func->id, this);
|
||||
|
||||
// Update program position after the call so the line number
|
||||
// is correct in case the system function queries it
|
||||
m_regs.programPointer += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the values from the context again
|
||||
@ -2476,13 +2678,17 @@ void asCContext::ExecuteNext()
|
||||
|
||||
if( func )
|
||||
{
|
||||
// Push the object pointer on the stack (it will be popped by the function)
|
||||
l_sp -= AS_PTR_SIZE;
|
||||
*(asPWORD*)l_sp = (asPWORD)mem;
|
||||
|
||||
// Need to move the values back to the context as the called functions
|
||||
// may use the debug interface to inspect the registers
|
||||
m_regs.programPointer = l_bc;
|
||||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
l_sp += CallSystemFunction(func, this, mem);
|
||||
l_sp += CallSystemFunction(func, this);
|
||||
}
|
||||
|
||||
// Pop the variable address from the stack
|
||||
@ -3352,7 +3558,7 @@ void asCContext::ExecuteNext()
|
||||
break;
|
||||
|
||||
case asBC_u64TOf:
|
||||
#if _MSC_VER <= 1200 // MSVC6
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC6
|
||||
{
|
||||
// MSVC6 doesn't permit UINT64 to double
|
||||
asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc));
|
||||
@ -3373,7 +3579,7 @@ void asCContext::ExecuteNext()
|
||||
break;
|
||||
|
||||
case asBC_u64TOd:
|
||||
#if _MSC_VER <= 1200 // MSVC6
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC6
|
||||
{
|
||||
// MSVC6 doesn't permit UINT64 to double
|
||||
asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
|
||||
@ -3655,7 +3861,7 @@ void asCContext::ExecuteNext()
|
||||
// Call the delegated method
|
||||
if( func->funcForDelegate->funcType == asFUNC_SYSTEM )
|
||||
{
|
||||
m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this, 0);
|
||||
m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this);
|
||||
|
||||
// Update program position after the call so the line number
|
||||
// is correct in case the system function queries it
|
||||
@ -3673,7 +3879,7 @@ void asCContext::ExecuteNext()
|
||||
{
|
||||
asASSERT( func->funcType == asFUNC_SYSTEM );
|
||||
|
||||
m_regs.stackPointer += CallSystemFunction(func->id, this, 0);
|
||||
m_regs.stackPointer += CallSystemFunction(func->id, this);
|
||||
|
||||
// Update program position after the call so the line number
|
||||
// is correct in case the system function queries it
|
||||
@ -3906,7 +4112,11 @@ void asCContext::ExecuteNext()
|
||||
|
||||
asUINT size = asBC_DWORDARG(l_bc);
|
||||
asBYTE **var = (asBYTE**)(l_fp - asBC_SWORDARG0(l_bc));
|
||||
#ifndef WIP_16BYTE_ALIGN
|
||||
*var = asNEWARRAY(asBYTE, size);
|
||||
#else
|
||||
*var = asNEWARRAYALIGNED(asBYTE, size, MAX_TYPE_ALIGNMENT);
|
||||
#endif
|
||||
|
||||
// Clear the buffer for the pointers that will be placed in it
|
||||
memset(*var, 0, size);
|
||||
@ -4622,23 +4832,6 @@ void asCContext::CleanStackFrame()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the object is a script declared object, then we must release it
|
||||
// as the compiler adds a reference at the entry of the function. Make sure
|
||||
// the function has actually been entered
|
||||
if( m_currentFunction->objectType && m_regs.programPointer != m_currentFunction->scriptData->byteCode.AddressOf() )
|
||||
{
|
||||
// Methods returning a reference or constructors don't add a reference
|
||||
if( !m_currentFunction->returnType.IsReference() && m_currentFunction->name != m_currentFunction->objectType->name )
|
||||
{
|
||||
asSTypeBehaviour *beh = &m_currentFunction->objectType->beh;
|
||||
if( beh->release && *(asPWORD*)&m_regs.stackFramePointer[0] != 0 )
|
||||
{
|
||||
m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[0], beh->release);
|
||||
*(asPWORD*)&m_regs.stackFramePointer[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
m_isStackMemoryNotAllocated = false;
|
||||
@ -4729,13 +4922,14 @@ asEContextState asCContext::GetState() const
|
||||
// interface
|
||||
int asCContext::SetLineCallback(asSFuncPtr callback, void *obj, int callConv)
|
||||
{
|
||||
m_lineCallback = true;
|
||||
m_regs.doProcessSuspend = true;
|
||||
// First turn off the line callback to avoid a second thread
|
||||
// attempting to call it while the new one is still being set
|
||||
m_lineCallback = false;
|
||||
|
||||
m_lineCallbackObj = obj;
|
||||
bool isObj = false;
|
||||
if( (unsigned)callConv == asCALL_GENERIC )
|
||||
if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST )
|
||||
{
|
||||
m_lineCallback = false;
|
||||
m_regs.doProcessSuspend = m_doSuspend;
|
||||
return asNOT_SUPPORTED;
|
||||
}
|
||||
@ -4744,15 +4938,18 @@ int asCContext::SetLineCallback(asSFuncPtr callback, void *obj, int callConv)
|
||||
isObj = true;
|
||||
if( obj == 0 )
|
||||
{
|
||||
m_lineCallback = false;
|
||||
m_regs.doProcessSuspend = m_doSuspend;
|
||||
return asINVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_lineCallbackFunc);
|
||||
if( r < 0 ) m_lineCallback = false;
|
||||
|
||||
// Turn on the line callback after setting both the function pointer and object pointer
|
||||
if( r >= 0 ) m_lineCallback = true;
|
||||
|
||||
// The BC_SUSPEND instruction should be processed if either line
|
||||
// callback is set or if the application has requested a suspension
|
||||
m_regs.doProcessSuspend = m_doSuspend || m_lineCallback;
|
||||
|
||||
return r;
|
||||
@ -4772,7 +4969,7 @@ int asCContext::SetExceptionCallback(asSFuncPtr callback, void *obj, int callCon
|
||||
m_exceptionCallback = true;
|
||||
m_exceptionCallbackObj = obj;
|
||||
bool isObj = false;
|
||||
if( (unsigned)callConv == asCALL_GENERIC )
|
||||
if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST )
|
||||
return asNOT_SUPPORTED;
|
||||
if( (unsigned)callConv >= asCALL_THISCALL )
|
||||
{
|
||||
@ -4809,91 +5006,79 @@ void asCContext::ClearExceptionCallback()
|
||||
m_exceptionCallback = false;
|
||||
}
|
||||
|
||||
int asCContext::CallGeneric(int id, void *objectPointer)
|
||||
int asCContext::CallGeneric(asCScriptFunction *descr)
|
||||
{
|
||||
asCScriptFunction *sysFunction = m_engine->scriptFunctions[id];
|
||||
asSSystemFunctionInterface *sysFunc = sysFunction->sysFuncIntf;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
void (*func)(asIScriptGeneric*) = (void (*)(asIScriptGeneric*))sysFunc->func;
|
||||
int popSize = sysFunc->paramSize;
|
||||
asDWORD *args = m_regs.stackPointer;
|
||||
|
||||
// Verify the object pointer if it is a class method
|
||||
void *currentObject = 0;
|
||||
asASSERT( sysFunc->callConv == ICC_GENERIC_FUNC || sysFunc->callConv == ICC_GENERIC_METHOD );
|
||||
if( sysFunc->callConv == ICC_GENERIC_METHOD )
|
||||
{
|
||||
if( objectPointer )
|
||||
// The object pointer should be popped from the context stack
|
||||
popSize += AS_PTR_SIZE;
|
||||
|
||||
// Check for null pointer
|
||||
currentObject = (void*)*(asPWORD*)(args);
|
||||
if( currentObject == 0 )
|
||||
{
|
||||
currentObject = objectPointer;
|
||||
|
||||
// Don't increase the reference of this pointer
|
||||
// since it will not have been constructed yet
|
||||
SetInternalException(TXT_NULL_POINTER_ACCESS);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The object pointer should be popped from the context stack
|
||||
popSize += AS_PTR_SIZE;
|
||||
|
||||
// Check for null pointer
|
||||
currentObject = (void*)*(asPWORD*)(args);
|
||||
if( currentObject == 0 )
|
||||
{
|
||||
SetInternalException(TXT_NULL_POINTER_ACCESS);
|
||||
return 0;
|
||||
}
|
||||
asASSERT( sysFunc->baseOffset == 0 );
|
||||
|
||||
// Add the base offset for multiple inheritance
|
||||
currentObject = (void*)(asPWORD(currentObject) + sysFunc->baseOffset);
|
||||
|
||||
// Skip object pointer
|
||||
args += AS_PTR_SIZE;
|
||||
}
|
||||
// Skip object pointer
|
||||
args += AS_PTR_SIZE;
|
||||
}
|
||||
|
||||
if( sysFunction->DoesReturnOnStack() )
|
||||
if( descr->DoesReturnOnStack() )
|
||||
{
|
||||
// Skip the address where the return value will be stored
|
||||
args += AS_PTR_SIZE;
|
||||
popSize += AS_PTR_SIZE;
|
||||
}
|
||||
|
||||
asCGeneric gen(m_engine, sysFunction, currentObject, args);
|
||||
asCGeneric gen(m_engine, descr, currentObject, args);
|
||||
|
||||
m_callingSystemFunction = sysFunction;
|
||||
m_callingSystemFunction = descr;
|
||||
func(&gen);
|
||||
m_callingSystemFunction = 0;
|
||||
|
||||
m_regs.valueRegister = gen.returnVal;
|
||||
m_regs.objectRegister = gen.objectRegister;
|
||||
m_regs.objectType = sysFunction->returnType.GetObjectType();
|
||||
m_regs.objectType = descr->returnType.GetObjectType();
|
||||
|
||||
// Clean up function parameters
|
||||
int offset = 0;
|
||||
for( asUINT n = 0; n < sysFunction->parameterTypes.GetLength(); n++ )
|
||||
// Clean up arguments
|
||||
const asUINT cleanCount = sysFunc->cleanArgs.GetLength();
|
||||
if( cleanCount )
|
||||
{
|
||||
if( sysFunction->parameterTypes[n].IsObject() && !sysFunction->parameterTypes[n].IsReference() )
|
||||
asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf();
|
||||
for( asUINT n = 0; n < cleanCount; n++, clean++ )
|
||||
{
|
||||
void *obj = *(void**)&args[offset];
|
||||
if( obj )
|
||||
void **addr = (void**)&args[clean->off];
|
||||
if( clean->op == 0 )
|
||||
{
|
||||
// Release the object
|
||||
asSTypeBehaviour *beh = &sysFunction->parameterTypes[n].GetObjectType()->beh;
|
||||
if( sysFunction->parameterTypes[n].GetObjectType()->flags & asOBJ_REF )
|
||||
if( *addr != 0 )
|
||||
{
|
||||
asASSERT( (sysFunction->parameterTypes[n].GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release );
|
||||
if( beh->release )
|
||||
m_engine->CallObjectMethod(obj, beh->release);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Call the destructor then free the memory
|
||||
if( beh->destruct )
|
||||
m_engine->CallObjectMethod(obj, beh->destruct);
|
||||
|
||||
m_engine->CallFree(obj);
|
||||
m_engine->CallObjectMethod(*addr, clean->ot->beh.release);
|
||||
*addr = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asASSERT( clean->op == 1 || clean->op == 2 );
|
||||
asASSERT( *addr );
|
||||
|
||||
if( clean->op == 2 )
|
||||
m_engine->CallObjectMethod(*addr, clean->ot->beh.destruct);
|
||||
|
||||
m_engine->CallFree(*addr);
|
||||
}
|
||||
}
|
||||
offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
|
||||
// Return how much should be popped from the stack
|
||||
|
@ -76,14 +76,15 @@ public:
|
||||
int SetObject(void *obj);
|
||||
|
||||
// Arguments
|
||||
int SetArgByte(asUINT arg, asBYTE value);
|
||||
int SetArgWord(asUINT arg, asWORD value);
|
||||
int SetArgDWord(asUINT arg, asDWORD value);
|
||||
int SetArgQWord(asUINT arg, asQWORD value);
|
||||
int SetArgFloat(asUINT arg, float value);
|
||||
int SetArgDouble(asUINT arg, double value);
|
||||
int SetArgAddress(asUINT arg, void *addr);
|
||||
int SetArgObject(asUINT arg, void *obj);
|
||||
int SetArgByte(asUINT arg, asBYTE value);
|
||||
int SetArgWord(asUINT arg, asWORD value);
|
||||
int SetArgDWord(asUINT arg, asDWORD value);
|
||||
int SetArgQWord(asUINT arg, asQWORD value);
|
||||
int SetArgFloat(asUINT arg, float value);
|
||||
int SetArgDouble(asUINT arg, double value);
|
||||
int SetArgAddress(asUINT arg, void *addr);
|
||||
int SetArgObject(asUINT arg, void *obj);
|
||||
int SetArgVarType(asUINT arg, void *ptr, int typeId);
|
||||
void *GetAddressOfArg(asUINT arg);
|
||||
|
||||
// Return value
|
||||
@ -122,8 +123,8 @@ public:
|
||||
asIScriptFunction *GetSystemFunction();
|
||||
|
||||
// User data
|
||||
void *SetUserData(void *data);
|
||||
void *GetUserData() const;
|
||||
void *SetUserData(void *data, asPWORD type);
|
||||
void *GetUserData(asPWORD type) const;
|
||||
|
||||
public:
|
||||
// Internal public functions
|
||||
@ -136,7 +137,7 @@ public:
|
||||
void CallLineCallback();
|
||||
void CallExceptionCallback();
|
||||
|
||||
int CallGeneric(int funcID, void *objectPointer);
|
||||
int CallGeneric(asCScriptFunction *func);
|
||||
|
||||
void DetachEngine();
|
||||
|
||||
@ -204,7 +205,7 @@ public:
|
||||
asSSystemFunctionInterface m_exceptionCallbackFunc;
|
||||
void * m_exceptionCallbackObj;
|
||||
|
||||
void *m_userData;
|
||||
asCArray<asPWORD> m_userData;
|
||||
|
||||
// Registers available to JIT compiler functions
|
||||
asSVMRegisters m_regs;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -46,24 +46,28 @@ BEGIN_AS_NAMESPACE
|
||||
|
||||
asCDataType::asCDataType()
|
||||
{
|
||||
tokenType = ttUnrecognizedToken;
|
||||
objectType = 0;
|
||||
isReference = false;
|
||||
isReadOnly = false;
|
||||
isObjectHandle = false;
|
||||
isConstHandle = false;
|
||||
funcDef = 0;
|
||||
tokenType = ttUnrecognizedToken;
|
||||
objectType = 0;
|
||||
isReference = false;
|
||||
isReadOnly = false;
|
||||
isAuto = false;
|
||||
isObjectHandle = false;
|
||||
isConstHandle = false;
|
||||
funcDef = 0;
|
||||
isHandleToAsHandleType = false;
|
||||
}
|
||||
|
||||
asCDataType::asCDataType(const asCDataType &dt)
|
||||
{
|
||||
tokenType = dt.tokenType;
|
||||
objectType = dt.objectType;
|
||||
isReference = dt.isReference;
|
||||
isReadOnly = dt.isReadOnly;
|
||||
isObjectHandle = dt.isObjectHandle;
|
||||
isConstHandle = dt.isConstHandle;
|
||||
funcDef = dt.funcDef;
|
||||
tokenType = dt.tokenType;
|
||||
objectType = dt.objectType;
|
||||
isReference = dt.isReference;
|
||||
isReadOnly = dt.isReadOnly;
|
||||
isAuto = dt.isAuto;
|
||||
isObjectHandle = dt.isObjectHandle;
|
||||
isConstHandle = dt.isConstHandle;
|
||||
funcDef = dt.funcDef;
|
||||
isHandleToAsHandleType = dt.isHandleToAsHandleType;
|
||||
}
|
||||
|
||||
asCDataType::~asCDataType()
|
||||
@ -90,6 +94,17 @@ asCDataType asCDataType::CreateObject(asCObjectType *ot, bool isConst)
|
||||
return dt;
|
||||
}
|
||||
|
||||
asCDataType asCDataType::CreateAuto(bool isConst)
|
||||
{
|
||||
asCDataType dt;
|
||||
|
||||
dt.tokenType = ttIdentifier;
|
||||
dt.isReadOnly = isConst;
|
||||
dt.isAuto = true;
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
asCDataType asCDataType::CreateObjectHandle(asCObjectType *ot, bool isConst)
|
||||
{
|
||||
asCDataType dt;
|
||||
@ -144,7 +159,7 @@ bool asCDataType::IsNullHandle() const
|
||||
return false;
|
||||
}
|
||||
|
||||
asCString asCDataType::Format(bool includeNamespace) const
|
||||
asCString asCDataType::Format(asSNameSpace *currNs, bool includeNamespace) const
|
||||
{
|
||||
if( IsNullHandle() )
|
||||
return "<null handle>";
|
||||
@ -154,11 +169,13 @@ asCString asCDataType::Format(bool includeNamespace) const
|
||||
if( isReadOnly )
|
||||
str = "const ";
|
||||
|
||||
if( includeNamespace )
|
||||
// If the type is not declared in the current namespace, then the namespace
|
||||
// must always be informed to guarantee that the correct type is informed
|
||||
if( includeNamespace || (objectType && objectType->nameSpace != currNs) || (funcDef && funcDef->nameSpace != currNs) )
|
||||
{
|
||||
if( objectType )
|
||||
if( objectType && objectType->nameSpace->name != "" )
|
||||
str += objectType->nameSpace->name + "::";
|
||||
else if( funcDef )
|
||||
else if( funcDef && funcDef->nameSpace->name != "" )
|
||||
str += funcDef->nameSpace->name + "::";
|
||||
}
|
||||
|
||||
@ -169,7 +186,7 @@ asCString asCDataType::Format(bool includeNamespace) const
|
||||
else if( IsArrayType() && objectType && !objectType->engine->ep.expandDefaultArrayToTemplate )
|
||||
{
|
||||
asASSERT( objectType->templateSubTypes.GetLength() == 1 );
|
||||
str += objectType->templateSubTypes[0].Format(includeNamespace);
|
||||
str += objectType->templateSubTypes[0].Format(currNs, includeNamespace);
|
||||
str += "[]";
|
||||
}
|
||||
else if( funcDef )
|
||||
@ -184,13 +201,20 @@ asCString asCDataType::Format(bool includeNamespace) const
|
||||
str += "<";
|
||||
for( asUINT subtypeIndex = 0; subtypeIndex < objectType->templateSubTypes.GetLength(); subtypeIndex++ )
|
||||
{
|
||||
str += objectType->templateSubTypes[subtypeIndex].Format(includeNamespace);
|
||||
str += objectType->templateSubTypes[subtypeIndex].Format(currNs, includeNamespace);
|
||||
if( subtypeIndex != objectType->templateSubTypes.GetLength()-1 )
|
||||
str += ",";
|
||||
}
|
||||
str += ">";
|
||||
}
|
||||
}
|
||||
else if( isAuto )
|
||||
{
|
||||
if( isObjectHandle )
|
||||
str += "<auto@>";
|
||||
else
|
||||
str += "<auto>";
|
||||
}
|
||||
else
|
||||
{
|
||||
str = "<unknown>";
|
||||
@ -211,13 +235,15 @@ asCString asCDataType::Format(bool includeNamespace) const
|
||||
|
||||
asCDataType &asCDataType::operator =(const asCDataType &dt)
|
||||
{
|
||||
tokenType = dt.tokenType;
|
||||
isReference = dt.isReference;
|
||||
objectType = dt.objectType;
|
||||
isReadOnly = dt.isReadOnly;
|
||||
isObjectHandle = dt.isObjectHandle;
|
||||
isConstHandle = dt.isConstHandle;
|
||||
funcDef = dt.funcDef;
|
||||
tokenType = dt.tokenType;
|
||||
isReference = dt.isReference;
|
||||
objectType = dt.objectType;
|
||||
isReadOnly = dt.isReadOnly;
|
||||
isObjectHandle = dt.isObjectHandle;
|
||||
isConstHandle = dt.isConstHandle;
|
||||
isAuto = dt.isAuto;
|
||||
funcDef = dt.funcDef;
|
||||
isHandleToAsHandleType = dt.isHandleToAsHandleType;
|
||||
|
||||
return (asCDataType &)*this;
|
||||
}
|
||||
@ -226,35 +252,46 @@ int asCDataType::MakeHandle(bool b, bool acceptHandleForScope)
|
||||
{
|
||||
if( !b )
|
||||
{
|
||||
isObjectHandle = b;
|
||||
isObjectHandle = false;
|
||||
isConstHandle = false;
|
||||
isHandleToAsHandleType = false;
|
||||
}
|
||||
else if( b && !isObjectHandle )
|
||||
else
|
||||
{
|
||||
// Only reference types are allowed to be handles,
|
||||
// but not nohandle reference types, and not scoped references
|
||||
// (except when returned from registered function)
|
||||
// funcdefs are special reference types and support handles
|
||||
// value types with asOBJ_ASHANDLE are treated as a handle
|
||||
if( !funcDef &&
|
||||
(!objectType ||
|
||||
!((objectType->flags & asOBJ_REF) || (objectType->flags & asOBJ_TEMPLATE_SUBTYPE) || (objectType->flags & asOBJ_ASHANDLE)) ||
|
||||
(objectType->flags & asOBJ_NOHANDLE) ||
|
||||
((objectType->flags & asOBJ_SCOPED) && !acceptHandleForScope)) )
|
||||
return -1;
|
||||
if( isAuto )
|
||||
{
|
||||
isObjectHandle = true;
|
||||
}
|
||||
else if( !isObjectHandle )
|
||||
{
|
||||
// Only reference types are allowed to be handles,
|
||||
// but not nohandle reference types, and not scoped references
|
||||
// (except when returned from registered function)
|
||||
// funcdefs are special reference types and support handles
|
||||
// value types with asOBJ_ASHANDLE are treated as a handle
|
||||
if( !funcDef &&
|
||||
(!objectType ||
|
||||
!((objectType->flags & asOBJ_REF) || (objectType->flags & asOBJ_TEMPLATE_SUBTYPE) || (objectType->flags & asOBJ_ASHANDLE)) ||
|
||||
(objectType->flags & asOBJ_NOHANDLE) ||
|
||||
((objectType->flags & asOBJ_SCOPED) && !acceptHandleForScope)) )
|
||||
return -1;
|
||||
|
||||
isObjectHandle = b;
|
||||
isConstHandle = false;
|
||||
isObjectHandle = b;
|
||||
isConstHandle = false;
|
||||
|
||||
// ASHANDLE supports being handle, but as it really is a value type it will not be marked as a handle
|
||||
if( (objectType->flags & asOBJ_ASHANDLE) )
|
||||
isObjectHandle = false;
|
||||
// ASHANDLE supports being handle, but as it really is a value type it will not be marked as a handle
|
||||
if( (objectType->flags & asOBJ_ASHANDLE) )
|
||||
{
|
||||
isObjectHandle = false;
|
||||
isHandleToAsHandleType = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asCDataType::MakeArray(asCScriptEngine *engine)
|
||||
int asCDataType::MakeArray(asCScriptEngine *engine, asCModule *module)
|
||||
{
|
||||
if( engine->defaultArrayObjectType == 0 )
|
||||
return asINVALID_TYPE;
|
||||
@ -263,7 +300,7 @@ int asCDataType::MakeArray(asCScriptEngine *engine)
|
||||
isReadOnly = false;
|
||||
asCArray<asCDataType> subTypes;
|
||||
subTypes.PushLast(*this);
|
||||
asCObjectType *at = engine->GetTemplateInstanceType(engine->defaultArrayObjectType, subTypes);
|
||||
asCObjectType *at = engine->GetTemplateInstanceType(engine->defaultArrayObjectType, subTypes, module);
|
||||
isReadOnly = tmpIsReadOnly;
|
||||
|
||||
isObjectHandle = false;
|
||||
@ -305,7 +342,7 @@ int asCDataType::MakeHandleToConst(bool b)
|
||||
bool asCDataType::SupportHandles() const
|
||||
{
|
||||
if( objectType &&
|
||||
(objectType->flags & asOBJ_REF) &&
|
||||
(objectType->flags & (asOBJ_REF | asOBJ_ASHANDLE)) &&
|
||||
!(objectType->flags & asOBJ_NOHANDLE) &&
|
||||
!isObjectHandle )
|
||||
return true;
|
||||
@ -313,19 +350,39 @@ bool asCDataType::SupportHandles() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCDataType::CanBeInstanciated() const
|
||||
bool asCDataType::CanBeInstantiated() const
|
||||
{
|
||||
if( GetSizeOnStackDWords() == 0 ||
|
||||
(IsObject() &&
|
||||
(objectType->flags & asOBJ_REF) && // It's a ref type and
|
||||
((objectType->flags & asOBJ_NOHANDLE) || // the ref type doesn't support handles or
|
||||
(!IsObjectHandle() && // it's not a handle and
|
||||
objectType->beh.factories.GetLength() == 0))) ) // the ref type cannot be instanciated
|
||||
if( GetSizeOnStackDWords() == 0 ) // Void
|
||||
return false;
|
||||
|
||||
if( !IsObject() ) // Primitives
|
||||
return true;
|
||||
|
||||
if( IsObjectHandle() && !(objectType->flags & asOBJ_NOHANDLE) ) // Handles
|
||||
return true;
|
||||
|
||||
if( funcDef ) // Funcdefs can be instantiated as delegates
|
||||
return true;
|
||||
|
||||
if( (objectType->flags & asOBJ_REF) && objectType->beh.factories.GetLength() == 0 ) // ref types without factories
|
||||
return false;
|
||||
|
||||
if( (objectType->flags & asOBJ_ABSTRACT) && !IsObjectHandle() ) // Can't instantiate abstract classes
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asCDataType::IsAbstractClass() const
|
||||
{
|
||||
return objectType && (objectType->flags & asOBJ_ABSTRACT) ? true : false;
|
||||
}
|
||||
|
||||
bool asCDataType::IsInterface() const
|
||||
{
|
||||
return objectType && objectType->IsInterface();
|
||||
}
|
||||
|
||||
bool asCDataType::CanBeCopied() const
|
||||
{
|
||||
// All primitives can be copied
|
||||
@ -334,8 +391,8 @@ bool asCDataType::CanBeCopied() const
|
||||
// Plain-old-data structures can always be copied
|
||||
if( objectType->flags & asOBJ_POD ) return true;
|
||||
|
||||
// It must be possible to instanciate the type
|
||||
if( !CanBeInstanciated() ) return false;
|
||||
// It must be possible to instantiate the type
|
||||
if( !CanBeInstantiated() ) return false;
|
||||
|
||||
// It must have a default constructor or factory
|
||||
if( objectType->beh.construct == 0 &&
|
||||
@ -361,6 +418,14 @@ bool asCDataType::IsHandleToConst() const
|
||||
return isReadOnly;
|
||||
}
|
||||
|
||||
bool asCDataType::IsObjectConst() const
|
||||
{
|
||||
if( IsObjectHandle() )
|
||||
return IsHandleToConst();
|
||||
|
||||
return IsReadOnly();
|
||||
}
|
||||
|
||||
// TODO: 3.0.0: This should be removed
|
||||
bool asCDataType::IsArrayType() const
|
||||
{
|
||||
@ -441,7 +506,7 @@ bool asCDataType::IsEqualExceptConst(const asCDataType &dt) const
|
||||
|
||||
bool asCDataType::IsPrimitive() const
|
||||
{
|
||||
// Enumerations are primitives
|
||||
// Enumerations are primitives
|
||||
if( IsEnumType() )
|
||||
return true;
|
||||
|
||||
@ -456,6 +521,16 @@ bool asCDataType::IsPrimitive() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asCDataType::IsMathType() const
|
||||
{
|
||||
if( tokenType == ttInt || tokenType == ttInt8 || tokenType == ttInt16 || tokenType == ttInt64 ||
|
||||
tokenType == ttUInt || tokenType == ttUInt8 || tokenType == ttUInt16 || tokenType == ttUInt64 ||
|
||||
tokenType == ttFloat || tokenType == ttDouble )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCDataType::IsIntegerType() const
|
||||
{
|
||||
if( tokenType == ttInt ||
|
||||
@ -505,13 +580,14 @@ bool asCDataType::IsBooleanType() const
|
||||
|
||||
bool asCDataType::IsObject() const
|
||||
{
|
||||
// Enumerations are not objects, even though they are described with an objectType.
|
||||
if( IsEnumType() )
|
||||
if( IsPrimitive() )
|
||||
return false;
|
||||
|
||||
if( objectType ) return true;
|
||||
// Null handle doesn't have an object type but should still be considered an object
|
||||
if( objectType == 0 )
|
||||
return IsNullHandle();
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int asCDataType::GetSizeInMemoryBytes() const
|
||||
@ -569,6 +645,19 @@ int asCDataType::GetSizeOnStackDWords() const
|
||||
return GetSizeInMemoryDWords() + size;
|
||||
}
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
int asCDataType::GetAlignment() const
|
||||
{
|
||||
if( objectType == NULL )
|
||||
{
|
||||
// TODO: Small primitives should not be aligned to 4 byte boundaries
|
||||
return 4; //Default alignment
|
||||
}
|
||||
|
||||
return objectType->alignment;
|
||||
}
|
||||
#endif
|
||||
|
||||
asSTypeBehaviour *asCDataType::GetBehaviour() const
|
||||
{
|
||||
return objectType ? &objectType->beh : 0;
|
||||
@ -576,6 +665,9 @@ asSTypeBehaviour *asCDataType::GetBehaviour() const
|
||||
|
||||
bool asCDataType::IsEnumType() const
|
||||
{
|
||||
// Do a sanity check on the objectType, to verify that we aren't trying to access memory after it has been released
|
||||
asASSERT( objectType == 0 || objectType->name.GetLength() < 100 );
|
||||
|
||||
if( objectType && (objectType->flags & asOBJ_ENUM) )
|
||||
return true;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -49,6 +49,8 @@ struct asSTypeBehaviour;
|
||||
class asCScriptEngine;
|
||||
class asCObjectType;
|
||||
class asCScriptFunction;
|
||||
class asCModule;
|
||||
struct asSNameSpace;
|
||||
|
||||
// TODO: refactor: Reference should not be part of the datatype. This should be stored separately, e.g. in asCTypeInfo
|
||||
// MakeReference, MakeReadOnly, IsReference, IsReadOnly should be removed
|
||||
@ -62,36 +64,45 @@ public:
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
asCString Format(bool includeNamespace = false) const;
|
||||
asCString Format(asSNameSpace *currNs, bool includeNamespace = false) const;
|
||||
|
||||
static asCDataType CreatePrimitive(eTokenType tt, bool isConst);
|
||||
static asCDataType CreateObject(asCObjectType *ot, bool isConst);
|
||||
static asCDataType CreateAuto(bool isConst);
|
||||
static asCDataType CreateObjectHandle(asCObjectType *ot, bool isConst);
|
||||
static asCDataType CreateFuncDef(asCScriptFunction *ot);
|
||||
static asCDataType CreateNullHandle();
|
||||
|
||||
int MakeHandle(bool b, bool acceptHandleForScope = false);
|
||||
int MakeArray(asCScriptEngine *engine);
|
||||
int MakeArray(asCScriptEngine *engine, asCModule *requestingModule);
|
||||
int MakeReference(bool b);
|
||||
int MakeReadOnly(bool b);
|
||||
int MakeHandleToConst(bool b);
|
||||
|
||||
bool IsTemplate() const;
|
||||
bool IsScriptObject() const;
|
||||
bool IsPrimitive() const;
|
||||
bool IsObject() const;
|
||||
bool IsReference() const {return isReference;}
|
||||
bool IsReadOnly() const;
|
||||
bool IsIntegerType() const;
|
||||
bool IsUnsignedType() const;
|
||||
bool IsFloatType() const;
|
||||
bool IsDoubleType() const;
|
||||
bool IsBooleanType() const;
|
||||
bool IsObjectHandle() const {return isObjectHandle;}
|
||||
bool IsHandleToConst() const;
|
||||
bool IsArrayType() const;
|
||||
bool IsEnumType() const;
|
||||
bool IsAnyType() const {return tokenType == ttQuestion;}
|
||||
bool IsTemplate() const;
|
||||
bool IsScriptObject() const;
|
||||
bool IsPrimitive() const;
|
||||
bool IsMathType() const;
|
||||
bool IsObject() const;
|
||||
bool IsReference() const {return isReference;}
|
||||
bool IsAuto() const {return isAuto;}
|
||||
bool IsReadOnly() const;
|
||||
bool IsIntegerType() const;
|
||||
bool IsUnsignedType() const;
|
||||
bool IsFloatType() const;
|
||||
bool IsDoubleType() const;
|
||||
bool IsBooleanType() const;
|
||||
bool IsObjectHandle() const {return isObjectHandle;}
|
||||
bool IsHandleToAuto() const {return isAuto && isObjectHandle;}
|
||||
bool IsHandleToConst() const;
|
||||
bool IsArrayType() const;
|
||||
bool IsEnumType() const;
|
||||
bool IsAnyType() const {return tokenType == ttQuestion;}
|
||||
bool IsHandleToAsHandleType() const {return isHandleToAsHandleType;}
|
||||
bool IsAbstractClass() const;
|
||||
bool IsInterface() const;
|
||||
|
||||
bool IsObjectConst() const;
|
||||
|
||||
bool IsEqualExceptRef(const asCDataType &) const;
|
||||
bool IsEqualExceptRefAndConst(const asCDataType &) const;
|
||||
@ -99,7 +110,7 @@ public:
|
||||
bool IsNullHandle() const;
|
||||
|
||||
bool SupportHandles() const;
|
||||
bool CanBeInstanciated() const;
|
||||
bool CanBeInstantiated() const;
|
||||
bool CanBeCopied() const;
|
||||
|
||||
bool operator ==(const asCDataType &) const;
|
||||
@ -113,6 +124,9 @@ public:
|
||||
int GetSizeOnStackDWords() const;
|
||||
int GetSizeInMemoryBytes() const;
|
||||
int GetSizeInMemoryDWords() const;
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
int GetAlignment() const;
|
||||
#endif
|
||||
|
||||
void SetTokenType(eTokenType tt) {tokenType = tt;}
|
||||
void SetObjectType(asCObjectType *obj) {objectType = obj;}
|
||||
@ -135,7 +149,9 @@ protected:
|
||||
bool isReadOnly:1;
|
||||
bool isObjectHandle:1;
|
||||
bool isConstHandle:1;
|
||||
char dummy:4;
|
||||
bool isAuto:1;
|
||||
bool isHandleToAsHandleType:1; // Used by the compiler to know how to initialize the object
|
||||
char dummy:2;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -38,12 +38,16 @@
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#if defined(AS_DEBUG)
|
||||
|
||||
#ifndef AS_WII
|
||||
// The Wii SDK doesn't have these, we'll survive without AS_DEBUG
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
// Neither does WinCE
|
||||
|
||||
#ifndef AS_PSVITA
|
||||
// Possible on PSVita, but requires SDK access
|
||||
|
||||
#if defined(__GNUC__) || defined( AS_MARMALADE )
|
||||
|
||||
@ -256,10 +260,17 @@ END_AS_NAMESPACE
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // AS_PSVITA
|
||||
#endif // _WIN32_WCE
|
||||
#endif // AS_WII
|
||||
|
||||
#else // !defined(AS_DEBUG)
|
||||
|
||||
// Define it so nothing is done
|
||||
#define TimeIt(x)
|
||||
|
||||
#endif // !defined(AS_DEBUG)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -156,7 +156,14 @@ int asCGarbageCollector::GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, a
|
||||
return asSUCCESS;
|
||||
}
|
||||
|
||||
int asCGarbageCollector::GarbageCollect(asDWORD flags)
|
||||
// TODO: Should have a flag to tell the garbage collector to automatically determine how many iterations are needed
|
||||
// It should then gather statistics such as how many objects has been created since last run, and how many objects
|
||||
// are destroyed per iteration, and how many objects are detected as cyclic garbage per iteration.
|
||||
// It should try to reach a stable number of objects, i.e. so that on average the number of objects added to
|
||||
// the garbage collector is the same as the number of objects destroyed. And it should try to minimize the number
|
||||
// of iterations of detections that must be executed per cycle while still identifying the cyclic garbage
|
||||
// These variables should also be available for inspection through the gcstatistics.
|
||||
int asCGarbageCollector::GarbageCollect(asDWORD flags, asUINT iterations)
|
||||
{
|
||||
// If the GC is already processing in another thread, then don't enter here again
|
||||
if( TRYENTERCRITICALSECTION(gcCollecting) )
|
||||
@ -178,9 +185,8 @@ int asCGarbageCollector::GarbageCollect(asDWORD flags)
|
||||
// Reset the state
|
||||
if( doDetect )
|
||||
{
|
||||
// Move all objects to the old list, so we guarantee that all is detected
|
||||
for( asUINT n = (asUINT)gcNewObjects.GetLength(); n-- > 0; )
|
||||
MoveObjectToOldList(n);
|
||||
// Move all new objects to the old list, so we guarantee that all is detected
|
||||
MoveAllObjectsToOldList();
|
||||
detectState = clearCounters_init;
|
||||
}
|
||||
if( doDestroy )
|
||||
@ -189,7 +195,10 @@ int asCGarbageCollector::GarbageCollect(asDWORD flags)
|
||||
destroyOldState = destroyGarbage_init;
|
||||
}
|
||||
|
||||
unsigned int count = (unsigned int)(gcNewObjects.GetLength() + gcOldObjects.GetLength());
|
||||
// The full cycle only works with the objects in the old list so that the
|
||||
// set of objects scanned for garbage is fixed even if new objects are added
|
||||
// by other threads in parallel.
|
||||
unsigned int count = (unsigned int)(gcOldObjects.GetLength());
|
||||
for(;;)
|
||||
{
|
||||
// Detect all garbage with cyclic references
|
||||
@ -199,25 +208,16 @@ int asCGarbageCollector::GarbageCollect(asDWORD flags)
|
||||
// Now destroy all known garbage
|
||||
if( doDestroy )
|
||||
{
|
||||
while( DestroyNewGarbage() == 1 ) {}
|
||||
if( !doDetect )
|
||||
while( DestroyNewGarbage() == 1 ) {}
|
||||
while( DestroyOldGarbage() == 1 ) {}
|
||||
}
|
||||
|
||||
// Run another iteration if any garbage was destroyed
|
||||
if( count != (unsigned int)(gcNewObjects.GetLength() + gcOldObjects.GetLength()) )
|
||||
count = (unsigned int)(gcNewObjects.GetLength() + gcOldObjects.GetLength());
|
||||
if( count != (unsigned int)(gcOldObjects.GetLength()) )
|
||||
count = (unsigned int)(gcOldObjects.GetLength());
|
||||
else
|
||||
{
|
||||
// Let the engine destroy the types that reached refCount 0
|
||||
// If none were destroyed, then leave the GC
|
||||
// TODO: The asCObjectType should destroy its content when refCount reaches 0
|
||||
// since no-one is using them. The registered types should have their
|
||||
// refcount increased by the config groups. Doing it like that will allow
|
||||
// me to remove this call to ClearUnusedTypes() that the GC really
|
||||
// shouldn't be calling.
|
||||
if( engine->ClearUnusedTypes() == 0 )
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
isProcessing = false;
|
||||
@ -226,16 +226,19 @@ int asCGarbageCollector::GarbageCollect(asDWORD flags)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Destroy the garbage that we know of
|
||||
if( doDestroy )
|
||||
while( iterations-- > 0 )
|
||||
{
|
||||
DestroyNewGarbage();
|
||||
DestroyOldGarbage();
|
||||
}
|
||||
// Destroy the garbage that we know of
|
||||
if( doDestroy )
|
||||
{
|
||||
DestroyNewGarbage();
|
||||
DestroyOldGarbage();
|
||||
}
|
||||
|
||||
// Run another incremental step of the identification of cyclic references
|
||||
if( doDetect )
|
||||
IdentifyGarbageWithCyclicRefs();
|
||||
// Run another incremental step of the identification of cyclic references
|
||||
if( doDetect && gcOldObjects.GetLength() > 0 )
|
||||
IdentifyGarbageWithCyclicRefs();
|
||||
}
|
||||
}
|
||||
|
||||
isProcessing = false;
|
||||
@ -246,19 +249,33 @@ int asCGarbageCollector::GarbageCollect(asDWORD flags)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO: Additional statistics to gather
|
||||
//
|
||||
// - How many objects are added on average between each destroyed object
|
||||
// - How many objects are added on average between each detected object
|
||||
// - how many iterations are needed for each destroyed object
|
||||
// - how many iterations are needed for each detected object
|
||||
//
|
||||
// The average must have a decay so that long running applications will not suffer
|
||||
// from objects being created early on in the application and then never destroyed.
|
||||
//
|
||||
// This ought to be possible to accomplish by holding two buckets.
|
||||
// Numbers will be accumulated in one bucket while the other is held fixed.
|
||||
// When returning the average it should use a weighted average between the two buckets using the size as weight.
|
||||
// When a bucket is filled up, the buckets are switched, and then new bucket is emptied to gather new statistics.
|
||||
void asCGarbageCollector::GetStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const
|
||||
{
|
||||
// It's not necessary to protect this access, as
|
||||
// it doesn't matter if another thread is currently
|
||||
// appending a new object.
|
||||
// It is not necessary to protect this with critical sections, however
|
||||
// as it is not protected the variables can be filled in slightly different
|
||||
// moments and might not match perfectly when inspected by the application
|
||||
// afterwards.
|
||||
|
||||
if( currentSize )
|
||||
*currentSize = (asUINT)(gcNewObjects.GetLength() + gcOldObjects.GetLength());
|
||||
|
||||
if( totalDestroyed )
|
||||
*totalDestroyed = numDestroyed;
|
||||
|
||||
asASSERT( numAdded == gcNewObjects.GetLength() + gcOldObjects.GetLength() + numDestroyed );
|
||||
|
||||
if( totalDetected )
|
||||
*totalDetected = numDetected;
|
||||
|
||||
@ -328,6 +345,16 @@ void asCGarbageCollector::MoveObjectToOldList(int idx)
|
||||
LEAVECRITICALSECTION(gcCritical);
|
||||
}
|
||||
|
||||
void asCGarbageCollector::MoveAllObjectsToOldList()
|
||||
{
|
||||
// We need to protect this update with a critical section as
|
||||
// another thread might be appending an object at the same time
|
||||
ENTERCRITICALSECTION(gcCritical);
|
||||
if( gcOldObjects.Concatenate(gcNewObjects) )
|
||||
gcNewObjects.SetLength(0);
|
||||
LEAVECRITICALSECTION(gcCritical);
|
||||
}
|
||||
|
||||
int asCGarbageCollector::DestroyNewGarbage()
|
||||
{
|
||||
// This function will only be called within the critical section gcCollecting
|
||||
@ -900,7 +927,14 @@ asCGarbageCollector::asSMapNode_t *asCGarbageCollector::GetNode(void *obj, asSIn
|
||||
if( freeNodes.GetLength() )
|
||||
node = freeNodes.PopLast();
|
||||
else
|
||||
{
|
||||
node = asNEW(asSMapNode_t);
|
||||
if( !node )
|
||||
{
|
||||
// Out of memory
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
node->Init(obj, it);
|
||||
return node;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -56,7 +56,7 @@ public:
|
||||
asCGarbageCollector();
|
||||
~asCGarbageCollector();
|
||||
|
||||
int GarbageCollect(asDWORD flags);
|
||||
int GarbageCollect(asDWORD flags, asUINT iterations);
|
||||
void GetStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const;
|
||||
void GCEnumCallback(void *reference);
|
||||
int AddScriptObjectToGC(void *obj, asCObjectType *objType);
|
||||
@ -104,6 +104,7 @@ protected:
|
||||
void RemoveNewObjectAtIdx(int idx);
|
||||
void RemoveOldObjectAtIdx(int idx);
|
||||
void MoveObjectToOldList(int idx);
|
||||
void MoveAllObjectsToOldList();
|
||||
|
||||
// Holds all the objects known by the garbage collector
|
||||
asCArray<asSObjTypePair> gcNewObjects;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -50,31 +50,32 @@ asCGlobalProperty::asCGlobalProperty()
|
||||
|
||||
asCGlobalProperty::~asCGlobalProperty()
|
||||
{
|
||||
#ifndef WIP_16BYTE_ALIGNED
|
||||
if( memoryAllocated ) { asDELETEARRAY(memory); }
|
||||
#else
|
||||
if( memoryAllocated ) { asDELETEARRAYALIGNED(memory); }
|
||||
#endif
|
||||
|
||||
if( initFunc )
|
||||
initFunc->Release();
|
||||
initFunc->ReleaseInternal();
|
||||
}
|
||||
|
||||
void asCGlobalProperty::AddRef()
|
||||
{
|
||||
gcFlag = false;
|
||||
refCount.atomicInc();
|
||||
}
|
||||
|
||||
void asCGlobalProperty::Release()
|
||||
{
|
||||
gcFlag = false;
|
||||
if( refCount.atomicDec() == 0 )
|
||||
asDELETE(this, asCGlobalProperty);
|
||||
}
|
||||
|
||||
// The property doesn't delete itself. The
|
||||
// engine will do that at a later time
|
||||
if( refCount.atomicDec() == 2 && initFunc )
|
||||
void asCGlobalProperty::DestroyInternal()
|
||||
{
|
||||
if( initFunc )
|
||||
{
|
||||
// Since the initFunc holds references to the property,
|
||||
// we'll release it when we reach refCount 2. This will
|
||||
// break the circle and allow the engine to free the property
|
||||
// without the need for the GC to attempt finding circular
|
||||
// references.
|
||||
initFunc->Release();
|
||||
initFunc->ReleaseInternal();
|
||||
initFunc = 0;
|
||||
}
|
||||
}
|
||||
@ -92,7 +93,12 @@ void asCGlobalProperty::AllocateMemory()
|
||||
{
|
||||
if( type.GetSizeOnStackDWords() > 2 )
|
||||
{
|
||||
#ifndef WIP_16BYTE_ALIGNED
|
||||
memory = asNEWARRAY(asDWORD, type.GetSizeOnStackDWords());
|
||||
#else
|
||||
// TODO: Avoid aligned allocation if not needed to reduce the waste of memory for the alignment
|
||||
memory = asNEWARRAYALIGNED(asDWORD, type.GetSizeOnStackDWords(), type.GetAlignment());
|
||||
#endif
|
||||
memoryAllocated = true;
|
||||
}
|
||||
}
|
||||
@ -114,60 +120,13 @@ void *asCGlobalProperty::GetRegisteredAddress() const
|
||||
return realAddress;
|
||||
}
|
||||
|
||||
int asCGlobalProperty::GetRefCount()
|
||||
{
|
||||
return refCount.get();
|
||||
}
|
||||
|
||||
void asCGlobalProperty::SetGCFlag()
|
||||
{
|
||||
gcFlag = true;
|
||||
}
|
||||
|
||||
bool asCGlobalProperty::GetGCFlag()
|
||||
{
|
||||
return gcFlag;
|
||||
}
|
||||
|
||||
void asCGlobalProperty::EnumReferences(asIScriptEngine *engine)
|
||||
{
|
||||
engine->GCEnumCallback(initFunc);
|
||||
}
|
||||
|
||||
void asCGlobalProperty::ReleaseAllHandles(asIScriptEngine *)
|
||||
{
|
||||
if( initFunc )
|
||||
{
|
||||
initFunc->Release();
|
||||
initFunc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void asCGlobalProperty::Orphan(asCModule *module)
|
||||
{
|
||||
if( initFunc && initFunc->module == module )
|
||||
{
|
||||
// The owning module is releasing the property, so we need to notify
|
||||
// the GC in order to resolve any circular references that may exists
|
||||
|
||||
// This will add the property
|
||||
initFunc->engine->gc.AddScriptObjectToGC(this, &initFunc->engine->globalPropertyBehaviours);
|
||||
|
||||
// This will add the function
|
||||
initFunc->AddRef();
|
||||
initFunc->Orphan(module);
|
||||
}
|
||||
|
||||
Release();
|
||||
}
|
||||
|
||||
void asCGlobalProperty::SetInitFunc(asCScriptFunction *initFunc)
|
||||
{
|
||||
// This should only be done once
|
||||
asASSERT( this->initFunc == 0 );
|
||||
|
||||
this->initFunc = initFunc;
|
||||
this->initFunc->AddRef();
|
||||
this->initFunc->AddRefInternal();
|
||||
}
|
||||
|
||||
asCScriptFunction *asCGlobalProperty::GetInitFunc()
|
||||
@ -175,81 +134,4 @@ asCScriptFunction *asCGlobalProperty::GetInitFunc()
|
||||
return initFunc;
|
||||
}
|
||||
|
||||
|
||||
#ifdef AS_MAX_PORTABILITY
|
||||
|
||||
static void GlobalProperty_AddRef_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject();
|
||||
self->AddRef();
|
||||
}
|
||||
|
||||
static void GlobalProperty_Release_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject();
|
||||
self->Release();
|
||||
}
|
||||
|
||||
static void GlobalProperty_GetRefCount_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject();
|
||||
*(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
|
||||
}
|
||||
|
||||
static void GlobalProperty_SetGCFlag_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject();
|
||||
self->SetGCFlag();
|
||||
}
|
||||
|
||||
static void GlobalProperty_GetGCFlag_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject();
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag();
|
||||
}
|
||||
|
||||
static void GlobalProperty_EnumReferences_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject();
|
||||
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
|
||||
self->EnumReferences(engine);
|
||||
}
|
||||
|
||||
static void GlobalProperty_ReleaseAllHandles_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCGlobalProperty *self = (asCGlobalProperty*)gen->GetObject();
|
||||
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
|
||||
self->ReleaseAllHandles(engine);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void asCGlobalProperty::RegisterGCBehaviours(asCScriptEngine *engine)
|
||||
{
|
||||
// Register the gc behaviours for the global properties
|
||||
int r = 0;
|
||||
UNUSED_VAR(r); // It is only used in debug mode
|
||||
engine->globalPropertyBehaviours.engine = engine;
|
||||
engine->globalPropertyBehaviours.flags = asOBJ_REF | asOBJ_GC;
|
||||
engine->globalPropertyBehaviours.name = "_builtin_globalprop_";
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCGlobalProperty,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCGlobalProperty,Release), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(asCGlobalProperty,GetRefCount), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_SETGCFLAG, "void f()", asMETHOD(asCGlobalProperty,SetGCFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCGlobalProperty,GetGCFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCGlobalProperty,EnumReferences), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCGlobalProperty,ReleaseAllHandles), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
#else
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(GlobalProperty_AddRef_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(GlobalProperty_Release_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(GlobalProperty_GetRefCount_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(GlobalProperty_SetGCFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(GlobalProperty_GetGCFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(GlobalProperty_EnumReferences_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->globalPropertyBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(GlobalProperty_ReleaseAllHandles_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -49,6 +49,63 @@
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
|
||||
// TODO: Add support for 16byte aligned application types (e.g. __m128). The following is a list of things that needs to be implemented:
|
||||
//
|
||||
// ok - The script context must make sure to always allocate the local stack memory buffer on 16byte aligned boundaries (asCContext::ReserveStackSpace)
|
||||
// ok - The engine must make sure to always allocate the memory for the script objects on 16byte aligned boundaries (asCScriptEngine::CallAlloc)
|
||||
// ok - The application needs to inform a new flag when registering types that require 16byte alignment, e.g. asOBJ_APP_ALIGN16 (asCScriptEngine::RegisterObjectType)
|
||||
// ok - The script object type must make sure to align member properties of these types correctly (asCObjectType::AddPropertyToClass)
|
||||
// ok - Script global properties must allocate memory on 16byte boundaries if holding these types (asCGlobalProperty::AllocateMemory)
|
||||
// TODO - The script compiler must make sure to allocate the local variables on 16byte boundaries (asCCompiler::AllocateVariable)
|
||||
// TODO - The script compiler must add pad bytes on the stack for all function calls to guarantee that the stack position is 16byte aligned on entry in the called function (asCCompiler)
|
||||
// TODO - The bytecode serializer must be capable of adjusting these pad bytes to guarantee platform independent saved bytecode. Remember that the registered type may not be 16byte aligned on all platforms (asCWriter & asCReader)
|
||||
// TODO - The bytecode serializer must also be prepared to adjust the position of the local variables according to the need fro 16byte alignment (asCWriter & asCReader)
|
||||
// TODO - The code for the native calling conventions must be adjusted for all platforms that should support 16byte aligned types (as_callfunc...)
|
||||
// ok - When the context needs to grow the local stack memory it must copy the function arguments so that the stack entry position is 16byte aligned (asCContext::CallScriptFunction)
|
||||
// TODO - When the context is prepared for a new call, it must set the initial stack position so the stack entry position is 16byte aligned (asCContext::Prepare)
|
||||
//
|
||||
// http://www.gamedev.net/topic/650555-alignment-requirements/
|
||||
|
||||
|
||||
// TODO: Allow user to register its own aligned memory routines
|
||||
// Wrappers for aligned allocations
|
||||
void *debugAlignedMalloc(size_t size, size_t align, const char *file, int line)
|
||||
{
|
||||
void *mem = ((asALLOCFUNCDEBUG_t)userAlloc)(size + (align-1) + sizeof(void*), file, line);
|
||||
|
||||
char *amem = ((char*)mem) + sizeof(void*);
|
||||
if( (uintptr_t)amem & (align - 1) )
|
||||
amem += align - ((uintptr_t)amem & (align - 1));
|
||||
|
||||
((void**)amem)[-1] = mem;
|
||||
return amem;
|
||||
}
|
||||
|
||||
void *alignedMalloc(size_t size, size_t align)
|
||||
{
|
||||
void *mem = userAlloc(size + (align-1) + sizeof(void*));
|
||||
|
||||
char *amem = ((char*)mem) + sizeof(void*);
|
||||
if( (uintptr_t)amem & (align - 1) )
|
||||
amem += align - ((uintptr_t)amem & (align - 1));
|
||||
|
||||
((void**)amem)[-1] = mem;
|
||||
return amem;
|
||||
}
|
||||
|
||||
void alignedFree(void *mem)
|
||||
{
|
||||
userFree( ((void**)mem)[-1] );
|
||||
}
|
||||
|
||||
bool isAligned(const void* const pointer, asUINT alignment)
|
||||
{
|
||||
return (uintptr_t(pointer) % alignment) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// By default we'll use the standard memory management functions
|
||||
|
||||
// Make sure these globals are initialized first. Otherwise the
|
||||
@ -61,25 +118,47 @@ BEGIN_AS_NAMESPACE
|
||||
#pragma init_seg(lib)
|
||||
asALLOCFUNC_t userAlloc = malloc;
|
||||
asFREEFUNC_t userFree = free;
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
#ifdef AS_DEBUG
|
||||
asALLOCALIGNEDFUNC_t userAllocAligned = (asALLOCALIGNEDFUNC_t)debugAlignedMalloc;
|
||||
#else
|
||||
asALLOCALIGNEDFUNC_t userAllocAligned = alignedMalloc;
|
||||
#endif
|
||||
asFREEALIGNEDFUNC_t userFreeAligned = alignedFree;
|
||||
#endif
|
||||
#else
|
||||
// Other compilers will just have to rely on luck.
|
||||
asALLOCFUNC_t userAlloc = malloc;
|
||||
asFREEFUNC_t userFree = free;
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
asALLOCALIGNEDFUNC_t userAllocAligned = alignedMalloc;
|
||||
asFREEALIGNEDFUNC_t userFreeAligned = alignedFree;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// interface
|
||||
int asSetGlobalMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc)
|
||||
{
|
||||
// Clean-up thread local memory before changing the allocation routines to avoid
|
||||
// potential problem with trying to free memory using a different allocation
|
||||
// routine than used when allocating it.
|
||||
asThreadCleanup();
|
||||
|
||||
userAlloc = allocFunc;
|
||||
userFree = freeFunc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asResetGlobalMemoryFunctions()
|
||||
{
|
||||
// Clean-up thread local memory before changing the allocation routines to avoid
|
||||
// potential problem with trying to free memory using a different allocation
|
||||
// routine than used when allocating it.
|
||||
asThreadCleanup();
|
||||
|
||||
userAlloc = malloc;
|
||||
@ -88,6 +167,18 @@ int asResetGlobalMemoryFunctions()
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asAllocMem(size_t size)
|
||||
{
|
||||
return asNEWARRAY(asBYTE, size);
|
||||
}
|
||||
|
||||
// interface
|
||||
void asFreeMem(void *mem)
|
||||
{
|
||||
asDELETEARRAY(mem);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
asCMemoryMgr::asCMemoryMgr()
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -48,6 +48,25 @@ BEGIN_AS_NAMESPACE
|
||||
extern asALLOCFUNC_t userAlloc;
|
||||
extern asFREEFUNC_t userFree;
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
|
||||
// TODO: This declaration should be in angelscript.h
|
||||
// when the application can register it's own
|
||||
// aligned memory routines
|
||||
typedef void *(*asALLOCALIGNEDFUNC_t)(size_t, size_t);
|
||||
typedef void (*asFREEALIGNEDFUNC_t)(void *);
|
||||
extern asALLOCALIGNEDFUNC_t userAllocAligned;
|
||||
extern asFREEALIGNEDFUNC_t userFreeAligned;
|
||||
typedef void *(*asALLOCALIGNEDFUNCDEBUG_t)(size_t, size_t, const char *, unsigned int);
|
||||
|
||||
// The maximum type alignment supported.
|
||||
const int MAX_TYPE_ALIGNMENT = 16;
|
||||
|
||||
// Utility function used for assertions.
|
||||
bool isAligned(const void* const pointer, asUINT alignment);
|
||||
|
||||
#endif // WIP_16BYTE_ALIGN
|
||||
|
||||
// We don't overload the new operator as that would affect the application as well
|
||||
|
||||
#ifndef AS_DEBUG
|
||||
@ -58,6 +77,11 @@ extern asFREEFUNC_t userFree;
|
||||
#define asNEWARRAY(x,cnt) (x*)userAlloc(sizeof(x)*cnt)
|
||||
#define asDELETEARRAY(ptr) userFree(ptr)
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
#define asNEWARRAYALIGNED(x,cnt, alignment) (x*)userAllocAligned(sizeof(x)*cnt, alignment)
|
||||
#define asDELETEARRAYALIGNED(ptr) userFreeAligned(ptr)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
typedef void *(*asALLOCFUNCDEBUG_t)(size_t, const char *, unsigned int);
|
||||
@ -68,6 +92,12 @@ extern asFREEFUNC_t userFree;
|
||||
#define asNEWARRAY(x,cnt) (x*)((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(x)*cnt, __FILE__, __LINE__)
|
||||
#define asDELETEARRAY(ptr) userFree(ptr)
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
//TODO: Equivalent of debug allocation function with alignment?
|
||||
#define asNEWARRAYALIGNED(x,cnt, alignment) (x*)userAllocAligned(sizeof(x)*cnt, alignment)
|
||||
#define asDELETEARRAYALIGNED(ptr) userFreeAligned(ptr)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -46,6 +46,33 @@
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// TODO: 2.30.0: redesign: Improved method for discarding modules (faster clean-up, less abuse of garbage collector)
|
||||
//
|
||||
// I need to separate the reference counter for internal references and outside references:
|
||||
//
|
||||
// - Internal references are for example, when the module refers to a function or object since it is declared in the module, or when
|
||||
// a function refers to another function since it is being called in the code.
|
||||
// - Outside references are for example object instances holding a reference to the object type, or a context currently
|
||||
// executing a function.
|
||||
//
|
||||
// If no object instances are alive or no contexts are alive it is known that functions from a discarded module
|
||||
// can be called, so they can be destroyed without any need to execute the complex garbage collection routines.
|
||||
//
|
||||
// If there are live objects, the entire module should be kept for safe keeping, though no longer visible.
|
||||
//
|
||||
// TODO: It may not be necessary to keep track of internal references. Without keeping track of internal references, can I still
|
||||
// handle RemoveFunction and RemoveGlobalVariable correctly?
|
||||
//
|
||||
// TODO: How to avoid global variables keeping code alive? For example a script object, or a funcdef?
|
||||
// Can I do a quick check of the object types and functions to count number of outside references, and then do another
|
||||
// check over the global variables to subtract the outside references coming from these? What if the outside reference
|
||||
// is added by an application type in a global variable that the engine doesn't know about? Example, a global dictionary
|
||||
// holding object instances. Should discarding a module immediately destroy the content of the global variables? What if
|
||||
// a live object tries to access the global variable after it has been discarded? Throwing a script exception is acceptable?
|
||||
// Perhaps I need to allow the user to provide a clean-up routine that will be executed before destroying the objects.
|
||||
// Or I might just put that responsibility on the application.
|
||||
|
||||
|
||||
// internal
|
||||
asCModule::asCModule(const char *name, asCScriptEngine *engine)
|
||||
{
|
||||
@ -66,6 +93,8 @@ asCModule::~asCModule()
|
||||
{
|
||||
InternalReset();
|
||||
|
||||
// The builder is not removed by InternalReset because it holds the script
|
||||
// sections that will be built, so we need to explictly remove it now if it exists
|
||||
if( builder )
|
||||
{
|
||||
asDELETE(builder,asCBuilder);
|
||||
@ -75,34 +104,114 @@ asCModule::~asCModule()
|
||||
if( engine )
|
||||
{
|
||||
// Clean the user data
|
||||
if( userData && engine->cleanModuleFunc )
|
||||
engine->cleanModuleFunc(this);
|
||||
for( asUINT n = 0; n < userData.GetLength(); n += 2 )
|
||||
{
|
||||
if( userData[n+1] )
|
||||
{
|
||||
for( asUINT c = 0; c < engine->cleanModuleFuncs.GetLength(); c++ )
|
||||
if( engine->cleanModuleFuncs[c].type == userData[n] )
|
||||
engine->cleanModuleFuncs[c].cleanFunc(this);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the module from the engine
|
||||
if( engine->lastModule == this )
|
||||
engine->lastModule = 0;
|
||||
engine->scriptModules.RemoveValue(this);
|
||||
ACQUIREEXCLUSIVE(engine->engineRWLock);
|
||||
// The module must have been discarded before it is deleted
|
||||
asASSERT( !engine->scriptModules.Exists(this) );
|
||||
engine->discardedModules.RemoveValue(this);
|
||||
RELEASEEXCLUSIVE(engine->engineRWLock);
|
||||
}
|
||||
}
|
||||
|
||||
// interface
|
||||
void asCModule::Discard()
|
||||
{
|
||||
asDELETE(this,asCModule);
|
||||
// Reset the global variables already so that no object in the global variables keep the module alive forever.
|
||||
// If any live object tries to access the global variables during clean up they will fail with a script exception,
|
||||
// so the application must keep that in mind before discarding a module.
|
||||
CallExit();
|
||||
|
||||
// Keep a local copy of the engine pointer, because once the module is moved do the discarded
|
||||
// pile, it is possible that another thread might discard it while we are still in here. So no
|
||||
// further access to members may be done after that
|
||||
asCScriptEngine *lEngine = engine;
|
||||
|
||||
// Instead of deleting the module immediately, move it to the discarded pile
|
||||
// This will turn it invisible to the application, yet keep it alive until all
|
||||
// external references to its entities have been released.
|
||||
ACQUIREEXCLUSIVE(engine->engineRWLock);
|
||||
if( lEngine->lastModule == this )
|
||||
lEngine->lastModule = 0;
|
||||
lEngine->scriptModules.RemoveValue(this);
|
||||
lEngine->discardedModules.PushLast(this);
|
||||
RELEASEEXCLUSIVE(lEngine->engineRWLock);
|
||||
|
||||
// Allow the engine to go over the list of discarded modules to see what can be cleaned up at this moment.
|
||||
// Don't do this if the engine is already shutting down, as it will be done explicitly by the engine itself with error reporting
|
||||
if( !lEngine->shuttingDown )
|
||||
{
|
||||
if( lEngine->ep.autoGarbageCollect )
|
||||
lEngine->GarbageCollect();
|
||||
else
|
||||
{
|
||||
// GarbageCollect calls DeleteDiscardedModules, so no need
|
||||
// to call it again if we already called GarbageCollect
|
||||
lEngine->DeleteDiscardedModules();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asCModule::SetUserData(void *data)
|
||||
void *asCModule::SetUserData(void *data, asPWORD type)
|
||||
{
|
||||
void *oldData = userData;
|
||||
userData = data;
|
||||
return oldData;
|
||||
// As a thread might add a new new user data at the same time as another
|
||||
// it is necessary to protect both read and write access to the userData member
|
||||
ACQUIREEXCLUSIVE(engine->engineRWLock);
|
||||
|
||||
// It is not intended to store a lot of different types of userdata,
|
||||
// so a more complex structure like a associative map would just have
|
||||
// more overhead than a simple array.
|
||||
for( asUINT n = 0; n < userData.GetLength(); n += 2 )
|
||||
{
|
||||
if( userData[n] == type )
|
||||
{
|
||||
void *oldData = reinterpret_cast<void*>(userData[n+1]);
|
||||
userData[n+1] = reinterpret_cast<asPWORD>(data);
|
||||
|
||||
RELEASEEXCLUSIVE(engine->engineRWLock);
|
||||
|
||||
return oldData;
|
||||
}
|
||||
}
|
||||
|
||||
userData.PushLast(type);
|
||||
userData.PushLast(reinterpret_cast<asPWORD>(data));
|
||||
|
||||
RELEASEEXCLUSIVE(engine->engineRWLock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asCModule::GetUserData() const
|
||||
void *asCModule::GetUserData(asPWORD type) const
|
||||
{
|
||||
return userData;
|
||||
// There may be multiple threads reading, but when
|
||||
// setting the user data nobody must be reading.
|
||||
ACQUIRESHARED(engine->engineRWLock);
|
||||
|
||||
for( asUINT n = 0; n < userData.GetLength(); n += 2 )
|
||||
{
|
||||
if( userData[n] == type )
|
||||
{
|
||||
void *ud = reinterpret_cast<void*>(userData[n+1]);
|
||||
RELEASESHARED(engine->engineRWLock);
|
||||
return ud;
|
||||
}
|
||||
}
|
||||
|
||||
RELEASESHARED(engine->engineRWLock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
@ -204,6 +313,15 @@ int asCModule::Build()
|
||||
#else
|
||||
TimeIt("asCModule::Build");
|
||||
|
||||
// Don't allow the module to be rebuilt if there are still
|
||||
// external references that will need the previous code
|
||||
// TODO: 2.30.0: interface: The asIScriptModule must have a method for querying if the module is used
|
||||
if( HasExternalReferences(false) )
|
||||
{
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_MODULE_IS_IN_USE);
|
||||
return asMODULE_IS_IN_USE;
|
||||
}
|
||||
|
||||
// Only one thread may build at one time
|
||||
// TODO: It should be possible to have multiple threads perform compilations
|
||||
int r = engine->RequestBuild();
|
||||
@ -218,7 +336,7 @@ int asCModule::Build()
|
||||
return asINVALID_CONFIGURATION;
|
||||
}
|
||||
|
||||
InternalReset();
|
||||
InternalReset();
|
||||
|
||||
if( !builder )
|
||||
{
|
||||
@ -306,8 +424,8 @@ int asCModule::CallInit(asIScriptContext *myCtx)
|
||||
{
|
||||
if( ctx == 0 )
|
||||
{
|
||||
r = engine->CreateContext(&ctx, true);
|
||||
if( r < 0 )
|
||||
ctx = engine->RequestContext();
|
||||
if( ctx == 0 )
|
||||
break;
|
||||
}
|
||||
|
||||
@ -346,7 +464,7 @@ int asCModule::CallInit(asIScriptContext *myCtx)
|
||||
|
||||
if( ctx && !myCtx )
|
||||
{
|
||||
ctx->Release();
|
||||
engine->ReturnContext(ctx);
|
||||
ctx = 0;
|
||||
}
|
||||
|
||||
@ -401,33 +519,98 @@ void asCModule::CallExit()
|
||||
isGlobalVarInitialized = false;
|
||||
}
|
||||
|
||||
// internal
|
||||
bool asCModule::HasExternalReferences(bool shuttingDown)
|
||||
{
|
||||
// Check all entiteis in the module for any external references.
|
||||
// If there are any external references the module cannot be deleted yet.
|
||||
|
||||
for( asUINT n = 0; n < scriptFunctions.GetLength(); n++ )
|
||||
if( scriptFunctions[n] && scriptFunctions[n]->externalRefCount.get() )
|
||||
{
|
||||
if( !shuttingDown )
|
||||
return true;
|
||||
else
|
||||
{
|
||||
asCString msg;
|
||||
msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, name.AddressOf());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf());
|
||||
|
||||
msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, scriptFunctions[n]->GetName(), scriptFunctions[n]->GetFuncType());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
}
|
||||
|
||||
for( asUINT n = 0; n < classTypes.GetLength(); n++ )
|
||||
if( classTypes[n] && classTypes[n]->externalRefCount.get() )
|
||||
{
|
||||
if( !shuttingDown )
|
||||
return true;
|
||||
else
|
||||
{
|
||||
asCString msg;
|
||||
msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, name.AddressOf());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf());
|
||||
|
||||
msg.Format(TXT_PREV_TYPE_IS_NAMED_s, classTypes[n]->GetName());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
}
|
||||
|
||||
for( asUINT n = 0; n < funcDefs.GetLength(); n++ )
|
||||
if( funcDefs[n] && funcDefs[n]->externalRefCount.get() )
|
||||
{
|
||||
if( !shuttingDown )
|
||||
return true;
|
||||
else
|
||||
{
|
||||
asCString msg;
|
||||
msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, name.AddressOf());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf());
|
||||
|
||||
msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, funcDefs[n]->GetName(), funcDefs[n]->GetFuncType());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
}
|
||||
|
||||
for( asUINT n = 0; n < templateInstances.GetLength(); n++ )
|
||||
if( templateInstances[n] && templateInstances[n]->externalRefCount.get() )
|
||||
{
|
||||
if( !shuttingDown )
|
||||
return true;
|
||||
else
|
||||
{
|
||||
asCString msg;
|
||||
msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, name.AddressOf());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf());
|
||||
|
||||
msg.Format(TXT_PREV_TYPE_IS_NAMED_s, templateInstances[n]->GetName());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// internal
|
||||
void asCModule::InternalReset()
|
||||
{
|
||||
CallExit();
|
||||
|
||||
size_t n;
|
||||
asUINT n;
|
||||
|
||||
// Release all global functions
|
||||
asCSymbolTable<asCScriptFunction>::iterator funcIt = globalFunctions.List();
|
||||
for( ; funcIt; funcIt++ )
|
||||
(*funcIt)->Release();
|
||||
// Remove all global functions
|
||||
globalFunctions.Clear();
|
||||
|
||||
// First release all compiled functions
|
||||
for( n = 0; n < scriptFunctions.GetLength(); n++ )
|
||||
if( scriptFunctions[n] )
|
||||
scriptFunctions[n]->Orphan(this);
|
||||
scriptFunctions.SetLength(0);
|
||||
|
||||
// Release the global properties declared in the module
|
||||
// Destroy the internals of the global properties here, but do not yet remove them from the
|
||||
// engine, because functions need the engine's varAddressMap to get to the property. If the
|
||||
// property is removed already, it may leak as the refCount doesn't reach 0.
|
||||
asCSymbolTableIterator<asCGlobalProperty> globIt = scriptGlobals.List();
|
||||
while( globIt )
|
||||
{
|
||||
(*globIt)->Orphan(this);
|
||||
(*globIt)->DestroyInternal();
|
||||
globIt++;
|
||||
}
|
||||
scriptGlobals.Clear();
|
||||
|
||||
UnbindAllImportedFunctions();
|
||||
|
||||
@ -436,39 +619,156 @@ void asCModule::InternalReset()
|
||||
{
|
||||
if( bindInformations[n] )
|
||||
{
|
||||
asUINT id = bindInformations[n]->importedFunctionSignature->id & ~FUNC_IMPORTED;
|
||||
engine->importedFunctions[id] = 0;
|
||||
engine->freeImportedFunctionIdxs.PushLast(id);
|
||||
bindInformations[n]->importedFunctionSignature->ReleaseInternal();
|
||||
|
||||
asDELETE(bindInformations[n]->importedFunctionSignature, asCScriptFunction);
|
||||
asDELETE(bindInformations[n], sBindInfo);
|
||||
}
|
||||
}
|
||||
bindInformations.SetLength(0);
|
||||
|
||||
// Free declared types, including classes, typedefs, and enums
|
||||
// TODO: optimize: Check if it is possible to destroy the object directly without notifying the GC
|
||||
for( n = 0; n < templateInstances.GetLength(); n++ )
|
||||
{
|
||||
asCObjectType *type = templateInstances[n];
|
||||
if( engine->FindNewOwnerForSharedType(type, this) != this )
|
||||
{
|
||||
// The type is owned by another module, just release our reference
|
||||
type->ReleaseInternal();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Orphan the template instance
|
||||
type->module = 0;
|
||||
|
||||
// No other module is holding the template type
|
||||
engine->RemoveTemplateInstanceType(type);
|
||||
type->ReleaseInternal();
|
||||
}
|
||||
templateInstances.SetLength(0);
|
||||
for( n = 0; n < classTypes.GetLength(); n++ )
|
||||
classTypes[n]->Orphan(this);
|
||||
{
|
||||
asCObjectType *type = classTypes[n];
|
||||
if( type->IsShared() )
|
||||
{
|
||||
// The type is shared, so transfer ownership to another module that also uses it
|
||||
if( engine->FindNewOwnerForSharedType(type, this) != this )
|
||||
{
|
||||
// The type is owned by another module, just release our reference
|
||||
type->ReleaseInternal();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// The type should be destroyed now
|
||||
type->DestroyInternal();
|
||||
|
||||
// Remove the type from the engine
|
||||
if( type->IsShared() )
|
||||
{
|
||||
engine->sharedScriptTypes.RemoveValue(type);
|
||||
type->ReleaseInternal();
|
||||
}
|
||||
|
||||
// Release it from the module
|
||||
type->module = 0;
|
||||
type->ReleaseInternal();
|
||||
}
|
||||
classTypes.SetLength(0);
|
||||
for( n = 0; n < enumTypes.GetLength(); n++ )
|
||||
enumTypes[n]->Release();
|
||||
{
|
||||
asCObjectType *type = enumTypes[n];
|
||||
if( type->IsShared() )
|
||||
{
|
||||
// The type is shared, so transfer ownership to another module that also uses it
|
||||
if( engine->FindNewOwnerForSharedType(type, this) != this )
|
||||
{
|
||||
// The type is owned by another module, just release our reference
|
||||
type->ReleaseInternal();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// The type should be destroyed now
|
||||
type->DestroyInternal();
|
||||
|
||||
// Remove the type from the engine
|
||||
if( type->IsShared() )
|
||||
{
|
||||
engine->sharedScriptTypes.RemoveValue(type);
|
||||
type->ReleaseInternal();
|
||||
}
|
||||
|
||||
// Release it from the module
|
||||
type->module = 0;
|
||||
type->ReleaseInternal();
|
||||
}
|
||||
enumTypes.SetLength(0);
|
||||
for( n = 0; n < typeDefs.GetLength(); n++ )
|
||||
typeDefs[n]->Release();
|
||||
{
|
||||
asCObjectType *type = typeDefs[n];
|
||||
|
||||
// The type should be destroyed now
|
||||
type->DestroyInternal();
|
||||
|
||||
// Release it from the module
|
||||
type->module = 0;
|
||||
type->ReleaseInternal();
|
||||
}
|
||||
typeDefs.SetLength(0);
|
||||
|
||||
// Free funcdefs
|
||||
for( n = 0; n < funcDefs.GetLength(); n++ )
|
||||
{
|
||||
// The funcdefs are not removed from the engine at this moment as they may still be referred
|
||||
// to by other types. The engine's ClearUnusedTypes will take care of the clean up.
|
||||
funcDefs[n]->Release();
|
||||
asCScriptFunction *func = funcDefs[n];
|
||||
if( func->IsShared() )
|
||||
{
|
||||
// The func is shared, so transfer ownership to another module that also uses it
|
||||
if( engine->FindNewOwnerForSharedFunc(func, this) != this )
|
||||
{
|
||||
// The func is owned by another module, just release our reference
|
||||
func->ReleaseInternal();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
func->DestroyInternal();
|
||||
engine->RemoveFuncdef(func);
|
||||
func->module = 0;
|
||||
func->ReleaseInternal();
|
||||
}
|
||||
funcDefs.SetLength(0);
|
||||
|
||||
// Allow the engine to clean up what is not used
|
||||
engine->CleanupAfterDiscardModule();
|
||||
// Then release the functions
|
||||
for( n = 0; n < scriptFunctions.GetLength(); n++ )
|
||||
{
|
||||
asCScriptFunction *func = scriptFunctions[n];
|
||||
if( func->IsShared() )
|
||||
{
|
||||
// The func is shared, so transfer ownership to another module that also uses it
|
||||
if( engine->FindNewOwnerForSharedFunc(func, this) != this )
|
||||
{
|
||||
// The func is owned by another module, just release our reference
|
||||
func->ReleaseInternal();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
func->DestroyInternal();
|
||||
func->module = 0;
|
||||
func->ReleaseInternal();
|
||||
}
|
||||
scriptFunctions.SetLength(0);
|
||||
|
||||
// Now remove and release the global properties as there are no more references to them
|
||||
globIt = scriptGlobals.List();
|
||||
while( globIt )
|
||||
{
|
||||
engine->RemoveGlobalProperty(*globIt);
|
||||
asASSERT( (*globIt)->refCount.get() == 1 );
|
||||
(*globIt)->Release();
|
||||
globIt++;
|
||||
}
|
||||
scriptGlobals.Clear();
|
||||
|
||||
asASSERT( IsEmpty() );
|
||||
}
|
||||
@ -476,12 +776,22 @@ void asCModule::InternalReset()
|
||||
// interface
|
||||
asIScriptFunction *asCModule::GetFunctionByName(const char *name) const
|
||||
{
|
||||
const asCArray<unsigned int> &idxs = globalFunctions.GetIndexes(defaultNamespace, name);
|
||||
if( idxs.GetLength() != 1 )
|
||||
return 0;
|
||||
asSNameSpace *ns = defaultNamespace;
|
||||
while( ns )
|
||||
{
|
||||
const asCArray<unsigned int> &idxs = globalFunctions.GetIndexes(ns, name);
|
||||
if( idxs.GetLength() != 1 )
|
||||
return 0;
|
||||
|
||||
const asIScriptFunction *func = globalFunctions.Get(idxs[0]);
|
||||
return const_cast<asIScriptFunction*>(func);
|
||||
const asIScriptFunction *func = globalFunctions.Get(idxs[0]);
|
||||
if( func )
|
||||
return const_cast<asIScriptFunction*>(func);
|
||||
|
||||
// Recursively search parent namespaces
|
||||
ns = engine->GetParentNameSpace(ns);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
@ -562,38 +872,49 @@ asIScriptFunction *asCModule::GetFunctionByDecl(const char *decl) const
|
||||
asSNameSpace *ns = func.nameSpace == engine->nameSpaces[0] ? defaultNamespace : func.nameSpace;
|
||||
|
||||
// Search script functions for matching interface
|
||||
asIScriptFunction *f = 0;
|
||||
const asCArray<unsigned int> &idxs = globalFunctions.GetIndexes(ns, func.name);
|
||||
for( unsigned int n = 0; n < idxs.GetLength(); n++ )
|
||||
while( ns )
|
||||
{
|
||||
const asCScriptFunction *funcPtr = globalFunctions.Get(idxs[n]);
|
||||
if( funcPtr->objectType == 0 &&
|
||||
func.returnType == funcPtr->returnType &&
|
||||
func.parameterTypes.GetLength() == funcPtr->parameterTypes.GetLength()
|
||||
)
|
||||
asIScriptFunction *f = 0;
|
||||
const asCArray<unsigned int> &idxs = globalFunctions.GetIndexes(ns, func.name);
|
||||
for( unsigned int n = 0; n < idxs.GetLength(); n++ )
|
||||
{
|
||||
bool match = true;
|
||||
for( size_t p = 0; p < func.parameterTypes.GetLength(); ++p )
|
||||
const asCScriptFunction *funcPtr = globalFunctions.Get(idxs[n]);
|
||||
if( funcPtr->objectType == 0 &&
|
||||
func.returnType == funcPtr->returnType &&
|
||||
func.parameterTypes.GetLength() == funcPtr->parameterTypes.GetLength()
|
||||
)
|
||||
{
|
||||
if( func.parameterTypes[p] != funcPtr->parameterTypes[p] )
|
||||
bool match = true;
|
||||
for( asUINT p = 0; p < func.parameterTypes.GetLength(); ++p )
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
if( func.parameterTypes[p] != funcPtr->parameterTypes[p] )
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( match )
|
||||
{
|
||||
if( f == 0 )
|
||||
f = const_cast<asCScriptFunction*>(funcPtr);
|
||||
else
|
||||
// Multiple functions
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( match )
|
||||
{
|
||||
if( f == 0 )
|
||||
f = const_cast<asCScriptFunction*>(funcPtr);
|
||||
else
|
||||
// Multiple functions
|
||||
return 0;
|
||||
}
|
||||
if( f )
|
||||
return f;
|
||||
else
|
||||
{
|
||||
// Search for matching functions in the parent namespace
|
||||
ns = engine->GetParentNameSpace(ns);
|
||||
}
|
||||
}
|
||||
|
||||
return f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
@ -605,21 +926,41 @@ asUINT asCModule::GetGlobalVarCount() const
|
||||
// interface
|
||||
int asCModule::GetGlobalVarIndexByName(const char *name) const
|
||||
{
|
||||
asSNameSpace *ns = defaultNamespace;
|
||||
|
||||
// Find the global var id
|
||||
int id = scriptGlobals.GetFirstIndex(defaultNamespace, name);
|
||||
while( ns )
|
||||
{
|
||||
int id = scriptGlobals.GetFirstIndex(ns, name);
|
||||
if( id >= 0 ) return id;
|
||||
|
||||
if( id == -1 ) return asNO_GLOBAL_VAR;
|
||||
// Recursively search parent namespaces
|
||||
ns = engine->GetParentNameSpace(ns);
|
||||
}
|
||||
|
||||
return id;
|
||||
return asNO_GLOBAL_VAR;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCModule::RemoveGlobalVar(asUINT index)
|
||||
{
|
||||
// TODO: 2.30.0: redesign: Before removing the variable, clear it to free the object
|
||||
// The property shouldn't be orphaned.
|
||||
|
||||
asCGlobalProperty *prop = scriptGlobals.Get(index);
|
||||
if( !prop )
|
||||
return asINVALID_ARG;
|
||||
prop->Orphan(this);
|
||||
|
||||
// Destroy the internal of the global variable (removes the initialization function)
|
||||
prop->DestroyInternal();
|
||||
|
||||
// Check if the module is the only one referring to the module, if so remove it from the engine too
|
||||
// If the property is not removed now, it will be removed later when the module is discarded
|
||||
if( prop->refCount.get() == 2 )
|
||||
engine->RemoveGlobalProperty(prop);
|
||||
|
||||
// Remove the global variable from the module
|
||||
prop->Release();
|
||||
scriptGlobals.Erase(index);
|
||||
|
||||
return 0;
|
||||
@ -641,9 +982,15 @@ int asCModule::GetGlobalVarIndexByDecl(const char *decl) const
|
||||
return r;
|
||||
|
||||
// Search global variables for a match
|
||||
int id = scriptGlobals.GetFirstIndex(nameSpace, name, asCCompGlobPropType(dt));
|
||||
if( id != -1 )
|
||||
return id;
|
||||
while( nameSpace )
|
||||
{
|
||||
int id = scriptGlobals.GetFirstIndex(nameSpace, name, asCCompGlobPropType(dt));
|
||||
if( id != -1 )
|
||||
return id;
|
||||
|
||||
// Recursively search parent namespace
|
||||
nameSpace = engine->GetParentNameSpace(nameSpace);
|
||||
}
|
||||
|
||||
return asNO_GLOBAL_VAR;
|
||||
}
|
||||
@ -670,9 +1017,9 @@ const char *asCModule::GetGlobalVarDeclaration(asUINT index, bool includeNamespa
|
||||
if (!prop) return 0;
|
||||
|
||||
asCString *tempString = &asCThreadManager::GetLocalData()->string;
|
||||
*tempString = prop->type.Format();
|
||||
*tempString = prop->type.Format(defaultNamespace);
|
||||
*tempString += " ";
|
||||
if( includeNamespace )
|
||||
if( includeNamespace && prop->nameSpace->name != "" )
|
||||
*tempString += prop->nameSpace->name + "::";
|
||||
*tempString += prop->name;
|
||||
|
||||
@ -715,12 +1062,19 @@ asIObjectType *asCModule::GetObjectTypeByIndex(asUINT index) const
|
||||
// interface
|
||||
asIObjectType *asCModule::GetObjectTypeByName(const char *name) const
|
||||
{
|
||||
for( asUINT n = 0; n < classTypes.GetLength(); n++ )
|
||||
asSNameSpace *ns = defaultNamespace;
|
||||
while( ns )
|
||||
{
|
||||
if( classTypes[n] &&
|
||||
classTypes[n]->name == name &&
|
||||
classTypes[n]->nameSpace == defaultNamespace )
|
||||
return classTypes[n];
|
||||
for( asUINT n = 0; n < classTypes.GetLength(); n++ )
|
||||
{
|
||||
if( classTypes[n] &&
|
||||
classTypes[n]->name == name &&
|
||||
classTypes[n]->nameSpace == ns )
|
||||
return classTypes[n];
|
||||
}
|
||||
|
||||
// Recursively search parent namespace
|
||||
ns = engine->GetParentNameSpace(ns);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -744,6 +1098,24 @@ int asCModule::GetTypeIdByDecl(const char *decl) const
|
||||
return engine->GetTypeIdFromDataType(dt);
|
||||
}
|
||||
|
||||
// interface
|
||||
asIObjectType *asCModule::GetObjectTypeByDecl(const char *decl) const
|
||||
{
|
||||
asCDataType dt;
|
||||
|
||||
// This const cast is safe since we know the engine won't be modified
|
||||
asCBuilder bld(engine, const_cast<asCModule*>(this));
|
||||
|
||||
// Don't write parser errors to the message callback
|
||||
bld.silent = true;
|
||||
|
||||
int r = bld.ParseDataType(decl, &dt, defaultNamespace);
|
||||
if( r < 0 )
|
||||
return 0;
|
||||
|
||||
return dt.GetObjectType();
|
||||
}
|
||||
|
||||
// interface
|
||||
asUINT asCModule::GetEnumCount() const
|
||||
{
|
||||
@ -827,7 +1199,7 @@ int asCModule::GetNextImportedFunctionId()
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
// internal
|
||||
int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &name, const asCDataType &returnType, const asCArray<asCDataType> ¶ms, const asCArray<asETypeModifiers> &inOutFlags, const asCArray<asCString *> &defaultArgs, bool isInterface, asCObjectType *objType, bool isConstMethod, bool isGlobalFunction, bool isPrivate, bool isFinal, bool isOverride, bool isShared, asSNameSpace *ns)
|
||||
int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &name, const asCDataType &returnType, const asCArray<asCDataType> ¶ms, const asCArray<asCString> ¶mNames, const asCArray<asETypeModifiers> &inOutFlags, const asCArray<asCString *> &defaultArgs, bool isInterface, asCObjectType *objType, bool isConstMethod, bool isGlobalFunction, bool isPrivate, bool isProtected, bool isFinal, bool isOverride, bool isShared, asSNameSpace *ns)
|
||||
{
|
||||
asASSERT(id >= 0);
|
||||
|
||||
@ -860,11 +1232,15 @@ int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const a
|
||||
func->scriptData->declaredAt = declaredAt;
|
||||
}
|
||||
func->parameterTypes = params;
|
||||
func->parameterNames = paramNames;
|
||||
func->inOutFlags = inOutFlags;
|
||||
func->defaultArgs = defaultArgs;
|
||||
func->objectType = objType;
|
||||
if( objType )
|
||||
objType->AddRefInternal();
|
||||
func->isReadOnly = isConstMethod;
|
||||
func->isPrivate = isPrivate;
|
||||
func->isProtected = isProtected;
|
||||
func->isFinal = isFinal;
|
||||
func->isOverride = isOverride;
|
||||
func->isShared = isShared;
|
||||
@ -875,9 +1251,9 @@ int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const a
|
||||
asASSERT( !(!objType && isFinal) );
|
||||
asASSERT( !(!objType && isOverride) );
|
||||
|
||||
// The script function's refCount was initialized to 1
|
||||
// The internal ref count was already set by the constructor
|
||||
scriptFunctions.PushLast(func);
|
||||
engine->SetScriptFunction(func);
|
||||
engine->AddScriptFunction(func);
|
||||
|
||||
// Compute the signature id
|
||||
if( objType )
|
||||
@ -885,10 +1261,7 @@ int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const a
|
||||
|
||||
// Add reference
|
||||
if( isGlobalFunction )
|
||||
{
|
||||
globalFunctions.Put(func);
|
||||
func->AddRef();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -897,8 +1270,8 @@ int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const a
|
||||
int asCModule::AddScriptFunction(asCScriptFunction *func)
|
||||
{
|
||||
scriptFunctions.PushLast(func);
|
||||
func->AddRef();
|
||||
engine->SetScriptFunction(func);
|
||||
func->AddRefInternal();
|
||||
engine->AddScriptFunction(func);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -982,14 +1355,14 @@ int asCModule::BindImportedFunction(asUINT index, asIScriptFunction *func)
|
||||
if( dst->parameterTypes.GetLength() != src->parameterTypes.GetLength() )
|
||||
return asINVALID_INTERFACE;
|
||||
|
||||
for( size_t n = 0; n < dst->parameterTypes.GetLength(); ++n )
|
||||
for( asUINT n = 0; n < dst->parameterTypes.GetLength(); ++n )
|
||||
{
|
||||
if( dst->parameterTypes[n] != src->parameterTypes[n] )
|
||||
return asINVALID_INTERFACE;
|
||||
}
|
||||
|
||||
bindInformations[index]->boundFunctionId = src->GetId();
|
||||
src->AddRef();
|
||||
src->AddRefInternal();
|
||||
|
||||
return asSUCCESS;
|
||||
}
|
||||
@ -1007,7 +1380,7 @@ int asCModule::UnbindImportedFunction(asUINT index)
|
||||
if( oldFuncID != -1 )
|
||||
{
|
||||
bindInformations[index]->boundFunctionId = -1;
|
||||
engine->scriptFunctions[oldFuncID]->Release();
|
||||
engine->scriptFunctions[oldFuncID]->ReleaseInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1047,7 +1420,7 @@ int asCModule::BindAllImportedFunctions()
|
||||
asCScriptFunction *importFunc = GetImportedFunction(n);
|
||||
if( importFunc == 0 ) return asERROR;
|
||||
|
||||
asCString str = importFunc->GetDeclarationStr();
|
||||
asCString str = importFunc->GetDeclarationStr(false, true);
|
||||
|
||||
// Get module name from where the function should be imported
|
||||
const char *moduleName = GetImportedFunctionSourceModule(n);
|
||||
@ -1086,7 +1459,7 @@ int asCModule::UnbindAllImportedFunctions()
|
||||
// internal
|
||||
asCObjectType *asCModule::GetObjectType(const char *type, asSNameSpace *ns)
|
||||
{
|
||||
size_t n;
|
||||
asUINT n;
|
||||
|
||||
// TODO: optimize: Improve linear search
|
||||
for( n = 0; n < classTypes.GetLength(); n++ )
|
||||
@ -1121,8 +1494,9 @@ asCGlobalProperty *asCModule::AllocateGlobalProperty(const char *name, const asC
|
||||
// Make an entry in the address to variable map
|
||||
engine->varAddressMap.Insert(prop->GetAddressOfValue(), prop);
|
||||
|
||||
// Store the variable in the module scope (the reference count is already set to 1)
|
||||
// Store the variable in the module scope
|
||||
scriptGlobals.Put(prop);
|
||||
prop->AddRef();
|
||||
|
||||
return prop;
|
||||
}
|
||||
@ -1166,6 +1540,14 @@ int asCModule::LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped)
|
||||
{
|
||||
if( in == 0 ) return asINVALID_ARG;
|
||||
|
||||
// Don't allow the module to be rebuilt if there are still
|
||||
// external references that will need the previous code
|
||||
if( HasExternalReferences(false) )
|
||||
{
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_MODULE_IS_IN_USE);
|
||||
return asMODULE_IS_IN_USE;
|
||||
}
|
||||
|
||||
// Only permit loading bytecode if no other thread is currently compiling
|
||||
// TODO: It should be possible to have multiple threads perform compilations
|
||||
int r = engine->RequestBuild();
|
||||
@ -1302,14 +1684,14 @@ int asCModule::CompileFunction(const char *sectionName, const char *code, int li
|
||||
|
||||
if( r >= 0 && outFunc && func )
|
||||
{
|
||||
// Return the function to the caller
|
||||
// Return the function to the caller and add an external reference
|
||||
*outFunc = func;
|
||||
func->AddRef();
|
||||
}
|
||||
|
||||
// Release our reference to the function
|
||||
if( func )
|
||||
func->Release();
|
||||
func->ReleaseInternal();
|
||||
|
||||
return r;
|
||||
#endif
|
||||
@ -1318,15 +1700,24 @@ int asCModule::CompileFunction(const char *sectionName, const char *code, int li
|
||||
// interface
|
||||
int asCModule::RemoveFunction(asIScriptFunction *func)
|
||||
{
|
||||
// TODO: 2.30.0: redesign: Check if there are any references before removing the function
|
||||
// if there are, just hide it from the visible but do not destroy or
|
||||
// remove it from the module.
|
||||
//
|
||||
// Only if the function has no live references, nor internal references
|
||||
// can it be immediately removed, and its internal references released.
|
||||
//
|
||||
// Check if any previously hidden functions are without references,
|
||||
// if so they should removed too.
|
||||
|
||||
// Find the global function
|
||||
asCScriptFunction *f = static_cast<asCScriptFunction*>(func);
|
||||
int idx = globalFunctions.GetIndex(f);
|
||||
if( idx >= 0 )
|
||||
{
|
||||
globalFunctions.Erase(idx);
|
||||
f->Release();
|
||||
scriptFunctions.RemoveValue(f);
|
||||
f->Orphan(this);
|
||||
f->ReleaseInternal();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1348,7 +1739,7 @@ int asCModule::AddFuncDef(const asCString &name, asSNameSpace *ns)
|
||||
|
||||
engine->funcDefs.PushLast(func);
|
||||
func->id = engine->GetNextScriptFunctionId();
|
||||
engine->SetScriptFunction(func);
|
||||
engine->AddScriptFunction(func);
|
||||
|
||||
return (int)funcDefs.GetLength()-1;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -132,6 +132,7 @@ public:
|
||||
virtual asUINT GetObjectTypeCount() const;
|
||||
virtual asIObjectType *GetObjectTypeByIndex(asUINT index) const;
|
||||
virtual asIObjectType *GetObjectTypeByName(const char *name) const;
|
||||
virtual asIObjectType *GetObjectTypeByDecl(const char *decl) const;
|
||||
virtual int GetTypeIdByDecl(const char *decl) const;
|
||||
|
||||
// Enums
|
||||
@ -159,8 +160,8 @@ public:
|
||||
virtual int LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped);
|
||||
|
||||
// User data
|
||||
virtual void *SetUserData(void *data);
|
||||
virtual void *GetUserData() const;
|
||||
virtual void *SetUserData(void *data, asPWORD type);
|
||||
virtual void *GetUserData(asPWORD type) const;
|
||||
|
||||
//-----------------------------------------------
|
||||
// Internal
|
||||
@ -177,6 +178,7 @@ public:
|
||||
|
||||
void InternalReset();
|
||||
bool IsEmpty() const;
|
||||
bool HasExternalReferences(bool shuttingDown);
|
||||
|
||||
int CallInit(asIScriptContext *ctx);
|
||||
void CallExit();
|
||||
@ -184,7 +186,7 @@ public:
|
||||
void JITCompile();
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
int AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &name, const asCDataType &returnType, const asCArray<asCDataType> ¶ms, const asCArray<asETypeModifiers> &inOutFlags, const asCArray<asCString *> &defaultArgs, bool isInterface, asCObjectType *objType = 0, bool isConstMethod = false, bool isGlobalFunction = false, bool isPrivate = false, bool isFinal = false, bool isOverride = false, bool isShared = false, asSNameSpace *ns = 0);
|
||||
int AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &name, const asCDataType &returnType, const asCArray<asCDataType> ¶ms, const asCArray<asCString> ¶mNames, const asCArray<asETypeModifiers> &inOutFlags, const asCArray<asCString *> &defaultArgs, bool isInterface, asCObjectType *objType = 0, bool isConstMethod = false, bool isGlobalFunction = false, bool isPrivate = false, bool isProtected = false, bool isFinal = false, bool isOverride = false, bool isShared = false, asSNameSpace *ns = 0);
|
||||
int AddScriptFunction(asCScriptFunction *func);
|
||||
int AddImportedFunction(int id, const asCString &name, const asCDataType &returnType, const asCArray<asCDataType> ¶ms, const asCArray<asETypeModifiers> &inOutFlags, const asCArray<asCString *> &defaultArgs, asSNameSpace *ns, const asCString &moduleName);
|
||||
int AddFuncDef(const asCString &name, asSNameSpace *ns);
|
||||
@ -197,31 +199,35 @@ public:
|
||||
|
||||
asCString name;
|
||||
|
||||
asCScriptEngine *engine;
|
||||
asCBuilder *builder;
|
||||
void *userData;
|
||||
asDWORD accessMask;
|
||||
asSNameSpace *defaultNamespace;
|
||||
asCScriptEngine *engine;
|
||||
asCBuilder *builder;
|
||||
asCArray<asPWORD> userData;
|
||||
asDWORD accessMask;
|
||||
asSNameSpace *defaultNamespace;
|
||||
|
||||
// This array holds all functions, class members, factories, etc that were compiled with the module
|
||||
asCArray<asCScriptFunction *> scriptFunctions;
|
||||
// This array holds global functions declared in the module
|
||||
asCSymbolTable<asCScriptFunction> globalFunctions;
|
||||
// This array holds imported functions in the module
|
||||
asCArray<sBindInfo *> bindInformations;
|
||||
// This array holds all functions, class members, factories, etc that were compiled with the module.
|
||||
// These references hold an internal reference to the function object.
|
||||
asCArray<asCScriptFunction *> scriptFunctions; // increases ref count
|
||||
// This array holds global functions declared in the module. These references are not counted,
|
||||
// as the same pointer is always present in the scriptFunctions array too.
|
||||
asCSymbolTable<asCScriptFunction> globalFunctions; // doesn't increase ref count
|
||||
// This array holds imported functions in the module.
|
||||
asCArray<sBindInfo *> bindInformations; // increases ref count
|
||||
// This array holds template instance types created for the module's object types
|
||||
asCArray<asCObjectType*> templateInstances; // increases ref count
|
||||
|
||||
// This array holds the global variables declared in the script
|
||||
asCSymbolTable<asCGlobalProperty> scriptGlobals;
|
||||
asCSymbolTable<asCGlobalProperty> scriptGlobals; // increases ref count
|
||||
bool isGlobalVarInitialized;
|
||||
|
||||
// This array holds class and interface types
|
||||
asCArray<asCObjectType*> classTypes;
|
||||
asCArray<asCObjectType*> classTypes; // increases ref count
|
||||
// This array holds enum types
|
||||
asCArray<asCObjectType*> enumTypes;
|
||||
asCArray<asCObjectType*> enumTypes; // increases ref count
|
||||
// This array holds typedefs
|
||||
asCArray<asCObjectType*> typeDefs;
|
||||
asCArray<asCObjectType*> typeDefs; // increases ref count
|
||||
// This array holds the funcdefs declared in the module
|
||||
asCArray<asCScriptFunction*> funcDefs;
|
||||
asCArray<asCScriptFunction*> funcDefs; // increases ref count
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2013 Andreas Jonsson
|
||||
Copyright (c) 2013-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -74,3 +74,4 @@ struct asSNameSpaceNamePair
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -45,140 +45,95 @@
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
#ifdef AS_MAX_PORTABILITY
|
||||
|
||||
static void ObjectType_AddRef_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCObjectType *self = (asCObjectType*)gen->GetObject();
|
||||
self->AddRef();
|
||||
}
|
||||
|
||||
static void ObjectType_Release_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCObjectType *self = (asCObjectType*)gen->GetObject();
|
||||
self->Release();
|
||||
}
|
||||
|
||||
static void ObjectType_GetRefCount_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCObjectType *self = (asCObjectType*)gen->GetObject();
|
||||
*(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
|
||||
}
|
||||
|
||||
static void ObjectType_SetGCFlag_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCObjectType *self = (asCObjectType*)gen->GetObject();
|
||||
self->SetGCFlag();
|
||||
}
|
||||
|
||||
static void ObjectType_GetGCFlag_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCObjectType *self = (asCObjectType*)gen->GetObject();
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag();
|
||||
}
|
||||
|
||||
static void ObjectType_EnumReferences_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCObjectType *self = (asCObjectType*)gen->GetObject();
|
||||
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
|
||||
self->EnumReferences(engine);
|
||||
}
|
||||
|
||||
static void ObjectType_ReleaseAllHandles_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCObjectType *self = (asCObjectType*)gen->GetObject();
|
||||
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
|
||||
self->ReleaseAllHandles(engine);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void RegisterObjectTypeGCBehaviours(asCScriptEngine *engine)
|
||||
{
|
||||
// Register the gc behaviours for the object types
|
||||
int r = 0;
|
||||
UNUSED_VAR(r); // It is only used in debug mode
|
||||
engine->objectTypeBehaviours.engine = engine;
|
||||
engine->objectTypeBehaviours.flags = asOBJ_REF | asOBJ_GC;
|
||||
engine->objectTypeBehaviours.name = "_builtin_objecttype_";
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCObjectType,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCObjectType,Release), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(asCObjectType,GetRefCount), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_SETGCFLAG, "void f()", asMETHOD(asCObjectType,SetGCFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCObjectType,GetGCFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCObjectType,EnumReferences), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCObjectType,ReleaseAllHandles), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
#else
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(ObjectType_AddRef_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(ObjectType_Release_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ObjectType_GetRefCount_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ObjectType_SetGCFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ObjectType_GetGCFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ObjectType_EnumReferences_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->objectTypeBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ObjectType_ReleaseAllHandles_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
asCObjectType::asCObjectType()
|
||||
{
|
||||
engine = 0;
|
||||
module = 0;
|
||||
refCount.set(0);
|
||||
externalRefCount.set(0);
|
||||
internalRefCount.set(1); // start with one internal ref-count
|
||||
engine = 0;
|
||||
module = 0;
|
||||
derivedFrom = 0;
|
||||
size = 0;
|
||||
|
||||
acceptValueSubType = true;
|
||||
acceptRefSubType = true;
|
||||
acceptRefSubType = true;
|
||||
|
||||
scriptSectionIdx = -1;
|
||||
declaredAt = 0;
|
||||
|
||||
accessMask = 0xFFFFFFFF;
|
||||
nameSpace = 0;
|
||||
nameSpace = 0;
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
alignment = 4;
|
||||
#endif
|
||||
}
|
||||
|
||||
asCObjectType::asCObjectType(asCScriptEngine *engine)
|
||||
{
|
||||
externalRefCount.set(0);
|
||||
internalRefCount.set(1); // start with one internal ref count
|
||||
this->engine = engine;
|
||||
module = 0;
|
||||
refCount.set(0);
|
||||
module = 0;
|
||||
derivedFrom = 0;
|
||||
|
||||
acceptValueSubType = true;
|
||||
acceptRefSubType = true;
|
||||
acceptRefSubType = true;
|
||||
|
||||
scriptSectionIdx = -1;
|
||||
declaredAt = 0;
|
||||
|
||||
accessMask = 0xFFFFFFFF;
|
||||
nameSpace = engine->nameSpaces[0];
|
||||
nameSpace = engine->nameSpaces[0];
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
alignment = 4;
|
||||
#endif
|
||||
}
|
||||
|
||||
int asCObjectType::AddRef() const
|
||||
{
|
||||
gcFlag = false;
|
||||
return refCount.atomicInc();
|
||||
return externalRefCount.atomicInc();
|
||||
}
|
||||
|
||||
int asCObjectType::Release() const
|
||||
{
|
||||
gcFlag = false;
|
||||
return refCount.atomicDec();
|
||||
}
|
||||
int r = externalRefCount.atomicDec();
|
||||
|
||||
void asCObjectType::Orphan(asCModule *mod)
|
||||
{
|
||||
if( mod && mod == module )
|
||||
if( r == 0 )
|
||||
{
|
||||
module = 0;
|
||||
if( flags & asOBJ_SCRIPT_OBJECT )
|
||||
// There are no more external references, if there are also no
|
||||
// internal references then it is time to delete the object type
|
||||
if( internalRefCount.get() == 0 )
|
||||
{
|
||||
// Tell the GC that this type exists so it can resolve potential circular references
|
||||
engine->gc.AddScriptObjectToGC(this, &engine->objectTypeBehaviours);
|
||||
|
||||
// It's necessary to orphan the template instance types that refer to this object type,
|
||||
// otherwise the garbage collector cannot identify the circular references that involve
|
||||
// the type and the template type
|
||||
engine->OrphanTemplateInstances(this);
|
||||
// If the engine is no longer set, then it has already been
|
||||
// released and we must take care of the deletion ourselves
|
||||
asDELETE(const_cast<asCObjectType*>(this), asCObjectType);
|
||||
}
|
||||
}
|
||||
|
||||
Release();
|
||||
return r;
|
||||
}
|
||||
|
||||
int asCObjectType::AddRefInternal()
|
||||
{
|
||||
return internalRefCount.atomicInc();
|
||||
}
|
||||
|
||||
int asCObjectType::ReleaseInternal()
|
||||
{
|
||||
int r = internalRefCount.atomicDec();
|
||||
|
||||
if( r == 0 )
|
||||
{
|
||||
// There are no more internal references, if there are also no
|
||||
// external references then it is time to delete the object type
|
||||
if( externalRefCount.get() == 0 )
|
||||
{
|
||||
// If the engine is no longer set, then it has already been
|
||||
// released and we must take care of the deletion ourselves
|
||||
asDELETE(const_cast<asCObjectType*>(this), asCObjectType);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// interface
|
||||
@ -237,36 +192,29 @@ void *asCObjectType::GetUserData(asPWORD type) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asCObjectType::GetRefCount()
|
||||
void asCObjectType::DestroyInternal()
|
||||
{
|
||||
return refCount.get();
|
||||
}
|
||||
if( engine == 0 ) return;
|
||||
|
||||
bool asCObjectType::GetGCFlag()
|
||||
{
|
||||
return gcFlag;
|
||||
}
|
||||
|
||||
void asCObjectType::SetGCFlag()
|
||||
{
|
||||
gcFlag = true;
|
||||
}
|
||||
|
||||
asCObjectType::~asCObjectType()
|
||||
{
|
||||
// Skip this for list patterns as they do not increase the references
|
||||
if( flags & asOBJ_LIST_PATTERN )
|
||||
{
|
||||
// Clear the engine pointer to mark the object type as invalid
|
||||
engine = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Release the object types held by the templateSubTypes
|
||||
for( asUINT subtypeIndex = 0; subtypeIndex < templateSubTypes.GetLength(); subtypeIndex++ )
|
||||
{
|
||||
if( templateSubTypes[subtypeIndex].GetObjectType() )
|
||||
templateSubTypes[subtypeIndex].GetObjectType()->Release();
|
||||
templateSubTypes[subtypeIndex].GetObjectType()->ReleaseInternal();
|
||||
}
|
||||
templateSubTypes.SetLength(0);
|
||||
|
||||
if( derivedFrom )
|
||||
derivedFrom->Release();
|
||||
derivedFrom->ReleaseInternal();
|
||||
derivedFrom = 0;
|
||||
|
||||
ReleaseAllProperties();
|
||||
|
||||
@ -290,6 +238,22 @@ asCObjectType::~asCObjectType()
|
||||
engine->cleanObjectTypeFuncs[c].cleanFunc(this);
|
||||
}
|
||||
}
|
||||
userData.SetLength(0);
|
||||
|
||||
// Remove the type from the engine
|
||||
engine->RemoveFromTypeIdMap(this);
|
||||
|
||||
// Clear the engine pointer to mark the object type as invalid
|
||||
engine = 0;
|
||||
}
|
||||
|
||||
asCObjectType::~asCObjectType()
|
||||
{
|
||||
if( engine == 0 )
|
||||
return;
|
||||
|
||||
// TODO: 2.30.0: redesign: Shouldn't this have been done already?
|
||||
DestroyInternal();
|
||||
}
|
||||
|
||||
// interface
|
||||
@ -369,30 +333,23 @@ int asCObjectType::GetTypeId() const
|
||||
// interface
|
||||
int asCObjectType::GetSubTypeId(asUINT subtypeIndex) const
|
||||
{
|
||||
if( flags & asOBJ_TEMPLATE )
|
||||
{
|
||||
if( subtypeIndex >= templateSubTypes.GetLength() )
|
||||
return asINVALID_ARG;
|
||||
// This method is only supported for templates and template specializations
|
||||
if( templateSubTypes.GetLength() == 0 )
|
||||
return asERROR;
|
||||
|
||||
return engine->GetTypeIdFromDataType(templateSubTypes[subtypeIndex]);
|
||||
}
|
||||
if( subtypeIndex >= templateSubTypes.GetLength() )
|
||||
return asINVALID_ARG;
|
||||
|
||||
// Only template types have sub types
|
||||
return asERROR;
|
||||
return engine->GetTypeIdFromDataType(templateSubTypes[subtypeIndex]);
|
||||
}
|
||||
|
||||
// interface
|
||||
asIObjectType *asCObjectType::GetSubType(asUINT subtypeIndex) const
|
||||
{
|
||||
if( flags & asOBJ_TEMPLATE )
|
||||
{
|
||||
if( subtypeIndex >= templateSubTypes.GetLength() )
|
||||
return 0;
|
||||
if( subtypeIndex >= templateSubTypes.GetLength() )
|
||||
return 0;
|
||||
|
||||
return templateSubTypes[subtypeIndex].GetObjectType();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return templateSubTypes[subtypeIndex].GetObjectType();
|
||||
}
|
||||
|
||||
asUINT asCObjectType::GetSubTypeCount() const
|
||||
@ -475,7 +432,7 @@ asIScriptFunction *asCObjectType::GetMethodByIndex(asUINT index, bool getVirtual
|
||||
asIScriptFunction *asCObjectType::GetMethodByName(const char *name, bool getVirtual) const
|
||||
{
|
||||
int id = -1;
|
||||
for( size_t n = 0; n < methods.GetLength(); n++ )
|
||||
for( asUINT n = 0; n < methods.GetLength(); n++ )
|
||||
{
|
||||
if( engine->scriptFunctions[methods[n]]->name == name )
|
||||
{
|
||||
@ -532,23 +489,26 @@ asUINT asCObjectType::GetPropertyCount() const
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCObjectType::GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, int *offset, bool *isReference, asDWORD *accessMask) const
|
||||
int asCObjectType::GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask) const
|
||||
{
|
||||
if( index >= properties.GetLength() )
|
||||
return asINVALID_ARG;
|
||||
|
||||
asCObjectProperty *prop = properties[index];
|
||||
if( name )
|
||||
*name = properties[index]->name.AddressOf();
|
||||
*name = prop->name.AddressOf();
|
||||
if( typeId )
|
||||
*typeId = engine->GetTypeIdFromDataType(properties[index]->type);
|
||||
*typeId = engine->GetTypeIdFromDataType(prop->type);
|
||||
if( isPrivate )
|
||||
*isPrivate = properties[index]->isPrivate;
|
||||
*isPrivate = prop->isPrivate;
|
||||
if( isProtected )
|
||||
*isProtected = prop->isProtected;
|
||||
if( offset )
|
||||
*offset = properties[index]->byteOffset;
|
||||
*offset = prop->byteOffset;
|
||||
if( isReference )
|
||||
*isReference = properties[index]->type.IsReference();
|
||||
*isReference = prop->type.IsReference();
|
||||
if( accessMask )
|
||||
*accessMask = properties[index]->accessMask;
|
||||
*accessMask = prop->accessMask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -562,9 +522,11 @@ const char *asCObjectType::GetPropertyDeclaration(asUINT index, bool includeName
|
||||
asCString *tempString = &asCThreadManager::GetLocalData()->string;
|
||||
if( properties[index]->isPrivate )
|
||||
*tempString = "private ";
|
||||
else if( properties[index]->isProtected )
|
||||
*tempString = "protected ";
|
||||
else
|
||||
*tempString = "";
|
||||
*tempString += properties[index]->type.Format(includeNamespace);
|
||||
*tempString += properties[index]->type.Format(nameSpace, includeNamespace);
|
||||
*tempString += " ";
|
||||
*tempString += properties[index]->name;
|
||||
|
||||
@ -596,7 +558,6 @@ asUINT asCObjectType::GetBehaviourCount() const
|
||||
// For reference types, the factories are also stored in the constructor
|
||||
// list, so it is sufficient to enumerate only those
|
||||
count += (asUINT)beh.constructors.GetLength();
|
||||
count += (asUINT)beh.operators.GetLength() / 2;
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -689,14 +650,6 @@ asIScriptFunction *asCObjectType::GetBehaviourByIndex(asUINT index, asEBehaviour
|
||||
else
|
||||
count += (asUINT)beh.constructors.GetLength();
|
||||
|
||||
if( index - count < beh.operators.GetLength() / 2 )
|
||||
{
|
||||
index = 2*(index - count);
|
||||
|
||||
if( outBehaviour ) *outBehaviour = static_cast<asEBehaviours>(beh.operators[index]);
|
||||
return engine->scriptFunctions[beh.operators[index + 1]];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -717,10 +670,10 @@ asDWORD asCObjectType::GetAccessMask() const
|
||||
}
|
||||
|
||||
// internal
|
||||
asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate)
|
||||
asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited)
|
||||
{
|
||||
asASSERT( flags & asOBJ_SCRIPT_OBJECT );
|
||||
asASSERT( dt.CanBeInstanciated() );
|
||||
asASSERT( dt.CanBeInstantiated() );
|
||||
asASSERT( !IsInterface() );
|
||||
|
||||
// Store the properties in the object type descriptor
|
||||
@ -731,9 +684,11 @@ asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &name, cons
|
||||
return 0;
|
||||
}
|
||||
|
||||
prop->name = name;
|
||||
prop->type = dt;
|
||||
prop->isPrivate = isPrivate;
|
||||
prop->name = name;
|
||||
prop->type = dt;
|
||||
prop->isPrivate = isPrivate;
|
||||
prop->isProtected = isProtected;
|
||||
prop->isInherited = isInherited;
|
||||
|
||||
int propSize;
|
||||
if( dt.IsObject() )
|
||||
@ -755,8 +710,19 @@ asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &name, cons
|
||||
propSize = dt.GetSizeInMemoryBytes();
|
||||
|
||||
// Add extra bytes so that the property will be properly aligned
|
||||
#ifndef WIP_16BYTE_ALIGN
|
||||
if( propSize == 2 && (size & 1) ) size += 1;
|
||||
if( propSize > 2 && (size & 3) ) size += 4 - (size & 3);
|
||||
#else
|
||||
asUINT alignment = dt.GetAlignment();
|
||||
const asUINT propSizeAlignmentDifference = size & (alignment-1);
|
||||
if( propSizeAlignmentDifference != 0 )
|
||||
{
|
||||
size += (alignment - propSizeAlignmentDifference);
|
||||
}
|
||||
|
||||
asASSERT((size % alignment) == 0);
|
||||
#endif
|
||||
|
||||
prop->byteOffset = size;
|
||||
size += propSize;
|
||||
@ -770,7 +736,7 @@ asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &name, cons
|
||||
// Add reference to object types
|
||||
asCObjectType *type = prop->type.GetObjectType();
|
||||
if( type )
|
||||
type->AddRef();
|
||||
type->AddRefInternal();
|
||||
|
||||
return prop;
|
||||
}
|
||||
@ -791,7 +757,14 @@ void asCObjectType::ReleaseAllProperties()
|
||||
// Release references to objects types
|
||||
asCObjectType *type = properties[n]->type.GetObjectType();
|
||||
if( type )
|
||||
type->Release();
|
||||
type->ReleaseInternal();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Release template instance types (ref increased by RegisterObjectProperty)
|
||||
asCObjectType *type = properties[n]->type.GetObjectType();
|
||||
if( type )
|
||||
type->ReleaseInternal();
|
||||
}
|
||||
|
||||
asDELETE(properties[n],asCObjectProperty);
|
||||
@ -801,13 +774,6 @@ void asCObjectType::ReleaseAllProperties()
|
||||
properties.SetLength(0);
|
||||
}
|
||||
|
||||
// internal
|
||||
void asCObjectType::ReleaseAllHandles(asIScriptEngine *)
|
||||
{
|
||||
ReleaseAllFunctions();
|
||||
ReleaseAllProperties();
|
||||
}
|
||||
|
||||
// internal
|
||||
void asCObjectType::ReleaseAllFunctions()
|
||||
{
|
||||
@ -816,7 +782,7 @@ void asCObjectType::ReleaseAllFunctions()
|
||||
for( asUINT a = 0; a < beh.factories.GetLength(); a++ )
|
||||
{
|
||||
if( engine->scriptFunctions[beh.factories[a]] )
|
||||
engine->scriptFunctions[beh.factories[a]]->Release();
|
||||
engine->scriptFunctions[beh.factories[a]]->ReleaseInternal();
|
||||
}
|
||||
beh.factories.SetLength(0);
|
||||
|
||||
@ -825,155 +791,74 @@ void asCObjectType::ReleaseAllFunctions()
|
||||
for( asUINT b = 0; b < beh.constructors.GetLength(); b++ )
|
||||
{
|
||||
if( engine->scriptFunctions[beh.constructors[b]] )
|
||||
engine->scriptFunctions[beh.constructors[b]]->Release();
|
||||
engine->scriptFunctions[beh.constructors[b]]->ReleaseInternal();
|
||||
}
|
||||
beh.constructors.SetLength(0);
|
||||
|
||||
if( beh.templateCallback )
|
||||
engine->scriptFunctions[beh.templateCallback]->Release();
|
||||
engine->scriptFunctions[beh.templateCallback]->ReleaseInternal();
|
||||
beh.templateCallback = 0;
|
||||
|
||||
if( beh.listFactory )
|
||||
engine->scriptFunctions[beh.listFactory]->Release();
|
||||
engine->scriptFunctions[beh.listFactory]->ReleaseInternal();
|
||||
beh.listFactory = 0;
|
||||
|
||||
if( beh.destruct )
|
||||
engine->scriptFunctions[beh.destruct]->Release();
|
||||
engine->scriptFunctions[beh.destruct]->ReleaseInternal();
|
||||
beh.destruct = 0;
|
||||
|
||||
if( beh.copy )
|
||||
engine->scriptFunctions[beh.copy]->Release();
|
||||
engine->scriptFunctions[beh.copy]->ReleaseInternal();
|
||||
beh.copy = 0;
|
||||
|
||||
for( asUINT e = 1; e < beh.operators.GetLength(); e += 2 )
|
||||
{
|
||||
if( engine->scriptFunctions[beh.operators[e]] )
|
||||
engine->scriptFunctions[beh.operators[e]]->Release();
|
||||
}
|
||||
beh.operators.SetLength(0);
|
||||
|
||||
for( asUINT c = 0; c < methods.GetLength(); c++ )
|
||||
{
|
||||
if( engine->scriptFunctions[methods[c]] )
|
||||
engine->scriptFunctions[methods[c]]->Release();
|
||||
engine->scriptFunctions[methods[c]]->ReleaseInternal();
|
||||
}
|
||||
methods.SetLength(0);
|
||||
|
||||
for( asUINT d = 0; d < virtualFunctionTable.GetLength(); d++ )
|
||||
{
|
||||
if( virtualFunctionTable[d] )
|
||||
virtualFunctionTable[d]->Release();
|
||||
virtualFunctionTable[d]->ReleaseInternal();
|
||||
}
|
||||
virtualFunctionTable.SetLength(0);
|
||||
|
||||
// GC behaviours
|
||||
if( beh.addref )
|
||||
engine->scriptFunctions[beh.addref]->Release();
|
||||
engine->scriptFunctions[beh.addref]->ReleaseInternal();
|
||||
beh.addref = 0;
|
||||
|
||||
if( beh.release )
|
||||
engine->scriptFunctions[beh.release]->Release();
|
||||
engine->scriptFunctions[beh.release]->ReleaseInternal();
|
||||
beh.release = 0;
|
||||
|
||||
if( beh.gcEnumReferences )
|
||||
engine->scriptFunctions[beh.gcEnumReferences]->Release();
|
||||
engine->scriptFunctions[beh.gcEnumReferences]->ReleaseInternal();
|
||||
beh.gcEnumReferences = 0;
|
||||
|
||||
if( beh.gcGetFlag )
|
||||
engine->scriptFunctions[beh.gcGetFlag]->Release();
|
||||
engine->scriptFunctions[beh.gcGetFlag]->ReleaseInternal();
|
||||
beh.gcGetFlag = 0;
|
||||
|
||||
if( beh.gcGetRefCount )
|
||||
engine->scriptFunctions[beh.gcGetRefCount]->Release();
|
||||
engine->scriptFunctions[beh.gcGetRefCount]->ReleaseInternal();
|
||||
beh.gcGetRefCount = 0;
|
||||
|
||||
if( beh.gcReleaseAllReferences )
|
||||
engine->scriptFunctions[beh.gcReleaseAllReferences]->Release();
|
||||
engine->scriptFunctions[beh.gcReleaseAllReferences]->ReleaseInternal();
|
||||
beh.gcReleaseAllReferences = 0;
|
||||
|
||||
if( beh.gcSetFlag )
|
||||
engine->scriptFunctions[beh.gcSetFlag]->Release();
|
||||
engine->scriptFunctions[beh.gcSetFlag]->ReleaseInternal();
|
||||
beh.gcSetFlag = 0;
|
||||
|
||||
if ( beh.getWeakRefFlag )
|
||||
engine->scriptFunctions[beh.getWeakRefFlag]->Release();
|
||||
engine->scriptFunctions[beh.getWeakRefFlag]->ReleaseInternal();
|
||||
beh.getWeakRefFlag = 0;
|
||||
}
|
||||
|
||||
// internal
|
||||
void asCObjectType::EnumReferences(asIScriptEngine *)
|
||||
{
|
||||
for( asUINT a = 0; a < beh.factories.GetLength(); a++ )
|
||||
if( engine->scriptFunctions[beh.factories[a]] )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.factories[a]]);
|
||||
|
||||
for( asUINT b = 0; b < beh.constructors.GetLength(); b++ )
|
||||
if( engine->scriptFunctions[beh.constructors[b]] )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.constructors[b]]);
|
||||
|
||||
if( beh.templateCallback )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.templateCallback]);
|
||||
|
||||
if( beh.listFactory )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.listFactory]);
|
||||
|
||||
if( beh.destruct )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.destruct]);
|
||||
|
||||
if( beh.addref )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.addref]);
|
||||
|
||||
if( beh.release )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.release]);
|
||||
|
||||
if( beh.copy )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.copy]);
|
||||
|
||||
if( beh.gcEnumReferences )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.gcEnumReferences]);
|
||||
|
||||
if( beh.gcGetFlag )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.gcGetFlag]);
|
||||
|
||||
if( beh.gcGetRefCount )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.gcGetRefCount]);
|
||||
|
||||
if( beh.gcReleaseAllReferences )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.gcReleaseAllReferences]);
|
||||
|
||||
if( beh.gcSetFlag )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.gcSetFlag]);
|
||||
|
||||
for( asUINT e = 1; e < beh.operators.GetLength(); e += 2 )
|
||||
if( engine->scriptFunctions[beh.operators[e]] )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.operators[e]]);
|
||||
|
||||
for( asUINT c = 0; c < methods.GetLength(); c++ )
|
||||
if( engine->scriptFunctions[methods[c]] )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[methods[c]]);
|
||||
|
||||
for( asUINT d = 0; d < virtualFunctionTable.GetLength(); d++ )
|
||||
if( virtualFunctionTable[d] )
|
||||
engine->GCEnumCallback(virtualFunctionTable[d]);
|
||||
|
||||
for( asUINT p = 0; p < properties.GetLength(); p++ )
|
||||
{
|
||||
asCObjectType *type = properties[p]->type.GetObjectType();
|
||||
if( type )
|
||||
engine->GCEnumCallback(type);
|
||||
}
|
||||
|
||||
for( asUINT t = 0; t < templateSubTypes.GetLength(); t++ )
|
||||
if( templateSubTypes[t].GetObjectType() )
|
||||
engine->GCEnumCallback(templateSubTypes[t].GetObjectType());
|
||||
|
||||
if( beh.getWeakRefFlag )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[beh.getWeakRefFlag]);
|
||||
|
||||
if( derivedFrom )
|
||||
engine->GCEnumCallback(derivedFrom);
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -51,28 +51,6 @@ BEGIN_AS_NAMESPACE
|
||||
|
||||
// TODO: memory: Need to minimize used memory here, because not all types use all properties of the class
|
||||
|
||||
// TODO: The type id should have flags for differenciating between value types and reference types. It should also have a flag for differenciating interface types.
|
||||
|
||||
// Additional flag to the class object type
|
||||
const asDWORD asOBJ_IMPLICIT_HANDLE = 0x00400000;
|
||||
const asDWORD asOBJ_LIST_PATTERN = 0x08000000;
|
||||
const asDWORD asOBJ_ENUM = 0x10000000;
|
||||
const asDWORD asOBJ_TEMPLATE_SUBTYPE = 0x20000000;
|
||||
const asDWORD asOBJ_TYPEDEF = 0x40000000;
|
||||
|
||||
|
||||
|
||||
// asOBJ_GC is used to indicate that the type can potentially
|
||||
// form circular references, thus is garbage collected.
|
||||
|
||||
// The fact that an object is garbage collected doesn't imply that an other object
|
||||
// that can reference it also must be garbage collected, only if the garbage collected
|
||||
// object can reference the other object as well.
|
||||
|
||||
// For registered types however, we set the flag asOBJ_GC if the GC
|
||||
// behaviours are registered. For script types that contain any such type we
|
||||
// automatically make garbage collected as well, because we cannot know what type
|
||||
// of references that object can contain, and must assume the worst.
|
||||
|
||||
struct asSTypeBehaviour
|
||||
{
|
||||
@ -119,7 +97,6 @@ struct asSTypeBehaviour
|
||||
|
||||
asCArray<int> factories;
|
||||
asCArray<int> constructors;
|
||||
asCArray<int> operators;
|
||||
};
|
||||
|
||||
struct asSEnumValue
|
||||
@ -131,8 +108,6 @@ struct asSEnumValue
|
||||
class asCScriptEngine;
|
||||
struct asSNameSpace;
|
||||
|
||||
void RegisterObjectTypeGCBehaviours(asCScriptEngine *engine);
|
||||
|
||||
class asCObjectType : public asIObjectType
|
||||
{
|
||||
public:
|
||||
@ -178,7 +153,7 @@ public:
|
||||
|
||||
// Properties
|
||||
asUINT GetPropertyCount() const;
|
||||
int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, int *offset, bool *isReference, asDWORD *accessMask) const;
|
||||
int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask) const;
|
||||
const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const;
|
||||
|
||||
// Behaviours
|
||||
@ -195,25 +170,27 @@ public:
|
||||
public:
|
||||
asCObjectType(asCScriptEngine *engine);
|
||||
~asCObjectType();
|
||||
void DestroyInternal();
|
||||
|
||||
void Orphan(asCModule *module);
|
||||
int GetRefCount();
|
||||
void SetGCFlag();
|
||||
bool GetGCFlag();
|
||||
void EnumReferences(asIScriptEngine *);
|
||||
void ReleaseAllHandles(asIScriptEngine *);
|
||||
// Keep an internal reference counter to separate references coming from
|
||||
// application or script objects and references coming from the script code
|
||||
int AddRefInternal();
|
||||
int ReleaseInternal();
|
||||
|
||||
void ReleaseAllFunctions();
|
||||
|
||||
bool IsInterface() const;
|
||||
bool IsShared() const;
|
||||
|
||||
asCObjectProperty *AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate);
|
||||
asCObjectProperty *AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited);
|
||||
void ReleaseAllProperties();
|
||||
|
||||
asCString name;
|
||||
asSNameSpace *nameSpace;
|
||||
int size;
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
int alignment;
|
||||
#endif
|
||||
asCArray<asCObjectProperty*> properties;
|
||||
asCArray<int> methods;
|
||||
asCArray<asCObjectType*> interfaces;
|
||||
@ -232,16 +209,23 @@ public:
|
||||
bool acceptValueSubType;
|
||||
bool acceptRefSubType;
|
||||
|
||||
// Store the script section where the code was declared
|
||||
int scriptSectionIdx;
|
||||
// Store the location where the function was declared (row in the lower 20 bits, and column in the upper 12)
|
||||
int declaredAt;
|
||||
|
||||
asCScriptEngine *engine;
|
||||
asCModule *module;
|
||||
asCArray<asPWORD> userData;
|
||||
|
||||
protected:
|
||||
friend class asCScriptEngine;
|
||||
friend class asCConfigGroup;
|
||||
friend class asCModule;
|
||||
asCObjectType();
|
||||
|
||||
mutable asCAtomic refCount;
|
||||
mutable bool gcFlag;
|
||||
mutable asCAtomic externalRefCount;
|
||||
asCAtomic internalRefCount;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -76,6 +76,7 @@ protected:
|
||||
void RewindTo(const sToken *token);
|
||||
void SetPos(size_t pos);
|
||||
void Error(const asCString &text, sToken *token);
|
||||
void Warning(const asCString &text, sToken *token);
|
||||
void Info(const asCString &text, sToken *token);
|
||||
|
||||
asCScriptNode *CreateNode(eScriptNode type);
|
||||
@ -83,11 +84,11 @@ protected:
|
||||
asCScriptNode *ParseFunctionDefinition();
|
||||
asCScriptNode *ParseParameterList();
|
||||
asCScriptNode *SuperficiallyParseExpression();
|
||||
asCScriptNode *ParseType(bool allowConst, bool allowVariableType = false);
|
||||
asCScriptNode *ParseType(bool allowConst, bool allowVariableType = false, bool allowAuto = false);
|
||||
asCScriptNode *ParseTypeMod(bool isParam);
|
||||
void ParseOptionalScope(asCScriptNode *node);
|
||||
asCScriptNode *ParseRealType();
|
||||
asCScriptNode *ParseDataType(bool allowVariableType = false);
|
||||
asCScriptNode *ParseDataType(bool allowVariableType = false, bool allowAuto = false);
|
||||
asCScriptNode *ParseIdentifier();
|
||||
|
||||
asCScriptNode *ParseListPattern();
|
||||
@ -143,7 +144,7 @@ protected:
|
||||
asCScriptNode *ParseExprPreOp();
|
||||
asCScriptNode *ParseExprPostOp();
|
||||
asCScriptNode *ParseExprValue();
|
||||
asCScriptNode *ParseArgList();
|
||||
asCScriptNode *ParseArgList(bool withParenthesis = true);
|
||||
asCScriptNode *ParseFunctionCall();
|
||||
asCScriptNode *ParseVariableAccess();
|
||||
asCScriptNode *ParseConstructCall();
|
||||
@ -168,6 +169,7 @@ protected:
|
||||
asCString ExpectedTokens(const char *token1, const char *token2);
|
||||
asCString ExpectedOneOf(int *tokens, int count);
|
||||
asCString ExpectedOneOf(const char **tokens, int count);
|
||||
asCString InsteadFound(sToken &t);
|
||||
|
||||
bool errorWhileParsing;
|
||||
bool isSyntaxError;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -54,11 +54,14 @@ class asCObjectProperty
|
||||
{
|
||||
public:
|
||||
asCObjectProperty() {accessMask = 0xFFFFFFFF;}
|
||||
asCObjectProperty(const asCObjectProperty &o) : name(o.name), type(o.type), byteOffset(o.byteOffset), accessMask(o.accessMask), isPrivate(o.isPrivate), isProtected(o.isProtected), isInherited(o.isInherited) {}
|
||||
asCString name;
|
||||
asCDataType type;
|
||||
int byteOffset;
|
||||
bool isPrivate;
|
||||
asDWORD accessMask;
|
||||
bool isPrivate;
|
||||
bool isProtected;
|
||||
bool isInherited;
|
||||
};
|
||||
|
||||
class asCGlobalProperty
|
||||
@ -69,7 +72,7 @@ public:
|
||||
|
||||
void AddRef();
|
||||
void Release();
|
||||
int GetRefCount();
|
||||
void DestroyInternal();
|
||||
|
||||
void *GetAddressOfValue();
|
||||
void AllocateMemory();
|
||||
@ -84,16 +87,7 @@ public:
|
||||
void SetInitFunc(asCScriptFunction *initFunc);
|
||||
asCScriptFunction *GetInitFunc();
|
||||
|
||||
static void RegisterGCBehaviours(asCScriptEngine *engine);
|
||||
|
||||
//protected:
|
||||
void SetGCFlag();
|
||||
bool GetGCFlag();
|
||||
void EnumReferences(asIScriptEngine *);
|
||||
void ReleaseAllHandles(asIScriptEngine *);
|
||||
|
||||
void Orphan(asCModule *module);
|
||||
|
||||
// This is only stored for registered properties, and keeps the pointer given by the application
|
||||
void *realAddress;
|
||||
|
||||
@ -108,7 +102,6 @@ public:
|
||||
// The global property structure is reference counted, so that the
|
||||
// engine can keep track of how many references to the property there are.
|
||||
asCAtomic refCount;
|
||||
bool gcFlag;
|
||||
};
|
||||
|
||||
class asCCompGlobPropType : public asIFilter
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -124,9 +124,9 @@ protected:
|
||||
// Helper class for adjusting offsets within initialization list buffers
|
||||
struct SListAdjuster
|
||||
{
|
||||
SListAdjuster(asDWORD *bc, asCObjectType *ot);
|
||||
SListAdjuster(asCReader *rd, asDWORD *bc, asCObjectType *ot);
|
||||
void AdjustAllocMem();
|
||||
int AdjustOffset(int offset, asCObjectType *listPatternType);
|
||||
int AdjustOffset(int offset);
|
||||
void SetRepeatCount(asUINT rc);
|
||||
void SetNextType(int typeId);
|
||||
|
||||
@ -137,11 +137,13 @@ protected:
|
||||
};
|
||||
asCArray<SInfo> stack;
|
||||
|
||||
asCReader *reader;
|
||||
asDWORD *allocMemBC;
|
||||
asUINT maxOffset;
|
||||
asCObjectType *patternType;
|
||||
asUINT repeatCount;
|
||||
int lastOffset;
|
||||
int nextOffset;
|
||||
asUINT lastAdjustedOffset;
|
||||
asSListPatternNode *patternNode;
|
||||
int nextTypeId;
|
||||
@ -239,7 +241,8 @@ protected:
|
||||
asUINT repeatCount;
|
||||
asSListPatternNode *patternNode;
|
||||
asUINT entries;
|
||||
int lastOffset;
|
||||
int lastOffset; // Last offset adjusted
|
||||
int nextOffset; // next expected offset to be adjusted
|
||||
int nextTypeId;
|
||||
};
|
||||
asCArray<SListAdjuster*> listAdjusters;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -70,6 +70,7 @@ public:
|
||||
// Memory management
|
||||
virtual int AddRef() const;
|
||||
virtual int Release() const;
|
||||
virtual int ShutDownAndRelease();
|
||||
|
||||
// Engine properties
|
||||
virtual int SetEngineProperty(asEEngineProp property, asPWORD value);
|
||||
@ -100,17 +101,18 @@ public:
|
||||
// Type registration
|
||||
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags);
|
||||
virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset);
|
||||
virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv);
|
||||
virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0);
|
||||
virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0);
|
||||
virtual int RegisterInterface(const char *name);
|
||||
virtual int RegisterInterfaceMethod(const char *intf, const char *declaration);
|
||||
virtual asUINT GetObjectTypeCount() const;
|
||||
virtual asIObjectType *GetObjectTypeByIndex(asUINT index) const;
|
||||
virtual asIObjectType *GetObjectTypeByName(const char *name) const;
|
||||
virtual asIObjectType *GetObjectTypeByDecl(const char *decl) const;
|
||||
|
||||
// String factory
|
||||
virtual int RegisterStringFactory(const char *datatype, const asSFuncPtr &factoryFunc, asDWORD callConv, void *objForThiscall = 0);
|
||||
virtual int GetStringFactoryReturnTypeId() const;
|
||||
virtual int GetStringFactoryReturnTypeId(asDWORD *flags) const;
|
||||
|
||||
// Default array type
|
||||
virtual int RegisterDefaultArrayType(const char *type);
|
||||
@ -160,48 +162,45 @@ public:
|
||||
virtual int GetSizeOfPrimitiveType(int typeId) const;
|
||||
|
||||
// Script execution
|
||||
virtual asIScriptContext *CreateContext();
|
||||
virtual asIScriptContext *CreateContext();
|
||||
virtual void *CreateScriptObject(const asIObjectType *type);
|
||||
virtual void *CreateScriptObjectCopy(void *obj, const asIObjectType *type);
|
||||
virtual void *CreateUninitializedScriptObject(const asIObjectType *type);
|
||||
virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj);
|
||||
virtual int AssignScriptObject(void *dstObj, void *srcObj, const asIObjectType *type);
|
||||
virtual void ReleaseScriptObject(void *obj, const asIObjectType *type);
|
||||
virtual void AddRefScriptObject(void *obj, const asIObjectType *type);
|
||||
virtual int RefCastObject(void *obj, asIObjectType *fromType, asIObjectType *toType, void **newPtr, bool useOnlyImplicitCast = false);
|
||||
#ifdef AS_DEPRECATED
|
||||
// Deprecated since 2.27.0, 2013-07-18
|
||||
virtual void *CreateScriptObject(int typeId);
|
||||
virtual void *CreateScriptObjectCopy(void *obj, int typeId);
|
||||
virtual void *CreateUninitializedScriptObject(int typeId);
|
||||
virtual void AssignScriptObject(void *dstObj, void *srcObj, int typeId);
|
||||
virtual void ReleaseScriptObject(void *obj, int typeId);
|
||||
virtual void AddRefScriptObject(void *obj, int typeId);
|
||||
// Deprecated since 2.30.0, 2014-11-04
|
||||
virtual bool IsHandleCompatibleWithObject(void *obj, int objTypeId, int handleTypeId) const;
|
||||
#endif
|
||||
virtual void *CreateScriptObject(const asIObjectType *type);
|
||||
virtual void *CreateScriptObjectCopy(void *obj, const asIObjectType *type);
|
||||
virtual void *CreateUninitializedScriptObject(const asIObjectType *type);
|
||||
virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj);
|
||||
virtual void AssignScriptObject(void *dstObj, void *srcObj, const asIObjectType *type);
|
||||
virtual void ReleaseScriptObject(void *obj, const asIObjectType *type);
|
||||
virtual void AddRefScriptObject(void *obj, const asIObjectType *type);
|
||||
// TODO: interface: Should have a method void *CastObject(void *obj, asIObjectType *fromType, asIObjectType *toType);
|
||||
// For script objects it should simply check if the object implements or derives from the toType
|
||||
// For application objects it should look for ref cast behaviours and call the matching one
|
||||
// Once implemented the IsHandleCompatibleWithObject should be removed from the engine
|
||||
virtual bool IsHandleCompatibleWithObject(void *obj, int objTypeId, int handleTypeId) const;
|
||||
asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asIObjectType *type) const;
|
||||
virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asIObjectType *type) const;
|
||||
|
||||
// Context pooling
|
||||
virtual asIScriptContext *RequestContext();
|
||||
virtual void ReturnContext(asIScriptContext *ctx);
|
||||
virtual int SetContextCallbacks(asREQUESTCONTEXTFUNC_t requestCtx, asRETURNCONTEXTFUNC_t returnCtx, void *param = 0);
|
||||
|
||||
// String interpretation
|
||||
virtual asETokenClass ParseToken(const char *string, size_t stringLength = 0, int *tokenLength = 0) const;
|
||||
virtual asETokenClass ParseToken(const char *string, size_t stringLength = 0, asUINT *tokenLength = 0) const;
|
||||
|
||||
// Garbage collection
|
||||
virtual int GarbageCollect(asDWORD flags = asGC_FULL_CYCLE);
|
||||
virtual int GarbageCollect(asDWORD flags = asGC_FULL_CYCLE, asUINT numIterations = 1);
|
||||
virtual void GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const;
|
||||
virtual int NotifyGarbageCollectorOfNewObject(void *obj, asIObjectType *type);
|
||||
virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj = 0, asIObjectType **type = 0);
|
||||
virtual void GCEnumCallback(void *reference);
|
||||
|
||||
// User data
|
||||
virtual void *SetUserData(void *data, asPWORD type = 0);
|
||||
virtual void *GetUserData(asPWORD type = 0) const;
|
||||
virtual void SetEngineUserDataCleanupCallback(asCLEANENGINEFUNC_t callback, asPWORD type = 0);
|
||||
virtual void SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback);
|
||||
virtual void SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback);
|
||||
virtual void SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback);
|
||||
virtual void *SetUserData(void *data, asPWORD type);
|
||||
virtual void *GetUserData(asPWORD type) const;
|
||||
virtual void SetEngineUserDataCleanupCallback(asCLEANENGINEFUNC_t callback, asPWORD type);
|
||||
virtual void SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback, asPWORD type);
|
||||
virtual void SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback, asPWORD type);
|
||||
virtual void SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback, asPWORD type);
|
||||
virtual void SetObjectTypeUserDataCleanupCallback(asCLEANOBJECTTYPEFUNC_t callback, asPWORD type);
|
||||
virtual void SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type);
|
||||
|
||||
//===========================================================
|
||||
// internal methods
|
||||
@ -220,12 +219,12 @@ public:
|
||||
friend class asCByteCode;
|
||||
friend int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine);
|
||||
|
||||
int RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv);
|
||||
int RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall = 0);
|
||||
int RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *objForThiscall);
|
||||
|
||||
int VerifyVarTypeNotInFunction(asCScriptFunction *func);
|
||||
|
||||
void *CallAlloc(asCObjectType *objType) const;
|
||||
void *CallAlloc(const asCObjectType *objType) const;
|
||||
void CallFree(void *obj) const;
|
||||
|
||||
void *CallGlobalFunctionRetPtr(int func) const;
|
||||
@ -244,11 +243,10 @@ public:
|
||||
|
||||
void ConstructScriptObjectCopy(void *mem, void *obj, asCObjectType *type);
|
||||
|
||||
void CleanupAfterDiscardModule();
|
||||
void DeleteDiscardedModules();
|
||||
|
||||
int ClearUnusedTypes();
|
||||
void RemoveTemplateInstanceType(asCObjectType *t);
|
||||
void RemoveTypeAndRelatedFromList(asCArray<asCObjectType*> &types, asCObjectType *ot);
|
||||
void RemoveTypeAndRelatedFromList(asCMap<asCObjectType*,char> &types, asCObjectType *ot);
|
||||
|
||||
asCConfigGroup *FindConfigGroupForFunction(int funcId) const;
|
||||
asCConfigGroup *FindConfigGroupForGlobalVar(int gvarId) const;
|
||||
@ -282,8 +280,9 @@ public:
|
||||
int GetFactoryIdByDecl(const asCObjectType *ot, const char *decl);
|
||||
|
||||
int GetNextScriptFunctionId();
|
||||
void SetScriptFunction(asCScriptFunction *func);
|
||||
void FreeScriptFunctionId(int id);
|
||||
void AddScriptFunction(asCScriptFunction *func);
|
||||
void RemoveScriptFunction(asCScriptFunction *func);
|
||||
void RemoveFuncdef(asCScriptFunction *func);
|
||||
|
||||
int ConfigError(int err, const char *funcName, const char *arg1, const char *arg2);
|
||||
|
||||
@ -293,11 +292,14 @@ public:
|
||||
void RemoveFromTypeIdMap(asCObjectType *type);
|
||||
|
||||
bool IsTemplateType(const char *name) const;
|
||||
asCObjectType *GetTemplateInstanceType(asCObjectType *templateType, asCArray<asCDataType> &subTypes);
|
||||
asCObjectType *GetTemplateInstanceType(asCObjectType *templateType, asCArray<asCDataType> &subTypes, asCModule *requestingModule);
|
||||
asCScriptFunction *GenerateTemplateFactoryStub(asCObjectType *templateType, asCObjectType *templateInstanceType, int origFactoryId);
|
||||
bool GenerateNewTemplateFunction(asCObjectType *templateType, asCObjectType *templateInstanceType, asCScriptFunction *templateFunc, asCScriptFunction **newFunc);
|
||||
void OrphanTemplateInstances(asCObjectType *subType);
|
||||
asCDataType DetermineTypeForTemplate(const asCDataType &orig, asCObjectType *tmpl, asCObjectType *ot);
|
||||
bool RequireTypeReplacement(asCDataType &type, asCObjectType *templateType);
|
||||
|
||||
asCModule *FindNewOwnerForSharedType(asCObjectType *type, asCModule *mod);
|
||||
asCModule *FindNewOwnerForSharedFunc(asCScriptFunction *func, asCModule *mod);
|
||||
|
||||
// String constants
|
||||
// TODO: Must free unused string constants, thus the ref count for each must be tracked
|
||||
@ -306,13 +308,14 @@ public:
|
||||
|
||||
// Global property management
|
||||
asCGlobalProperty *AllocateGlobalProperty();
|
||||
void FreeUnusedGlobalProperties();
|
||||
void RemoveGlobalProperty(asCGlobalProperty *prop);
|
||||
|
||||
int GetScriptSectionNameIndex(const char *name);
|
||||
|
||||
// Namespace management
|
||||
asSNameSpace *AddNameSpace(const char *name);
|
||||
asSNameSpace *FindNameSpace(const char *name);
|
||||
asSNameSpace *FindNameSpace(const char *name) const;
|
||||
asSNameSpace *GetParentNameSpace(asSNameSpace *ns) const;
|
||||
|
||||
//===========================================================
|
||||
// internal properties
|
||||
@ -324,14 +327,12 @@ public:
|
||||
asCObjectType *defaultArrayObjectType;
|
||||
asCObjectType scriptTypeBehaviours;
|
||||
asCObjectType functionBehaviours;
|
||||
asCObjectType objectTypeBehaviours;
|
||||
asCObjectType globalPropertyBehaviours;
|
||||
|
||||
// Registered interface
|
||||
asCArray<asCObjectType *> registeredObjTypes;
|
||||
asCArray<asCObjectType *> registeredTypeDefs;
|
||||
asCArray<asCObjectType *> registeredEnums;
|
||||
asCSymbolTable<asCGlobalProperty> registeredGlobalProps; // TODO: memory savings: Since there can be only one property with the same name a simpler symbol table should be used
|
||||
asCSymbolTable<asCGlobalProperty> registeredGlobalProps; // increases ref count // TODO: memory savings: Since there can be only one property with the same name a simpler symbol table should be used
|
||||
asCSymbolTable<asCScriptFunction> registeredGlobalFuncs;
|
||||
asCArray<asCScriptFunction *> registeredFuncDefs;
|
||||
asCArray<asCObjectType *> registeredTemplateTypes;
|
||||
@ -339,54 +340,69 @@ public:
|
||||
bool configFailed;
|
||||
|
||||
// Stores all registered types except funcdefs
|
||||
asCMap<asSNameSpaceNamePair, asCObjectType*> allRegisteredTypes;
|
||||
asCMap<asSNameSpaceNamePair, asCObjectType*> allRegisteredTypes; // increases ref count
|
||||
|
||||
// Dummy types used to name the subtypes in the template objects
|
||||
asCArray<asCObjectType *> templateSubTypes;
|
||||
|
||||
// Store information about template types
|
||||
// This list will contain all instances of templates, both registered specialized
|
||||
// types and those automacially instanciated from scripts
|
||||
asCArray<asCObjectType *> templateInstanceTypes;
|
||||
// types and those automacially instantiated from scripts
|
||||
asCArray<asCObjectType *> templateInstanceTypes; // increases ref count
|
||||
|
||||
// Store information about list patterns
|
||||
asCArray<asCObjectType *> listPatternTypes;
|
||||
asCArray<asCObjectType *> listPatternTypes; // increases ref count
|
||||
|
||||
// Stores all global properties, both those registered by application, and those declared by scripts.
|
||||
// The id of a global property is the index in this array.
|
||||
asCArray<asCGlobalProperty *> globalProperties;
|
||||
asCArray<asCGlobalProperty *> globalProperties; // increases ref count
|
||||
asCArray<int> freeGlobalPropertyIds;
|
||||
|
||||
// This map is used to quickly find a property by its memory address
|
||||
// It is used principally during building, cleanup, and garbage detection for script functions
|
||||
asCMap<void*, asCGlobalProperty*> varAddressMap;
|
||||
|
||||
asCArray<int> freeGlobalPropertyIds;
|
||||
asCMap<void*, asCGlobalProperty*> varAddressMap; // doesn't increase ref count
|
||||
|
||||
// Stores all functions, i.e. registered functions, script functions, class methods, behaviours, etc.
|
||||
asCArray<asCScriptFunction *> scriptFunctions;
|
||||
asCArray<asCScriptFunction *> scriptFunctions; // doesn't increase ref count
|
||||
asCArray<int> freeScriptFunctionIds;
|
||||
asCArray<asCScriptFunction *> signatureIds;
|
||||
|
||||
// An array with all module imported functions
|
||||
asCArray<sBindInfo *> importedFunctions;
|
||||
asCArray<sBindInfo *> importedFunctions; // doesn't increase ref count
|
||||
asCArray<int> freeImportedFunctionIdxs;
|
||||
|
||||
// These resources must be protected for multiple accesses
|
||||
// Synchronized
|
||||
mutable asCAtomic refCount;
|
||||
// Synchronized with engineRWLock
|
||||
// This array holds all live script modules
|
||||
asCArray<asCModule *> scriptModules;
|
||||
// Synchronized with engineRWLock
|
||||
// This is a pointer to the last module that was requested. It is used for performance
|
||||
// improvement, since it is common that the same module is accessed many times in a row
|
||||
asCModule *lastModule;
|
||||
// Synchronized with engineRWLock
|
||||
// This flag is true if a script is currently being compiled. It is used to prevent multiple
|
||||
// threads from requesting builds at the same time (without blocking)
|
||||
bool isBuilding;
|
||||
// Synchronized with engineRWLock
|
||||
// This array holds modules that have been discard (thus are no longer visible to the application)
|
||||
// but cannot yet be deleted due to having external references to some of the entities in them
|
||||
asCArray<asCModule *> discardedModules;
|
||||
// This flag is set to true during compilations of scripts (or loading pre-compiled scripts)
|
||||
// to delay the validation of template types until the subtypes have been fully declared
|
||||
bool deferValidationOfTemplateTypes;
|
||||
|
||||
// Tokenizer is instanciated once to share resources
|
||||
// Tokenizer is instantiated once to share resources
|
||||
asCTokenizer tok;
|
||||
|
||||
// Stores script declared object types
|
||||
asCArray<asCObjectType *> classTypes;
|
||||
// Stores shared script declared types (classes, interfaces, enums)
|
||||
asCArray<asCObjectType *> sharedScriptTypes; // increases ref count
|
||||
// This array stores the template instances types that have been automatically generated from template types
|
||||
asCArray<asCObjectType *> generatedTemplateTypes;
|
||||
// Stores the funcdefs
|
||||
asCArray<asCScriptFunction *> funcDefs;
|
||||
// TODO: 2.30.0: redesign: Only shared funcdefs should be stored here
|
||||
// a funcdef becomes shared if all arguments and the return type are shared (or application registered)
|
||||
asCArray<asCScriptFunction *> funcDefs; // doesn't increase ref count
|
||||
|
||||
// Stores the names of the script sections for debugging purposes
|
||||
asCArray<asCString *> scriptSectionNames;
|
||||
@ -409,7 +425,17 @@ public:
|
||||
bool msgCallback;
|
||||
asSSystemFunctionInterface msgCallbackFunc;
|
||||
void *msgCallbackObj;
|
||||
struct preMessage_t
|
||||
{
|
||||
preMessage_t() { isSet = false; }
|
||||
bool isSet;
|
||||
asCString message;
|
||||
asCString scriptname;
|
||||
int r;
|
||||
int c;
|
||||
} preMessage;
|
||||
|
||||
// JIt compilation
|
||||
asIJITCompiler *jitCompiler;
|
||||
|
||||
// Namespaces
|
||||
@ -423,16 +449,26 @@ public:
|
||||
asCArray<asCString*> stringConstants;
|
||||
asCMap<asCStringPointer, int> stringToIdMap;
|
||||
|
||||
// Callbacks for context pooling
|
||||
asREQUESTCONTEXTFUNC_t requestCtxFunc;
|
||||
asRETURNCONTEXTFUNC_t returnCtxFunc;
|
||||
void *ctxCallbackParam;
|
||||
|
||||
// User data
|
||||
asCArray<asPWORD> userData;
|
||||
|
||||
struct SEngineClean { asPWORD type; asCLEANENGINEFUNC_t cleanFunc; };
|
||||
asCArray<SEngineClean> cleanEngineFuncs;
|
||||
asCLEANMODULEFUNC_t cleanModuleFunc;
|
||||
asCLEANCONTEXTFUNC_t cleanContextFunc;
|
||||
asCLEANFUNCTIONFUNC_t cleanFunctionFunc;
|
||||
struct SObjTypeClean { asPWORD type; asCLEANOBJECTTYPEFUNC_t cleanFunc; };
|
||||
asCArray<SObjTypeClean> cleanObjectTypeFuncs;
|
||||
struct SEngineClean { asPWORD type; asCLEANENGINEFUNC_t cleanFunc; };
|
||||
asCArray<SEngineClean> cleanEngineFuncs;
|
||||
struct SModuleClean { asPWORD type; asCLEANMODULEFUNC_t cleanFunc; };
|
||||
asCArray<SModuleClean> cleanModuleFuncs;
|
||||
struct SContextClean { asPWORD type; asCLEANCONTEXTFUNC_t cleanFunc; };
|
||||
asCArray<SContextClean> cleanContextFuncs;
|
||||
struct SFunctionClean { asPWORD type; asCLEANFUNCTIONFUNC_t cleanFunc; };
|
||||
asCArray<SFunctionClean> cleanFunctionFuncs;
|
||||
struct SObjTypeClean { asPWORD type; asCLEANOBJECTTYPEFUNC_t cleanFunc; };
|
||||
asCArray<SObjTypeClean> cleanObjectTypeFuncs;
|
||||
struct SScriptObjClean { asPWORD type; asCLEANSCRIPTOBJECTFUNC_t cleanFunc; };
|
||||
asCArray<SScriptObjClean> cleanScriptObjectFuncs;
|
||||
|
||||
// Synchronization for threads
|
||||
DECLAREREADWRITELOCK(mutable engineRWLock)
|
||||
@ -460,10 +496,21 @@ public:
|
||||
bool alwaysImplDefaultConstruct;
|
||||
int compilerWarnings;
|
||||
bool disallowValueAssignForRefType;
|
||||
// TODO: 3.0.0: Remove the alterSyntaxNamedArgs
|
||||
int alterSyntaxNamedArgs;
|
||||
bool disableIntegerDivision;
|
||||
bool disallowEmptyListElements;
|
||||
// TODO: 3.0.0: Remove the privatePropAsProtected
|
||||
bool privatePropAsProtected;
|
||||
} ep;
|
||||
|
||||
// This flag is to allow a quicker shutdown when releasing the engine
|
||||
bool shuttingDown;
|
||||
|
||||
// This flag is set when the engine's destructor is called, this is to
|
||||
// avoid recursive calls if an object happens to increment/decrement
|
||||
// the ref counter during shutdown
|
||||
bool inDestructor;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -105,6 +105,15 @@ static void ScriptFunction_CreateDelegate_Generic(asIScriptGeneric *gen)
|
||||
gen->SetReturnAddress(CreateDelegate(func, obj));
|
||||
}
|
||||
|
||||
// TODO: 2.29.0: operator==
|
||||
/*static void ScriptFunction_opEquals_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCScriptFunction *funcSelf = (asCScriptFunction*)gen->GetObject();
|
||||
asCScriptFunction *funcOther = (asCScriptFunction*)gen->GetArgAddress(0);
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = *funcSelf == *funcOther;
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -124,6 +133,8 @@ void RegisterScriptFunction(asCScriptEngine *engine)
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCScriptFunction,GetFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCScriptFunction,EnumReferences), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCScriptFunction,ReleaseAllHandles), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
// TODO: 2.29.0: Need some way to allow the arg type to adapt when the funcdefs are instantiated
|
||||
// r = engine->RegisterMethodToObjectType(&engine->functionBehaviours, "bool opEquals(const int &in)", asMETHOD(asCScriptFunction,operator==), asCALL_THISCALL); asASSERT( r >= 0 );
|
||||
#else
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptFunction_AddRef_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptFunction_Release_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
@ -132,6 +143,7 @@ void RegisterScriptFunction(asCScriptEngine *engine)
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptFunction_GetFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptFunction_EnumReferences_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptFunction_ReleaseAllHandles_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
|
||||
// r = engine->RegisterMethodToObjectType(&engine->functionBehaviours, "bool opEquals(const int &in)", asFUNCTION(ScriptFunction_opEquals_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
||||
#endif
|
||||
|
||||
// Register the builtin function for creating delegates
|
||||
@ -214,6 +226,24 @@ asIScriptFunction *asCScriptFunction::GetDelegateFunction() const
|
||||
return funcForDelegate;
|
||||
}
|
||||
|
||||
// TODO: 2.29.0: operator==
|
||||
/*
|
||||
// internal
|
||||
bool asCScriptFunction::operator==(const asCScriptFunction &other) const
|
||||
{
|
||||
if( this == &other ) return true;
|
||||
|
||||
if( this->funcType == asFUNC_DELEGATE && other.funcType == asFUNC_DELEGATE )
|
||||
{
|
||||
if( this->objForDelegate == other.objForDelegate &&
|
||||
this->funcForDelegate == other.funcForDelegate )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
// internal
|
||||
int asCScriptFunction::RegisterListPattern(const char *decl, asCScriptNode *listNodes)
|
||||
{
|
||||
@ -243,8 +273,23 @@ int asCScriptFunction::ParseListPattern(asSListPatternNode *&target, const char
|
||||
{
|
||||
if( listNodes->nodeType == snIdentifier )
|
||||
{
|
||||
node->next = asNEW(asSListPatternNode)(asLPT_REPEAT);
|
||||
node = node->next;
|
||||
asCString token(&decl[listNodes->tokenPos], listNodes->tokenLength);
|
||||
if( token == "repeat" )
|
||||
{
|
||||
node->next = asNEW(asSListPatternNode)(asLPT_REPEAT);
|
||||
node = node->next;
|
||||
}
|
||||
else if( token == "repeat_same" )
|
||||
{
|
||||
// TODO: list: Should make sure this is a sub-list
|
||||
node->next = asNEW(asSListPatternNode)(asLPT_REPEAT_SAME);
|
||||
node = node->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shouldn't happen as the parser already reported the error
|
||||
asASSERT(false);
|
||||
}
|
||||
}
|
||||
else if( listNodes->nodeType == snDataType )
|
||||
{
|
||||
@ -287,15 +332,27 @@ int asCScriptFunction::ParseListPattern(asSListPatternNode *&target, const char
|
||||
// internal
|
||||
asCScriptFunction::asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType _funcType)
|
||||
{
|
||||
refCount.set(1);
|
||||
funcType = _funcType;
|
||||
if( funcType == asFUNC_DELEGATE )
|
||||
{
|
||||
// Delegates behave like object instances, rather than script code
|
||||
externalRefCount.set(1);
|
||||
internalRefCount.set(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
internalRefCount.set(1);
|
||||
externalRefCount.set(0);
|
||||
}
|
||||
|
||||
this->engine = engine;
|
||||
this->scriptData = 0;
|
||||
funcType = _funcType;
|
||||
module = mod;
|
||||
objectType = 0;
|
||||
name = "";
|
||||
isReadOnly = false;
|
||||
isPrivate = false;
|
||||
isProtected = false;
|
||||
isFinal = false;
|
||||
isOverride = false;
|
||||
sysFuncIntf = 0;
|
||||
@ -315,8 +372,8 @@ asCScriptFunction::asCScriptFunction(asCScriptEngine *engine, asCModule *mod, as
|
||||
if( funcType == asFUNC_SCRIPT )
|
||||
AllocateScriptFunctionData();
|
||||
|
||||
// Notify the GC of script functions
|
||||
if( (funcType == asFUNC_SCRIPT && mod == 0) || (funcType == asFUNC_DELEGATE) )
|
||||
// Notify the GC of delegates
|
||||
if( funcType == asFUNC_DELEGATE )
|
||||
engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours);
|
||||
}
|
||||
|
||||
@ -348,35 +405,58 @@ void asCScriptFunction::DeallocateScriptFunctionData()
|
||||
// internal
|
||||
asCScriptFunction::~asCScriptFunction()
|
||||
{
|
||||
// Imported functions are not reference counted, nor are dummy
|
||||
// functions that are allocated on the stack
|
||||
// Dummy functions that are allocated on the stack are not reference counted
|
||||
asASSERT( funcType == asFUNC_DUMMY ||
|
||||
funcType == asFUNC_IMPORTED ||
|
||||
refCount.get() == 0 );
|
||||
(externalRefCount.get() == 0 && internalRefCount.get() == 0) );
|
||||
|
||||
// Remove the script function from the engine's scriptFunctions array here
|
||||
// Don't remove it before, because there may still be functions referring to it
|
||||
// by index until now. If it was removed in DestroyInternal, those would not
|
||||
// be able to release the refcount, thus causing memory leak.
|
||||
if( engine && id != 0 && funcType != asFUNC_DUMMY )
|
||||
engine->RemoveScriptFunction(this);
|
||||
|
||||
// If the engine pointer is 0, then DestroyInternal has already been called and there is nothing more to do
|
||||
if( engine == 0 ) return;
|
||||
|
||||
// TODO: 2.30.0: redesign: Shouldn't this have been done already?
|
||||
DestroyInternal();
|
||||
|
||||
// Tell engine to free the function id. This will make it impossible to
|
||||
// refer to the function by id. Where this is done, it is quite possible
|
||||
// they will leak.
|
||||
if( funcType != -1 && funcType != asFUNC_IMPORTED && id )
|
||||
engine->FreeScriptFunctionId(id);
|
||||
id = 0;
|
||||
|
||||
// Finally set the engine pointer to 0 because it must not be accessed again
|
||||
engine = 0;
|
||||
}
|
||||
|
||||
// internal
|
||||
void asCScriptFunction::DestroyHalfCreated()
|
||||
{
|
||||
asASSERT( externalRefCount.get() == 0 && internalRefCount.get() == 1 );
|
||||
|
||||
// Set the funcType to dummy so the destructor won't complain
|
||||
funcType = asFUNC_DUMMY;
|
||||
|
||||
// If the bytecode exist remove it before destroying, otherwise it
|
||||
// will fail when the destructor releases the references as the bytecode
|
||||
// is not fully constructed.
|
||||
if( scriptData )
|
||||
scriptData->byteCode.SetLength(0);
|
||||
|
||||
asDELETE(this, asCScriptFunction);
|
||||
}
|
||||
|
||||
// internal
|
||||
void asCScriptFunction::DestroyInternal()
|
||||
{
|
||||
// Clean up user data
|
||||
if( userData && engine->cleanFunctionFunc )
|
||||
engine->cleanFunctionFunc(this);
|
||||
userData = 0;
|
||||
for( asUINT n = 0; n < userData.GetLength(); n += 2 )
|
||||
{
|
||||
if( userData[n+1] )
|
||||
{
|
||||
for( asUINT c = 0; c < engine->cleanFunctionFuncs.GetLength(); c++ )
|
||||
if( engine->cleanFunctionFuncs[c].type == userData[n] )
|
||||
engine->cleanFunctionFuncs[c].cleanFunc(this);
|
||||
}
|
||||
}
|
||||
userData.SetLength(0);
|
||||
|
||||
// Release all references the function holds to other objects
|
||||
ReleaseReferences();
|
||||
@ -392,6 +472,12 @@ void asCScriptFunction::DestroyInternal()
|
||||
asDELETE(sysFuncIntf,asSSystemFunctionInterface);
|
||||
sysFuncIntf = 0;
|
||||
|
||||
if( objectType )
|
||||
{
|
||||
objectType->ReleaseInternal();
|
||||
objectType = 0;
|
||||
}
|
||||
|
||||
DeallocateScriptFunctionData();
|
||||
|
||||
// Deallocate list pattern data
|
||||
@ -413,38 +499,54 @@ int asCScriptFunction::GetId() const
|
||||
int asCScriptFunction::AddRef() const
|
||||
{
|
||||
gcFlag = false;
|
||||
asASSERT( funcType != asFUNC_IMPORTED );
|
||||
return refCount.atomicInc();
|
||||
return externalRefCount.atomicInc();
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCScriptFunction::Release() const
|
||||
{
|
||||
gcFlag = false;
|
||||
asASSERT( funcType != asFUNC_IMPORTED );
|
||||
int r = refCount.atomicDec();
|
||||
int r = externalRefCount.atomicDec();
|
||||
if( r == 0 &&
|
||||
funcType != asFUNC_FUNCDEF && // Funcdefs are treated as object types and will be deleted by ClearUnusedTypes()
|
||||
funcType != asFUNC_DUMMY ) // Dummy functions are allocated on the stack and cannot be deleted
|
||||
asDELETE(const_cast<asCScriptFunction*>(this),asCScriptFunction);
|
||||
{
|
||||
// There are no more external references, if there are also no
|
||||
// internal references then it is time to delete the function
|
||||
if( internalRefCount.get() == 0 )
|
||||
{
|
||||
// If there are no internal references, then no module is owning the function
|
||||
// For example if the function was dynamically compiled without adding it to the scope of the module
|
||||
asASSERT( module == 0 );
|
||||
|
||||
asDELETE(const_cast<asCScriptFunction*>(this),asCScriptFunction);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// internal
|
||||
void asCScriptFunction::Orphan(asIScriptModule *mod)
|
||||
int asCScriptFunction::AddRefInternal()
|
||||
{
|
||||
if( mod && module == mod )
|
||||
return internalRefCount.atomicInc();
|
||||
}
|
||||
|
||||
// internal
|
||||
int asCScriptFunction::ReleaseInternal()
|
||||
{
|
||||
int r = internalRefCount.atomicDec();
|
||||
if( r == 0 &&
|
||||
funcType != asFUNC_DUMMY )
|
||||
{
|
||||
module = 0;
|
||||
if( funcType == asFUNC_SCRIPT && refCount.get() > 1 )
|
||||
// There are no more internal references, if there are also no
|
||||
// external references then it is time to delete the function
|
||||
if( externalRefCount.get() == 0 )
|
||||
{
|
||||
// This function is being orphaned, so notify the GC so it can check for circular references
|
||||
engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours);
|
||||
asDELETE(const_cast<asCScriptFunction*>(this),asCScriptFunction);
|
||||
}
|
||||
}
|
||||
|
||||
Release();
|
||||
return r;
|
||||
}
|
||||
|
||||
// interface
|
||||
@ -531,6 +633,12 @@ bool asCScriptFunction::IsPrivate() const
|
||||
return isPrivate;
|
||||
}
|
||||
|
||||
// interface
|
||||
bool asCScriptFunction::IsProtected() const
|
||||
{
|
||||
return isProtected;
|
||||
}
|
||||
|
||||
// internal
|
||||
int asCScriptFunction::GetSpaceNeededForArguments()
|
||||
{
|
||||
@ -560,7 +668,7 @@ bool asCScriptFunction::DoesReturnOnStack() const
|
||||
}
|
||||
|
||||
// internal
|
||||
asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool includeNamespace) const
|
||||
asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool includeNamespace, bool includeParamNames) const
|
||||
{
|
||||
asCString str;
|
||||
|
||||
@ -572,12 +680,12 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
|
||||
(name == objectType->name || (name.GetLength() > 0 && name[0] == '~') ||
|
||||
name == "_beh_0_" || name == "_beh_2_")) )
|
||||
{
|
||||
str = returnType.Format();
|
||||
str = returnType.Format(nameSpace, includeNamespace);
|
||||
str += " ";
|
||||
}
|
||||
if( objectType && includeObjectName )
|
||||
{
|
||||
if( includeNamespace )
|
||||
if( includeNamespace && objectType->nameSpace->name != "" )
|
||||
str += objectType->nameSpace->name + "::";
|
||||
|
||||
if( objectType->name != "" )
|
||||
@ -585,7 +693,7 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
|
||||
else
|
||||
str += "_unnamed_type_::";
|
||||
}
|
||||
else if( includeNamespace )
|
||||
else if( includeNamespace && nameSpace->name != "" )
|
||||
{
|
||||
str += nameSpace->name + "::";
|
||||
}
|
||||
@ -610,7 +718,7 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
|
||||
asUINT n;
|
||||
for( n = 0; n < parameterTypes.GetLength() - 1; n++ )
|
||||
{
|
||||
str += parameterTypes[n].Format();
|
||||
str += parameterTypes[n].Format(nameSpace, includeNamespace);
|
||||
if( parameterTypes[n].IsReference() && inOutFlags.GetLength() > n )
|
||||
{
|
||||
if( inOutFlags[n] == asTM_INREF ) str += "in";
|
||||
@ -618,6 +726,12 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
|
||||
else if( inOutFlags[n] == asTM_INOUTREF ) str += "inout";
|
||||
}
|
||||
|
||||
if( includeParamNames && n < parameterNames.GetLength() && parameterNames[n].GetLength() != 0 )
|
||||
{
|
||||
str += " ";
|
||||
str += parameterNames[n];
|
||||
}
|
||||
|
||||
if( defaultArgs.GetLength() > n && defaultArgs[n] )
|
||||
{
|
||||
asCString tmp;
|
||||
@ -629,7 +743,7 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
|
||||
}
|
||||
|
||||
// Add the last parameter
|
||||
str += parameterTypes[n].Format();
|
||||
str += parameterTypes[n].Format(nameSpace, includeNamespace);
|
||||
if( parameterTypes[n].IsReference() && inOutFlags.GetLength() > n )
|
||||
{
|
||||
if( inOutFlags[n] == asTM_INREF ) str += "in";
|
||||
@ -637,6 +751,12 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
|
||||
else if( inOutFlags[n] == asTM_INOUTREF ) str += "inout";
|
||||
}
|
||||
|
||||
if( includeParamNames && n < parameterNames.GetLength() && parameterNames[n].GetLength() != 0 )
|
||||
{
|
||||
str += " ";
|
||||
str += parameterNames[n];
|
||||
}
|
||||
|
||||
if( defaultArgs.GetLength() > n && defaultArgs[n] )
|
||||
{
|
||||
asCString tmp;
|
||||
@ -654,18 +774,33 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
|
||||
if( listPattern )
|
||||
{
|
||||
asSListPatternNode *n = listPattern;
|
||||
bool first = true;
|
||||
while( n )
|
||||
{
|
||||
if( n->type == asLPT_START )
|
||||
{
|
||||
str += " {";
|
||||
first = true;
|
||||
}
|
||||
else if( n->type == asLPT_END )
|
||||
{
|
||||
str += " }";
|
||||
first = false;
|
||||
}
|
||||
else if( n->type == asLPT_REPEAT )
|
||||
str += " repeat";
|
||||
else if( n->type == asLPT_REPEAT_SAME )
|
||||
str += " repeat_same";
|
||||
else if( n->type == asLPT_TYPE )
|
||||
{
|
||||
str += " ";
|
||||
str += reinterpret_cast<asSListPatternDataTypeNode*>(n)->dataType.Format();
|
||||
if( first )
|
||||
{
|
||||
str += " ";
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
str += ", ";
|
||||
str += reinterpret_cast<asSListPatternDataTypeNode*>(n)->dataType.Format(nameSpace, includeNamespace);
|
||||
}
|
||||
|
||||
n = n->next;
|
||||
@ -694,7 +829,7 @@ int asCScriptFunction::FindNextLineWithCode(int line) const
|
||||
{
|
||||
static int cmp(const void *a, const void *b) { return *(int*)a - *(int*)b; }
|
||||
};
|
||||
qsort(&lineNbrs[0], lineNbrs.GetLength(), sizeof(int), C::cmp);
|
||||
std::qsort(&lineNbrs[0], lineNbrs.GetLength(), sizeof(int), C::cmp);
|
||||
|
||||
if( line < lineNbrs[0] && line < (scriptData->declaredAt&0xFFFFF)) return -1;
|
||||
if( line > lineNbrs[lineNbrs.GetLength()-1] ) return -1;
|
||||
@ -811,7 +946,7 @@ const char *asCScriptFunction::GetVarDecl(asUINT index, bool includeNamespace) c
|
||||
return 0;
|
||||
|
||||
asCString *tempString = &asCThreadManager::GetLocalData()->string;
|
||||
*tempString = scriptData->variables[index]->type.Format(includeNamespace);
|
||||
*tempString = scriptData->variables[index]->type.Format(nameSpace, includeNamespace);
|
||||
*tempString += " " + scriptData->variables[index]->name;
|
||||
|
||||
return tempString->AddressOf();
|
||||
@ -928,15 +1063,31 @@ void asCScriptFunction::AddReferences()
|
||||
// Only count references if there is any bytecode
|
||||
if( scriptData && scriptData->byteCode.GetLength() )
|
||||
{
|
||||
if( returnType.IsObject() )
|
||||
returnType.GetObjectType()->AddRef();
|
||||
if( returnType.GetObjectType() )
|
||||
{
|
||||
returnType.GetObjectType()->AddRefInternal();
|
||||
|
||||
asCConfigGroup *group = engine->FindConfigGroupForObjectType(returnType.GetObjectType());
|
||||
if( group != 0 ) group->AddRef();
|
||||
}
|
||||
|
||||
for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
|
||||
if( parameterTypes[p].IsObject() )
|
||||
parameterTypes[p].GetObjectType()->AddRef();
|
||||
if( parameterTypes[p].GetObjectType() )
|
||||
{
|
||||
parameterTypes[p].GetObjectType()->AddRefInternal();
|
||||
|
||||
asCConfigGroup *group = engine->FindConfigGroupForObjectType(parameterTypes[p].GetObjectType());
|
||||
if( group != 0 ) group->AddRef();
|
||||
}
|
||||
|
||||
for( asUINT v = 0; v < scriptData->objVariableTypes.GetLength(); v++ )
|
||||
scriptData->objVariableTypes[v]->AddRef();
|
||||
if( scriptData->objVariableTypes[v] ) // The null handle is also stored, but it doesn't have an object type
|
||||
{
|
||||
scriptData->objVariableTypes[v]->AddRefInternal();
|
||||
|
||||
asCConfigGroup *group = engine->FindConfigGroupForObjectType(scriptData->objVariableTypes[v]);
|
||||
if( group != 0 ) group->AddRef();
|
||||
}
|
||||
|
||||
// Go through the byte code and add references to all resources used by the function
|
||||
asCArray<asDWORD> &bc = scriptData->byteCode;
|
||||
@ -951,7 +1102,9 @@ void asCScriptFunction::AddReferences()
|
||||
case asBC_RefCpyV:
|
||||
{
|
||||
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
|
||||
objType->AddRef();
|
||||
asASSERT( objType );
|
||||
if( objType )
|
||||
objType->AddRefInternal();
|
||||
}
|
||||
break;
|
||||
|
||||
@ -959,11 +1112,13 @@ void asCScriptFunction::AddReferences()
|
||||
case asBC_ALLOC:
|
||||
{
|
||||
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
|
||||
objType->AddRef();
|
||||
asASSERT( objType );
|
||||
if( objType )
|
||||
objType->AddRefInternal();
|
||||
|
||||
int func = asBC_INTARG(&bc[n]+AS_PTR_SIZE);
|
||||
if( func )
|
||||
engine->scriptFunctions[func]->AddRef();
|
||||
int funcId = asBC_INTARG(&bc[n]+AS_PTR_SIZE);
|
||||
if( funcId )
|
||||
engine->scriptFunctions[funcId]->AddRefInternal();
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1002,7 +1157,9 @@ void asCScriptFunction::AddReferences()
|
||||
asCConfigGroup *group = engine->FindConfigGroupForFunction(funcId);
|
||||
if( group != 0 ) group->AddRef();
|
||||
|
||||
engine->scriptFunctions[funcId]->AddRef();
|
||||
asASSERT( funcId > 0 );
|
||||
if( funcId > 0 )
|
||||
engine->scriptFunctions[funcId]->AddRefInternal();
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1010,8 +1167,10 @@ void asCScriptFunction::AddReferences()
|
||||
case asBC_CALL:
|
||||
case asBC_CALLINTF:
|
||||
{
|
||||
int func = asBC_INTARG(&bc[n]);
|
||||
engine->scriptFunctions[func]->AddRef();
|
||||
int funcId = asBC_INTARG(&bc[n]);
|
||||
asASSERT( funcId > 0 );
|
||||
if( funcId > 0 )
|
||||
engine->scriptFunctions[funcId]->AddRefInternal();
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1019,7 +1178,9 @@ void asCScriptFunction::AddReferences()
|
||||
case asBC_FuncPtr:
|
||||
{
|
||||
asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]);
|
||||
func->AddRef();
|
||||
asASSERT( func );
|
||||
if( func )
|
||||
func->AddRefInternal();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1035,16 +1196,31 @@ void asCScriptFunction::ReleaseReferences()
|
||||
// Only count references if there is any bytecode
|
||||
if( scriptData && scriptData->byteCode.GetLength() )
|
||||
{
|
||||
if( returnType.IsObject() )
|
||||
returnType.GetObjectType()->Release();
|
||||
if( returnType.GetObjectType() )
|
||||
{
|
||||
returnType.GetObjectType()->ReleaseInternal();
|
||||
|
||||
asCConfigGroup *group = engine->FindConfigGroupForObjectType(returnType.GetObjectType());
|
||||
if( group != 0 ) group->Release();
|
||||
}
|
||||
|
||||
for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
|
||||
if( parameterTypes[p].IsObject() )
|
||||
parameterTypes[p].GetObjectType()->Release();
|
||||
if( parameterTypes[p].GetObjectType() )
|
||||
{
|
||||
parameterTypes[p].GetObjectType()->ReleaseInternal();
|
||||
|
||||
asCConfigGroup *group = engine->FindConfigGroupForObjectType(parameterTypes[p].GetObjectType());
|
||||
if( group != 0 ) group->Release();
|
||||
}
|
||||
|
||||
for( asUINT v = 0; v < scriptData->objVariableTypes.GetLength(); v++ )
|
||||
if( scriptData->objVariableTypes[v] )
|
||||
scriptData->objVariableTypes[v]->Release();
|
||||
if( scriptData->objVariableTypes[v] ) // The null handle is also stored, but it doesn't have an object type
|
||||
{
|
||||
scriptData->objVariableTypes[v]->ReleaseInternal();
|
||||
|
||||
asCConfigGroup *group = engine->FindConfigGroupForObjectType(scriptData->objVariableTypes[v]);
|
||||
if( group != 0 ) group->Release();
|
||||
}
|
||||
|
||||
// Go through the byte code and release references to all resources used by the function
|
||||
asCArray<asDWORD> &bc = scriptData->byteCode;
|
||||
@ -1060,7 +1236,7 @@ void asCScriptFunction::ReleaseReferences()
|
||||
{
|
||||
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
|
||||
if( objType )
|
||||
objType->Release();
|
||||
objType->ReleaseInternal();
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1069,14 +1245,14 @@ void asCScriptFunction::ReleaseReferences()
|
||||
{
|
||||
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
|
||||
if( objType )
|
||||
objType->Release();
|
||||
objType->ReleaseInternal();
|
||||
|
||||
int func = asBC_INTARG(&bc[n]+AS_PTR_SIZE);
|
||||
if( func )
|
||||
int funcId = asBC_INTARG(&bc[n]+AS_PTR_SIZE);
|
||||
if( funcId > 0 )
|
||||
{
|
||||
asCScriptFunction *fptr = engine->scriptFunctions[func];
|
||||
asCScriptFunction *fptr = engine->scriptFunctions[funcId];
|
||||
if( fptr )
|
||||
fptr->Release();
|
||||
fptr->ReleaseInternal();
|
||||
|
||||
// The engine may have been forced to destroy the function internals early
|
||||
// and this may will make it impossible to find the function by id anymore.
|
||||
@ -1123,7 +1299,7 @@ void asCScriptFunction::ReleaseReferences()
|
||||
if( group != 0 ) group->Release();
|
||||
|
||||
if( funcId )
|
||||
engine->scriptFunctions[funcId]->Release();
|
||||
engine->scriptFunctions[funcId]->ReleaseInternal();
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1131,12 +1307,12 @@ void asCScriptFunction::ReleaseReferences()
|
||||
case asBC_CALL:
|
||||
case asBC_CALLINTF:
|
||||
{
|
||||
int func = asBC_INTARG(&bc[n]);
|
||||
if( func )
|
||||
int funcId = asBC_INTARG(&bc[n]);
|
||||
if( funcId )
|
||||
{
|
||||
asCScriptFunction *fptr = engine->scriptFunctions[func];
|
||||
asCScriptFunction *fptr = engine->scriptFunctions[funcId];
|
||||
if( fptr )
|
||||
fptr->Release();
|
||||
fptr->ReleaseInternal();
|
||||
|
||||
// The engine may have been forced to destroy the function internals early
|
||||
// and this may will make it impossible to find the function by id anymore.
|
||||
@ -1152,7 +1328,7 @@ void asCScriptFunction::ReleaseReferences()
|
||||
{
|
||||
asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]);
|
||||
if( func )
|
||||
func->Release();
|
||||
func->ReleaseInternal();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1197,6 +1373,42 @@ asUINT asCScriptFunction::GetParamCount() const
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCScriptFunction::GetParam(asUINT index, int *typeId, asDWORD *flags, const char **name, const char **defaultArg) const
|
||||
{
|
||||
if( index >= parameterTypes.GetLength() )
|
||||
return asINVALID_ARG;
|
||||
|
||||
if( typeId )
|
||||
*typeId = engine->GetTypeIdFromDataType(parameterTypes[index]);
|
||||
|
||||
if( flags )
|
||||
{
|
||||
*flags = inOutFlags[index];
|
||||
*flags |= parameterTypes[index].IsReadOnly() ? asTM_CONST : 0;
|
||||
}
|
||||
|
||||
if( name )
|
||||
{
|
||||
// The parameter names are not stored if loading from bytecode without debug information
|
||||
if( index < parameterNames.GetLength() )
|
||||
*name = parameterNames[index].AddressOf();
|
||||
else
|
||||
*name = 0;
|
||||
}
|
||||
|
||||
if( defaultArg )
|
||||
{
|
||||
if( index < defaultArgs.GetLength() && defaultArgs[index] )
|
||||
*defaultArg = defaultArgs[index]->AddressOf();
|
||||
else
|
||||
*defaultArg = 0;
|
||||
}
|
||||
|
||||
return asSUCCESS;
|
||||
}
|
||||
|
||||
#ifdef AS_DEPRECATED
|
||||
// Deprecated since 2014-04-06, 2.29.0
|
||||
int asCScriptFunction::GetParamTypeId(asUINT index, asDWORD *flags) const
|
||||
{
|
||||
if( index >= parameterTypes.GetLength() )
|
||||
@ -1210,6 +1422,7 @@ int asCScriptFunction::GetParamTypeId(asUINT index, asDWORD *flags) const
|
||||
|
||||
return engine->GetTypeIdFromDataType(parameterTypes[index]);
|
||||
}
|
||||
#endif
|
||||
|
||||
// interface
|
||||
asIScriptEngine *asCScriptFunction::GetEngine() const
|
||||
@ -1218,10 +1431,10 @@ asIScriptEngine *asCScriptFunction::GetEngine() const
|
||||
}
|
||||
|
||||
// interface
|
||||
const char *asCScriptFunction::GetDeclaration(bool includeObjectName, bool includeNamespace) const
|
||||
const char *asCScriptFunction::GetDeclaration(bool includeObjectName, bool includeNamespace, bool includeParamNames) const
|
||||
{
|
||||
asCString *tempString = &asCThreadManager::GetLocalData()->string;
|
||||
*tempString = GetDeclarationStr(includeObjectName, includeNamespace);
|
||||
*tempString = GetDeclarationStr(includeObjectName, includeNamespace, includeParamNames);
|
||||
return tempString->AddressOf();
|
||||
}
|
||||
|
||||
@ -1267,6 +1480,33 @@ void asCScriptFunction::JITCompile()
|
||||
if( !jit )
|
||||
return;
|
||||
|
||||
// Make sure the function has been compiled with JitEntry instructions
|
||||
// For functions that has JitEntry this will be a quick test
|
||||
asUINT length;
|
||||
asDWORD *byteCode = GetByteCode(&length);
|
||||
asDWORD *end = byteCode + length;
|
||||
bool foundJitEntry = false;
|
||||
while( byteCode < end )
|
||||
{
|
||||
// Determine the instruction
|
||||
asEBCInstr op = asEBCInstr(*(asBYTE*)byteCode);
|
||||
if( op == asBC_JitEntry )
|
||||
{
|
||||
foundJitEntry = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Move to next instruction
|
||||
byteCode += asBCTypeSize[asBCInfo[op].type];
|
||||
}
|
||||
|
||||
if( !foundJitEntry )
|
||||
{
|
||||
asCString msg;
|
||||
msg.Format(TXT_NO_JIT_IN_FUNC_s, GetDeclaration());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf());
|
||||
}
|
||||
|
||||
// Release the previous function, if any
|
||||
if( scriptData->jitFunction )
|
||||
{
|
||||
@ -1277,9 +1517,7 @@ void asCScriptFunction::JITCompile()
|
||||
// Compile for native system
|
||||
int r = jit->CompileFunction(this, &scriptData->jitFunction);
|
||||
if( r < 0 )
|
||||
{
|
||||
asASSERT( scriptData->jitFunction == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
// interface
|
||||
@ -1297,17 +1535,55 @@ asDWORD *asCScriptFunction::GetByteCode(asUINT *length)
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asCScriptFunction::SetUserData(void *data)
|
||||
void *asCScriptFunction::SetUserData(void *data, asPWORD type)
|
||||
{
|
||||
void *oldData = userData;
|
||||
userData = data;
|
||||
return oldData;
|
||||
// As a thread might add a new new user data at the same time as another
|
||||
// it is necessary to protect both read and write access to the userData member
|
||||
ACQUIREEXCLUSIVE(engine->engineRWLock);
|
||||
|
||||
// It is not intended to store a lot of different types of userdata,
|
||||
// so a more complex structure like a associative map would just have
|
||||
// more overhead than a simple array.
|
||||
for( asUINT n = 0; n < userData.GetLength(); n += 2 )
|
||||
{
|
||||
if( userData[n] == type )
|
||||
{
|
||||
void *oldData = reinterpret_cast<void*>(userData[n+1]);
|
||||
userData[n+1] = reinterpret_cast<asPWORD>(data);
|
||||
|
||||
RELEASEEXCLUSIVE(engine->engineRWLock);
|
||||
|
||||
return oldData;
|
||||
}
|
||||
}
|
||||
|
||||
userData.PushLast(type);
|
||||
userData.PushLast(reinterpret_cast<asPWORD>(data));
|
||||
|
||||
RELEASEEXCLUSIVE(engine->engineRWLock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asCScriptFunction::GetUserData() const
|
||||
void *asCScriptFunction::GetUserData(asPWORD type) const
|
||||
{
|
||||
return userData;
|
||||
// There may be multiple threads reading, but when
|
||||
// setting the user data nobody must be reading.
|
||||
ACQUIRESHARED(engine->engineRWLock);
|
||||
|
||||
for( asUINT n = 0; n < userData.GetLength(); n += 2 )
|
||||
{
|
||||
if( userData[n] == type )
|
||||
{
|
||||
RELEASESHARED(engine->engineRWLock);
|
||||
return reinterpret_cast<void*>(userData[n+1]);
|
||||
}
|
||||
}
|
||||
|
||||
RELEASESHARED(engine->engineRWLock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// internal
|
||||
@ -1326,7 +1602,9 @@ asCGlobalProperty *asCScriptFunction::GetPropertyByGlobalVarPtr(void *gvarPtr)
|
||||
// internal
|
||||
int asCScriptFunction::GetRefCount()
|
||||
{
|
||||
return refCount.get();
|
||||
asASSERT( funcType == asFUNC_DELEGATE );
|
||||
|
||||
return externalRefCount.get();
|
||||
}
|
||||
|
||||
// internal
|
||||
@ -1344,192 +1622,24 @@ bool asCScriptFunction::GetFlag()
|
||||
// internal
|
||||
void asCScriptFunction::EnumReferences(asIScriptEngine *)
|
||||
{
|
||||
// Notify the GC of all object types used
|
||||
if( returnType.IsObject() )
|
||||
engine->GCEnumCallback(returnType.GetObjectType());
|
||||
|
||||
for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
|
||||
if( parameterTypes[p].IsObject() )
|
||||
engine->GCEnumCallback(parameterTypes[p].GetObjectType());
|
||||
|
||||
if( scriptData )
|
||||
{
|
||||
for( asUINT t = 0; t < scriptData->objVariableTypes.GetLength(); t++ )
|
||||
engine->GCEnumCallback(scriptData->objVariableTypes[t]);
|
||||
|
||||
// Notify the GC of all script functions that is accessed
|
||||
asCArray<asDWORD> &bc = scriptData->byteCode;
|
||||
for( asUINT n = 0; n < bc.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&bc[n]].type] )
|
||||
{
|
||||
switch( *(asBYTE*)&bc[n] )
|
||||
{
|
||||
case asBC_OBJTYPE:
|
||||
case asBC_FREE:
|
||||
case asBC_REFCPY:
|
||||
case asBC_RefCpyV:
|
||||
{
|
||||
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
|
||||
engine->GCEnumCallback(objType);
|
||||
}
|
||||
break;
|
||||
|
||||
case asBC_ALLOC:
|
||||
{
|
||||
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
|
||||
engine->GCEnumCallback(objType);
|
||||
|
||||
int func = asBC_INTARG(&bc[n]+AS_PTR_SIZE);
|
||||
if( func )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[func]);
|
||||
}
|
||||
break;
|
||||
|
||||
case asBC_CALL:
|
||||
case asBC_CALLINTF:
|
||||
{
|
||||
int func = asBC_INTARG(&bc[n]);
|
||||
if( func )
|
||||
engine->GCEnumCallback(engine->scriptFunctions[func]);
|
||||
}
|
||||
break;
|
||||
|
||||
// Function pointers
|
||||
case asBC_FuncPtr:
|
||||
{
|
||||
asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]);
|
||||
if( func )
|
||||
engine->GCEnumCallback(func);
|
||||
}
|
||||
break;
|
||||
|
||||
// Global variables
|
||||
case asBC_PGA:
|
||||
case asBC_PshGPtr:
|
||||
case asBC_LDG:
|
||||
case asBC_PshG4:
|
||||
case asBC_LdGRdR4:
|
||||
case asBC_CpyGtoV4:
|
||||
case asBC_CpyVtoG4:
|
||||
case asBC_SetG4:
|
||||
// Need to enumerate the reference for each global variable
|
||||
{
|
||||
// TODO: optimize: Keep an array of accessed global properties
|
||||
void *gvarPtr = (void*)asBC_PTRARG(&bc[n]);
|
||||
asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr);
|
||||
|
||||
engine->GCEnumCallback(prop);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
asASSERT( funcType == asFUNC_DELEGATE );
|
||||
|
||||
// Delegate
|
||||
if( objForDelegate )
|
||||
engine->GCEnumCallback(objForDelegate);
|
||||
if( funcForDelegate )
|
||||
engine->GCEnumCallback(funcForDelegate);
|
||||
}
|
||||
|
||||
// internal
|
||||
void asCScriptFunction::ReleaseAllHandles(asIScriptEngine *)
|
||||
{
|
||||
asASSERT( funcType == asFUNC_DELEGATE );
|
||||
|
||||
// Release paramaters
|
||||
if( scriptData && scriptData->byteCode.GetLength() )
|
||||
{
|
||||
if( returnType.IsObject() )
|
||||
{
|
||||
returnType.GetObjectType()->Release();
|
||||
returnType = asCDataType::CreatePrimitive(ttVoid, false);
|
||||
}
|
||||
|
||||
for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
|
||||
if( parameterTypes[p].IsObject() )
|
||||
{
|
||||
parameterTypes[p].GetObjectType()->Release();
|
||||
parameterTypes[p] = asCDataType::CreatePrimitive(ttInt, false);
|
||||
}
|
||||
|
||||
for( asUINT n = 0; n < scriptData->objVariableTypes.GetLength(); n++ )
|
||||
scriptData->objVariableTypes[n]->Release();
|
||||
scriptData->objVariableTypes.SetLength(0);
|
||||
|
||||
// Release all script functions
|
||||
asCArray<asDWORD> &bc = scriptData->byteCode;
|
||||
for( asUINT n = 0; n < bc.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&bc[n]].type] )
|
||||
{
|
||||
switch( *(asBYTE*)&bc[n] )
|
||||
{
|
||||
// Object types
|
||||
case asBC_OBJTYPE:
|
||||
case asBC_FREE:
|
||||
case asBC_REFCPY:
|
||||
case asBC_RefCpyV:
|
||||
{
|
||||
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
|
||||
if( objType )
|
||||
{
|
||||
objType->Release();
|
||||
*(asPWORD*)&bc[n+1] = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case asBC_ALLOC:
|
||||
{
|
||||
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
|
||||
if( objType )
|
||||
{
|
||||
objType->Release();
|
||||
*(asPWORD*)&bc[n+1] = 0;
|
||||
}
|
||||
|
||||
int func = asBC_INTARG(&bc[n]+AS_PTR_SIZE);
|
||||
if( func )
|
||||
{
|
||||
engine->scriptFunctions[func]->Release();
|
||||
bc[n+AS_PTR_SIZE+1] = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case asBC_CALL:
|
||||
case asBC_CALLINTF:
|
||||
{
|
||||
int func = asBC_INTARG(&bc[n]);
|
||||
if( func )
|
||||
{
|
||||
engine->scriptFunctions[func]->Release();
|
||||
bc[n+1] = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Function pointers
|
||||
case asBC_FuncPtr:
|
||||
{
|
||||
asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]);
|
||||
if( func )
|
||||
{
|
||||
func->Release();
|
||||
*(asPWORD*)&bc[n+1] = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// The global variables are not released here. It is enough that the global
|
||||
// variable itself release the function to break the circle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delegate
|
||||
if( objForDelegate )
|
||||
engine->ReleaseScriptObject(objForDelegate, funcForDelegate->GetObjectType());
|
||||
objForDelegate = 0;
|
||||
if( funcForDelegate )
|
||||
funcForDelegate->Release();
|
||||
funcForDelegate = 0;
|
||||
}
|
||||
|
||||
// internal
|
||||
@ -1539,6 +1649,7 @@ bool asCScriptFunction::IsShared() const
|
||||
if( funcType == asFUNC_SYSTEM ) return true;
|
||||
|
||||
// All class methods for shared classes are also shared
|
||||
asASSERT( objectType == 0 || objectType->engine == engine || objectType->engine == 0 );
|
||||
if( objectType && (objectType->flags & asOBJ_SHARED) ) return true;
|
||||
|
||||
// Functions that have been specifically marked as shared are shared
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -66,6 +66,7 @@ struct asSScriptVariable
|
||||
enum asEListPatternNodeType
|
||||
{
|
||||
asLPT_REPEAT,
|
||||
asLPT_REPEAT_SAME,
|
||||
asLPT_START,
|
||||
asLPT_END,
|
||||
asLPT_TYPE
|
||||
@ -134,14 +135,19 @@ public:
|
||||
const char *GetObjectName() const;
|
||||
const char *GetName() const;
|
||||
const char *GetNamespace() const;
|
||||
const char *GetDeclaration(bool includeObjectName = true, bool includeNamespace = false) const;
|
||||
const char *GetDeclaration(bool includeObjectName = true, bool includeNamespace = false, bool includeParamNames = false) const;
|
||||
bool IsReadOnly() const;
|
||||
bool IsPrivate() const;
|
||||
bool IsProtected() const;
|
||||
bool IsFinal() const;
|
||||
bool IsOverride() const;
|
||||
bool IsShared() const;
|
||||
asUINT GetParamCount() const;
|
||||
int GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const;
|
||||
#ifdef AS_DEPRECATED
|
||||
// Deprecated, since 2.29.0, 2014-04-06
|
||||
int GetParamTypeId(asUINT index, asDWORD *flags = 0) const;
|
||||
#endif
|
||||
int GetReturnTypeId(asDWORD *flags = 0) const;
|
||||
|
||||
// Type id for function pointers
|
||||
@ -163,8 +169,8 @@ public:
|
||||
asDWORD *GetByteCode(asUINT *length = 0);
|
||||
|
||||
// User data
|
||||
void *SetUserData(void *userData);
|
||||
void *GetUserData() const;
|
||||
void *SetUserData(void *userData, asPWORD type);
|
||||
void *GetUserData(asPWORD type) const;
|
||||
|
||||
public:
|
||||
//-----------------------------------
|
||||
@ -173,14 +179,28 @@ public:
|
||||
asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType funcType);
|
||||
~asCScriptFunction();
|
||||
|
||||
// Keep an internal reference counter to separate references coming from
|
||||
// application or script objects and references coming from the script code
|
||||
int AddRefInternal();
|
||||
int ReleaseInternal();
|
||||
|
||||
void DestroyHalfCreated();
|
||||
|
||||
// TODO: 2.29.0: operator==
|
||||
// TODO: 2.29.0: The asIScriptFunction should provide operator== and operator!= that should do a
|
||||
// a value comparison. Two delegate objects that point to the same object and class method should compare as equal
|
||||
// TODO: 2.29.0: The operator== should also be provided in script as opEquals to allow the same comparison in script
|
||||
// To do this we'll need some way to adapt the argtype for opEquals for each funcdef, preferrably without instantiating lots of different methods
|
||||
// Perhaps reusing 'auto' to mean the same type as the object
|
||||
//bool operator==(const asCScriptFunction &other) const;
|
||||
|
||||
void DestroyInternal();
|
||||
void Orphan(asIScriptModule *mod);
|
||||
|
||||
void AddVariable(asCString &name, asCDataType &type, int stackOffset);
|
||||
|
||||
int GetSpaceNeededForArguments();
|
||||
int GetSpaceNeededForReturnValue();
|
||||
asCString GetDeclarationStr(bool includeObjectName = true, bool includeNamespace = false) const;
|
||||
asCString GetDeclarationStr(bool includeObjectName = true, bool includeNamespace = false, bool includeParamNames = false) const;
|
||||
int GetLineNumber(int programPosition, int *sectionIdx);
|
||||
void ComputeSignatureId();
|
||||
bool IsSignatureEqual(const asCScriptFunction *func) const;
|
||||
@ -209,7 +229,7 @@ public:
|
||||
|
||||
asCGlobalProperty *GetPropertyByGlobalVarPtr(void *gvarPtr);
|
||||
|
||||
// GC methods
|
||||
// GC methods (for delegates)
|
||||
int GetRefCount();
|
||||
void SetFlag();
|
||||
bool GetFlag();
|
||||
@ -220,21 +240,24 @@ public:
|
||||
//-----------------------------------
|
||||
// Properties
|
||||
|
||||
mutable asCAtomic refCount;
|
||||
mutable asCAtomic externalRefCount; // Used for external referneces
|
||||
asCAtomic internalRefCount; // Used for internal references
|
||||
mutable bool gcFlag;
|
||||
asCScriptEngine *engine;
|
||||
asCModule *module;
|
||||
|
||||
void *userData;
|
||||
asCArray<asPWORD> userData;
|
||||
|
||||
// Function signature
|
||||
asCString name;
|
||||
asCDataType returnType;
|
||||
asCArray<asCDataType> parameterTypes;
|
||||
asCArray<asCString> parameterNames;
|
||||
asCArray<asETypeModifiers> inOutFlags;
|
||||
asCArray<asCString *> defaultArgs;
|
||||
bool isReadOnly;
|
||||
bool isPrivate;
|
||||
bool isProtected;
|
||||
bool isFinal;
|
||||
bool isOverride;
|
||||
asCObjectType *objectType;
|
||||
@ -264,7 +287,7 @@ public:
|
||||
// The stack space needed for the local variables
|
||||
asDWORD variableSpace;
|
||||
|
||||
// These hold information objects and function pointers, including temporary
|
||||
// These hold information on objects and function pointers, including temporary
|
||||
// variables used by exception handler and when saving bytecode
|
||||
asCArray<asCObjectType*> objVariableTypes;
|
||||
asCArray<asCScriptFunction*> funcVariableTypes;
|
||||
@ -289,7 +312,7 @@ public:
|
||||
asCArray<int> lineNumbers;
|
||||
// Store the script section where the code was declared
|
||||
int scriptSectionIdx;
|
||||
// Store the location where the function was declared
|
||||
// Store the location where the function was declared (row in the lower 20 bits, and column in the upper 12)
|
||||
int declaredAt;
|
||||
// Store position/index pairs if the bytecode is compiled from multiple script sections
|
||||
asCArray<int> sectionIdxs;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -88,7 +88,8 @@ enum eScriptNode
|
||||
snVirtualProperty,
|
||||
snNamespace,
|
||||
snMixin,
|
||||
snListPattern
|
||||
snListPattern,
|
||||
snNamedArgument
|
||||
};
|
||||
|
||||
struct sToken
|
||||
|
@ -44,11 +44,6 @@ asIScriptObject *ScriptObjectFactory(const asCObjectType *objType, asCScriptEngi
|
||||
int r = 0;
|
||||
bool isNested = false;
|
||||
|
||||
// TODO: runtime optimize: There should be a pool for the context so it doesn't
|
||||
// have to be allocated just for creating the script object
|
||||
|
||||
// TODO: It must be possible for the application to debug the creation of the object too
|
||||
|
||||
// Use nested call in the context if there is an active context
|
||||
ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
@ -63,9 +58,13 @@ asIScriptObject *ScriptObjectFactory(const asCObjectType *objType, asCScriptEngi
|
||||
|
||||
if( ctx == 0 )
|
||||
{
|
||||
r = engine->CreateContext(&ctx, true);
|
||||
if( r < 0 )
|
||||
// Request a context from the engine
|
||||
ctx = engine->RequestContext();
|
||||
if( ctx == 0 )
|
||||
{
|
||||
// TODO: How to best report this failure?
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
r = ctx->Prepare(engine->scriptFunctions[objType->beh.factory]);
|
||||
@ -74,7 +73,7 @@ asIScriptObject *ScriptObjectFactory(const asCObjectType *objType, asCScriptEngi
|
||||
if( isNested )
|
||||
ctx->PopState();
|
||||
else
|
||||
ctx->Release();
|
||||
engine->ReturnContext(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -105,7 +104,7 @@ asIScriptObject *ScriptObjectFactory(const asCObjectType *objType, asCScriptEngi
|
||||
ctx->Abort();
|
||||
}
|
||||
else
|
||||
ctx->Release();
|
||||
engine->ReturnContext(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -117,7 +116,7 @@ asIScriptObject *ScriptObjectFactory(const asCObjectType *objType, asCScriptEngi
|
||||
if( isNested )
|
||||
ctx->PopState();
|
||||
else
|
||||
ctx->Release();
|
||||
engine->ReturnContext(ctx);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
@ -241,7 +240,7 @@ asCScriptObject::asCScriptObject(asCObjectType *ot, bool doInitialize)
|
||||
objType = ot;
|
||||
objType->AddRef();
|
||||
isDestructCalled = false;
|
||||
weakRefFlag = 0;
|
||||
extra = 0;
|
||||
hasRefCountReachedZero = false;
|
||||
|
||||
// Notify the garbage collector of this object
|
||||
@ -250,7 +249,7 @@ asCScriptObject::asCScriptObject(asCObjectType *ot, bool doInitialize)
|
||||
|
||||
// Initialize members to zero. Technically we only need to zero the pointer
|
||||
// members, but just the memset is faster than having to loop and check the datatypes
|
||||
memset(this+1, 0, objType->size - sizeof(asCScriptObject));
|
||||
memset((void*)(this+1), 0, objType->size - sizeof(asCScriptObject));
|
||||
|
||||
if( doInitialize )
|
||||
{
|
||||
@ -299,15 +298,40 @@ void asCScriptObject::Destruct()
|
||||
this->~asCScriptObject();
|
||||
|
||||
// Free the memory
|
||||
#ifndef WIP_16BYTE_ALIGN
|
||||
userFree(this);
|
||||
#else
|
||||
// Script object memory is allocated through asCScriptEngine::CallAlloc()
|
||||
// This free call must match the allocator used in CallAlloc().
|
||||
userFreeAligned(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
asCScriptObject::~asCScriptObject()
|
||||
{
|
||||
if( weakRefFlag )
|
||||
if( extra )
|
||||
{
|
||||
weakRefFlag->Release();
|
||||
weakRefFlag = 0;
|
||||
if( extra->weakRefFlag )
|
||||
{
|
||||
extra->weakRefFlag->Release();
|
||||
extra->weakRefFlag = 0;
|
||||
}
|
||||
|
||||
if( objType->engine )
|
||||
{
|
||||
// Clean the user data
|
||||
for( asUINT n = 0; n < extra->userData.GetLength(); n += 2 )
|
||||
{
|
||||
if( extra->userData[n+1] )
|
||||
{
|
||||
for( asUINT c = 0; c < objType->engine->cleanScriptObjectFuncs.GetLength(); c++ )
|
||||
if( objType->engine->cleanScriptObjectFuncs[c].type == extra->userData[n] )
|
||||
objType->engine->cleanScriptObjectFuncs[c].cleanFunc(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
asDELETE(extra, SExtra);
|
||||
}
|
||||
|
||||
// The engine pointer should be available from the objectType
|
||||
@ -361,8 +385,8 @@ asILockableSharedBool *asCScriptObject::GetWeakRefFlag() const
|
||||
// If the object's refCount has already reached zero then the object is already
|
||||
// about to be destroyed so it's ok to return null if the weakRefFlag doesn't already
|
||||
// exist
|
||||
if( weakRefFlag || hasRefCountReachedZero )
|
||||
return weakRefFlag;
|
||||
if( (extra && extra->weakRefFlag) || hasRefCountReachedZero )
|
||||
return extra->weakRefFlag;
|
||||
|
||||
// Lock globally so no other thread can attempt
|
||||
// to create a shared bool at the same time.
|
||||
@ -373,12 +397,77 @@ asILockableSharedBool *asCScriptObject::GetWeakRefFlag() const
|
||||
|
||||
// Make sure another thread didn't create the
|
||||
// flag while we waited for the lock
|
||||
if( !weakRefFlag )
|
||||
weakRefFlag = asNEW(asCLockableSharedBool);
|
||||
if( !extra )
|
||||
extra = asNEW(SExtra);
|
||||
if( !extra->weakRefFlag )
|
||||
extra->weakRefFlag = asNEW(asCLockableSharedBool);
|
||||
|
||||
asReleaseExclusiveLock();
|
||||
|
||||
return weakRefFlag;
|
||||
return extra->weakRefFlag;
|
||||
}
|
||||
|
||||
void *asCScriptObject::GetUserData(asPWORD type) const
|
||||
{
|
||||
if( !extra )
|
||||
return 0;
|
||||
|
||||
// There may be multiple threads reading, but when
|
||||
// setting the user data nobody must be reading.
|
||||
// TODO: runtime optimize: Would it be worth it to have a rwlock per object type?
|
||||
asAcquireSharedLock();
|
||||
|
||||
for( asUINT n = 0; n < extra->userData.GetLength(); n += 2 )
|
||||
{
|
||||
if( extra->userData[n] == type )
|
||||
{
|
||||
void *userData = reinterpret_cast<void*>(extra->userData[n+1]);
|
||||
asReleaseSharedLock();
|
||||
return userData;
|
||||
}
|
||||
}
|
||||
|
||||
asReleaseSharedLock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *asCScriptObject::SetUserData(void *data, asPWORD type)
|
||||
{
|
||||
// Lock globally so no other thread can attempt
|
||||
// to manipulate the extra data at the same time.
|
||||
// TODO: runtime optimize: Instead of locking globally, it would be possible to have
|
||||
// a critical section per object type. This would reduce the
|
||||
// chances of two threads lock on the same critical section.
|
||||
asAcquireExclusiveLock();
|
||||
|
||||
// Make sure another thread didn't create the
|
||||
// flag while we waited for the lock
|
||||
if( !extra )
|
||||
extra = asNEW(SExtra);
|
||||
|
||||
// It is not intended to store a lot of different types of userdata,
|
||||
// so a more complex structure like a associative map would just have
|
||||
// more overhead than a simple array.
|
||||
for( asUINT n = 0; n < extra->userData.GetLength(); n += 2 )
|
||||
{
|
||||
if( extra->userData[n] == type )
|
||||
{
|
||||
void *oldData = reinterpret_cast<void*>(extra->userData[n+1]);
|
||||
extra->userData[n+1] = reinterpret_cast<asPWORD>(data);
|
||||
|
||||
asReleaseExclusiveLock();
|
||||
|
||||
return oldData;
|
||||
}
|
||||
}
|
||||
|
||||
extra->userData.PushLast(type);
|
||||
extra->userData.PushLast(reinterpret_cast<asPWORD>(data));
|
||||
|
||||
asReleaseExclusiveLock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
asIScriptEngine *asCScriptObject::GetEngine() const
|
||||
@ -417,14 +506,14 @@ int asCScriptObject::Release() const
|
||||
// is ok to check the existance of the weakRefFlag without locking here
|
||||
// because if the refCount is 1 then no other thread is currently
|
||||
// creating the weakRefFlag.
|
||||
if( refCount.get() == 1 && weakRefFlag )
|
||||
if( refCount.get() == 1 && extra && extra->weakRefFlag )
|
||||
{
|
||||
// Set the flag to tell others that the object is no longer alive
|
||||
// We must do this before decreasing the refCount to 0 so we don't
|
||||
// end up with a race condition between this thread attempting to
|
||||
// destroy the object and the other that temporary added a strong
|
||||
// ref from the weak ref.
|
||||
weakRefFlag->Set(true);
|
||||
extra->weakRefFlag->Set(true);
|
||||
}
|
||||
|
||||
// Call the script destructor behaviour if the reference counter is 1.
|
||||
@ -491,10 +580,13 @@ void asCScriptObject::CallDestructor()
|
||||
|
||||
if( ctx == 0 )
|
||||
{
|
||||
// Setup a context for calling the default constructor
|
||||
asCScriptEngine *engine = objType->engine;
|
||||
int r = engine->CreateContext(&ctx, true);
|
||||
if( r < 0 ) return;
|
||||
// Request a context from the engine
|
||||
ctx = objType->engine->RequestContext();
|
||||
if( ctx == 0 )
|
||||
{
|
||||
// TODO: How to best report this failure?
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -538,7 +630,10 @@ void asCScriptObject::CallDestructor()
|
||||
ctx->Abort();
|
||||
}
|
||||
else
|
||||
ctx->Release();
|
||||
{
|
||||
// Return the context to engine
|
||||
objType->engine->ReturnContext(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -726,9 +821,13 @@ asCScriptObject &asCScriptObject::operator=(const asCScriptObject &other)
|
||||
|
||||
if( ctx == 0 )
|
||||
{
|
||||
r = engine->CreateContext(&ctx, true);
|
||||
if( r < 0 )
|
||||
// Request a context from the engine
|
||||
ctx = engine->RequestContext();
|
||||
if( ctx == 0 )
|
||||
{
|
||||
// TODO: How to best report this failure?
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
r = ctx->Prepare(engine->scriptFunctions[objType->beh.copy]);
|
||||
@ -737,7 +836,8 @@ asCScriptObject &asCScriptObject::operator=(const asCScriptObject &other)
|
||||
if( isNested )
|
||||
ctx->PopState();
|
||||
else
|
||||
ctx->Release();
|
||||
engine->ReturnContext(ctx);
|
||||
// TODO: How to best report this failure?
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -773,14 +873,20 @@ asCScriptObject &asCScriptObject::operator=(const asCScriptObject &other)
|
||||
ctx->Abort();
|
||||
}
|
||||
else
|
||||
ctx->Release();
|
||||
{
|
||||
// Return the context to the engine
|
||||
engine->ReturnContext(ctx);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
if( isNested )
|
||||
ctx->PopState();
|
||||
else
|
||||
ctx->Release();
|
||||
{
|
||||
// Return the context to the engine
|
||||
engine->ReturnContext(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -76,11 +76,11 @@ public:
|
||||
//===================================
|
||||
// From asIScriptObject
|
||||
//===================================
|
||||
asIScriptEngine *GetEngine() const;
|
||||
|
||||
// Memory management
|
||||
int AddRef() const;
|
||||
int Release() const;
|
||||
int AddRef() const;
|
||||
int Release() const;
|
||||
asILockableSharedBool *GetWeakRefFlag() const;
|
||||
|
||||
// Type info
|
||||
int GetTypeId() const;
|
||||
@ -92,7 +92,13 @@ public:
|
||||
const char *GetPropertyName(asUINT prop) const;
|
||||
void *GetAddressOfProperty(asUINT prop);
|
||||
|
||||
int CopyFrom(asIScriptObject *other);
|
||||
// Miscellaneous
|
||||
asIScriptEngine *GetEngine() const;
|
||||
int CopyFrom(asIScriptObject *other);
|
||||
|
||||
// User data
|
||||
void *SetUserData(void *data, asPWORD type = 0);
|
||||
void *GetUserData(asPWORD type = 0) const;
|
||||
|
||||
//====================================
|
||||
// Internal
|
||||
@ -110,9 +116,6 @@ public:
|
||||
void EnumReferences(asIScriptEngine *engine);
|
||||
void ReleaseAllHandles(asIScriptEngine *engine);
|
||||
|
||||
// Weakref methods
|
||||
asILockableSharedBool *GetWeakRefFlag() const;
|
||||
|
||||
// Used for properties
|
||||
void *AllocateUninitializedObject(asCObjectType *objType, asCScriptEngine *engine);
|
||||
void FreeObject(void *ptr, asCObjectType *objType, asCScriptEngine *engine);
|
||||
@ -124,15 +127,26 @@ public:
|
||||
//=============================================
|
||||
// Properties
|
||||
//=============================================
|
||||
public:
|
||||
asCObjectType *objType;
|
||||
|
||||
protected:
|
||||
friend class asCContext;
|
||||
asCObjectType *objType;
|
||||
|
||||
mutable asCAtomic refCount;
|
||||
mutable asBYTE gcFlag:1;
|
||||
mutable asBYTE hasRefCountReachedZero:1;
|
||||
bool isDestructCalled;
|
||||
mutable asCLockableSharedBool *weakRefFlag;
|
||||
mutable asBYTE gcFlag:1;
|
||||
mutable asBYTE hasRefCountReachedZero:1;
|
||||
bool isDestructCalled;
|
||||
|
||||
// Most script classes instances won't have neither the weakRefFlags nor
|
||||
// userData so we only allocate this if requested. Even when used it is
|
||||
// not something that will be accessed all the time so having the extra
|
||||
// indirection will not affect the performance significantly.
|
||||
struct SExtra
|
||||
{
|
||||
SExtra() : weakRefFlag(0) {};
|
||||
asCLockableSharedBool *weakRefFlag;
|
||||
asCArray<asPWORD> userData;
|
||||
};
|
||||
mutable SExtra *extra;
|
||||
};
|
||||
|
||||
void ScriptObject_Construct(asCObjectType *objType, asCScriptObject *self);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -31,8 +31,8 @@
|
||||
#include "as_config.h"
|
||||
|
||||
#include <stdarg.h> // va_list, va_start(), etc
|
||||
#include <stdlib.h> // strtod(), strtol()
|
||||
#include <string.h> // some compilers declare memcpy() here
|
||||
#include <stdlib.h> // strtod(), strtol()
|
||||
#include <string.h> // some compilers declare memcpy() here
|
||||
|
||||
#if !defined(AS_NO_MEMORY_H)
|
||||
#include <memory.h>
|
||||
@ -56,6 +56,26 @@ asCString::asCString(const asCString &str)
|
||||
Assign(str.AddressOf(), str.length);
|
||||
}
|
||||
|
||||
#ifdef AS_CAN_USE_CPP11
|
||||
asCString::asCString(asCString &&str)
|
||||
{
|
||||
if( str.length <= 11 )
|
||||
{
|
||||
length = str.length;
|
||||
memcpy(local, str.local, length);
|
||||
local[length] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dynamic = str.dynamic;
|
||||
length = str.length;
|
||||
}
|
||||
|
||||
str.dynamic = 0;
|
||||
str.length = 0;
|
||||
}
|
||||
#endif // c++11
|
||||
|
||||
asCString::asCString(const char *str, size_t len)
|
||||
{
|
||||
length = 0;
|
||||
@ -183,6 +203,37 @@ asCString &asCString::operator =(const asCString &str)
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef AS_CAN_USE_CPP11
|
||||
asCString &asCString::operator =(asCString &&str)
|
||||
{
|
||||
if( this != &str )
|
||||
{
|
||||
if( length > 11 && dynamic )
|
||||
{
|
||||
asDELETEARRAY(dynamic);
|
||||
}
|
||||
|
||||
if ( str.length <= 11 )
|
||||
{
|
||||
length = str.length;
|
||||
|
||||
memcpy(local, str.local, length);
|
||||
local[length] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dynamic = str.dynamic;
|
||||
length = str.length;
|
||||
}
|
||||
|
||||
str.dynamic = 0;
|
||||
str.length = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
#endif // c++11
|
||||
|
||||
asCString &asCString::operator =(char ch)
|
||||
{
|
||||
Assign(&ch, 1);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -38,14 +38,17 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// TODO: optimize: On compilers with C++11 support the string class should take advantage of the move operator &&
|
||||
|
||||
class asCString
|
||||
{
|
||||
public:
|
||||
asCString();
|
||||
~asCString();
|
||||
|
||||
#ifdef AS_CAN_USE_CPP11
|
||||
asCString(asCString &&);
|
||||
asCString &operator =(asCString &&);
|
||||
#endif // c++11
|
||||
|
||||
asCString(const asCString &);
|
||||
asCString(const char *);
|
||||
asCString(const char *, size_t length);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2012-2013 Andreas Jonsson
|
||||
Copyright (c) 2012-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -59,6 +59,7 @@ BEGIN_AS_NAMESPACE
|
||||
struct asIFilter
|
||||
{
|
||||
virtual bool operator()(const void*) const = 0;
|
||||
virtual ~asIFilter() {};
|
||||
};
|
||||
|
||||
|
||||
@ -107,7 +108,7 @@ public:
|
||||
typedef asCSymbolTableIterator<T, T> iterator;
|
||||
typedef asCSymbolTableIterator<T, const T> const_iterator;
|
||||
|
||||
asCSymbolTable(unsigned int initialCapacity = 0);
|
||||
asCSymbolTable(asUINT initialCapacity = 0);
|
||||
|
||||
int GetFirstIndex(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const;
|
||||
int GetFirstIndex(const asSNameSpace *ns, const asCString &name) const;
|
||||
@ -118,22 +119,22 @@ public:
|
||||
T* GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const;
|
||||
T* GetFirst(const asSNameSpace *ns, const asCString &name);
|
||||
const T* GetFirst(const asSNameSpace *ns, const asCString &name) const;
|
||||
T* Get(unsigned int index);
|
||||
const T* Get(unsigned int index) const;
|
||||
T* Get(asUINT index);
|
||||
const T* Get(asUINT index) const;
|
||||
T* GetLast();
|
||||
const T* GetLast() const;
|
||||
|
||||
const asCArray<unsigned int> &GetIndexes(const asSNameSpace *ns, const asCString &name) const;
|
||||
const asCArray<asUINT> &GetIndexes(const asSNameSpace *ns, const asCString &name) const;
|
||||
|
||||
int Put(T* entry);
|
||||
asUINT Put(T* entry);
|
||||
|
||||
unsigned int GetSize() const;
|
||||
asUINT GetSize() const;
|
||||
|
||||
void SwapWith(asCSymbolTable<T> &other);
|
||||
|
||||
void Clear();
|
||||
bool Erase(unsigned int idx);
|
||||
void Allocate(unsigned int elem_cnt, bool keep_data);
|
||||
bool Erase(asUINT idx);
|
||||
void Allocate(asUINT elem_cnt, bool keep_data);
|
||||
|
||||
iterator List();
|
||||
const_iterator List() const;
|
||||
@ -146,11 +147,11 @@ private:
|
||||
friend class asCSymbolTableIterator<T, const T>;
|
||||
|
||||
void GetKey(const T *entry, asSNameSpaceNamePair &key) const;
|
||||
bool CheckIdx(unsigned idx) const;
|
||||
bool CheckIdx(asUINT idx) const;
|
||||
|
||||
asCMap<asSNameSpaceNamePair, asCArray<unsigned int> > m_map;
|
||||
asCArray<T*> m_entries;
|
||||
unsigned int m_size;
|
||||
asCMap<asSNameSpaceNamePair, asCArray<asUINT> > m_map;
|
||||
asCArray<T*> m_entries;
|
||||
unsigned int m_size;
|
||||
};
|
||||
|
||||
|
||||
@ -162,7 +163,7 @@ void asCSymbolTable<T>::SwapWith(asCSymbolTable<T> &other)
|
||||
m_map.SwapWith(other.m_map);
|
||||
m_entries.SwapWith(other.m_entries);
|
||||
|
||||
unsigned int tmp = m_size;
|
||||
asUINT tmp = m_size;
|
||||
m_size = other.m_size;
|
||||
other.m_size = tmp;
|
||||
}
|
||||
@ -173,7 +174,7 @@ void asCSymbolTable<T>::SwapWith(asCSymbolTable<T> &other)
|
||||
// Constructor
|
||||
// initialCapacity gives the number of entries to allocate in advance
|
||||
template<class T>
|
||||
asCSymbolTable<T>::asCSymbolTable(unsigned initialCapacity) : m_entries(initialCapacity)
|
||||
asCSymbolTable<T>::asCSymbolTable(asUINT initialCapacity) : m_entries(initialCapacity)
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
@ -188,11 +189,11 @@ int asCSymbolTable<T>::GetFirstIndex(
|
||||
{
|
||||
asSNameSpaceNamePair key(ns, name);
|
||||
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<unsigned int> > *cursor;
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
|
||||
if( m_map.MoveTo(&cursor, key) )
|
||||
{
|
||||
const asCArray<unsigned int> &arr = m_map.GetValue(cursor);
|
||||
for( unsigned int n = 0; n < arr.GetLength(); n++ )
|
||||
const asCArray<asUINT> &arr = m_map.GetValue(cursor);
|
||||
for( asUINT n = 0; n < arr.GetLength(); n++ )
|
||||
{
|
||||
T *entry = m_entries[arr[n]];
|
||||
if( entry && filter(entry) )
|
||||
@ -206,15 +207,15 @@ int asCSymbolTable<T>::GetFirstIndex(
|
||||
|
||||
|
||||
template<class T>
|
||||
const asCArray<unsigned int> &asCSymbolTable<T>::GetIndexes(const asSNameSpace *ns, const asCString &name) const
|
||||
const asCArray<asUINT> &asCSymbolTable<T>::GetIndexes(const asSNameSpace *ns, const asCString &name) const
|
||||
{
|
||||
asSNameSpaceNamePair key(ns, name);
|
||||
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<unsigned int> > *cursor;
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
|
||||
if( m_map.MoveTo(&cursor, key) )
|
||||
return m_map.GetValue(cursor);
|
||||
|
||||
static asCArray<unsigned int> dummy;
|
||||
static asCArray<asUINT> dummy;
|
||||
return dummy;
|
||||
}
|
||||
|
||||
@ -237,7 +238,7 @@ int asCSymbolTable<T>::GetFirstIndex(const asSNameSpace *ns, const asCString &na
|
||||
{
|
||||
asSNameSpaceNamePair key(ns, name);
|
||||
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<unsigned int> > *cursor;
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
|
||||
if( m_map.MoveTo(&cursor, key) )
|
||||
return m_map.GetValue(cursor)[0];
|
||||
|
||||
@ -252,7 +253,7 @@ int asCSymbolTable<T>::GetFirstIndex(const asSNameSpace *ns, const asCString &na
|
||||
template<class T>
|
||||
int asCSymbolTable<T>::GetIndex(const T* entry) const
|
||||
{
|
||||
for( unsigned int n = 0; n < m_entries.GetLength(); n++ )
|
||||
for( asUINT n = 0; n < m_entries.GetLength(); n++ )
|
||||
if( m_entries[n] == entry )
|
||||
return n;
|
||||
|
||||
@ -265,7 +266,7 @@ int asCSymbolTable<T>::GetIndex(const T* entry) const
|
||||
|
||||
|
||||
template<class T>
|
||||
T* asCSymbolTable<T>::Get(unsigned idx)
|
||||
T* asCSymbolTable<T>::Get(asUINT idx)
|
||||
{
|
||||
if( !CheckIdx(idx) )
|
||||
return 0;
|
||||
@ -274,7 +275,7 @@ T* asCSymbolTable<T>::Get(unsigned idx)
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const T* asCSymbolTable<T>::Get(unsigned idx) const
|
||||
const T* asCSymbolTable<T>::Get(asUINT idx) const
|
||||
{
|
||||
return const_cast< asCSymbolTable<T>* >(this)->Get(idx);
|
||||
}
|
||||
@ -331,7 +332,7 @@ void asCSymbolTable<T>::Clear()
|
||||
|
||||
// Pre-allocate slots for elemCnt entries
|
||||
template<class T>
|
||||
void asCSymbolTable<T>::Allocate(unsigned elemCnt, bool keepData)
|
||||
void asCSymbolTable<T>::Allocate(asUINT elemCnt, bool keepData)
|
||||
{
|
||||
asASSERT( elemCnt >= m_entries.GetLength() );
|
||||
m_entries.Allocate(elemCnt, keepData);
|
||||
@ -342,7 +343,7 @@ void asCSymbolTable<T>::Allocate(unsigned elemCnt, bool keepData)
|
||||
|
||||
|
||||
template<class T>
|
||||
bool asCSymbolTable<T>::Erase(unsigned idx)
|
||||
bool asCSymbolTable<T>::Erase(asUINT idx)
|
||||
{
|
||||
if( !CheckIdx(idx) )
|
||||
{
|
||||
@ -355,26 +356,14 @@ bool asCSymbolTable<T>::Erase(unsigned idx)
|
||||
if( !entry )
|
||||
return false;
|
||||
|
||||
if( idx == m_entries.GetLength() - 1 )
|
||||
{
|
||||
m_entries.PopLast();
|
||||
|
||||
// TODO: Should remove all trailing empty slots
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Must pack or reuse empty slots
|
||||
m_entries[idx] = 0;
|
||||
}
|
||||
m_size--;
|
||||
|
||||
// Remove the symbol from the lookup map
|
||||
asSNameSpaceNamePair key;
|
||||
GetKey(entry, key);
|
||||
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<unsigned int> > *cursor;
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
|
||||
if( m_map.MoveTo(&cursor, key) )
|
||||
{
|
||||
asCArray<unsigned int> &arr = m_map.GetValue(cursor);
|
||||
asCArray<asUINT> &arr = m_map.GetValue(cursor);
|
||||
arr.RemoveValue(idx);
|
||||
if( arr.GetLength() == 0 )
|
||||
m_map.Erase(cursor);
|
||||
@ -382,6 +371,28 @@ bool asCSymbolTable<T>::Erase(unsigned idx)
|
||||
else
|
||||
asASSERT(false);
|
||||
|
||||
// Remove the symbol from the indexed array
|
||||
if( idx == m_entries.GetLength() - 1 )
|
||||
m_entries.PopLast();
|
||||
else
|
||||
{
|
||||
// Must keep the array packed
|
||||
int prevIdx = int(m_entries.GetLength()-1);
|
||||
m_entries[idx] = m_entries.PopLast();
|
||||
|
||||
// Update the index in the lookup map
|
||||
entry = m_entries[idx];
|
||||
GetKey(entry, key);
|
||||
if( m_map.MoveTo(&cursor, key) )
|
||||
{
|
||||
asCArray<asUINT> &arr = m_map.GetValue(cursor);
|
||||
arr[arr.IndexOf(prevIdx)] = idx;
|
||||
}
|
||||
else
|
||||
asASSERT(false);
|
||||
}
|
||||
m_size--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -389,18 +400,18 @@ bool asCSymbolTable<T>::Erase(unsigned idx)
|
||||
|
||||
|
||||
template<class T>
|
||||
int asCSymbolTable<T>::Put(T *entry)
|
||||
asUINT asCSymbolTable<T>::Put(T *entry)
|
||||
{
|
||||
unsigned int idx = (unsigned int)(m_entries.GetLength());
|
||||
asUINT idx = m_entries.GetLength();
|
||||
asSNameSpaceNamePair key;
|
||||
GetKey(entry, key);
|
||||
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<unsigned int> > *cursor;
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
|
||||
if( m_map.MoveTo(&cursor, key) )
|
||||
m_map.GetValue(cursor).PushLast(idx);
|
||||
else
|
||||
{
|
||||
asCArray<unsigned int> arr(1);
|
||||
asCArray<asUINT> arr(1);
|
||||
arr.PushLast(idx);
|
||||
m_map.Insert(key, arr);
|
||||
}
|
||||
@ -424,7 +435,7 @@ void asCSymbolTable<T>::GetKey(const T *entry, asSNameSpaceNamePair &key) const
|
||||
|
||||
|
||||
template<class T>
|
||||
unsigned int asCSymbolTable<T>::GetSize() const
|
||||
asUINT asCSymbolTable<T>::GetSize() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
@ -433,7 +444,7 @@ unsigned int asCSymbolTable<T>::GetSize() const
|
||||
|
||||
|
||||
template<class T>
|
||||
bool asCSymbolTable<T>::CheckIdx(unsigned int idx) const
|
||||
bool asCSymbolTable<T>::CheckIdx(asUINT idx) const
|
||||
{
|
||||
return idx < m_entries.GetLength();
|
||||
}
|
||||
@ -444,9 +455,9 @@ bool asCSymbolTable<T>::CheckIdx(unsigned int idx) const
|
||||
template<class T>
|
||||
int asCSymbolTable<T>::GetLastIndex() const
|
||||
{
|
||||
unsigned int idx = (unsigned int)(m_entries.GetLength()) - 1;
|
||||
asASSERT( idx == asUINT(-1) || m_entries[idx] );
|
||||
return int(idx);
|
||||
int idx = int(m_entries.GetLength()) - 1;
|
||||
asASSERT( idx == -1 || m_entries[idx] );
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
@ -475,7 +486,7 @@ typename asCSymbolTable<T>::const_iterator asCSymbolTable<T>::List() const
|
||||
template<class T, class T2>
|
||||
asCSymbolTableIterator<T, T2>::asCSymbolTableIterator(asCSymbolTable<T> *table) : m_table(table), m_idx(0)
|
||||
{
|
||||
unsigned int sz = (unsigned int)(m_table->m_entries.GetLength());
|
||||
asUINT sz = m_table->m_entries.GetLength();
|
||||
while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
|
||||
m_idx++;
|
||||
}
|
||||
@ -523,7 +534,7 @@ asCSymbolTableIterator<T, T2>::operator bool() const
|
||||
template<class T, class T2>
|
||||
void asCSymbolTableIterator<T, T2>::Next()
|
||||
{
|
||||
unsigned int sz = (unsigned int)(m_table->m_entries.GetLength());
|
||||
asUINT sz = m_table->m_entries.GetLength();
|
||||
m_idx++;
|
||||
while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
|
||||
m_idx++;
|
||||
@ -535,7 +546,7 @@ template<class T, class T2>
|
||||
void asCSymbolTableIterator<T, T2>::Previous()
|
||||
{
|
||||
// overflow on stepping over first element
|
||||
unsigned int sz = (unsigned int)(m_table->m_entries.GetLength());
|
||||
asUINT sz = m_table->m_entries.GetLength();
|
||||
m_idx--;
|
||||
while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
|
||||
m_idx--;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -41,59 +41,70 @@
|
||||
|
||||
// Compiler messages
|
||||
|
||||
#define TXT_s_ALREADY_DECLARED "'%s' is already declared"
|
||||
#define TXT_ARG_NOT_LVALUE "Argument cannot be assigned. Output will be discarded."
|
||||
#define TXT_s_ALREADY_DECLARED "'%s' is already declared"
|
||||
#define TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED "Abstract class '%s' cannot be instantiated"
|
||||
#define TXT_ACCESSING_PRIVATE_PROP_s "Accessing private property '%s' of parent class"
|
||||
#define TXT_ARG_NOT_LVALUE "Output argument expression is not assignable"
|
||||
#define TXT_ATTR_s_INFORMED_MULTIPLE_TIMES "Attribute '%s' informed multiple times"
|
||||
#define TXT_AUTO_NOT_ALLOWED "Auto is not allowed here"
|
||||
|
||||
#define TXT_BOTH_MUST_BE_SAME "Both expressions must have the same type"
|
||||
#define TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR "Both conditions must call constructor"
|
||||
#define TEXT_BASE_DOESNT_HAVE_DEF_CONSTR "Base class doesn't have default constructor. Make explicit call to base constructor"
|
||||
|
||||
#define TXT_CANDIDATES_ARE "Candidates are:"
|
||||
#define TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS "Can't call a constructor in loops"
|
||||
#define TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH "Can't call a constructor in switch"
|
||||
#define TXT_CANNOT_CALL_CONSTRUCTOR_TWICE "Can't call a constructor multiple times"
|
||||
#define TXT_CANDIDATES_ARE "Candidates are:"
|
||||
#define TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS "Can't call a constructor in loops"
|
||||
#define TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH "Can't call a constructor in switch"
|
||||
#define TXT_CANNOT_CALL_CONSTRUCTOR_TWICE "Can't call a constructor multiple times"
|
||||
#define TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES "Can't create delegate for types that do not support handles"
|
||||
#define TXT_CANNOT_IMPLEMENT_SELF "Can't implement itself, or another interface that implements this interface"
|
||||
#define TXT_CANNOT_INHERIT_FROM_s_FINAL "Can't inherit from class '%s' marked as final"
|
||||
#define TXT_CANNOT_INHERIT_FROM_MULTIPLE_CLASSES "Can't inherit from multiple classes"
|
||||
#define TXT_CANNOT_INHERIT_FROM_SELF "Can't inherit from itself, or another class that inherits from this class"
|
||||
#define TXT_CANNOT_INSTANCIATE_TEMPLATE_s_WITH_s "Can't instanciate template '%s' with subtype '%s'"
|
||||
#define TXT_CANNOT_RETURN_REF_TO_LOCAL "Can't return reference to local value."
|
||||
#define TXT_CANT_IMPLICITLY_CONVERT_s_TO_s "Can't implicitly convert from '%s' to '%s'."
|
||||
#define TXT_CANT_RETURN_VALUE "Can't return value when return type is 'void'"
|
||||
#define TXT_CHANGE_SIGN "Implicit conversion changed sign of value"
|
||||
#define TXT_COMPILING_s "Compiling %s"
|
||||
#define TXT_COMPOUND_ASGN_WITH_PROP "Compound assignments with property accessors are not allowed"
|
||||
#define TXT_CONSTRUCTOR_NAME_ERROR "The name of constructors and destructors must be the same as the class"
|
||||
#define TXT_CANNOT_IMPLEMENT_SELF "Can't implement itself, or another interface that implements this interface"
|
||||
#define TXT_CANNOT_INHERIT_FROM_s_FINAL "Can't inherit from class '%s' marked as final"
|
||||
#define TXT_CANNOT_INHERIT_FROM_MULTIPLE_CLASSES "Can't inherit from multiple classes"
|
||||
#define TXT_CANNOT_INHERIT_FROM_SELF "Can't inherit from itself, or another class that inherits from this class"
|
||||
#define TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG "Can't pass class method as arg directly. Use a delegate object instead"
|
||||
#define TXT_CANNOT_RESOLVE_AUTO "Unable to resolve auto type"
|
||||
#define TXT_CANNOT_RETURN_REF_TO_LOCAL "Can't return reference to local value."
|
||||
#define TXT_CANT_CONSTRUCT_s_USE_REF_CAST "Can't construct handle '%s'. Use ref cast instead"
|
||||
#define TXT_CANT_IMPLICITLY_CONVERT_s_TO_s "Can't implicitly convert from '%s' to '%s'."
|
||||
#define TXT_CANT_RETURN_VALUE "Can't return value when return type is 'void'"
|
||||
#define TXT_CHANGE_SIGN "Implicit conversion changed sign of value"
|
||||
#define TXT_CLASS_CANT_BE_FINAL_AND_ABSTRACT "A class cannot be both abstract and final"
|
||||
#define TXT_COMPILING_s "Compiling %s"
|
||||
#define TXT_COMPOUND_ASGN_ON_VALUE_TYPE "Compound assignments with property accessors on value types are not supported"
|
||||
#define TXT_COMPOUND_ASGN_WITH_IDX_PROP "Compound assignments with indexed property accessors are not supported"
|
||||
#define TXT_COMPOUND_ASGN_REQUIRE_GET_SET "Compound assignments with property accessors require both get and set accessors"
|
||||
|
||||
#define TXT_DATA_TYPE_CANT_BE_s "Data type can't be '%s'"
|
||||
#define TXT_DECL_IN_SWITCH "Variables cannot be declared in switch cases, except inside statement blocks"
|
||||
#define TXT_DEFAULT_MUST_BE_LAST "The default case must be the last one"
|
||||
#define TXT_DEF_ARG_MISSING_IN_FUNC_s "All subsequent parameters after the first default value must have default values in function '%s'"
|
||||
#define TXT_DEF_ARG_TYPE_DOESNT_MATCH "The type of the default argument expression doesn't match the function parameter type"
|
||||
#define TXT_DATA_TYPE_CANT_BE_s "Data type can't be '%s'"
|
||||
#define TXT_DECL_IN_SWITCH "Variables cannot be declared in switch cases, except inside statement blocks"
|
||||
#define TXT_DEFAULT_MUST_BE_LAST "The default case must be the last one"
|
||||
#define TXT_DEF_ARG_MISSING_IN_FUNC_s "All subsequent parameters after the first default value must have default values in function '%s'"
|
||||
#define TXT_DEF_ARG_TYPE_DOESNT_MATCH "The type of the default argument expression doesn't match the function parameter type"
|
||||
#define TXT_DUPLICATE_NAMED_ARG "Duplicate named argument"
|
||||
#define TXT_DERIVED_METHOD_MUST_HAVE_SAME_RETTYPE_s "The method in the derived class must have the same return type as in the base class: '%s'"
|
||||
#define TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM "The destructor must not have any parameters"
|
||||
#define TXT_DISALLOW_ASSIGN_ON_REF_TYPE "Value assignment on reference types is not allowed. Did you mean to do a handle assignment?"
|
||||
#define TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE "Compound assignment on reference types is not allowed"
|
||||
#define TXT_DUPLICATE_SWITCH_CASE "Duplicate switch case"
|
||||
#define TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM "The destructor must not have any parameters"
|
||||
#define TXT_DESTRUCTOR_s_s_NAME_ERROR "The name of the destructor '%s::~%s' must be the same as the class"
|
||||
#define TXT_DISALLOW_ASSIGN_ON_REF_TYPE "Value assignment on reference types is not allowed. Did you mean to do a handle assignment?"
|
||||
#define TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE "Compound assignment on reference types is not allowed"
|
||||
#define TXT_DUPLICATE_SWITCH_CASE "Duplicate switch case"
|
||||
|
||||
#define TXT_ELSE_WITH_EMPTY_STATEMENT "Else with empty statement"
|
||||
#define TXT_EMPTY_SWITCH "Empty switch statement"
|
||||
#define TXT_EXPECTED_s "Expected '%s'"
|
||||
#define TXT_EXPECTED_CONSTANT "Expected constant"
|
||||
#define TXT_EXPECTED_DATA_TYPE "Expected data type"
|
||||
#define TXT_EXPECTED_EXPRESSION_VALUE "Expected expression value"
|
||||
#define TXT_EXPECTED_IDENTIFIER "Expected identifier"
|
||||
#define TXT_EXPECTED_LIST "Expected a list enclosed by { } to match pattern"
|
||||
#define TXT_EXPECTED_METHOD_OR_PROPERTY "Expected method or property"
|
||||
#define TXT_EXPECTED_ONE_OF "Expected one of: "
|
||||
#define TXT_EXPECTED_OPERATOR "Expected operator"
|
||||
#define TXT_EXPECTED_s_OR_s "Expected '%s' or '%s'"
|
||||
#define TXT_EXPECTED_POST_OPERATOR "Expected post operator"
|
||||
#define TXT_EXPECTED_PRE_OPERATOR "Expected pre operator"
|
||||
#define TXT_EXPECTED_STRING "Expected string"
|
||||
#define TXT_EXPR_DOESNT_EVAL_TO_FUNC "Expression doesn't evaluate to a function"
|
||||
#define TXT_EXPR_MUST_BE_BOOL "Expression must be of boolean type"
|
||||
#define TXT_ELSE_WITH_EMPTY_STATEMENT "Else with empty statement"
|
||||
#define TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED "Empty list element is not allowed"
|
||||
#define TXT_EMPTY_SWITCH "Empty switch statement"
|
||||
#define TXT_EXPECTED_s "Expected '%s'"
|
||||
#define TXT_EXPECTED_CONSTANT "Expected constant"
|
||||
#define TXT_EXPECTED_DATA_TYPE "Expected data type"
|
||||
#define TXT_EXPECTED_EXPRESSION_VALUE "Expected expression value"
|
||||
#define TXT_EXPECTED_IDENTIFIER "Expected identifier"
|
||||
#define TXT_EXPECTED_LIST "Expected a list enclosed by { } to match pattern"
|
||||
#define TXT_EXPECTED_METHOD_OR_PROPERTY "Expected method or property"
|
||||
#define TXT_EXPECTED_ONE_OF "Expected one of: "
|
||||
#define TXT_EXPECTED_OPERATOR "Expected operator"
|
||||
#define TXT_EXPECTED_s_OR_s "Expected '%s' or '%s'"
|
||||
#define TXT_EXPECTED_POST_OPERATOR "Expected post operator"
|
||||
#define TXT_EXPECTED_PRE_OPERATOR "Expected pre operator"
|
||||
#define TXT_EXPECTED_STRING "Expected string"
|
||||
#define TXT_EXPR_DOESNT_EVAL_TO_FUNC "Expression doesn't evaluate to a function"
|
||||
#define TXT_EXPR_MUST_BE_BOOL "Expression must be of boolean type"
|
||||
|
||||
#define TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s "Failed while compiling default arg for parameter %d in function '%s'"
|
||||
#define TXT_FAILED_TO_CREATE_TEMP_OBJ "Previous error occurred while attempting to create a temporary copy of object"
|
||||
@ -107,32 +118,42 @@
|
||||
|
||||
#define TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP "It is not allowed to perform a handle assignment on a non-handle property"
|
||||
#define TXT_HANDLE_COMPARISON "The operand is implicitly converted to handle in order to compare them"
|
||||
#define TXT_HANDLE_OF_HANDLE_IS_NOT_ALLOWED "Handle to handle is not allowed"
|
||||
#define TXT_s_HIDES_VAR_IN_OUTER_SCOPE "Variable '%s' hides another variable of same name in outer scope"
|
||||
|
||||
#define TXT_IDENTIFIER_s_NOT_DATA_TYPE "Identifier '%s' is not a data type"
|
||||
#define TXT_IF_WITH_EMPTY_STATEMENT "If with empty statement"
|
||||
#define TXT_ILLEGAL_MEMBER_TYPE "Illegal member type"
|
||||
#define TXT_IDENTIFIER_s_NOT_DATA_TYPE "Identifier '%s' is not a data type"
|
||||
#define TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS "Identifier '%s' is not a data type in global namespace"
|
||||
#define TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s "Identifier '%s' is not a data type in namespace '%s' or parent"
|
||||
#define TXT_IF_WITH_EMPTY_STATEMENT "If with empty statement"
|
||||
#define TXT_ILLEGAL_MEMBER_TYPE "Illegal member type"
|
||||
// TODO: Should be TXT_ILLEGAL_OPERATION_ON_s
|
||||
#define TXT_ILLEGAL_OPERATION "Illegal operation on this datatype"
|
||||
#define TXT_ILLEGAL_OPERATION_ON_s "Illegal operation on '%s'"
|
||||
#define TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST "Illegal target type for reference cast"
|
||||
#define TXT_ILLEGAL_VARIABLE_NAME_s "Illegal variable name '%s'."
|
||||
#define TXT_INIT_LIST_CANNOT_BE_USED_WITH_s "Initialization lists cannot be used with '%s'"
|
||||
#define TXT_ILLEGAL_OPERATION "Illegal operation on this datatype"
|
||||
#define TXT_ILLEGAL_OPERATION_ON_s "Illegal operation on '%s'"
|
||||
#define TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST "Illegal target type for reference cast"
|
||||
#define TXT_ILLEGAL_VARIABLE_NAME_s "Illegal variable name '%s'."
|
||||
#define TXT_INHERITED_PRIVATE_PROP_ACCESS_s "Illegal access to inherited private property '%s'"
|
||||
#define TXT_INIT_LIST_CANNOT_BE_USED_WITH_s "Initialization lists cannot be used with '%s'"
|
||||
#define TXT_INSTANCING_INVLD_TMPL_TYPE_s_s "Attempting to instantiate invalid template type '%s<%s>'"
|
||||
#define TXT_INSTEAD_FOUND_s "Instead found '%s'"
|
||||
#define TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED "Interface '%s' cannot be instantiated"
|
||||
#define TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE "Interfaces can only implement other interfaces"
|
||||
#define TXT_INVALID_BREAK "Invalid 'break'"
|
||||
#define TXT_INVALID_CHAR_LITERAL "Invalid character literal"
|
||||
#define TXT_INVALID_CONTINUE "Invalid 'continue'"
|
||||
#define TXT_INVALID_ESCAPE_SEQUENCE "Invalid escape sequence"
|
||||
#define TXT_INVALID_OP_ON_METHOD "Invalid operation on method"
|
||||
#define TXT_INVALID_REF_PROP_ACCESS "Invalid reference. Property accessors cannot be used in combined read/write operations"
|
||||
#define TXT_INVALID_SCOPE "Invalid scope resolution"
|
||||
#define TXT_INVALID_TYPE "Invalid type"
|
||||
#define TXT_INVALID_UNICODE_FORMAT_EXPECTED_d "Invalid unicode escape sequence, expected %d hex digits"
|
||||
#define TXT_INVALID_UNICODE_VALUE "Invalid unicode code point"
|
||||
#define TXT_INVALID_UNICODE_SEQUENCE_IN_SRC "Invalid unicode sequence in source"
|
||||
#define TXT_INVALID_BREAK "Invalid 'break'"
|
||||
#define TXT_INVALID_CHAR_LITERAL "Invalid character literal"
|
||||
#define TXT_INVALID_CONTINUE "Invalid 'continue'"
|
||||
#define TXT_INVALID_ESCAPE_SEQUENCE "Invalid escape sequence"
|
||||
#define TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME "Invalid expression: ambiguous name"
|
||||
#define TXT_INVALID_OP_ON_METHOD "Invalid operation on method"
|
||||
#define TXT_INVALID_REF_PROP_ACCESS "Invalid reference. Property accessors cannot be used in combined read/write operations"
|
||||
#define TXT_INVALID_SCOPE "Invalid scope resolution"
|
||||
#define TXT_INVALID_TYPE "Invalid type"
|
||||
#define TXT_INVALID_UNICODE_FORMAT_EXPECTED_d "Invalid unicode escape sequence, expected %d hex digits"
|
||||
#define TXT_INVALID_UNICODE_VALUE "Invalid unicode code point"
|
||||
#define TXT_INVALID_UNICODE_SEQUENCE_IN_SRC "Invalid unicode sequence in source"
|
||||
|
||||
#define TXT_METHOD_CANNOT_OVERRIDE_s "Method '%s' declared as final and cannot be overridden"
|
||||
#define TXT_METHOD_CANT_HAVE_NAME_OF_CLASS "The method cannot be named with the class name"
|
||||
#define TXT_METHOD_s_DOES_NOT_OVERRIDE "Method '%s' marked as override but does not replace any base class or interface method"
|
||||
#define TXT_METHOD_s_s_HAS_NO_RETURN_TYPE "Method '%s::%s' is missing the return type, nor is it the same name as object to be a constructor"
|
||||
#define TXT_MISSING_IMPLEMENTATION_OF_s "Missing implementation of '%s'"
|
||||
#define TXT_MIXIN_CANNOT_BE_DECLARED_AS_s "Mixin class cannot be declared as '%s'"
|
||||
#define TXT_MIXIN_CANNOT_HAVE_CONSTRUCTOR "Mixin classes cannot have constructors or destructors"
|
||||
@ -155,14 +176,15 @@
|
||||
#define TXT_NAME_CONFLICT_s_OBJ_PROPERTY "Name conflict. '%s' is an object property."
|
||||
#define TXT_NAME_CONFLICT_s_METHOD "Name conflict. '%s' is a class method."
|
||||
#define TXT_NAME_CONFLICT_s_ALREADY_USED "Name conflict. '%s' is already used."
|
||||
#define TXT_NAMED_ARGS_WITH_OLD_SYNTAX "Detected named argument with old syntax"
|
||||
#define TXT_NO_APPROPRIATE_INDEX_OPERATOR "No appropriate indexing operator found"
|
||||
#define TXT_NO_APPROPRIATE_OPASSIGN "No appropriate opAssign method found"
|
||||
#define TXT_NO_APPROPRIATE_OPHNDLASSIGN_s "No appropriate opHndlAssign method found in '%s' for handle assignment"
|
||||
#define TXT_NO_APPROPRIATE_OPEQUALS "No appropriate opEquals method found"
|
||||
#define TXT_NO_CONVERSION_s_TO_s "No conversion from '%s' to '%s' available."
|
||||
#define TXT_NO_CONVERSION_s_TO_MATH_TYPE "No conversion from '%s' to math type available."
|
||||
#define TXT_NO_DEFAULT_ARRAY_TYPE "The application doesn't support the default array type."
|
||||
#define TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s "No default constructor for object of type '%s'."
|
||||
#define TXT_NO_DEFAULT_COPY_OP_FOR_s "There is no copy operator for the type '%s' available."
|
||||
#define TXT_NO_DEFAULT_COPY_OP_FOR_s "No appropriate opAssign method found in '%s' for value assignment"
|
||||
#define TXT_NO_COPY_CONSTRUCTOR_FOR_s "No copy constructor for object of type '%s'."
|
||||
#define TXT_NO_MATCHING_SIGNATURES_TO_s "No matching signatures to '%s'"
|
||||
#define TXT_NO_MATCHING_OP_FOUND_FOR_TYPE_s "No matching operator that takes the type '%s' found"
|
||||
@ -181,18 +203,22 @@
|
||||
#define TXT_NOT_VALID_LVALUE "Not a valid lvalue"
|
||||
#define TXT_NOTHING_WAS_BUILT "Nothing was built in the module"
|
||||
|
||||
#define TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP "Type '%s' doesn't support the indexing operator"
|
||||
#define TXT_OBJECT_HANDLE_NOT_SUPPORTED "Object handle is not supported for this type"
|
||||
#define TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT "Only object types that support object handles can use &inout. Use &in or &out instead"
|
||||
#define TXT_ONLY_ONE_ARGUMENT_IN_CAST "A cast operator has one argument"
|
||||
#define TXT_ONLY_ONE_FUNCTION_ALLOWED "The code must contain one and only one function"
|
||||
#define TXT_ONLY_ONE_VARIABLE_ALLOWED "The code must contain one and only one global variable"
|
||||
#define TXT_OPERANDS_MUST_BE_HANDLES "Both operands must be handles when comparing identity"
|
||||
#define TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP "Type '%s' doesn't support the indexing operator"
|
||||
#define TXT_OBJECT_HANDLE_NOT_SUPPORTED "Object handle is not supported for this type"
|
||||
#define TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT "Only object types that support object handles can use &inout. Use &in or &out instead"
|
||||
#define TXT_ONLY_ONE_ARGUMENT_IN_CAST "A cast operator has one argument"
|
||||
#define TXT_ONLY_ONE_FUNCTION_ALLOWED "The code must contain one and only one function"
|
||||
#define TXT_ONLY_ONE_VARIABLE_ALLOWED "The code must contain one and only one global variable"
|
||||
#define TXT_OPERANDS_MUST_BE_HANDLES "Both operands must be handles when comparing identity"
|
||||
#define TXT_OVERLOAD_CONFLICTS_DUE_TO_DEFAULT_ARGS "The overloaded functions are identical on initial parameters without default arguments"
|
||||
|
||||
#define TXT_PARAMETER_ALREADY_DECLARED "Parameter already declared"
|
||||
#define TXT_PARAMETER_CANT_BE_s "Parameter type can't be '%s', because the type cannot be instanciated."
|
||||
#define TXT_PARAMETER_CANT_BE_s "Parameter type can't be '%s', because the type cannot be instantiated."
|
||||
#define TXT_POS_ARG_AFTER_NAMED_ARG "Positional arguments cannot be passed after named arguments"
|
||||
#define TXT_PRIVATE_METHOD_CALL_s "Illegal call to private method '%s'"
|
||||
#define TXT_PRIVATE_PROP_ACCESS_s "Illegal access to private property '%s'"
|
||||
#define TXT_PROTECTED_METHOD_CALL_s "Illegal call to protected method '%s'"
|
||||
#define TXT_PROTECTED_PROP_ACCESS_s "Illegal access to protected property '%s'"
|
||||
#define TXT_PROPERTY_ACCESSOR_DISABLED "Property accessors have been disabled by the application"
|
||||
#define TXT_PROPERTY_ACCESSOR_MUST_BE_IMPLEMENTED "Property accessor must be implemented"
|
||||
#define TXT_PROPERTY_CANT_BE_CONST "Class properties cannot be declared as const"
|
||||
@ -200,6 +226,7 @@
|
||||
#define TXT_PROPERTY_HAS_NO_SET_ACCESSOR "The property has no set accessor"
|
||||
#define TXT_PROPERTY_WITHOUT_ACCESSOR "Virtual property must have at least one get or set accessor"
|
||||
|
||||
#define TXT_REF_CANT_BE_TO_LOCAL_VAR "Resulting reference cannot be returned. Returned references must not refer to local variables."
|
||||
#define TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM "Resulting reference cannot be returned. There are deferred arguments that may invalidate it."
|
||||
#define TXT_REF_CANT_BE_RETURNED_LOCAL_VARS "Resulting reference cannot be returned. The expression uses objects that during cleanup may invalidate it."
|
||||
#define TXT_REF_IS_READ_ONLY "Reference is read-only"
|
||||
@ -226,13 +253,14 @@
|
||||
#define TXT_TOO_MANY_VALUES_FOR_LIST "Too many values to match pattern"
|
||||
#define TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE "Type '%s' is not available for this module"
|
||||
|
||||
#define TXT_UNEXPECTED_END_OF_FILE "Unexpected end of file"
|
||||
#define TXT_UNEXPECTED_TOKEN_s "Unexpected token '%s'"
|
||||
#define TXT_UNINITIALIZED_GLOBAL_VAR_s "Use of uninitialized global variable '%s'."
|
||||
#define TXT_UNKNOWN_SCOPE_s "Unknown scope '%s'"
|
||||
#define TXT_UNREACHABLE_CODE "Unreachable code"
|
||||
#define TXT_UNEXPECTED_END_OF_FILE "Unexpected end of file"
|
||||
#define TXT_UNEXPECTED_TOKEN_s "Unexpected token '%s'"
|
||||
#define TXT_UNEXPECTED_VAR_DECL "Unexpected variable declaration"
|
||||
#define TXT_UNINITIALIZED_GLOBAL_VAR_s "Use of uninitialized global variable '%s'."
|
||||
#define TXT_UNKNOWN_SCOPE_s "Unknown scope '%s'"
|
||||
#define TXT_UNREACHABLE_CODE "Unreachable code"
|
||||
#define TXT_UNRECOGNIZED_VIRTUAL_PROPERTY_NODE "Virtual property contains unrecognized aspect"
|
||||
#define TXT_UNUSED_SCRIPT_NODE "Unused script node"
|
||||
#define TXT_UNUSED_SCRIPT_NODE "Unused script node"
|
||||
|
||||
#define TXT_VALUE_TOO_LARGE_FOR_TYPE "Value is too large for data type"
|
||||
#define TXT_VOID_CANT_BE_OPERAND "Void cannot be an operand in expressions"
|
||||
@ -247,7 +275,7 @@
|
||||
|
||||
// Global variable initialization
|
||||
|
||||
#define TXT_FAILED_TO_INITIALIZE_s "Failed to initialize global variable '%s'"
|
||||
#define TXT_FAILED_TO_INITIALIZE_s "Failed to initialize global variable '%s'"
|
||||
#define TXT_EXCEPTION_s_IN_s "Exception '%s' in '%s'"
|
||||
|
||||
// Engine message
|
||||
@ -271,12 +299,12 @@
|
||||
#define TXT_d_GC_CANNOT_FREE_OBJ_OF_TYPE_s "Object {%d}. GC cannot destroy an object of type '%s' as it doesn't know how many references to there are."
|
||||
#define TXT_d_GC_CANNOT_FREE_OBJ_OF_TYPE_s_REF_COUNT_d "Object {%d}. GC cannot destroy an object of type '%s' as it can't see all references. Current ref count is %d."
|
||||
#define TXT_OBJECT_TYPE_s_DOESNT_EXIST "Object type '%s' doesn't exist"
|
||||
#define TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER "Cannot register. The template type instance '%s' has already been generated."
|
||||
#define TXT_TEMPLATE_TYPE_s_DOESNT_EXIST "Template type '%s' doesn't exist"
|
||||
#define TXT_TEMPLATE_SUBTYPE_s_DOESNT_EXIST "Template subtype '%s' doesn't exist"
|
||||
#define TXT_TEMPLATE_LIST_FACTORY_EXPECTS_2_REF_PARAMS "Template list factory expects two reference parameters. The last is the pointer to the initialization buffer"
|
||||
#define TXT_LIST_FACTORY_EXPECTS_1_REF_PARAM "List factory expects only one reference parameter. The pointer to the initialization buffer will be passed in this parameter"
|
||||
#define TXT_FAILED_READ_SUBTYPE_OF_TEMPLATE_s "Failed to read subtype of template type '%s'"
|
||||
#define TXT_INSTANCING_INVLD_TMPL_TYPE_s_s "Attempting to instanciate invalid template type '%s<%s>'"
|
||||
#define TXT_FAILED_IN_FUNC_s_d "Failed in call to function '%s' (Code: %d)"
|
||||
#define TXT_FAILED_IN_FUNC_s_WITH_s_d "Failed in call to function '%s' with '%s' (Code: %d)"
|
||||
#define TXT_FAILED_IN_FUNC_s_WITH_s_AND_s_d "Failed in call to function '%s' with '%s' and '%s' (Code: %d)"
|
||||
@ -287,6 +315,10 @@
|
||||
#define TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d "The function in previous message is named '%s'. The func type is %d"
|
||||
#define TXT_RESURRECTING_SCRIPTOBJECT_s "The script object of type '%s' is being resurrected illegally during destruction"
|
||||
#define TXT_INVALID_BYTECODE_d "LoadByteCode failed. The bytecode is invalid. Number of bytes read from stream: %d"
|
||||
#define TXT_NO_JIT_IN_FUNC_s "Function '%s' appears to have been compiled without JIT entry points"
|
||||
#define TXT_ENGINE_REF_COUNT_ERROR_DURING_SHUTDOWN "Uh oh! The engine's reference count is increasing while it is being destroyed. Make sure references needed for clean-up are immediately released"
|
||||
#define TXT_MODULE_IS_IN_USE "The module is still in use and cannot be rebuilt. Discard it and request another module"
|
||||
#define TXT_EXTRNL_REF_TO_MODULE_s "There is an external reference to an object in module '%s', preventing it from being deleted"
|
||||
|
||||
// Internal names
|
||||
|
||||
|
@ -109,7 +109,7 @@ AS_API void asReleaseSharedLock()
|
||||
|
||||
//======================================================================
|
||||
|
||||
#if !defined(AS_NO_THREADS) && defined(_MSC_VER) && defined(AS_WINDOWS_THREADS) && !(WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP)
|
||||
#if !defined(AS_NO_THREADS) && defined(_MSC_VER) && defined(AS_WINDOWS_THREADS) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
__declspec(thread) asCThreadLocalData *asCThreadManager::tld = 0;
|
||||
#endif
|
||||
|
||||
@ -126,7 +126,7 @@ asCThreadManager::asCThreadManager()
|
||||
pthread_key_create(&pKey, 0);
|
||||
tlsKey = (asDWORD)pKey;
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
#if defined(_MSC_VER) && !(WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP)
|
||||
#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
tld = 0;
|
||||
#else
|
||||
tlsKey = (asDWORD)TlsAlloc();
|
||||
@ -211,7 +211,7 @@ asCThreadManager::~asCThreadManager()
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_key_delete((pthread_key_t)tlsKey);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
#if defined(_MSC_VER) && !(WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP)
|
||||
#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
tld = 0;
|
||||
#else
|
||||
TlsFree((DWORD)tlsKey);
|
||||
@ -235,7 +235,7 @@ int asCThreadManager::CleanupLocalData()
|
||||
#if defined AS_POSIX_THREADS
|
||||
asCThreadLocalData *tld = (asCThreadLocalData*)pthread_getspecific((pthread_key_t)threadManager->tlsKey);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
#if !defined(_MSC_VER) || (WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP)
|
||||
#if !defined(_MSC_VER) || !(WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
asCThreadLocalData *tld = (asCThreadLocalData*)TlsGetValue((DWORD)threadManager->tlsKey);
|
||||
#endif
|
||||
#endif
|
||||
@ -249,7 +249,7 @@ int asCThreadManager::CleanupLocalData()
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_setspecific((pthread_key_t)threadManager->tlsKey, 0);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
#if defined(_MSC_VER) && !(WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP)
|
||||
#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
tld = 0;
|
||||
#else
|
||||
TlsSetValue((DWORD)threadManager->tlsKey, 0);
|
||||
@ -289,7 +289,7 @@ asCThreadLocalData *asCThreadManager::GetLocalData()
|
||||
pthread_setspecific((pthread_key_t)threadManager->tlsKey, tld);
|
||||
}
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
#if defined(_MSC_VER) && !(WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP)
|
||||
#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
if( tld == 0 )
|
||||
tld = asNEW(asCThreadLocalData)();
|
||||
#else
|
||||
@ -329,10 +329,13 @@ asCThreadCriticalSection::asCThreadCriticalSection()
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_mutex_init(&cs, 0);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
// Only the Ex version is available on Windows Store
|
||||
InitializeCriticalSectionEx(&cs, 4000, 0);
|
||||
#else
|
||||
InitializeCriticalSection(&cs);
|
||||
// Only the non-Ex version is available on WinXP and older
|
||||
// MinGW also only defines this version
|
||||
InitializeCriticalSection(&cs);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@ -382,7 +385,9 @@ asCThreadReadWriteLock::asCThreadReadWriteLock()
|
||||
asASSERT( r == 0 );
|
||||
UNUSED_VAR(r);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
// Only the Ex versions are available on Windows Store
|
||||
|
||||
// Create a semaphore to allow up to maxReaders simultaneous readers
|
||||
readLocks = CreateSemaphoreExW(NULL, maxReaders, maxReaders, 0, 0, 0);
|
||||
// Create a critical section to synchronize writers
|
||||
|
@ -70,7 +70,7 @@ protected:
|
||||
int refCount;
|
||||
|
||||
#ifndef AS_NO_THREADS
|
||||
#if defined(_MSC_VER) && defined(AS_WINDOWS_THREADS) && !(WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP)
|
||||
#if defined(_MSC_VER) && defined(AS_WINDOWS_THREADS) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
// On Windows Store we must use MSVC specific thread variables for thread
|
||||
// local storage, as the TLS API isn't available. On desktop we can't use
|
||||
// this as it may cause problems if the library is used in a dll.
|
||||
|
@ -171,8 +171,10 @@ enum eTokenType
|
||||
ttEnum, // enum
|
||||
ttCast, // cast
|
||||
ttPrivate, // private
|
||||
ttProtected, // protected
|
||||
ttNamespace, // namespace
|
||||
ttMixin // mixin
|
||||
ttMixin, // mixin
|
||||
ttAuto // auto
|
||||
};
|
||||
|
||||
struct sTokenWord
|
||||
@ -239,6 +241,7 @@ sTokenWord const tokenWords[] =
|
||||
asTokenDef("!is" , ttNotIs),
|
||||
asTokenDef("@" , ttHandle),
|
||||
asTokenDef("and" , ttAnd),
|
||||
asTokenDef("auto" , ttAuto),
|
||||
asTokenDef("bool" , ttBool),
|
||||
asTokenDef("break" , ttBreak),
|
||||
asTokenDef("case" , ttCase),
|
||||
@ -277,6 +280,7 @@ sTokenWord const tokenWords[] =
|
||||
asTokenDef("or" , ttOr),
|
||||
asTokenDef("out" , ttOut),
|
||||
asTokenDef("private" , ttPrivate),
|
||||
asTokenDef("protected" , ttProtected),
|
||||
asTokenDef("return" , ttReturn),
|
||||
asTokenDef("switch" , ttSwitch),
|
||||
asTokenDef("true" , ttTrue),
|
||||
@ -306,6 +310,7 @@ const char * const FINAL_TOKEN = "final";
|
||||
const char * const OVERRIDE_TOKEN = "override";
|
||||
const char * const GET_TOKEN = "get";
|
||||
const char * const SET_TOKEN = "set";
|
||||
const char * const ABSTRACT_TOKEN = "abstract";
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -223,7 +223,7 @@ bool asCTokenizer::IsComment(const char *source, size_t sourceLength, size_t &to
|
||||
}
|
||||
|
||||
tokenType = ttOnelineComment;
|
||||
tokenLength = n+1;
|
||||
tokenLength = n < sourceLength ? n+1 : n;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -443,7 +443,8 @@ bool asCTokenizer::IsKeyWord(const char *source, size_t sourceLength, size_t &to
|
||||
// and the tokens "!" and "isTrue" in the "!isTrue" expression.
|
||||
if( wlen < sourceLength &&
|
||||
((source[wlen-1] >= 'a' && source[wlen-1] <= 'z') ||
|
||||
(source[wlen-1] >= 'A' && source[wlen-1] <= 'Z')) &&
|
||||
(source[wlen-1] >= 'A' && source[wlen-1] <= 'Z') ||
|
||||
(source[wlen-1] >= '0' && source[wlen-1] <= '9')) &&
|
||||
((source[wlen] >= 'a' && source[wlen] <= 'z') ||
|
||||
(source[wlen] >= 'A' && source[wlen] <= 'Z') ||
|
||||
(source[wlen] >= '0' && source[wlen] <= '9') ||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -54,6 +54,7 @@ asCTypeInfo::asCTypeInfo()
|
||||
qwordValue = 0;
|
||||
isLValue = false;
|
||||
isVoidExpression = false;
|
||||
isRefToLocal = false;
|
||||
}
|
||||
|
||||
void asCTypeInfo::Set(const asCDataType &dt)
|
||||
@ -68,6 +69,7 @@ void asCTypeInfo::Set(const asCDataType &dt)
|
||||
qwordValue = 0;
|
||||
isLValue = false;
|
||||
isVoidExpression = false;
|
||||
isRefToLocal = false;
|
||||
}
|
||||
|
||||
void asCTypeInfo::SetVariable(const asCDataType &dt, int stackOffset, bool isTemporary)
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
Copyright (c) 2003-2014 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
@ -74,7 +74,8 @@ struct asCTypeInfo
|
||||
bool isVariable : 1;
|
||||
bool isExplicitHandle : 1;
|
||||
bool isVoidExpression : 1;
|
||||
short dummy : 10;
|
||||
bool isRefToLocal : 1; // The reference may be to a local variable
|
||||
short dummy : 9;
|
||||
short stackOffset;
|
||||
union
|
||||
{
|
||||
|
@ -151,20 +151,21 @@ irr::core::stringw Achievement::getProgressAsString() const
|
||||
* \param key The key whose value is increased.
|
||||
* \param increase Amount to add to the value of this key.
|
||||
*/
|
||||
void Achievement::increase(const std::string & key, int increase)
|
||||
void Achievement::increase(const std::string & key,
|
||||
const std::string &goal_key, int increase)
|
||||
{
|
||||
std::map<std::string, int>::iterator it;
|
||||
it = m_progress_map.find(key);
|
||||
if (it != m_progress_map.end())
|
||||
{
|
||||
it->second += increase;
|
||||
if (it->second > m_achievement_info->getGoalValue(key))
|
||||
it->second = m_achievement_info->getGoalValue(key);
|
||||
if (it->second > m_achievement_info->getGoalValue(goal_key))
|
||||
it->second = m_achievement_info->getGoalValue(goal_key);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (increase>m_achievement_info->getGoalValue(key))
|
||||
increase = m_achievement_info->getGoalValue(key);
|
||||
if (increase>m_achievement_info->getGoalValue(goal_key))
|
||||
increase = m_achievement_info->getGoalValue(goal_key);
|
||||
m_progress_map[key] = increase;
|
||||
}
|
||||
check();
|
||||
|
@ -65,7 +65,8 @@ public:
|
||||
virtual void load(const XMLNode *node);
|
||||
virtual void save(UTFWriter &out);
|
||||
virtual int getValue(const std::string & key);
|
||||
void increase(const std::string & key, int increase = 1);
|
||||
void increase(const std::string & key, const std::string &goal_key,
|
||||
int increase = 1);
|
||||
|
||||
virtual void reset();
|
||||
virtual irr::core::stringw getProgressAsString() const;
|
||||
|
@ -113,7 +113,7 @@ public:
|
||||
irr::core::stringw getDescription() const { return _(m_description.c_str()); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the name of this achievement. */
|
||||
irr::core::stringw getName() const { return _(m_name.c_str()); }
|
||||
irr::core::stringw getName() const { return _LTR(m_name.c_str()); }
|
||||
// ------------------------------------------------------------------------
|
||||
bool needsResetAfterRace() const { return m_reset_type == AFTER_RACE; }
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -143,16 +143,27 @@ public:
|
||||
} // getCurrentAchievementsStatus
|
||||
// ------------------------------------------------------------------------
|
||||
/** A handy shortcut to increase points for an achievement key of the
|
||||
* current player. */
|
||||
static void increaseAchievement(unsigned int index, const std::string &key,
|
||||
int increase = 1)
|
||||
* current player.
|
||||
* \param achievement_id The achievement id.
|
||||
* \param key The key of the current value to increase.
|
||||
* \param increase How much to increase the current value.
|
||||
* \param goal_key Optional: The goal key to compare the current value
|
||||
* with. If not set, defaults to key.
|
||||
*/
|
||||
static void increaseAchievement(unsigned int achievement_id,
|
||||
const std::string &key,
|
||||
int increase = 1,
|
||||
const std::string &goal_key="")
|
||||
{
|
||||
Achievement *a = getCurrentAchievementsStatus()->getAchievement(index);
|
||||
Achievement *a = getCurrentAchievementsStatus()
|
||||
->getAchievement(achievement_id);
|
||||
if (!a)
|
||||
{
|
||||
Log::fatal("PlayerManager", "Achievement '%d' not found.", index);
|
||||
Log::fatal("PlayerManager", "Achievement '%d' not found.",
|
||||
achievement_id);
|
||||
}
|
||||
a->increase(key, increase);
|
||||
a->increase(key, goal_key.empty() ? key : goal_key, increase);
|
||||
|
||||
} // increaseAchievement
|
||||
// ------------------------------------------------------------------------
|
||||
}; // PlayerManager
|
||||
|
@ -356,8 +356,13 @@ void IrrDriver::initDevice()
|
||||
|
||||
video::IVideoModeList* modes = m_device->getVideoModeList();
|
||||
const core::dimension2d<u32> ssize = modes->getDesktopResolution();
|
||||
if (UserConfigParams::m_width > (int)ssize.Width ||
|
||||
UserConfigParams::m_height > (int)ssize.Height)
|
||||
|
||||
if (ssize.Width < 1 || ssize.Height < 1)
|
||||
{
|
||||
Log::warn("irr_driver", "Unknown desktop resolution.");
|
||||
}
|
||||
else if (UserConfigParams::m_width > (int)ssize.Width ||
|
||||
UserConfigParams::m_height > (int)ssize.Height)
|
||||
{
|
||||
Log::warn("irr_driver", "The window size specified in "
|
||||
"user config is larger than your screen!");
|
||||
@ -365,13 +370,13 @@ void IrrDriver::initDevice()
|
||||
UserConfigParams::m_height = (int)ssize.Height;
|
||||
}
|
||||
|
||||
core::dimension2d<u32> res = core::dimension2du(UserConfigParams::m_width,
|
||||
UserConfigParams::m_height);
|
||||
|
||||
if (UserConfigParams::m_fullscreen)
|
||||
{
|
||||
if (modes->getVideoModeCount() > 0)
|
||||
{
|
||||
core::dimension2d<u32> res = core::dimension2du(
|
||||
UserConfigParams::m_width,
|
||||
UserConfigParams::m_height);
|
||||
res = modes->getVideoModeResolution(res, res);
|
||||
|
||||
UserConfigParams::m_width = res.Width;
|
||||
@ -379,13 +384,20 @@ void IrrDriver::initDevice()
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::verbose("irr_driver", "Cannot get information about "
|
||||
"resolutions. Try to use the default one.");
|
||||
UserConfigParams::m_width = MIN_SUPPORTED_WIDTH;
|
||||
UserConfigParams::m_height = MIN_SUPPORTED_HEIGHT;
|
||||
Log::warn("irr_driver", "Cannot get information about "
|
||||
"resolutions. Disable fullscreen.");
|
||||
UserConfigParams::m_fullscreen = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (UserConfigParams::m_width < 1 || UserConfigParams::m_height < 1)
|
||||
{
|
||||
Log::warn("irr_driver", "Invalid window size. "
|
||||
"Try to use the default one.");
|
||||
UserConfigParams::m_width = MIN_SUPPORTED_WIDTH;
|
||||
UserConfigParams::m_height = MIN_SUPPORTED_HEIGHT;
|
||||
}
|
||||
|
||||
m_device->closeDevice();
|
||||
m_video_driver = NULL;
|
||||
m_gui_env = NULL;
|
||||
|
@ -74,7 +74,7 @@ void BubbleWidget::replaceText()
|
||||
EGUI_ALIGNMENT align = EGUIA_UPPERLEFT;
|
||||
if (m_properties[PROP_TEXT_ALIGN] == "center") align = EGUIA_CENTER;
|
||||
else if (m_properties[PROP_TEXT_ALIGN] == "right") align = EGUIA_LOWERRIGHT;
|
||||
else if (translations->isRTLLanguage()) align = EGUIA_LOWERRIGHT;
|
||||
else if (translations->isRTLText(message)) align = EGUIA_LOWERRIGHT;
|
||||
|
||||
EGUI_ALIGNMENT valign = EGUIA_CENTER ; //TODO: make label v-align configurable through XML file?
|
||||
|
||||
@ -90,7 +90,7 @@ void BubbleWidget::replaceText()
|
||||
m_expanded_size.LowerRightCorner.Y += additionalNeededSize/2 + 10;
|
||||
|
||||
// reduce text to fit in the available space if it's too long
|
||||
if (translations->isRTLLanguage())
|
||||
if (translations->isRTLText(message))
|
||||
{
|
||||
while (text_height > m_shrinked_size.getHeight() && message.size() > 10)
|
||||
{
|
||||
|
@ -346,6 +346,7 @@ void PlayerKartWidget::add()
|
||||
name = m_associated_player->getProfile()->getName();
|
||||
if (m_associated_user)
|
||||
name = m_associated_user->getUserName();
|
||||
core::stringw label = translations->fribidize(name);
|
||||
|
||||
if (m_parent_screen->m_multiplayer)
|
||||
{
|
||||
@ -359,21 +360,21 @@ void PlayerKartWidget::add()
|
||||
{
|
||||
// I18N: 'handicapped' indicates that per-player handicaps are
|
||||
// activated for this kart (i.e. it will drive slower)
|
||||
label = _("%s (handicapped)", label);
|
||||
label = _("%s (handicapped)", name);
|
||||
m_player_ident_spinner->addLabel(label);
|
||||
}
|
||||
}
|
||||
|
||||
// select the right player profile in the spinner
|
||||
m_player_ident_spinner->setValue(name);
|
||||
m_player_ident_spinner->setValue(label);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_player_ident_spinner->addLabel(name);
|
||||
m_player_ident_spinner->addLabel(label);
|
||||
m_player_ident_spinner->setVisible(false);
|
||||
}
|
||||
|
||||
assert(m_player_ident_spinner->getStringValue() == name);
|
||||
assert(m_player_ident_spinner->getStringValue() == label);
|
||||
} // add
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -547,6 +547,8 @@ void cmdLineHelp()
|
||||
" stdout.log.\n"
|
||||
" --console Write messages in the console and files\n"
|
||||
" -h, --help Show this help.\n"
|
||||
" --log=N Set the verbosity to a value between\n"
|
||||
" 0 (Debug) and 5 (Only Fatal messages)\n"
|
||||
"\n"
|
||||
"You can visit SuperTuxKart's homepage at "
|
||||
"http://supertuxkart.sourceforge.net\n\n",
|
||||
|
@ -63,6 +63,8 @@ PhysicalObject::Settings::Settings(const XMLNode &xml_node)
|
||||
xml_node.get("reset", &m_crash_reset );
|
||||
xml_node.get("explode", &m_knock_kart );
|
||||
xml_node.get("flatten", &m_flatten_kart);
|
||||
xml_node.get("on-kart-collision", &m_on_kart_collision);
|
||||
xml_node.get("on-item-collision", &m_on_item_collision);
|
||||
m_reset_when_too_low =
|
||||
xml_node.get("reset-when-below", &m_reset_height) == 1;
|
||||
|
||||
@ -140,6 +142,8 @@ PhysicalObject::PhysicalObject(bool is_dynamic,
|
||||
m_flatten_kart = settings.m_flatten_kart;
|
||||
m_reset_when_too_low = settings.m_reset_when_too_low;
|
||||
m_reset_height = settings.m_reset_height;
|
||||
m_on_kart_collision = settings.m_on_kart_collision;
|
||||
m_on_item_collision = settings.m_on_item_collision;
|
||||
|
||||
m_init_pos.setIdentity();
|
||||
Vec3 radHpr(m_init_hpr);
|
||||
|
@ -67,6 +67,14 @@ public:
|
||||
/** If the item is below that height, it is reset (when
|
||||
* m_reset_when_too_low is true). */
|
||||
float m_reset_height;
|
||||
/** If non-empty, the name of the scripting function to call
|
||||
* when a kart collides with this object
|
||||
*/
|
||||
std::string m_on_kart_collision;
|
||||
/** If non-empty, the name of the scripting function to call
|
||||
* when a (flyable) item collides with this object
|
||||
*/
|
||||
std::string m_on_item_collision;
|
||||
private:
|
||||
void init();
|
||||
public:
|
||||
@ -140,7 +148,14 @@ private:
|
||||
/** If m_reset_when_too_low this object is set back to its start
|
||||
* position if its height is below this value. */
|
||||
float m_reset_height;
|
||||
|
||||
/** If non-empty, the name of the scripting function to call
|
||||
* when a kart collides with this object
|
||||
*/
|
||||
std::string m_on_kart_collision;
|
||||
/** If non-empty, the name of the scripting function to call
|
||||
* when a (flyable) item collides with this object
|
||||
*/
|
||||
std::string m_on_item_collision;
|
||||
/** If this body is a bullet dynamic body, i.e. affected by physics
|
||||
* or not (static (not moving) or kinematic (animated outside
|
||||
* of physics). */
|
||||
@ -185,10 +200,6 @@ public:
|
||||
* it. */
|
||||
bool isExplodeKartObject () const { return m_explode_kart; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns true if this object should cause a kart that touches it to
|
||||
* be flattened. */
|
||||
bool isFlattenKartObject () const { return m_flatten_kart; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the interaction type */
|
||||
void setInteraction(std::string interaction);
|
||||
// ------------------------------------------------------------------------
|
||||
@ -197,6 +208,38 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Add body to dynamic world */
|
||||
void addBody();
|
||||
// ------------------------------------------------------------------------
|
||||
const std::string& getOnKartCollisionFunction() const { return m_on_kart_collision; }
|
||||
// ------------------------------------------------------------------------
|
||||
const std::string& getOnItemCollisionFunction() const { return m_on_item_collision; }
|
||||
// ------------------------------------------------------------------------
|
||||
// Methods usable by scripts
|
||||
|
||||
/**
|
||||
* \addtogroup Scripting
|
||||
* @{
|
||||
* \addtogroup Scripting_Track Track
|
||||
* @{
|
||||
* \addtogroup Scripting_PhysicalObject PhysicalObject (script binding)
|
||||
* Type returned by trackObject.getPhysicalObject()
|
||||
* @{
|
||||
*/
|
||||
/** Returns true if this object should cause a kart that touches it to
|
||||
* be flattened. */
|
||||
bool isFlattenKartObject() const { return m_flatten_kart; }
|
||||
void disable(/** \cond DOXYGEN_IGNORE */void *memory/** \endcond */)
|
||||
{
|
||||
((PhysicalObject*)(memory))->removeBody();
|
||||
}
|
||||
|
||||
//enables track object passed from the script
|
||||
void enable(/** \cond DOXYGEN_IGNORE */void *memory/** \endcond */)
|
||||
{
|
||||
((PhysicalObject*)(memory))->addBody();
|
||||
}
|
||||
/** @} */
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
LEAK_CHECK()
|
||||
}; // PhysicalObject
|
||||
|
@ -171,9 +171,11 @@ void Physics::update(float dt)
|
||||
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
||||
int kartid1 = p->getUserPointer(0)->getPointerKart()->getWorldKartId();
|
||||
int kartid2 = p->getUserPointer(1)->getPointerKart()->getWorldKartId();
|
||||
Scripting::Physics::setCollision(kartid1,kartid2);
|
||||
Scripting::Physics::setCollisionType("KartKart");
|
||||
script_engine->runScript("collisions");
|
||||
script_engine->runFunction("void onKartKartCollision(int, int)",
|
||||
[=](asIScriptContext* ctx) {
|
||||
ctx->SetArgDWord(0, kartid1);
|
||||
ctx->SetArgDWord(1, kartid2);
|
||||
});
|
||||
continue;
|
||||
} // if kart-kart collision
|
||||
|
||||
@ -182,29 +184,29 @@ void Physics::update(float dt)
|
||||
// Kart hits physical object
|
||||
// -------------------------
|
||||
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
||||
Scripting::Physics::setCollision(0, 0);
|
||||
Scripting::Physics::setCollisionType("KartObject"); //object as in physical object
|
||||
Scripting::Physics::setCollision
|
||||
(
|
||||
p->getUserPointer(0)->getPointerPhysicalObject()->getID(),
|
||||
"kart"
|
||||
);
|
||||
script_engine->runScript("collisions");
|
||||
PhysicalObject *obj = p->getUserPointer(0)
|
||||
->getPointerPhysicalObject();
|
||||
if(obj->isCrashReset())
|
||||
AbstractKart *kart = p->getUserPointer(1)->getPointerKart();
|
||||
int kartId = kart->getWorldKartId();
|
||||
PhysicalObject* obj = p->getUserPointer(0)->getPointerPhysicalObject();
|
||||
std::string obj_id = obj->getID();
|
||||
std::string scripting_function = obj->getOnKartCollisionFunction();
|
||||
if (scripting_function.size() > 0)
|
||||
{
|
||||
script_engine->runFunction("void " + scripting_function + "(int, const string)",
|
||||
[&](asIScriptContext* ctx) {
|
||||
ctx->SetArgDWord(0, kartId);
|
||||
ctx->SetArgObject(1, &obj_id);
|
||||
});
|
||||
}
|
||||
if (obj->isCrashReset())
|
||||
{
|
||||
AbstractKart *kart = p->getUserPointer(1)->getPointerKart();
|
||||
new RescueAnimation(kart);
|
||||
}
|
||||
else if (obj->isExplodeKartObject())
|
||||
{
|
||||
AbstractKart *kart = p->getUserPointer(1)->getPointerKart();
|
||||
ExplosionAnimation::create(kart);
|
||||
}
|
||||
else if (obj->isFlattenKartObject())
|
||||
{
|
||||
AbstractKart *kart = p->getUserPointer(1)->getPointerKart();
|
||||
const KartProperties* kp = kart->getKartProperties();
|
||||
kart->setSquash(kp->getSquashDuration() * kart->getPlayerDifficulty()->getSquashDuration(),
|
||||
kp->getSquashSlowdown() * kart->getPlayerDifficulty()->getSquashSlowdown());
|
||||
@ -212,14 +214,13 @@ void Physics::update(float dt)
|
||||
else if(obj->isSoccerBall() &&
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
|
||||
{
|
||||
int kartId = p->getUserPointer(1)->getPointerKart()->getWorldKartId();
|
||||
SoccerWorld* soccerWorld = (SoccerWorld*)World::getWorld();
|
||||
soccerWorld->setLastKartTohitBall(kartId);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(p->getUserPointer(0)->is(UserPointer::UP_ANIMATION))
|
||||
if (p->getUserPointer(0)->is(UserPointer::UP_ANIMATION))
|
||||
{
|
||||
// Kart hits animation
|
||||
ThreeDAnimation *anim=p->getUserPointer(0)->getPointerAnimation();
|
||||
@ -256,17 +257,20 @@ void Physics::update(float dt)
|
||||
// Projectile hits physical object
|
||||
// -------------------------------
|
||||
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
||||
Scripting::Physics::setCollision(0,0); //TODO : support item types etc
|
||||
Scripting::Physics::setCollisionType("ItemObject");
|
||||
Scripting::Physics::setCollision
|
||||
(
|
||||
p->getUserPointer(1)->getPointerPhysicalObject()->getID(),
|
||||
"item"
|
||||
);
|
||||
script_engine->runScript("collisions");
|
||||
p->getUserPointer(0)->getPointerFlyable()
|
||||
->hit(NULL, p->getUserPointer(1)->getPointerPhysicalObject());
|
||||
Flyable* flyable = p->getUserPointer(0)->getPointerFlyable();
|
||||
PhysicalObject* obj = p->getUserPointer(1)->getPointerPhysicalObject();
|
||||
std::string obj_id = obj->getID();
|
||||
std::string scripting_function = obj->getOnItemCollisionFunction();
|
||||
if (scripting_function.size() > 0)
|
||||
{
|
||||
script_engine->runFunction("void " + scripting_function + "(int, int, const string)",
|
||||
[&](asIScriptContext* ctx) {
|
||||
ctx->SetArgDWord(0, (int)flyable->getType());
|
||||
ctx->SetArgDWord(1, flyable->getOwnerId());
|
||||
ctx->SetArgObject(2, &obj_id);
|
||||
});
|
||||
}
|
||||
flyable->hit(NULL, obj);
|
||||
|
||||
if (obj->isSoccerBall() &&
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
|
||||
@ -301,8 +305,11 @@ void Physics::update(float dt)
|
||||
if (target_kart != kart && c &&
|
||||
c->getPlayer()->getConstProfile() == PlayerManager::getCurrentPlayer())
|
||||
{
|
||||
// Compare the current value of hits with the 'hit' goal value
|
||||
// (otherwise it would be compared with the kart id goal value,
|
||||
// which doesn't exist.
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_ARCH_ENEMY,
|
||||
target_kart->getIdent(), 1);
|
||||
target_kart->getIdent(), 1, "hit");
|
||||
if (type == PowerupManager::POWERUP_BOWLING)
|
||||
{
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_STRIKE,
|
||||
|
@ -145,30 +145,30 @@ public:
|
||||
unsigned int laps, bool reverse);
|
||||
void remove(const unsigned int track);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
/** @return the (potentially translated) user-visible name of the Grand
|
||||
* Prix (apply fribidi as needed) */
|
||||
irr::core::stringw getName() const { return _LTR(m_name.c_str()); }
|
||||
irr::core::stringw getName() const { return m_editable ? m_name.c_str() : _LTR(m_name.c_str()); }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
/** @return the internal indentifier of the Grand Prix (not translated) */
|
||||
const std::string& getId() const { return m_id; }
|
||||
const std::string& getId() const { return m_id; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
/** Returns true if this GP is a random GP. */
|
||||
bool isRandomGP() const { return m_id==getRandomGPID(); }
|
||||
// ------------------------------------------------------------------------
|
||||
bool isRandomGP() const { return m_id==getRandomGPID(); }
|
||||
// -------------------------------------------------------------------------
|
||||
/** Returns the filename of the grand prix xml file. */
|
||||
const std::string& getFilename() const { return m_filename; }
|
||||
const std::string& getFilename() const { return m_filename; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
enum GPGroupType getGroup() const { return m_group; }
|
||||
enum GPGroupType getGroup() const { return m_group; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
enum GPReverseType getReverseType()
|
||||
const { return m_reverse_type; }
|
||||
static const char* getRandomGPID() { return "random"; }
|
||||
static const wchar_t* getRandomGPName() { return _("Random Grand Prix"); }
|
||||
const { return m_reverse_type; }
|
||||
static const char* getRandomGPID() { return "random"; }
|
||||
static const wchar_t* getRandomGPName() { return _LTR("Random Grand Prix");}
|
||||
}; // GrandPrixData
|
||||
|
||||
#endif
|
||||
|
76
src/scriptengine/script_challenges.cpp
Normal file
76
src/scriptengine/script_challenges.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 SuperTuxKart Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "script_track.hpp"
|
||||
|
||||
#include "animations/three_d_animation.hpp"
|
||||
#include "input/device_manager.hpp"
|
||||
#include "input/input_device.hpp"
|
||||
#include "input/input_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "states_screens/dialogs/tutorial_message_dialog.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_object.hpp"
|
||||
#include "tracks/track_object_manager.hpp"
|
||||
|
||||
#include <angelscript.h>
|
||||
#include <assert.h>
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
namespace Scripting
|
||||
{
|
||||
/** \endcond */
|
||||
namespace Challenges
|
||||
{
|
||||
/** \addtogroup Scripting
|
||||
* @{
|
||||
*/
|
||||
/** \addtogroup Scripting_Challenges Challenges
|
||||
* @{
|
||||
*/
|
||||
|
||||
int getCompletedChallengesCount()
|
||||
{
|
||||
::Track* track = World::getWorld()->getTrack();
|
||||
return track->getNumOfCompletedChallenges();
|
||||
}
|
||||
|
||||
int getChallengeCount()
|
||||
{
|
||||
::Track* track = World::getWorld()->getTrack();
|
||||
return track->getChallengeList().size();
|
||||
}
|
||||
|
||||
/** @}*/
|
||||
/** @}*/
|
||||
|
||||
void registerScriptFunctions(asIScriptEngine *engine)
|
||||
{
|
||||
int r; // of type asERetCodes
|
||||
|
||||
engine->SetDefaultNamespace("Challenges");
|
||||
|
||||
r = engine->RegisterGlobalFunction("int getCompletedChallengesCount()", asFUNCTION(getCompletedChallengesCount), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("int getChallengeCount()", asFUNCTION(getChallengeCount), asCALL_CDECL); assert(r >= 0);
|
||||
}
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
}
|
||||
}
|
||||
/** \endcond */
|
||||
|
35
src/scriptengine/script_challenges.hpp
Normal file
35
src/scriptengine/script_challenges.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 SuperTuxKart Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_SCRIPT_CHALLENGES_HPP
|
||||
#define HEADER_SCRIPT_CHALLENGES_HPP
|
||||
|
||||
#include <angelscript.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
namespace Challenges
|
||||
{
|
||||
//script engine functions
|
||||
void registerScriptFunctions(asIScriptEngine *engine);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
@ -16,300 +16,406 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include <assert.h> // assert()
|
||||
#include <assert.h>
|
||||
#include <angelscript.h>
|
||||
#include "io/file_manager.hpp"
|
||||
#include <iostream> // cout
|
||||
#include "karts/kart.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "script_engine.hpp"
|
||||
#include "scriptstdstring.hpp"
|
||||
#include "scriptvec3.hpp"
|
||||
#include <string.h> // strstr()
|
||||
#include "scriptengine/script_challenges.hpp"
|
||||
#include "scriptengine/script_kart.hpp"
|
||||
#include "scriptengine/script_engine.hpp"
|
||||
#include "scriptengine/script_gui.hpp"
|
||||
#include "scriptengine/script_physics.hpp"
|
||||
#include "scriptengine/script_track.hpp"
|
||||
#include "scriptengine/script_utils.hpp"
|
||||
#include "scriptengine/scriptstdstring.hpp"
|
||||
#include "scriptengine/scriptvec3.hpp"
|
||||
#include <string.h>
|
||||
#include "states_screens/dialogs/tutorial_message_dialog.hpp"
|
||||
#include "tracks/track_object_manager.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
|
||||
#include "utils/profiler.hpp"
|
||||
|
||||
|
||||
using namespace Scripting;
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
const char* MODULE_ID_MAIN_SCRIPT_FILE = "main";
|
||||
|
||||
|
||||
//Line Callback
|
||||
void MessageCallback(const asSMessageInfo *msg, void *param)
|
||||
{
|
||||
const char *type = "ERR ";
|
||||
if (msg->type == asMSGTYPE_WARNING)
|
||||
type = "WARN";
|
||||
else if (msg->type == asMSGTYPE_INFORMATION)
|
||||
type = "INFO";
|
||||
|
||||
printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
|
||||
}
|
||||
|
||||
|
||||
//Constructor, creates a new Scripting Engine using AngelScript
|
||||
ScriptEngine::ScriptEngine()
|
||||
{
|
||||
// Create the script engine
|
||||
m_engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
|
||||
if( m_engine == 0 )
|
||||
void AngelScript_ErrorCallback (const asSMessageInfo *msg, void *param)
|
||||
{
|
||||
std::cout << "Failed to create script engine." << std::endl;
|
||||
const char *type = "ERR ";
|
||||
if (msg->type == asMSGTYPE_WARNING)
|
||||
type = "WARN";
|
||||
else if (msg->type == asMSGTYPE_INFORMATION)
|
||||
type = "INFO";
|
||||
|
||||
Log::warn("Scripting", "%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
|
||||
}
|
||||
|
||||
// The script compiler will write any compiler messages to the callback.
|
||||
//m_engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);
|
||||
|
||||
// Configure the script engine with all the functions,
|
||||
// and variables that the script should be able to use.
|
||||
configureEngine(m_engine);
|
||||
|
||||
}
|
||||
ScriptEngine::~ScriptEngine()
|
||||
{
|
||||
// Release the engine
|
||||
m_engine->Release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Get Script By it's file name
|
||||
* \param string scriptname = name of script to get
|
||||
* \return The corresponding script
|
||||
*/
|
||||
std::string getScript(std::string scriptName)
|
||||
{
|
||||
std::string script_dir = file_manager->getAsset(FileManager::SCRIPT, "");
|
||||
script_dir += World::getWorld()->getTrack()->getIdent() + "/";
|
||||
if (scriptName != "update" && scriptName != "collisions" && scriptName!="start") scriptName = "triggers";
|
||||
script_dir += scriptName + ".as";
|
||||
FILE *f = fopen(script_dir.c_str(), "rb");
|
||||
if( f == 0 )
|
||||
//Constructor, creates a new Scripting Engine using AngelScript
|
||||
ScriptEngine::ScriptEngine()
|
||||
{
|
||||
std::cout << "Failed to open the script file " + scriptName + ".as" << std::endl;
|
||||
// Create the script engine
|
||||
m_engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
|
||||
if (m_engine == NULL)
|
||||
{
|
||||
Log::fatal("Scripting", "Failed to create script engine.");
|
||||
}
|
||||
|
||||
// The script compiler will write any compiler messages to the callback.
|
||||
m_engine->SetMessageCallback(asFUNCTION(AngelScript_ErrorCallback), 0, asCALL_CDECL);
|
||||
|
||||
// Configure the script engine with all the functions,
|
||||
// and variables that the script should be able to use.
|
||||
configureEngine(m_engine);
|
||||
}
|
||||
|
||||
// Determine the size of the file
|
||||
fseek(f, 0, SEEK_END);
|
||||
int len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
// Read the entire file
|
||||
std::string script;
|
||||
script.resize(len);
|
||||
int c = fread(&script[0], len, 1, f);
|
||||
fclose(f);
|
||||
if( c == 0 )
|
||||
ScriptEngine::~ScriptEngine()
|
||||
{
|
||||
std::cout << "Failed to load script file." << std::endl;
|
||||
// Release the engine
|
||||
m_engine->Release();
|
||||
}
|
||||
return script;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
/** runs the specified script
|
||||
* \param string scriptName = name of script to run
|
||||
*/
|
||||
void ScriptEngine::runScript(std::string scriptName)
|
||||
{
|
||||
return; // Scripting disabled for now
|
||||
|
||||
// Create a context that will execute the script.
|
||||
asIScriptContext *ctx = m_engine->CreateContext();
|
||||
if (ctx == 0)
|
||||
|
||||
|
||||
/** Get Script By it's file name
|
||||
* \param string scriptname = name of script to get
|
||||
* \return The corresponding script
|
||||
*/
|
||||
std::string getScript(std::string fileName)
|
||||
{
|
||||
std::cout << "Failed to create the context." << std::endl;
|
||||
//m_engine->Release();
|
||||
return;
|
||||
std::string script_dir = file_manager->getAsset(FileManager::SCRIPT, "");
|
||||
script_dir += World::getWorld()->getTrack()->getIdent() + "/";
|
||||
|
||||
script_dir += fileName;
|
||||
FILE *f = fopen(script_dir.c_str(), "rb");
|
||||
if (f == NULL)
|
||||
{
|
||||
Log::debug("Scripting", "File does not exist : {0}.as", fileName.c_str());
|
||||
return "";
|
||||
}
|
||||
|
||||
// Determine the size of the file
|
||||
fseek(f, 0, SEEK_END);
|
||||
int len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
// Read the entire file
|
||||
std::string script;
|
||||
script.resize(len);
|
||||
int c = fread(&script[0], len, 1, f);
|
||||
fclose(f);
|
||||
if (c == NULL)
|
||||
{
|
||||
Log::error("Scripting", "Failed to load script file.");
|
||||
return "";
|
||||
}
|
||||
return script;
|
||||
}
|
||||
int r; //int for error checking
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
asIScriptFunction *func;
|
||||
if (m_script_cache.find(scriptName) == m_script_cache.end())
|
||||
void ScriptEngine::evalScript(std::string script_fragment)
|
||||
{
|
||||
// Compile the script code
|
||||
r = compileScript(m_engine, scriptName);
|
||||
script_fragment = "void evalScript_main() { \n" + script_fragment + "\n}";
|
||||
|
||||
asIScriptModule* mod = m_engine->GetModule(MODULE_ID_MAIN_SCRIPT_FILE, asGM_ONLY_IF_EXISTS);
|
||||
|
||||
asIScriptFunction* func;
|
||||
int r = mod->CompileFunction("eval", script_fragment.c_str(), 0, 0, &func);
|
||||
if (r < 0)
|
||||
{
|
||||
Log::error("Scripting", "evalScript: CompileFunction() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
//set line callback here soon
|
||||
asIScriptContext *ctx = m_engine->CreateContext();
|
||||
if (ctx == NULL)
|
||||
{
|
||||
Log::error("Scripting", "evalScript: Failed to create the context.");
|
||||
//m_engine->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
r = ctx->Prepare(func);
|
||||
if (r < 0)
|
||||
{
|
||||
std::cout << "Failed to set the line callback function." << std::endl;
|
||||
Log::error("Scripting", "evalScript: Failed to prepare the context.");
|
||||
ctx->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the function for the function we want to execute.
|
||||
//This is how you call a normal function with arguments
|
||||
//asIScriptFunction *func = engine->GetModule(0)->GetFunctionByDecl("void func(arg1Type, arg2Type)");
|
||||
if (scriptName == "collisions")
|
||||
// Execute the function
|
||||
r = ctx->Execute();
|
||||
if (r != asEXECUTION_FINISHED)
|
||||
{
|
||||
func = Scripting::Physics::registerScriptCallbacks(m_engine);
|
||||
// The execution didn't finish as we had planned. Determine why.
|
||||
if (r == asEXECUTION_ABORTED)
|
||||
{
|
||||
Log::error("Scripting", "The script was aborted before it could finish. Probably it timed out.");
|
||||
}
|
||||
else if (r == asEXECUTION_EXCEPTION)
|
||||
{
|
||||
Log::error("Scripting", "The script ended with an exception.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("Scripting", "The script ended for some unforeseen reason (%i)", r);
|
||||
}
|
||||
}
|
||||
else if (scriptName == "update")
|
||||
|
||||
ctx->Release();
|
||||
func->Release();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** runs the specified script
|
||||
* \param string scriptName = name of script to run
|
||||
*/
|
||||
void ScriptEngine::runFunction(std::string function_name)
|
||||
{
|
||||
std::function<void(asIScriptContext*)> callback;
|
||||
std::function<void(asIScriptContext*)> get_return_value;
|
||||
runFunction(function_name, callback, get_return_value);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void ScriptEngine::runFunction(std::string function_name,
|
||||
std::function<void(asIScriptContext*)> callback)
|
||||
{
|
||||
std::function<void(asIScriptContext*)> get_return_value;
|
||||
runFunction(function_name, callback, get_return_value);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** runs the specified script
|
||||
* \param string scriptName = name of script to run
|
||||
*/
|
||||
void ScriptEngine::runFunction(std::string function_name,
|
||||
std::function<void(asIScriptContext*)> callback,
|
||||
std::function<void(asIScriptContext*)> get_return_value)
|
||||
{
|
||||
int r; //int for error checking
|
||||
|
||||
asIScriptFunction *func;
|
||||
|
||||
// TODO: allow splitting in multiple files
|
||||
std::string script_filename = "scripting.as";
|
||||
auto cached_script = m_loaded_files.find(script_filename);
|
||||
auto cached_function = m_functions_cache.find(function_name);
|
||||
|
||||
if (cached_script == m_loaded_files.end())
|
||||
{
|
||||
func = Scripting::Track::registerUpdateScriptCallbacks(m_engine);
|
||||
// Compile the script code
|
||||
Log::info("Scripting", "Checking for script file '%s'", script_filename.c_str());
|
||||
r = compileScript(m_engine, script_filename);
|
||||
if (r < 0)
|
||||
{
|
||||
Log::info("Scripting", "Script '%s' is not available", script_filename.c_str());
|
||||
m_loaded_files[script_filename] = false;
|
||||
m_functions_cache[function_name] = NULL; // remember that this script is unavailable
|
||||
return;
|
||||
}
|
||||
|
||||
m_loaded_files[script_filename] = true;
|
||||
}
|
||||
else if (scriptName == "start")
|
||||
else if (cached_script->second == false)
|
||||
{
|
||||
func = Scripting::Track::registerStartScriptCallbacks(m_engine);
|
||||
return; // script file unavailable
|
||||
}
|
||||
|
||||
if (cached_function == m_functions_cache.end())
|
||||
{
|
||||
// Find the function for the function we want to execute.
|
||||
// This is how you call a normal function with arguments
|
||||
// asIScriptFunction *func = engine->GetModule(0)->GetFunctionByDecl("void func(arg1Type, arg2Type)");
|
||||
func = m_engine->GetModule(MODULE_ID_MAIN_SCRIPT_FILE)
|
||||
->GetFunctionByDecl(function_name.c_str());
|
||||
|
||||
if (func == NULL)
|
||||
{
|
||||
Log::debug("Scripting", "Scripting function was not found : %s", function_name.c_str());
|
||||
m_loaded_files[function_name] = NULL; // remember that this script is unavailable
|
||||
return;
|
||||
}
|
||||
|
||||
m_functions_cache[function_name] = func;
|
||||
func->AddRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
//trigger type can have different names
|
||||
func = Scripting::Track::registerScriptCallbacks(m_engine, scriptName);
|
||||
// Script present in cache
|
||||
func = cached_function->second;
|
||||
}
|
||||
if (func == 0)
|
||||
|
||||
if (func == NULL)
|
||||
{
|
||||
std::cout << "The required function was not found." << std::endl;
|
||||
return; // function unavailable
|
||||
}
|
||||
|
||||
// Create a context that will execute the script.
|
||||
asIScriptContext *ctx = m_engine->CreateContext();
|
||||
if (ctx == NULL)
|
||||
{
|
||||
Log::error("Scripting", "Failed to create the context.");
|
||||
//m_engine->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare the script context with the function we wish to execute. Prepare()
|
||||
// must be called on the context before each new script function that will be
|
||||
// executed. Note, that if because we intend to execute the same function
|
||||
// several times, we will store the function returned by
|
||||
// GetFunctionByDecl(), so that this relatively slow call can be skipped.
|
||||
r = ctx->Prepare(func);
|
||||
if (r < 0)
|
||||
{
|
||||
Log::error("Scripting", "Failed to prepare the context.");
|
||||
ctx->Release();
|
||||
//m_engine->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
//CACHE UPDATE
|
||||
m_script_cache[scriptName] = func;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Script present in cache
|
||||
func = m_script_cache[scriptName];
|
||||
std::cout << "FOUND CACHED : " << scriptName << std::endl;
|
||||
}
|
||||
// Prepare the script context with the function we wish to execute. Prepare()
|
||||
// must be called on the context before each new script function that will be
|
||||
// executed. Note, that if because we intend to execute the same function
|
||||
// several times, we will store the function returned by
|
||||
// GetFunctionByDecl(), so that this relatively slow call can be skipped.
|
||||
r = ctx->Prepare(func);
|
||||
if( r < 0 )
|
||||
{
|
||||
std::cout << "Failed to prepare the context." << std::endl;
|
||||
ctx->Release();
|
||||
//m_engine->Release();
|
||||
return;
|
||||
}
|
||||
// Here, we can pass parameters to the script functions.
|
||||
//ctx->setArgType(index, value);
|
||||
//for example : ctx->SetArgFloat(0, 3.14159265359f);
|
||||
|
||||
// Here, we can pass parameters to the script functions.
|
||||
//ctx->setArgType(index, value);
|
||||
//for example : ctx->SetArgFloat(0, 3.14159265359f);
|
||||
if (callback)
|
||||
callback(ctx);
|
||||
|
||||
|
||||
// Execute the function
|
||||
r = ctx->Execute();
|
||||
if( r != asEXECUTION_FINISHED )
|
||||
{
|
||||
// The execution didn't finish as we had planned. Determine why.
|
||||
if( r == asEXECUTION_ABORTED )
|
||||
std::cout << "The script was aborted before it could finish. Probably it timed out." << std::endl;
|
||||
else if( r == asEXECUTION_EXCEPTION )
|
||||
// Execute the function
|
||||
r = ctx->Execute();
|
||||
if (r != asEXECUTION_FINISHED)
|
||||
{
|
||||
std::cout << "The script ended with an exception." << std::endl;
|
||||
// The execution didn't finish as we had planned. Determine why.
|
||||
if (r == asEXECUTION_ABORTED)
|
||||
{
|
||||
Log::error("Scripting", "The script was aborted before it could finish. Probably it timed out.");
|
||||
}
|
||||
else if (r == asEXECUTION_EXCEPTION)
|
||||
{
|
||||
Log::error("Scripting", "The script ended with an exception.");
|
||||
|
||||
// Write some information about the script exception
|
||||
asIScriptFunction *func = ctx->GetExceptionFunction();
|
||||
std::cout << "func: " << func->GetDeclaration() << std::endl;
|
||||
std::cout << "modl: " << func->GetModuleName() << std::endl;
|
||||
std::cout << "sect: " << func->GetScriptSectionName() << std::endl;
|
||||
std::cout << "line: " << ctx->GetExceptionLineNumber() << std::endl;
|
||||
std::cout << "desc: " << ctx->GetExceptionString() << std::endl;
|
||||
// Write some information about the script exception
|
||||
asIScriptFunction *func = ctx->GetExceptionFunction();
|
||||
//std::cout << "func: " << func->GetDeclaration() << std::endl;
|
||||
//std::cout << "modl: " << func->GetModuleName() << std::endl;
|
||||
//std::cout << "sect: " << func->GetScriptSectionName() << std::endl;
|
||||
//std::cout << "line: " << ctx->GetExceptionLineNumber() << std::endl;
|
||||
//std::cout << "desc: " << ctx->GetExceptionString() << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("Scripting", "The script ended for some unforeseen reason (%i)", r);
|
||||
}
|
||||
}
|
||||
else
|
||||
std::cout << "The script ended for some unforeseen reason (" << r << ")." << std::endl;
|
||||
{
|
||||
// Retrieve the return value from the context here (for scripts that return values)
|
||||
// <type> returnValue = ctx->getReturnType(); for example
|
||||
//float returnValue = ctx->GetReturnFloat();
|
||||
|
||||
if (get_return_value)
|
||||
get_return_value(ctx);
|
||||
}
|
||||
|
||||
// We must release the contexts when no longer using them
|
||||
ctx->Release();
|
||||
}
|
||||
else
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void ScriptEngine::cleanupCache()
|
||||
{
|
||||
// Retrieve the return value from the context here (for scripts that return values)
|
||||
// <type> returnValue = ctx->getReturnType(); for example
|
||||
//float returnValue = ctx->GetReturnFloat();
|
||||
for (auto curr : m_functions_cache)
|
||||
{
|
||||
if (curr.second != NULL)
|
||||
curr.second->Release();
|
||||
}
|
||||
m_functions_cache.clear();
|
||||
m_loaded_files.clear();
|
||||
}
|
||||
|
||||
// We must release the contexts when no longer using them
|
||||
ctx->Release();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Configures the script engine by binding functions, enums
|
||||
* \param asIScriptEngine engine = engine to configure
|
||||
*/
|
||||
void ScriptEngine::configureEngine(asIScriptEngine *engine)
|
||||
{
|
||||
// Register the script string type
|
||||
RegisterStdString(engine); //register std::string
|
||||
RegisterVec3(engine); //register Vec3
|
||||
|
||||
Scripting::Track::registerScriptFunctions(m_engine);
|
||||
|
||||
Scripting::Track::registerScriptEnums(m_engine);
|
||||
|
||||
Scripting::Kart::registerScriptFunctions(m_engine);
|
||||
|
||||
Scripting::Physics::registerScriptFunctions(m_engine);
|
||||
|
||||
|
||||
// It is possible to register the functions, properties, and types in
|
||||
// configuration groups as well. When compiling the scripts it can then
|
||||
// be defined which configuration groups should be available for that
|
||||
// script. If necessary a configuration group can also be removed from
|
||||
// the engine, so that the engine configuration could be changed
|
||||
// without having to recompile all the scripts.
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
int ScriptEngine::compileScript(asIScriptEngine *engine, std::string scriptName)
|
||||
{
|
||||
int r;
|
||||
|
||||
std::string script = getScript(scriptName);
|
||||
// Add the script sections that will be compiled into executable code.
|
||||
// If we want to combine more than one file into the same script, then
|
||||
// we can call AddScriptSection() several times for the same module and
|
||||
// the script engine will treat them all as if they were one. The script
|
||||
// section name, will allow us to localize any errors in the script code.
|
||||
asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
|
||||
r = mod->AddScriptSection("script", &script[0], script.size());
|
||||
if( r < 0 )
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Configures the script engine by binding functions, enums
|
||||
* \param asIScriptEngine engine = engine to configure
|
||||
*/
|
||||
void ScriptEngine::configureEngine(asIScriptEngine *engine)
|
||||
{
|
||||
std::cout << "AddScriptSection() failed" << std::endl;
|
||||
return -1;
|
||||
// Register the script string type
|
||||
RegisterStdString(engine); //register std::string
|
||||
RegisterVec3(engine); //register Vec3
|
||||
|
||||
Scripting::Track::registerScriptFunctions(m_engine);
|
||||
Scripting::Challenges::registerScriptFunctions(m_engine);
|
||||
Scripting::Kart::registerScriptFunctions(m_engine);
|
||||
Scripting::Kart::registerScriptEnums(m_engine);
|
||||
Scripting::Physics::registerScriptFunctions(m_engine);
|
||||
Scripting::Utils::registerScriptFunctions(m_engine);
|
||||
Scripting::GUI::registerScriptFunctions(m_engine);
|
||||
Scripting::GUI::registerScriptEnums(m_engine);
|
||||
|
||||
// It is possible to register the functions, properties, and types in
|
||||
// configuration groups as well. When compiling the scripts it can then
|
||||
// be defined which configuration groups should be available for that
|
||||
// script. If necessary a configuration group can also be removed from
|
||||
// the engine, so that the engine configuration could be changed
|
||||
// without having to recompile all the scripts.
|
||||
}
|
||||
|
||||
// Compile the script. If there are any compiler messages they will
|
||||
// be written to the message stream that we set right after creating the
|
||||
// script engine. If there are no errors, and no warnings, nothing will
|
||||
// be written to the stream.
|
||||
r = mod->Build();
|
||||
if( r < 0 )
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int ScriptEngine::compileScript(asIScriptEngine *engine, std::string scriptName)
|
||||
{
|
||||
std::cout << "Build() failed" << std::endl;
|
||||
return -1;
|
||||
int r;
|
||||
|
||||
std::string script = getScript(scriptName);
|
||||
if (script.size() == 0)
|
||||
{
|
||||
// No such file
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add the script sections that will be compiled into executable code.
|
||||
// If we want to combine more than one file into the same script, then
|
||||
// we can call AddScriptSection() several times for the same module and
|
||||
// the script engine will treat them all as if they were one. The script
|
||||
// section name, will allow us to localize any errors in the script code.
|
||||
asIScriptModule *mod = engine->GetModule(MODULE_ID_MAIN_SCRIPT_FILE, asGM_ALWAYS_CREATE);
|
||||
r = mod->AddScriptSection("script", &script[0], script.size());
|
||||
if (r < 0)
|
||||
{
|
||||
Log::error("Scripting", "AddScriptSection() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Compile the script. If there are any compiler messages they will
|
||||
// be written to the message stream that we set right after creating the
|
||||
// script engine. If there are no errors, and no warnings, nothing will
|
||||
// be written to the stream.
|
||||
r = mod->Build();
|
||||
if (r < 0)
|
||||
{
|
||||
Log::error("Scripting", "Build() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// The engine doesn't keep a copy of the script sections after Build() has
|
||||
// returned. So if the script needs to be recompiled, then all the script
|
||||
// sections must be added again.
|
||||
|
||||
// If we want to have several scripts executing at different times but
|
||||
// that have no direct relation with each other, then we can compile them
|
||||
// into separate script modules. Each module uses their own namespace and
|
||||
// scope, so function names, and global variables will not conflict with
|
||||
// each other.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The engine doesn't keep a copy of the script sections after Build() has
|
||||
// returned. So if the script needs to be recompiled, then all the script
|
||||
// sections must be added again.
|
||||
|
||||
// If we want to have several scripts executing at different times but
|
||||
// that have no direct relation with each other, then we can compile them
|
||||
// into separate script modules. Each module uses their own namespace and
|
||||
// scope, so function names, and global variables will not conflict with
|
||||
// each other.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -21,54 +21,32 @@
|
||||
|
||||
#include <string>
|
||||
#include <angelscript.h>
|
||||
#include <functional>
|
||||
|
||||
class TrackObjectPresentation;
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
|
||||
namespace Physics
|
||||
{
|
||||
void registerScriptFunctions(asIScriptEngine *engine);
|
||||
asIScriptFunction*
|
||||
registerScriptCallbacks(asIScriptEngine *engine);
|
||||
void setCollision(int collider1,int collider2);
|
||||
void setCollisionType(std::string collisionType);
|
||||
void setCollision(std::string collider1, std::string collider2);
|
||||
}
|
||||
|
||||
namespace Kart
|
||||
{
|
||||
void registerScriptFunctions(asIScriptEngine *engine);
|
||||
}
|
||||
|
||||
namespace Track
|
||||
{
|
||||
void registerScriptFunctions(asIScriptEngine *engine);
|
||||
|
||||
void registerScriptEnums(asIScriptEngine *engine);
|
||||
|
||||
asIScriptFunction*
|
||||
registerScriptCallbacks(asIScriptEngine *engine, std::string scriptName);
|
||||
|
||||
asIScriptFunction*
|
||||
registerUpdateScriptCallbacks(asIScriptEngine *engine);
|
||||
|
||||
asIScriptFunction*
|
||||
registerStartScriptCallbacks(asIScriptEngine *engine);
|
||||
}
|
||||
|
||||
class ScriptEngine
|
||||
{
|
||||
public:
|
||||
|
||||
ScriptEngine();
|
||||
~ScriptEngine();
|
||||
|
||||
void runScript(std::string scriptName);
|
||||
void runFunction(std::string function_name);
|
||||
void runFunction(std::string function_name,
|
||||
std::function<void(asIScriptContext*)> callback);
|
||||
void runFunction(std::string function_name,
|
||||
std::function<void(asIScriptContext*)> callback,
|
||||
std::function<void(asIScriptContext*)> get_return_value);
|
||||
void evalScript(std::string script_fragment);
|
||||
void cleanupCache();
|
||||
|
||||
private:
|
||||
asIScriptEngine *m_engine;
|
||||
std::map<std::string, asIScriptFunction*> m_script_cache;
|
||||
std::map<std::string, bool> m_loaded_files;
|
||||
std::map<std::string, asIScriptFunction*> m_functions_cache;
|
||||
|
||||
void configureEngine(asIScriptEngine *engine);
|
||||
int compileScript(asIScriptEngine *engine,std::string scriptName);
|
||||
|
187
src/scriptengine/script_gui.cpp
Normal file
187
src/scriptengine/script_gui.cpp
Normal file
@ -0,0 +1,187 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 SuperTuxKart Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "script_track.hpp"
|
||||
|
||||
#include "animations/three_d_animation.hpp"
|
||||
#include "input/device_manager.hpp"
|
||||
#include "input/input_device.hpp"
|
||||
#include "input/input_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "states_screens/dialogs/tutorial_message_dialog.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_object.hpp"
|
||||
#include "tracks/track_object_manager.hpp"
|
||||
|
||||
#include <angelscript.h>
|
||||
#include "scriptarray.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream> //debug
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
namespace Scripting
|
||||
{
|
||||
/** \endcond */
|
||||
|
||||
namespace GUI
|
||||
{
|
||||
/** \addtogroup Scripting
|
||||
* @{
|
||||
*/
|
||||
/** \addtogroup GUI
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Get the key bound to a player action (enum GUI::PlayerAction)*/
|
||||
std::string getKeyBinding(int Enum_value)
|
||||
{
|
||||
InputDevice* device = input_manager->getDeviceManager()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw control;
|
||||
PlayerAction ScriptAction = (PlayerAction)Enum_value;
|
||||
control = config->getBindingAsString(ScriptAction);
|
||||
std::string key = std::string(irr::core::stringc(control).c_str());
|
||||
return key;
|
||||
}
|
||||
|
||||
/** Show the specified message in a popup */
|
||||
void displayMessage(std::string* input)
|
||||
{
|
||||
irr::core::stringw out = StringUtils::utf8_to_wide(input->c_str());
|
||||
new TutorialMessageDialog((out), true);
|
||||
}
|
||||
|
||||
/** Get translated version of string */
|
||||
std::string translate(std::string* input)
|
||||
{
|
||||
irr::core::stringw out = translations->fribidize(translations->w_gettext(input->c_str()));
|
||||
|
||||
return StringUtils::wide_to_utf8(out.c_str());
|
||||
}
|
||||
|
||||
/** Translate string and insert values. e.g. GUI::translate("Hello %s !", "John") */
|
||||
std::string translate(std::string* formatString, std::string* arg1)
|
||||
{
|
||||
irr::core::stringw out = translations->w_gettext(formatString->c_str());
|
||||
|
||||
out = StringUtils::insertValues(out,
|
||||
StringUtils::utf8_to_wide(arg1->c_str()));
|
||||
|
||||
out = translations->fribidize(out);
|
||||
|
||||
return StringUtils::wide_to_utf8(out.c_str());
|
||||
}
|
||||
|
||||
/** Translate string and insert values. e.g. GUI::translate("Hello %s !", "John") */
|
||||
std::string translate(std::string* formatString, std::string* arg1, std::string* arg2)
|
||||
{
|
||||
irr::core::stringw out = translations->w_gettext(formatString->c_str());
|
||||
|
||||
out = StringUtils::insertValues(out,
|
||||
StringUtils::utf8_to_wide(arg1->c_str()),
|
||||
StringUtils::utf8_to_wide(arg2->c_str()));
|
||||
|
||||
out = translations->fribidize(out);
|
||||
|
||||
return StringUtils::wide_to_utf8(out.c_str());
|
||||
}
|
||||
|
||||
/** Translate string and insert values. e.g. GUI::translate("Hello %s !", "John") */
|
||||
std::string translate(std::string* formatString, std::string* arg1, std::string* arg2,
|
||||
std::string* arg3)
|
||||
{
|
||||
irr::core::stringw out = translations->w_gettext(formatString->c_str());
|
||||
|
||||
out = StringUtils::insertValues(out,
|
||||
StringUtils::utf8_to_wide(arg1->c_str()),
|
||||
StringUtils::utf8_to_wide(arg2->c_str()),
|
||||
StringUtils::utf8_to_wide(arg3->c_str()));
|
||||
|
||||
out = translations->fribidize(out);
|
||||
|
||||
return StringUtils::wide_to_utf8(out.c_str());
|
||||
}
|
||||
/** @}*/
|
||||
/** @}*/
|
||||
|
||||
// UNDOCUMENTED PROXIES : Use proxies to have different signatures, then redirect to the
|
||||
// documented function whose name is exposed in angelscript (these proxies exist so that
|
||||
// angelscript can properly resolve overloads, but doxygen can still generate the right docs
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
std::string proxy_translate(std::string* formatString)
|
||||
{
|
||||
return translate(formatString);
|
||||
}
|
||||
|
||||
std::string proxy_translateAndInsertValues1(std::string* formatString, std::string* arg1)
|
||||
{
|
||||
return translate(formatString, arg1);
|
||||
}
|
||||
|
||||
std::string proxy_translateAndInsertValues2(std::string* formatString, std::string* arg1, std::string* arg2)
|
||||
{
|
||||
return translate(formatString, arg1, arg2);
|
||||
}
|
||||
|
||||
std::string proxy_translateAndInsertValues3(std::string* formatString, std::string* arg1, std::string* arg2,
|
||||
std::string* arg3)
|
||||
{
|
||||
return translate(formatString, arg1, arg2, arg3);
|
||||
}
|
||||
/** \endcond */
|
||||
|
||||
void registerScriptFunctions(asIScriptEngine *engine)
|
||||
{
|
||||
int r; // of type asERetCodes
|
||||
engine->SetDefaultNamespace("GUI");
|
||||
r = engine->RegisterGlobalFunction("void displayMessage(const string &in)", asFUNCTION(displayMessage), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string getKeyBinding(int input)", asFUNCTION(getKeyBinding), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string translate(const string &in)", asFUNCTION(proxy_translate), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string translate(const string &in, const string &in)", asFUNCTION(proxy_translateAndInsertValues1), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string translate(const string &in, const string &in, const string &in)", asFUNCTION(proxy_translateAndInsertValues2), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string translate(const string &in, const string &in, const string &in, const string &in)", asFUNCTION(proxy_translateAndInsertValues3), asCALL_CDECL); assert(r >= 0);
|
||||
}
|
||||
|
||||
void registerScriptEnums(asIScriptEngine *engine)
|
||||
{
|
||||
// TODO: document enum in doxygen-generated scripting docs
|
||||
engine->SetDefaultNamespace("GUI");
|
||||
engine->RegisterEnum("PlayerAction");
|
||||
engine->RegisterEnumValue("PlayerAction", "STEER_LEFT", PA_STEER_LEFT);
|
||||
engine->RegisterEnumValue("PlayerAction", "STEER_RIGHT", PA_STEER_RIGHT);
|
||||
engine->RegisterEnumValue("PlayerAction", "ACCEL", PA_ACCEL);
|
||||
engine->RegisterEnumValue("PlayerAction", "BRAKE", PA_BRAKE);
|
||||
engine->RegisterEnumValue("PlayerAction", "NITRO", PA_NITRO);
|
||||
engine->RegisterEnumValue("PlayerAction", "DRIFT", PA_DRIFT);
|
||||
engine->RegisterEnumValue("PlayerAction", "RESCUE", PA_RESCUE);
|
||||
engine->RegisterEnumValue("PlayerAction", "FIRE", PA_FIRE);
|
||||
engine->RegisterEnumValue("PlayerAction", "LOOK_BACK", PA_LOOK_BACK);
|
||||
engine->RegisterEnumValue("PlayerAction", "PAUSE_RACE", PA_PAUSE_RACE);
|
||||
engine->RegisterEnumValue("PlayerAction", "MENU_UP", PA_MENU_UP);
|
||||
engine->RegisterEnumValue("PlayerAction", "MENU_DOWN", PA_MENU_DOWN);
|
||||
engine->RegisterEnumValue("PlayerAction", "MENU_LEFT", PA_MENU_LEFT);
|
||||
engine->RegisterEnumValue("PlayerAction", "MENU_RIGHT", PA_MENU_RIGHT);
|
||||
engine->RegisterEnumValue("PlayerAction", "MENU_SELECT", PA_MENU_SELECT);
|
||||
engine->RegisterEnumValue("PlayerAction", "MENU_CANCEL", PA_MENU_CANCEL);
|
||||
}
|
||||
}
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
}
|
||||
/** \endcond */
|
36
src/scriptengine/script_gui.hpp
Normal file
36
src/scriptengine/script_gui.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 SuperTuxKart Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_SCRIPT_GUI_HPP
|
||||
#define HEADER_SCRIPT_GUI_HPP
|
||||
|
||||
#include <angelscript.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
namespace GUI
|
||||
{
|
||||
//script engine functions
|
||||
void registerScriptFunctions(asIScriptEngine *engine);
|
||||
void registerScriptEnums(asIScriptEngine *engine);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
@ -21,102 +21,127 @@
|
||||
#include "karts/kart.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "script_kart.hpp"
|
||||
#include "scriptvec3.hpp"
|
||||
|
||||
//debug
|
||||
#include <iostream>
|
||||
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
namespace Scripting
|
||||
{
|
||||
/** \endcond */
|
||||
|
||||
namespace Kart
|
||||
{
|
||||
//Squashes the specified kart, specified time
|
||||
void squashKart(asIScriptGeneric *gen)
|
||||
/** \addtogroup Scripting
|
||||
* @{
|
||||
*/
|
||||
/** \addtogroup Kart
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Squashes the specified kart, for the specified time */
|
||||
void squash(int idKart, float time)
|
||||
{
|
||||
int id = (int)gen->GetArgDWord(0);
|
||||
float time = gen->GetArgFloat(1);
|
||||
AbstractKart* kart = World::getWorld()->getKart(id);
|
||||
AbstractKart* kart = World::getWorld()->getKart(idKart);
|
||||
kart->setSquash(time, 0.5); //0.5 * max speed is new max for squashed duration
|
||||
}
|
||||
//Teleports the kart to the specified Vec3 location
|
||||
void teleportKart(asIScriptGeneric *gen)
|
||||
|
||||
/** Teleports the kart to the specified Vec3 location */
|
||||
void teleport(int idKart, SimpleVec3* position)
|
||||
{
|
||||
int id = (int)gen->GetArgDWord(0);
|
||||
Vec3 *position = (Vec3*)gen->GetArgAddress(1);
|
||||
|
||||
float x = position->getX();
|
||||
float y = position->getY();
|
||||
float z = position->getZ();
|
||||
|
||||
AbstractKart* kart = World::getWorld()->getKart(id);
|
||||
kart->setXYZ(btVector3(x, y, z));
|
||||
AbstractKart* kart = World::getWorld()->getKart(idKart);
|
||||
Vec3 v(position->getX(), position->getY(), position->getZ());
|
||||
kart->setXYZ(v);
|
||||
unsigned int index = World::getWorld()->getRescuePositionIndex(kart);
|
||||
btTransform s = World::getWorld()->getRescueTransform(index);
|
||||
const btVector3 &xyz = s.getOrigin();
|
||||
s.setRotation(btQuaternion(btVector3(0.0f, 1.0f, 0.0f), 0.0f));
|
||||
World::getWorld()->moveKartTo(kart, s);
|
||||
}
|
||||
//Attempts to project kart to the given 2D location, to the position
|
||||
//with height 0, at a 45 degree angle.
|
||||
void jumpKartTo(asIScriptGeneric *gen)
|
||||
|
||||
/** Attempts to project kart to the given 2D location, to the position
|
||||
* with height 0, at a 45 degree angle.
|
||||
*/
|
||||
// TODO: not sure what this function is for
|
||||
//void jumpTo(asIScriptGeneric *gen)
|
||||
//{
|
||||
// //attempts to project kart to target destination
|
||||
// //at present, assumes both initial and target location are
|
||||
// //on the same horizontal plane (z=k plane) and projects
|
||||
// //at a 45 degree angle.
|
||||
// int id = (int)gen->GetArgDWord(0);
|
||||
//
|
||||
// float x = gen->GetArgFloat(1);
|
||||
// float y = gen->GetArgFloat(2);
|
||||
// //float velocity = gen->GetArgFloat(3);
|
||||
// //angle = pi/4 so t = v/(root 2 * g)
|
||||
// //d = t * v/root 2 so d = v^2/(2g) => v = root(2dg)
|
||||
// //component in x = component in y = root (dg)
|
||||
// AbstractKart* kart = World::getWorld()->getKart(id);
|
||||
// Vec3 pos = kart->getXYZ();
|
||||
// float dx = x - pos[0];
|
||||
// float dy = y - pos[2]; //blender uses xyz, bullet xzy
|
||||
// float d = (sqrtf(dx*dx + dy*dy));
|
||||
// float normalized_dx = dx / d;
|
||||
// float normalized_dy = dy / d;
|
||||
// float g = 9.81f;
|
||||
// float velocity = sqrtf(d * g);
|
||||
//
|
||||
// kart->setVelocity(btVector3(velocity * normalized_dx, velocity, velocity * normalized_dy));
|
||||
//}
|
||||
|
||||
/** Returns the location of the corresponding kart. */
|
||||
SimpleVec3 getLocation(int idKart)
|
||||
{
|
||||
//attempts to project kart to target destination
|
||||
//at present, assumes both initial and target location are
|
||||
//on the same horizontal plane (z=k plane) and projects
|
||||
//at a 45 degree angle.
|
||||
int id = (int)gen->GetArgDWord(0);
|
||||
|
||||
float x = gen->GetArgFloat(1);
|
||||
float y = gen->GetArgFloat(2);
|
||||
//float velocity = gen->GetArgFloat(3);
|
||||
//angle = pi/4 so t = v/(root 2 * g)
|
||||
//d = t * v/root 2 so d = v^2/(2g) => v = root(2dg)
|
||||
//component in x = component in y = root (dg)
|
||||
AbstractKart* kart = World::getWorld()->getKart(id);
|
||||
Vec3 pos = kart->getXYZ();
|
||||
float dx = x - pos[0];
|
||||
float dy = y - pos[2]; //blender uses xyz, bullet xzy
|
||||
float d = (sqrtf(dx*dx + dy*dy));
|
||||
float normalized_dx = dx / d;
|
||||
float normalized_dy = dy / d;
|
||||
float g = 9.81f;
|
||||
float velocity = sqrtf(d * g);
|
||||
|
||||
kart->setVelocity(btVector3(velocity * normalized_dx, velocity, velocity * normalized_dy));
|
||||
AbstractKart* kart = World::getWorld()->getKart(idKart);
|
||||
Vec3 v = kart->getXYZ();
|
||||
return SimpleVec3(v.getX(), v.getY(), v.getZ());
|
||||
}
|
||||
//Bind kart location
|
||||
void getKartLocation(asIScriptGeneric *gen)
|
||||
|
||||
/** Sets the kart's velocity to the specified value. */
|
||||
void setVelocity(int idKart, Vec3* position)
|
||||
{
|
||||
int id = (int)gen->GetArgDWord(0);
|
||||
|
||||
AbstractKart* kart = World::getWorld()->getKart(id);
|
||||
Vec3 kart_loc = kart->getXYZ();
|
||||
void *pointer = &kart_loc;
|
||||
|
||||
gen->SetReturnObject(pointer);
|
||||
}
|
||||
//Bind setter for velocity
|
||||
void setVelocity(asIScriptGeneric *gen)
|
||||
{
|
||||
int id = (int)gen->GetArgDWord(0);
|
||||
Vec3 *position = (Vec3*)gen->GetArgAddress(1);
|
||||
|
||||
float x = position->getX();
|
||||
float y = position->getY();
|
||||
float z = position->getZ();
|
||||
|
||||
AbstractKart* kart = World::getWorld()->getKart(id);
|
||||
AbstractKart* kart = World::getWorld()->getKart(idKart);
|
||||
kart->setVelocity(btVector3(x, y, z));
|
||||
}
|
||||
|
||||
/** @}*/
|
||||
/** @}*/
|
||||
|
||||
void registerScriptFunctions(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
r = engine->RegisterGlobalFunction("void squashKart(int id, float time)", asFUNCTION(squashKart), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void teleportKart(int id, Vec3 &in)", asFUNCTION(teleportKart), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void setVelocity(int id, Vec3 &in)", asFUNCTION(setVelocity), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void jumpKartTo(int id, float x, float y)", asFUNCTION(jumpKartTo), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("Vec3 getKartLocation(int id)", asFUNCTION(getKartLocation), asCALL_GENERIC); assert(r >= 0);
|
||||
int r; // of type asERetCodes
|
||||
engine->SetDefaultNamespace("Kart");
|
||||
r = engine->RegisterGlobalFunction("void squash(int id, float time)", asFUNCTION(squash), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void teleport(int id, const Vec3 &in)", asFUNCTION(teleport), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void setVelocity(int id, const Vec3 &in)", asFUNCTION(setVelocity), asCALL_CDECL); assert(r >= 0);
|
||||
//r = engine->RegisterGlobalFunction("void jumpTo(int id, float x, float y)", asFUNCTION(jumpTo), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("Vec3 getLocation(int id)", asFUNCTION(getLocation), asCALL_CDECL); assert(r >= 0);
|
||||
}
|
||||
|
||||
void registerScriptEnums(asIScriptEngine *engine)
|
||||
{
|
||||
// TODO: document enum in doxygen-generated scripting docs
|
||||
engine->SetDefaultNamespace("Kart");
|
||||
engine->RegisterEnum("PowerupType");
|
||||
engine->RegisterEnumValue("PowerupType", "ANVIL", PowerupManager::PowerupType::POWERUP_ANVIL);
|
||||
engine->RegisterEnumValue("PowerupType", "BOWLING", PowerupManager::PowerupType::POWERUP_BOWLING);
|
||||
engine->RegisterEnumValue("PowerupType", "BUBBLEGUM", PowerupManager::PowerupType::POWERUP_BUBBLEGUM);
|
||||
engine->RegisterEnumValue("PowerupType", "CAKE", PowerupManager::PowerupType::POWERUP_CAKE);
|
||||
engine->RegisterEnumValue("PowerupType", "PARACHUTE", PowerupManager::PowerupType::POWERUP_PARACHUTE);
|
||||
engine->RegisterEnumValue("PowerupType", "PLUNGER", PowerupManager::PowerupType::POWERUP_PLUNGER);
|
||||
engine->RegisterEnumValue("PowerupType", "RUBBERBALL", PowerupManager::PowerupType::POWERUP_RUBBERBALL);
|
||||
engine->RegisterEnumValue("PowerupType", "SWATTER", PowerupManager::PowerupType::POWERUP_SWATTER);
|
||||
engine->RegisterEnumValue("PowerupType", "SWITCH", PowerupManager::PowerupType::POWERUP_SWITCH);
|
||||
engine->RegisterEnumValue("PowerupType", "ZIPPER", PowerupManager::PowerupType::POWERUP_ZIPPER);
|
||||
}
|
||||
}
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
}
|
||||
/** \endcond */
|
||||
|
@ -23,13 +23,12 @@
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
|
||||
namespace Kart
|
||||
{
|
||||
|
||||
void registerScriptFunctions(asIScriptEngine *engine);
|
||||
|
||||
void registerScriptEnums(asIScriptEngine *engine);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -29,6 +29,7 @@ namespace Scripting
|
||||
namespace Physics
|
||||
{
|
||||
//Creates an explosion animation at specified Vec3 location
|
||||
// TODO: does this even belong in Physics?
|
||||
void createExplosion(asIScriptGeneric *gen)
|
||||
{
|
||||
//TODO: allow different types? sand etc
|
||||
@ -36,56 +37,10 @@ namespace Scripting
|
||||
HitEffect *he = new Explosion(*explosion_loc, "explosion", "explosion_bomb.xml");
|
||||
projectile_manager->addHitEffect(he);
|
||||
}
|
||||
//Bind getters for colliding karts
|
||||
void getCollidingKart1(asIScriptGeneric *gen)
|
||||
{
|
||||
gen->SetReturnDWord(m_collidingkartid1);
|
||||
}
|
||||
void getCollidingKart2(asIScriptGeneric *gen)
|
||||
{
|
||||
gen->SetReturnDWord(m_collidingkartid2);
|
||||
}
|
||||
//Bind getter for colliding objects
|
||||
void getCollidingID(asIScriptGeneric *gen)
|
||||
{
|
||||
void *pointer = &m_collider1;
|
||||
gen->SetReturnObject(pointer);
|
||||
}
|
||||
void getCollisionType(asIScriptGeneric *gen)
|
||||
{
|
||||
void *pointer = &m_collisionType;
|
||||
gen->SetReturnObject(pointer);
|
||||
}
|
||||
|
||||
//Callbacks from Physics Engine, for collisions
|
||||
void setCollision(int collider1,int collider2)
|
||||
{
|
||||
m_collidingkartid1 = collider1;
|
||||
m_collidingkartid2 = collider2;
|
||||
}
|
||||
void setCollision(std::string collider1, std::string collider2)
|
||||
{
|
||||
m_collider1 = collider1;
|
||||
m_collider2 = collider2;
|
||||
}
|
||||
void setCollisionType(std::string collisionType)
|
||||
{
|
||||
m_collisionType = collisionType;
|
||||
}
|
||||
asIScriptFunction* registerScriptCallbacks(asIScriptEngine *engine)
|
||||
{
|
||||
asIScriptFunction *func;
|
||||
std::string function_name = "void on" + m_collisionType + "Collision()";
|
||||
func = engine->GetModule(0)->GetFunctionByDecl(function_name.c_str());
|
||||
return func;
|
||||
}
|
||||
void registerScriptFunctions(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
r = engine->RegisterGlobalFunction("uint getCollidingKart1()", asFUNCTION(getCollidingKart1), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("uint getCollidingKart2()", asFUNCTION(getCollidingKart2), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("string getCollisionType()", asFUNCTION(getCollisionType), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string getCollidingID()", asFUNCTION(getCollidingID), asCALL_GENERIC); assert(r >= 0);
|
||||
engine->SetDefaultNamespace("Physics");
|
||||
r = engine->RegisterGlobalFunction("string createExplosion(Vec3 &in)", asFUNCTION(createExplosion), asCALL_GENERIC); assert(r >= 0);
|
||||
}
|
||||
}
|
||||
|
@ -28,33 +28,10 @@ namespace Scripting
|
||||
namespace Physics
|
||||
{
|
||||
|
||||
//IDs of kart collisions
|
||||
int m_collidingkartid1;
|
||||
int m_collidingkartid2;
|
||||
|
||||
//Details of collision
|
||||
std::string m_collider1;
|
||||
std::string m_collider2;
|
||||
std::string m_collisionType;
|
||||
|
||||
//script engine functions
|
||||
void registerScriptFunctions(asIScriptEngine *engine);
|
||||
asIScriptFunction*
|
||||
registerScriptCallbacks(asIScriptEngine *engine);
|
||||
|
||||
|
||||
//game engine functions
|
||||
void setCollision(int collider1, int collider2);
|
||||
void setCollisionType(std::string);
|
||||
|
||||
|
||||
|
||||
//script-bound functions
|
||||
void getCollidingKart1(asIScriptGeneric *gen);
|
||||
void getCollidingKart2(asIScriptGeneric *gen);
|
||||
void getCollsionType(asIScriptGeneric *gen);
|
||||
void getCollidingID(asIScriptGeneric *gen);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,286 +24,284 @@
|
||||
#include "input/input_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "states_screens/dialogs/tutorial_message_dialog.hpp"
|
||||
#include "states_screens/dialogs/race_paused_dialog.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_object.hpp"
|
||||
#include "tracks/track_object_manager.hpp"
|
||||
|
||||
#include <angelscript.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream> //debug
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
namespace Scripting
|
||||
{
|
||||
|
||||
/** \endcond */
|
||||
namespace Track
|
||||
{
|
||||
//register callbacks
|
||||
asIScriptFunction* registerScriptCallbacks(asIScriptEngine *engine, std::string scriptName)
|
||||
{
|
||||
asIScriptFunction *func;
|
||||
std::string function_name = "void " + scriptName + "()";
|
||||
func = engine->GetModule(0)->GetFunctionByDecl(function_name.c_str());
|
||||
return func;
|
||||
}
|
||||
asIScriptFunction* registerStartScriptCallbacks(asIScriptEngine *engine)
|
||||
{
|
||||
asIScriptFunction *func;
|
||||
func = engine->GetModule(0)->GetFunctionByDecl("void onStart()");
|
||||
return func;
|
||||
}
|
||||
asIScriptFunction* registerUpdateScriptCallbacks(asIScriptEngine *engine)
|
||||
{
|
||||
asIScriptFunction *func;
|
||||
func = engine->GetModule(0)->GetFunctionByDecl("void onUpdate()");
|
||||
return func;
|
||||
}
|
||||
/** \addtogroup Scripting
|
||||
* @{
|
||||
*/
|
||||
/** \addtogroup Scripting_Track Track
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*
|
||||
void disableAnimation(std::string *name, void *memory)
|
||||
{
|
||||
std::string *str = name;
|
||||
std::string type = "mesh";
|
||||
World::getWorld()->getTrack()->getTrackObjectManager()->disable(*str, type);
|
||||
}*/
|
||||
//disables track object passed from the script
|
||||
void disable(void *memory)
|
||||
{
|
||||
((PhysicalObject*)(memory))->removeBody();
|
||||
}
|
||||
//enables track object passed from the script
|
||||
void enable(void *memory)
|
||||
{
|
||||
((PhysicalObject*)(memory))->addBody();
|
||||
}
|
||||
//pause an animation
|
||||
void setPaused(bool mode, void *memory)
|
||||
{
|
||||
((ThreeDAnimation*)(memory))->setPaused(mode);
|
||||
}
|
||||
//move objects of type TrackObjectPresentation, to the specified location
|
||||
void movePresentation(Vec3 *new_pos, void *memory)
|
||||
{
|
||||
core::vector3df xyz = new_pos->toIrrVector();
|
||||
core::vector3df hpr = core::vector3df(0, 0, 0);
|
||||
core::vector3df scale = core::vector3df(1, 1, 1);
|
||||
((TrackObjectPresentation*)(memory))->move(xyz, hpr, scale, false);
|
||||
}
|
||||
//stop a sound
|
||||
void stop(void *memory)
|
||||
{
|
||||
((TrackObjectPresentationSound*)memory)->stopSound();
|
||||
}
|
||||
//play the specified sound once
|
||||
void playOnce(void *memory)
|
||||
{
|
||||
((TrackObjectPresentationSound*)memory)->triggerSound(false); //false = once
|
||||
}
|
||||
//play the specified sound continuously
|
||||
void playLoop(void *memory)
|
||||
{
|
||||
((TrackObjectPresentationSound*)memory)->triggerSound(true); //true = loop
|
||||
}
|
||||
//sets a loop for an animation (skeletal)
|
||||
void setLoop(int start, int end, void *memory)
|
||||
{
|
||||
((TrackObjectPresentationMesh*)(memory))->setLoop(start,end);
|
||||
}
|
||||
//sets the current frame for a skeletal animation
|
||||
void setCurrentFrame(int frame,void *memory)
|
||||
{
|
||||
((TrackObjectPresentationMesh*)(memory))->setCurrentFrame(frame);
|
||||
}
|
||||
//getter for current frame in a skeletal animation
|
||||
void getCurrentFrame(void *memory)
|
||||
{
|
||||
((TrackObjectPresentationMesh*)(memory))->getCurrentFrame();
|
||||
}
|
||||
//getter for key binding for player action enums
|
||||
void getKeyBinding(asIScriptGeneric *gen)
|
||||
{
|
||||
int Enum_value = (int)gen->GetArgDWord(0);
|
||||
InputDevice* device = input_manager->getDeviceManager()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw control;
|
||||
PlayerAction ScriptAction = (PlayerAction)Enum_value;
|
||||
control = config->getBindingAsString(ScriptAction);
|
||||
std::string key = std::string(irr::core::stringc(control).c_str());
|
||||
void *key_pointer = &key;
|
||||
gen->SetReturnObject(key_pointer);
|
||||
}
|
||||
//generic track object getter, Entry point of track objects into scripts
|
||||
void getTrackObject(asIScriptGeneric *gen)
|
||||
{
|
||||
std::string *str = (std::string*)gen->GetArgAddress(0);
|
||||
TrackObject* t_obj = World::getWorld()->getTrack()->getTrackObjectManager()->getTrackObject(*str);
|
||||
gen->SetReturnObject(t_obj);
|
||||
}
|
||||
//runs the script specified by the given string
|
||||
void runScript(asIScriptGeneric *gen)
|
||||
{
|
||||
std::string *str = (std::string*)gen->GetArgAddress(0);
|
||||
ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
||||
script_engine->runScript(*str);
|
||||
}
|
||||
/*TrackObject* getTrackObject(std::string *name)
|
||||
{
|
||||
TrackObject* t_obj = World::getWorld()->getTrack()->getTrackObjectManager()->getTrackObject(*name);
|
||||
return t_obj;
|
||||
std::string *str = name;
|
||||
std::string type = "mesh";
|
||||
World::getWorld()->getTrack()->getTrackObjectManager()->disable(*str, type);
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Get a track object by ID.
|
||||
* @return An object of type @ref Scripting_TrackObject
|
||||
*/
|
||||
TrackObject* getTrackObject(std::string* objID)
|
||||
{
|
||||
return World::getWorld()->getTrack()->getTrackObjectManager()->getTrackObject(*objID);
|
||||
}
|
||||
|
||||
// Displays the message specified in displayMessage( string message ) within the script
|
||||
void displayMessage(asIScriptGeneric *gen)
|
||||
/** Hide/disable a track object */
|
||||
void disableTrackObject(std::string* objID)
|
||||
{
|
||||
std::string *input = (std::string*)gen->GetArgAddress(0);
|
||||
irr::core::stringw out = irr::core::stringw((*input).c_str()); //irr::core::stringw supported by message dialogs
|
||||
new TutorialMessageDialog((out), true);
|
||||
World::getWorld()->getTrack()->getTrackObjectManager()->disable(*objID);
|
||||
}
|
||||
//generic disable method for track objects
|
||||
void disableTrackObject(asIScriptGeneric *gen)
|
||||
|
||||
/** Show/enable a track objects */
|
||||
void enableTrackObject(std::string* objID)
|
||||
{
|
||||
std::string *str = (std::string*)gen->GetArgAddress(0);
|
||||
World::getWorld()->getTrack()->getTrackObjectManager()->disable(*str);
|
||||
World::getWorld()->getTrack()->getTrackObjectManager()->enable(*objID);
|
||||
}
|
||||
//generic enable method for track objects
|
||||
void enableTrackObject(asIScriptGeneric *gen)
|
||||
|
||||
/** Disables an action trigger of specified ID */
|
||||
void disableTrigger(std::string* triggerID)
|
||||
{
|
||||
std::string *str = (std::string*)gen->GetArgAddress(0);
|
||||
World::getWorld()->getTrack()->getTrackObjectManager()->enable(*str);
|
||||
World::getWorld()->getTrack()->getTrackObjectManager()->disable(*triggerID);
|
||||
}
|
||||
//disables an action trigger of specified ID
|
||||
void disableTrigger(asIScriptGeneric *gen)
|
||||
|
||||
/** Enables an action trigger of specified ID */
|
||||
void enableTrigger(std::string* triggerID)
|
||||
{
|
||||
std::string *str = (std::string*)gen->GetArgAddress(0);
|
||||
World::getWorld()->getTrack()->getTrackObjectManager()->disable(*str);
|
||||
World::getWorld()->getTrack()->getTrackObjectManager()->enable(*triggerID);
|
||||
}
|
||||
//enables an action trigger of specified ID
|
||||
void enableTrigger(asIScriptGeneric *gen)
|
||||
|
||||
/** Creates a trigger at the specified location */
|
||||
void createTrigger(std::string* triggerID, Vec3* creation_loc, float distance)
|
||||
{
|
||||
std::string *str = (std::string*)gen->GetArgAddress(0);
|
||||
World::getWorld()->getTrack()->getTrackObjectManager()->enable(*str);
|
||||
}
|
||||
//Creates a trigger at the specified location
|
||||
void createTrigger(asIScriptGeneric *gen)
|
||||
{
|
||||
std::string *script_name = (std::string*)gen->GetArgAddress(0);
|
||||
Vec3 *creation_loc = (Vec3*)gen->GetArgAddress(1);
|
||||
float x = creation_loc->getX();
|
||||
float y = creation_loc->getY();
|
||||
float z = creation_loc->getZ();
|
||||
float distance = gen->GetArgFloat(2); //triggering distance
|
||||
core::vector3df posi(x, y, z);
|
||||
core::vector3df hpr(0, 0, 0);
|
||||
core::vector3df scale(1.0f, 1.0f, 1.0f);
|
||||
TrackObjectPresentationActionTrigger* newtrigger =
|
||||
new TrackObjectPresentationActionTrigger(posi, *script_name, distance);
|
||||
new TrackObjectPresentationActionTrigger(posi, *triggerID, distance);
|
||||
TrackObject* tobj = new TrackObject(posi, hpr, scale,
|
||||
"none", newtrigger, false /* isDynamic */, NULL /* physics settings */);
|
||||
tobj->setID(*script_name);
|
||||
tobj->setID(*triggerID);
|
||||
World::getWorld()->getTrack()->getTrackObjectManager()->insertObject(tobj);
|
||||
}
|
||||
|
||||
/** Exits the race to the main menu */
|
||||
void exitRace()
|
||||
{
|
||||
World::getWorld()->scheduleExitRace();
|
||||
}
|
||||
|
||||
void pauseRace()
|
||||
{
|
||||
new RacePausedDialog(0.8f, 0.6f);
|
||||
}
|
||||
}
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
namespace Track
|
||||
{
|
||||
/** \endcond */
|
||||
|
||||
// ----------- TrackObjectPresentationMesh methods -----------
|
||||
// TODO: this method is WRONG, we should in most cases move not the presentation but the entire object
|
||||
//void movePresentation(Vec3 *new_pos, void *memory)
|
||||
//{
|
||||
// core::vector3df xyz = new_pos->toIrrVector();
|
||||
// core::vector3df hpr = core::vector3df(0, 0, 0);
|
||||
// core::vector3df scale = core::vector3df(1, 1, 1);
|
||||
// ((TrackObjectPresentation*)(memory))->move(xyz, hpr, scale, false);
|
||||
//}
|
||||
|
||||
namespace Mesh
|
||||
{
|
||||
/**
|
||||
* \addtogroup Scripting_Mesh Mesh (script binding)
|
||||
* Type returned by trackObject.getMesh()
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Sets a loop for a skeletal animation */
|
||||
// TODO: can we use a type and avoid void* ?
|
||||
void setLoop(int start, int end /** \cond DOXYGEN_IGNORE */, void *memory /** \endcond */)
|
||||
{
|
||||
((TrackObjectPresentationMesh*)(memory))->setLoop(start, end);
|
||||
}
|
||||
|
||||
/** Sets the current frame for a skeletal animation */
|
||||
void setCurrentFrame(int frame /** \cond DOXYGEN_IGNORE */, void *memory /** \endcond */)
|
||||
{
|
||||
((TrackObjectPresentationMesh*)(memory))->setCurrentFrame(frame);
|
||||
}
|
||||
|
||||
/** Get current frame in a skeletal animation */
|
||||
int getCurrentFrame(/** \cond DOXYGEN_IGNORE */void *memory /** \endcond */)
|
||||
{
|
||||
return ((TrackObjectPresentationMesh*)(memory))->getCurrentFrame();
|
||||
}
|
||||
/** @} */
|
||||
}
|
||||
|
||||
// ----------- Animator Object methods -----------
|
||||
|
||||
namespace Animator
|
||||
{
|
||||
/**
|
||||
* \addtogroup Scripting_Animator Animator (script binding)
|
||||
* Type returned by trackObject.getIPOAnimator()
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Pause/resumes a curve-based animation */
|
||||
void setPaused(bool mode /** \cond DOXYGEN_IGNORE */, void *memory /** \endcond */)
|
||||
{
|
||||
((ThreeDAnimation*)(memory))->setPaused(mode);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
}
|
||||
|
||||
// ----------- Sound Object methods -----------
|
||||
|
||||
namespace SoundEmitter
|
||||
{
|
||||
/**
|
||||
* @addtogroup Scripting_SoundEmitter SoundEmitter (script binding)
|
||||
* Type returned by trackObject.getSoundEmitter()
|
||||
* @{
|
||||
*/
|
||||
|
||||
// TODO: adjust all signatures to type "void*" parameters if possible
|
||||
/** Stop a sound */
|
||||
void stop(/** \cond DOXYGEN_IGNORE */void *memory /** \endcond */)
|
||||
{
|
||||
((TrackObjectPresentationSound*)memory)->stopSound();
|
||||
}
|
||||
|
||||
/** Play the specified sound once */
|
||||
void playOnce(/** \cond DOXYGEN_IGNORE */void *memory /** \endcond */)
|
||||
{
|
||||
((TrackObjectPresentationSound*)memory)->triggerSound(false); //false = once
|
||||
}
|
||||
|
||||
/** Play the specified sound continuously */
|
||||
void playLoop(/** \cond DOXYGEN_IGNORE */void *memory /** \endcond */)
|
||||
{
|
||||
((TrackObjectPresentationSound*)memory)->triggerSound(true); //true = loop
|
||||
}
|
||||
/** @} */
|
||||
}
|
||||
|
||||
// ----------- ParticleEmitter Object methods -----------
|
||||
|
||||
namespace ParticleEmitter
|
||||
{
|
||||
/**
|
||||
* @addtogroup Scripting_ParticleEmitter ParticleEmitter (script binding)
|
||||
* Type returned by trackObject.getParticleEmitter()
|
||||
* @{
|
||||
*/
|
||||
|
||||
// TODO: adjust all signatures to type "void*" parameters if possible
|
||||
/** Stop particle emission */
|
||||
void stop(/** \cond DOXYGEN_IGNORE */ void *memory /** \endcond */)
|
||||
{
|
||||
((TrackObjectPresentationParticles*)memory)->stop();
|
||||
}
|
||||
|
||||
/** Play the specified sound once */
|
||||
void setEmissionRate(float rate /** \cond DOXYGEN_IGNORE */, void *memory /** \endcond */)
|
||||
{
|
||||
((TrackObjectPresentationParticles*)memory)->setRate(rate);
|
||||
}
|
||||
/** @} */
|
||||
}
|
||||
|
||||
/** @}*/
|
||||
/** @}*/
|
||||
|
||||
void registerScriptFunctions(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
int r; // of type asERetCodes
|
||||
|
||||
r = engine->RegisterGlobalFunction("void displayMessage(string &in)", asFUNCTION(displayMessage), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void disable(string &in)", asFUNCTION(disableTrackObject), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void enable(string &in)", asFUNCTION(enableTrackObject), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void enableTrigger(string &in)", asFUNCTION(enableTrigger), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void disableTrigger(string &in)", asFUNCTION(disableTrigger), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void createTrigger(string &in,Vec3 &in, float distance)",
|
||||
asFUNCTION(createTrigger), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string getKeyBinding(int input)", asFUNCTION(getKeyBinding), asCALL_GENERIC); assert(r >= 0);
|
||||
engine->SetDefaultNamespace("Track");
|
||||
|
||||
|
||||
/*
|
||||
//Test singleton, and various calling conventions
|
||||
// Register the track object manager as a singleton. The script will access it through the global property
|
||||
//r = engine->RegisterObjectType("TrackObjectManager", 0, asOBJ_REF | asOBJ_NOHANDLE); assert(r >= 0);
|
||||
r = engine->RegisterObjectType("TrackObjectManager", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
||||
|
||||
// Register the track object manager's methods
|
||||
TrackObjectManager* track_obj_manager = World::getWorld()->getTrack()->getTrackObjectManager();
|
||||
r = engine->RegisterGlobalProperty("TrackObjectManager track_obj_manager", track_obj_manager); assert(r >= 0);
|
||||
//r = engine->RegisterObjectMethod("TrackObjectManager", "void disable(string name , string type)", asMETHOD(TrackObjectManager, disable), asCALL_THISCALL); assert(r >= 0);
|
||||
//r = engine->RegisterObjectMethod("TrackObjectManager", "void disable(string &in name)", asFUNCTION(disableAnimation), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObjectManager", "void disable(string &in)", asFUNCTION(disableAnimation), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
*/
|
||||
//TrackObject
|
||||
r = engine->RegisterObjectType("TrackObject", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("TrackObject @getTrackObject(string &in)", asFUNCTION(getTrackObject), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "void setEnable(bool status)", asMETHOD(TrackObject, setEnable), asCALL_THISCALL); assert(r >= 0);
|
||||
|
||||
|
||||
//PhysicalObject
|
||||
r = engine->RegisterObjectType("PhysicalObject", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "PhysicalObject @getPhysicalObject()", asMETHOD(TrackObject, getPhysicalObjectForScript), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("PhysicalObject", "bool isFlattener()", asMETHOD(PhysicalObject, isFlattenKartObject), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("PhysicalObject", "void disable()", asFUNCTION(disable), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("PhysicalObject", "void enable()", asFUNCTION(enable), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
|
||||
|
||||
//Mesh or Skeletal Animation
|
||||
r = engine->RegisterObjectType("Mesh", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "Mesh @getMesh()", asMETHOD(TrackObject, getMesh), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("Mesh", "void setLoop(int start, int end)", asFUNCTION(setLoop), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("Mesh", "int getCurrentFrame()", asFUNCTION(getCurrentFrame), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("Mesh", "void setCurrentFrame(int frame)", asFUNCTION(setCurrentFrame), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("Mesh", "void move(Vec3 &in)", asFUNCTION(movePresentation), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
|
||||
//Particle Emitter
|
||||
r = engine->RegisterObjectType("Mesh", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0); // TrackObjectPresentationMesh
|
||||
r = engine->RegisterObjectType("ParticleEmitter", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "ParticleEmitter @getParticleEmitter()", asMETHOD(TrackObject, getParticles), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("ParticleEmitter", "void move(Vec3 &in)", asFUNCTION(movePresentation), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
|
||||
//Sound Effect
|
||||
r = engine->RegisterObjectType("SoundEmitter", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "SoundEmitter @getSoundEmitter()", asMETHOD(TrackObject, getSound), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("SoundEmitter", "void move(Vec3 &in)", asFUNCTION(movePresentation), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("SoundEmitter", "void stop()", asFUNCTION(stop), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("SoundEmitter", "void playOnce()", asFUNCTION(playOnce), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("SoundEmitter", "void playLoop()", asFUNCTION(playLoop), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
|
||||
|
||||
|
||||
//Curve based Animation
|
||||
r = engine->RegisterObjectType("Animator", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "Animator @getAnimator()", asMETHOD(TrackObject, getAnimatorForScript), asCALL_THISCALL); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterGlobalFunction("void disableTrackObject(const string &in)", asFUNCTION(disableTrackObject), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void enableTrackObject(const string &in)", asFUNCTION(enableTrackObject), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void enableTrigger(const string &in)", asFUNCTION(enableTrigger), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void disableTrigger(const string &in)", asFUNCTION(disableTrigger), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void createTrigger(const string &in, const Vec3 &in, float distance)",
|
||||
asFUNCTION(createTrigger), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("TrackObject@ getTrackObject(const string &in)", asFUNCTION(getTrackObject), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void exitRace()", asFUNCTION(exitRace), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void pauseRace()", asFUNCTION(pauseRace), asCALL_CDECL); assert(r >= 0);
|
||||
|
||||
// TrackObject
|
||||
r = engine->RegisterObjectMethod("TrackObject", "void setEnable(bool status)", asMETHOD(TrackObject, setEnable), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "SoundEmitter@ getSoundEmitter()", asMETHOD(TrackObject, getSoundEmitter), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "PhysicalObject@ getPhysics()", asMETHOD(TrackObject, getPhysics), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "Mesh@ getMesh()", asMETHOD(TrackObject, getMesh), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "ParticleEmitter@ getParticleEmitter()", asMETHOD(TrackObject, getParticleEmitter), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "Animator@ getIPOAnimator()", asMETHOD(TrackObject, getIPOAnimator), asCALL_THISCALL); assert(r >= 0);
|
||||
// TODO: add move method
|
||||
|
||||
// PhysicalObject
|
||||
r = engine->RegisterObjectMethod("PhysicalObject", "bool isFlattenKartObject()", asMETHOD(PhysicalObject, isFlattenKartObject), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("PhysicalObject", "void disable()", asMETHOD(PhysicalObject, disable), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("PhysicalObject", "void enable()", asMETHOD(PhysicalObject, enable), asCALL_THISCALL); assert(r >= 0);
|
||||
|
||||
// TrackObjectPresentationMesh (Mesh or Skeletal Animation)
|
||||
r = engine->RegisterObjectMethod("Mesh", "void setLoop(int start, int end)", asFUNCTION(Mesh::setLoop), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("Mesh", "int getCurrentFrame()", asFUNCTION(Mesh::getCurrentFrame), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("Mesh", "void setCurrentFrame(int frame)", asFUNCTION(Mesh::setCurrentFrame), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
//r = engine->RegisterObjectMethod("Mesh", "void move(Vec3 &in)", asFUNCTION(movePresentation), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
|
||||
// Particle Emitter
|
||||
r = engine->RegisterObjectMethod("ParticleEmitter", "void stop()", asFUNCTION(ParticleEmitter::stop), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("ParticleEmitter", "void setEmissionRate(float)", asFUNCTION(ParticleEmitter::setEmissionRate), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
|
||||
// Sound Effect
|
||||
//r = engine->RegisterObjectMethod("SoundEmitter", "void move(Vec3 &in)", asFUNCTION(movePresentation), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("SoundEmitter", "void stop()", asFUNCTION(SoundEmitter::stop), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("SoundEmitter", "void playOnce()", asFUNCTION(SoundEmitter::playOnce), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("SoundEmitter", "void playLoop()", asFUNCTION(SoundEmitter::playLoop), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
|
||||
|
||||
// Curve based Animation
|
||||
//fails due to insufficient visibility to scripts TODO : Decide whether to fix visibility or introduce wrappers
|
||||
//r = engine->RegisterObjectMethod("Animator", "void setPaused(bool mode)", asMETHOD(ThreeDAnimation, setPaused), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("Animator", "void setPaused(bool mode)", asFUNCTION( setPaused ), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterGlobalFunction("void runScript(string &in)", asFUNCTION(runScript), asCALL_GENERIC); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterObjectMethod("Animator", "void setPaused(bool mode)", asFUNCTION(Animator::setPaused), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
// TODO: add method to set current frame
|
||||
// TODO: add method to launch playback from frame X to frame Y
|
||||
// TODO: add method to register onAnimationComplete notifications ?
|
||||
}
|
||||
|
||||
void registerScriptEnums(asIScriptEngine *engine)
|
||||
{
|
||||
|
||||
engine->RegisterEnum("PA");
|
||||
engine->RegisterEnumValue("PA", "STEER_LEFT", PA_STEER_LEFT);
|
||||
engine->RegisterEnumValue("PA", "STEER_RIGHT", PA_STEER_RIGHT);
|
||||
engine->RegisterEnumValue("PA", "ACCEL", PA_ACCEL);
|
||||
engine->RegisterEnumValue("PA", "BRAKE", PA_BRAKE);
|
||||
engine->RegisterEnumValue("PA", "NITRO", PA_NITRO);
|
||||
engine->RegisterEnumValue("PA", "DRIFT", PA_DRIFT);
|
||||
engine->RegisterEnumValue("PA", "RESCUE", PA_RESCUE);
|
||||
engine->RegisterEnumValue("PA", "FIRE", PA_FIRE);
|
||||
engine->RegisterEnumValue("PA", "LOOK_BACK", PA_LOOK_BACK);
|
||||
engine->RegisterEnumValue("PA", "PAUSE_RACE", PA_PAUSE_RACE);
|
||||
engine->RegisterEnumValue("PA", "MENU_UP", PA_MENU_UP);
|
||||
engine->RegisterEnumValue("PA", "MENU_DOWN", PA_MENU_DOWN);
|
||||
engine->RegisterEnumValue("PA", "MENU_LEFT", PA_MENU_LEFT);
|
||||
engine->RegisterEnumValue("PA", "MENU_RIGHT", PA_MENU_RIGHT);
|
||||
engine->RegisterEnumValue("PA", "MENU_SELECT", PA_MENU_SELECT);
|
||||
engine->RegisterEnumValue("PA", "MENU_CANCEL", PA_MENU_CANCEL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
}
|
||||
}
|
||||
/** \endcond */
|
||||
|
||||
|
@ -25,25 +25,10 @@
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
|
||||
namespace Track
|
||||
{
|
||||
|
||||
//script engine functions
|
||||
void registerScriptFunctions(asIScriptEngine *engine);
|
||||
asIScriptFunction*
|
||||
registerScriptCallbacks(asIScriptEngine *engine , std::string scriptName);
|
||||
void registerScriptEnums(asIScriptEngine *engine);
|
||||
|
||||
|
||||
//script-bound functions
|
||||
void displayMessage(asIScriptGeneric *gen);
|
||||
void disableAnimation(asIScriptGeneric *gen);
|
||||
void enableAnimation(asIScriptGeneric *gen);
|
||||
void enableTrigger(asIScriptGeneric *gen);
|
||||
void disableTrigger(asIScriptGeneric *gen);
|
||||
void createTrigger(asIScriptGeneric *gen);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
174
src/scriptengine/script_utils.cpp
Normal file
174
src/scriptengine/script_utils.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 SuperTuxKart Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "script_track.hpp"
|
||||
|
||||
#include "animations/three_d_animation.hpp"
|
||||
#include "input/device_manager.hpp"
|
||||
#include "input/input_device.hpp"
|
||||
#include "input/input_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "states_screens/dialogs/tutorial_message_dialog.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_object.hpp"
|
||||
#include "tracks/track_object_manager.hpp"
|
||||
|
||||
#include <angelscript.h>
|
||||
#include "scriptarray.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream> //debug
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
namespace Scripting
|
||||
{
|
||||
/** \endcond */
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
/** \addtogroup Scripting
|
||||
* @{
|
||||
*/
|
||||
/** \addtogroup Utils
|
||||
* @{
|
||||
*/
|
||||
// TODO: build these variations with variadic templates?
|
||||
|
||||
/** Replaces placeholders with values. Note, in angelscript, omit the trailing number.
|
||||
* e.g. Utils::insertValues("Hello %s !", "world");
|
||||
*/
|
||||
std::string insertValues(std::string* formatString, std::string* arg1)
|
||||
{
|
||||
irr::core::stringw out = StringUtils::insertValues(StringUtils::utf8_to_wide(formatString->c_str()),
|
||||
StringUtils::utf8_to_wide(arg1->c_str()));
|
||||
|
||||
return StringUtils::wide_to_utf8(out.c_str());
|
||||
}
|
||||
|
||||
/** Replaces placeholders with values. Note, in angelscript, omit the trailing number.
|
||||
* e.g. Utils::insertValues("Hello %s %s !", "John", "Doe");
|
||||
*/
|
||||
std::string insertValues(std::string* formatString, std::string* arg1, std::string* arg2)
|
||||
{
|
||||
irr::core::stringw out = StringUtils::insertValues(StringUtils::utf8_to_wide(formatString->c_str()),
|
||||
StringUtils::utf8_to_wide(arg1->c_str()),
|
||||
StringUtils::utf8_to_wide(arg2->c_str()));
|
||||
|
||||
return StringUtils::wide_to_utf8(out.c_str());
|
||||
}
|
||||
|
||||
/** Replaces placeholders with values. Note, in angelscript, omit the trailing number.
|
||||
* e.g. Utils::insertValues("Hello %s %s %s !", "Mr", "John", "Doe");
|
||||
*/
|
||||
std::string insertValues(std::string* formatString, std::string* arg1, std::string* arg2,
|
||||
std::string* arg3)
|
||||
{
|
||||
irr::core::stringw out = StringUtils::insertValues(StringUtils::utf8_to_wide(formatString->c_str()),
|
||||
StringUtils::utf8_to_wide(arg1->c_str()),
|
||||
StringUtils::utf8_to_wide(arg2->c_str()),
|
||||
StringUtils::utf8_to_wide(arg3->c_str()));
|
||||
|
||||
return StringUtils::wide_to_utf8(out.c_str());
|
||||
}
|
||||
|
||||
/** Replaces placeholders with values. Note, in angelscript, omit the trailing number.
|
||||
* e.g. Utils::insertValues("%s %s %s %s !", "Hello", "Mr", "John", "Doe");
|
||||
*/
|
||||
std::string insertValues(std::string* formatString, std::string* arg1, std::string* arg2,
|
||||
std::string* arg3, std::string* arg4)
|
||||
{
|
||||
irr::core::stringw out = StringUtils::insertValues(StringUtils::utf8_to_wide(formatString->c_str()),
|
||||
StringUtils::utf8_to_wide(arg1->c_str()),
|
||||
StringUtils::utf8_to_wide(arg2->c_str()),
|
||||
StringUtils::utf8_to_wide(arg3->c_str()),
|
||||
StringUtils::utf8_to_wide(arg4->c_str()));
|
||||
|
||||
return StringUtils::wide_to_utf8(out.c_str());
|
||||
}
|
||||
|
||||
/** Runs the script specified by the given string */
|
||||
void runScript(const std::string* str)
|
||||
{
|
||||
ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
||||
script_engine->runFunction(*str);
|
||||
}
|
||||
|
||||
/** Log to the console */
|
||||
void logInfo(std::string* log)
|
||||
{
|
||||
Log::info("Script", "%s", log->c_str());
|
||||
}
|
||||
|
||||
/** Log warning to the console */
|
||||
void logWarning(std::string* log)
|
||||
{
|
||||
Log::warn("Script", "%s", log->c_str());
|
||||
}
|
||||
|
||||
/** Log error to the console */
|
||||
void logError(std::string* log)
|
||||
{
|
||||
Log::error("Script", "%s", log->c_str());
|
||||
}
|
||||
/** @}*/
|
||||
/** @}*/
|
||||
|
||||
// UNDOCUMENTED PROXIES : Use proxies to have different signatures, then redirect to the
|
||||
// documented function whose name is exposed in angelscript (these proxies exist so that
|
||||
// angelscript can properly resolve overloads, but doxygen can still generate the right docs
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
std::string proxy_insertValues1(std::string* formatString, std::string* arg1)
|
||||
{
|
||||
return insertValues(formatString, arg1);
|
||||
}
|
||||
std::string proxy_insertValues2(std::string* formatString, std::string* arg1, std::string* arg2)
|
||||
{
|
||||
return insertValues(formatString, arg1, arg2);
|
||||
}
|
||||
std::string proxy_insertValues3(std::string* formatString, std::string* arg1, std::string* arg2,
|
||||
std::string* arg3)
|
||||
{
|
||||
return insertValues(formatString, arg1, arg2, arg3);
|
||||
}
|
||||
std::string proxy_insertValues4(std::string* formatString, std::string* arg1, std::string* arg2,
|
||||
std::string* arg3, std::string* arg4)
|
||||
{
|
||||
return insertValues(formatString, arg1, arg2, arg3, arg4);
|
||||
}
|
||||
/** \endcond */
|
||||
|
||||
void registerScriptFunctions(asIScriptEngine *engine)
|
||||
{
|
||||
int r; // of type asERetCodes
|
||||
engine->SetDefaultNamespace("Utils");
|
||||
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in)", asFUNCTION(proxy_insertValues1), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in, const string &in)", asFUNCTION(proxy_insertValues2), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in, const string &in, const string &in)", asFUNCTION(proxy_insertValues3), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in, const string &in, const string &in, const string &in)", asFUNCTION(proxy_insertValues4), asCALL_CDECL); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterGlobalFunction("void runScript(string &in)", asFUNCTION(runScript), asCALL_CDECL); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterGlobalFunction("void logInfo(const string &in)", asFUNCTION(logInfo), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void logWarning(const string &in)", asFUNCTION(logWarning), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void logError(const string &in)", asFUNCTION(logError), asCALL_CDECL); assert(r >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
}
|
||||
/** \endcond */
|
34
src/scriptengine/script_utils.hpp
Normal file
34
src/scriptengine/script_utils.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 SuperTuxKart Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_SCRIPT_UTILS_HPP
|
||||
#define HEADER_SCRIPT_UTILS_HPP
|
||||
|
||||
#include <angelscript.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
namespace Utils
|
||||
{
|
||||
void registerScriptFunctions(asIScriptEngine *engine);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
@ -1,19 +1,32 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you
|
||||
must not claim that you wrote the original software. If you use
|
||||
this software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
The original version of this library can be located at:
|
||||
http://www.angelcode.com/angelscript/
|
||||
|
||||
Andreas Jonsson
|
||||
andreas@angelcode.com
|
||||
*/
|
||||
|
||||
#include <new>
|
||||
#include <stdlib.h>
|
||||
@ -27,6 +40,22 @@ using namespace std;
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// This macro is used to avoid warnings about unused variables.
|
||||
// Usually where the variables are only used in debug mode.
|
||||
#define UNUSED_VAR(x) (void)(x)
|
||||
|
||||
// Set the default memory routines
|
||||
// Use the angelscript engine's memory routines by default
|
||||
static asALLOCFUNC_t userAlloc = asAllocMem;
|
||||
static asFREEFUNC_t userFree = asFreeMem;
|
||||
|
||||
// Allows the application to set which memory routines should be used by the array object
|
||||
void CScriptArray::SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc)
|
||||
{
|
||||
userAlloc = allocFunc;
|
||||
userFree = freeFunc;
|
||||
}
|
||||
|
||||
static void RegisterScriptArray_Native(asIScriptEngine *engine);
|
||||
static void RegisterScriptArray_Generic(asIScriptEngine *engine);
|
||||
|
||||
@ -42,7 +71,7 @@ struct SArrayCache
|
||||
asIScriptFunction *cmpFunc;
|
||||
asIScriptFunction *eqFunc;
|
||||
int cmpFuncReturnCode; // To allow better error message in case of multiple matches
|
||||
int eqFuncReturnCode;
|
||||
int eqFuncReturnCode;
|
||||
};
|
||||
|
||||
// We just define a number here that we assume nobody else is using for
|
||||
@ -54,16 +83,31 @@ static void CleanupObjectTypeArrayCache(asIObjectType *type)
|
||||
{
|
||||
SArrayCache *cache = reinterpret_cast<SArrayCache*>(type->GetUserData(ARRAY_CACHE));
|
||||
if( cache )
|
||||
delete cache;
|
||||
{
|
||||
cache->~SArrayCache();
|
||||
userFree(cache);
|
||||
}
|
||||
}
|
||||
|
||||
static CScriptArray* ScriptArrayFactory2(asIObjectType *ot, asUINT length)
|
||||
CScriptArray* CScriptArray::Create(asIObjectType *ot, asUINT length)
|
||||
{
|
||||
CScriptArray *a = new CScriptArray(length, ot);
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
|
||||
// Allocate the memory
|
||||
void *mem = userAlloc(sizeof(CScriptArray));
|
||||
if( mem == 0 )
|
||||
{
|
||||
if( ctx )
|
||||
ctx->SetException("Out of memory");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize the object
|
||||
CScriptArray *a = new(mem) CScriptArray(length, ot);
|
||||
|
||||
// It's possible the constructor raised a script exception, in which case we
|
||||
// need to free the memory and return null instead, else we get a memory leak.
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION )
|
||||
{
|
||||
a->Release();
|
||||
@ -73,13 +117,25 @@ static CScriptArray* ScriptArrayFactory2(asIObjectType *ot, asUINT length)
|
||||
return a;
|
||||
}
|
||||
|
||||
static CScriptArray* ScriptArrayListFactory(asIObjectType *ot, void *initList)
|
||||
CScriptArray* CScriptArray::Create(asIObjectType *ot, void *initList)
|
||||
{
|
||||
CScriptArray *a = new CScriptArray(ot, initList);
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
|
||||
// Allocate the memory
|
||||
void *mem = userAlloc(sizeof(CScriptArray));
|
||||
if( mem == 0 )
|
||||
{
|
||||
if( ctx )
|
||||
ctx->SetException("Out of memory");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize the object
|
||||
CScriptArray *a = new(mem) CScriptArray(ot, initList);
|
||||
|
||||
// It's possible the constructor raised a script exception, in which case we
|
||||
// need to free the memory and return null instead, else we get a memory leak.
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION )
|
||||
{
|
||||
a->Release();
|
||||
@ -89,13 +145,25 @@ static CScriptArray* ScriptArrayListFactory(asIObjectType *ot, void *initList)
|
||||
return a;
|
||||
}
|
||||
|
||||
static CScriptArray* ScriptArrayFactoryDefVal(asIObjectType *ot, asUINT length, void *defVal)
|
||||
CScriptArray* CScriptArray::Create(asIObjectType *ot, asUINT length, void *defVal)
|
||||
{
|
||||
CScriptArray *a = new CScriptArray(length, defVal, ot);
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
|
||||
// Allocate the memory
|
||||
void *mem = userAlloc(sizeof(CScriptArray));
|
||||
if( mem == 0 )
|
||||
{
|
||||
if( ctx )
|
||||
ctx->SetException("Out of memory");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize the object
|
||||
CScriptArray *a = new(mem) CScriptArray(length, defVal, ot);
|
||||
|
||||
// It's possible the constructor raised a script exception, in which case we
|
||||
// need to free the memory and return null instead, else we get a memory leak.
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION )
|
||||
{
|
||||
a->Release();
|
||||
@ -105,20 +173,20 @@ static CScriptArray* ScriptArrayFactoryDefVal(asIObjectType *ot, asUINT length,
|
||||
return a;
|
||||
}
|
||||
|
||||
static CScriptArray* ScriptArrayFactory(asIObjectType *ot)
|
||||
CScriptArray* CScriptArray::Create(asIObjectType *ot)
|
||||
{
|
||||
return ScriptArrayFactory2(ot, asUINT(0));
|
||||
return CScriptArray::Create(ot, asUINT(0));
|
||||
}
|
||||
|
||||
// This optional callback is called when the template type is first used by the compiler.
|
||||
// It allows the application to validate if the template can be instanciated for the requested
|
||||
// It allows the application to validate if the template can be instantiated for the requested
|
||||
// subtype at compile time, instead of at runtime. The output argument dontGarbageCollect
|
||||
// allow the callback to tell the engine if the template instance type shouldn't be garbage collected,
|
||||
// i.e. no asOBJ_GC flag.
|
||||
static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageCollect)
|
||||
{
|
||||
// Make sure the subtype can be instanciated with a default factory/constructor,
|
||||
// otherwise we won't be able to instanciate the elements.
|
||||
// Make sure the subtype can be instantiated with a default factory/constructor,
|
||||
// otherwise we won't be able to instantiate the elements.
|
||||
int typeId = ot->GetSubTypeId();
|
||||
if( typeId == asTYPEID_VOID )
|
||||
return false;
|
||||
@ -147,6 +215,7 @@ static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageColl
|
||||
if( !found )
|
||||
{
|
||||
// There is no default constructor
|
||||
ot->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default constructor");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -174,6 +243,7 @@ static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageColl
|
||||
if( !found )
|
||||
{
|
||||
// No default factory
|
||||
ot->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default factory");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -188,6 +258,39 @@ static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageColl
|
||||
// thus there is no need to garbage collect them
|
||||
dontGarbageCollect = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( typeId & asTYPEID_OBJHANDLE );
|
||||
|
||||
// It is not necessary to set the array as garbage collected for all handle types.
|
||||
// If it is possible to determine that the handle cannot refer to an object type
|
||||
// that can potentially form a circular reference with the array then it is not
|
||||
// necessary to make the array garbage collected.
|
||||
asIObjectType *subtype = ot->GetEngine()->GetObjectTypeById(typeId);
|
||||
asDWORD flags = subtype->GetFlags();
|
||||
if( !(flags & asOBJ_GC) )
|
||||
{
|
||||
if( (flags & asOBJ_SCRIPT_OBJECT) )
|
||||
{
|
||||
// Even if a script class is by itself not garbage collected, it is possible
|
||||
// that classes that derive from it may be, so it is not possible to know
|
||||
// that no circular reference can occur.
|
||||
if( (flags & asOBJ_NOINHERIT) )
|
||||
{
|
||||
// A script class declared as final cannot be inherited from, thus
|
||||
// we can be certain that the object cannot be garbage collected.
|
||||
dontGarbageCollect = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For application registered classes we assume the application knows
|
||||
// what it is doing and don't mark the array as garbage collected unless
|
||||
// the type is also garbage collected.
|
||||
dontGarbageCollect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The type is ok
|
||||
return true;
|
||||
@ -204,12 +307,14 @@ void RegisterScriptArray(asIScriptEngine *engine, bool defaultArray)
|
||||
if( defaultArray )
|
||||
{
|
||||
int r = engine->RegisterDefaultArrayType("array<T>"); assert( r >= 0 );
|
||||
UNUSED_VAR(r);
|
||||
}
|
||||
}
|
||||
|
||||
static void RegisterScriptArray_Native(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
int r = 0;
|
||||
UNUSED_VAR(r);
|
||||
|
||||
// Register the object type user data clean up
|
||||
engine->SetObjectTypeUserDataCleanupCallback(CleanupObjectTypeArrayCache, ARRAY_CACHE);
|
||||
@ -221,12 +326,12 @@ static void RegisterScriptArray_Native(asIScriptEngine *engine)
|
||||
r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Templates receive the object type as the first parameter. To the script writer this is hidden
|
||||
r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_FACTORY, "array<T>@ f(int&in)", asFUNCTIONPR(ScriptArrayFactory, (asIObjectType*), CScriptArray*), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_FACTORY, "array<T>@ f(int&in, uint)", asFUNCTIONPR(ScriptArrayFactory2, (asIObjectType*, asUINT), CScriptArray*), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_FACTORY, "array<T>@ f(int&in, uint, const T &in)", asFUNCTIONPR(ScriptArrayFactoryDefVal, (asIObjectType*, asUINT, void *), CScriptArray*), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_FACTORY, "array<T>@ f(int&in)", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*), CScriptArray*), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_FACTORY, "array<T>@ f(int&in, uint)", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*, asUINT), CScriptArray*), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_FACTORY, "array<T>@ f(int&in, uint, const T &in)", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*, asUINT, void *), CScriptArray*), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Register the factory that will be used for initialization lists
|
||||
r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_LIST_FACTORY, "array<T>@ f(int&in type, int&in list) {repeat T}", asFUNCTIONPR(ScriptArrayListFactory, (asIObjectType*, void*), CScriptArray*), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_LIST_FACTORY, "array<T>@ f(int&in type, int&in list) {repeat T}", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*, void*), CScriptArray*), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// The memory management methods
|
||||
r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptArray,AddRef), asCALL_THISCALL); assert( r >= 0 );
|
||||
@ -337,14 +442,16 @@ CScriptArray::CScriptArray(asIObjectType *ot, void *buf)
|
||||
CreateBuffer(&buffer, length);
|
||||
|
||||
// Copy the values of the primitive type into the internal buffer
|
||||
memcpy(At(0), (((asUINT*)buf)+1), length * elementSize);
|
||||
if( length > 0 )
|
||||
memcpy(At(0), (((asUINT*)buf)+1), length * elementSize);
|
||||
}
|
||||
else if( ot->GetSubTypeId() & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
CreateBuffer(&buffer, length);
|
||||
|
||||
// Copy the handles into the internal buffer
|
||||
memcpy(At(0), (((asUINT*)buf)+1), length * elementSize);
|
||||
if( length > 0 )
|
||||
memcpy(At(0), (((asUINT*)buf)+1), length * elementSize);
|
||||
|
||||
// With object handles it is safe to clear the memory in the received buffer
|
||||
// instead of increasing the ref count. It will save time both by avoiding the
|
||||
@ -360,7 +467,8 @@ CScriptArray::CScriptArray(asIObjectType *ot, void *buf)
|
||||
subTypeId &= ~asTYPEID_OBJHANDLE;
|
||||
|
||||
// Copy the handles into the internal buffer
|
||||
memcpy(buffer->data, (((asUINT*)buf)+1), length * elementSize);
|
||||
if( length > 0 )
|
||||
memcpy(buffer->data, (((asUINT*)buf)+1), length * elementSize);
|
||||
|
||||
// For ref types we can do the same as for handles, as they are
|
||||
// implicitly stored as handles.
|
||||
@ -539,12 +647,7 @@ void CScriptArray::Reserve(asUINT maxElements)
|
||||
return;
|
||||
|
||||
// Allocate memory for the buffer
|
||||
SArrayBuffer *newBuffer;
|
||||
#if defined(__S3E__) // Marmalade doesn't understand (nothrow)
|
||||
newBuffer = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1 + elementSize*maxElements];
|
||||
#else
|
||||
newBuffer = (SArrayBuffer*)new (nothrow) asBYTE[sizeof(SArrayBuffer)-1 + elementSize*maxElements];
|
||||
#endif
|
||||
SArrayBuffer *newBuffer = reinterpret_cast<SArrayBuffer*>(userAlloc(sizeof(SArrayBuffer)-1 + elementSize*maxElements));
|
||||
if( newBuffer )
|
||||
{
|
||||
newBuffer->numElements = buffer->numElements;
|
||||
@ -559,10 +662,13 @@ void CScriptArray::Reserve(asUINT maxElements)
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: memcpy assumes the objects in the array doesn't hold pointers to themselves
|
||||
// This should really be using the objects copy/move constructor to copy each object
|
||||
// to the new location. It would most likely be a hit on the performance though.
|
||||
memcpy(newBuffer->data, buffer->data, buffer->numElements*elementSize);
|
||||
|
||||
// Release the old buffer
|
||||
delete[] (asBYTE*)buffer;
|
||||
userFree(buffer);
|
||||
|
||||
buffer = newBuffer;
|
||||
}
|
||||
@ -600,12 +706,7 @@ void CScriptArray::Resize(int delta, asUINT at)
|
||||
if( buffer->maxElements < buffer->numElements + delta )
|
||||
{
|
||||
// Allocate memory for the buffer
|
||||
SArrayBuffer *newBuffer;
|
||||
#if defined(__S3E__) // Marmalade doesn't understand (nothrow)
|
||||
newBuffer = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta)];
|
||||
#else
|
||||
newBuffer = (SArrayBuffer*)new (nothrow) asBYTE[sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta)];
|
||||
#endif
|
||||
SArrayBuffer *newBuffer = reinterpret_cast<SArrayBuffer*>(userAlloc(sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta)));
|
||||
if( newBuffer )
|
||||
{
|
||||
newBuffer->numElements = buffer->numElements + delta;
|
||||
@ -621,17 +722,17 @@ void CScriptArray::Resize(int delta, asUINT at)
|
||||
}
|
||||
|
||||
// TODO: memcpy assumes the objects in the array doesn't hold pointers to themselves
|
||||
// This should really be using the objects copy constructor to copy each object
|
||||
// This should really be using the objects copy/move constructor to copy each object
|
||||
// to the new location. It would most likely be a hit on the performance though.
|
||||
memcpy(newBuffer->data, buffer->data, at*elementSize);
|
||||
if( at < buffer->numElements )
|
||||
memcpy(newBuffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements-at)*elementSize);
|
||||
|
||||
if( subTypeId & asTYPEID_MASK_OBJECT )
|
||||
Construct(newBuffer, at, at+delta);
|
||||
// Initialize the new elements with default values
|
||||
Construct(newBuffer, at, at+delta);
|
||||
|
||||
// Release the old buffer
|
||||
delete[] (asBYTE*)buffer;
|
||||
userFree(buffer);
|
||||
|
||||
buffer = newBuffer;
|
||||
}
|
||||
@ -639,7 +740,7 @@ void CScriptArray::Resize(int delta, asUINT at)
|
||||
{
|
||||
Destruct(buffer, at, at-delta);
|
||||
// TODO: memmove assumes the objects in the array doesn't hold pointers to themselves
|
||||
// This should really be using the objects copy constructor to copy each object
|
||||
// This should really be using the objects copy/move constructor to copy each object
|
||||
// to the new location. It would most likely be a hit on the performance though.
|
||||
memmove(buffer->data + at*elementSize, buffer->data + (at-delta)*elementSize, (buffer->numElements - (at-delta))*elementSize);
|
||||
buffer->numElements += delta;
|
||||
@ -647,7 +748,7 @@ void CScriptArray::Resize(int delta, asUINT at)
|
||||
else
|
||||
{
|
||||
// TODO: memmove assumes the objects in the array doesn't hold pointers to themselves
|
||||
// This should really be using the objects copy constructor to copy each object
|
||||
// This should really be using the objects copy/move constructor to copy each object
|
||||
// to the new location. It would most likely be a hit on the performance though.
|
||||
memmove(buffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements - at)*elementSize);
|
||||
Construct(buffer, at, at+delta);
|
||||
@ -662,19 +763,14 @@ bool CScriptArray::CheckMaxSize(asUINT numElements)
|
||||
// for the array doesn't overflow and becomes smaller than requested
|
||||
|
||||
asUINT maxSize = 0xFFFFFFFFul - sizeof(SArrayBuffer) + 1;
|
||||
if( subTypeId & asTYPEID_MASK_OBJECT )
|
||||
maxSize /= sizeof(void*);
|
||||
else if( elementSize > 0 )
|
||||
if( elementSize > 0 )
|
||||
maxSize /= elementSize;
|
||||
|
||||
if( numElements > maxSize )
|
||||
{
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
{
|
||||
// Set a script exception
|
||||
ctx->SetException("Too large array size");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -754,7 +850,7 @@ const void *CScriptArray::At(asUINT index) const
|
||||
}
|
||||
|
||||
if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) )
|
||||
return (void*)((size_t*)buffer->data)[index];
|
||||
return *(void**)(buffer->data + elementSize*index);
|
||||
else
|
||||
return buffer->data + elementSize*index;
|
||||
}
|
||||
@ -767,22 +863,7 @@ void *CScriptArray::At(asUINT index)
|
||||
// internal
|
||||
void CScriptArray::CreateBuffer(SArrayBuffer **buf, asUINT numElements)
|
||||
{
|
||||
if( subTypeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
#if defined(__S3E__) // Marmalade doesn't understand (nothrow)
|
||||
*buf = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1+sizeof(void*)*numElements];
|
||||
#else
|
||||
*buf = (SArrayBuffer*)new (nothrow) asBYTE[sizeof(SArrayBuffer)-1+sizeof(void*)*numElements];
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(__S3E__)
|
||||
*buf = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1+elementSize*numElements];
|
||||
#else
|
||||
*buf = (SArrayBuffer*)new (nothrow) asBYTE[sizeof(SArrayBuffer)-1+elementSize*numElements];
|
||||
#endif
|
||||
}
|
||||
*buf = reinterpret_cast<SArrayBuffer*>(userAlloc(sizeof(SArrayBuffer)-1+elementSize*numElements));
|
||||
|
||||
if( *buf )
|
||||
{
|
||||
@ -805,20 +886,15 @@ void CScriptArray::DeleteBuffer(SArrayBuffer *buf)
|
||||
Destruct(buf, 0, buf->numElements);
|
||||
|
||||
// Free the buffer
|
||||
delete[] (asBYTE*)buf;
|
||||
userFree(buf);
|
||||
}
|
||||
|
||||
// internal
|
||||
void CScriptArray::Construct(SArrayBuffer *buf, asUINT start, asUINT end)
|
||||
{
|
||||
if( subTypeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// Set all object handles to null
|
||||
void *d = (void*)(buf->data + start * sizeof(void*));
|
||||
memset(d, 0, (end-start)*sizeof(void*));
|
||||
}
|
||||
else if( subTypeId & asTYPEID_MASK_OBJECT )
|
||||
if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) )
|
||||
{
|
||||
// Create an object using the default constructor/factory for each element
|
||||
void **max = (void**)(buf->data + end * sizeof(void*));
|
||||
void **d = (void**)(buf->data + start * sizeof(void*));
|
||||
|
||||
@ -826,7 +902,25 @@ void CScriptArray::Construct(SArrayBuffer *buf, asUINT start, asUINT end)
|
||||
asIObjectType *subType = objType->GetSubType();
|
||||
|
||||
for( ; d < max; d++ )
|
||||
{
|
||||
*d = (void*)engine->CreateScriptObject(subType);
|
||||
if( *d == 0 )
|
||||
{
|
||||
// Set the remaining entries to null so the destructor
|
||||
// won't attempt to destroy invalid objects later
|
||||
memset(d, 0, sizeof(void*)*(max-d));
|
||||
|
||||
// There is no need to set an exception on the context,
|
||||
// as CreateScriptObject has already done that
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set all elements to zero whether they are handles or primitives
|
||||
void *d = (void*)(buf->data + start * elementSize);
|
||||
memset(d, 0, (end-start)*elementSize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -978,7 +1072,7 @@ bool CScriptArray::operator==(const CScriptArray &other) const
|
||||
}
|
||||
|
||||
if( cmpContext )
|
||||
{
|
||||
{
|
||||
if( isNested )
|
||||
{
|
||||
asEContextState state = cmpContext->GetState();
|
||||
@ -988,7 +1082,7 @@ bool CScriptArray::operator==(const CScriptArray &other) const
|
||||
}
|
||||
else
|
||||
cmpContext->Release();
|
||||
}
|
||||
}
|
||||
|
||||
return isEqual;
|
||||
}
|
||||
@ -1366,7 +1460,7 @@ void CScriptArray::Sort(asUINT startAt, asUINT count, bool asc)
|
||||
}
|
||||
|
||||
if( cmpContext )
|
||||
{
|
||||
{
|
||||
if( isNested )
|
||||
{
|
||||
asEContextState state = cmpContext->GetState();
|
||||
@ -1376,7 +1470,7 @@ void CScriptArray::Sort(asUINT startAt, asUINT count, bool asc)
|
||||
}
|
||||
else
|
||||
cmpContext->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// internal
|
||||
@ -1447,7 +1541,7 @@ void CScriptArray::Precache()
|
||||
|
||||
// First check if a cache already exists for this array type
|
||||
SArrayCache *cache = reinterpret_cast<SArrayCache*>(objType->GetUserData(ARRAY_CACHE));
|
||||
if( cache ) return;
|
||||
if( cache ) return;
|
||||
|
||||
// We need to make sure the cache is created only once, even
|
||||
// if multiple threads reach the same point at the same time
|
||||
@ -1463,7 +1557,7 @@ void CScriptArray::Precache()
|
||||
}
|
||||
|
||||
// Create the cache
|
||||
cache = new SArrayCache();
|
||||
cache = reinterpret_cast<SArrayCache*>(userAlloc(sizeof(SArrayCache)));
|
||||
memset(cache, 0, sizeof(SArrayCache));
|
||||
|
||||
// If the sub type is a handle to const, then the methods must be const too
|
||||
@ -1496,7 +1590,8 @@ void CScriptArray::Precache()
|
||||
continue;
|
||||
|
||||
// The parameter must either be a reference to the subtype or a handle to the subtype
|
||||
int paramTypeId = func->GetParamTypeId(0, &flags);
|
||||
int paramTypeId;
|
||||
func->GetParam(0, ¶mTypeId, &flags);
|
||||
|
||||
if( (paramTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) != (subTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) )
|
||||
continue;
|
||||
@ -1552,6 +1647,9 @@ void CScriptArray::Precache()
|
||||
// GC behaviour
|
||||
void CScriptArray::EnumReferences(asIScriptEngine *engine)
|
||||
{
|
||||
// TODO: If garbage collection can be done from a separate thread, then this method must be
|
||||
// protected so that it doesn't get lost during the iteration if the array is modified
|
||||
|
||||
// If the array is holding handles, then we need to notify the GC of them
|
||||
if( subTypeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
@ -1565,7 +1663,7 @@ void CScriptArray::EnumReferences(asIScriptEngine *engine)
|
||||
}
|
||||
|
||||
// GC behaviour
|
||||
void CScriptArray::ReleaseAllHandles(asIScriptEngine *engine)
|
||||
void CScriptArray::ReleaseAllHandles(asIScriptEngine *)
|
||||
{
|
||||
// Resizing to zero will release everything
|
||||
Resize(0);
|
||||
@ -1586,7 +1684,8 @@ void CScriptArray::Release() const
|
||||
{
|
||||
// When reaching 0 no more references to this instance
|
||||
// exists and the object should be destroyed
|
||||
delete this;
|
||||
this->~CScriptArray();
|
||||
userFree(const_cast<CScriptArray*>(this));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1615,7 +1714,7 @@ static void ScriptArrayFactory_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0);
|
||||
|
||||
*(CScriptArray**)gen->GetAddressOfReturnLocation() = ScriptArrayFactory(ot);
|
||||
*reinterpret_cast<CScriptArray**>(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ot);
|
||||
}
|
||||
|
||||
static void ScriptArrayFactory2_Generic(asIScriptGeneric *gen)
|
||||
@ -1623,7 +1722,7 @@ static void ScriptArrayFactory2_Generic(asIScriptGeneric *gen)
|
||||
asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0);
|
||||
asUINT length = gen->GetArgDWord(1);
|
||||
|
||||
*(CScriptArray**)gen->GetAddressOfReturnLocation() = ScriptArrayFactory2(ot, length);
|
||||
*reinterpret_cast<CScriptArray**>(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ot, length);
|
||||
}
|
||||
|
||||
static void ScriptArrayListFactory_Generic(asIScriptGeneric *gen)
|
||||
@ -1631,7 +1730,7 @@ static void ScriptArrayListFactory_Generic(asIScriptGeneric *gen)
|
||||
asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0);
|
||||
void *buf = gen->GetArgAddress(1);
|
||||
|
||||
*(CScriptArray**)gen->GetAddressOfReturnLocation() = ScriptArrayListFactory(ot, buf);
|
||||
*reinterpret_cast<CScriptArray**>(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ot, buf);
|
||||
}
|
||||
|
||||
static void ScriptArrayFactoryDefVal_Generic(asIScriptGeneric *gen)
|
||||
@ -1640,14 +1739,14 @@ static void ScriptArrayFactoryDefVal_Generic(asIScriptGeneric *gen)
|
||||
asUINT length = gen->GetArgDWord(1);
|
||||
void *defVal = gen->GetArgAddress(2);
|
||||
|
||||
*(CScriptArray**)gen->GetAddressOfReturnLocation() = ScriptArrayFactoryDefVal(ot, length, defVal);
|
||||
*reinterpret_cast<CScriptArray**>(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ot, length, defVal);
|
||||
}
|
||||
|
||||
static void ScriptArrayTemplateCallback_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0);
|
||||
bool *dontGarbageCollect = *(bool**)gen->GetAddressOfArg(1);
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = ScriptArrayTemplateCallback(ot, *dontGarbageCollect);
|
||||
*reinterpret_cast<bool*>(gen->GetAddressOfReturnLocation()) = ScriptArrayTemplateCallback(ot, *dontGarbageCollect);
|
||||
}
|
||||
|
||||
static void ScriptArrayAssignment_Generic(asIScriptGeneric *gen)
|
||||
@ -1768,7 +1867,7 @@ static void ScriptArrayReverse_Generic(asIScriptGeneric *gen)
|
||||
static void ScriptArrayIsEmpty_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptArray *self = (CScriptArray*)gen->GetObject();
|
||||
self->IsEmpty();
|
||||
*reinterpret_cast<bool*>(gen->GetAddressOfReturnLocation()) = self->IsEmpty();
|
||||
}
|
||||
|
||||
static void ScriptArraySortAsc2_Generic(asIScriptGeneric *gen)
|
||||
@ -1808,7 +1907,7 @@ static void ScriptArrayRelease_Generic(asIScriptGeneric *gen)
|
||||
static void ScriptArrayGetRefCount_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptArray *self = (CScriptArray*)gen->GetObject();
|
||||
*(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
|
||||
*reinterpret_cast<int*>(gen->GetAddressOfReturnLocation()) = self->GetRefCount();
|
||||
}
|
||||
|
||||
static void ScriptArraySetFlag_Generic(asIScriptGeneric *gen)
|
||||
@ -1820,7 +1919,7 @@ static void ScriptArraySetFlag_Generic(asIScriptGeneric *gen)
|
||||
static void ScriptArrayGetFlag_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptArray *self = (CScriptArray*)gen->GetObject();
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag();
|
||||
*reinterpret_cast<bool*>(gen->GetAddressOfReturnLocation()) = self->GetFlag();
|
||||
}
|
||||
|
||||
static void ScriptArrayEnumReferences_Generic(asIScriptGeneric *gen)
|
||||
@ -1839,7 +1938,8 @@ static void ScriptArrayReleaseAllHandles_Generic(asIScriptGeneric *gen)
|
||||
|
||||
static void RegisterScriptArray_Generic(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
int r = 0;
|
||||
UNUSED_VAR(r);
|
||||
|
||||
engine->SetObjectTypeUserDataCleanupCallback(CleanupObjectTypeArrayCache, ARRAY_CACHE);
|
||||
|
||||
|
@ -1,26 +1,9 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef SCRIPTARRAY_H
|
||||
#define SCRIPTARRAY_H
|
||||
|
||||
#ifndef ANGELSCRIPT_H
|
||||
// Avoid having to inform include path if header is already include before
|
||||
#include "angelscript.h"
|
||||
#include <angelscript.h>
|
||||
#endif
|
||||
|
||||
// Sometimes it may be desired to use the same method names as used by C++ STL.
|
||||
@ -42,12 +25,16 @@ struct SArrayCache;
|
||||
class CScriptArray
|
||||
{
|
||||
public:
|
||||
CScriptArray(asIObjectType *ot, void *initBuf); // Called from script when initialized with list
|
||||
CScriptArray(asUINT length, asIObjectType *ot);
|
||||
CScriptArray(asUINT length, void *defVal, asIObjectType *ot);
|
||||
CScriptArray(const CScriptArray &other);
|
||||
virtual ~CScriptArray();
|
||||
// Set the memory functions that should be used by all CScriptArrays
|
||||
static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc);
|
||||
|
||||
// Factory functions
|
||||
static CScriptArray *Create(asIObjectType *ot);
|
||||
static CScriptArray *Create(asIObjectType *ot, asUINT length);
|
||||
static CScriptArray *Create(asIObjectType *ot, asUINT length, void *defaultValue);
|
||||
static CScriptArray *Create(asIObjectType *ot, void *listBuffer);
|
||||
|
||||
// Memory management
|
||||
void AddRef() const;
|
||||
void Release() const;
|
||||
|
||||
@ -56,21 +43,35 @@ public:
|
||||
int GetArrayTypeId() const;
|
||||
int GetElementTypeId() const;
|
||||
|
||||
void Reserve(asUINT maxElements);
|
||||
void Resize(asUINT numElements);
|
||||
// Get the current size
|
||||
asUINT GetSize() const;
|
||||
|
||||
// Returns true if the array is empty
|
||||
bool IsEmpty() const;
|
||||
|
||||
// Pre-allocates memory for elements
|
||||
void Reserve(asUINT maxElements);
|
||||
|
||||
// Resize the array
|
||||
void Resize(asUINT numElements);
|
||||
|
||||
// Get a pointer to an element. Returns 0 if out of bounds
|
||||
void *At(asUINT index);
|
||||
const void *At(asUINT index) const;
|
||||
|
||||
// Set value of an element
|
||||
// Set value of an element.
|
||||
// The value arg should be a pointer to the value that will be copied to the element.
|
||||
// Remember, if the array holds handles the value parameter should be the
|
||||
// address of the handle. The refCount of the object will also be incremented
|
||||
void SetValue(asUINT index, void *value);
|
||||
|
||||
// Copy the contents of one array to another (only if the types are the same)
|
||||
CScriptArray &operator=(const CScriptArray&);
|
||||
|
||||
// Compare two arrays
|
||||
bool operator==(const CScriptArray &) const;
|
||||
|
||||
// Array manipulation
|
||||
void InsertAt(asUINT index, void *value);
|
||||
void RemoveAt(asUINT index);
|
||||
void InsertLast(void *value);
|
||||
@ -101,6 +102,13 @@ protected:
|
||||
int elementSize;
|
||||
int subTypeId;
|
||||
|
||||
// Constructors
|
||||
CScriptArray(asIObjectType *ot, void *initBuf); // Called from script when initialized with list
|
||||
CScriptArray(asUINT length, asIObjectType *ot);
|
||||
CScriptArray(asUINT length, void *defVal, asIObjectType *ot);
|
||||
CScriptArray(const CScriptArray &other);
|
||||
virtual ~CScriptArray();
|
||||
|
||||
bool Less(const void *a, const void *b, bool asc, asIScriptContext *ctx, SArrayCache *cache);
|
||||
void *GetArrayItemPointer(int index);
|
||||
void *GetDataPointer(void *buffer);
|
||||
|
@ -1,19 +1,32 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2015 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you
|
||||
must not claim that you wrote the original software. If you use
|
||||
this software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
The original version of this library can be located at:
|
||||
http://www.angelcode.com/angelscript/
|
||||
|
||||
Andreas Jonsson
|
||||
andreas@angelcode.com
|
||||
*/
|
||||
|
||||
#include "scriptstdstring.hpp"
|
||||
#include <assert.h> // assert()
|
||||
@ -21,13 +34,19 @@
|
||||
#include <string.h> // strstr()
|
||||
#include <stdio.h> // sprintf()
|
||||
#include <stdlib.h> // strtod()
|
||||
#include <locale.h> // setlocale()
|
||||
#ifndef __psp2__
|
||||
#include <locale.h> // setlocale()
|
||||
#endif
|
||||
#include <map> // std::map
|
||||
|
||||
using namespace std;
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// This macro is used to avoid warnings about unused variables.
|
||||
// Usually where the variables are only used in debug mode.
|
||||
#define UNUSED_VAR(x) (void)(x)
|
||||
|
||||
#if AS_USE_STRINGPOOL == 1
|
||||
|
||||
// By keeping the literal strings in a pool the application
|
||||
@ -168,7 +187,7 @@ static bool StringIsEmpty(const string &str)
|
||||
return str.empty();
|
||||
}
|
||||
|
||||
static string &AssignUIntToString(unsigned int i, string &dest)
|
||||
static string &AssignUInt64ToString(asQWORD i, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
@ -176,7 +195,7 @@ static string &AssignUIntToString(unsigned int i, string &dest)
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string &AddAssignUIntToString(unsigned int i, string &dest)
|
||||
static string &AddAssignUInt64ToString(asQWORD i, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
@ -184,21 +203,21 @@ static string &AddAssignUIntToString(unsigned int i, string &dest)
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string AddStringUInt(const string &str, unsigned int i)
|
||||
static string AddStringUInt64(const string &str, asQWORD i)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
return str + stream.str();
|
||||
}
|
||||
|
||||
static string AddIntString(int i, const string &str)
|
||||
static string AddInt64String(asINT64 i, const string &str)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
return stream.str() + str;
|
||||
}
|
||||
|
||||
static string &AssignIntToString(int i, string &dest)
|
||||
static string &AssignInt64ToString(asINT64 i, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
@ -206,7 +225,7 @@ static string &AssignIntToString(int i, string &dest)
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string &AddAssignIntToString(int i, string &dest)
|
||||
static string &AddAssignInt64ToString(asINT64 i, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
@ -214,14 +233,14 @@ static string &AddAssignIntToString(int i, string &dest)
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string AddStringInt(const string &str, int i)
|
||||
static string AddStringInt64(const string &str, asINT64 i)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
return str + stream.str();
|
||||
}
|
||||
|
||||
static string AddUIntString(unsigned int i, const string &str)
|
||||
static string AddUInt64String(asQWORD i, const string &str)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
@ -244,6 +263,22 @@ static string &AddAssignDoubleToString(double f, string &dest)
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string &AssignFloatToString(float f, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << f;
|
||||
dest = stream.str();
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string &AddAssignFloatToString(float f, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << f;
|
||||
dest += stream.str();
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string &AssignBoolToString(bool b, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
@ -274,6 +309,20 @@ static string AddDoubleString(double f, const string &str)
|
||||
return stream.str() + str;
|
||||
}
|
||||
|
||||
static string AddStringFloat(const string &str, float f)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << f;
|
||||
return str + stream.str();
|
||||
}
|
||||
|
||||
static string AddFloatString(float f, const string &str)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << f;
|
||||
return stream.str() + str;
|
||||
}
|
||||
|
||||
static string AddStringBool(const string &str, bool b)
|
||||
{
|
||||
ostringstream stream;
|
||||
@ -371,14 +420,14 @@ static string formatInt(asINT64 value, const string &options, asUINT width)
|
||||
if( spaceOnSign ) fmt += " ";
|
||||
if( padWithZero ) fmt += "0";
|
||||
|
||||
#ifdef __GNUC__
|
||||
#ifdef _WIN32
|
||||
fmt += "*I64";
|
||||
#else
|
||||
#ifdef _LP64
|
||||
fmt += "*l";
|
||||
#else
|
||||
fmt += "*ll";
|
||||
#endif
|
||||
#else
|
||||
fmt += "*I64";
|
||||
#endif
|
||||
|
||||
if( hexSmall ) fmt += "x";
|
||||
@ -386,7 +435,7 @@ static string formatInt(asINT64 value, const string &options, asUINT width)
|
||||
else fmt += "d";
|
||||
|
||||
string buf;
|
||||
buf.resize(width+20);
|
||||
buf.resize(width+30);
|
||||
#if _MSC_VER >= 1400 && !defined(__S3E__)
|
||||
// MSVC 8.0 / 2005 or newer
|
||||
sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, value);
|
||||
@ -500,7 +549,7 @@ double parseFloat(const string &val, asUINT *byteCount)
|
||||
// WinCE doesn't have setlocale. Some quick testing on my current platform
|
||||
// still manages to parse the numbers such as "3.14" even if the decimal for the
|
||||
// locale is ",".
|
||||
#if !defined(_WIN32_WCE) && !defined(ANDROID)
|
||||
#if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__)
|
||||
// Set the locale to C so that we are guaranteed to parse the float value correctly
|
||||
char *orig = setlocale(LC_NUMERIC, 0);
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
@ -508,7 +557,7 @@ double parseFloat(const string &val, asUINT *byteCount)
|
||||
|
||||
double res = strtod(val.c_str(), &end);
|
||||
|
||||
#if !defined(_WIN32_WCE) && !defined(ANDROID)
|
||||
#if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__)
|
||||
// Restore the locale
|
||||
setlocale(LC_NUMERIC, orig);
|
||||
#endif
|
||||
@ -547,11 +596,16 @@ static bool StringEquals(const std::string& lhs, const std::string& rhs)
|
||||
|
||||
void RegisterStdString_Native(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
int r = 0;
|
||||
UNUSED_VAR(r);
|
||||
|
||||
// Register the string type
|
||||
#if AS_CAN_USE_CPP11
|
||||
// With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags to use
|
||||
r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asGetTypeTraits<string>()); assert( r >= 0 );
|
||||
#else
|
||||
r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
|
||||
#endif
|
||||
|
||||
#if AS_USE_STRINGPOOL == 1
|
||||
// Register the string factory
|
||||
@ -598,15 +652,20 @@ void RegisterStdString_Native(asIScriptEngine *engine)
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddStringDouble), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDoubleString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(int)", asFUNCTION(AssignIntToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(int)", asFUNCTION(AddAssignIntToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(int) const", asFUNCTION(AddStringInt), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(int) const", asFUNCTION(AddIntString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(float)", asFUNCTION(AssignFloatToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)", asFUNCTION(AddAssignFloatToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(float) const", asFUNCTION(AddStringFloat), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const", asFUNCTION(AddFloatString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(uint)", asFUNCTION(AssignUIntToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint)", asFUNCTION(AddAssignUIntToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(uint) const", asFUNCTION(AddStringUInt), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(uint) const", asFUNCTION(AddUIntString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(int64)", asFUNCTION(AssignInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)", asFUNCTION(AddAssignInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddStringInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)", asFUNCTION(AssignUInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)", asFUNCTION(AddAssignUInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddStringUInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
@ -812,7 +871,7 @@ static void StringCharAtGeneric(asIScriptGeneric * gen)
|
||||
|
||||
static void AssignInt2StringGeneric(asIScriptGeneric *gen)
|
||||
{
|
||||
int *a = static_cast<int*>(gen->GetAddressOfArg(0));
|
||||
asINT64 *a = static_cast<asINT64*>(gen->GetAddressOfArg(0));
|
||||
string *self = static_cast<string*>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a;
|
||||
@ -822,7 +881,7 @@ static void AssignInt2StringGeneric(asIScriptGeneric *gen)
|
||||
|
||||
static void AssignUInt2StringGeneric(asIScriptGeneric *gen)
|
||||
{
|
||||
unsigned int *a = static_cast<unsigned int*>(gen->GetAddressOfArg(0));
|
||||
asQWORD *a = static_cast<asQWORD*>(gen->GetAddressOfArg(0));
|
||||
string *self = static_cast<string*>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a;
|
||||
@ -840,6 +899,16 @@ static void AssignDouble2StringGeneric(asIScriptGeneric *gen)
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AssignFloat2StringGeneric(asIScriptGeneric *gen)
|
||||
{
|
||||
float *a = static_cast<float*>(gen->GetAddressOfArg(0));
|
||||
string *self = static_cast<string*>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a;
|
||||
*self = sstr.str();
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AssignBool2StringGeneric(asIScriptGeneric *gen)
|
||||
{
|
||||
bool *a = static_cast<bool*>(gen->GetAddressOfArg(0));
|
||||
@ -860,9 +929,19 @@ static void AddAssignDouble2StringGeneric(asIScriptGeneric * gen)
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AddAssignFloat2StringGeneric(asIScriptGeneric * gen)
|
||||
{
|
||||
float * a = static_cast<float *>(gen->GetAddressOfArg(0));
|
||||
string * self = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a;
|
||||
*self += sstr.str();
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AddAssignInt2StringGeneric(asIScriptGeneric * gen)
|
||||
{
|
||||
int * a = static_cast<int *>(gen->GetAddressOfArg(0));
|
||||
asINT64 * a = static_cast<asINT64 *>(gen->GetAddressOfArg(0));
|
||||
string * self = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a;
|
||||
@ -872,7 +951,7 @@ static void AddAssignInt2StringGeneric(asIScriptGeneric * gen)
|
||||
|
||||
static void AddAssignUInt2StringGeneric(asIScriptGeneric * gen)
|
||||
{
|
||||
unsigned int * a = static_cast<unsigned int *>(gen->GetAddressOfArg(0));
|
||||
asQWORD * a = static_cast<asQWORD *>(gen->GetAddressOfArg(0));
|
||||
string * self = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a;
|
||||
@ -900,10 +979,20 @@ static void AddString2DoubleGeneric(asIScriptGeneric * gen)
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
static void AddString2FloatGeneric(asIScriptGeneric * gen)
|
||||
{
|
||||
string * a = static_cast<string *>(gen->GetObject());
|
||||
float * b = static_cast<float *>(gen->GetAddressOfArg(0));
|
||||
std::stringstream sstr;
|
||||
sstr << *a << *b;
|
||||
std::string ret_val = sstr.str();
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
static void AddString2IntGeneric(asIScriptGeneric * gen)
|
||||
{
|
||||
string * a = static_cast<string *>(gen->GetObject());
|
||||
int * b = static_cast<int *>(gen->GetAddressOfArg(0));
|
||||
asINT64 * b = static_cast<asINT64 *>(gen->GetAddressOfArg(0));
|
||||
std::stringstream sstr;
|
||||
sstr << *a << *b;
|
||||
std::string ret_val = sstr.str();
|
||||
@ -913,7 +1002,7 @@ static void AddString2IntGeneric(asIScriptGeneric * gen)
|
||||
static void AddString2UIntGeneric(asIScriptGeneric * gen)
|
||||
{
|
||||
string * a = static_cast<string *>(gen->GetObject());
|
||||
unsigned int * b = static_cast<unsigned int *>(gen->GetAddressOfArg(0));
|
||||
asQWORD * b = static_cast<asQWORD *>(gen->GetAddressOfArg(0));
|
||||
std::stringstream sstr;
|
||||
sstr << *a << *b;
|
||||
std::string ret_val = sstr.str();
|
||||
@ -940,9 +1029,19 @@ static void AddDouble2StringGeneric(asIScriptGeneric * gen)
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
static void AddFloat2StringGeneric(asIScriptGeneric * gen)
|
||||
{
|
||||
float* a = static_cast<float *>(gen->GetAddressOfArg(0));
|
||||
string * b = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a << *b;
|
||||
std::string ret_val = sstr.str();
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
static void AddInt2StringGeneric(asIScriptGeneric * gen)
|
||||
{
|
||||
int* a = static_cast<int *>(gen->GetAddressOfArg(0));
|
||||
asINT64* a = static_cast<asINT64 *>(gen->GetAddressOfArg(0));
|
||||
string * b = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a << *b;
|
||||
@ -952,7 +1051,7 @@ static void AddInt2StringGeneric(asIScriptGeneric * gen)
|
||||
|
||||
static void AddUInt2StringGeneric(asIScriptGeneric * gen)
|
||||
{
|
||||
unsigned int* a = static_cast<unsigned int *>(gen->GetAddressOfArg(0));
|
||||
asQWORD* a = static_cast<asQWORD *>(gen->GetAddressOfArg(0));
|
||||
string * b = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a << *b;
|
||||
@ -983,7 +1082,8 @@ static void StringSubString_Generic(asIScriptGeneric *gen)
|
||||
|
||||
void RegisterStdString_Generic(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
int r = 0;
|
||||
UNUSED_VAR(r);
|
||||
|
||||
// Register the string type
|
||||
r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
|
||||
@ -1027,15 +1127,20 @@ void RegisterStdString_Generic(asIScriptEngine *engine)
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddString2DoubleGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(int)", asFUNCTION(AssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(int)", asFUNCTION(AddAssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(int) const", asFUNCTION(AddString2IntGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(int) const", asFUNCTION(AddInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(float)", asFUNCTION(AssignFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)", asFUNCTION(AddAssignFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(float) const", asFUNCTION(AddString2FloatGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const", asFUNCTION(AddFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(uint)", asFUNCTION(AssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint)", asFUNCTION(AddAssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(uint) const", asFUNCTION(AddString2UIntGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(uint) const", asFUNCTION(AddUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(int64)", asFUNCTION(AssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)", asFUNCTION(AddAssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddString2IntGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)", asFUNCTION(AssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)", asFUNCTION(AddAssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddString2UIntGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user