SuperTuxKart 1.5 upstream source (from official release tarball)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,260 @@
|
||||
cmake_minimum_required(VERSION 3.5...4.0)
|
||||
|
||||
# STK Fix llvm mingw crashes
|
||||
if (MINGW AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
set(USE_AS_MAX_PORTABILITY 1)
|
||||
ADD_DEFINITIONS(-DAS_MAX_PORTABILITY)
|
||||
endif()
|
||||
|
||||
project(angelscript)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared library" OFF)
|
||||
option(AS_NO_EXCEPTIONS "Disable exception handling in script context" OFF)
|
||||
|
||||
if(MSVC)
|
||||
option(MSVC_COMPILE_FLAGS "Compiler flags to use with MSVC" "/MP")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
option(BUILD_FRAMEWORK "Build Framework bundle for OSX" OFF)
|
||||
endif()
|
||||
|
||||
file(READ ../../include/angelscript.h ANGELSCRIPT_H)
|
||||
string(REGEX MATCH "#define ANGELSCRIPT_VERSION_STRING \"([0-9]*).([0-9]*).([0-9]*)" ANGELSCRIPT_VERSION_REGEX ${ANGELSCRIPT_H})
|
||||
set(ANGELSCRIPT_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
set(ANGELSCRIPT_VERSION_MINOR ${CMAKE_MATCH_2})
|
||||
set(ANGELSCRIPT_VERSION_PATCH ${CMAKE_MATCH_3})
|
||||
set(PROJECT_VERSION ${ANGELSCRIPT_VERSION_MAJOR}.${ANGELSCRIPT_VERSION_MINOR}.${ANGELSCRIPT_VERSION_PATCH})
|
||||
|
||||
set(ARCHFLAGS "${CMAKE_SYSTEM_PROCESSOR}")
|
||||
if (APPLE AND NOT IOS)
|
||||
if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm")
|
||||
set(ARCHFLAGS "aarch64")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
message(STATUS "Configuring angelscript ${PROJECT_VERSION}")
|
||||
|
||||
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_mips.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
|
||||
)
|
||||
|
||||
# STK
|
||||
set(BUILD_ARCH "unknown")
|
||||
if (CMAKE_GENERATOR_PLATFORM)
|
||||
set(BUILD_ARCH "${CMAKE_GENERATOR_PLATFORM}")
|
||||
endif()
|
||||
|
||||
if (MSVC AND (${CMAKE_GENERATOR} MATCHES "(ARM)" OR ${BUILD_ARCH} MATCHES "(ARM)"))
|
||||
set(USE_AS_MAX_PORTABILITY 1)
|
||||
ADD_DEFINITIONS(-DAS_MAX_PORTABILITY)
|
||||
endif()
|
||||
|
||||
if(MSVC AND CMAKE_CL_64 AND NOT ${CMAKE_GENERATOR_PLATFORM} MATCHES "(ARM64)")
|
||||
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(MSVC AND CMAKE_CL_64 AND NOT ${BUILD_ARCH} MATCHES "(ARM64)")
|
||||
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(${ARCHFLAGS} MATCHES "^arm")
|
||||
enable_language(ASM)
|
||||
if (NOT USE_AS_MAX_PORTABILITY)
|
||||
if(CMAKE_ASM_COMPILER_WORKS)
|
||||
set(ANGELSCRIPT_SOURCE ${ANGELSCRIPT_SOURCE} ../../source/as_callfunc_arm.cpp ../../source/as_callfunc_arm_gcc.S)
|
||||
if (NOT APPLE)
|
||||
set_property(SOURCE ../../source/as_callfunc_arm_gcc.S APPEND PROPERTY COMPILE_FLAGS " -Wa,-mimplicit-it=always")
|
||||
endif()
|
||||
else()
|
||||
message(FATAL ERROR "ARM target requires a working assembler")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(${ARCHFLAGS} MATCHES "^aarch64")
|
||||
enable_language(ASM)
|
||||
ADD_DEFINITIONS(-DAS_MAX_PORTABILITY)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_DEBUG_POSTFIX "d")
|
||||
endif()
|
||||
|
||||
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(ANGELSCRIPT_LIBRARY_NAME ${ANGELSCRIPT_LIBRARY_NAME} CACHE STRING "" FORCE)
|
||||
|
||||
add_library(${ANGELSCRIPT_LIBRARY_NAME} ${ANGELSCRIPT_SOURCE} ${ANGELSCRIPT_HEADERS})
|
||||
|
||||
target_include_directories(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_definitions(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE -D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE -DANGELSCRIPT_EXPORT -D_LIB)
|
||||
|
||||
if(AS_NO_EXCEPTIONS)
|
||||
target_compile_definitions(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE AS_NO_EXCEPTIONS)
|
||||
endif()
|
||||
|
||||
# Fix x64 issues on Linux
|
||||
if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" AND UNIX AND NOT APPLE AND NOT WIN32)
|
||||
target_compile_options(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE -fPIC)
|
||||
endif()
|
||||
|
||||
# Don't override the default library output path to avoid conflicts when building for multiple target platforms
|
||||
#set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../lib)
|
||||
target_link_libraries(${ANGELSCRIPT_LIBRARY_NAME} Threads::Threads)
|
||||
|
||||
set_target_properties(${ANGELSCRIPT_LIBRARY_NAME} PROPERTIES VERSION ${PROJECT_VERSION})
|
||||
|
||||
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()
|
||||
|
||||
if(MSVC AND MSVC_COMPILE_FLAGS)
|
||||
target_compile_options(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE "${MSVC_COMPILE_FLAGS}")
|
||||
endif()
|
||||
|
||||
# Don't override the default runtime output path to avoid conflicts when building for multiple target platforms
|
||||
#set(RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../../bin)
|
||||
|
||||
#See https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#creating-packages for a detailed explanation about this part
|
||||
install(TARGETS ${ANGELSCRIPT_LIBRARY_NAME} EXPORT AngelscriptTargets
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
INCLUDES DESTINATION include
|
||||
)
|
||||
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../include/angelscript.h
|
||||
DESTINATION include
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptConfigVersion.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
|
||||
export(EXPORT AngelscriptTargets
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptTargets.cmake"
|
||||
NAMESPACE Angelscript::
|
||||
)
|
||||
configure_file(cmake/AngelscriptConfig.cmake
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptConfig.cmake"
|
||||
COPYONLY
|
||||
)
|
||||
|
||||
set(ConfigPackageLocation lib/cmake/Angelscript)
|
||||
install(EXPORT AngelscriptTargets
|
||||
FILE AngelscriptTargets.cmake
|
||||
NAMESPACE Angelscript::
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
)
|
||||
install(
|
||||
FILES
|
||||
cmake/AngelscriptConfig.cmake
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptConfigVersion.cmake"
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/AngelscriptTargets.cmake")
|
||||
|
||||
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
#ifndef AS_ARRAY_H
|
||||
#define AS_ARRAY_H
|
||||
|
||||
#if !defined(AS_NO_MEMORY_H)
|
||||
#include <memory.h>
|
||||
#endif
|
||||
#include <string.h> // some compilers declare memcpy() here
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4345) // warning about a change in how the code is handled in this version
|
||||
#endif
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
template <class T> class asCArray
|
||||
{
|
||||
public:
|
||||
asCArray();
|
||||
asCArray(const asCArray<T> &);
|
||||
asCArray(asUINT reserve);
|
||||
~asCArray();
|
||||
|
||||
void Allocate(asUINT numElements, bool keepData);
|
||||
void AllocateNoConstruct(asUINT numElements, bool keepData);
|
||||
asUINT GetCapacity() const;
|
||||
|
||||
void PushLast(const T &element);
|
||||
T PopLast();
|
||||
|
||||
bool SetLength(asUINT numElements);
|
||||
bool SetLengthNoConstruct(asUINT numElements);
|
||||
asUINT GetLength() const;
|
||||
|
||||
void Copy(const T*, asUINT count);
|
||||
asCArray<T> &operator =(const asCArray<T> &);
|
||||
void SwapWith(asCArray<T> &other);
|
||||
|
||||
const T &operator [](asUINT index) const;
|
||||
T &operator [](asUINT index);
|
||||
T *AddressOf();
|
||||
const T *AddressOf() const;
|
||||
|
||||
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(asUINT index); // Removes the entry without reordering the array
|
||||
void RemoveValue(const T &element); // Removes the value without reordering the array
|
||||
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;
|
||||
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
|
||||
|
||||
template <class T>
|
||||
T *asCArray<T>::AddressOf()
|
||||
{
|
||||
return array;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T *asCArray<T>::AddressOf() const
|
||||
{
|
||||
return array;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
asCArray<T>::asCArray(void)
|
||||
{
|
||||
array = 0;
|
||||
length = 0;
|
||||
maxLength = 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
asCArray<T>::asCArray(const asCArray<T> ©)
|
||||
{
|
||||
array = 0;
|
||||
length = 0;
|
||||
maxLength = 0;
|
||||
|
||||
*this = copy;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
asCArray<T>::asCArray(asUINT reserve)
|
||||
{
|
||||
array = 0;
|
||||
length = 0;
|
||||
maxLength = 0;
|
||||
|
||||
Allocate(reserve, false);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
asCArray<T>::~asCArray(void)
|
||||
{
|
||||
// Allocating a zero length array will free all memory
|
||||
Allocate(0,0);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
asUINT asCArray<T>::GetLength() const
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T &asCArray<T>::operator [](asUINT index) const
|
||||
{
|
||||
asASSERT(index < length);
|
||||
|
||||
return array[index];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T &asCArray<T>::operator [](asUINT index)
|
||||
{
|
||||
asASSERT(index < length);
|
||||
|
||||
return array[index];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void asCArray<T>::PushLast(const T &element)
|
||||
{
|
||||
if( length == maxLength )
|
||||
{
|
||||
if( maxLength == 0 )
|
||||
Allocate(1, false);
|
||||
else
|
||||
Allocate(2*maxLength, true);
|
||||
|
||||
if( length == maxLength )
|
||||
{
|
||||
// Out of memory. Return without doing anything
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
array[length++] = element;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T asCArray<T>::PopLast()
|
||||
{
|
||||
asASSERT(length > 0);
|
||||
|
||||
return array[--length];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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
|
||||
// 2. The previous array is 8 bytes or smaller and the new array is larger than 8 bytes
|
||||
// 3. The previous array is larger than 8 bytes and the new array is 8 bytes or smaller
|
||||
// 4. The previous array is larger than 8 bytes and the new array is also larger than 8 bytes
|
||||
|
||||
T *tmp = 0;
|
||||
if( numElements )
|
||||
{
|
||||
if( sizeof(T)*numElements <= sizeof(buf) )
|
||||
// Use the internal buffer
|
||||
tmp = reinterpret_cast<T*>(buf);
|
||||
else
|
||||
{
|
||||
// Allocate the array and construct each of the elements
|
||||
tmp = asNEWARRAY(T,numElements);
|
||||
if( tmp == 0 )
|
||||
{
|
||||
// Out of memory. Return without doing anything
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if( array == tmp )
|
||||
{
|
||||
// Construct only the newly allocated elements
|
||||
for( asUINT n = length; n < numElements; n++ )
|
||||
new (&tmp[n]) T();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Construct all elements
|
||||
for( asUINT n = 0; n < numElements; n++ )
|
||||
new (&tmp[n]) T();
|
||||
}
|
||||
}
|
||||
|
||||
if( array )
|
||||
{
|
||||
asUINT oldLength = length;
|
||||
|
||||
if( array == tmp )
|
||||
{
|
||||
if( keepData )
|
||||
{
|
||||
if( length > numElements )
|
||||
length = numElements;
|
||||
}
|
||||
else
|
||||
length = 0;
|
||||
|
||||
// Call the destructor for elements that are no longer used
|
||||
for( asUINT n = length; n < oldLength; n++ )
|
||||
array[n].~T();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( keepData )
|
||||
{
|
||||
if( length > numElements )
|
||||
length = numElements;
|
||||
|
||||
for( asUINT n = 0; n < length; n++ )
|
||||
tmp[n] = array[n];
|
||||
}
|
||||
else
|
||||
length = 0;
|
||||
|
||||
// Call the destructor for all elements
|
||||
for( asUINT n = 0; n < oldLength; n++ )
|
||||
array[n].~T();
|
||||
|
||||
if( array != reinterpret_cast<T*>(buf) )
|
||||
asDELETEARRAY(array);
|
||||
}
|
||||
}
|
||||
|
||||
array = tmp;
|
||||
maxLength = numElements;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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
|
||||
// 2. The previous array is 8 bytes or smaller and the new array is larger than 8 bytes
|
||||
// 3. The previous array is larger than 8 bytes and the new array is 8 bytes or smaller
|
||||
// 4. The previous array is larger than 8 bytes and the new array is also larger than 8 bytes
|
||||
|
||||
T *tmp = 0;
|
||||
if( numElements )
|
||||
{
|
||||
if( sizeof(T)*numElements <= sizeof(buf) )
|
||||
// Use the internal buffer
|
||||
tmp = reinterpret_cast<T*>(buf);
|
||||
else
|
||||
{
|
||||
// Allocate the array and construct each of the elements
|
||||
tmp = asNEWARRAY(T,numElements);
|
||||
if( tmp == 0 )
|
||||
{
|
||||
// Out of memory. Return without doing anything
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( array )
|
||||
{
|
||||
if( array == tmp )
|
||||
{
|
||||
if( keepData )
|
||||
{
|
||||
if( length > numElements )
|
||||
length = numElements;
|
||||
}
|
||||
else
|
||||
length = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( keepData )
|
||||
{
|
||||
if( length > numElements )
|
||||
length = numElements;
|
||||
|
||||
memcpy(tmp, array, sizeof(T)*length);
|
||||
}
|
||||
else
|
||||
length = 0;
|
||||
|
||||
if( array != reinterpret_cast<T*>(buf) )
|
||||
asDELETEARRAY(array);
|
||||
}
|
||||
}
|
||||
|
||||
array = tmp;
|
||||
maxLength = numElements;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
asUINT asCArray<T>::GetCapacity() const
|
||||
{
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool asCArray<T>::SetLength(asUINT numElements)
|
||||
{
|
||||
if( numElements > maxLength )
|
||||
{
|
||||
Allocate(numElements, true);
|
||||
if( numElements > maxLength )
|
||||
{
|
||||
// Out of memory. Return without doing anything
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
length = numElements;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool asCArray<T>::SetLengthNoConstruct(asUINT numElements)
|
||||
{
|
||||
if( numElements > maxLength )
|
||||
{
|
||||
AllocateNoConstruct(numElements, true);
|
||||
if( numElements > maxLength )
|
||||
{
|
||||
// Out of memory. Return without doing anything
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
length = numElements;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void asCArray<T>::Copy(const T *data, asUINT count)
|
||||
{
|
||||
if( maxLength < count )
|
||||
{
|
||||
Allocate(count, false);
|
||||
if( maxLength < count )
|
||||
{
|
||||
// Out of memory. Return without doing anything
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for( asUINT n = 0; n < count; n++ )
|
||||
array[n] = data[n];
|
||||
|
||||
length = count;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
asCArray<T> &asCArray<T>::operator =(const asCArray<T> ©)
|
||||
{
|
||||
Copy(copy.array, copy.length);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void asCArray<T>::SwapWith(asCArray<T> &other)
|
||||
{
|
||||
T *tmpArray = array;
|
||||
asUINT tmpLength = length;
|
||||
asUINT tmpMaxLength = maxLength;
|
||||
char tmpBuf[sizeof(buf)];
|
||||
memcpy(tmpBuf, buf, sizeof(buf));
|
||||
|
||||
array = other.array;
|
||||
length = other.length;
|
||||
maxLength = other.maxLength;
|
||||
memcpy(buf, other.buf, sizeof(buf));
|
||||
|
||||
other.array = tmpArray;
|
||||
other.length = tmpLength;
|
||||
other.maxLength = tmpMaxLength;
|
||||
memcpy(other.buf, tmpBuf, sizeof(buf));
|
||||
|
||||
// If the data is in the internal buffer, then the array pointer must refer to it
|
||||
if( array == reinterpret_cast<T*>(other.buf) )
|
||||
array = reinterpret_cast<T*>(buf);
|
||||
if( other.array == reinterpret_cast<T*>(buf) )
|
||||
other.array = reinterpret_cast<T*>(other.buf);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool asCArray<T>::operator ==(const asCArray<T> &other) const
|
||||
{
|
||||
if( length != other.length ) return false;
|
||||
|
||||
for( asUINT n = 0; n < length; n++ )
|
||||
if( array[n] != other.array[n] )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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>
|
||||
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( asUINT n = 0; n < other.length; n++ )
|
||||
array[length+n] = other.array[n];
|
||||
|
||||
length += other.length;
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void asCArray<T>::Concatenate(T* other, unsigned int count)
|
||||
{
|
||||
for( unsigned int c = 0; c < count; c++ )
|
||||
PushLast(other[c]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool asCArray<T>::Exists(const T &e) const
|
||||
{
|
||||
return IndexOf(e) == -1 ? false : true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int asCArray<T>::IndexOf(const T &e) const
|
||||
{
|
||||
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(asUINT index)
|
||||
{
|
||||
if( index < length )
|
||||
{
|
||||
for( asUINT n = index; n < length-1; n++ )
|
||||
array[n] = array[n+1];
|
||||
|
||||
PopLast();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void asCArray<T>::RemoveValue(const T &e)
|
||||
{
|
||||
for( asUINT n = 0; n < length; n++ )
|
||||
{
|
||||
if( array[n] == e )
|
||||
{
|
||||
RemoveIndex(n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void asCArray<T>::RemoveIndexUnordered(asUINT index)
|
||||
{
|
||||
if( index == length - 1 )
|
||||
PopLast();
|
||||
else if( index < length )
|
||||
array[index] = PopLast();
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
//
|
||||
// as_atomic.cpp
|
||||
//
|
||||
// The implementation of the atomic class for thread safe reference counting
|
||||
//
|
||||
|
||||
#include "as_atomic.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asCAtomic::asCAtomic()
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
// The following code implements the atomicInc and atomicDec on different platforms
|
||||
//
|
||||
#if defined(AS_NO_THREADS) || defined(AS_NO_ATOMIC)
|
||||
|
||||
int asAtomicInc(int &value)
|
||||
{
|
||||
return ++value;
|
||||
}
|
||||
|
||||
int asAtomicDec(int &value)
|
||||
{
|
||||
return --value;
|
||||
}
|
||||
|
||||
#elif defined(AS_XENON) /// XBox360
|
||||
|
||||
END_AS_NAMESPACE
|
||||
#include <xtl.h>
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
int asAtomicInc(int &value)
|
||||
{
|
||||
return InterlockedIncrement((LONG*)&value);
|
||||
}
|
||||
|
||||
int asAtomicDec(int &value)
|
||||
{
|
||||
return InterlockedDecrement((LONG*)&value);
|
||||
}
|
||||
|
||||
#elif defined(AS_WIN)
|
||||
|
||||
END_AS_NAMESPACE
|
||||
#define WIN32_MEAN_AND_LEAN
|
||||
#include <windows.h>
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
int asAtomicInc(int &value)
|
||||
{
|
||||
return InterlockedIncrement((LONG*)&value);
|
||||
}
|
||||
|
||||
int asAtomicDec(int &value)
|
||||
{
|
||||
asASSERT(value > 0);
|
||||
return InterlockedDecrement((LONG*)&value);
|
||||
}
|
||||
|
||||
#elif defined(AS_LINUX) || defined(AS_BSD) || defined(AS_ILLUMOS) || defined(AS_ANDROID)
|
||||
|
||||
//
|
||||
// atomic_inc_and_test() and atomic_dec_and_test() from asm/atomic.h is not meant
|
||||
// to be used outside the Linux kernel. Instead we should use the GNUC provided
|
||||
// __sync_add_and_fetch() and __sync_sub_and_fetch() functions.
|
||||
//
|
||||
// Reference: http://golubenco.org/blog/atomic-operations/
|
||||
//
|
||||
// These are only available in GCC 4.1 and above, so for older versions we
|
||||
// use the critical sections, though it is a lot slower.
|
||||
//
|
||||
|
||||
int asAtomicInc(int &value)
|
||||
{
|
||||
return __sync_add_and_fetch(&value, 1);
|
||||
}
|
||||
|
||||
int asAtomicDec(int &value)
|
||||
{
|
||||
return __sync_sub_and_fetch(&value, 1);
|
||||
}
|
||||
|
||||
#elif defined(AS_MAC) || defined(AS_IPHONE)
|
||||
|
||||
END_AS_NAMESPACE
|
||||
#include <libkern/OSAtomic.h>
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
int asAtomicInc(int &value)
|
||||
{
|
||||
return OSAtomicIncrement32((int32_t*)&value);
|
||||
}
|
||||
|
||||
int asAtomicDec(int &value)
|
||||
{
|
||||
return OSAtomicDecrement32((int32_t*)&value);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// If we get here, then the configuration in as_config.h
|
||||
// is wrong for the compiler/platform combination.
|
||||
int ERROR_PleaseFixTheConfig[-1];
|
||||
|
||||
#endif
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_atomic.h
|
||||
//
|
||||
// The asCAtomic class provides methods for performing threadsafe
|
||||
// operations on a single dword, e.g. reference counting and
|
||||
// bitfields.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_ATOMIC_H
|
||||
#define AS_ATOMIC_H
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCAtomic
|
||||
{
|
||||
public:
|
||||
asCAtomic();
|
||||
|
||||
asDWORD get() const;
|
||||
void set(asDWORD val);
|
||||
|
||||
// Increase and return new value
|
||||
asDWORD atomicInc();
|
||||
|
||||
// Decrease and return new value
|
||||
asDWORD atomicDec();
|
||||
|
||||
protected:
|
||||
asDWORD value;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2021 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_builder.h
|
||||
//
|
||||
// This is the class that manages the compilation of the scripts
|
||||
//
|
||||
|
||||
|
||||
#ifndef AS_BUILDER_H
|
||||
#define AS_BUILDER_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_symboltable.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_module.h"
|
||||
#include "as_array.h"
|
||||
#include "as_scriptcode.h"
|
||||
#include "as_scriptnode.h"
|
||||
#include "as_datatype.h"
|
||||
#include "as_property.h"
|
||||
|
||||
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
|
||||
{
|
||||
asCScriptCode *script;
|
||||
asCScriptNode *node;
|
||||
asCString name;
|
||||
asCObjectType *objType;
|
||||
asCArray<asCString> paramNames;
|
||||
int funcId;
|
||||
bool isExistingShared;
|
||||
};
|
||||
|
||||
struct sGlobalVariableDescription
|
||||
{
|
||||
asCScriptCode *script;
|
||||
asCScriptNode *declaredAtNode;
|
||||
asCScriptNode *initializationNode;
|
||||
asCString name;
|
||||
asCGlobalProperty *property;
|
||||
asCDataType datatype;
|
||||
asSNameSpace *ns;
|
||||
int index;
|
||||
bool isCompiled;
|
||||
bool isPureConstant;
|
||||
bool isEnumValue;
|
||||
asQWORD constantValue;
|
||||
};
|
||||
|
||||
struct sPropertyInitializer
|
||||
{
|
||||
sPropertyInitializer() : declNode(0), initNode(0), file(0) {}
|
||||
sPropertyInitializer(const asCString &nm, asCScriptNode *decl, asCScriptNode *init, asCScriptCode *f) : name(nm), declNode(decl), initNode(init), file(f) {}
|
||||
sPropertyInitializer &operator=(const sPropertyInitializer &o) {name = o.name; declNode = o.declNode; initNode = o.initNode; file = o.file; return *this;}
|
||||
|
||||
asCString name;
|
||||
asCScriptNode *declNode;
|
||||
asCScriptNode *initNode;
|
||||
asCScriptCode *file;
|
||||
};
|
||||
|
||||
struct sClassDeclaration
|
||||
{
|
||||
sClassDeclaration() {script = 0; node = 0; validState = 0; typeInfo = 0; isExistingShared = false; isFinal = false;}
|
||||
|
||||
asCScriptCode *script;
|
||||
asCScriptNode *node;
|
||||
asCString name;
|
||||
int validState;
|
||||
asCTypeInfo *typeInfo;
|
||||
bool isExistingShared;
|
||||
bool isFinal;
|
||||
|
||||
asCArray<sPropertyInitializer> propInits;
|
||||
};
|
||||
|
||||
struct sFuncDef
|
||||
{
|
||||
asCScriptCode *script;
|
||||
asCScriptNode *node;
|
||||
asCString name;
|
||||
int idx;
|
||||
};
|
||||
|
||||
struct sMixinClass
|
||||
{
|
||||
asCScriptCode *script;
|
||||
asCScriptNode *node;
|
||||
asCString name;
|
||||
asSNameSpace *ns;
|
||||
};
|
||||
|
||||
#endif // AS_NO_COMPILER
|
||||
|
||||
class asCBuilder
|
||||
{
|
||||
public:
|
||||
asCBuilder(asCScriptEngine *engine, asCModule *module);
|
||||
~asCBuilder();
|
||||
|
||||
// These methods are used by the application interface
|
||||
int VerifyProperty(asCDataType *dt, const char *decl, asCString &outName, asCDataType &outType, asSNameSpace *ns);
|
||||
int ParseDataType(const char *datatype, asCDataType *result, asSNameSpace *implicitNamespace, bool isReturnType = false);
|
||||
int ParseTemplateDecl(const char *decl, asCString *name, asCArray<asCString> &subtypeNames);
|
||||
int ParseFunctionDeclaration(asCObjectType *type, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray<bool> *paramAutoHandles = 0, bool *returnAutoHandle = 0, asSNameSpace *ns = 0, asCScriptNode **outListPattern = 0, asCObjectType **outParentClass = 0);
|
||||
int ParseVariableDeclaration(const char *decl, asSNameSpace *implicitNamespace, asCString &outName, asSNameSpace *&outNamespace, asCDataType &outDt);
|
||||
int CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code, asSNameSpace *ns, bool isProperty, bool isVirtualProperty);
|
||||
int CheckNameConflictMember(asCTypeInfo *type, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty, bool isVirtualProperty);
|
||||
int ValidateVirtualProperty(asCScriptFunction *func);
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
int AddCode(const char *name, const char *code, int codeLength, int lineOffset, int sectionIdx, bool makeCopy);
|
||||
asCScriptCode *FindOrAddCode(const char *name, const char *code, size_t length);
|
||||
int Build();
|
||||
|
||||
int CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asCScriptFunction **outFunc);
|
||||
int CompileGlobalVar(const char *sectionName, const char *code, int lineOffset);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
friend class asCModule;
|
||||
friend class asCParser;
|
||||
friend class asCScriptFunction;
|
||||
friend class asCScriptEngine;
|
||||
|
||||
void Reset();
|
||||
|
||||
void WriteInfo(const asCString &scriptname, const asCString &msg, int r, int c, bool preMessage);
|
||||
void WriteInfo(const asCString &msg, asCScriptCode *file, asCScriptNode *node);
|
||||
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, asCObjectType **objType = 0);
|
||||
asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, asCTypeInfo **scopeType = 0, bool isRequired = true);
|
||||
asCString GetScopeFromNode(asCScriptNode *n, asCScriptCode *script, asCScriptNode **next = 0);
|
||||
|
||||
asCTypeInfo *GetType(const char *type, asSNameSpace *ns, asCObjectType *parentType);
|
||||
asCObjectType *GetObjectType(const char *type, asSNameSpace *ns);
|
||||
asCFuncdefType *GetFuncDef(const char *type, asSNameSpace *ns, asCObjectType *parentType);
|
||||
asCTypeInfo *GetTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType);
|
||||
asCDataType CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope = false, asCObjectType *currentType = 0, bool reportError = true, bool *isValid = 0);
|
||||
asCObjectType *GetTemplateInstanceFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *templateType, asSNameSpace *implicitNamespace, asCObjectType *currentType, asCScriptNode **next = 0);
|
||||
asCDataType ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlag, bool *autoHandle);
|
||||
|
||||
int numErrors;
|
||||
int numWarnings;
|
||||
bool silent;
|
||||
|
||||
asCScriptEngine *engine;
|
||||
asCModule *module;
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
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);
|
||||
void IncludePropertiesFromMixins(sClassDeclaration *decl);
|
||||
void IncludeMethodsFromMixins(sClassDeclaration *decl);
|
||||
void AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *errNode, asCObjectType *intf);
|
||||
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, asSFunctionTraits funcTraits);
|
||||
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);
|
||||
int RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
int RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
int RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
int RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
int RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns, asCObjectType *parent);
|
||||
asCScriptFunction *RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns, bool isShared);
|
||||
void CompleteFuncDef(sFuncDef *funcDef);
|
||||
void CompileInterfaces();
|
||||
void CompileClasses(asUINT originalNumTempl);
|
||||
void DetermineTypeRelations();
|
||||
void GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray<asCString> ¶meterNames, asCArray<asCDataType> ¶meterTypes, asCArray<asETypeModifiers> &inOutFlags, asCArray<asCString *> &defaultArgs, asSFunctionTraits &traits, 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, 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);
|
||||
void RegisterNonTypesFromScript(asCScriptNode *node, asCScriptCode *script, asSNameSpace *ns);
|
||||
void CompileFunctions();
|
||||
void CompileGlobalVariables();
|
||||
int GetEnumValueFromType(asCEnumType *type, const char *name, asCDataType &outDt, asDWORD &outValue);
|
||||
int GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outValue, asSNameSpace *ns);
|
||||
bool DoesTypeExist(const asCString &type);
|
||||
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 = "", asCScriptNode *errNode = 0, asCScriptCode *script = 0);
|
||||
void EvaluateTemplateInstances(asUINT startIdx, bool keepSilent);
|
||||
void CleanupEnumValues();
|
||||
|
||||
asCArray<asCScriptCode *> scripts;
|
||||
asCArray<sFunctionDescription *> functions;
|
||||
asCSymbolTable<sGlobalVariableDescription> globVariables;
|
||||
asCArray<sClassDeclaration *> classDeclarations;
|
||||
asCArray<sClassDeclaration *> interfaceDeclarations;
|
||||
asCArray<sClassDeclaration *> namedTypeDeclarations;
|
||||
asCArray<sFuncDef *> funcDefs;
|
||||
asCArray<sMixinClass *> mixinClasses;
|
||||
|
||||
// For use with the DoesTypeExists() method
|
||||
bool hasCachedKnownTypes;
|
||||
asCMap<asCString, bool> knownTypes;
|
||||
#endif
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2018 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_bytecode.h
|
||||
//
|
||||
// A class for constructing the final byte code
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_BYTECODE_H
|
||||
#define AS_BYTECODE_H
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
|
||||
#include "as_array.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
#define BYTECODE_SIZE 4
|
||||
#define MAX_DATA_SIZE 8
|
||||
#define MAX_INSTR_SIZE (BYTECODE_SIZE+MAX_DATA_SIZE)
|
||||
|
||||
class asCScriptEngine;
|
||||
class asCScriptFunction;
|
||||
class asCByteInstruction;
|
||||
|
||||
class asCByteCode
|
||||
{
|
||||
public:
|
||||
asCByteCode(asCScriptEngine *engine);
|
||||
~asCByteCode();
|
||||
|
||||
void ClearAll();
|
||||
|
||||
int GetSize();
|
||||
|
||||
void Finalize(const asCArray<int> &tempVariableOffsets);
|
||||
|
||||
void Optimize();
|
||||
void OptimizeLocally(const asCArray<int> &tempVariableOffsets);
|
||||
void ExtractLineNumbers();
|
||||
void ExtractObjectVariableInfo(asCScriptFunction *outFunc);
|
||||
void ExtractTryCatchInfo(asCScriptFunction *outFunc);
|
||||
int ResolveJumpAddresses();
|
||||
int FindLabel(int label, asCByteInstruction *from, asCByteInstruction **dest, int *positionDelta);
|
||||
|
||||
void AddPath(asCArray<asCByteInstruction *> &paths, asCByteInstruction *instr, int stackSize);
|
||||
|
||||
void Output(asDWORD *array);
|
||||
void AddCode(asCByteCode *bc);
|
||||
|
||||
void PostProcess();
|
||||
|
||||
#ifdef AS_DEBUG
|
||||
void DebugOutput(const char *name, asCScriptFunction *func);
|
||||
#endif
|
||||
|
||||
int GetLastInstr();
|
||||
int RemoveLastInstr();
|
||||
asDWORD GetLastInstrValueDW();
|
||||
|
||||
void InsertIfNotExists(asCArray<int> &vars, int var);
|
||||
void GetVarsUsed(asCArray<int> &vars);
|
||||
bool IsVarUsed(int offset);
|
||||
void ExchangeVar(int oldOffset, int newOffset);
|
||||
bool IsSimpleExpression();
|
||||
|
||||
void Label(short label);
|
||||
void Line(int line, int column, int scriptIdx);
|
||||
void ObjInfo(int offset, int info);
|
||||
void Block(bool start);
|
||||
void TryBlock(short catchLabel);
|
||||
|
||||
void VarDecl(int varDeclIdx);
|
||||
void Call(asEBCInstr bc, int funcID, int pop);
|
||||
void CallPtr(asEBCInstr bc, int funcPtrVar, int pop);
|
||||
void Alloc(asEBCInstr bc, void *objID, int funcID, int pop);
|
||||
void Ret(int pop);
|
||||
void JmpP(int var, asDWORD max);
|
||||
|
||||
int InsertFirstInstrDWORD(asEBCInstr bc, asDWORD param);
|
||||
int InsertFirstInstrQWORD(asEBCInstr bc, asQWORD param);
|
||||
int Instr(asEBCInstr bc);
|
||||
int InstrQWORD(asEBCInstr bc, asQWORD param);
|
||||
int InstrDOUBLE(asEBCInstr bc, double param);
|
||||
int InstrPTR(asEBCInstr bc, void *param);
|
||||
int InstrDWORD(asEBCInstr bc, asDWORD param);
|
||||
int InstrWORD(asEBCInstr bc, asWORD param);
|
||||
int InstrSHORT(asEBCInstr bc, short param);
|
||||
int InstrFLOAT(asEBCInstr bc, float param);
|
||||
int InstrINT(asEBCInstr bc, int param);
|
||||
int InstrW_W_W(asEBCInstr bc, int a, int b, int c);
|
||||
int InstrSHORT_B(asEBCInstr bc, short a, asBYTE b);
|
||||
int InstrSHORT_W(asEBCInstr bc, short a, asWORD b);
|
||||
int InstrSHORT_DW(asEBCInstr bc, short a, asDWORD b);
|
||||
int InstrSHORT_QW(asEBCInstr bc, short a, asQWORD b);
|
||||
int InstrW_DW(asEBCInstr bc, asWORD a, asDWORD b);
|
||||
int InstrW_QW(asEBCInstr bc, asWORD a, asQWORD b);
|
||||
int InstrW_PTR(asEBCInstr bc, short a, void *param);
|
||||
int InstrW_FLOAT(asEBCInstr bc, asWORD a, float b);
|
||||
int InstrW_W(asEBCInstr bc, int w, int b);
|
||||
int InstrSHORT_DW_DW(asEBCInstr bc, short a, asDWORD b, asDWORD c);
|
||||
|
||||
asCScriptEngine *GetEngine() const { return engine; };
|
||||
|
||||
asCArray<int> lineNumbers;
|
||||
asCArray<int> sectionIdxs;
|
||||
int largestStackUsed;
|
||||
|
||||
protected:
|
||||
// Assignments are not allowed
|
||||
void operator=(const asCByteCode &) {}
|
||||
|
||||
// Helpers for Optimize
|
||||
bool CanBeSwapped(asCByteInstruction *curr);
|
||||
asCByteInstruction *ChangeFirstDeleteNext(asCByteInstruction *curr, asEBCInstr bc);
|
||||
asCByteInstruction *DeleteFirstChangeNext(asCByteInstruction *curr, asEBCInstr bc);
|
||||
asCByteInstruction *DeleteInstruction(asCByteInstruction *instr);
|
||||
void RemoveInstruction(asCByteInstruction *instr);
|
||||
asCByteInstruction *GoBack(asCByteInstruction *curr);
|
||||
asCByteInstruction *GoForward(asCByteInstruction *curr);
|
||||
void InsertBefore(asCByteInstruction *before, asCByteInstruction *instr);
|
||||
bool RemoveUnusedValue(asCByteInstruction *curr, asCByteInstruction **next);
|
||||
bool IsTemporary(int offset);
|
||||
bool IsTempRegUsed(asCByteInstruction *curr);
|
||||
bool IsTempVarRead(asCByteInstruction *curr, int offset);
|
||||
bool PostponeInitOfTemp(asCByteInstruction *curr, asCByteInstruction **next);
|
||||
bool IsTempVarReadByInstr(asCByteInstruction *curr, int var);
|
||||
bool IsTempVarOverwrittenByInstr(asCByteInstruction *curr, int var);
|
||||
bool IsInstrJmpOrLabel(asCByteInstruction *curr);
|
||||
|
||||
int AddInstruction();
|
||||
int AddInstructionFirst();
|
||||
|
||||
asCByteInstruction *first;
|
||||
asCByteInstruction *last;
|
||||
|
||||
const asCArray<int> *temporaryVariables;
|
||||
|
||||
asCScriptEngine *engine;
|
||||
};
|
||||
|
||||
class asCByteInstruction
|
||||
{
|
||||
public:
|
||||
asCByteInstruction();
|
||||
|
||||
void AddAfter(asCByteInstruction *nextCode);
|
||||
void AddBefore(asCByteInstruction *nextCode);
|
||||
void Remove();
|
||||
|
||||
int GetSize();
|
||||
int GetStackIncrease();
|
||||
|
||||
asCByteInstruction *next;
|
||||
asCByteInstruction *prev;
|
||||
|
||||
asEBCInstr op;
|
||||
asQWORD arg;
|
||||
short wArg[3];
|
||||
int size;
|
||||
int stackInc;
|
||||
|
||||
// Testing
|
||||
bool marked;
|
||||
int stackSize;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_NO_COMPILER
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,920 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2021 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_callfunc.cpp
|
||||
//
|
||||
// These functions handle the actual calling of system functions
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_callfunc.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_context.h"
|
||||
|
||||
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 *auxiliary, asSSystemFunctionInterface *internal)
|
||||
{
|
||||
internal->Clear();
|
||||
internal->func = ptr.ptr.f.func;
|
||||
internal->auxiliary = 0;
|
||||
|
||||
// Was a compatible calling convention specified?
|
||||
if( internal->func )
|
||||
{
|
||||
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 || callConv == asCALL_THISCALL_OBJFIRST || callConv == asCALL_THISCALL_OBJLAST) )
|
||||
return asWRONG_CALLING_CONV;
|
||||
else if( ptr.flag == 3 && !(callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL || callConv == asCALL_THISCALL_OBJFIRST || callConv == asCALL_THISCALL_OBJLAST) )
|
||||
return asWRONG_CALLING_CONV;
|
||||
}
|
||||
|
||||
asDWORD base = callConv;
|
||||
if( !isMethod )
|
||||
{
|
||||
if( base == asCALL_CDECL )
|
||||
internal->callConv = ICC_CDECL;
|
||||
else if( base == asCALL_STDCALL )
|
||||
internal->callConv = ICC_STDCALL;
|
||||
else if( base == asCALL_THISCALL_ASGLOBAL )
|
||||
{
|
||||
if(auxiliary == 0)
|
||||
return asINVALID_ARG;
|
||||
internal->auxiliary = auxiliary;
|
||||
internal->callConv = ICC_THISCALL;
|
||||
|
||||
// This is really a thiscall, so it is necessary to check for virtual method pointers
|
||||
base = asCALL_THISCALL;
|
||||
isMethod = true;
|
||||
}
|
||||
else if (base == asCALL_GENERIC)
|
||||
{
|
||||
internal->callConv = ICC_GENERIC_FUNC;
|
||||
|
||||
// The auxiliary object is optional for generic calling convention
|
||||
internal->auxiliary = auxiliary;
|
||||
}
|
||||
else
|
||||
return asNOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if( isMethod )
|
||||
{
|
||||
#ifndef AS_NO_CLASS_METHODS
|
||||
if( base == asCALL_THISCALL || base == asCALL_THISCALL_OBJFIRST || base == asCALL_THISCALL_OBJLAST )
|
||||
{
|
||||
internalCallConv thisCallConv;
|
||||
if( base == asCALL_THISCALL )
|
||||
{
|
||||
if(callConv != asCALL_THISCALL_ASGLOBAL && auxiliary)
|
||||
return asINVALID_ARG;
|
||||
|
||||
thisCallConv = ICC_THISCALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
return asNOT_SUPPORTED;
|
||||
#else
|
||||
if(auxiliary == 0)
|
||||
return asINVALID_ARG;
|
||||
|
||||
internal->auxiliary = auxiliary;
|
||||
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 = (internalCallConv)(thisCallConv + 2);
|
||||
#endif
|
||||
internal->baseOffset = ( int )MULTI_BASE_OFFSET(ptr);
|
||||
#if (defined(AS_ARM64) || defined(AS_ARM) || defined(AS_MIPS)) && (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.
|
||||
// MIPS also appear to use the base offset to indicate virtual method.
|
||||
if( (size_t(internal->baseOffset) & 1) )
|
||||
internal->callConv = (internalCallConv)(thisCallConv + 2);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VIRTUAL_BASE_OFFSET
|
||||
// We don't support virtual inheritance
|
||||
if( VIRTUAL_BASE_OFFSET(ptr) != 0 )
|
||||
return asNOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if( base == asCALL_CDECL_OBJLAST )
|
||||
internal->callConv = ICC_CDECL_OBJLAST;
|
||||
else if( base == asCALL_CDECL_OBJFIRST )
|
||||
internal->callConv = ICC_CDECL_OBJFIRST;
|
||||
else if (base == asCALL_GENERIC)
|
||||
{
|
||||
internal->callConv = ICC_GENERIC_METHOD;
|
||||
internal->auxiliary = auxiliary;
|
||||
}
|
||||
else
|
||||
return asNOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This function should prepare system functions so that it will be faster to call them
|
||||
int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine)
|
||||
{
|
||||
asASSERT(internal->callConv == ICC_GENERIC_METHOD || internal->callConv == ICC_GENERIC_FUNC);
|
||||
|
||||
// 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.IsFuncdef()) && !dt.IsReference() )
|
||||
{
|
||||
if (dt.IsFuncdef())
|
||||
{
|
||||
// If the generic call mode is set to old behaviour then always release handles
|
||||
// else only release the handle if the function is declared with auto handles
|
||||
if (engine->ep.genericCallMode == 0 || (internal->paramAutoHandles.GetLength() > n && internal->paramAutoHandles[n]))
|
||||
{
|
||||
asSSystemFunctionInterface::SClean clean;
|
||||
clean.op = 0; // call release
|
||||
clean.ot = &engine->functionBehaviours;
|
||||
clean.off = short(offset);
|
||||
internal->cleanArgs.PushLast(clean);
|
||||
}
|
||||
}
|
||||
else if( dt.GetTypeInfo()->flags & asOBJ_REF )
|
||||
{
|
||||
// If the generic call mode is set to old behaviour then always release handles
|
||||
// else only release the handle if the function is declared with auto handles
|
||||
if (!dt.IsObjectHandle() ||
|
||||
engine->ep.genericCallMode == 0 ||
|
||||
(internal->paramAutoHandles.GetLength() > n && internal->paramAutoHandles[n]) )
|
||||
{
|
||||
asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh;
|
||||
asASSERT((dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release);
|
||||
if (beh->release)
|
||||
{
|
||||
asSSystemFunctionInterface::SClean clean;
|
||||
clean.op = 0; // call release
|
||||
clean.ot = CastToObjectType(dt.GetTypeInfo());
|
||||
clean.off = short(offset);
|
||||
internal->cleanArgs.PushLast(clean);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asSSystemFunctionInterface::SClean clean;
|
||||
clean.op = 1; // call free
|
||||
clean.ot = CastToObjectType(dt.GetTypeInfo());
|
||||
clean.off = short(offset);
|
||||
|
||||
// Call the destructor then free the memory
|
||||
asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh;
|
||||
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;
|
||||
}
|
||||
|
||||
// This function should prepare system functions so that it will be faster to call them
|
||||
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);
|
||||
#else
|
||||
// References are always returned as primitive data
|
||||
if( func->returnType.IsReference() || func->returnType.IsObjectHandle() )
|
||||
{
|
||||
internal->hostReturnInMemory = false;
|
||||
internal->hostReturnSize = sizeof(void*)/4;
|
||||
internal->hostReturnFloat = false;
|
||||
}
|
||||
// Registered types have special flags that determine how they are returned
|
||||
else if( func->returnType.IsObject() )
|
||||
{
|
||||
asDWORD objType = func->returnType.GetTypeInfo()->flags;
|
||||
|
||||
// Only value types can be returned by value
|
||||
asASSERT( objType & asOBJ_VALUE );
|
||||
|
||||
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());
|
||||
|
||||
asCString str;
|
||||
str.Format(TXT_CANNOT_RET_TYPE_s_BY_VAL, func->returnType.GetTypeInfo()->name.AddressOf());
|
||||
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;
|
||||
if( objType & COMPLEX_RETURN_MASK )
|
||||
{
|
||||
internal->hostReturnInMemory = true;
|
||||
internal->hostReturnSize = sizeof(void*)/4;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HAS_128_BIT_PRIMITIVES
|
||||
if( func->returnType.GetSizeInMemoryDWords() > 4 )
|
||||
#else
|
||||
if( func->returnType.GetSizeInMemoryDWords() > 2 )
|
||||
#endif
|
||||
{
|
||||
internal->hostReturnInMemory = true;
|
||||
internal->hostReturnSize = sizeof(void*)/4;
|
||||
}
|
||||
else
|
||||
{
|
||||
internal->hostReturnInMemory = false;
|
||||
internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords();
|
||||
#ifdef SPLIT_OBJS_BY_MEMBER_TYPES
|
||||
if( func->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS )
|
||||
internal->hostReturnFloat = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#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;
|
||||
internal->hostReturnSize = sizeof(void*)/4;
|
||||
}
|
||||
#endif
|
||||
#ifdef CDECL_RETURN_SIMPLE_IN_MEMORY
|
||||
if((internal->callConv == ICC_CDECL ||
|
||||
internal->callConv == ICC_CDECL_OBJLAST ||
|
||||
internal->callConv == ICC_CDECL_OBJFIRST) &&
|
||||
func->returnType.GetSizeInMemoryDWords() >= CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE)
|
||||
{
|
||||
internal->hostReturnInMemory = true;
|
||||
internal->hostReturnSize = sizeof(void*)/4;
|
||||
}
|
||||
#endif
|
||||
#ifdef STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
if( internal->callConv == ICC_STDCALL &&
|
||||
func->returnType.GetSizeInMemoryDWords() >= STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE)
|
||||
{
|
||||
internal->hostReturnInMemory = true;
|
||||
internal->hostReturnSize = sizeof(void*)/4;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SPLIT_OBJS_BY_MEMBER_TYPES
|
||||
// It's not safe to return objects by value because different registers
|
||||
// will be used depending on the memory layout of the object.
|
||||
// Ref: http://www.x86-64.org/documentation/abi.pdf
|
||||
// Ref: http://www.agner.org/optimize/calling_conventions.pdf
|
||||
// If the application informs that the class should be treated as all integers, then we allow it
|
||||
if( !internal->hostReturnInMemory &&
|
||||
!(func->returnType.GetTypeInfo()->flags & (asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) )
|
||||
{
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
|
||||
|
||||
asCString str;
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if( objType & asOBJ_APP_PRIMITIVE )
|
||||
{
|
||||
internal->hostReturnInMemory = false;
|
||||
internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords();
|
||||
internal->hostReturnFloat = false;
|
||||
}
|
||||
else if( objType & asOBJ_APP_FLOAT )
|
||||
{
|
||||
internal->hostReturnInMemory = false;
|
||||
internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords();
|
||||
internal->hostReturnFloat = true;
|
||||
}
|
||||
}
|
||||
// Primitive types can easily be determined
|
||||
#ifdef HAS_128_BIT_PRIMITIVES
|
||||
else if( func->returnType.GetSizeInMemoryDWords() > 4 )
|
||||
{
|
||||
// Shouldn't be possible to get here
|
||||
asASSERT(false);
|
||||
}
|
||||
else if( func->returnType.GetSizeInMemoryDWords() == 4 )
|
||||
{
|
||||
internal->hostReturnInMemory = false;
|
||||
internal->hostReturnSize = 4;
|
||||
internal->hostReturnFloat = false;
|
||||
}
|
||||
#else
|
||||
else if( func->returnType.GetSizeInMemoryDWords() > 2 )
|
||||
{
|
||||
// Shouldn't be possible to get here
|
||||
asASSERT(false);
|
||||
}
|
||||
#endif
|
||||
else if( func->returnType.GetSizeInMemoryDWords() == 2 )
|
||||
{
|
||||
internal->hostReturnInMemory = false;
|
||||
internal->hostReturnSize = 2;
|
||||
internal->hostReturnFloat = func->returnType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttDouble, true));
|
||||
}
|
||||
else if( func->returnType.GetSizeInMemoryDWords() == 1 )
|
||||
{
|
||||
internal->hostReturnInMemory = false;
|
||||
internal->hostReturnSize = 1;
|
||||
internal->hostReturnFloat = func->returnType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttFloat, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
internal->hostReturnInMemory = false;
|
||||
internal->hostReturnSize = 0;
|
||||
internal->hostReturnFloat = false;
|
||||
}
|
||||
|
||||
// Calculate the size needed for the parameters
|
||||
internal->paramSize = func->GetSpaceNeededForArguments();
|
||||
|
||||
// Verify if the function takes any objects by value
|
||||
asUINT n;
|
||||
internal->takesObjByVal = false;
|
||||
for( n = 0; n < func->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
if( func->parameterTypes[n].IsObject() && !func->parameterTypes[n].IsObjectHandle() && !func->parameterTypes[n].IsReference() )
|
||||
{
|
||||
internal->takesObjByVal = true;
|
||||
|
||||
// Can't pass objects by value unless the application type is informed
|
||||
if( !(func->parameterTypes[n].GetTypeInfo()->flags & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) )
|
||||
{
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
|
||||
|
||||
asCString str;
|
||||
str.Format(TXT_CANNOT_PASS_TYPE_s_BY_VAL, func->parameterTypes[n].GetTypeInfo()->name.AddressOf());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
|
||||
engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
#ifdef SPLIT_OBJS_BY_MEMBER_TYPES
|
||||
// It's not safe to pass objects by value because different registers
|
||||
// will be used depending on the memory layout of the object
|
||||
// Ref: http://www.x86-64.org/documentation/abi.pdf
|
||||
// Ref: http://www.agner.org/optimize/calling_conventions.pdf
|
||||
if(
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
!(func->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK) &&
|
||||
#endif
|
||||
#ifdef LARGE_OBJS_PASS_BY_REF
|
||||
func->parameterTypes[n].GetSizeInMemoryDWords() < AS_LARGE_OBJ_MIN_SIZE &&
|
||||
#endif
|
||||
!(func->parameterTypes[n].GetTypeInfo()->flags & (asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) )
|
||||
{
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
|
||||
|
||||
asCString str;
|
||||
str.Format(TXT_DONT_SUPPORT_TYPE_s_BY_VAL, func->parameterTypes[n].GetTypeInfo()->name.AddressOf());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
|
||||
engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the clean up instructions for the function arguments
|
||||
internal->cleanArgs.SetLength(0);
|
||||
int offset = 0;
|
||||
for( n = 0; n < func->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
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.GetTypeInfo() && dt.GetTypeInfo()->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 = CastToObjectType(dt.GetTypeInfo());
|
||||
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 = &CastToObjectType(dt.GetTypeInfo())->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
|
||||
if (dt.IsFuncdef())
|
||||
clean.ot = &engine->functionBehaviours;
|
||||
else
|
||||
clean.ot = CastToObjectType(dt.GetTypeInfo());
|
||||
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)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
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(func);
|
||||
|
||||
context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//
|
||||
// CallSystemFunctionNative
|
||||
//
|
||||
// This function is implemented for each platform where the native calling conventions is supported.
|
||||
// See the various as_callfunc_xxx.cpp files for their implementation. It is responsible for preparing
|
||||
// the arguments for the function call, calling the function, and then retrieving the return value.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// context - This is the context that can be used to retrieve specific information from the engine
|
||||
// descr - This is the script function object that holds the information on how to call the function
|
||||
// obj - This is the object pointer, if the call is for a class method, otherwise it is null
|
||||
// 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, void *secondObj);
|
||||
|
||||
|
||||
int CallSystemFunction(int id, asCContext *context)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asCScriptFunction *descr = engine->scriptFunctions[id];
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
|
||||
int callConv = sysFunc->callConv;
|
||||
if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD )
|
||||
return context->CallGeneric(descr);
|
||||
|
||||
asQWORD retQW = 0;
|
||||
asQWORD retQW2 = 0;
|
||||
asDWORD *args = context->m_regs.stackPointer;
|
||||
void *retPointer = 0;
|
||||
int popSize = sysFunc->paramSize;
|
||||
|
||||
// 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;
|
||||
|
||||
#ifdef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
if( callConv >= ICC_THISCALL )
|
||||
{
|
||||
if(sysFunc->auxiliary)
|
||||
{
|
||||
// This class method is being called as if it is a global function
|
||||
obj = sysFunc->auxiliary;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The object pointer should be popped from the context stack
|
||||
popSize += AS_PTR_SIZE;
|
||||
|
||||
// Check for null pointer
|
||||
obj = (void*)*(asPWORD*)(args);
|
||||
if( obj == 0 )
|
||||
{
|
||||
context->SetInternalException(TXT_NULL_POINTER_ACCESS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Skip the object pointer
|
||||
args += AS_PTR_SIZE;
|
||||
}
|
||||
|
||||
// Add the base offset for multiple inheritance
|
||||
#if (defined(__GNUC__) && (defined(AS_ARM64) || defined(AS_ARM) || defined(AS_MIPS))) || 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
|
||||
// MIPS also work like ARM in this regard
|
||||
obj = (void*)(asPWORD(obj) + (sysFunc->baseOffset>>1));
|
||||
#else
|
||||
obj = (void*)(asPWORD(obj) + sysFunc->baseOffset);
|
||||
#endif
|
||||
}
|
||||
#else // !defined(AS_NO_THISCALL_FUNCTOR_METHOD)
|
||||
|
||||
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->auxiliary != 0 );
|
||||
// This class method is being called as object method (sysFunc->auxiliary must be set).
|
||||
obj = sysFunc->auxiliary;
|
||||
continueCheckIndex = 1;
|
||||
}
|
||||
else if(sysFunc->auxiliary)
|
||||
{
|
||||
// This class method is being called as if it is a global function
|
||||
obj = sysFunc->auxiliary;
|
||||
continueCheck = false;
|
||||
}
|
||||
|
||||
if( obj )
|
||||
{
|
||||
// Add the base offset for multiple inheritance
|
||||
#if (defined(__GNUC__) && (defined(AS_ARM64) || defined(AS_ARM) || defined(AS_MIPS))) || 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
|
||||
// MIPS also work like ARM in this regard
|
||||
obj = (void*)(asPWORD(obj) + (sysFunc->baseOffset>>1));
|
||||
#else
|
||||
obj = (void*)(asPWORD(obj) + sysFunc->baseOffset);
|
||||
#endif
|
||||
}
|
||||
|
||||
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_ARM64) || defined(AS_ARM) || defined(AS_MIPS))) || 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
|
||||
// MIPS also work like ARM in this regard
|
||||
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() )
|
||||
{
|
||||
// Get the address of the location for the return value from the stack
|
||||
retPointer = (void*)*(asPWORD*)(args);
|
||||
popSize += AS_PTR_SIZE;
|
||||
args += AS_PTR_SIZE;
|
||||
|
||||
// When returning the value on the location allocated by the called
|
||||
// we shouldn't set the object type in the register
|
||||
context->m_regs.objectType = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the object type of the reference held in the register
|
||||
context->m_regs.objectType = descr->returnType.GetTypeInfo();
|
||||
}
|
||||
|
||||
// For composition we need to add the offset and/or dereference the pointer
|
||||
if(obj)
|
||||
{
|
||||
obj = (void*) ((char*) obj + sysFunc->compositeOffset);
|
||||
if(sysFunc->isCompositeIndirect) obj = *((void**)obj);
|
||||
}
|
||||
|
||||
context->m_callingSystemFunction = descr;
|
||||
bool cppException = false;
|
||||
#ifdef AS_NO_EXCEPTIONS
|
||||
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
|
||||
// CallSystemFunctionNative() must make sure not to have any manual
|
||||
// clean-up after the call to the real function, or that won't be
|
||||
// executed in case of an exception.
|
||||
try
|
||||
{
|
||||
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->HandleAppException();
|
||||
}
|
||||
#endif
|
||||
context->m_callingSystemFunction = 0;
|
||||
|
||||
// Store the returned value in our stack
|
||||
if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() )
|
||||
{
|
||||
if( descr->returnType.IsObjectHandle() )
|
||||
{
|
||||
#if defined(AS_BIG_ENDIAN) && AS_PTR_SIZE == 1
|
||||
// Since we're treating the system function as if it is returning a QWORD we are
|
||||
// actually receiving the value in the high DWORD of retQW.
|
||||
retQW >>= 32;
|
||||
#endif
|
||||
|
||||
context->m_regs.objectRegister = (void*)(asPWORD)retQW;
|
||||
|
||||
if( sysFunc->returnAutoHandle && context->m_regs.objectRegister )
|
||||
{
|
||||
asASSERT( !(descr->returnType.GetTypeInfo()->flags & asOBJ_NOCOUNT) );
|
||||
engine->CallObjectMethod(context->m_regs.objectRegister, CastToObjectType(descr->returnType.GetTypeInfo())->beh.addref);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asASSERT( retPointer );
|
||||
|
||||
if( !sysFunc->hostReturnInMemory )
|
||||
{
|
||||
// Copy the returned value to the pointer sent by the script engine
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
{
|
||||
#if defined(AS_BIG_ENDIAN) && AS_PTR_SIZE == 1
|
||||
// Since we're treating the system function as if it is returning a QWORD we are
|
||||
// actually receiving the value in the high DWORD of retQW.
|
||||
retQW >>= 32;
|
||||
#endif
|
||||
|
||||
*(asDWORD*)retPointer = (asDWORD)retQW;
|
||||
}
|
||||
else if( sysFunc->hostReturnSize == 2 )
|
||||
*(asQWORD*)retPointer = retQW;
|
||||
else if( sysFunc->hostReturnSize == 3 )
|
||||
{
|
||||
*(asQWORD*)retPointer = retQW;
|
||||
*(((asDWORD*)retPointer) + 2) = (asDWORD)retQW2;
|
||||
}
|
||||
else // if( sysFunc->hostReturnSize == 4 )
|
||||
{
|
||||
*(asQWORD*)retPointer = retQW;
|
||||
*(((asQWORD*)retPointer) + 1) = retQW2;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// no way for the application to not return a value, so instead we simply
|
||||
// destroy it here, to pretend it was never created.
|
||||
if(CastToObjectType(descr->returnType.GetTypeInfo())->beh.destruct )
|
||||
engine->CallObjectMethod(retPointer, CastToObjectType(descr->returnType.GetTypeInfo())->beh.destruct);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Store value in value register
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
{
|
||||
#if defined(AS_BIG_ENDIAN)
|
||||
// Since we're treating the system function as if it is returning a QWORD we are
|
||||
// actually receiving the value in the high DWORD of retQW.
|
||||
retQW >>= 32;
|
||||
|
||||
// Due to endian issues we need to handle return values that are
|
||||
// less than a DWORD (32 bits) in size specially
|
||||
int numBytes = descr->returnType.GetSizeInMemoryBytes();
|
||||
if( descr->returnType.IsReference() ) numBytes = 4;
|
||||
switch( numBytes )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
// 8 bits
|
||||
asBYTE *val = (asBYTE*)&context->m_regs.valueRegister;
|
||||
val[0] = (asBYTE)retQW;
|
||||
val[1] = 0;
|
||||
val[2] = 0;
|
||||
val[3] = 0;
|
||||
val[4] = 0;
|
||||
val[5] = 0;
|
||||
val[6] = 0;
|
||||
val[7] = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
// 16 bits
|
||||
asWORD *val = (asWORD*)&context->m_regs.valueRegister;
|
||||
val[0] = (asWORD)retQW;
|
||||
val[1] = 0;
|
||||
val[2] = 0;
|
||||
val[3] = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
// 32 bits
|
||||
asDWORD *val = (asDWORD*)&context->m_regs.valueRegister;
|
||||
val[0] = (asDWORD)retQW;
|
||||
val[1] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#else
|
||||
*(asDWORD*)&context->m_regs.valueRegister = (asDWORD)retQW;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
context->m_regs.valueRegister = retQW;
|
||||
}
|
||||
|
||||
// Clean up arguments
|
||||
const asUINT cleanCount = sysFunc->cleanArgs.GetLength();
|
||||
if( cleanCount )
|
||||
{
|
||||
args = context->m_regs.stackPointer;
|
||||
|
||||
// Skip the hidden argument for the return pointer
|
||||
// TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction
|
||||
if( descr->DoesReturnOnStack() )
|
||||
args += AS_PTR_SIZE;
|
||||
|
||||
// Skip the object pointer on the stack
|
||||
// TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction
|
||||
if( callConv >= ICC_THISCALL && sysFunc->auxiliary == 0 )
|
||||
args += AS_PTR_SIZE;
|
||||
|
||||
asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf();
|
||||
for( asUINT n = 0; n < cleanCount; n++, clean++ )
|
||||
{
|
||||
void **addr = (void**)&args[clean->off];
|
||||
if( clean->op == 0 )
|
||||
{
|
||||
if( *addr != 0 )
|
||||
{
|
||||
engine->CallObjectMethod(*addr, clean->ot->beh.release);
|
||||
*addr = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asASSERT( clean->op == 1 || clean->op == 2 );
|
||||
asASSERT( *addr );
|
||||
|
||||
if( clean->op == 2 )
|
||||
engine->CallObjectMethod(*addr, clean->ot->beh.destruct);
|
||||
|
||||
engine->CallFree(*addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return popSize;
|
||||
}
|
||||
|
||||
#endif // AS_MAX_PORTABILITY
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2021 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_callfunc.h
|
||||
//
|
||||
// These functions handle the actual calling of system functions
|
||||
//
|
||||
|
||||
|
||||
#ifndef AS_CALLFUNC_H
|
||||
#define AS_CALLFUNC_H
|
||||
|
||||
#include "as_array.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCContext;
|
||||
class asCScriptEngine;
|
||||
class asCScriptFunction;
|
||||
class asCObjectType;
|
||||
struct asSSystemFunctionInterface;
|
||||
|
||||
int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *auxiliary, asSSystemFunctionInterface *internal);
|
||||
|
||||
int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine);
|
||||
|
||||
int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine);
|
||||
|
||||
int CallSystemFunction(int id, asCContext *context);
|
||||
|
||||
inline asPWORD FuncPtrToUInt(asFUNCTION_t func)
|
||||
{
|
||||
// A little trickery as the C++ standard doesn't allow direct
|
||||
// conversion between function pointer and data pointer
|
||||
union { asFUNCTION_t func; asPWORD idx; } u;
|
||||
u.func = func;
|
||||
|
||||
return u.idx;
|
||||
}
|
||||
|
||||
enum internalCallConv
|
||||
{
|
||||
ICC_GENERIC_FUNC,
|
||||
ICC_GENERIC_FUNC_RETURNINMEM, // never used
|
||||
ICC_CDECL,
|
||||
ICC_CDECL_RETURNINMEM,
|
||||
ICC_STDCALL,
|
||||
ICC_STDCALL_RETURNINMEM,
|
||||
ICC_THISCALL,
|
||||
ICC_THISCALL_RETURNINMEM,
|
||||
ICC_VIRTUAL_THISCALL,
|
||||
ICC_VIRTUAL_THISCALL_RETURNINMEM,
|
||||
ICC_CDECL_OBJLAST,
|
||||
ICC_CDECL_OBJLAST_RETURNINMEM,
|
||||
ICC_CDECL_OBJFIRST,
|
||||
ICC_CDECL_OBJFIRST_RETURNINMEM,
|
||||
ICC_GENERIC_METHOD,
|
||||
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
|
||||
{
|
||||
asFUNCTION_t func;
|
||||
int baseOffset;
|
||||
internalCallConv callConv;
|
||||
bool hostReturnInMemory;
|
||||
bool hostReturnFloat;
|
||||
int hostReturnSize;
|
||||
int paramSize;
|
||||
bool takesObjByVal;
|
||||
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;
|
||||
int compositeOffset;
|
||||
bool isCompositeIndirect;
|
||||
void *auxiliary; // can be used for functors, e.g. by asCALL_THISCALL_ASGLOBAL or asCALL_THISCALL_OBJFIRST
|
||||
|
||||
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()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
asSSystemFunctionInterface(const asSSystemFunctionInterface &in)
|
||||
{
|
||||
*this = in;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
func = 0;
|
||||
baseOffset = 0;
|
||||
callConv = ICC_GENERIC_FUNC;
|
||||
hostReturnInMemory = false;
|
||||
hostReturnFloat = false;
|
||||
hostReturnSize = 0;
|
||||
paramSize = 0;
|
||||
takesObjByVal = false;
|
||||
returnAutoHandle = false;
|
||||
compositeOffset = 0;
|
||||
isCompositeIndirect = false;
|
||||
auxiliary = 0;
|
||||
|
||||
paramAutoHandles.SetLength(0);
|
||||
cleanArgs.SetLength(0);
|
||||
}
|
||||
|
||||
asSSystemFunctionInterface &operator=(const asSSystemFunctionInterface &in)
|
||||
{
|
||||
func = in.func;
|
||||
baseOffset = in.baseOffset;
|
||||
callConv = in.callConv;
|
||||
hostReturnInMemory = in.hostReturnInMemory;
|
||||
hostReturnFloat = in.hostReturnFloat;
|
||||
hostReturnSize = in.hostReturnSize;
|
||||
paramSize = in.paramSize;
|
||||
takesObjByVal = in.takesObjByVal;
|
||||
returnAutoHandle = in.returnAutoHandle;
|
||||
compositeOffset = in.compositeOffset;
|
||||
isCompositeIndirect = in.isCompositeIndirect;
|
||||
auxiliary = in.auxiliary;
|
||||
|
||||
cleanArgs = in.cleanArgs;
|
||||
paramAutoHandles = in.paramAutoHandles;
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,665 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_callfunc_arm.cpp
|
||||
//
|
||||
// These functions handle the actual calling of system functions on the arm platform
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// Reference:
|
||||
//
|
||||
// AAPCS: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf
|
||||
// iOS: http://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/iPhoneOSABIReference.pdf
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
#ifdef AS_ARM
|
||||
|
||||
#include "as_callfunc.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_tokendef.h"
|
||||
#include "as_context.h"
|
||||
|
||||
#if defined(AS_SOFTFP)
|
||||
|
||||
// This code supports the soft-float ABI, i.e. g++ -mfloat-abi=softfp
|
||||
//
|
||||
// The code for iOS, Android, Marmalade and Windows Phone goes here
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
extern "C" asQWORD armFunc (const asDWORD *, int, asFUNCTION_t);
|
||||
extern "C" asQWORD armFuncR0 (const asDWORD *, int, asFUNCTION_t, asDWORD r0);
|
||||
extern "C" asQWORD armFuncR0R1 (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD r1);
|
||||
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*/, void *secondObject)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
int callConv = sysFunc->callConv;
|
||||
|
||||
asQWORD retQW = 0;
|
||||
asFUNCTION_t func = sysFunc->func;
|
||||
int paramSize = sysFunc->paramSize;
|
||||
asFUNCTION_t *vftable;
|
||||
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
{
|
||||
// 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)
|
||||
// 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;
|
||||
|
||||
if( isThisCallMethod )
|
||||
{
|
||||
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;
|
||||
#endif
|
||||
paramSize = 0;
|
||||
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() )
|
||||
{
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
|
||||
{
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
paramSize++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if defined(AS_ANDROID) || defined(AS_LINUX)
|
||||
if( (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) &&
|
||||
((dpos & 1) == mask) )
|
||||
{
|
||||
// 64 bit value align
|
||||
dpos++;
|
||||
paramSize++;
|
||||
}
|
||||
#endif
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
|
||||
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+spos));
|
||||
spos++;
|
||||
dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(AS_ANDROID) || defined(AS_LINUX)
|
||||
// Should an alignment be performed?
|
||||
if( !descr->parameterTypes[n].IsObjectHandle() &&
|
||||
!descr->parameterTypes[n].IsReference() &&
|
||||
descr->parameterTypes[n].GetSizeOnStackDWords() == 2 &&
|
||||
((dpos & 1) == mask) )
|
||||
{
|
||||
// 64 bit value align
|
||||
dpos++;
|
||||
paramSize++;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Copy the value directly
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
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];
|
||||
}
|
||||
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_CDECL_RETURNINMEM: // fall through
|
||||
case ICC_STDCALL_RETURNINMEM:
|
||||
retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)retPointer);
|
||||
break;
|
||||
case ICC_CDECL: // fall through
|
||||
case ICC_STDCALL:
|
||||
retQW = armFunc(args, paramSize<<2, func);
|
||||
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);
|
||||
#else
|
||||
// On Windows the R0 should always hold the object pointer, and the address for the return value comes after
|
||||
retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)obj, (asDWORD)retPointer);
|
||||
#endif
|
||||
break;
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
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__
|
||||
// On GNUC the address where the return value will be placed should be put in R0
|
||||
retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)retPointer, (asDWORD)obj);
|
||||
#else
|
||||
// On Windows the R0 should always hold the object pointer, and the address for the return value comes after
|
||||
retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj, (asDWORD)retPointer);
|
||||
#endif
|
||||
break;
|
||||
case ICC_CDECL_OBJLAST:
|
||||
retQW = armFuncObjLast(args, paramSize<<2, func, (asDWORD)obj);
|
||||
break;
|
||||
case ICC_CDECL_OBJLAST_RETURNINMEM:
|
||||
retQW = armFuncR0ObjLast(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
|
||||
break;
|
||||
default:
|
||||
context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#elif !defined(AS_SOFTFP)
|
||||
|
||||
// This code supports the hard-float ABI, i.e. g++ -mfloat-abi=hard
|
||||
// The main difference is that the floating point values are passed in the fpu registers
|
||||
|
||||
#define VFP_OFFSET 70
|
||||
#define STACK_OFFSET 6
|
||||
#define PARAM_BUFFER_SIZE 104
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
extern "C" asQWORD armFunc (const asDWORD *, int, asFUNCTION_t);
|
||||
extern "C" asQWORD armFuncR0 (const asDWORD *, int, asFUNCTION_t, asDWORD r0);
|
||||
extern "C" asQWORD armFuncR0R1 (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD r1);
|
||||
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*/, void *secondObject)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
int callConv = sysFunc->callConv;
|
||||
|
||||
asQWORD retQW = 0;
|
||||
asFUNCTION_t func = sysFunc->func;
|
||||
int paramSize = sysFunc->paramSize;
|
||||
asFUNCTION_t *vftable;
|
||||
|
||||
//---------------------------------------------------------------------------- RPi
|
||||
int freeFloatSlot = VFP_OFFSET;
|
||||
int freeDoubleSlot = VFP_OFFSET;
|
||||
int stackPos = STACK_OFFSET;
|
||||
int stackSize = 0;
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------------- RPi
|
||||
// We´ll divide paramBuffer into several segments:
|
||||
//
|
||||
// 0-1 Unused
|
||||
// 2-5 (+8 / +0 asm) values that should be placed in R0 - R3
|
||||
// 6-67 (+24 / +16 asm) values that should be placed on the stack
|
||||
// 68 (+272 / +264 asm) number of values stored in r registers (R0 - R3)
|
||||
// 69 (+276 / +268 asm) number of args stored on the stack
|
||||
// 70-85 (+280 / +272 asm) values that should be placed in VFP registers (16)
|
||||
// 86-87 (+344 / +336 asm) sp original value - sp final value - for debugging
|
||||
// 88-103 (+352 / +344 asm) Check area for free-used VFP registers
|
||||
//
|
||||
// Total number of elements: 104
|
||||
//
|
||||
// When passing the paramBuffer to the asm routines via the args pointer we are
|
||||
// offsetting the start of the array to being at element # 2. That´s why in asm
|
||||
// all addresses must have an offset of -2 words (-8 bytes).
|
||||
//---------------------------------------------------------------------------- RPi
|
||||
|
||||
asDWORD paramBuffer[PARAM_BUFFER_SIZE];
|
||||
memset(paramBuffer, 0, sizeof(asDWORD) * PARAM_BUFFER_SIZE);
|
||||
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
{
|
||||
// TODO: runtime optimize: This check should be done in PrepareSystemFunction
|
||||
if ( !( descr->returnType.GetTypeInfo()->flags & COMPLEX_RETURN_MASK ) &&
|
||||
( descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS ) &&
|
||||
descr->returnType.GetSizeInMemoryBytes() <= 8 )
|
||||
callConv--;
|
||||
|
||||
// The return is made in memory
|
||||
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
|
||||
{
|
||||
// mask is used as a toggler to skip uneven registers.
|
||||
int mask = 1;
|
||||
|
||||
if( isThisCallMethod )
|
||||
{
|
||||
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;
|
||||
|
||||
paramSize = 0;
|
||||
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() &&
|
||||
!(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) )
|
||||
{
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
|
||||
{
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
paramSize++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if( (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) )
|
||||
{
|
||||
if ( (dpos & 1) == mask )
|
||||
{
|
||||
// 64 bit value align
|
||||
dpos++;
|
||||
paramSize++;
|
||||
}
|
||||
|
||||
if ( (stackPos & 1) == mask )
|
||||
{
|
||||
// 64 bit value align
|
||||
stackPos++;
|
||||
stackSize++;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the object's memory to the buffer
|
||||
if (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS)
|
||||
{
|
||||
int target = (freeFloatSlot > freeDoubleSlot) ? freeFloatSlot : freeDoubleSlot;
|
||||
|
||||
if ( descr->parameterTypes[n].GetSizeInMemoryDWords() <= ( (VFP_OFFSET + 16) - target) )
|
||||
{
|
||||
memcpy(¶mBuffer[target], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
|
||||
memset(¶mBuffer[target + 18], (asDWORD)1, descr->parameterTypes[n].GetSizeInMemoryDWords());
|
||||
target += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
freeFloatSlot = freeDoubleSlot = target;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(¶mBuffer[stackPos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
|
||||
stackPos += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
stackSize += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
|
||||
dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
}
|
||||
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+spos));
|
||||
spos++;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if( descr->parameterTypes[n].IsFloatType() && !descr->parameterTypes[n].IsReference() )
|
||||
{
|
||||
// Are there any "s" registers available?
|
||||
if ( freeFloatSlot < (VFP_OFFSET + 16) )
|
||||
{
|
||||
if (freeFloatSlot == freeDoubleSlot)
|
||||
freeDoubleSlot += 2;
|
||||
|
||||
paramBuffer[freeFloatSlot + 18] = (asDWORD)1;
|
||||
paramBuffer[freeFloatSlot++] = args[spos++];
|
||||
|
||||
while(freeFloatSlot < (VFP_OFFSET + 16) && paramBuffer[freeFloatSlot + 18] != 0)
|
||||
freeFloatSlot++;
|
||||
}
|
||||
// If not, then store the float arg in the stack area
|
||||
else
|
||||
{
|
||||
paramBuffer[stackPos++] = args[spos++];
|
||||
stackSize++;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if( descr->parameterTypes[n].IsDoubleType() && !descr->parameterTypes[n].IsReference() )
|
||||
{
|
||||
// Are there any "d" registers available?
|
||||
if ( freeDoubleSlot < (VFP_OFFSET + 15) )
|
||||
{
|
||||
if (freeFloatSlot == freeDoubleSlot)
|
||||
freeFloatSlot += 2;
|
||||
|
||||
// Copy two dwords for the double
|
||||
paramBuffer[freeDoubleSlot + 18] = (asDWORD)1;
|
||||
paramBuffer[freeDoubleSlot + 19] = (asDWORD)1;
|
||||
paramBuffer[freeDoubleSlot++] = args[spos++];
|
||||
paramBuffer[freeDoubleSlot++] = args[spos++];
|
||||
|
||||
while(freeDoubleSlot < (VFP_OFFSET + 15) && paramBuffer[freeDoubleSlot + 18] != 0)
|
||||
freeDoubleSlot += 2;
|
||||
}
|
||||
// If not, then store the double arg in the stack area
|
||||
else
|
||||
{
|
||||
if ( (stackPos & 1) == mask )
|
||||
{
|
||||
// 64 bit value align
|
||||
stackPos++;
|
||||
stackSize++;
|
||||
}
|
||||
|
||||
paramBuffer[stackPos++] = args[spos++];
|
||||
paramBuffer[stackPos++] = args[spos++];
|
||||
stackSize += 2;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the value directly to "r" registers or the stack, checking for alignment
|
||||
if (paramSize < 4)
|
||||
{
|
||||
// Should an alignment be performed?
|
||||
if( (dpos & 1) == mask && descr->parameterTypes[n].GetSizeOnStackDWords() == 2 &&
|
||||
!descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() &&
|
||||
!descr->parameterTypes[n].IsAnyType() )
|
||||
{
|
||||
// 64 bit value align
|
||||
dpos++;
|
||||
paramSize++;
|
||||
}
|
||||
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Should an alignment be performed?
|
||||
if( (stackPos & 1) == mask && descr->parameterTypes[n].GetSizeOnStackDWords() == 2 &&
|
||||
!descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() &&
|
||||
!descr->parameterTypes[n].IsAnyType() )
|
||||
{
|
||||
// 64 bit value align
|
||||
stackPos++;
|
||||
stackSize++;
|
||||
}
|
||||
|
||||
paramBuffer[stackPos++] = args[spos++];
|
||||
stackSize += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
|
||||
if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
|
||||
{
|
||||
if (paramSize < 5)
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
else
|
||||
paramBuffer[stackPos++] = args[spos++];
|
||||
}
|
||||
}// 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];
|
||||
}
|
||||
|
||||
paramBuffer[69] = static_cast<asDWORD>(stackSize<<2);
|
||||
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_CDECL_RETURNINMEM: // fall through
|
||||
case ICC_STDCALL_RETURNINMEM:
|
||||
retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)retPointer);
|
||||
break;
|
||||
case ICC_CDECL: // fall through
|
||||
case ICC_STDCALL:
|
||||
retQW = armFunc(args, paramSize<<2, func);
|
||||
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;
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
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
|
||||
retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)retPointer, (asDWORD)obj);
|
||||
break;
|
||||
case ICC_CDECL_OBJLAST:
|
||||
retQW = armFuncObjLast(args, paramSize<<2, func, (asDWORD)obj);
|
||||
break;
|
||||
case ICC_CDECL_OBJLAST_RETURNINMEM:
|
||||
retQW = armFuncR0ObjLast(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
|
||||
break;
|
||||
default:
|
||||
context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
|
||||
}
|
||||
|
||||
// On Linux with arm the float and double values are returns in the
|
||||
// floating point registers, s0 and s1. Objects that contain only
|
||||
// float types and are not considered complex are also returned in the
|
||||
// floating point registers.
|
||||
if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
retQW = paramBuffer[VFP_OFFSET];
|
||||
|
||||
if ( sysFunc->hostReturnSize > 1 )
|
||||
retQW = *( (asQWORD*)¶mBuffer[VFP_OFFSET] );
|
||||
}
|
||||
else if ( descr->returnType.IsObject() )
|
||||
{
|
||||
// TODO: runtime optimize: This should be identified with a flag determined in PrepareSystemFunction
|
||||
if ( !descr->returnType.IsObjectHandle() &&
|
||||
!descr->returnType.IsReference() &&
|
||||
!(descr->returnType.GetTypeInfo()->flags & COMPLEX_RETURN_MASK) &&
|
||||
(descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) )
|
||||
memcpy( retPointer, ¶mBuffer[VFP_OFFSET], descr->returnType.GetSizeInMemoryBytes() );
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_LINUX
|
||||
|
||||
#endif // AS_ARM
|
||||
#endif // AS_MAX_PORTABILITY
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2020-2021 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_callfunc_arm64.cpp
|
||||
//
|
||||
// These functions handle the actual calling of system functions on the arm64 platform
|
||||
//
|
||||
// Written by Max Waine in July 2020, based on as_callfunc_arm.cpp
|
||||
//
|
||||
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
#ifdef AS_ARM64
|
||||
|
||||
#include "as_callfunc.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_tokendef.h"
|
||||
#include "as_context.h"
|
||||
|
||||
// ARM64 targets use has no software floating-point ABI, it's all hardware (or totally disabled)
|
||||
|
||||
#define HFA_RET_REGISTERS 4 // s0-s3/d0-d3
|
||||
#define GP_ARG_REGISTERS 8 // x0-x7
|
||||
#define FLOAT_ARG_REGISTERS 8 // v0-v7
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// x0-7: Argument registers (pass params or return results. OK as volatile local variables)
|
||||
// x8: Indirect result register (e.g. address of large returned struct)
|
||||
// x9-15: Volatile local variable registers
|
||||
// x16-17: Intra-procedure-call temporary registers
|
||||
// x18: Platform register (reserved for use of platform ABIs)
|
||||
// x19-29: Non-volatile variable registers (must be saved and restored if modified)
|
||||
// x29: Frame pointer register
|
||||
// x30: Link register (where to return to)
|
||||
|
||||
extern "C" void GetHFAReturnDouble(asQWORD *out1, asQWORD *out2, asQWORD returnSize);
|
||||
extern "C" void GetHFAReturnFloat(asQWORD *out1, asQWORD *out2, asQWORD returnSize);
|
||||
|
||||
extern "C" asQWORD CallARM64RetInMemory(
|
||||
const asQWORD *gpRegArgs, asQWORD numGPRegArgs,
|
||||
const asQWORD *floatRegArgs, asQWORD numFloatRegArgs,
|
||||
const asQWORD *stackArgs, asQWORD numStackArgs,
|
||||
void *retPointer, asFUNCTION_t func
|
||||
);
|
||||
extern "C" double CallARM64Double(
|
||||
const asQWORD *gpRegArgs, asQWORD numGPRegArgs,
|
||||
const asQWORD *floatRegArgs, asQWORD numFloatRegArgs,
|
||||
const asQWORD *stackArgs, asQWORD numStackArgs,
|
||||
asFUNCTION_t func
|
||||
);
|
||||
extern "C" float CallARM64Float(
|
||||
const asQWORD *gpRegArgs, asQWORD numGPRegArgs,
|
||||
const asQWORD *floatRegArgs, asQWORD numFloatRegArgs,
|
||||
const asQWORD *stackArgs, asQWORD numStackArgs,
|
||||
asFUNCTION_t func
|
||||
);
|
||||
extern "C" asQWORD CallARM64(
|
||||
const asQWORD *gpRegArgs, asQWORD numGPRegArgs,
|
||||
const asQWORD *floatRegArgs, asQWORD numFloatRegArgs,
|
||||
const asQWORD *stackArgs, asQWORD numStackArgs,
|
||||
asFUNCTION_t func
|
||||
);
|
||||
extern "C" asQWORD CallARM64Ret128(
|
||||
const asQWORD *gpRegArgs, asQWORD numGPRegArgs,
|
||||
const asQWORD *floatRegArgs, asQWORD numFloatRegArgs,
|
||||
const asQWORD *stackArgs, asQWORD numStackArgs,
|
||||
asQWORD *higherQWORD, asFUNCTION_t func
|
||||
);
|
||||
|
||||
//
|
||||
// If it's possible to fit in registers,
|
||||
// there may not be enough float register space even if true is returned
|
||||
//
|
||||
static inline bool IsRegisterHFA(const asCDataType &type)
|
||||
{
|
||||
const asCTypeInfo *const typeInfo = type.GetTypeInfo();
|
||||
|
||||
if( typeInfo == nullptr ||
|
||||
(typeInfo->flags & asOBJ_APP_CLASS_ALLFLOATS) == 0 ||
|
||||
type.IsObjectHandle() || type.IsReference() )
|
||||
return false;
|
||||
|
||||
const bool doubles = (typeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0;
|
||||
const int maxAllowedSize = doubles ? sizeof(double) * HFA_RET_REGISTERS : sizeof(float) * HFA_RET_REGISTERS;
|
||||
|
||||
return type.GetSizeInMemoryBytes() <= maxAllowedSize;
|
||||
}
|
||||
|
||||
//
|
||||
// If it's possible to fit it in registers,
|
||||
// if true is returned there is enough space to fit
|
||||
//
|
||||
static inline bool IsRegisterHFAParameter(const asCDataType &type, const asQWORD numFloatRegArgs)
|
||||
{
|
||||
if( !IsRegisterHFA(type) )
|
||||
return false;
|
||||
|
||||
const bool doubles = (type.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) != 0;
|
||||
const int registersUsed = type.GetSizeInMemoryDWords() / (doubles ? sizeof(double) : sizeof(float));
|
||||
|
||||
return numFloatRegArgs + registersUsed <= FLOAT_ARG_REGISTERS;
|
||||
}
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2, void *secondObject)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
const asSSystemFunctionInterface *const sysFunc = descr->sysFuncIntf;
|
||||
const asCDataType &retType = descr->returnType;
|
||||
const asCTypeInfo *const retTypeInfo = retType.GetTypeInfo();
|
||||
asFUNCTION_t func = sysFunc->func;
|
||||
int callConv = sysFunc->callConv;
|
||||
asQWORD retQW = 0;
|
||||
|
||||
asQWORD gpRegArgs[GP_ARG_REGISTERS];
|
||||
asQWORD floatRegArgs[FLOAT_ARG_REGISTERS];
|
||||
asQWORD stackArgs[64]; // It's how many x64 users can have
|
||||
asQWORD numGPRegArgs = 0;
|
||||
asQWORD numFloatRegArgs = 0;
|
||||
asQWORD numStackArgs = 0;
|
||||
|
||||
asFUNCTION_t *vftable;
|
||||
|
||||
// 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
|
||||
gpRegArgs[numGPRegArgs++] = (asQWORD)obj;
|
||||
}
|
||||
|
||||
if( callConv == ICC_CDECL_OBJFIRST || callConv == ICC_CDECL_OBJFIRST_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the first parameter
|
||||
gpRegArgs[numGPRegArgs++] = (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
|
||||
gpRegArgs[numGPRegArgs++] = (asQWORD)secondObject;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(asFUNCTION_t**)obj;
|
||||
func = vftable[FuncPtrToUInt(func)/sizeof(void*)];
|
||||
}
|
||||
|
||||
asUINT argsPos = 0;
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
const asCDataType &parmType = descr->parameterTypes[n];
|
||||
const asCTypeInfo *const parmTypeInfo = parmType.GetTypeInfo();
|
||||
|
||||
if( parmType.IsObject() && !parmType.IsObjectHandle() && !parmType.IsReference() )
|
||||
{
|
||||
const asUINT parmDWords = parmType.GetSizeInMemoryDWords();
|
||||
const asUINT parmQWords = (parmDWords >> 1) + (parmDWords & 1);
|
||||
|
||||
const bool passedAsPointer = parmQWords <= 2;
|
||||
const bool fitsInRegisters = passedAsPointer ? (numGPRegArgs < GP_ARG_REGISTERS) : (numGPRegArgs + parmQWords <= GP_ARG_REGISTERS);
|
||||
asQWORD *const argsArray = fitsInRegisters ? gpRegArgs : stackArgs;
|
||||
asQWORD &numArgs = fitsInRegisters ? numGPRegArgs : numStackArgs;
|
||||
|
||||
if( (parmTypeInfo->flags & COMPLEX_MASK) )
|
||||
{
|
||||
argsArray[numArgs++] = *(asQWORD*)&args[argsPos];
|
||||
argsPos += AS_PTR_SIZE;
|
||||
}
|
||||
else if( IsRegisterHFAParameter(parmType, numFloatRegArgs) )
|
||||
{
|
||||
if( (parmTypeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0 )
|
||||
{
|
||||
const asQWORD *const contents = *(asQWORD**)&args[argsPos];
|
||||
for( asUINT i = 0; i < parmQWords; i++ )
|
||||
floatRegArgs[numFloatRegArgs++] = *(asQWORD*)&contents[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
const asDWORD *const contents = *(asDWORD**)&args[argsPos];
|
||||
for( asUINT i = 0; i < parmDWords; i++ )
|
||||
floatRegArgs[numFloatRegArgs++] = *(asQWORD*)&contents[i];
|
||||
}
|
||||
engine->CallFree(*(char**)(args+argsPos));
|
||||
argsPos += AS_PTR_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy(&argsArray[numArgs], *(void**)(args+argsPos), parmType.GetSizeInMemoryBytes());
|
||||
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+argsPos));
|
||||
argsPos += AS_PTR_SIZE;
|
||||
numArgs += parmQWords;
|
||||
}
|
||||
}
|
||||
else if( parmType.IsFloatType() && !parmType.IsReference() )
|
||||
{
|
||||
if( numFloatRegArgs >= FLOAT_ARG_REGISTERS )
|
||||
stackArgs[numStackArgs++] = args[argsPos];
|
||||
else
|
||||
floatRegArgs[numFloatRegArgs++] = args[argsPos];
|
||||
argsPos++;
|
||||
}
|
||||
else if( parmType.IsDoubleType() && !parmType.IsReference() )
|
||||
{
|
||||
if( numFloatRegArgs >= FLOAT_ARG_REGISTERS )
|
||||
stackArgs[numStackArgs++] = *(asQWORD*)&args[argsPos];
|
||||
else
|
||||
floatRegArgs[numFloatRegArgs++] = *(asQWORD*)&args[argsPos];
|
||||
argsPos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the value directly
|
||||
const asUINT parmDWords = parmType.GetSizeOnStackDWords();
|
||||
const asUINT parmQWords = (parmDWords >> 1) + (parmDWords & 1);
|
||||
|
||||
const bool fitsInRegisters = numGPRegArgs + parmQWords <= GP_ARG_REGISTERS;
|
||||
asQWORD *const argsArray = fitsInRegisters ? gpRegArgs : stackArgs;
|
||||
asQWORD &numArgs = fitsInRegisters ? numGPRegArgs : numStackArgs;
|
||||
|
||||
memcpy(&argsArray[numArgs], (void*)(args+argsPos), parmDWords * 4);
|
||||
argsPos += parmDWords;
|
||||
numArgs += parmQWords;
|
||||
}
|
||||
}
|
||||
|
||||
if( callConv == ICC_CDECL_OBJLAST || callConv == ICC_CDECL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the last parameter
|
||||
if( numGPRegArgs < GP_ARG_REGISTERS )
|
||||
gpRegArgs[numGPRegArgs++] = (asQWORD)obj;
|
||||
else
|
||||
stackArgs[numStackArgs++] = (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
|
||||
if( numGPRegArgs < GP_ARG_REGISTERS )
|
||||
gpRegArgs[numGPRegArgs++] = (asQWORD)secondObject;
|
||||
else
|
||||
stackArgs[numStackArgs++] = (asQWORD)secondObject;
|
||||
}
|
||||
|
||||
if( IsRegisterHFA(retType) && !(retTypeInfo->flags & COMPLEX_MASK) )
|
||||
{
|
||||
// This is to deal with HFAs (Homogeneous Floating-point Aggregates):
|
||||
// ARM64 will place all-float composite types (of equal precision)
|
||||
// with <= 4 members in the float return registers
|
||||
|
||||
const int structSize = retType.GetSizeInMemoryBytes();
|
||||
|
||||
CallARM64(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func);
|
||||
if( (retTypeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0 )
|
||||
{
|
||||
if( structSize <= sizeof(double) * 2 )
|
||||
GetHFAReturnDouble(&retQW, &retQW2, structSize);
|
||||
else
|
||||
GetHFAReturnDouble((asQWORD*)retPointer, ((asQWORD*)retPointer) + 1, structSize);
|
||||
}
|
||||
else
|
||||
GetHFAReturnFloat(&retQW, &retQW2, structSize);
|
||||
}
|
||||
else if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
*(float*)&retQW = CallARM64Float(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func);
|
||||
else
|
||||
*(double*)&retQW = CallARM64Double(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func);
|
||||
}
|
||||
else if( sysFunc->hostReturnInMemory )
|
||||
retQW = CallARM64RetInMemory(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, retPointer, func);
|
||||
else
|
||||
{
|
||||
if( retType.GetSizeInMemoryBytes() > sizeof(asQWORD) )
|
||||
retQW = CallARM64Ret128(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, &retQW2, func);
|
||||
else
|
||||
retQW = CallARM64(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func);
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_ARM64
|
||||
#endif // AS_MAX_PORTABILITY
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
//
|
||||
// AngelCode Scripting Library
|
||||
// Copyright (c) 2020-2021 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 ARM64/AArch64 call convention used for Linux
|
||||
// Written by Max Waine in July 2020, based on as_callfunc_arm_msvc.asm,
|
||||
// with assistance & guidance provided by Sir Kane
|
||||
|
||||
// Compile with GCC/GAS
|
||||
|
||||
#if !defined(AS_MAX_PORTABILITY)
|
||||
|
||||
#if defined(__aarch64__)
|
||||
|
||||
.arch armv8-a
|
||||
.text
|
||||
|
||||
.global GetHFAReturnDouble
|
||||
.global GetHFAReturnFloat
|
||||
.global CallARM64Ret128
|
||||
.global CallARM64RetInMemory
|
||||
.global CallARM64Double
|
||||
.global CallARM64Float
|
||||
.global CallARM64
|
||||
|
||||
.type GetHFAReturnDouble, %function
|
||||
.type GetHFAReturnFloat, %function
|
||||
.type CallARM64Ret128, %function
|
||||
.type CallARM64RetInMemory, %function
|
||||
.type CallARM64Double, %function
|
||||
.type CallARM64Float, %function
|
||||
.type CallARM64, %function
|
||||
|
||||
.align 2
|
||||
GetHFAReturnDouble:
|
||||
adr x9, populateDoubles
|
||||
sub x9, x9, x1, lsr 1 // x9 -= returnSize >> 1; (/2 because double is 2x instruction size)
|
||||
br x9
|
||||
|
||||
str d3, [x0, #0x18]
|
||||
str d2, [x0, #0x10]
|
||||
str d1, [x1]
|
||||
str d0, [x0]
|
||||
populateDoubles:
|
||||
|
||||
ret
|
||||
|
||||
.align 2
|
||||
GetHFAReturnFloat:
|
||||
adr x9, populateFloats
|
||||
sub x9, x9, x2 // x9 -= returnSize; (already 4 bytes per return)
|
||||
br x9
|
||||
|
||||
str s3, [x1, #0x4]
|
||||
str s2, [x1]
|
||||
str s1, [x0, #0x4]
|
||||
str s0, [x0]
|
||||
populateFloats:
|
||||
|
||||
ret
|
||||
|
||||
|
||||
//[returnType] CallARM64[type](
|
||||
// const asQWORD *gpRegArgs, asQWORD numGPRegArgs,
|
||||
// const asQWORD *floatRegArgs, asQWORD numFloatRegArgs,
|
||||
// const asQWORD *stackArgs, asQWORD numStackArgs,
|
||||
// asFUNCTION_t func
|
||||
//)
|
||||
.align 2
|
||||
CallARM64Double:
|
||||
CallARM64Float:
|
||||
CallARM64:
|
||||
.cfi_startproc
|
||||
stp fp, lr, [sp,#-0x20]!
|
||||
str x20, [sp,#0x10]
|
||||
.cfi_def_cfa_offset 0x20
|
||||
.cfi_offset 20, 0x10
|
||||
.cfi_offset fp, -0x20
|
||||
.cfi_offset lr, -0x18
|
||||
mov fp, sp
|
||||
|
||||
mov x20, #0
|
||||
|
||||
cbz x5, stackArgsLoopEnd
|
||||
|
||||
// Align count to 2, then multiply by 8, resulting in a size aligned to 16
|
||||
add x20, x5, #1
|
||||
lsl x20, x20, #3
|
||||
and x20, x20, #-0x10
|
||||
// Multiply count by 8
|
||||
lsl x10, x5, #3
|
||||
sub sp, sp, x20
|
||||
stackArgsLoopStart:
|
||||
ldp x9,x11, [x4],#16
|
||||
stp x9,x11, [sp],#16
|
||||
subs x10, x10, #16
|
||||
bgt stackArgsLoopStart
|
||||
stackArgsLoopEnd:
|
||||
|
||||
// Calculate amount to jump forward, avoiding pointless instructions
|
||||
adr x9, populateFloatRegisterArgsEnd
|
||||
sub x9, x9, x3, lsl 2 // x9 -= numFloatRegArgs * 4
|
||||
br x9
|
||||
|
||||
ldr d7, [x2, #0x38]
|
||||
ldr d6, [x2, #0x30]
|
||||
ldr d5, [x2, #0x28]
|
||||
ldr d4, [x2, #0x20]
|
||||
ldr d3, [x2, #0x18]
|
||||
ldr d2, [x2, #0x10]
|
||||
ldr d1, [x2, #0x08]
|
||||
ldr d0, [x2]
|
||||
populateFloatRegisterArgsEnd:
|
||||
|
||||
mov x15, x6
|
||||
// Calculate amount to jump forward, avoiding pointless instructions
|
||||
adr x9, populateGPRegisterArgsEnd
|
||||
sub x9, x9, x1, lsl 2 // x9 -= numGPRegArgs * 4
|
||||
br x9
|
||||
|
||||
ldr x7, [x0, #0x38]
|
||||
ldr x6, [x0, #0x30]
|
||||
ldr x5, [x0, #0x28]
|
||||
ldr x4, [x0, #0x20]
|
||||
ldr x3, [x0, #0x18]
|
||||
ldr x2, [x0, #0x10]
|
||||
ldr x1, [x0, #0x08]
|
||||
ldr x0, [x0]
|
||||
populateGPRegisterArgsEnd:
|
||||
|
||||
// Actually call function
|
||||
sub sp, sp, x20
|
||||
blr x15
|
||||
add sp, sp, x20
|
||||
|
||||
ldr x20, [sp,#0x10]
|
||||
ldp fp, lr, [sp],#0x20
|
||||
|
||||
.cfi_restore lr
|
||||
.cfi_restore fp
|
||||
.cfi_restore 20
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
.align 2
|
||||
CallARM64Ret128:
|
||||
.cfi_startproc
|
||||
stp fp, lr, [sp,#-0x20]!
|
||||
str x20, [sp,#0x10]
|
||||
.cfi_def_cfa_offset 0x20
|
||||
.cfi_offset 20, 0x10
|
||||
.cfi_offset fp, -0x20
|
||||
.cfi_offset lr, -0x18
|
||||
mov fp, sp
|
||||
|
||||
mov x20, x6
|
||||
mov x6, x7
|
||||
mov x7, #0
|
||||
bl CallARM64
|
||||
|
||||
str x1, [x20]
|
||||
|
||||
ldr x20, [sp,#0x10]
|
||||
ldp fp, lr, [sp],#0x20
|
||||
|
||||
.cfi_restore lr
|
||||
.cfi_restore fp
|
||||
.cfi_restore 20
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
.align 2
|
||||
CallARM64RetInMemory:
|
||||
.cfi_startproc
|
||||
stp fp, lr, [sp,#-0x10]!
|
||||
mov fp, sp
|
||||
.cfi_def_cfa_offset 0x10
|
||||
.cfi_offset fp, -0x10
|
||||
.cfi_offset lr, -0x08
|
||||
|
||||
mov x8, x6
|
||||
mov x6, x7
|
||||
mov x7, #0
|
||||
bl CallARM64
|
||||
|
||||
mov x0, x8
|
||||
|
||||
ldp fp, lr, [sp],#0x10
|
||||
|
||||
.cfi_restore lr
|
||||
.cfi_restore fp
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
#endif /* __aarch64__ */
|
||||
|
||||
#endif /* !AS_MAX_PORTABILITY */
|
||||
@@ -0,0 +1,205 @@
|
||||
;
|
||||
; AngelCode Scripting Library
|
||||
; Copyright (c) 2020-2020 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 ARM64/AArch64 call convention used for Windows 10 on ARM
|
||||
; Written by Max Waine in July 2020, based on as_callfunc_arm_msvc.asm
|
||||
|
||||
; MSVC currently doesn't support inline assembly for the ARM64 platform,
|
||||
; and if they're treating it like x64 /won't/ ever support inline assembly,
|
||||
; so this separate file is needed.
|
||||
|
||||
; Compile with Microsoft ARM64 assembler (armasm64)
|
||||
; http://msdn.microsoft.com/en-us/library/hh873190.aspx
|
||||
|
||||
AREA |.rdata|, DATA, READONLY
|
||||
EXPORT GetHFAReturnDouble
|
||||
EXPORT GetHFAReturnFloat
|
||||
EXPORT CallARM64Ret128
|
||||
EXPORT CallARM64RetInMemory
|
||||
EXPORT CallARM64Double
|
||||
EXPORT CallARM64Float
|
||||
EXPORT CallARM64
|
||||
|
||||
AREA |.text|, CODE, ALIGN=2
|
||||
|
||||
ALIGN 4
|
||||
GetHFAReturnDouble PROC
|
||||
adr x9, |populateDoubles|
|
||||
sub x9, x9, x1, lsr 1 ; x9 -= returnSize >> 1; (/2 because double is 2x instruction size)
|
||||
br x9
|
||||
|
||||
str d3, [x0, #0x18]
|
||||
str d2, [x0, #0x10]
|
||||
str d1, [x1]
|
||||
str d0, [x0]
|
||||
|populateDoubles|
|
||||
|
||||
ret
|
||||
ENDP ; GetHFAReturnDouble
|
||||
|
||||
ALIGN 4
|
||||
GetHFAReturnFloat PROC
|
||||
adr x9, |populateFloats|
|
||||
sub x9, x9, x2 // x9 -= returnSize; (already 4 bytes per return)
|
||||
br x9
|
||||
|
||||
str s3, [x1, #0x4]
|
||||
str s2, [x1]
|
||||
str s1, [x0, #0x4]
|
||||
str s0, [x0]
|
||||
|populateFloats|
|
||||
|
||||
ret
|
||||
ENDP ; GetHFAReturnFloat
|
||||
|
||||
|
||||
;[returnType] CallARM64[type](
|
||||
; const asQWORD *gpRegArgs, asQWORD numGPRegArgs,
|
||||
; const asQWORD *floatRegArgs, asQWORD numFloatRegArgs,
|
||||
; const asQWORD *stackArgs, asQWORD numStackArgs,
|
||||
; asFUNCTION_t func
|
||||
;)
|
||||
ALIGN 4
|
||||
CallARM64Double PROC
|
||||
stp fp, lr, [sp,#-0x10]!
|
||||
bl CallARM64
|
||||
ldp fp, lr, [sp,#-0x10]!
|
||||
ret
|
||||
ENDP ; CallARM64Double
|
||||
|
||||
ALIGN 4
|
||||
CallARM64Float PROC
|
||||
stp fp, lr, [sp,#-0x10]!
|
||||
bl CallARM64
|
||||
ldp fp, lr, [sp,#-0x10]!
|
||||
ret
|
||||
ENDP ; CallARM64Float
|
||||
|
||||
ALIGN 4
|
||||
CallARM64 PROC
|
||||
stp fp, lr, [sp,#-0x20]!
|
||||
str x20, [sp,#0x10]
|
||||
|
||||
mov x20, #0;
|
||||
|
||||
cbz x5, |stackArgsLoopEnd|
|
||||
|
||||
; Align count to 2, then multiply by 8, resulting in a size aligned to 16
|
||||
add x20, x5, #1
|
||||
lsl x20, x20, #3
|
||||
and x20, x20, #-0x10
|
||||
; Multiply count by 8
|
||||
lsl x10, x5, #3
|
||||
sub sp, sp, x20
|
||||
|stackArgsLoopStart|
|
||||
ldp x9,x11, [x4],#16
|
||||
stp x9,x11, [sp],#16
|
||||
subs x10, x10, #16
|
||||
bgt |stackArgsLoopStart|
|
||||
|stackArgsLoopEnd|
|
||||
|
||||
; Calculate amount to jump forward, avoiding pointless instructions
|
||||
adr x9, |populateFloatRegisterArgsEnd|
|
||||
sub x9, x9, x3, lsl 2 ; x9 -= numFloatRegArgs * 4
|
||||
br x9
|
||||
|
||||
ldr d7, [x2, #0x38]
|
||||
ldr d6, [x2, #0x30]
|
||||
ldr d5, [x2, #0x28]
|
||||
ldr d4, [x2, #0x20]
|
||||
ldr d3, [x2, #0x18]
|
||||
ldr d2, [x2, #0x10]
|
||||
ldr d1, [x2, #0x08]
|
||||
ldr d0, [x2]
|
||||
|populateFloatRegisterArgsEnd|
|
||||
|
||||
mov x15, x6
|
||||
; Calculate amount to jump forward, avoiding pointless instructions
|
||||
adr x9, |populateGPRegisterArgsEnd|
|
||||
sub x9, x9, x1, lsl 2 ; x9 -= numGPRegArgs * 4
|
||||
br x9
|
||||
|
||||
ldr x7, [x0, #0x38]
|
||||
ldr x6, [x0, #0x30]
|
||||
ldr x5, [x0, #0x28]
|
||||
ldr x4, [x0, #0x20]
|
||||
ldr x3, [x0, #0x18]
|
||||
ldr x2, [x0, #0x10]
|
||||
ldr x1, [x0, #0x08]
|
||||
ldr x0, [x0]
|
||||
|populateGPRegisterArgsEnd|
|
||||
|
||||
; Actually call function
|
||||
sub sp, sp, x20
|
||||
blr x15
|
||||
add sp, sp, x20
|
||||
|
||||
ldr x20, [sp,#0x10]
|
||||
ldp fp, lr, [sp],#0x20
|
||||
|
||||
ret
|
||||
ENDP ; CallARM64
|
||||
|
||||
ALIGN 4
|
||||
CallARM64Ret128 PROC
|
||||
stp fp, lr, [sp,#-0x20]!
|
||||
str x20, [sp,#0x10]
|
||||
mov fp, sp
|
||||
|
||||
mov x20, x6
|
||||
mov x6, x7
|
||||
mov x7, #0
|
||||
bl CallARM64
|
||||
|
||||
str x1, [x20]
|
||||
|
||||
ldr x20, [sp,#0x10]
|
||||
ldp fp, lr, [sp],#0x20
|
||||
|
||||
ret ; CallARM64Ret128
|
||||
|
||||
ALIGN 4
|
||||
CallARM64RetInMemory PROC
|
||||
stp fp, lr, [sp,#-0x10]!
|
||||
mov fp, sp
|
||||
|
||||
mov x8, x6
|
||||
mov x6, x7
|
||||
mov x7, #0
|
||||
bl CallARM64
|
||||
|
||||
mov x0, x8
|
||||
|
||||
ldp fp, lr, [sp],#0x10
|
||||
|
||||
ret ; CallARM64RetInMemory
|
||||
|
||||
END
|
||||
@@ -0,0 +1,730 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2020 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 ARM call convention
|
||||
Written by Fredrik Ehnbom in June 2009
|
||||
|
||||
Adapted to GNUC by darktemplar216 in September 2009
|
||||
|
||||
Modified by Lasse Oorni for 8-byte stack alignment in May 2012
|
||||
|
||||
The assembler routines for Linux were written by Carlos Luna in December 2012
|
||||
*/
|
||||
|
||||
#if !defined(AS_MAX_PORTABILITY)
|
||||
|
||||
#if defined(__arm__) || defined(__ARM__) || defined(I3D_ARCH_ARM)
|
||||
|
||||
#if !defined(__linux__) || defined(__ANDROID__) || defined(ANDROID) || defined(__SOFTFP__) || defined(__ARM_PCS)
|
||||
|
||||
/* iOS, Android, Marmalade, and Linux with soft-float ABI goes here */
|
||||
|
||||
.global armFunc
|
||||
.global armFuncR0
|
||||
.global armFuncR0R1
|
||||
.global armFuncObjLast
|
||||
.global armFuncR0ObjLast
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFunc:
|
||||
stmdb sp!, {r4-r8, 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 r8, #0
|
||||
|
||||
beq nomoreargs
|
||||
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
ble nomoreargs
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #4*4 /* skip the 4 registers already loaded into r0-r3 */
|
||||
add r8, r7, #4 /* ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
sub sp, sp, r8
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargsloop:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargsloop
|
||||
mov sp, r12
|
||||
nomoreargs:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncObjLast:
|
||||
stmdb sp!, {r4-r8, 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 r8, #0
|
||||
|
||||
mov r0, r3 /* objlast. might get overwritten */
|
||||
mov r5, r3 /* objlast to temp reg */
|
||||
|
||||
beq nomoreargsarmFuncObjLast
|
||||
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
movlt r1, r5
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
movlt r2, r5
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
movlt r3, r5
|
||||
blt nomoreargsarmFuncObjLast
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #4*4 /* skip the 4 registers already loaded into r0-r3 */
|
||||
add r8, r7, #8 /* account for the objlast pointer, ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
str r5, [sp,#-4] /* store the objlast on stack, twice in case we adjusted alignment */
|
||||
str r5, [sp,#-8]
|
||||
sub sp, sp, r8 /* adjust frame */
|
||||
cmp r7, #0 /* we may also have come here with no extra params */
|
||||
beq nomoreargsarmFuncObjLast
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargslooparmFuncObjLast:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncObjLast
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncObjLast:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncR0ObjLast:
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
ldr r5, [sp,#6*4] /* 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 r8, #0
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
mov r1, r5 /* objlast. might get overwritten */
|
||||
|
||||
beq nomoreargsarmFuncR0ObjLast
|
||||
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
movlt r2, r5
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
movlt r3, r5
|
||||
blt nomoreargsarmFuncR0ObjLast
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #3*4 /* skip the 3 registers already loaded into r1-r3 */
|
||||
add r8, r7, #8 /* account for the objlast pointer, ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
str r5, [sp,#-4] /* store the objlast on stack, twice in case we adjusted alignment */
|
||||
str r5, [sp,#-8]
|
||||
sub sp, sp, r8 /* adjust frame */
|
||||
cmp r7, #0 /* we may also have come here with no extra params */
|
||||
beq nomoreargsarmFuncR0ObjLast
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargslooparmFuncR0ObjLast:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0ObjLast
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0ObjLast:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncR0:
|
||||
stmdb sp!, {r4-r8, 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 r8, #0
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
|
||||
beq nomoreargsarmFuncR0
|
||||
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
ble nomoreargsarmFuncR0
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #3*4 /* skip the 3 registers already loaded into r1-r3 */
|
||||
add r8, r7, #4 /* ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
sub sp, sp, r8
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargslooparmFuncR0:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncR0R1:
|
||||
stmdb sp!, {r4-r8, 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 r8, #0
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
ldr r1, [sp, #6*4] /* r1 explicitly set too */
|
||||
|
||||
beq nomoreargsarmFuncR0R1
|
||||
|
||||
/* Load the first 2 arguments into r2-r3 */
|
||||
cmp r7, #1*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r3, [r6],#4
|
||||
ble nomoreargsarmFuncR0R1
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #2*4 /* skip the 2 registers already loaded into r2-r3 */
|
||||
add r8, r7, #4 /* ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
sub sp, sp, r8
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargslooparmFuncR0R1:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0R1
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0R1:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
#elif defined(__linux__) && !defined(__SOFTFP__) && !defined(__ARM_PCS)
|
||||
|
||||
/* The Linux with hard-float ABI code goes here */
|
||||
|
||||
|
||||
/* These codes are suitable for armeabi + vfp / armeabihf */
|
||||
/* when using armeabi + vfp, please set C_FLAGS -mfloat-abi=softfp -mfpu=vfp */
|
||||
/* using armeabihf, please set C_FLAGS -mfloat-abi=hard -mfpu=vfpv3-d16 */
|
||||
|
||||
/* if you prefer to run in ARM mode, please add -marm to C_FLAGS */
|
||||
/* while using thumb mode, please add -mthumb -Wa,-mimplicit-it=thumb */
|
||||
|
||||
|
||||
/* SP is a multiple of 8 when control first enters a program.*/
|
||||
/* This places an obligation on authors of low level OS, RTOS, and runtime library code to align SP at all points */
|
||||
/* at which control first enters a body of (AAPCS-conforming) code. (please read "ARM IHI 0046B" document)*/
|
||||
|
||||
|
||||
.section .text
|
||||
|
||||
.align 2 /* Align the function code to a 4-byte (2^n) word boundary. */
|
||||
#if defined(__thumb__) || defined(__thumb2__)
|
||||
.thumb
|
||||
.syntax unified
|
||||
#else
|
||||
.arm /* Use ARM instructions instead of Thumb.*/
|
||||
#endif
|
||||
.globl armFunc /* Make the function globally accessible.*/
|
||||
armFunc:
|
||||
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
|
||||
ldrge r0, [r6]
|
||||
cmp r7, #8
|
||||
ldrge r1, [r6, #4]
|
||||
cmp r7, #12
|
||||
ldrge r2, [r6, #8]
|
||||
cmp r7, #16
|
||||
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:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
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}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
.align 2 /* Align the function code to a 4-byte (2^n) word boundary. */
|
||||
#if defined(__thumb__) || defined(__thumb2__)
|
||||
.thumb
|
||||
.syntax unified
|
||||
#else
|
||||
.arm /* Use ARM instructions instead of Thumb.*/
|
||||
#endif
|
||||
.globl armFuncObjLast /* Make the function globally accessible.*/
|
||||
armFuncObjLast:
|
||||
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
|
||||
ldrge r0, [r6]
|
||||
cmp r7, #8
|
||||
ldrge r1, [r6,#4]
|
||||
movlt r1, r5
|
||||
cmp r7, #12
|
||||
ldrge r2, [r6,#8]
|
||||
movlt r2, r5
|
||||
cmp r7, #16
|
||||
ldrge r3, [r6,#12]
|
||||
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:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
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}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------- */
|
||||
.align 2 /* Align the function code to a 4-byte (2^n) word boundary. */
|
||||
#if defined(__thumb__) || defined(__thumb2__)
|
||||
.thumb
|
||||
.syntax unified
|
||||
#else
|
||||
.arm /* Use ARM instructions instead of Thumb.*/
|
||||
#endif
|
||||
.globl armFuncR0ObjLast /* Make the function globally accessible.*/
|
||||
armFuncR0ObjLast:
|
||||
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
|
||||
ldrge r1, [r6]
|
||||
cmp r7, #8
|
||||
ldrge r2, [r6,#4]
|
||||
movlt r2, r5
|
||||
cmp r7, #12
|
||||
ldrge r3, [r6,#8]
|
||||
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 */
|
||||
ldrge r7, [r6, #12]
|
||||
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 */
|
||||
|
||||
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:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
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}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------- */
|
||||
.align 2 /* Align the function code to a 4-byte (2^n) word boundary. */
|
||||
#if defined(__thumb__) || defined(__thumb2__)
|
||||
.thumb
|
||||
.syntax unified
|
||||
#else
|
||||
.arm /* Use ARM instructions instead of Thumb.*/
|
||||
#endif
|
||||
.globl armFuncR0 /* Make the function globally accessible.*/
|
||||
armFuncR0:
|
||||
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
|
||||
ldrge r1, [r6]
|
||||
cmp r7, #8
|
||||
ldrge r2, [r6, #4]
|
||||
cmp r7, #12
|
||||
ldrge r3, [r6, #8]
|
||||
cmp r7, #16
|
||||
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:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
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}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------- */
|
||||
.align 2 /* Align the function code to a 4-byte (2^n) word boundary. */
|
||||
#if defined(__thumb__) || defined(__thumb2__)
|
||||
.thumb
|
||||
.syntax unified
|
||||
#else
|
||||
.arm /* Use ARM instructions instead of Thumb.*/
|
||||
#endif
|
||||
.globl armFuncR0R1 /* Make the function globally accessible.*/
|
||||
armFuncR0R1:
|
||||
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
|
||||
ldrge r2, [r6]
|
||||
cmp r7, #8
|
||||
ldrge r3, [r6, #4]
|
||||
cmp r7, #12
|
||||
movge r11, #4 /* If there is a third arg to be placed, set the offset in r11 to #4 */
|
||||
cmp r7, #16
|
||||
movge r11, #8 /* If there is a fourth arg to be placed, set the offset in r11 to #8 */
|
||||
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:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
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}
|
||||
|
||||
#endif /* hard float abi */
|
||||
|
||||
#endif /* arm */
|
||||
|
||||
#if defined(__linux__) && defined(__ELF__)
|
||||
/* ref: http://hardened.gentoo.org/gnu-stack.xml
|
||||
ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart */
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
|
||||
#endif /* !AS_MAX_PORTABILITY */
|
||||
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
;
|
||||
; AngelCode Scripting Library
|
||||
; 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
|
||||
; 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 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
|
||||
; so this separate file is needed.
|
||||
|
||||
; Compile with Microsoft ARM assembler (armasm)
|
||||
; http://msdn.microsoft.com/en-us/library/hh873190.aspx
|
||||
|
||||
|
||||
AREA |.rdata|, DATA, READONLY
|
||||
EXPORT armFunc
|
||||
EXPORT armFuncR0
|
||||
EXPORT armFuncR0R1
|
||||
EXPORT armFuncObjLast
|
||||
EXPORT armFuncR0ObjLast
|
||||
|
||||
AREA |.text|, CODE, ARM, ALIGN=3
|
||||
|
||||
ALIGN 8
|
||||
armFunc PROC
|
||||
stmdb sp!, {r4-r8, 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 r8, #0
|
||||
|
||||
beq |nomoreargs|
|
||||
|
||||
; Load the first 4 arguments into r0-r3
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
ble |nomoreargs|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #4*4 ; skip the 4 registers already loaded into r0-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop|
|
||||
|nomoreargs|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
ALIGN 8
|
||||
armFuncObjLast PROC
|
||||
stmdb sp!, {r4-r8, 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 r8, #0
|
||||
|
||||
mov r0, r3 ; objlast. might get overwritten
|
||||
str r3, [sp, #-4]! ; objlast again.
|
||||
|
||||
beq |nomoreargs@armFuncObjLast|
|
||||
|
||||
; Load the first 4 arguments into r0-r3
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
ldrlt r1, [sp]
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
ldrlt r2, [sp]
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
ldrlt r3, [sp]
|
||||
ble |nomoreargs@armFuncObjLast|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #4*4 ; skip the 4 registers already loaded into r0-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop@armFuncObjLast|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop@armFuncObjLast|
|
||||
|nomoreargs@armFuncObjLast|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
add sp, sp, #4
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
ALIGN 8
|
||||
armFuncR0ObjLast PROC
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
ldr r7, [sp,#6*4]
|
||||
str r7, [sp,#-4]!
|
||||
|
||||
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 r8, #0
|
||||
|
||||
mov r0, r3 ; r0 explicitly set
|
||||
ldr r1, [sp] ; objlast. might get overwritten
|
||||
|
||||
beq |nomoreargs@armFuncR0ObjLast|
|
||||
|
||||
; Load the first 3 arguments into r1-r3
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
ldrlt r2, [sp]
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
ldrlt r3, [sp]
|
||||
ble |nomoreargs@armFuncR0ObjLast|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #3*4 ; skip the 3 registers already loaded into r1-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop@armFuncR0ObjLast|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop@armFuncR0ObjLast|
|
||||
|nomoreargs@armFuncR0ObjLast|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
add sp, sp, #4
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
ALIGN 8
|
||||
armFuncR0 PROC
|
||||
stmdb sp!, {r4-r8, 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 r8, #0
|
||||
|
||||
mov r0, r3 ; r0 explicitly set
|
||||
|
||||
beq |nomoreargs@armFuncR0|
|
||||
|
||||
; Load the first 3 arguments into r1-r3
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
ble |nomoreargs@armFuncR0|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #3*4 ; skip the 3 registers already loaded into r1-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop@armFuncR0|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop@armFuncR0|
|
||||
|nomoreargs@armFuncR0|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
ALIGN 8
|
||||
armFuncR0R1 PROC
|
||||
stmdb sp!, {r4-r8, 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 r8, #0
|
||||
|
||||
mov r0, r3 ; r0 explicitly set
|
||||
ldr r1, [sp, #6*4] ; r1 explicitly set too
|
||||
|
||||
beq |nomoreargs@armFuncR0R1|
|
||||
|
||||
; Load the first 2 arguments into r2-r3
|
||||
cmp r7, #1*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r3, [r6],#4
|
||||
ble |nomoreargs@armFuncR0R1|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #2*4 ; skip the 2 registers already loaded into r2-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop@armFuncR0R1|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop@armFuncR0R1|
|
||||
|nomoreargs@armFuncR0R1|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
END
|
||||
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#if !defined(AS_MAX_PORTABILITY)
|
||||
|
||||
#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
|
||||
|
||||
#endif /* !AS_MAX_PORTABILITY */
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
// Assembly routines for the ARM call convention
|
||||
// Written by Fredrik Ehnbom in June 2009
|
||||
|
||||
// Adapted to GNUC by darktemplar216 in September 2009
|
||||
// Small fixed to work under XCode GCC by Gilad Novik in October 2009
|
||||
|
||||
#if !defined(AS_MAX_PORTABILITY)
|
||||
|
||||
#if defined(__arm__) || defined(__ARM__)
|
||||
|
||||
.align 2
|
||||
.globl _armFunc
|
||||
.globl _armFuncR0
|
||||
.globl _armFuncR0R1
|
||||
.globl _armFuncObjLast
|
||||
.globl _armFuncR0ObjLast
|
||||
|
||||
_armFunc:
|
||||
stmdb sp!, {r4-r8, 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 r8, #0
|
||||
|
||||
beq nomoreargs
|
||||
|
||||
// Load the first 4 arguments into r0-r3
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
ble nomoreargs
|
||||
|
||||
// Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #4*4 // skip the 4 registers already loaded into r0-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
stackargsloop:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargsloop
|
||||
nomoreargs:
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
_armFuncObjLast:
|
||||
stmdb sp!, {r4-r8, 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 r8, #0
|
||||
|
||||
mov r0, r3 // objlast. might get overwritten
|
||||
str r3, [sp, #-4]! // objlast again.
|
||||
|
||||
beq nomoreargsarmFuncObjLast
|
||||
|
||||
// Load the first 4 arguments into r0-r3
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
ldrlt r1, [sp]
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
ldrlt r2, [sp]
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
ldrlt r3, [sp]
|
||||
ble nomoreargsarmFuncObjLast
|
||||
|
||||
// Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #4*4 // skip the 4 registers already loaded into r0-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
stackargslooparmFuncObjLast:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncObjLast
|
||||
nomoreargsarmFuncObjLast:
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
add sp, sp, #4
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
_armFuncR0ObjLast:
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
ldr r7, [sp,#6*4]
|
||||
str r7, [sp,#-4]!
|
||||
|
||||
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 r8, #0
|
||||
|
||||
mov r0, r3 // r0 explicitly set
|
||||
ldr r1, [sp] // objlast. might get overwritten
|
||||
|
||||
beq nomoreargsarmFuncR0ObjLast
|
||||
|
||||
// Load the first 3 arguments into r1-r3
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
ldrlt r2, [sp]
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
ldrlt r3, [sp]
|
||||
ble nomoreargsarmFuncR0ObjLast
|
||||
|
||||
// Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #3*4 // skip the 3 registers already loaded into r1-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
stackargslooparmFuncR0ObjLast:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0ObjLast
|
||||
nomoreargsarmFuncR0ObjLast:
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
add sp, sp, #4
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
|
||||
_armFuncR0:
|
||||
stmdb sp!, {r4-r8, 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 r8, #0
|
||||
|
||||
mov r0, r3 // r0 explicitly set
|
||||
|
||||
beq nomoreargsarmFuncR0
|
||||
|
||||
// Load the first 3 arguments into r1-r3
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
ble nomoreargsarmFuncR0
|
||||
|
||||
// Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #3*4 // skip the 3 registers already loaded into r1-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
stackargslooparmFuncR0:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0
|
||||
nomoreargsarmFuncR0:
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
|
||||
_armFuncR0R1:
|
||||
stmdb sp!, {r4-r8, 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 r8, #0
|
||||
|
||||
mov r0, r3 // r0 explicitly set
|
||||
ldr r1, [sp, #6*4] // r1 explicitly set too
|
||||
|
||||
beq nomoreargsarmFuncR0R1
|
||||
|
||||
// Load the first 2 arguments into r2-r3
|
||||
cmp r7, #1*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r3, [r6],#4
|
||||
ble nomoreargsarmFuncR0R1
|
||||
|
||||
// Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #2*4 // skip the 2 registers already loaded into r2-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
stackargslooparmFuncR0R1:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0R1
|
||||
nomoreargsarmFuncR0R1:
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !AS_MAX_PORTABILITY */
|
||||
|
||||
@@ -0,0 +1,735 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_callfunc_mips.cpp
|
||||
//
|
||||
// These functions handle the actual calling of system functions
|
||||
//
|
||||
// This version is MIPS specific and was originally written
|
||||
// by Manu Evans in April, 2006 for Playstation Portable (PSP)
|
||||
//
|
||||
// Support for Linux with MIPS was added by Andreas Jonsson in April, 2015
|
||||
//
|
||||
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
#ifdef AS_MIPS
|
||||
|
||||
#include "as_callfunc.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_tokendef.h"
|
||||
#include "as_context.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if !defined(AS_ANDROID)
|
||||
#include <regdef.h>
|
||||
#endif
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
#if defined(__linux__) && defined(_ABIO32)
|
||||
|
||||
// The MIPS ABI used by Linux is implemented here
|
||||
// (Tested on CI20 MIPS Creator with Debian Linux)
|
||||
//
|
||||
// ref: SYSTEM V
|
||||
// APPLICATION BINARY INTERFACE
|
||||
// MIPS RISC Processor
|
||||
// http://math-atlas.sourceforge.net/devel/assembly/mipsabi32.pdf
|
||||
//
|
||||
// ref: MIPS Instruction Reference
|
||||
// http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html
|
||||
|
||||
union SFloatRegs
|
||||
{
|
||||
union { double d0; struct { float f0; asDWORD dummy0; };};
|
||||
union { double d1; struct { float f1; asDWORD dummy1; };};
|
||||
} ;
|
||||
|
||||
extern "C" asQWORD mipsFunc(asUINT argSize, asDWORD *argBuffer, void *func, SFloatRegs &floatRegs);
|
||||
asDWORD GetReturnedFloat();
|
||||
asQWORD GetReturnedDouble();
|
||||
|
||||
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;
|
||||
|
||||
asQWORD retQW = 0;
|
||||
|
||||
void *func = (void*)sysFunc->func;
|
||||
void **vftable;
|
||||
|
||||
asDWORD argBuffer[128]; // Ought to be big enough
|
||||
asASSERT( sysFunc->paramSize < 128 );
|
||||
|
||||
asDWORD argOffset = 0;
|
||||
|
||||
SFloatRegs floatRegs;
|
||||
asDWORD floatOffset = 0;
|
||||
|
||||
// If the application function returns the value in memory then
|
||||
// the first argument must be the pointer to that memory
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
{
|
||||
asASSERT( retPointer );
|
||||
argBuffer[argOffset++] = (asPWORD)retPointer;
|
||||
}
|
||||
|
||||
if( callConv == ICC_CDECL_OBJFIRST || callConv == ICC_CDECL_OBJFIRST_RETURNINMEM ||
|
||||
callConv == ICC_THISCALL || callConv == ICC_THISCALL_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL || callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ||
|
||||
callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ||
|
||||
callConv == ICC_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
||||
callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the first argument
|
||||
argBuffer[argOffset++] = (asPWORD)obj;
|
||||
}
|
||||
|
||||
if( callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM )
|
||||
{
|
||||
// Add the second object pointer
|
||||
argBuffer[argOffset++] = (asPWORD)secondObject;
|
||||
}
|
||||
|
||||
int spos = 0;
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
asCDataType ¶mType = descr->parameterTypes[n];
|
||||
if( paramType.IsObject() && !paramType.IsObjectHandle() && !paramType.IsReference() )
|
||||
{
|
||||
if( paramType.GetTypeInfo()->flags & COMPLEX_MASK )
|
||||
{
|
||||
// The object is passed by reference
|
||||
argBuffer[argOffset++] = args[spos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure 8byte alignment for classes that need it
|
||||
if( (paramType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) && (argOffset & 1) )
|
||||
argOffset++;
|
||||
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy(&argBuffer[argOffset], *(void**)(args+spos), paramType.GetSizeInMemoryBytes());
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+spos));
|
||||
spos++;
|
||||
argOffset += paramType.GetSizeInMemoryDWords();
|
||||
}
|
||||
}
|
||||
else if( paramType.GetTokenType() == ttQuestion )
|
||||
{
|
||||
// Copy both pointer and type id
|
||||
argBuffer[argOffset++] = args[spos++];
|
||||
argBuffer[argOffset++] = args[spos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The first 2 floats or doubles are loaded into the float registers.
|
||||
// Actually this is only done if they are the first arguments to the function,
|
||||
// but it doesn't cause any harm to load them into the registers even if they
|
||||
// won't be used so we don't need to check if they really are the first args.
|
||||
if( floatOffset == 0 )
|
||||
{
|
||||
if( paramType.GetTokenType() == ttFloat )
|
||||
floatRegs.f0 = *reinterpret_cast<float*>(&args[spos]);
|
||||
else if( paramType.GetTokenType() == ttDouble )
|
||||
floatRegs.d0 = *reinterpret_cast<double*>(&args[spos]);
|
||||
floatOffset++;
|
||||
}
|
||||
else if( floatOffset == 1 )
|
||||
{
|
||||
if( paramType.GetTokenType() == ttFloat )
|
||||
floatRegs.f1 = *reinterpret_cast<float*>(&args[spos]);
|
||||
else if( paramType.GetTokenType() == ttDouble )
|
||||
floatRegs.d1 = *reinterpret_cast<double*>(&args[spos]);
|
||||
floatOffset++;
|
||||
}
|
||||
|
||||
// Copy the value directly
|
||||
if( paramType.GetSizeOnStackDWords() > 1 )
|
||||
{
|
||||
// Make sure the argument is 8byte aligned
|
||||
if( argOffset & 1 )
|
||||
argOffset++;
|
||||
*reinterpret_cast<asQWORD*>(&argBuffer[argOffset]) = *reinterpret_cast<asQWORD*>(&args[spos]);
|
||||
argOffset += 2;
|
||||
spos += 2;
|
||||
}
|
||||
else
|
||||
argBuffer[argOffset++] = args[spos++];
|
||||
}
|
||||
}
|
||||
|
||||
if( callConv == ICC_CDECL_OBJLAST || callConv == ICC_CDECL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the last argument
|
||||
argBuffer[argOffset++] = (asPWORD)obj;
|
||||
}
|
||||
|
||||
if( callConv == ICC_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
||||
callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Add the second object pointer
|
||||
argBuffer[argOffset++] = (asPWORD)secondObject;
|
||||
}
|
||||
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_CDECL:
|
||||
case ICC_CDECL_RETURNINMEM:
|
||||
case ICC_STDCALL:
|
||||
case ICC_STDCALL_RETURNINMEM:
|
||||
case ICC_CDECL_OBJLAST:
|
||||
case ICC_CDECL_OBJLAST_RETURNINMEM:
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_THISCALL_OBJFIRST:
|
||||
case ICC_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_THISCALL_OBJLAST:
|
||||
case ICC_THISCALL_OBJLAST_RETURNINMEM:
|
||||
retQW = mipsFunc(argOffset*4, argBuffer, func, floatRegs);
|
||||
break;
|
||||
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(void***)obj;
|
||||
retQW = mipsFunc(argOffset*4, argBuffer, vftable[asPWORD(func)>>2], floatRegs);
|
||||
break;
|
||||
default:
|
||||
context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
|
||||
}
|
||||
|
||||
// If the return is a float value we need to get the value from the FP register
|
||||
if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
*(asDWORD*)&retQW = GetReturnedFloat();
|
||||
else
|
||||
retQW = GetReturnedDouble();
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
asDWORD GetReturnedFloat()
|
||||
{
|
||||
asDWORD f;
|
||||
|
||||
asm("swc1 $f0, %0\n" : "=m"(f));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
asQWORD GetReturnedDouble()
|
||||
{
|
||||
asQWORD d = 0;
|
||||
|
||||
asm("sdc1 $f0, %0\n" : "=m"(d));
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
// asQWORD mipsFunc(asUINT argSize, asDWORD *argBuffer, void *func, SFloatRegs &floatRegs);
|
||||
// $2,$3 $4 $5 $6 $7
|
||||
asm(
|
||||
" .text\n"
|
||||
//" .align 2\n"
|
||||
" .cfi_startproc\n"
|
||||
" .global mipsFunc\n"
|
||||
" .ent mipsFunc\n"
|
||||
"mipsFunc:\n"
|
||||
//" .frame $fp,64,$31 # vars= 0, regs= 0/0, args= 0, gp= 0\n"
|
||||
//" .mask 0x00000000,0\n"
|
||||
//" .fmask 0x00000000,0\n"
|
||||
" .set noreorder\n"
|
||||
" .set nomacro\n"
|
||||
|
||||
// align the stack frame to 8 bytes
|
||||
" addiu $12, $4, 7\n" // t4 ($12) = argSize ($4) + 7
|
||||
" li $13, -8\n" // t5 ($13) = 0xfffffffffffffff8
|
||||
" and $12, $12, $13\n" // t4 ($12) &= t5 ($13). t4 holds the size of the argument block
|
||||
// It is required that the caller reserves space for at least 16 bytes even if there are less than 4 arguments
|
||||
// and add 8 bytes for the return pointer and s0 ($16) backup
|
||||
" addiu $13, $12, 24\n" // t5 = t4 + 24. t5 ($13) holds the total size of the stack frame (including return pointer)
|
||||
// save the s0 register (so we can use it to remember where our return pointer is lives)
|
||||
" sw $16, -4($sp)\n" // store the s0 register (so we can use it to remember how big our stack frame is)
|
||||
" .cfi_offset 16, -4\n"
|
||||
// store the return pointer
|
||||
" sw $31, -8($sp)\n"
|
||||
" .cfi_offset 31, -8\n"
|
||||
// keep original stack pointer
|
||||
" move $16, $sp\n"
|
||||
" .cfi_def_cfa_register 16\n"
|
||||
// push the stack
|
||||
" subu $sp, $sp, $13\n"
|
||||
|
||||
// store the argument in temporary registers
|
||||
" addiu $25, $6, 0\n" // t9 ($25) holds the function pointer (must be t9 for position independent code)
|
||||
" addiu $3, $4, 0\n" // v1 ($3) holds the size of the argument buffer
|
||||
" move $15, $5\n" // t7 ($15) holds the pointer to the argBuffer
|
||||
" move $14, $7\n" // t6 ($14) holds the values for the float registers
|
||||
|
||||
// load integer registers
|
||||
" lw $4, 0($15)\n" // a0 ($4)
|
||||
" lw $5, 4($15)\n" // a1 ($5)
|
||||
" lw $6, 8($15)\n" // a2 ($6)
|
||||
" lw $7, 12($15)\n" // a3 ($7)
|
||||
|
||||
// load float registers
|
||||
" ldc1 $f12, 8($14)\n"
|
||||
" ldc1 $f14, 0($14)\n"
|
||||
|
||||
// skip stack parameters if there are 4 or less as they are moved into the registers
|
||||
" addi $14, $3, -16\n" // The first 4 args were already loaded into registers
|
||||
" blez $14, andCall\n"
|
||||
" nop\n"
|
||||
|
||||
// push stack parameters
|
||||
"pushArgs:\n"
|
||||
" addi $3, -4\n"
|
||||
// load from $15 + stack bytes ($3)
|
||||
" addu $14, $15, $3\n"
|
||||
" lw $14, 0($14)\n"
|
||||
// store to $sp + stack bytes ($3)
|
||||
" addu $13, $sp, $3\n"
|
||||
" sw $14, 0($13)\n"
|
||||
// if there are more, loop...
|
||||
" bne $3, $0, pushArgs\n"
|
||||
" nop\n"
|
||||
|
||||
// and call the function
|
||||
"andCall:\n"
|
||||
" jalr $25\n"
|
||||
" nop\n"
|
||||
|
||||
// restore original stack pointer
|
||||
" move $sp, $16\n"
|
||||
// restore the return pointer
|
||||
" lw $31, -8($sp)\n"
|
||||
// restore the original value of $16
|
||||
" lw $16, -4($sp)\n"
|
||||
// and return from the function
|
||||
" jr $31\n"
|
||||
" nop\n"
|
||||
|
||||
" .set macro\n"
|
||||
" .set reorder\n"
|
||||
" .end mipsFunc\n"
|
||||
" .cfi_endproc\n"
|
||||
" .size mipsFunc, .-mipsFunc\n"
|
||||
);
|
||||
|
||||
#else // !(defined(__linux__) && defined(_ABIO32))
|
||||
|
||||
// The MIPS ABI used by PSP and PS2 is implemented here
|
||||
|
||||
#define AS_MIPS_MAX_ARGS 32
|
||||
#define AS_NUM_REG_FLOATS 8
|
||||
#define AS_NUM_REG_INTS 8
|
||||
|
||||
// The array used to send values to the correct places.
|
||||
// first 0-8 regular values to load into the a0-a3, t0-t3 registers
|
||||
// then 0-8 float values to load into the f12-f19 registers
|
||||
// then (AS_MIPS_MAX_ARGS - 16) values to load onto the stack
|
||||
// the +1 is for when CallThis (object methods) is used
|
||||
// extra +1 when returning in memory
|
||||
extern "C" {
|
||||
// TODO: This array shouldn't be global. It should be a local array in CallSystemFunctionNative
|
||||
asDWORD mipsArgs[AS_MIPS_MAX_ARGS + 1 + 1];
|
||||
}
|
||||
|
||||
// Loads all data into the correct places and calls the function.
|
||||
// intArgSize is the size in bytes for how much data to put in int registers
|
||||
// floatArgSize is the size in bytes for how much data to put in float registers
|
||||
// stackArgSize is the size in bytes for how much data to put on the callstack
|
||||
extern "C" asQWORD mipsFunc(int intArgSize, int floatArgSize, int stackArgSize, asDWORD func);
|
||||
|
||||
// puts the arguments in the correct place in the mipsArgs-array. See comments above.
|
||||
// This could be done better.
|
||||
inline void splitArgs(const asDWORD *args, int argNum, int &numRegIntArgs, int &numRegFloatArgs, int &numRestArgs, int hostFlags)
|
||||
{
|
||||
int i;
|
||||
|
||||
int argBit = 1;
|
||||
for (i = 0; i < argNum; i++)
|
||||
{
|
||||
if (hostFlags & argBit)
|
||||
{
|
||||
if (numRegFloatArgs < AS_NUM_REG_FLOATS)
|
||||
{
|
||||
// put in float register
|
||||
mipsArgs[AS_NUM_REG_INTS + numRegFloatArgs] = args[i];
|
||||
numRegFloatArgs++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// put in stack
|
||||
mipsArgs[AS_NUM_REG_INTS + AS_NUM_REG_FLOATS + numRestArgs] = args[i];
|
||||
numRestArgs++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numRegIntArgs < AS_NUM_REG_INTS)
|
||||
{
|
||||
// put in int register
|
||||
mipsArgs[numRegIntArgs] = args[i];
|
||||
numRegIntArgs++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// put in stack
|
||||
mipsArgs[AS_NUM_REG_INTS + AS_NUM_REG_FLOATS + numRestArgs] = args[i];
|
||||
numRestArgs++;
|
||||
}
|
||||
}
|
||||
argBit <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
asQWORD CallCDeclFunction(const asDWORD *args, int argSize, asDWORD func, int flags)
|
||||
{
|
||||
int argNum = argSize >> 2;
|
||||
|
||||
int intArgs = 0;
|
||||
int floatArgs = 0;
|
||||
int restArgs = 0;
|
||||
|
||||
// put the arguments in the correct places in the mipsArgs array
|
||||
if(argNum > 0)
|
||||
splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags);
|
||||
|
||||
return mipsFunc(intArgs << 2, floatArgs << 2, restArgs << 2, func);
|
||||
}
|
||||
|
||||
// This function is identical to CallCDeclFunction, with the only difference that
|
||||
// the value in the first parameter is the object
|
||||
asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags)
|
||||
{
|
||||
int argNum = argSize >> 2;
|
||||
|
||||
int intArgs = 1;
|
||||
int floatArgs = 0;
|
||||
int restArgs = 0;
|
||||
|
||||
mipsArgs[0] = (asDWORD) obj;
|
||||
|
||||
// put the arguments in the correct places in the mipsArgs array
|
||||
if (argNum > 0)
|
||||
splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags);
|
||||
|
||||
return mipsFunc(intArgs << 2, floatArgs << 2, restArgs << 2, func);
|
||||
}
|
||||
|
||||
// This function is identical to CallCDeclFunction, with the only difference that
|
||||
// the value in the last parameter is the object
|
||||
asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags)
|
||||
{
|
||||
int argNum = argSize >> 2;
|
||||
|
||||
int intArgs = 0;
|
||||
int floatArgs = 0;
|
||||
int restArgs = 0;
|
||||
|
||||
// put the arguments in the correct places in the mipsArgs array
|
||||
if(argNum > 0)
|
||||
splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags);
|
||||
|
||||
if(intArgs < AS_NUM_REG_INTS)
|
||||
{
|
||||
mipsArgs[intArgs] = (asDWORD) obj;
|
||||
intArgs++;
|
||||
}
|
||||
else
|
||||
{
|
||||
mipsArgs[AS_NUM_REG_INTS + AS_NUM_REG_FLOATS + restArgs] = (asDWORD) obj;
|
||||
restArgs++;
|
||||
}
|
||||
|
||||
return mipsFunc(intArgs << 2, floatArgs << 2, restArgs << 2, func);
|
||||
}
|
||||
|
||||
asDWORD GetReturnedFloat()
|
||||
{
|
||||
asDWORD f;
|
||||
|
||||
asm("swc1 $f0, %0\n" : "=m"(f));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
asQWORD GetReturnedDouble()
|
||||
{
|
||||
asQWORD d = 0;
|
||||
|
||||
asm("sdc1 $f0, %0\n" : "=m"(d));
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
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;
|
||||
int paramSize = sysFunc->paramSize;
|
||||
asDWORD *vftable;
|
||||
|
||||
if( descr->returnType.IsObject() && !descr->returnType.IsReference() && !descr->returnType.IsObjectHandle() )
|
||||
{
|
||||
mipsArgs[AS_MIPS_MAX_ARGS+1] = (asDWORD) retPointer;
|
||||
}
|
||||
|
||||
asASSERT(descr->parameterTypes.GetLength() <= AS_MIPS_MAX_ARGS);
|
||||
|
||||
// mark all float arguments
|
||||
int argBit = 1;
|
||||
int hostFlags = 0;
|
||||
int intArgs = 0;
|
||||
for( size_t a = 0; a < descr->parameterTypes.GetLength(); a++ )
|
||||
{
|
||||
if (descr->parameterTypes[a].IsFloatType())
|
||||
hostFlags |= argBit;
|
||||
else
|
||||
intArgs++;
|
||||
argBit <<= 1;
|
||||
}
|
||||
|
||||
asDWORD paramBuffer[64];
|
||||
if( sysFunc->takesObjByVal )
|
||||
{
|
||||
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() )
|
||||
{
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
|
||||
{
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
paramSize++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+spos));
|
||||
spos++;
|
||||
dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the value directly
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
}
|
||||
// Keep a free location at the beginning
|
||||
args = ¶mBuffer[1];
|
||||
}
|
||||
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_CDECL:
|
||||
case ICC_CDECL_RETURNINMEM:
|
||||
case ICC_STDCALL:
|
||||
case ICC_STDCALL_RETURNINMEM:
|
||||
retQW = CallCDeclFunction(args, paramSize<<2, (asDWORD)func, hostFlags);
|
||||
break;
|
||||
case ICC_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags);
|
||||
break;
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(asDWORD**)obj;
|
||||
retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[asDWORD(func)>>2], hostFlags);
|
||||
break;
|
||||
case ICC_CDECL_OBJLAST:
|
||||
case ICC_CDECL_OBJLAST_RETURNINMEM:
|
||||
retQW = CallThisCallFunction_objLast(obj, args, paramSize<<2, (asDWORD)func, hostFlags);
|
||||
break;
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags);
|
||||
break;
|
||||
default:
|
||||
context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
|
||||
}
|
||||
|
||||
// If the return is a float value we need to get the value from the FP register
|
||||
if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
*(asDWORD*)&retQW = GetReturnedFloat();
|
||||
else
|
||||
retQW = GetReturnedDouble();
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
|
||||
asm(
|
||||
" .text\n"
|
||||
//" .align 2\n"
|
||||
" .global mipsFunc\n"
|
||||
" .ent mipsFunc\n"
|
||||
"mipsFunc:\n"
|
||||
//" .frame $fp,64,$31 # vars= 0, regs= 0/0, args= 0, gp= 0\n"
|
||||
//" .mask 0x00000000,0\n"
|
||||
//" .fmask 0x00000000,0\n"
|
||||
" .set noreorder\n"
|
||||
" .set nomacro\n"
|
||||
// align the stack frame to 8 bytes
|
||||
" addiu $12, $6, 7\n"
|
||||
" li $13, -8\n" // 0xfffffffffffffff8
|
||||
" and $12, $12, $13\n" // t4 holds the size of the argument block
|
||||
// and add 8 bytes for the return pointer and s0 backup
|
||||
" addiu $13, $12, 8\n" // t5 holds the total size of the stack frame (including return pointer)
|
||||
// save the s0 register (so we can use it to remember where our return pointer is lives)
|
||||
" sw $16, -4($sp)\n" // store the s0 register (so we can use it to remember how big our stack frame is)
|
||||
// push the stack
|
||||
" subu $sp, $sp, $13\n"
|
||||
// find the return address, place in s0
|
||||
" addu $16, $sp, $12\n"
|
||||
// store the return pointer
|
||||
" sw $31, 0($16)\n"
|
||||
|
||||
// backup our function params
|
||||
" addiu $2, $7, 0\n"
|
||||
" addiu $3, $6, 0\n"
|
||||
|
||||
// get global mipsArgs[] array pointer
|
||||
//" lui $15, %hi(mipsArgs)\n"
|
||||
//" addiu $15, $15, %lo(mipsArgs)\n"
|
||||
// we'll use the macro instead because SN Systems doesnt like %hi/%lo
|
||||
".set macro\n"
|
||||
" la $15, mipsArgs\n"
|
||||
".set nomacro\n"
|
||||
// load register params
|
||||
" lw $4, 0($15)\n"
|
||||
" lw $5, 4($15)\n"
|
||||
" lw $6, 8($15)\n"
|
||||
" lw $7, 12($15)\n"
|
||||
" lw $8, 16($15)\n"
|
||||
" lw $9, 20($15)\n"
|
||||
" lw $10, 24($15)\n"
|
||||
" lw $11, 28($15)\n"
|
||||
|
||||
// load float params
|
||||
" lwc1 $f12, 32($15)\n"
|
||||
" lwc1 $f13, 36($15)\n"
|
||||
" lwc1 $f14, 40($15)\n"
|
||||
" lwc1 $f15, 44($15)\n"
|
||||
" lwc1 $f16, 48($15)\n"
|
||||
" lwc1 $f17, 52($15)\n"
|
||||
" lwc1 $f18, 56($15)\n"
|
||||
" lwc1 $f19, 60($15)\n"
|
||||
|
||||
// skip stack paramaters if there are none
|
||||
" beq $3, $0, andCall\n"
|
||||
|
||||
// push stack paramaters
|
||||
" addiu $15, $15, 64\n"
|
||||
"pushArgs:\n"
|
||||
" addiu $3, -4\n"
|
||||
// load from $15 + stack bytes ($3)
|
||||
" addu $14, $15, $3\n"
|
||||
" lw $14, 0($14)\n"
|
||||
// store to $sp + stack bytes ($3)
|
||||
" addu $13, $sp, $3\n"
|
||||
" sw $14, 0($13)\n"
|
||||
// if there are more, loop...
|
||||
" bne $3, $0, pushArgs\n"
|
||||
" nop\n"
|
||||
|
||||
// and call the function
|
||||
"andCall:\n"
|
||||
" jal $2\n"
|
||||
" nop\n"
|
||||
|
||||
// restore the return pointer
|
||||
" lw $31, 0($16)\n"
|
||||
// pop the stack pointer (remembering the return pointer was 8 bytes below the top)
|
||||
" addiu $sp, $16, 8\n"
|
||||
// and return from the function
|
||||
" jr $31\n"
|
||||
// restore the s0 register (in the branch delay slot)
|
||||
" lw $16, -4($sp)\n"
|
||||
" .set macro\n"
|
||||
" .set reorder\n"
|
||||
" .end mipsFunc\n"
|
||||
" .size mipsFunc, .-mipsFunc\n"
|
||||
);
|
||||
|
||||
#endif // PSP and PS2 MIPS ABI
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_MIPS
|
||||
#endif // AS_MAX_PORTABILITY
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,674 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_callfunc_ppc.cpp
|
||||
//
|
||||
// These functions handle the actual calling of system functions
|
||||
//
|
||||
// This version is PPC specific
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
#ifdef AS_PPC
|
||||
|
||||
#include "as_callfunc.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_tokendef.h"
|
||||
#include "as_context.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// This part was originally written by Pecan Heber, June 2006, for
|
||||
// use on MacOS X with 32bit PPC processor. He based the code on the
|
||||
// code in as_callfunc_sh4.cpp
|
||||
|
||||
#define AS_PPC_MAX_ARGS 32
|
||||
|
||||
// The array used to send values to the correct places.
|
||||
// Contains a byte of argTypes to indicate the register tYpe to load
|
||||
// or zero if end of arguments
|
||||
// The +1 is for when CallThis (object methods) is used
|
||||
// Extra +1 when returning in memory
|
||||
// Extra +1 in ppcArgsType to ensure zero end-of-args marker
|
||||
|
||||
// TODO: multithread: We need to remove these global variables for thread-safety
|
||||
|
||||
enum argTypes { ppcENDARG, ppcINTARG, ppcFLOATARG, ppcDOUBLEARG };
|
||||
static asDWORD ppcArgs[2*AS_PPC_MAX_ARGS + 1 + 1];
|
||||
|
||||
// Using extern "C" because we use this symbol name in the assembly code
|
||||
extern "C"
|
||||
{
|
||||
static asBYTE ppcArgsType[2*AS_PPC_MAX_ARGS + 1 + 1 + 1];
|
||||
}
|
||||
|
||||
// NOTE: these values are for PowerPC 32 bit.
|
||||
#define PPC_LINKAGE_SIZE (24) // how big the PPC linkage area is in a stack frame
|
||||
#define PPC_NUM_REGSTORE (9) // how many registers of the PPC we need to store/restore for ppcFunc()
|
||||
#define PPC_REGSTORE_SIZE (4*PPC_NUM_REGSTORE) // how many bytes are required for register store/restore
|
||||
#define EXTRA_STACK_SIZE (PPC_LINKAGE_SIZE + PPC_REGSTORE_SIZE) // memory required, not including parameters, for the stack frame
|
||||
#define PPC_STACK_SIZE(numParams) (-( ( ((((numParams)<8)?8:(numParams))<<2) + EXTRA_STACK_SIZE + 15 ) & ~15 )) // calculates the total stack size needed for ppcFunc64, must pad to 16bytes
|
||||
|
||||
// Loads all data into the correct places and calls the function.
|
||||
// ppcArgsType is an array containing a byte type (enum argTypes) for each argument.
|
||||
// stackArgSize is the size in bytes for how much data to put on the stack frame
|
||||
extern "C" asQWORD ppcFunc(const asDWORD* argsPtr, int StackArgSize, asDWORD func);
|
||||
|
||||
asm(" .text\n"
|
||||
" .align 2\n" // align the code to 1 << 2 = 4 bytes
|
||||
" .globl _ppcFunc\n"
|
||||
"_ppcFunc:\n"
|
||||
|
||||
// We're receiving the following parameters
|
||||
|
||||
// r3 : argsPtr
|
||||
// r4 : StackArgSize
|
||||
// r5 : func
|
||||
|
||||
// The following registers are used through out the function
|
||||
|
||||
// r31 : the address of the label address, as reference for all other labels
|
||||
// r30 : temporary variable
|
||||
// r29 : arg list pointer
|
||||
// r28 : number of FPR registers used by the parameters
|
||||
// r27 : the function pointer that will be called
|
||||
// r26 : the location of the parameters for the call
|
||||
// r25 : arg type list pointer
|
||||
// r24 : temporary variable
|
||||
// r23 : number of GPR registers used by the parameters
|
||||
// r1 : this is stack pointer
|
||||
// r0 : temporary variable
|
||||
// f0 : temporary variable
|
||||
|
||||
// We need to store some of the registers for restoral before returning to caller
|
||||
|
||||
// lr - always stored in 8(r1) - this is the return address
|
||||
// cr - not required to be stored, but if it is, its place is in 4(r1) - this is the condition register
|
||||
// r1 - always stored in 0(r1) - this is the stack pointer
|
||||
// r11
|
||||
// r13 to r31
|
||||
// f14 to f31
|
||||
|
||||
// Store register values and setup our stack frame
|
||||
" mflr r0 \n" // move the return address into r0
|
||||
" stw r0, 8(r1) \n" // Store the return address on the stack
|
||||
" stmw r23, -36(r1) \n" // Store registers r23 to r31 on the stack
|
||||
" stwux r1, r1, r4 \n" // Increase the stack with the needed space and store the original value in the destination
|
||||
|
||||
// Obtain an address that we'll use as our position of reference when obtaining addresses of other labels
|
||||
" bl address \n"
|
||||
"address: \n"
|
||||
" mflr r31 \n"
|
||||
|
||||
// initial registers for the function
|
||||
" mr r29, r3 \n" // (r29) args list
|
||||
" mr r27, r5 \n" // load the function pointer to call. func actually holds the pointer to our function
|
||||
" addi r26, r1, 24 \n" // setup the pointer to the parameter area to the function we're going to call
|
||||
" sub r0, r0, r0 \n" // zero out r0
|
||||
" mr r23, r0 \n" // zero out r23, which holds the number of used GPR registers
|
||||
" mr r28, r0 \n" // zero our r22, which holds the number of used float registers
|
||||
|
||||
// load the global ppcArgsType which holds the types of arguments for each argument
|
||||
" addis r25, r31, ha16(_ppcArgsType - address) \n" // load the upper 16 bits of the address to r25
|
||||
" la r25, lo16(_ppcArgsType - address)(r25) \n" // load the lower 16 bits of the address to r25
|
||||
" subi r25, r25, 1 \n" // since we increment r25 on its use, we'll pre-decrement it
|
||||
|
||||
// loop through the arguments
|
||||
"ppcNextArg: \n"
|
||||
" addi r25, r25, 1 \n" // increment r25, our arg type pointer
|
||||
// switch based on the current argument type (0:end, 1:int, 2:float 3:double)
|
||||
" lbz r24, 0(r25) \n" // load the current argument type (it's a byte)
|
||||
" mulli r24, r24, 4 \n" // our jump table has 4 bytes per case (1 instruction)
|
||||
" addis r30, r31, ha16(ppcTypeSwitch - address) \n" // load the address of the jump table for the switch
|
||||
" la r30, lo16(ppcTypeSwitch - address)(r30) \n"
|
||||
|
||||
" add r0, r30, r24 \n" // offset by our argument type
|
||||
" mtctr r0 \n" // load the jump address into CTR
|
||||
" bctr \n" // jump into the jump table/switch
|
||||
" nop \n"
|
||||
|
||||
// the jump table/switch based on the current argument type
|
||||
"ppcTypeSwitch: \n"
|
||||
" b ppcArgsEnd \n"
|
||||
" b ppcArgIsInteger \n"
|
||||
" b ppcArgIsFloat \n"
|
||||
" b ppcArgIsDouble \n"
|
||||
|
||||
// when we get here we have finished processing all the arguments
|
||||
// everything is ready to go to call the function
|
||||
"ppcArgsEnd: \n"
|
||||
" mtctr r27 \n" // the function pointer is stored in r27, load that into CTR
|
||||
" bctrl \n" // call the function. We have to do it this way so that the LR gets the proper
|
||||
" nop \n" // return value (the next instruction below). So we have to branch from CTR instead of LR.
|
||||
|
||||
// Restore registers and caller's stack frame, then return to caller
|
||||
" lwz r1, 0(r1) \n" // restore the caller's stack pointer
|
||||
" lwz r0, 8(r1) \n" // load in the caller's LR
|
||||
" mtlr r0 \n" // restore the caller's LR
|
||||
" lmw r23, -36(r1) \n" // restore registers r23 to r31 from the stack
|
||||
" blr \n" // return back to the caller
|
||||
" nop \n"
|
||||
|
||||
// Integer argument (GPR register)
|
||||
"ppcArgIsInteger: \n"
|
||||
" addis r30, r31, ha16(ppcLoadIntReg - address) \n" // load the address to the jump table for integer registers
|
||||
" la r30, lo16(ppcLoadIntReg - address)(r30) \n"
|
||||
" mulli r0, r23, 8 \n" // each item in the jump table is 2 instructions (8 bytes)
|
||||
" add r0, r0, r30 \n" // calculate ppcLoadIntReg[numUsedGPRRegs]
|
||||
" lwz r30, 0(r29) \n" // load the next argument from the argument list into r30
|
||||
" cmpwi r23, 8 \n" // we can only load GPR3 through GPR10 (8 registers)
|
||||
" bgt ppcLoadIntRegUpd \n" // if we're beyond 8 GPR registers, we're in the stack, go there
|
||||
" mtctr r0 \n" // load the address of our ppcLoadIntReg jump table (we're below 8 GPR registers)
|
||||
" bctr \n" // load the argument into a GPR register
|
||||
" nop \n"
|
||||
// jump table for GPR registers, for the first 8 GPR arguments
|
||||
"ppcLoadIntReg: \n"
|
||||
" mr r3, r30 \n" // arg0 (to r3)
|
||||
" b ppcLoadIntRegUpd \n"
|
||||
" mr r4, r30 \n" // arg1 (to r4)
|
||||
" b ppcLoadIntRegUpd \n"
|
||||
" mr r5, r30 \n" // arg2 (to r5)
|
||||
" b ppcLoadIntRegUpd \n"
|
||||
" mr r6, r30 \n" // arg3 (to r6)
|
||||
" b ppcLoadIntRegUpd \n"
|
||||
" mr r7, r30 \n" // arg4 (to r7)
|
||||
" b ppcLoadIntRegUpd \n"
|
||||
" mr r8, r30 \n" // arg5 (to r8)
|
||||
" b ppcLoadIntRegUpd \n"
|
||||
" mr r9, r30 \n" // arg6 (to r9)
|
||||
" b ppcLoadIntRegUpd \n"
|
||||
" mr r10, r30 \n" // arg7 (to r10)
|
||||
" b ppcLoadIntRegUpd \n"
|
||||
// all GPR arguments still go on the stack
|
||||
"ppcLoadIntRegUpd: \n"
|
||||
" stw r30, 0(r26) \n" // store the argument into the next slot on the stack's argument list
|
||||
" addi r23, r23, 1 \n" // count a used GPR register
|
||||
" addi r29, r29, 4 \n" // move to the next argument on the list
|
||||
" addi r26, r26, 4 \n" // adjust our argument stack pointer for the next
|
||||
" b ppcNextArg \n" // next argument
|
||||
|
||||
// single Float argument
|
||||
"ppcArgIsFloat:\n"
|
||||
" addis r30, r31, ha16(ppcLoadFloatReg - address) \n" // get the base address of the float register jump table
|
||||
" la r30, lo16(ppcLoadFloatReg - address)(r30) \n"
|
||||
" mulli r0, r28, 8 \n" // each jump table entry is 8 bytes
|
||||
" add r0, r0, r30 \n" // calculate the offset to ppcLoadFloatReg[numUsedFloatReg]
|
||||
" lfs f0, 0(r29) \n" // load the next argument as a float into f0
|
||||
" cmpwi r28, 13 \n" // can't load more than 13 float/double registers
|
||||
" bgt ppcLoadFloatRegUpd \n" // if we're beyond 13 registers, just fall to inserting into the stack
|
||||
" mtctr r0 \n" // jump into the float jump table
|
||||
" bctr \n"
|
||||
" nop \n"
|
||||
// jump table for float registers, for the first 13 float arguments
|
||||
"ppcLoadFloatReg: \n"
|
||||
" fmr f1, f0 \n" // arg0 (f1)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" fmr f2, f0 \n" // arg1 (f2)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" fmr f3, f0 \n" // arg2 (f3)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" fmr f4, f0 \n" // arg3 (f4)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" fmr f5, f0 \n" // arg4 (f5)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" fmr f6, f0 \n" // arg5 (f6)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" fmr f7, f0 \n" // arg6 (f7)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" fmr f8, f0 \n" // arg7 (f8)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" fmr f9, f0 \n" // arg8 (f9)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" fmr f10, f0 \n" // arg9 (f10)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" fmr f11, f0 \n" // arg10 (f11)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" fmr f12, f0 \n" // arg11 (f12)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" fmr f13, f0 \n" // arg12 (f13)
|
||||
" b ppcLoadFloatRegUpd \n"
|
||||
" nop \n"
|
||||
// all float arguments still go on the stack
|
||||
"ppcLoadFloatRegUpd: \n"
|
||||
" stfs f0, 0(r26) \n" // store, as a single float, f0 (current argument) on to the stack argument list
|
||||
" addi r23, r23, 1 \n" // a float register eats up a GPR register
|
||||
" addi r28, r28, 1 \n" // ...and, of course, a float register
|
||||
" addi r29, r29, 4 \n" // move to the next argument in the list
|
||||
" addi r26, r26, 4 \n" // move to the next stack slot
|
||||
" b ppcNextArg \n" // on to the next argument
|
||||
" nop \n"
|
||||
|
||||
// double Float argument
|
||||
"ppcArgIsDouble: \n"
|
||||
" addis r30, r31, ha16(ppcLoadDoubleReg - address) \n" // load the base address of the jump table for double registers
|
||||
" la r30, lo16(ppcLoadDoubleReg - address)(r30) \n"
|
||||
" mulli r0, r28, 8 \n" // each slot of the jump table is 8 bytes
|
||||
" add r0, r0, r30 \n" // calculate ppcLoadDoubleReg[numUsedFloatReg]
|
||||
" lfd f0, 0(r29) \n" // load the next argument, as a double float, into f0
|
||||
" cmpwi r28, 13 \n" // the first 13 floats must go into float registers also
|
||||
" bgt ppcLoadDoubleRegUpd \n" // if we're beyond 13, then just put on to the stack
|
||||
" mtctr r0 \n" // we're under 13, first load our register
|
||||
" bctr \n" // jump into the jump table
|
||||
" nop \n"
|
||||
// jump table for float registers, for the first 13 float arguments
|
||||
"ppcLoadDoubleReg: \n"
|
||||
" fmr f1, f0 \n" // arg0 (f1)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" fmr f2, f0 \n" // arg1 (f2)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" fmr f3, f0 \n" // arg2 (f3)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" fmr f4, f0 \n" // arg3 (f4)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" fmr f5, f0 \n" // arg4 (f5)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" fmr f6, f0 \n" // arg5 (f6)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" fmr f7, f0 \n" // arg6 (f7)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" fmr f8, f0 \n" // arg7 (f8)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" fmr f9, f0 \n" // arg8 (f9)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" fmr f10, f0 \n" // arg9 (f10)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" fmr f11, f0 \n" // arg10 (f11)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" fmr f12, f0 \n" // arg11 (f12)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" fmr f13, f0 \n" // arg12 (f13)
|
||||
" b ppcLoadDoubleRegUpd \n"
|
||||
" nop \n"
|
||||
// all float arguments still go on the stack
|
||||
"ppcLoadDoubleRegUpd: \n"
|
||||
" stfd f0, 0(r26) \n" // store f0, as a double, into the argument list on the stack
|
||||
" addi r23, r23, 2 \n" // a double float eats up two GPRs
|
||||
" addi r28, r28, 1 \n" // ...and, of course, a float
|
||||
" addi r29, r29, 8 \n" // increment to our next argument we need to process (8 bytes for the 64bit float)
|
||||
" addi r26, r26, 8 \n" // increment to the next slot on the argument list on the stack (8 bytes)
|
||||
" b ppcNextArg \n" // on to the next argument
|
||||
" nop \n"
|
||||
);
|
||||
|
||||
asDWORD GetReturnedFloat()
|
||||
{
|
||||
asDWORD f;
|
||||
asm(" stfs f1, %0\n" : "=m"(f));
|
||||
return f;
|
||||
}
|
||||
|
||||
asQWORD GetReturnedDouble()
|
||||
{
|
||||
asQWORD f;
|
||||
asm(" stfd f1, %0\n" : "=m"(f));
|
||||
return f;
|
||||
}
|
||||
|
||||
// puts the arguments in the correct place in the stack array. See comments above.
|
||||
void stackArgs(const asDWORD *args, const asBYTE *argsType, int& numIntArgs, int& numFloatArgs, int& numDoubleArgs)
|
||||
{
|
||||
int i;
|
||||
int argWordPos = numIntArgs + numFloatArgs + (numDoubleArgs*2);
|
||||
int typeOffset = numIntArgs + numFloatArgs + numDoubleArgs;
|
||||
|
||||
int typeIndex;
|
||||
for( i = 0, typeIndex = 0; ; i++, typeIndex++ )
|
||||
{
|
||||
// store the type
|
||||
ppcArgsType[typeOffset++] = argsType[typeIndex];
|
||||
if( argsType[typeIndex] == ppcENDARG )
|
||||
break;
|
||||
|
||||
switch( argsType[typeIndex] )
|
||||
{
|
||||
case ppcFLOATARG:
|
||||
// stow float
|
||||
ppcArgs[argWordPos] = args[i]; // it's just a bit copy
|
||||
numFloatArgs++;
|
||||
argWordPos++; //add one word
|
||||
break;
|
||||
|
||||
case ppcDOUBLEARG:
|
||||
// stow double
|
||||
memcpy( &ppcArgs[argWordPos], &args[i], sizeof(double) ); // we have to do this because of alignment
|
||||
numDoubleArgs++;
|
||||
argWordPos+=2; //add two words
|
||||
i++;//doubles take up 2 argument slots
|
||||
break;
|
||||
|
||||
case ppcINTARG:
|
||||
// stow register
|
||||
ppcArgs[argWordPos] = args[i];
|
||||
numIntArgs++;
|
||||
argWordPos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// close off the argument list (if we have max args we won't close it off until here)
|
||||
ppcArgsType[typeOffset] = ppcENDARG;
|
||||
}
|
||||
|
||||
static asQWORD CallCDeclFunction(const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory)
|
||||
{
|
||||
int baseArgCount = 0;
|
||||
if( retInMemory )
|
||||
{
|
||||
// the first argument is the 'return in memory' pointer
|
||||
ppcArgs[0] = (asDWORD)retInMemory;
|
||||
ppcArgsType[0] = ppcINTARG;
|
||||
ppcArgsType[1] = ppcENDARG;
|
||||
baseArgCount = 1;
|
||||
}
|
||||
|
||||
// put the arguments in the correct places in the ppcArgs array
|
||||
int numTotalArgs = baseArgCount;
|
||||
if( argSize > 0 )
|
||||
{
|
||||
int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0;
|
||||
stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs );
|
||||
numTotalArgs = intArgs + floatArgs + 2*doubleArgs; // doubles occupy two slots
|
||||
}
|
||||
else
|
||||
{
|
||||
// no arguments, cap the type list
|
||||
ppcArgsType[baseArgCount] = ppcENDARG;
|
||||
}
|
||||
|
||||
// call the function with the arguments
|
||||
return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func );
|
||||
}
|
||||
|
||||
// This function is identical to CallCDeclFunction, with the only difference that
|
||||
// the value in the first parameter is the object (unless we are returning in memory)
|
||||
static asQWORD CallThisCallFunction(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory )
|
||||
{
|
||||
int baseArgCount = 0;
|
||||
if( retInMemory )
|
||||
{
|
||||
// the first argument is the 'return in memory' pointer
|
||||
ppcArgs[0] = (asDWORD)retInMemory;
|
||||
ppcArgsType[0] = ppcINTARG;
|
||||
ppcArgsType[1] = ppcENDARG;
|
||||
baseArgCount = 1;
|
||||
}
|
||||
|
||||
// the first argument is the 'this' of the object
|
||||
ppcArgs[baseArgCount] = (asDWORD)obj;
|
||||
ppcArgsType[baseArgCount++] = ppcINTARG;
|
||||
ppcArgsType[baseArgCount] = ppcENDARG;
|
||||
|
||||
// put the arguments in the correct places in the ppcArgs array
|
||||
int numTotalArgs = baseArgCount;
|
||||
if( argSize > 0 )
|
||||
{
|
||||
int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0;
|
||||
stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs );
|
||||
numTotalArgs = intArgs + floatArgs + 2*doubleArgs; // doubles occupy two slots
|
||||
}
|
||||
|
||||
// call the function with the arguments
|
||||
return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func);
|
||||
}
|
||||
|
||||
// This function is identical to CallCDeclFunction, with the only difference that
|
||||
// the value in the last parameter is the object
|
||||
// NOTE: on PPC the order for the args is reversed
|
||||
static asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory)
|
||||
{
|
||||
UNUSED_VAR(argSize);
|
||||
int baseArgCount = 0;
|
||||
if( retInMemory )
|
||||
{
|
||||
// the first argument is the 'return in memory' pointer
|
||||
ppcArgs[0] = (asDWORD)retInMemory;
|
||||
ppcArgsType[0] = ppcINTARG;
|
||||
ppcArgsType[1] = ppcENDARG;
|
||||
baseArgCount = 1;
|
||||
}
|
||||
|
||||
// stack any of the arguments
|
||||
int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0;
|
||||
stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs );
|
||||
int numTotalArgs = intArgs + floatArgs + doubleArgs;
|
||||
|
||||
// can we fit the object in at the end?
|
||||
if( numTotalArgs < AS_PPC_MAX_ARGS )
|
||||
{
|
||||
// put the object pointer at the end
|
||||
int argPos = intArgs + floatArgs + (doubleArgs * 2);
|
||||
ppcArgs[argPos] = (asDWORD)obj;
|
||||
ppcArgsType[numTotalArgs++] = ppcINTARG;
|
||||
ppcArgsType[numTotalArgs] = ppcENDARG;
|
||||
}
|
||||
|
||||
// call the function with the arguments
|
||||
return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func );
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
|
||||
asQWORD retQW = 0;
|
||||
void *func = (void*)sysFunc->func;
|
||||
int paramSize = sysFunc->paramSize;
|
||||
asDWORD *vftable = NULL;
|
||||
int a, s;
|
||||
|
||||
// convert the parameters that are < 4 bytes from little endian to big endian
|
||||
int argDwordOffset = 0;
|
||||
for( a = 0; a < (int)descr->parameterTypes.GetLength(); a++ )
|
||||
{
|
||||
int numBytes = descr->parameterTypes[a].GetSizeInMemoryBytes();
|
||||
if( numBytes >= 4 || descr->parameterTypes[a].IsReference() || descr->parameterTypes[a].IsObjectHandle() )
|
||||
{
|
||||
argDwordOffset += descr->parameterTypes[a].GetSizeOnStackDWords();
|
||||
continue;
|
||||
}
|
||||
|
||||
// flip
|
||||
asASSERT( numBytes == 1 || numBytes == 2 );
|
||||
switch( numBytes )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
volatile asBYTE *bPtr = (asBYTE*)ARG_DW(args[argDwordOffset]);
|
||||
asBYTE t = bPtr[0];
|
||||
bPtr[0] = bPtr[3];
|
||||
bPtr[3] = t;
|
||||
t = bPtr[1];
|
||||
bPtr[1] = bPtr[2];
|
||||
bPtr[2] = t;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
volatile asWORD *wPtr = (asWORD*)ARG_DW(args[argDwordOffset]);
|
||||
asWORD t = wPtr[0];
|
||||
wPtr[0] = wPtr[1];
|
||||
wPtr[1] = t;
|
||||
}
|
||||
break;
|
||||
}
|
||||
argDwordOffset++;
|
||||
}
|
||||
|
||||
// mark all float/double/int arguments
|
||||
if( !sysFunc->takesObjByVal )
|
||||
{
|
||||
for( s = 0, a = 0; s < (int)descr->parameterTypes.GetLength(); s++, a++ )
|
||||
{
|
||||
if( descr->parameterTypes[s].IsFloatType() && !descr->parameterTypes[s].IsReference() )
|
||||
{
|
||||
argsType[a] = ppcFLOATARG;
|
||||
}
|
||||
else if( descr->parameterTypes[s].IsDoubleType() && !descr->parameterTypes[s].IsReference() )
|
||||
{
|
||||
argsType[a] = ppcDOUBLEARG;
|
||||
}
|
||||
else
|
||||
{
|
||||
argsType[a] = ppcINTARG;
|
||||
if( descr->parameterTypes[s].GetSizeOnStackDWords() == 2 )
|
||||
{
|
||||
// Add an extra integer argument for the extra size
|
||||
a++;
|
||||
argsType[a] = ppcINTARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
asDWORD paramBuffer[64];
|
||||
if( sysFunc->takesObjByVal )
|
||||
{
|
||||
paramSize = 0;
|
||||
int spos = 0;
|
||||
int dpos = 1;
|
||||
|
||||
int a = 0;
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
|
||||
{
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
|
||||
{
|
||||
argsType[a++] = ppcINTARG;
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
paramSize++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// TODO: Probably have to handle asOBJ_APP_FLOAT as a primitive
|
||||
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy( ¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes() );
|
||||
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+spos) );
|
||||
spos++;
|
||||
asUINT dwords = descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
dpos += dwords;
|
||||
paramSize += dwords;
|
||||
for( asUINT i = 0; i < dwords; i++ )
|
||||
argsType[a++] = ppcINTARG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the value directly
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
if( descr->parameterTypes[n].IsFloatType() && !descr->parameterTypes[n].IsReference() )
|
||||
argsType[a++] = ppcFLOATARG;
|
||||
else if( descr->parameterTypes[n].IsDoubleType() && !descr->parameterTypes[n].IsReference() )
|
||||
argsType[a++] = ppcDOUBLEARG;
|
||||
else
|
||||
argsType[a++] = ppcINTARG;
|
||||
if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
|
||||
{
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
if( !descr->parameterTypes[n].IsDoubleType() ) // Double already knows it is 2 dwords
|
||||
argsType[a++] = ppcINTARG;
|
||||
}
|
||||
paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
}
|
||||
|
||||
// Keep a free location at the beginning
|
||||
args = ¶mBuffer[1];
|
||||
}
|
||||
|
||||
int callConv = sysFunc->callConv;
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_CDECL:
|
||||
case ICC_CDECL_RETURNINMEM:
|
||||
case ICC_STDCALL:
|
||||
case ICC_STDCALL_RETURNINMEM:
|
||||
retQW = CallCDeclFunction( args, argsType, paramSize, (asDWORD)func, retPointer );
|
||||
break;
|
||||
case ICC_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
retQW = CallThisCallFunction(obj, args, argsType, paramSize, (asDWORD)func, retPointer );
|
||||
break;
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(asDWORD**)obj;
|
||||
retQW = CallThisCallFunction( obj, args, argsType, paramSize, vftable[asDWORD(func)>>2], retPointer );
|
||||
break;
|
||||
case ICC_CDECL_OBJLAST:
|
||||
case ICC_CDECL_OBJLAST_RETURNINMEM:
|
||||
retQW = CallThisCallFunction_objLast( obj, args, argsType, paramSize, (asDWORD)func, retPointer );
|
||||
break;
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
retQW = CallThisCallFunction( obj, args, argsType, paramSize, (asDWORD)func, retPointer );
|
||||
break;
|
||||
default:
|
||||
context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
|
||||
}
|
||||
|
||||
// If the return is a float value we need to get the value from the FP register
|
||||
if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
*(asDWORD*)&retQW = GetReturnedFloat();
|
||||
else
|
||||
retQW = GetReturnedDouble();
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_PPC
|
||||
#endif // AS_MAX_PORTABILITY
|
||||
|
||||
@@ -0,0 +1,773 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2016 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_callfunc_ppc_64.cpp
|
||||
//
|
||||
// These functions handle the actual calling of system functions
|
||||
//
|
||||
// This version is 64 bit PPC specific
|
||||
//
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
#ifdef AS_PPC_64
|
||||
#if AS_PTR_SIZE == 2
|
||||
// TODO: Add support for PPC 64bit platforms with 64bit pointers, for example Linux PPC64 (big endian) and PPC64 (little endian)
|
||||
#error This code has not been prepared for PPC with 64bit pointers. Most likely the ABI is different
|
||||
#else
|
||||
|
||||
#include "as_callfunc.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_tokendef.h"
|
||||
#include "as_context.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __SNC__
|
||||
#include "ppu_asm_intrinsics.h"
|
||||
#endif
|
||||
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// This part was written and tested by Jeff Slutter
|
||||
// from Reactor Zero, Abril, 2007, for PlayStation 3, which
|
||||
// is a PowerPC 64bit based architecture. Even though it is
|
||||
// 64bit it seems the pointer size is still 32bit.
|
||||
|
||||
// It still remains to be seen how well this code works
|
||||
// on other PPC platforms, such as XBox 360, GameCube.
|
||||
|
||||
#define AS_PPC_MAX_ARGS 32
|
||||
|
||||
// The array used to send values to the correct places.
|
||||
// Contains a byte of argTypes to indicate the register type to load
|
||||
// or zero if end of arguments
|
||||
// The +1 is for when CallThis (object methods) is used
|
||||
// Extra +1 when returning in memory
|
||||
// Extra +1 in ppcArgsType to ensure zero end-of-args marker
|
||||
|
||||
// TODO: multithread: The global variables must be removed to make the code thread safe
|
||||
|
||||
extern "C"
|
||||
{
|
||||
enum argTypes { ppcENDARG = 0, ppcINTARG = 1, ppcFLOATARG = 2, ppcDOUBLEARG = 3, ppcLONGARG = 4 };
|
||||
static asBYTE ppcArgsType[AS_PPC_MAX_ARGS + 1 + 1 + 1];
|
||||
static asDWORD ppcArgs[2*AS_PPC_MAX_ARGS + 1 + 1];
|
||||
}
|
||||
|
||||
// NOTE: these values are for PowerPC 64 bit. I'm sure things are different for PowerPC 32bit, but I don't have one.
|
||||
// I'm pretty sure that PPC 32bit sets up a stack frame slightly different (only 24 bytes for linkage area for instance)
|
||||
#define PPC_LINKAGE_SIZE (0x30) // how big the PPC linkage area is in a stack frame
|
||||
#define PPC_NUM_REGSTORE (10) // how many registers of the PPC we need to store/restore for ppcFunc64()
|
||||
#define PPC_REGSTORE_SIZE (8*PPC_NUM_REGSTORE) // how many bytes are required for register store/restore
|
||||
#define EXTRA_STACK_SIZE (PPC_LINKAGE_SIZE + PPC_REGSTORE_SIZE) // memory required, not including parameters, for the stack frame
|
||||
#define PPC_STACK_SIZE(numParams) ( -(( ( (((numParams)<8)?8:(numParams))<<3) + EXTRA_STACK_SIZE + 15 ) & ~15) ) // calculates the total stack size needed for ppcFunc64, must pad to 16bytes
|
||||
|
||||
// This is PowerPC 64 bit specific
|
||||
// Loads all data into the correct places and calls the function.
|
||||
// ppcArgsType is an array containing a byte type (enum argTypes) for each argument.
|
||||
// StackArgSizeInBytes is the size in bytes of the stack frame (takes into account linkage area, etc. must be multiple of 16)
|
||||
extern "C" asQWORD ppcFunc64(const asDWORD* argsPtr, int StackArgSizeInBytes, asDWORD func);
|
||||
asm(""
|
||||
".text\n"
|
||||
".align 4\n"
|
||||
".p2align 4,,15\n"
|
||||
".globl .ppcFunc64\n"
|
||||
".ppcFunc64:\n"
|
||||
|
||||
// function prolog
|
||||
"std %r22, -0x08(%r1)\n" // we need a register other than r0, to store the old stack pointer
|
||||
"mr %r22, %r1\n" // store the old stack pointer, for now (to make storing registers easier)
|
||||
"stdux %r1, %r1, %r4\n" // atomically store and update the stack pointer for the new stack frame (in case of a signal/interrupt)
|
||||
"mflr %r0\n" // get the caller's LR register
|
||||
"std %r0, 0x10(%r22)\n" // store the caller's LR register
|
||||
"std %r23, -0x10(%r22)\n" //
|
||||
"std %r24, -0x18(%r22)\n" //
|
||||
"std %r25, -0x20(%r22)\n" //
|
||||
"std %r26, -0x28(%r22)\n" //
|
||||
"std %r27, -0x30(%r22)\n" //
|
||||
"std %r28, -0x38(%r22)\n" //
|
||||
"std %r29, -0x40(%r22)\n" //
|
||||
"std %r30, -0x48(%r22)\n" //
|
||||
"std %r31, -0x50(%r22)\n" //
|
||||
"std %r3, 0x30(%r22)\n" // save our parameters
|
||||
"std %r4, 0x38(%r22)\n" //
|
||||
"std %r5, 0x40(%r22)\n" //
|
||||
"mr %r31, %r1\n" // functions tend to store the stack pointer here too
|
||||
|
||||
// initial registers for the function
|
||||
"mr %r29, %r3\n" // (r29) args list
|
||||
"lwz %r27, 0(%r5)\n" // load the function pointer to call. func actually holds the pointer to our function
|
||||
"addi %r26, %r1, 0x30\n" // setup the pointer to the parameter area to the function we're going to call
|
||||
"sub %r0,%r0,%r0\n" // zero out r0
|
||||
"mr %r23,%r0\n" // zero out r23, which holds the number of used GPR registers
|
||||
"mr %r22,%r0\n" // zero our r22, which holds the number of used float registers
|
||||
|
||||
// load the global ppcArgsType which holds the types of arguments for each argument
|
||||
"lis %r25, ppcArgsType@ha\n" // load the upper 16 bits of the address to r25
|
||||
"addi %r25, %r25, ppcArgsType@l\n" // load the lower 16 bits of the address to r25
|
||||
"subi %r25, %r25, 1\n" // since we increment r25 on its use, we'll pre-decrement it
|
||||
|
||||
// loop through the arguments
|
||||
"ppcNextArg:\n"
|
||||
"addi %r25, %r25, 1\n" // increment r25, our arg type pointer
|
||||
// switch based on the current argument type (0:end, 1:int, 2:float 3:double)
|
||||
"lbz %r24, 0(%r25)\n" // load the current argument type (it's a byte)
|
||||
"mulli %r24, %r24, 4\n" // our jump table has 4 bytes per case (1 instruction)
|
||||
"lis %r30, ppcTypeSwitch@ha\n" // load the address of the jump table for the switch
|
||||
"addi %r30, %r30, ppcTypeSwitch@l\n"
|
||||
"add %r0, %r30, %r24\n" // offset by our argument type
|
||||
"mtctr %r0\n" // load the jump address into CTR
|
||||
"bctr\n" // jump into the jump table/switch
|
||||
"nop\n"
|
||||
// the jump table/switch based on the current argument type
|
||||
"ppcTypeSwitch:\n"
|
||||
"b ppcArgsEnd\n"
|
||||
"b ppcArgIsInteger\n"
|
||||
"b ppcArgIsFloat\n"
|
||||
"b ppcArgIsDouble\n"
|
||||
"b ppcArgIsLong\n"
|
||||
|
||||
// when we get here we have finished processing all the arguments
|
||||
// everything is ready to go to call the function
|
||||
"ppcArgsEnd:\n"
|
||||
"mtctr %r27\n" // the function pointer is stored in r27, load that into CTR
|
||||
"bctrl\n" // call the function. We have to do it this way so that the LR gets the proper
|
||||
"nop\n" // return value (the next instruction below). So we have to branch from CTR instead of LR.
|
||||
// when we get here, the function has returned, this is the function epilog
|
||||
"ld %r11,0x00(%r1)\n" // load in the caller's stack pointer
|
||||
"ld %r0,0x10(%r11)\n" // load in the caller's LR
|
||||
"mtlr %r0\n" // restore the caller's LR
|
||||
"ld %r22, -0x08(%r11)\n" // load registers
|
||||
"ld %r23, -0x10(%r11)\n" //
|
||||
"ld %r24, -0x18(%r11)\n" //
|
||||
"ld %r25, -0x20(%r11)\n" //
|
||||
"ld %r26, -0x28(%r11)\n" //
|
||||
"ld %r27, -0x30(%r11)\n" //
|
||||
"ld %r28, -0x38(%r11)\n" //
|
||||
"ld %r29, -0x40(%r11)\n" //
|
||||
"ld %r30, -0x48(%r11)\n" //
|
||||
"ld %r31, -0x50(%r11)\n" //
|
||||
"mr %r1, %r11\n" // restore the caller's SP
|
||||
"blr\n" // return back to the caller
|
||||
"nop\n"
|
||||
// Integer argument (GPR register)
|
||||
"ppcArgIsInteger:\n"
|
||||
"lis %r30,ppcLoadIntReg@ha\n" // load the address to the jump table for integer registers
|
||||
"addi %r30, %r30, ppcLoadIntReg@l\n"
|
||||
"mulli %r0, %r23, 8\n" // each item in the jump table is 2 instructions (8 bytes)
|
||||
"add %r0, %r0, %r30\n" // calculate ppcLoadIntReg[numUsedGPRRegs]
|
||||
"lwz %r30,0(%r29)\n" // load the next argument from the argument list into r30
|
||||
"cmpwi %r23, 8\n" // we can only load GPR3 through GPR10 (8 registers)
|
||||
"bgt ppcLoadIntRegUpd\n" // if we're beyond 8 GPR registers, we're in the stack, go there
|
||||
"mtctr %r0\n" // load the address of our ppcLoadIntReg jump table (we're below 8 GPR registers)
|
||||
"bctr\n" // load the argument into a GPR register
|
||||
"nop\n"
|
||||
// jump table for GPR registers, for the first 8 GPR arguments
|
||||
"ppcLoadIntReg:\n"
|
||||
"mr %r3,%r30\n" // arg0 (to r3)
|
||||
"b ppcLoadIntRegUpd\n"
|
||||
"mr %r4,%r30\n" // arg1 (to r4)
|
||||
"b ppcLoadIntRegUpd\n"
|
||||
"mr %r5,%r30\n" // arg2 (to r5)
|
||||
"b ppcLoadIntRegUpd\n"
|
||||
"mr %r6,%r30\n" // arg3 (to r6)
|
||||
"b ppcLoadIntRegUpd\n"
|
||||
"mr %r7,%r30\n" // arg4 (to r7)
|
||||
"b ppcLoadIntRegUpd\n"
|
||||
"mr %r8,%r30\n" // arg5 (to r8)
|
||||
"b ppcLoadIntRegUpd\n"
|
||||
"mr %r9,%r30\n" // arg6 (to r9)
|
||||
"b ppcLoadIntRegUpd\n"
|
||||
"mr %r10,%r30\n" // arg7 (to r10)
|
||||
"b ppcLoadIntRegUpd\n"
|
||||
|
||||
// all GPR arguments still go on the stack
|
||||
"ppcLoadIntRegUpd:\n"
|
||||
"std %r30,0(%r26)\n" // store the argument into the next slot on the stack's argument list
|
||||
"addi %r23, %r23, 1\n" // count a used GPR register
|
||||
"addi %r29, %r29, 4\n" // move to the next argument on the list
|
||||
"addi %r26, %r26, 8\n" // adjust our argument stack pointer for the next
|
||||
"b ppcNextArg\n" // next argument
|
||||
|
||||
// single Float argument
|
||||
"ppcArgIsFloat:\n"
|
||||
"lis %r30,ppcLoadFloatReg@ha\n" // get the base address of the float register jump table
|
||||
"addi %r30, %r30, ppcLoadFloatReg@l\n"
|
||||
"mulli %r0, %r22 ,8\n" // each jump table entry is 8 bytes
|
||||
"add %r0, %r0, %r30\n" // calculate the offset to ppcLoadFloatReg[numUsedFloatReg]
|
||||
"lfs 0, 0(%r29)\n" // load the next argument as a float into f0
|
||||
"cmpwi %r22, 13\n" // can't load more than 13 float/double registers
|
||||
"bgt ppcLoadFloatRegUpd\n" // if we're beyond 13 registers, just fall to inserting into the stack
|
||||
"mtctr %r0\n" // jump into the float jump table
|
||||
"bctr\n"
|
||||
"nop\n"
|
||||
// jump table for float registers, for the first 13 float arguments
|
||||
"ppcLoadFloatReg:\n"
|
||||
"fmr 1,0\n" // arg0 (f1)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"fmr 2,0\n" // arg1 (f2)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"fmr 3,0\n" // arg2 (f3)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"fmr 4,0\n" // arg3 (f4)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"fmr 5,0\n" // arg4 (f5)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"fmr 6,0\n" // arg5 (f6)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"fmr 7,0\n" // arg6 (f7)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"fmr 8,0\n" // arg7 (f8)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"fmr 9,0\n" // arg8 (f9)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"fmr 10,0\n" // arg9 (f10)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"fmr 11,0\n" // arg10 (f11)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"fmr 12,0\n" // arg11 (f12)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"fmr 13,0\n" // arg12 (f13)
|
||||
"b ppcLoadFloatRegUpd\n"
|
||||
"nop\n"
|
||||
// all float arguments still go on the stack
|
||||
"ppcLoadFloatRegUpd:\n"
|
||||
"stfs 0, 0x04(%r26)\n" // store, as a single float, f0 (current argument) on to the stack argument list
|
||||
"addi %r23, %r23, 1\n" // a float register eats up a GPR register
|
||||
"addi %r22, %r22, 1\n" // ...and, of course, a float register
|
||||
"addi %r29, %r29, 4\n" // move to the next argument in the list
|
||||
"addi %r26, %r26, 8\n" // move to the next stack slot
|
||||
"b ppcNextArg\n" // on to the next argument
|
||||
"nop\n"
|
||||
// double Float argument
|
||||
"ppcArgIsDouble:\n"
|
||||
"lis %r30, ppcLoadDoubleReg@ha\n" // load the base address of the jump table for double registers
|
||||
"addi %r30, %r30, ppcLoadDoubleReg@l\n"
|
||||
"mulli %r0, %r22, 8\n" // each slot of the jump table is 8 bytes
|
||||
"add %r0, %r0, %r30\n" // calculate ppcLoadDoubleReg[numUsedFloatReg]
|
||||
"lfd 0, 0(%r29)\n" // load the next argument, as a double float, into f0
|
||||
"cmpwi %r22,13\n" // the first 13 floats must go into float registers also
|
||||
"bgt ppcLoadDoubleRegUpd\n" // if we're beyond 13, then just put on to the stack
|
||||
"mtctr %r0\n" // we're under 13, first load our register
|
||||
"bctr\n" // jump into the jump table
|
||||
"nop\n"
|
||||
// jump table for float registers, for the first 13 float arguments
|
||||
"ppcLoadDoubleReg:\n"
|
||||
"fmr 1,0\n" // arg0 (f1)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"fmr 2,0\n" // arg1 (f2)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"fmr 3,0\n" // arg2 (f3)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"fmr 4,0\n" // arg3 (f4)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"fmr 5,0\n" // arg4 (f5)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"fmr 6,0\n" // arg5 (f6)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"fmr 7,0\n" // arg6 (f7)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"fmr 8,0\n" // arg7 (f8)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"fmr 9,0\n" // arg8 (f9)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"fmr 10,0\n" // arg9 (f10)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"fmr 11,0\n" // arg10 (f11)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"fmr 12,0\n" // arg11 (f12)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"fmr 13,0\n" // arg12 (f13)
|
||||
"b ppcLoadDoubleRegUpd\n"
|
||||
"nop\n"
|
||||
// all float arguments still go on the stack
|
||||
"ppcLoadDoubleRegUpd:\n"
|
||||
"stfd 0,0(%r26)\n" // store f0, as a double, into the argument list on the stack
|
||||
"addi %r23, %r23, 1\n" // a double float eats up one GPR
|
||||
"addi %r22, %r22, 1\n" // ...and, of course, a float
|
||||
"addi %r29, %r29, 8\n" // increment to our next argument we need to process (8 bytes for the 64bit float)
|
||||
"addi %r26, %r26, 8\n" // increment to the next slot on the argument list on the stack (8 bytes)
|
||||
"b ppcNextArg\n" // on to the next argument
|
||||
"nop\n"
|
||||
|
||||
// Long (64 bit int) argument
|
||||
"ppcArgIsLong:\n"
|
||||
"lis %r30,ppcLoadLongReg@ha\n" // load the address to the jump table for integer64
|
||||
"addi %r30, %r30, ppcLoadLongReg@l\n"
|
||||
"mulli %r0, %r23, 8\n" // each item in the jump table is 2 instructions (8 bytes)
|
||||
"add %r0, %r0, %r30\n" // calculate ppcLoadLongReg[numUsedGPRRegs]
|
||||
"ld %r30,0(%r29)\n" // load the next argument from the argument list into r30
|
||||
"cmpwi %r23, 8\n" // we can only load GPR3 through GPR10 (8 registers)
|
||||
"bgt ppcLoadLongRegUpd\n" // if we're beyond 8 GPR registers, we're in the stack, go there
|
||||
"mtctr %r0\n" // load the address of our ppcLoadLongReg jump table (we're below 8 GPR registers)
|
||||
"bctr\n" // load the argument into a GPR register
|
||||
"nop\n"
|
||||
// jump table for GPR registers, for the first 8 GPR arguments
|
||||
"ppcLoadLongReg:\n"
|
||||
"mr %r3,%r30\n" // arg0 (to r3)
|
||||
"b ppcLoadLongRegUpd\n"
|
||||
"mr %r4,%r30\n" // arg1 (to r4)
|
||||
"b ppcLoadLongRegUpd\n"
|
||||
"mr %r5,%r30\n" // arg2 (to r5)
|
||||
"b ppcLoadLongRegUpd\n"
|
||||
"mr %r6,%r30\n" // arg3 (to r6)
|
||||
"b ppcLoadLongRegUpd\n"
|
||||
"mr %r7,%r30\n" // arg4 (to r7)
|
||||
"b ppcLoadLongRegUpd\n"
|
||||
"mr %r8,%r30\n" // arg5 (to r8)
|
||||
"b ppcLoadLongRegUpd\n"
|
||||
"mr %r9,%r30\n" // arg6 (to r9)
|
||||
"b ppcLoadLongRegUpd\n"
|
||||
"mr %r10,%r30\n" // arg7 (to r10)
|
||||
"b ppcLoadLongRegUpd\n"
|
||||
|
||||
// all GPR arguments still go on the stack
|
||||
"ppcLoadLongRegUpd:\n"
|
||||
"std %r30,0(%r26)\n" // store the argument into the next slot on the stack's argument list
|
||||
"addi %r23, %r23, 1\n" // count a used GPR register
|
||||
"addi %r29, %r29, 8\n" // move to the next argument on the list
|
||||
"addi %r26, %r26, 8\n" // adjust our argument stack pointer for the next
|
||||
"b ppcNextArg\n" // next argument
|
||||
);
|
||||
|
||||
static asDWORD GetReturnedFloat(void)
|
||||
{
|
||||
asDWORD f;
|
||||
#ifdef __SNC__
|
||||
__stfs( __freg(1), 0, (void*)&f);
|
||||
#else
|
||||
asm(" stfs 1, %0\n" : "=m"(f));
|
||||
#endif
|
||||
return f;
|
||||
}
|
||||
|
||||
static asQWORD GetReturnedDouble(void)
|
||||
{
|
||||
asQWORD f;
|
||||
#ifdef __SNC__
|
||||
__stfd( __freg(1), 0, (void*)&f);
|
||||
#else
|
||||
asm(" stfd 1, %0\n" : "=m"(f));
|
||||
#endif
|
||||
return f;
|
||||
}
|
||||
|
||||
// puts the arguments in the correct place in the stack array. See comments above.
|
||||
static void stackArgs( const asDWORD *args, const asBYTE *argsType, int &numIntArgs, int &numFloatArgs, int &numDoubleArgs, int &numLongArgs )
|
||||
{
|
||||
// initialize our offset based on any already placed arguments
|
||||
int i;
|
||||
int argWordPos = numIntArgs + numFloatArgs + (numDoubleArgs*2) + (numLongArgs*2);
|
||||
int typeOffset = numIntArgs + numFloatArgs + numDoubleArgs + numLongArgs;
|
||||
|
||||
int typeIndex;
|
||||
for( i = 0, typeIndex = 0; ; i++, typeIndex++ )
|
||||
{
|
||||
// store the type
|
||||
ppcArgsType[typeOffset++] = argsType[typeIndex];
|
||||
if( argsType[typeIndex] == ppcENDARG )
|
||||
break;
|
||||
|
||||
switch( argsType[typeIndex] )
|
||||
{
|
||||
case ppcFLOATARG:
|
||||
{
|
||||
// stow float
|
||||
ppcArgs[argWordPos] = args[i]; // it's just a bit copy
|
||||
numFloatArgs++;
|
||||
argWordPos++; //add one word
|
||||
}
|
||||
break;
|
||||
|
||||
case ppcDOUBLEARG:
|
||||
{
|
||||
// stow double
|
||||
memcpy( &ppcArgs[argWordPos], &args[i], sizeof(double) ); // we have to do this because of alignment
|
||||
numDoubleArgs++;
|
||||
argWordPos+=2; //add two words
|
||||
i++;//doubles take up 2 argument slots
|
||||
}
|
||||
break;
|
||||
|
||||
case ppcINTARG:
|
||||
{
|
||||
// stow register
|
||||
ppcArgs[argWordPos] = args[i];
|
||||
numIntArgs++;
|
||||
argWordPos++;
|
||||
}
|
||||
break;
|
||||
|
||||
case ppcLONGARG:
|
||||
{
|
||||
// stow long
|
||||
memcpy( &ppcArgs[argWordPos], &args[i], 8 ); // for alignment purposes, we use memcpy
|
||||
numLongArgs++;
|
||||
argWordPos += 2; // add two words
|
||||
i++; // longs take up 2 argument slots
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// close off the argument list (if we have max args we won't close it off until here)
|
||||
ppcArgsType[typeOffset] = ppcENDARG;
|
||||
}
|
||||
|
||||
static asQWORD CallCDeclFunction(const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory)
|
||||
{
|
||||
int baseArgCount = 0;
|
||||
if( retInMemory )
|
||||
{
|
||||
// the first argument is the 'return in memory' pointer
|
||||
ppcArgs[0] = (asDWORD)retInMemory;
|
||||
ppcArgsType[0] = ppcINTARG;
|
||||
ppcArgsType[1] = ppcENDARG;
|
||||
baseArgCount = 1;
|
||||
}
|
||||
|
||||
// put the arguments in the correct places in the ppcArgs array
|
||||
int numTotalArgs = baseArgCount;
|
||||
if( argSize > 0 )
|
||||
{
|
||||
int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0, longArgs = 0;
|
||||
stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs, longArgs );
|
||||
numTotalArgs = intArgs + floatArgs + doubleArgs + longArgs;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no arguments, cap the type list
|
||||
ppcArgsType[baseArgCount] = ppcENDARG;
|
||||
}
|
||||
|
||||
// call the function with the arguments
|
||||
return ppcFunc64( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func );
|
||||
}
|
||||
|
||||
// This function is identical to CallCDeclFunction, with the only difference that
|
||||
// the value in the first parameter is the object (unless we are returning in memory)
|
||||
static asQWORD CallThisCallFunction(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory )
|
||||
{
|
||||
int baseArgCount = 0;
|
||||
if( retInMemory )
|
||||
{
|
||||
// the first argument is the 'return in memory' pointer
|
||||
ppcArgs[0] = (asDWORD)retInMemory;
|
||||
ppcArgsType[0] = ppcINTARG;
|
||||
ppcArgsType[1] = ppcENDARG;
|
||||
baseArgCount = 1;
|
||||
}
|
||||
|
||||
// the first argument is the 'this' of the object
|
||||
ppcArgs[baseArgCount] = (asDWORD)obj;
|
||||
ppcArgsType[baseArgCount++] = ppcINTARG;
|
||||
ppcArgsType[baseArgCount] = ppcENDARG;
|
||||
|
||||
// put the arguments in the correct places in the ppcArgs array
|
||||
int numTotalArgs = baseArgCount;
|
||||
if( argSize > 0 )
|
||||
{
|
||||
int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0, longArgs = 0;
|
||||
stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs, longArgs );
|
||||
numTotalArgs = intArgs + floatArgs + doubleArgs + longArgs;
|
||||
}
|
||||
|
||||
// call the function with the arguments
|
||||
return ppcFunc64( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func);
|
||||
}
|
||||
|
||||
// This function is identical to CallCDeclFunction, with the only difference that
|
||||
// the value in the last parameter is the object
|
||||
// NOTE: on PPC the order for the args is reversed
|
||||
static asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory)
|
||||
{
|
||||
UNUSED_VAR(argSize);
|
||||
int baseArgCount = 0;
|
||||
if( retInMemory )
|
||||
{
|
||||
// the first argument is the 'return in memory' pointer
|
||||
ppcArgs[0] = (asDWORD)retInMemory;
|
||||
ppcArgsType[0] = ppcINTARG;
|
||||
ppcArgsType[1] = ppcENDARG;
|
||||
baseArgCount = 1;
|
||||
}
|
||||
|
||||
// stack any of the arguments
|
||||
int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0, longArgs = 0;
|
||||
stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs, longArgs );
|
||||
int numTotalArgs = intArgs + floatArgs + doubleArgs;
|
||||
|
||||
// can we fit the object in at the end?
|
||||
if( numTotalArgs < AS_PPC_MAX_ARGS )
|
||||
{
|
||||
// put the object pointer at the end
|
||||
int argPos = intArgs + floatArgs + (doubleArgs * 2) + (longArgs *2);
|
||||
ppcArgs[argPos] = (asDWORD)obj;
|
||||
ppcArgsType[numTotalArgs++] = ppcINTARG;
|
||||
ppcArgsType[numTotalArgs] = ppcENDARG;
|
||||
}
|
||||
|
||||
// call the function with the arguments
|
||||
return ppcFunc64( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func );
|
||||
}
|
||||
|
||||
// returns true if the given parameter is a 'variable argument'
|
||||
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*/, 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));
|
||||
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
|
||||
int callConv = sysFunc->callConv;
|
||||
|
||||
asQWORD retQW = 0;
|
||||
void *func = (void*)sysFunc->func;
|
||||
int paramSize = sysFunc->paramSize;
|
||||
asDWORD *vftable = NULL;
|
||||
int a;
|
||||
|
||||
// convert the parameters that are < 4 bytes from little endian to big endian
|
||||
int argDwordOffset = 0;
|
||||
int totalArgumentCount = 0;
|
||||
|
||||
for( a = 0; a < (int)descr->parameterTypes.GetLength(); ++a )
|
||||
{
|
||||
// get the size for the parameter
|
||||
int numBytes = descr->parameterTypes[a].GetSizeInMemoryBytes();
|
||||
++totalArgumentCount;
|
||||
|
||||
// is this a variable argument?
|
||||
// for variable arguments, the typeID will always follow...but we know it is 4 bytes
|
||||
// so we can skip that parameter automatically.
|
||||
bool isVarArg = IsVariableArgument( descr->parameterTypes[a] );
|
||||
if( isVarArg )
|
||||
{
|
||||
++totalArgumentCount;
|
||||
}
|
||||
|
||||
if( numBytes >= 4 || descr->parameterTypes[a].IsReference() || descr->parameterTypes[a].IsObjectHandle() )
|
||||
{
|
||||
// DWORD or larger parameter --- no flipping needed
|
||||
argDwordOffset += descr->parameterTypes[a].GetSizeOnStackDWords();
|
||||
}
|
||||
else
|
||||
{
|
||||
// flip
|
||||
asASSERT( numBytes == 1 || numBytes == 2 );
|
||||
switch( numBytes )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
volatile asBYTE *bPtr = (asBYTE*)ARG_DW(args[argDwordOffset]);
|
||||
asBYTE t = bPtr[0];
|
||||
bPtr[0] = bPtr[3];
|
||||
bPtr[3] = t;
|
||||
t = bPtr[1];
|
||||
bPtr[1] = bPtr[2];
|
||||
bPtr[2] = t;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
volatile asWORD *wPtr = (asWORD*)ARG_DW(args[argDwordOffset]);
|
||||
asWORD t = wPtr[0];
|
||||
wPtr[0] = wPtr[1];
|
||||
wPtr[1] = t;
|
||||
}
|
||||
break;
|
||||
}
|
||||
++argDwordOffset;
|
||||
}
|
||||
|
||||
if( isVarArg )
|
||||
{
|
||||
// skip the implicit typeID
|
||||
++argDwordOffset;
|
||||
}
|
||||
}
|
||||
|
||||
asASSERT( totalArgumentCount <= AS_PPC_MAX_ARGS );
|
||||
|
||||
// mark all float/double/int arguments
|
||||
int argIndex = 0;
|
||||
for( a = 0; a < (int)descr->parameterTypes.GetLength(); ++a, ++argIndex )
|
||||
{
|
||||
// get the base type
|
||||
argsType[argIndex] = ppcINTARG;
|
||||
if( descr->parameterTypes[a].IsFloatType() && !descr->parameterTypes[a].IsReference() )
|
||||
{
|
||||
argsType[argIndex] = ppcFLOATARG;
|
||||
}
|
||||
if( descr->parameterTypes[a].IsDoubleType() && !descr->parameterTypes[a].IsReference() )
|
||||
{
|
||||
argsType[argIndex] = ppcDOUBLEARG;
|
||||
}
|
||||
if( descr->parameterTypes[a].GetSizeOnStackDWords() == 2 && !descr->parameterTypes[a].IsDoubleType() && !descr->parameterTypes[a].IsReference() )
|
||||
{
|
||||
argsType[argIndex] = ppcLONGARG;
|
||||
}
|
||||
|
||||
// if it is a variable argument, account for the typeID
|
||||
if( IsVariableArgument(descr->parameterTypes[a]) )
|
||||
{
|
||||
// implicitly add another parameter (AFTER the parameter above), for the TypeID
|
||||
argsType[++argIndex] = ppcINTARG;
|
||||
}
|
||||
}
|
||||
asASSERT( argIndex == totalArgumentCount );
|
||||
|
||||
asDWORD paramBuffer[64];
|
||||
if( sysFunc->takesObjByVal )
|
||||
{
|
||||
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() &&
|
||||
!(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) )
|
||||
{
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
|
||||
{
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
++paramSize;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// NOTE: we may have to do endian flipping here
|
||||
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy( ¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes() );
|
||||
|
||||
// Delete the original memory
|
||||
engine->CallFree( *(char**)(args+spos) );
|
||||
spos++;
|
||||
dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the value directly
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
|
||||
{
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
}
|
||||
paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
|
||||
// if this was a variable argument parameter, then account for the implicit typeID
|
||||
if( IsVariableArgument( descr->parameterTypes[n] ) )
|
||||
{
|
||||
// the TypeID is just a DWORD
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
++paramSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep a free location at the beginning
|
||||
args = ¶mBuffer[1];
|
||||
}
|
||||
|
||||
// one last verification to make sure things are how we expect
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_CDECL:
|
||||
case ICC_CDECL_RETURNINMEM:
|
||||
case ICC_STDCALL:
|
||||
case ICC_STDCALL_RETURNINMEM:
|
||||
retQW = CallCDeclFunction( args, argsType, paramSize, (asDWORD)func, retPointer );
|
||||
break;
|
||||
case ICC_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
retQW = CallThisCallFunction(obj, args, argsType, paramSize, (asDWORD)func, retPointer );
|
||||
break;
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(asDWORD**)obj;
|
||||
retQW = CallThisCallFunction( obj, args, argsType, paramSize, vftable[asDWORD(func)>>2], retPointer );
|
||||
break;
|
||||
case ICC_CDECL_OBJLAST:
|
||||
case ICC_CDECL_OBJLAST_RETURNINMEM:
|
||||
retQW = CallThisCallFunction_objLast( obj, args, argsType, paramSize, (asDWORD)func, retPointer );
|
||||
break;
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
retQW = CallThisCallFunction( obj, args, argsType, paramSize, (asDWORD)func, retPointer );
|
||||
break;
|
||||
default:
|
||||
context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
|
||||
}
|
||||
|
||||
if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
// If the return is a float value we need to get the value from the FP register
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
*(asDWORD*)&retQW = GetReturnedFloat();
|
||||
else
|
||||
retQW = GetReturnedDouble();
|
||||
}
|
||||
else if( sysFunc->hostReturnSize == 1 )
|
||||
{
|
||||
// Move the bits to the higher value to compensate for the adjustment that the caller does
|
||||
retQW <<= 32;
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_PTR_SIZE == 2
|
||||
#endif // AS_PPC_64
|
||||
#endif // AS_MAX_PORTABILITY
|
||||
|
||||
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_callfunc_sh4.cpp
|
||||
//
|
||||
// These functions handle the actual calling of system functions
|
||||
//
|
||||
// This version is SH4 specific and was originally written
|
||||
// by Fredrik Ehnbom in May, 2004
|
||||
// Later updated for angelscript 2.0.0 by Fredrik Ehnbom in Jan, 2005
|
||||
|
||||
// References:
|
||||
// * http://www.renesas.com/avs/resource/japan/eng/pdf/mpumcu/e602156_sh4.pdf
|
||||
// * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcechp40/html/_callsh4_SH_4_Calling_Standard.asp
|
||||
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
#ifdef AS_SH4
|
||||
|
||||
#include "as_callfunc.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_tokendef.h"
|
||||
#include "as_context.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
#define AS_SH4_MAX_ARGS 32
|
||||
// The array used to send values to the correct places.
|
||||
// first 0-4 regular values to load into the r4-r7 registers
|
||||
// then 0-8 float values to load into the fr4-fr11 registers
|
||||
// then (AS_SH4_MAX_ARGS - 12) values to load onto the stack
|
||||
// the +1 is for when CallThis (object methods) is used
|
||||
// extra +1 when returning in memory
|
||||
extern "C" {
|
||||
static asDWORD sh4Args[AS_SH4_MAX_ARGS + 1 + 1];
|
||||
}
|
||||
|
||||
// Loads all data into the correct places and calls the function.
|
||||
// intArgSize is the size in bytes for how much data to put in int registers
|
||||
// floatArgSize is the size in bytes for how much data to put in float registers
|
||||
// stackArgSize is the size in bytes for how much data to put on the callstack
|
||||
extern "C" asQWORD sh4Func(int intArgSize, int floatArgSize, int stackArgSize, asDWORD func);
|
||||
|
||||
asm(""
|
||||
" .align 4\n"
|
||||
" .global _sh4Func\n"
|
||||
"_sh4Func:\n"
|
||||
" mov.l r14,@-r15\n"
|
||||
" mov.l r13,@-r15\n"
|
||||
" mov.l r12,@-r15\n"
|
||||
" sts.l pr,@-r15\n" // must be saved since we call a subroutine
|
||||
" mov r7, r14\n" // func
|
||||
" mov r6, r13\n" // stackArgSize
|
||||
" mov.l r5,@-r15\n" // floatArgSize
|
||||
" mov.l sh4Args,r0\n"
|
||||
" pref @r0\n"
|
||||
" mov r4, r1\n" // intArgsize
|
||||
" mov #33*4,r2\n"
|
||||
" extu.b r2,r2\n" // make unsigned (33*4 = 132 => 128)
|
||||
" mov.l @(r0,r2), r2\n" // r2 has adress for when returning in memory
|
||||
"_sh4f_intarguments:\n" // copy all the int arguments to the respective registers
|
||||
" mov #4*2*2,r3\n" // calculate how many bytes to skip
|
||||
" sub r1,r3\n"
|
||||
" braf r3\n"
|
||||
" add #-4,r1\n" // we are indexing the array backwards, so subtract one (delayed slot)
|
||||
" mov.l @(r0,r1),r7\n" // 4 arguments
|
||||
" add #-4,r1\n"
|
||||
" mov.l @(r0,r1),r6\n" // 3 arguments
|
||||
" add #-4,r1\n"
|
||||
" mov.l @(r0,r1),r5\n" // 2 arguments
|
||||
" add #-4,r1\n"
|
||||
" mov.l @(r0,r1),r4\n" // 1 argument
|
||||
" nop\n"
|
||||
"_sh4f_floatarguments:\n" // copy all the float arguments to the respective registers
|
||||
" add #4*4, r0\n"
|
||||
" mov.l @r15+,r1\n" // floatArgSize
|
||||
" mov #8*2*2,r3\n" // calculate how many bytes to skip
|
||||
" sub r1,r3\n"
|
||||
" braf r3\n"
|
||||
" add #-4,r1\n" // we are indexing the array backwards, so subtract one (delayed slot)
|
||||
" fmov.s @(r0,r1),fr11\n" // 8 arguments
|
||||
" add #-4,r1\n"
|
||||
" fmov.s @(r0,r1),fr10\n" // 7 arguments
|
||||
" add #-4,r1\n"
|
||||
" fmov.s @(r0,r1),fr9\n" // 6 arguments
|
||||
" add #-4,r1\n"
|
||||
" fmov.s @(r0,r1),fr8\n" // 5 arguments
|
||||
" add #-4,r1\n"
|
||||
" fmov.s @(r0,r1),fr7\n" // 4 arguments
|
||||
" add #-4,r1\n"
|
||||
" fmov.s @(r0,r1),fr6\n" // 3 arguments
|
||||
" add #-4,r1\n"
|
||||
" fmov.s @(r0,r1),fr5\n" // 2 arguments
|
||||
" add #-4,r1\n"
|
||||
" fmov.s @(r0,r1),fr4\n" // 1 argument
|
||||
" nop\n"
|
||||
"_sh4f_stackarguments:\n" // copy all the stack argument onto the stack
|
||||
" add #8*4, r0\n"
|
||||
" mov r0, r1\n"
|
||||
" mov #0, r0\n" // init position counter (also used as a 0-check on the line after)
|
||||
" cmp/eq r0, r13\n"
|
||||
" bt _sh4f_functioncall\n" // no arguments to push onto the stack
|
||||
" mov r13, r3\n" // stackArgSize
|
||||
" sub r3,r15\n" // "allocate" space on the stack
|
||||
" shlr2 r3\n" // make into a counter
|
||||
"_sh4f_stackloop:\n"
|
||||
" mov.l @r1+, r12\n"
|
||||
" mov.l r12, @(r0, r15)\n"
|
||||
" add #4, r0\n"
|
||||
" dt r3\n"
|
||||
" bf _sh4f_stackloop\n"
|
||||
"_sh4f_functioncall:\n"
|
||||
" jsr @r14\n" // no arguments
|
||||
" nop\n"
|
||||
" add r13, r15\n" // restore stack position
|
||||
" lds.l @r15+,pr\n"
|
||||
" mov.l @r15+, r12\n"
|
||||
" mov.l @r15+, r13\n"
|
||||
" rts\n"
|
||||
" mov.l @r15+, r14\n" // delayed slot
|
||||
"\n"
|
||||
" .align 4\n"
|
||||
"sh4Args:\n"
|
||||
" .long _sh4Args\n"
|
||||
);
|
||||
|
||||
// puts the arguments in the correct place in the sh4Args-array. See comments above.
|
||||
// This could be done better.
|
||||
inline void splitArgs(const asDWORD *args, int argNum, int &numRegIntArgs, int &numRegFloatArgs, int &numRestArgs, int hostFlags) {
|
||||
int i;
|
||||
|
||||
int argBit = 1;
|
||||
for (i = 0; i < argNum; i++) {
|
||||
if (hostFlags & argBit) {
|
||||
if (numRegFloatArgs < 12 - 4) {
|
||||
// put in float register
|
||||
sh4Args[4 + numRegFloatArgs] = args[i];
|
||||
numRegFloatArgs++;
|
||||
} else {
|
||||
// put in stack
|
||||
sh4Args[4 + 8 + numRestArgs] = args[i];
|
||||
numRestArgs++;
|
||||
}
|
||||
} else {
|
||||
if (numRegIntArgs < 8 - 4) {
|
||||
// put in int register
|
||||
sh4Args[numRegIntArgs] = args[i];
|
||||
numRegIntArgs++;
|
||||
} else {
|
||||
// put in stack
|
||||
sh4Args[4 + 8 + numRestArgs] = args[i];
|
||||
numRestArgs++;
|
||||
}
|
||||
}
|
||||
argBit <<= 1;
|
||||
}
|
||||
}
|
||||
asQWORD CallCDeclFunction(const asDWORD *args, int argSize, asDWORD func, int flags)
|
||||
{
|
||||
int argNum = argSize >> 2;
|
||||
|
||||
int intArgs = 0;
|
||||
int floatArgs = 0;
|
||||
int restArgs = 0;
|
||||
|
||||
// put the arguments in the correct places in the sh4Args array
|
||||
if (argNum > 0)
|
||||
splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags);
|
||||
|
||||
return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func);
|
||||
}
|
||||
|
||||
// This function is identical to CallCDeclFunction, with the only difference that
|
||||
// the value in the first parameter is the object
|
||||
asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags)
|
||||
{
|
||||
int argNum = argSize >> 2;
|
||||
|
||||
int intArgs = 1;
|
||||
int floatArgs = 0;
|
||||
int restArgs = 0;
|
||||
|
||||
sh4Args[0] = (asDWORD) obj;
|
||||
|
||||
// put the arguments in the correct places in the sh4Args array
|
||||
if (argNum >= 1)
|
||||
splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags);
|
||||
|
||||
return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func);
|
||||
}
|
||||
// This function is identical to CallCDeclFunction, with the only difference that
|
||||
// the value in the last parameter is the object
|
||||
asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags)
|
||||
{
|
||||
int argNum = argSize >> 2;
|
||||
|
||||
int intArgs = 0;
|
||||
int floatArgs = 0;
|
||||
int restArgs = 0;
|
||||
|
||||
|
||||
// put the arguments in the correct places in the sh4Args array
|
||||
if (argNum >= 1)
|
||||
splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags);
|
||||
|
||||
if (intArgs < 4) {
|
||||
sh4Args[intArgs] = (asDWORD) obj;
|
||||
intArgs++;
|
||||
} else {
|
||||
sh4Args[4 + 8 + restArgs] = (asDWORD) obj;
|
||||
restArgs++;
|
||||
}
|
||||
|
||||
|
||||
return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func);
|
||||
}
|
||||
|
||||
asDWORD GetReturnedFloat()
|
||||
{
|
||||
asDWORD f;
|
||||
|
||||
asm("fmov.s fr0, %0\n" : "=m"(f));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
// sizeof(double) == 4 with sh-elf-gcc (3.4.0) -m4
|
||||
// so this isn't really used...
|
||||
asQWORD GetReturnedDouble()
|
||||
{
|
||||
asQWORD d;
|
||||
|
||||
asm("fmov dr0, %0\n" : "=m"(d));
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
asQWORD retQW = 0;
|
||||
|
||||
void *func = (void*)sysFunc->func;
|
||||
int paramSize = sysFunc->paramSize;
|
||||
asDWORD *vftable;
|
||||
|
||||
if( descr->returnType.IsObject() && !descr->returnType.IsReference() && !descr->returnType.IsObjectHandle() )
|
||||
{
|
||||
sh4Args[AS_SH4_MAX_ARGS+1] = (asDWORD) retPointer;
|
||||
}
|
||||
|
||||
asASSERT(descr->parameterTypes.GetLength() <= 32);
|
||||
|
||||
// mark all float arguments
|
||||
int argBit = 1;
|
||||
int hostFlags = 0;
|
||||
int intArgs = 0;
|
||||
for( asUINT a = 0; a < descr->parameterTypes.GetLength(); a++ ) {
|
||||
if (descr->parameterTypes[a].IsFloatType()) {
|
||||
hostFlags |= argBit;
|
||||
} else intArgs++;
|
||||
argBit <<= 1;
|
||||
}
|
||||
|
||||
asDWORD paramBuffer[64];
|
||||
if( sysFunc->takesObjByVal )
|
||||
{
|
||||
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() )
|
||||
{
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
|
||||
{
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
paramSize++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+spos));
|
||||
spos++;
|
||||
dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the value directly
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
}
|
||||
// Keep a free location at the beginning
|
||||
args = ¶mBuffer[1];
|
||||
}
|
||||
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_CDECL:
|
||||
case ICC_CDECL_RETURNINMEM:
|
||||
case ICC_STDCALL:
|
||||
case ICC_STDCALL_RETURNINMEM:
|
||||
retQW = CallCDeclFunction(args, paramSize<<2, (asDWORD)func, hostFlags);
|
||||
break;
|
||||
case ICC_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags);
|
||||
break;
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(asDWORD**)obj;
|
||||
retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[asDWORD(func)>>2], hostFlags);
|
||||
break;
|
||||
case ICC_CDECL_OBJLAST:
|
||||
case ICC_CDECL_OBJLAST_RETURNINMEM:
|
||||
retQW = CallThisCallFunction_objLast(obj, args, paramSize<<2, (asDWORD)func, hostFlags);
|
||||
break;
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags);
|
||||
break;
|
||||
default:
|
||||
context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
|
||||
}
|
||||
|
||||
// If the return is a float value we need to get the value from the FP register
|
||||
if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
*(asDWORD*)&retQW = GetReturnedFloat();
|
||||
else
|
||||
retQW = GetReturnedDouble();
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_SH4
|
||||
#endif // AS_MAX_PORTABILITY
|
||||
|
||||
|
||||
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2017 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implements the AMD64 calling convention for gcc-based 64bit Unices
|
||||
*
|
||||
* 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
|
||||
#ifdef AS_X64_GCC
|
||||
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_context.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
enum argTypes { x64INTARG = 0, x64FLOATARG = 1 };
|
||||
typedef asQWORD ( *funcptr_t )( void );
|
||||
|
||||
#define X64_MAX_ARGS 32
|
||||
#define MAX_CALL_INT_REGISTERS 6
|
||||
#define MAX_CALL_SSE_REGISTERS 8
|
||||
#define X64_CALLSTACK_SIZE ( X64_MAX_ARGS + MAX_CALL_SSE_REGISTERS + 3 )
|
||||
|
||||
// Note to self: Always remember to inform the used registers on the clobber line,
|
||||
// so that the gcc optimizer doesn't try to use them for other things
|
||||
|
||||
static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, int cnt, funcptr_t func, asQWORD &retQW2, bool returnFloat)
|
||||
{
|
||||
// Need to flag the variable as volatile so the compiler doesn't optimize out the variable
|
||||
volatile asQWORD retQW1 = 0;
|
||||
|
||||
// Reference: http://www.x86-64.org/documentation/abi.pdf
|
||||
|
||||
__asm__ __volatile__ (
|
||||
|
||||
" movq %0, %%rcx \n" // rcx = cnt
|
||||
" movq %1, %%r10 \n" // r10 = args
|
||||
" movq %2, %%r11 \n" // r11 = func
|
||||
|
||||
// Backup stack pointer in R15 that is guaranteed to maintain its value over function calls
|
||||
" movq %%rsp, %%r15 \n"
|
||||
#ifdef __OPTIMIZE__
|
||||
// Make sure the stack unwind logic knows we've backed up the stack pointer in register r15
|
||||
// This should only be done if any optimization is done. If no optimization (-O0) is used,
|
||||
// then the compiler already backups the rsp before entering the inline assembler code
|
||||
" .cfi_def_cfa_register r15 \n"
|
||||
#endif
|
||||
|
||||
// Skip the first 128 bytes on the stack frame, called "red zone",
|
||||
// that might be used by the compiler to store temporary values
|
||||
" sub $128, %%rsp \n"
|
||||
|
||||
// Make sure the stack pointer will be aligned to 16 bytes when the function is called
|
||||
" movq %%rcx, %%rdx \n"
|
||||
" salq $3, %%rdx \n"
|
||||
" movq %%rsp, %%rax \n"
|
||||
" sub %%rdx, %%rax \n"
|
||||
" and $15, %%rax \n"
|
||||
" sub %%rax, %%rsp \n"
|
||||
|
||||
// Push the stack parameters, i.e. the arguments that won't be loaded into registers
|
||||
" movq %%rcx, %%rsi \n"
|
||||
" testl %%esi, %%esi \n"
|
||||
" jle endstack \n"
|
||||
" subl $1, %%esi \n"
|
||||
" xorl %%edx, %%edx \n"
|
||||
" leaq 8(, %%rsi, 8), %%rcx \n"
|
||||
"loopstack: \n"
|
||||
" movq 112(%%r10, %%rdx), %%rax \n"
|
||||
" pushq %%rax \n"
|
||||
" addq $8, %%rdx \n"
|
||||
" cmpq %%rcx, %%rdx \n"
|
||||
" jne loopstack \n"
|
||||
"endstack: \n"
|
||||
|
||||
// Populate integer and floating point parameters
|
||||
" movq %%r10, %%rax \n"
|
||||
" mov (%%rax), %%rdi \n"
|
||||
" mov 8(%%rax), %%rsi \n"
|
||||
" mov 16(%%rax), %%rdx \n"
|
||||
" mov 24(%%rax), %%rcx \n"
|
||||
" mov 32(%%rax), %%r8 \n"
|
||||
" mov 40(%%rax), %%r9 \n"
|
||||
" add $48, %%rax \n"
|
||||
" movsd (%%rax), %%xmm0 \n"
|
||||
" movsd 8(%%rax), %%xmm1 \n"
|
||||
" movsd 16(%%rax), %%xmm2 \n"
|
||||
" movsd 24(%%rax), %%xmm3 \n"
|
||||
" movsd 32(%%rax), %%xmm4 \n"
|
||||
" movsd 40(%%rax), %%xmm5 \n"
|
||||
" movsd 48(%%rax), %%xmm6 \n"
|
||||
" movsd 56(%%rax), %%xmm7 \n"
|
||||
|
||||
// Call the function
|
||||
" call *%%r11 \n"
|
||||
|
||||
// Restore stack pointer
|
||||
" mov %%r15, %%rsp \n"
|
||||
#ifdef __OPTIMIZE__
|
||||
// Inform the stack unwind logic that the stack pointer has been restored
|
||||
// This should only be done if any optimization is done. If no optimization (-O0) is used,
|
||||
// then the compiler already backups the rsp before entering the inline assembler code
|
||||
" .cfi_def_cfa_register rsp \n"
|
||||
#endif
|
||||
|
||||
// Put return value in retQW1 and retQW2, using either RAX:RDX or XMM0:XMM1 depending on type of return value
|
||||
" movl %5, %%ecx \n"
|
||||
" testb %%cl, %%cl \n"
|
||||
" je intret \n"
|
||||
" lea %3, %%rax \n"
|
||||
" movq %%xmm0, (%%rax) \n"
|
||||
" lea %4, %%rdx \n"
|
||||
" movq %%xmm1, (%%rdx) \n"
|
||||
" jmp endcall \n"
|
||||
"intret: \n"
|
||||
" movq %%rax, %3 \n"
|
||||
" movq %%rdx, %4 \n"
|
||||
"endcall: \n"
|
||||
|
||||
: : "g" ((asQWORD)cnt), "g" (args), "g" (func), "m" (retQW1), "m" (retQW2), "m" (returnFloat)
|
||||
: "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",
|
||||
"%rdi", "%rsi", "%rax", "%rdx", "%rcx", "%r8", "%r9", "%r10", "%r11", "%r15");
|
||||
|
||||
return retQW1;
|
||||
}
|
||||
|
||||
// returns true if the given parameter is a 'variable argument'
|
||||
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, void *secondObject)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
int callConv = sysFunc->callConv;
|
||||
asQWORD retQW = 0;
|
||||
asDWORD *stack_pointer = args;
|
||||
funcptr_t *vftable = NULL;
|
||||
int totalArgumentCount = 0;
|
||||
int n = 0;
|
||||
int param_post = 0;
|
||||
int argIndex = 0;
|
||||
funcptr_t func = (funcptr_t)sysFunc->func;
|
||||
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
{
|
||||
// The return is made in memory
|
||||
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];
|
||||
}
|
||||
|
||||
// Determine the type of the arguments, and prepare the input array for the X64_CallFunction
|
||||
asQWORD paramBuffer[X64_CALLSTACK_SIZE] = { 0 };
|
||||
asBYTE argsType[X64_CALLSTACK_SIZE] = { 0 };
|
||||
|
||||
switch ( callConv )
|
||||
{
|
||||
case ICC_CDECL_RETURNINMEM:
|
||||
case ICC_STDCALL_RETURNINMEM:
|
||||
{
|
||||
paramBuffer[0] = (asPWORD)retPointer;
|
||||
argsType[0] = x64INTARG;
|
||||
|
||||
argIndex = 1;
|
||||
|
||||
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:
|
||||
{
|
||||
paramBuffer[0] = (asPWORD)obj;
|
||||
argsType[0] = x64INTARG;
|
||||
|
||||
argIndex = 1;
|
||||
|
||||
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:
|
||||
{
|
||||
paramBuffer[0] = (asPWORD)retPointer;
|
||||
paramBuffer[1] = (asPWORD)obj;
|
||||
argsType[0] = x64INTARG;
|
||||
argsType[1] = x64INTARG;
|
||||
|
||||
argIndex = 2;
|
||||
|
||||
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;
|
||||
case ICC_CDECL_OBJLAST_RETURNINMEM:
|
||||
{
|
||||
paramBuffer[0] = (asPWORD)retPointer;
|
||||
argsType[0] = x64INTARG;
|
||||
|
||||
argIndex = 1;
|
||||
param_post = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int argumentCount = ( int )descr->parameterTypes.GetLength();
|
||||
for( int a = 0; a < argumentCount; ++a )
|
||||
{
|
||||
const asCDataType &parmType = descr->parameterTypes[a];
|
||||
if( parmType.IsFloatType() && !parmType.IsReference() )
|
||||
{
|
||||
argsType[argIndex] = x64FLOATARG;
|
||||
memcpy(paramBuffer + argIndex, stack_pointer, sizeof(float));
|
||||
argIndex++;
|
||||
stack_pointer++;
|
||||
}
|
||||
else if( parmType.IsDoubleType() && !parmType.IsReference() )
|
||||
{
|
||||
argsType[argIndex] = x64FLOATARG;
|
||||
memcpy(paramBuffer + argIndex, stack_pointer, sizeof(double));
|
||||
argIndex++;
|
||||
stack_pointer += 2;
|
||||
}
|
||||
else if( IsVariableArgument( parmType ) )
|
||||
{
|
||||
// The variable args are really two, one pointer and one type id
|
||||
argsType[argIndex] = x64INTARG;
|
||||
argsType[argIndex+1] = x64INTARG;
|
||||
memcpy(paramBuffer + argIndex, stack_pointer, sizeof(void*));
|
||||
memcpy(paramBuffer + argIndex + 1, stack_pointer + 2, sizeof(asDWORD));
|
||||
argIndex += 2;
|
||||
stack_pointer += 3;
|
||||
}
|
||||
else if( parmType.IsPrimitive() ||
|
||||
parmType.IsReference() ||
|
||||
parmType.IsObjectHandle() )
|
||||
{
|
||||
argsType[argIndex] = x64INTARG;
|
||||
if( parmType.GetSizeOnStackDWords() == 1 )
|
||||
{
|
||||
memcpy(paramBuffer + argIndex, stack_pointer, sizeof(asDWORD));
|
||||
stack_pointer++;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(paramBuffer + argIndex, stack_pointer, sizeof(asQWORD));
|
||||
stack_pointer += 2;
|
||||
}
|
||||
argIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// An object is being passed by value
|
||||
if( (parmType.GetTypeInfo()->flags & COMPLEX_MASK) ||
|
||||
parmType.GetSizeInMemoryDWords() > 4 )
|
||||
{
|
||||
// Copy the address of the object
|
||||
argsType[argIndex] = x64INTARG;
|
||||
memcpy(paramBuffer + argIndex, stack_pointer, sizeof(asQWORD));
|
||||
argIndex++;
|
||||
}
|
||||
else if( (parmType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLINTS) ||
|
||||
(parmType.GetTypeInfo()->flags & asOBJ_APP_PRIMITIVE) )
|
||||
{
|
||||
// Copy the value of the object
|
||||
if( parmType.GetSizeInMemoryDWords() > 2 )
|
||||
{
|
||||
argsType[argIndex] = x64INTARG;
|
||||
argsType[argIndex+1] = x64INTARG;
|
||||
memcpy(paramBuffer + argIndex, *(asDWORD**)stack_pointer, parmType.GetSizeInMemoryBytes());
|
||||
argIndex += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
argsType[argIndex] = x64INTARG;
|
||||
memcpy(paramBuffer + argIndex, *(asDWORD**)stack_pointer, parmType.GetSizeInMemoryBytes());
|
||||
argIndex++;
|
||||
}
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(void**)stack_pointer);
|
||||
}
|
||||
else if( (parmType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) ||
|
||||
(parmType.GetTypeInfo()->flags & asOBJ_APP_FLOAT) )
|
||||
{
|
||||
// Copy the value of the object
|
||||
if( parmType.GetSizeInMemoryDWords() > 2 )
|
||||
{
|
||||
argsType[argIndex] = x64FLOATARG;
|
||||
argsType[argIndex+1] = x64FLOATARG;
|
||||
memcpy(paramBuffer + argIndex, *(asDWORD**)stack_pointer, parmType.GetSizeInMemoryBytes());
|
||||
argIndex += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
argsType[argIndex] = x64FLOATARG;
|
||||
memcpy(paramBuffer + argIndex, *(asDWORD**)stack_pointer, parmType.GetSizeInMemoryBytes());
|
||||
argIndex++;
|
||||
}
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(void**)stack_pointer);
|
||||
}
|
||||
stack_pointer += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// 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++;
|
||||
}
|
||||
|
||||
totalArgumentCount = argIndex;
|
||||
|
||||
/*
|
||||
* Q: WTF is going on here !?
|
||||
*
|
||||
* A: The idea is to pre-arange the parameters so that X64_CallFunction() can do
|
||||
* it's little magic which must work regardless of how the compiler decides to
|
||||
* allocate registers. Basically:
|
||||
* - the first MAX_CALL_INT_REGISTERS entries in tempBuff will
|
||||
* contain the values/types of the x64INTARG parameters - that is the ones who
|
||||
* go into the registers. If the function has less then MAX_CALL_INT_REGISTERS
|
||||
* integer parameters then the last entries will be set to 0
|
||||
* - the next MAX_CALL_SSE_REGISTERS entries will contain the float/double arguments
|
||||
* that go into the floating point registers. If the function has less than
|
||||
* MAX_CALL_SSE_REGISTERS floating point parameters then the last entries will
|
||||
* be set to 0
|
||||
* - index MAX_CALL_INT_REGISTERS + MAX_CALL_SSE_REGISTERS marks the start of the
|
||||
* parameters which will get passed on the stack. These are added to the array
|
||||
* in reverse order so that X64_CallFunction() can simply push them to the stack
|
||||
* without the need to perform further tests
|
||||
*/
|
||||
asQWORD tempBuff[X64_CALLSTACK_SIZE] = { 0 };
|
||||
asBYTE argsSet[X64_CALLSTACK_SIZE] = { 0 };
|
||||
int used_int_regs = 0;
|
||||
int used_sse_regs = 0;
|
||||
int used_stack_args = 0;
|
||||
int idx = 0;
|
||||
for ( n = 0; ( n < totalArgumentCount ) && ( used_int_regs < MAX_CALL_INT_REGISTERS ); n++ )
|
||||
{
|
||||
if ( argsType[n] == x64INTARG )
|
||||
{
|
||||
argsSet[n] = 1;
|
||||
tempBuff[idx++] = paramBuffer[n];
|
||||
used_int_regs++;
|
||||
}
|
||||
}
|
||||
idx = MAX_CALL_INT_REGISTERS;
|
||||
for ( n = 0; ( n < totalArgumentCount ) && ( used_sse_regs < MAX_CALL_SSE_REGISTERS ); n++ )
|
||||
{
|
||||
if ( argsType[n] == x64FLOATARG )
|
||||
{
|
||||
argsSet[n] = 1;
|
||||
tempBuff[idx++] = paramBuffer[n];
|
||||
used_sse_regs++;
|
||||
}
|
||||
}
|
||||
idx = MAX_CALL_INT_REGISTERS + MAX_CALL_SSE_REGISTERS;
|
||||
for ( n = totalArgumentCount - 1; n >= 0; n-- )
|
||||
{
|
||||
if ( !argsSet[n] )
|
||||
{
|
||||
tempBuff[idx++] = paramBuffer[n];
|
||||
used_stack_args++;
|
||||
}
|
||||
}
|
||||
|
||||
retQW = X64_CallFunction( tempBuff, used_stack_args, func, retQW2, sysFunc->hostReturnFloat );
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_X64_GCC
|
||||
#endif // AS_MAX_PORTABILITY
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
//
|
||||
// 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>
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
#ifdef AS_X64_MINGW
|
||||
|
||||
#include "as_callfunc.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_context.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
static asQWORD __attribute__((noinline)) CallX64(const asQWORD *args, const asQWORD *floatArgs, const int paramSize, asQWORD func)
|
||||
{
|
||||
volatile asQWORD ret = 0;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"# Move the parameters into registers before the rsp is modified\n"
|
||||
"mov %1, %%r10\n" // r10 = args
|
||||
"mov %2, %%r11\n" // r11 = floatArgs
|
||||
"xor %%r12, %%r12\n"
|
||||
"mov %3, %%r12d\n"
|
||||
"mov %4, %%r14\n" // r14 = func
|
||||
|
||||
"# Store the stack pointer in r15 since it is guaranteed not to change over a function call\n"
|
||||
"mov %%rsp, %%r15\n"
|
||||
|
||||
"# Allocate space on the stack for the arguments\n"
|
||||
"# Make room for at least 4 arguments even if there are less. When\n"
|
||||
"# the compiler does optimizations for speed it may use these for \n"
|
||||
"# temporary storage.\n"
|
||||
"mov %%r12, %%rdi\n"
|
||||
"add $32,%%edi\n"
|
||||
|
||||
"# Make sure the stack pointer is 16byte aligned so the\n"
|
||||
"# whole program optimizations will work properly\n"
|
||||
"# TODO: runtime optimize: Can this be optimized with fewer instructions?\n"
|
||||
"mov %%rsp,%%rsi\n"
|
||||
"sub %%rdi,%%rsi\n"
|
||||
"and $0x8,%%rsi\n"
|
||||
"add %%rsi,%%rdi\n"
|
||||
"sub %%rdi,%%rsp\n"
|
||||
|
||||
"# Jump straight to calling the function if no parameters\n"
|
||||
"cmp $0,%%r12 # Compare paramSize with 0\n"
|
||||
"je callfunc # Jump to call funtion if (paramSize == 0)\n"
|
||||
|
||||
"# Copy arguments from script stack to application stack\n"
|
||||
"# Order is (first to last):\n"
|
||||
"# rcx, rdx, r8, r9 & everything else goes on stack\n"
|
||||
"movq (%%r10),%%rcx\n"
|
||||
"movq 8(%%r10),%%rdx\n"
|
||||
"movq 16(%%r10),%%r8\n"
|
||||
"movq 24(%%r10),%%r9\n"
|
||||
|
||||
"# Negate the 4 params from the size to be copied\n"
|
||||
"sub $32,%%r12d\n"
|
||||
"js copyfloat # Jump if negative result\n"
|
||||
"jz copyfloat # Jump if zero result\n"
|
||||
|
||||
"# Now copy all remaining params onto stack allowing space for first four\n"
|
||||
"# params to be flushed back to the stack if required by the callee.\n"
|
||||
"add $32,%%r10 # Position input pointer 4 args ahead\n"
|
||||
"mov %%rsp,%%r13 # Put the stack pointer into r13\n"
|
||||
"add $32,%%r13 # Leave space for first 4 args on stack\n"
|
||||
|
||||
"copyoverflow:\n"
|
||||
"movq (%%r10),%%rdi # Read param from source stack into rdi\n"
|
||||
"movq %%rdi,(%%r13) # Copy param to real stack\n"
|
||||
"add $8,%%r13 # Move virtual stack pointer\n"
|
||||
"add $8,%%r10 # Move source stack pointer\n"
|
||||
"sub $8,%%r12d # Decrement remaining count\n"
|
||||
"jnz copyoverflow # Continue if more params\n"
|
||||
|
||||
"copyfloat:\n"
|
||||
"# Any floating point params?\n"
|
||||
"cmp $0,%%r11\n"
|
||||
"je callfunc\n"
|
||||
|
||||
"movlpd (%%r11),%%xmm0\n"
|
||||
"movlpd 8(%%r11),%%xmm1\n"
|
||||
"movlpd 16(%%r11),%%xmm2\n"
|
||||
"movlpd 24(%%r11),%%xmm3\n"
|
||||
|
||||
"callfunc:\n"
|
||||
"call *%%r14\n"
|
||||
|
||||
"# restore stack pointer\n"
|
||||
"mov %%r15, %%rsp\n"
|
||||
|
||||
"lea %0, %%rbx\n" // Load the address of the ret variable into rbx
|
||||
"movq %%rax,(%%rbx)\n" // Copy the returned value into the ret variable
|
||||
|
||||
: // no output
|
||||
: "m" (ret), "r" (args), "r" (floatArgs), "r" (paramSize), "r" (func)
|
||||
: "rdi", "rsi", "rsp", "rbx", "r10", "r11", "%r12", "r13", "r14", "r15"
|
||||
);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static asDWORD GetReturnedFloat()
|
||||
{
|
||||
volatile asDWORD ret = 0;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"lea %0, %%rax\n"
|
||||
"movss %%xmm0, (%%rax)"
|
||||
: /* no output */
|
||||
: "m" (ret)
|
||||
: "%rax"
|
||||
);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static asQWORD GetReturnedDouble()
|
||||
{
|
||||
volatile asQWORD ret = 0;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"lea %0, %%rax\n"
|
||||
"movlpd %%xmm0, (%%rax)"
|
||||
: /* no optput */
|
||||
: "m" (ret)
|
||||
: "%rax"
|
||||
);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
asQWORD retQW = 0;
|
||||
void *func = (void*)sysFunc->func;
|
||||
asUINT paramSize = 0; // QWords
|
||||
void **vftable;
|
||||
|
||||
asQWORD allArgBuffer[64];
|
||||
asQWORD floatArgBuffer[4];
|
||||
|
||||
int callConv = sysFunc->callConv;
|
||||
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
{
|
||||
// The return is made in memory
|
||||
callConv++;
|
||||
|
||||
// Set the return pointer as the first argument
|
||||
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;
|
||||
}
|
||||
|
||||
if( callConv == ICC_CDECL_OBJFIRST ||
|
||||
callConv == ICC_CDECL_OBJFIRST_RETURNINMEM )
|
||||
{
|
||||
// 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;
|
||||
func = vftable[asPWORD(func)>>3];
|
||||
}
|
||||
|
||||
// Move the arguments to the buffer
|
||||
asUINT dpos = paramSize;
|
||||
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() )
|
||||
{
|
||||
if( descr->parameterTypes[n].GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ||
|
||||
(descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK) )
|
||||
{
|
||||
allArgBuffer[dpos++] = *(asQWORD*)&args[spos];
|
||||
spos += AS_PTR_SIZE;
|
||||
paramSize++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy(&allArgBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
|
||||
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+spos));
|
||||
spos += AS_PTR_SIZE;
|
||||
asUINT dwords = descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
asUINT qwords = (dwords >> 1) + (dwords & 1);
|
||||
dpos += qwords;
|
||||
paramSize += qwords;
|
||||
}
|
||||
}
|
||||
else if( descr->parameterTypes[n].GetTokenType() == ttQuestion )
|
||||
{
|
||||
// Copy the reference and the type id
|
||||
allArgBuffer[dpos++] = *(asQWORD*)&args[spos];
|
||||
spos += 2;
|
||||
allArgBuffer[dpos++] = args[spos++];
|
||||
paramSize += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the value directly
|
||||
asUINT dwords = descr->parameterTypes[n].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() )
|
||||
floatArgBuffer[dpos] = *(asQWORD*)&args[spos];
|
||||
|
||||
dpos++;
|
||||
spos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
allArgBuffer[dpos] = args[spos];
|
||||
|
||||
// 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() )
|
||||
floatArgBuffer[dpos] = args[spos];
|
||||
|
||||
dpos++;
|
||||
spos++;
|
||||
}
|
||||
|
||||
paramSize++;
|
||||
}
|
||||
}
|
||||
|
||||
if( callConv == ICC_CDECL_OBJLAST ||
|
||||
callConv == ICC_CDECL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// 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);
|
||||
|
||||
// If the return is a float value we need to get the value from the FP register
|
||||
if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
*(asDWORD*)&retQW = GetReturnedFloat();
|
||||
else
|
||||
retQW = GetReturnedDouble();
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_X64_MSVC
|
||||
#endif // AS_MAX_PORTABILITY
|
||||
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
//
|
||||
// Added support for thiscall methods by Jordi Oliveras Rovira in April, 2014.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
#ifdef AS_X64_MSVC
|
||||
|
||||
#include "as_callfunc.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_context.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// These functions are implemented in as_callfunc_x64_msvc.asm
|
||||
extern "C" asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, int paramSize, asQWORD func);
|
||||
extern "C" asDWORD GetReturnedFloat();
|
||||
extern "C" asQWORD GetReturnedDouble();
|
||||
|
||||
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;
|
||||
|
||||
asQWORD retQW = 0;
|
||||
void *func = (void*)sysFunc->func;
|
||||
asUINT paramSize = 0; // QWords
|
||||
void **vftable;
|
||||
|
||||
asQWORD allArgBuffer[64];
|
||||
asQWORD floatArgBuffer[4];
|
||||
|
||||
int callConv = sysFunc->callConv;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
{
|
||||
// The return is made in memory
|
||||
callConv++;
|
||||
|
||||
// Set the return pointer as the first argument
|
||||
allArgBuffer[paramSize++] = (asQWORD)retPointer;
|
||||
}
|
||||
|
||||
if( callConv == ICC_CDECL_OBJFIRST ||
|
||||
callConv == ICC_CDECL_OBJFIRST_RETURNINMEM )
|
||||
{
|
||||
// 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_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;
|
||||
func = vftable[asPWORD(func)>>2];
|
||||
}
|
||||
|
||||
// Move the arguments to the buffer
|
||||
asUINT dpos = paramSize;
|
||||
asUINT spos = 0;
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
asCDataType &dt = descr->parameterTypes[n];
|
||||
if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() )
|
||||
{
|
||||
if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ||
|
||||
(dt.GetTypeInfo()->flags & COMPLEX_MASK) )
|
||||
{
|
||||
allArgBuffer[dpos++] = *(asQWORD*)&args[spos];
|
||||
spos += AS_PTR_SIZE;
|
||||
paramSize++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy(&allArgBuffer[dpos], *(void**)(args+spos), dt.GetSizeInMemoryBytes());
|
||||
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+spos));
|
||||
spos += AS_PTR_SIZE;
|
||||
asUINT dwords = dt.GetSizeInMemoryDWords();
|
||||
asUINT qwords = (dwords >> 1) + (dwords & 1);
|
||||
dpos += qwords;
|
||||
paramSize += qwords;
|
||||
}
|
||||
}
|
||||
else if( dt.GetTokenType() == ttQuestion )
|
||||
{
|
||||
// Copy the reference and the type id
|
||||
allArgBuffer[dpos++] = *(asQWORD*)&args[spos];
|
||||
spos += 2;
|
||||
allArgBuffer[dpos++] = args[spos++];
|
||||
paramSize += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the value directly
|
||||
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 && dt.IsDoubleType() )
|
||||
floatArgBuffer[dpos] = *(asQWORD*)&args[spos];
|
||||
|
||||
dpos++;
|
||||
spos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
allArgBuffer[dpos] = args[spos];
|
||||
|
||||
// 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 && dt.IsFloatType() )
|
||||
floatArgBuffer[dpos] = args[spos];
|
||||
|
||||
dpos++;
|
||||
spos++;
|
||||
}
|
||||
|
||||
paramSize++;
|
||||
}
|
||||
}
|
||||
|
||||
if( callConv == ICC_CDECL_OBJLAST ||
|
||||
callConv == ICC_CDECL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// 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);
|
||||
|
||||
// If the return is a float value we need to get the value from the FP register
|
||||
if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
*(asDWORD*)&retQW = GetReturnedFloat();
|
||||
else
|
||||
retQW = GetReturnedDouble();
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_X64_MSVC
|
||||
#endif // AS_MAX_PORTABILITY
|
||||
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
;
|
||||
; AngelCode Scripting Library
|
||||
; Copyright (c) 2003-2011 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
|
||||
;
|
||||
|
||||
.code
|
||||
PUBLIC CallX64
|
||||
|
||||
; asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, int paramSize, asQWORD func)
|
||||
|
||||
CallX64 PROC FRAME
|
||||
|
||||
; PROLOG
|
||||
|
||||
; We must save preserved registers that are used
|
||||
; TODO: No need to save unused registers
|
||||
|
||||
push rbp
|
||||
.pushreg rbp
|
||||
push rsi
|
||||
.pushreg rsi
|
||||
push r11
|
||||
.pushreg r11
|
||||
push rdi
|
||||
.pushreg rdi
|
||||
push r12
|
||||
.pushreg r12
|
||||
push r13
|
||||
.pushreg r13
|
||||
push r14
|
||||
.pushreg r14
|
||||
push r15
|
||||
.pushreg r15
|
||||
push rbx
|
||||
.pushreg rbx
|
||||
sub rsp, 050h
|
||||
.allocstack 050h
|
||||
mov rbp, rsp
|
||||
.setframe rbp, 0
|
||||
.endprolog
|
||||
|
||||
; Move function param to non-scratch register
|
||||
mov r14, r9 ; r14 = function
|
||||
|
||||
; Allocate space on the stack for the arguments
|
||||
; Make room for at least 4 arguments even if there are less. When
|
||||
; the compiler does optimizations for speed it may use these for
|
||||
; temporary storage.
|
||||
mov rdi, r8
|
||||
add rdi, 32
|
||||
|
||||
; Make sure the stack pointer is 16byte aligned so the
|
||||
; whole program optimizations will work properly
|
||||
; TODO: optimize: Can this be optimized with fewer instructions?
|
||||
mov rsi, rsp
|
||||
sub rsi, rdi
|
||||
and rsi, 8h
|
||||
add rdi, rsi
|
||||
sub rsp, rdi
|
||||
|
||||
; Jump straight to calling the function if no parameters
|
||||
cmp r8d, 0 ; Compare paramSize with 0
|
||||
je callfunc ; Jump to call funtion if (paramSize == 0)
|
||||
|
||||
; Move params to non-scratch registers
|
||||
mov rsi, rcx ; rsi = pArgs
|
||||
mov r11, rdx ; r11 = pFloatArgs (can be NULL)
|
||||
mov r12d, r8d ; r12 = paramSize
|
||||
|
||||
; Copy arguments from script stack to application stack
|
||||
; Order is (first to last):
|
||||
; rcx, rdx, r8, r9 & everything else goes on stack
|
||||
mov rcx, qword ptr [rsi]
|
||||
mov rdx, qword ptr [rsi + 8]
|
||||
mov r8, qword ptr [rsi + 16]
|
||||
mov r9, qword ptr [rsi + 24]
|
||||
|
||||
; Negate the 4 params from the size to be copied
|
||||
sub r12d, 32
|
||||
js copyfloat ; Jump if negative result
|
||||
jz copyfloat ; Jump if zero result
|
||||
|
||||
; Now copy all remaining params onto stack allowing space for first four
|
||||
; params to be flushed back to the stack if required by the callee.
|
||||
|
||||
add rsi, 32 ; Position input pointer 4 args ahead
|
||||
mov r13, rsp ; Put the stack pointer into r13
|
||||
add r13, 32 ; Leave space for first 4 args on stack
|
||||
|
||||
copyoverflow:
|
||||
mov r15, qword ptr [rsi] ; Read param from source stack into r15
|
||||
mov qword ptr [r13], r15 ; Copy param to real stack
|
||||
add r13, 8 ; Move virtual stack pointer
|
||||
add rsi, 8 ; Move source stack pointer
|
||||
sub r12d, 8 ; Decrement remaining count
|
||||
jnz copyoverflow ; Continue if more params
|
||||
|
||||
copyfloat:
|
||||
; Any floating point params?
|
||||
cmp r11, 0
|
||||
je callfunc
|
||||
|
||||
movlpd xmm0, qword ptr [r11]
|
||||
movlpd xmm1, qword ptr [r11 + 8]
|
||||
movlpd xmm2, qword ptr [r11 + 16]
|
||||
movlpd xmm3, qword ptr [r11 + 24]
|
||||
|
||||
callfunc:
|
||||
|
||||
; Call function
|
||||
call r14
|
||||
|
||||
; Restore the stack
|
||||
mov rsp, rbp
|
||||
|
||||
; EPILOG: Restore stack & preserved registers
|
||||
add rsp, 050h
|
||||
pop rbx
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rdi
|
||||
pop r11
|
||||
pop rsi
|
||||
pop rbp
|
||||
|
||||
; return value in RAX
|
||||
ret
|
||||
|
||||
CallX64 ENDP
|
||||
|
||||
|
||||
PUBLIC GetReturnedFloat
|
||||
|
||||
; asDWORD GetReturnedFloat()
|
||||
|
||||
GetReturnedFloat PROC FRAME
|
||||
|
||||
; PROLOG: Store registers and allocate stack space
|
||||
|
||||
sub rsp, 8 ; We'll need 4 bytes for temporary storage (8 bytes with alignment)
|
||||
.allocstack 8
|
||||
.endprolog
|
||||
|
||||
; Move the float value from the XMM0 register to RAX register
|
||||
movss dword ptr [rsp], xmm0
|
||||
mov eax, dword ptr [rsp]
|
||||
|
||||
; EPILOG: Clean up
|
||||
|
||||
add rsp, 8
|
||||
|
||||
ret
|
||||
|
||||
GetReturnedFloat ENDP
|
||||
|
||||
|
||||
PUBLIC GetReturnedDouble
|
||||
|
||||
; asDWORD GetReturnedDouble()
|
||||
|
||||
GetReturnedDouble PROC FRAME
|
||||
|
||||
; PROLOG: Store registers and allocate stack space
|
||||
|
||||
sub rsp, 8 ; We'll need 8 bytes for temporary storage
|
||||
.allocstack 8
|
||||
.endprolog
|
||||
|
||||
; Move the double value from the XMM0 register to the RAX register
|
||||
movlpd qword ptr [rsp], xmm0
|
||||
mov rax, qword ptr [rsp]
|
||||
|
||||
; EPILOG: Clean up
|
||||
|
||||
add rsp, 8
|
||||
|
||||
ret
|
||||
|
||||
GetReturnedDouble ENDP
|
||||
|
||||
END
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,737 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_callfunc_xenon.cpp
|
||||
//
|
||||
// These functions handle the actual calling of system functions
|
||||
//
|
||||
// This version is Xenon specific
|
||||
// Modified from as_callfunc_ppc.cpp by Laszlo Perneky February 2007
|
||||
//
|
||||
// Modified by Cyril Tissier March 2010:
|
||||
// various fixes in 'float' args passing / function return
|
||||
// properly handling 'double' type
|
||||
// various fixes in asm ppcFunc
|
||||
// fix for variable arguments
|
||||
//
|
||||
// Modified by Anthony Clark May 2015
|
||||
// Fixed the issue where int64 and uint64 could not be passed nativly
|
||||
// few minor fixes within asm ppcFunc to handle int64 and uint64
|
||||
|
||||
|
||||
// XBox 360 calling convention
|
||||
// ===========================
|
||||
// I've yet to find an official document with the ABI for XBox 360,
|
||||
// but I'll describe what I've gathered from the code and tests
|
||||
// performed by the AngelScript community.
|
||||
//
|
||||
// Arguments are passed in the following registers:
|
||||
// r3 - r10 : integer/pointer arguments (each register is 64bit)
|
||||
// fr1 - fr13 : float/double arguments (each register is 64bit)
|
||||
//
|
||||
// Arguments that don't fit in the registers will be pushed on the stack.
|
||||
//
|
||||
// When a float or double is passed as argument, its value will be placed
|
||||
// in the next available float register, but it will also reserve general
|
||||
// purpose register.
|
||||
//
|
||||
// Example: void foo(float a, int b). a will be passed in fr1 and b in r4.
|
||||
//
|
||||
// For each argument passed to a function an 8byte slot is reserved on the
|
||||
// stack, so that the function can offload the value there if needed. The
|
||||
// first slot is at r1+20, the next at r1+28, etc.
|
||||
//
|
||||
// If the function is a class method, the this pointer is passed as hidden
|
||||
// first argument. If the function returns an object in memory, the address
|
||||
// for that memory is passed as hidden first argument.
|
||||
//
|
||||
// Return value are placed in the following registers:
|
||||
// r3 : integer/pointer values
|
||||
// fr1 : float/double values
|
||||
//
|
||||
// Rules for registers
|
||||
// r1 : stack pointer
|
||||
// r14-r31 : nonvolatile, i.e. their values must be preserved
|
||||
// fr14-fr31 : nonvolatile, i.e. their values must be preserved
|
||||
// r0, r2, r13 : dedicated. I'm not sure what it means, but it is probably best not to use them
|
||||
//
|
||||
// The stack pointer must always be aligned at 8 bytes.
|
||||
//
|
||||
// References:
|
||||
// https://www-01.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF77852569970071B0D6/$file/eabi_app.pdf
|
||||
//
|
||||
// TODO: The code doesn't handle objects passed by value (unless they are max 4 bytes in size)
|
||||
|
||||
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
#if defined(AS_XENON)
|
||||
|
||||
#include "as_callfunc.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_tokendef.h"
|
||||
#include "as_context.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <xtl.h>
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
#define AS_PPC_MAX_ARGS 32
|
||||
#define AS_PPC_THISCALL_REG 1
|
||||
#define AS_PPC_RETURNINMEM_REG 1
|
||||
#define AS_PPC_ENDOFARGS 1
|
||||
|
||||
// The array used to send values to the correct places.
|
||||
// Contains a byte of argTypes to indicate the register type to load, or zero if end of arguments
|
||||
enum argTypes
|
||||
{
|
||||
ppcENDARG = 0,
|
||||
ppcINTARG = 1,
|
||||
ppcFLOATARG = 2,
|
||||
ppcDOUBLEARG = 3
|
||||
};
|
||||
|
||||
// Loads all data into the correct places and calls the function.
|
||||
// pArgs is the array of the argument values
|
||||
// pArgTypes is an array containing a byte indicating the type (enum argTypes) for each argument.
|
||||
// dwFunc is the address of the function that will be called
|
||||
asQWORD __declspec( naked ) ppcFunc(const asQWORD* pArgs, asDWORD dwFunc, const asBYTE* pArgTypes)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
_ppcFunc:
|
||||
// Prologue
|
||||
// Read and stack the link register (return address)
|
||||
mflr r12
|
||||
stw r12,-8(r1)
|
||||
|
||||
// Backup all non-volatile registers we use in this function
|
||||
std r31,-10h(r1) // stack pointer for pushing arguments
|
||||
std r27,-18h(r1) // dwFunc
|
||||
std r26,-20h(r1) // pArgs
|
||||
std r25,-28h(r1) // pArgTypes
|
||||
std r24,-30h(r1) // current arg type
|
||||
std r23,-38h(r1) // counter for used GPRs
|
||||
std r22,-40h(r1) // counter for used float registers
|
||||
|
||||
// Setup the stack frame to make room for the backup of registers
|
||||
// and the arguments that will be passed to the application function.
|
||||
// 512 bytes is enough for about 50 arguments plus backup of 8
|
||||
// TODO: Should perhaps make this dynamic based on number of arguments
|
||||
stwu r1,-200h(r1)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Initialize local variables
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// r31 is our pointer into the stack where the arguments will be place
|
||||
// The MSVC optimizer seems to rely on nobody copying the r1 register directly
|
||||
// so we can't just do a simple 'addi r31, r1, 14h' as the optimizer may
|
||||
// end up moving this instruction to before the update of r1 above.
|
||||
// Instead we'll read the previous stack pointer from the stack, and then
|
||||
// subtract to get the correct offset.
|
||||
lwz r31, 0(r1)
|
||||
subi r31, r31, 1ECh // prev r1 - 512 + 20 = curr r1 + 20
|
||||
|
||||
mr r26, r3 // pArgs
|
||||
mr r27, r4 // dwFunc
|
||||
mr r25, r5 // pArgTypes
|
||||
|
||||
// Counting of used/assigned GPR's
|
||||
sub r23, r23, r23
|
||||
// Counting of used/assigned Float Registers
|
||||
sub r22, r22, r22
|
||||
|
||||
// Begin loading and stacking registers
|
||||
subi r25, r25, 1
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Fetch the next argument
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ppcNextArg:
|
||||
// Increment rArgTypePtr
|
||||
addi r25, r25, 1
|
||||
// Get data type
|
||||
lbz r24, 0(r25)
|
||||
|
||||
// r24 holds the data type
|
||||
cmplwi cr6, r24, 0
|
||||
beq cr6, ppcArgsEnd
|
||||
cmplwi cr6, r24, 1
|
||||
beq cr6, ppcArgIsInteger
|
||||
cmplwi cr6, r24, 2
|
||||
beq cr6, ppcArgIsFloat
|
||||
cmplwi cr6, r24, 3
|
||||
beq cr6, ppcArgIsDouble
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Load and stack integer arguments
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ppcArgIsInteger:
|
||||
// Get the arg from the stack
|
||||
ld r12, 0(r26)
|
||||
|
||||
// r23 holds the integer arg count so far
|
||||
cmplwi cr6, r23, 0
|
||||
beq cr6, ppcLoadIntReg0
|
||||
cmplwi cr6, r23, 1
|
||||
beq cr6, ppcLoadIntReg1
|
||||
cmplwi cr6, r23, 2
|
||||
beq cr6, ppcLoadIntReg2
|
||||
cmplwi cr6, r23, 3
|
||||
beq cr6, ppcLoadIntReg3
|
||||
cmplwi cr6, r23, 4
|
||||
beq cr6, ppcLoadIntReg4
|
||||
cmplwi cr6, r23, 5
|
||||
beq cr6, ppcLoadIntReg5
|
||||
cmplwi cr6, r23, 6
|
||||
beq cr6, ppcLoadIntReg6
|
||||
cmplwi cr6, r23, 7
|
||||
beq cr6, ppcLoadIntReg7
|
||||
|
||||
// no more than 8 parameters
|
||||
b ppcLoadIntRegUpd
|
||||
|
||||
ppcLoadIntReg0:
|
||||
mr r3, r12
|
||||
b ppcLoadIntRegUpd
|
||||
ppcLoadIntReg1:
|
||||
mr r4, r12
|
||||
b ppcLoadIntRegUpd
|
||||
ppcLoadIntReg2:
|
||||
mr r5, r12
|
||||
b ppcLoadIntRegUpd
|
||||
ppcLoadIntReg3:
|
||||
mr r6, r12
|
||||
b ppcLoadIntRegUpd
|
||||
ppcLoadIntReg4:
|
||||
mr r7, r12
|
||||
b ppcLoadIntRegUpd
|
||||
ppcLoadIntReg5:
|
||||
mr r8, r12
|
||||
b ppcLoadIntRegUpd
|
||||
ppcLoadIntReg6:
|
||||
mr r9, r12
|
||||
b ppcLoadIntRegUpd
|
||||
ppcLoadIntReg7:
|
||||
mr r10, r12
|
||||
b ppcLoadIntRegUpd
|
||||
|
||||
ppcLoadIntRegUpd:
|
||||
std r12, 0(r31) // push on the stack
|
||||
addi r31, r31, 8 // inc stack by 1 reg
|
||||
|
||||
addi r23, r23, 1 // Increment used int register count
|
||||
addi r26, r26, 8 // Increment pArgs
|
||||
b ppcNextArg // Call next arg
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Load and stack float arguments
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ppcArgIsFloat:
|
||||
// Get the arg from the stack
|
||||
lfs fr0, 0(r26)
|
||||
|
||||
// r22 holds the float arg count so far
|
||||
cmplwi cr6, r22, 0
|
||||
beq cr6, ppcLoadFloatReg0
|
||||
cmplwi cr6, r22, 1
|
||||
beq cr6, ppcLoadFloatReg1
|
||||
cmplwi cr6, r22, 2
|
||||
beq cr6, ppcLoadFloatReg2
|
||||
cmplwi cr6, r22, 3
|
||||
beq cr6, ppcLoadFloatReg3
|
||||
cmplwi cr6, r22, 4
|
||||
beq cr6, ppcLoadFloatReg4
|
||||
cmplwi cr6, r22, 5
|
||||
beq cr6, ppcLoadFloatReg5
|
||||
cmplwi cr6, r22, 6
|
||||
beq cr6, ppcLoadFloatReg6
|
||||
cmplwi cr6, r22, 7
|
||||
beq cr6, ppcLoadFloatReg7
|
||||
cmplwi cr6, r22, 8
|
||||
beq cr6, ppcLoadFloatReg8
|
||||
cmplwi cr6, r22, 9
|
||||
beq cr6, ppcLoadFloatReg9
|
||||
cmplwi cr6, r22, 10
|
||||
beq cr6, ppcLoadFloatReg10
|
||||
cmplwi cr6, r22, 11
|
||||
beq cr6, ppcLoadFloatReg11
|
||||
cmplwi cr6, r22, 12
|
||||
beq cr6, ppcLoadFloatReg12
|
||||
|
||||
// no more than 12 parameters
|
||||
b ppcLoadFloatRegUpd
|
||||
|
||||
ppcLoadFloatReg0:
|
||||
fmr fr1, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
ppcLoadFloatReg1:
|
||||
fmr fr2, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
ppcLoadFloatReg2:
|
||||
fmr fr3, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
ppcLoadFloatReg3:
|
||||
fmr fr4, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
ppcLoadFloatReg4:
|
||||
fmr fr5, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
ppcLoadFloatReg5:
|
||||
fmr fr6, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
ppcLoadFloatReg6:
|
||||
fmr fr7, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
ppcLoadFloatReg7:
|
||||
fmr fr8, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
ppcLoadFloatReg8:
|
||||
fmr fr9, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
ppcLoadFloatReg9:
|
||||
fmr fr10, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
ppcLoadFloatReg10:
|
||||
fmr fr11, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
ppcLoadFloatReg11:
|
||||
fmr fr12, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
ppcLoadFloatReg12:
|
||||
fmr fr13, fr0
|
||||
b ppcLoadFloatRegUpd
|
||||
|
||||
ppcLoadFloatRegUpd:
|
||||
stfs fr0, 0(r31) // push on the stack
|
||||
addi r31, r31, 8 // inc stack by 1 reg
|
||||
|
||||
addi r22, r22, 1 // Increment used float register count
|
||||
addi r23, r23, 1 // Increment used int register count - a float reg eats up a GPR
|
||||
addi r26, r26, 4 // Increment pArgs
|
||||
b ppcNextArg // Call next arg
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Load and stack double float arguments
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ppcArgIsDouble:
|
||||
// Get the arg from the stack
|
||||
lfd fr0, 0(r26)
|
||||
|
||||
// r22 holds the float arg count so far
|
||||
cmplwi cr6, r22, 0
|
||||
beq cr6, ppcLoadDoubleReg0
|
||||
cmplwi cr6, r22, 1
|
||||
beq cr6, ppcLoadDoubleReg1
|
||||
cmplwi cr6, r22, 2
|
||||
beq cr6, ppcLoadDoubleReg2
|
||||
cmplwi cr6, r22, 3
|
||||
beq cr6, ppcLoadDoubleReg3
|
||||
cmplwi cr6, r22, 4
|
||||
beq cr6, ppcLoadDoubleReg4
|
||||
cmplwi cr6, r22, 5
|
||||
beq cr6, ppcLoadDoubleReg5
|
||||
cmplwi cr6, r22, 6
|
||||
beq cr6, ppcLoadDoubleReg6
|
||||
cmplwi cr6, r22, 7
|
||||
beq cr6, ppcLoadDoubleReg7
|
||||
cmplwi cr6, r22, 8
|
||||
beq cr6, ppcLoadDoubleReg8
|
||||
cmplwi cr6, r22, 9
|
||||
beq cr6, ppcLoadDoubleReg9
|
||||
cmplwi cr6, r22, 10
|
||||
beq cr6, ppcLoadDoubleReg10
|
||||
cmplwi cr6, r22, 11
|
||||
beq cr6, ppcLoadDoubleReg11
|
||||
cmplwi cr6, r22, 12
|
||||
beq cr6, ppcLoadDoubleReg12
|
||||
|
||||
// no more than 12 parameters
|
||||
b ppcLoadDoubleRegUpd
|
||||
|
||||
ppcLoadDoubleReg0:
|
||||
fmr fr1, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
ppcLoadDoubleReg1:
|
||||
fmr fr2, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
ppcLoadDoubleReg2:
|
||||
fmr fr3, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
ppcLoadDoubleReg3:
|
||||
fmr fr4, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
ppcLoadDoubleReg4:
|
||||
fmr fr5, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
ppcLoadDoubleReg5:
|
||||
fmr fr6, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
ppcLoadDoubleReg6:
|
||||
fmr fr7, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
ppcLoadDoubleReg7:
|
||||
fmr fr8, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
ppcLoadDoubleReg8:
|
||||
fmr fr9, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
ppcLoadDoubleReg9:
|
||||
fmr fr10, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
ppcLoadDoubleReg10:
|
||||
fmr fr11, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
ppcLoadDoubleReg11:
|
||||
fmr fr12, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
ppcLoadDoubleReg12:
|
||||
fmr fr13, fr0
|
||||
b ppcLoadDoubleRegUpd
|
||||
|
||||
ppcLoadDoubleRegUpd:
|
||||
stfd fr0, 0(r31) // push on the stack
|
||||
addi r31, r31, 8 // inc stack by 1 reg
|
||||
|
||||
addi r22, r22, 1 // Increment used float register count
|
||||
addi r23, r23, 1 // Increment used int register count
|
||||
addi r26, r26, 8 // Increment pArgs
|
||||
b ppcNextArg
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Finished
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ppcArgsEnd:
|
||||
// Call the function
|
||||
mtctr r27
|
||||
bctrl
|
||||
|
||||
// Epilogue
|
||||
// Restore callers stack
|
||||
addi r1, r1, 200h
|
||||
|
||||
// restore all registers we used in this fct
|
||||
ld r22,-40h(r1)
|
||||
ld r23,-38h(r1)
|
||||
ld r24,-30h(r1)
|
||||
ld r25,-28h(r1)
|
||||
ld r26,-20h(r1)
|
||||
ld r27,-18h(r1)
|
||||
ld r31,-10h(r1)
|
||||
|
||||
// Fetch return link to caller
|
||||
lwz r12,-8(r1)
|
||||
mtlr r12
|
||||
blr
|
||||
}
|
||||
}
|
||||
|
||||
asDWORD GetReturnedFloat()
|
||||
{
|
||||
// This variable must be declared volatile so that the
|
||||
// compiler optimizations do not remove its initialization
|
||||
// with the fr1 register due to believing the fr1 register
|
||||
// isn't initialized.
|
||||
volatile asDWORD f;
|
||||
|
||||
__asm
|
||||
{
|
||||
stfs fr1, f
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
asQWORD GetReturnedDouble()
|
||||
{
|
||||
// This variable must be declared volatile so that the
|
||||
// compiler optimizations do not remove its initialization
|
||||
// with the fr1 register due to believing the fr1 register
|
||||
// isn't initialized.
|
||||
volatile asQWORD f;
|
||||
|
||||
__asm
|
||||
{
|
||||
stfd fr1, f
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
// returns true if the given parameter is a 'variable argument'
|
||||
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*/, void */*secondObject*/)
|
||||
{
|
||||
// TODO: Xenon does not yet support THISCALL_OBJFIRST/LAST
|
||||
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
int callConv = sysFunc->callConv;
|
||||
asQWORD retQW = 0;
|
||||
void *func = (void*)sysFunc->func;
|
||||
asDWORD *vftable;
|
||||
|
||||
// Pack the arguments into an array that ppcFunc() can use to load each CPU register properly
|
||||
asBYTE ppcArgsType[AS_PPC_MAX_ARGS + AS_PPC_RETURNINMEM_REG + AS_PPC_THISCALL_REG + AS_PPC_ENDOFARGS];
|
||||
asQWORD ppcArgs[AS_PPC_MAX_ARGS + AS_PPC_RETURNINMEM_REG + AS_PPC_THISCALL_REG];
|
||||
int argsCnt = 0;
|
||||
|
||||
// If the function returns an object in memory, we allocate the memory and put the ptr to the front (will go to r3)
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
{
|
||||
ppcArgs[argsCnt] = (asDWORD)retPointer;
|
||||
ppcArgsType[argsCnt] = ppcINTARG;
|
||||
argsCnt++;
|
||||
}
|
||||
|
||||
// If we have an object and it's not objectlast, then we put it as the first arg
|
||||
if ( obj &&
|
||||
callConv != ICC_CDECL_OBJLAST &&
|
||||
callConv != ICC_CDECL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
ppcArgs[argsCnt] = (asDWORD)obj;
|
||||
ppcArgsType[argsCnt] = ppcINTARG;
|
||||
argsCnt++;
|
||||
}
|
||||
|
||||
// If the function takes any objects by value, they must be copied
|
||||
// to the stack, shifting the other arguments as necessary. paramBuffer
|
||||
// will then replace the args pointer that was received from the VM.
|
||||
// TODO: Is this really how XBox 360 passes objects by value?
|
||||
asDWORD paramBuffer[AS_PPC_MAX_ARGS];
|
||||
if( sysFunc->takesObjByVal )
|
||||
{
|
||||
int paramSize = 0;
|
||||
int spos = 0;
|
||||
int dpos = 1;
|
||||
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
// Parameter object by value
|
||||
if( descr->parameterTypes[n].IsObject() &&
|
||||
!descr->parameterTypes[n].IsObjectHandle() &&
|
||||
!descr->parameterTypes[n].IsReference() )
|
||||
{
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
|
||||
{
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
paramSize++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy( ¶mBuffer[dpos], *(void**)(args + spos), descr->parameterTypes[n].GetSizeInMemoryBytes() );
|
||||
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args + spos));
|
||||
|
||||
spos++;
|
||||
dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the value directly
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
|
||||
// If this was a variable argument parameter, then account for the implicit typeId
|
||||
if( IsVariableArgument( descr->parameterTypes[n] ) )
|
||||
{
|
||||
// the TypeId is just a DWORD
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
++paramSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep a free location at the beginning
|
||||
args = ¶mBuffer[1];
|
||||
|
||||
asASSERT( paramSize <= AS_PPC_MAX_ARGS );
|
||||
}
|
||||
|
||||
|
||||
const asUINT paramCount = (asUINT)descr->parameterTypes.GetLength();
|
||||
|
||||
asBYTE * pCurArgType = (asBYTE*)&ppcArgsType[argsCnt];
|
||||
asBYTE * pCurFixedArgValue = (asBYTE*)&ppcArgs[argsCnt];
|
||||
asBYTE * pCurStackArgValue = (asBYTE*)args;
|
||||
|
||||
for( asUINT n = 0; n < paramCount; n++ )
|
||||
{
|
||||
argsCnt++;
|
||||
|
||||
if (descr->parameterTypes[n].IsFloatType() && !descr->parameterTypes[n].IsReference())
|
||||
{
|
||||
*pCurArgType++ = ppcFLOATARG;
|
||||
|
||||
*((float*) pCurFixedArgValue) = *((float*) pCurStackArgValue);
|
||||
|
||||
pCurFixedArgValue += 4;
|
||||
pCurStackArgValue += 4;
|
||||
}
|
||||
else if (descr->parameterTypes[n].IsDoubleType() && !descr->parameterTypes[n].IsReference())
|
||||
{
|
||||
*pCurArgType++ = ppcDOUBLEARG;
|
||||
|
||||
*((double*) pCurFixedArgValue) = *((double*) pCurStackArgValue);
|
||||
|
||||
pCurFixedArgValue += 8;
|
||||
pCurStackArgValue += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: The code also ignore the fact that large objects
|
||||
// passed by value has been copied to the stack
|
||||
// in the above loop.
|
||||
|
||||
*pCurArgType++ = ppcINTARG;
|
||||
|
||||
*((asQWORD*) pCurFixedArgValue) = *((asUINT*) pCurStackArgValue);
|
||||
|
||||
if( !descr->parameterTypes[n].IsReference() )
|
||||
{
|
||||
// If the arg is not 4 bytes which we coppied, lets do it again the right way
|
||||
asUINT numBytes = descr->parameterTypes[n].GetSizeInMemoryBytes();
|
||||
if( numBytes == 1 )
|
||||
{
|
||||
*((asQWORD*) pCurFixedArgValue) = *((asBYTE*) pCurStackArgValue);
|
||||
}
|
||||
else if( numBytes == 2 )
|
||||
{
|
||||
*((asQWORD*) pCurFixedArgValue) = *((asWORD*) pCurStackArgValue);
|
||||
}
|
||||
else if( numBytes == 8 )
|
||||
{
|
||||
*((asQWORD*) pCurFixedArgValue) = *((asQWORD*) pCurStackArgValue);
|
||||
pCurStackArgValue += 4; // Increase our cur stack arg value by 4 bytes to = 8 total later
|
||||
}
|
||||
}
|
||||
|
||||
pCurFixedArgValue += 8;
|
||||
pCurStackArgValue += 4;
|
||||
|
||||
// if it is a variable argument, account for the typeId
|
||||
// implicitly add another parameter (AFTER the parameter above) for the typeId
|
||||
if( IsVariableArgument(descr->parameterTypes[n]) )
|
||||
{
|
||||
argsCnt++;
|
||||
|
||||
*pCurArgType++ = ppcINTARG;
|
||||
|
||||
*((int*) pCurFixedArgValue) = *((int*) pCurStackArgValue);
|
||||
|
||||
pCurFixedArgValue += 4;
|
||||
pCurStackArgValue += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the arg list end indicator
|
||||
ppcArgsType[argsCnt] = ppcENDARG;
|
||||
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_CDECL:
|
||||
case ICC_CDECL_RETURNINMEM:
|
||||
case ICC_STDCALL:
|
||||
case ICC_STDCALL_RETURNINMEM:
|
||||
case ICC_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
{
|
||||
retQW = ppcFunc( ppcArgs, (asDWORD)func, ppcArgsType );
|
||||
break;
|
||||
}
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
{
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(asDWORD**)obj;
|
||||
retQW = ppcFunc( ppcArgs, vftable[asDWORD(func)>>2], ppcArgsType );
|
||||
break;
|
||||
}
|
||||
case ICC_CDECL_OBJLAST:
|
||||
case ICC_CDECL_OBJLAST_RETURNINMEM:
|
||||
{
|
||||
// Add the object pointer as the last argument
|
||||
ppcArgsType[argsCnt++] = ppcINTARG;
|
||||
ppcArgsType[argsCnt] = ppcENDARG;
|
||||
*((asQWORD*)pCurFixedArgValue) = (asPWORD)obj;
|
||||
retQW = ppcFunc( ppcArgs, (asDWORD)func, ppcArgsType );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
context->SetInternalException( TXT_INVALID_CALLING_CONVENTION );
|
||||
}
|
||||
|
||||
// If the return is a float value we need to get the value from the FP register
|
||||
if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
*(asDWORD*)&retQW = GetReturnedFloat();
|
||||
else
|
||||
retQW = GetReturnedDouble();
|
||||
}
|
||||
else if( sysFunc->hostReturnSize == 1 )
|
||||
{
|
||||
// Move the bits to the higher value to compensate for the adjustment that the caller does
|
||||
retQW <<= 32;
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_XENON
|
||||
#endif // AS_MAX_PORTABILITY
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2020 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_compiler.h
|
||||
//
|
||||
// The class that does the actual compilation of the functions
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_COMPILER_H
|
||||
#define AS_COMPILER_H
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
|
||||
#include "as_builder.h"
|
||||
#include "as_scriptfunction.h"
|
||||
#include "as_variablescope.h"
|
||||
#include "as_bytecode.h"
|
||||
#include "as_array.h"
|
||||
#include "as_datatype.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// This class represents the value of an expression as evaluated by the compiler.
|
||||
// It holds information such as the type of the value, stack offset for a local
|
||||
// variable, value of constants, whether the value can be modified (i.e. lvalue), etc.
|
||||
struct asCExprValue
|
||||
{
|
||||
asCExprValue();
|
||||
void Set(const asCDataType &dataType);
|
||||
|
||||
void SetVariable(const asCDataType &dataType, int stackOffset, bool isTemporary);
|
||||
void SetConstantB(const asCDataType &dataType, asBYTE value);
|
||||
void SetConstantQW(const asCDataType &dataType, asQWORD value);
|
||||
void SetConstantDW(const asCDataType &dataType, asDWORD value);
|
||||
void SetConstantW(const asCDataType &dataType, asWORD value);
|
||||
void SetConstantF(const asCDataType &dataType, float value);
|
||||
void SetConstantD(const asCDataType &dataType, double value);
|
||||
void SetConstantB(asBYTE value);
|
||||
void SetConstantW(asWORD value);
|
||||
void SetConstantQW(asQWORD value);
|
||||
void SetConstantDW(asDWORD value);
|
||||
void SetConstantF(float value);
|
||||
void SetConstantD(double value);
|
||||
asBYTE GetConstantB();
|
||||
asWORD GetConstantW();
|
||||
asQWORD GetConstantQW();
|
||||
asDWORD GetConstantDW();
|
||||
float GetConstantF();
|
||||
double GetConstantD();
|
||||
|
||||
void SetConstantData(const asCDataType &dataType, asQWORD value);
|
||||
asQWORD GetConstantData();
|
||||
|
||||
void SetNullConstant();
|
||||
void SetUndefinedFuncHandle(asCScriptEngine *engine);
|
||||
void SetVoid();
|
||||
void SetDummy();
|
||||
|
||||
bool IsUndefinedFuncHandle() const;
|
||||
bool IsNullConstant() const;
|
||||
bool IsVoid() const;
|
||||
|
||||
asCDataType dataType;
|
||||
bool isLValue : 1; // Can this value be updated in assignment, or increment operators, etc
|
||||
bool isTemporary : 1;
|
||||
bool isConstant : 1;
|
||||
bool isVariable : 1;
|
||||
bool isExplicitHandle : 1;
|
||||
bool isRefToLocal : 1; // The reference may be to a local variable
|
||||
bool isRefSafe : 1; // the life-time of the ref is guaranteed for the duration of the access
|
||||
short dummy : 9;
|
||||
short stackOffset;
|
||||
|
||||
private:
|
||||
// These values must not be accessed directly in order to avoid problems with endianess.
|
||||
// Use the appropriate accessor methods instead
|
||||
union
|
||||
{
|
||||
asQWORD qwordValue;
|
||||
double doubleValue;
|
||||
asDWORD dwordValue;
|
||||
float floatValue;
|
||||
asWORD wordValue;
|
||||
asBYTE byteValue;
|
||||
};
|
||||
};
|
||||
|
||||
struct asCExprContext;
|
||||
|
||||
// This class holds information for arguments that needs to be
|
||||
// cleaned up after the result of a function has been evaluated.
|
||||
struct asSDeferredParam
|
||||
{
|
||||
asSDeferredParam() {argNode = 0; origExpr = 0;}
|
||||
|
||||
asCScriptNode *argNode;
|
||||
asCExprValue argType;
|
||||
int argInOutFlags;
|
||||
asCExprContext *origExpr;
|
||||
};
|
||||
|
||||
// TODO: refactor: asCExprContext should have indicators to inform where the value is,
|
||||
// i.e. if the reference to an object is pushed on the stack or not, etc
|
||||
|
||||
// This class holds information about an expression that is being evaluated, e.g.
|
||||
// the current bytecode, ambiguous symbol names, property accessors, etc.
|
||||
struct asCExprContext
|
||||
{
|
||||
asCExprContext(asCScriptEngine *engine);
|
||||
~asCExprContext();
|
||||
void Clear();
|
||||
bool IsClassMethod() const;
|
||||
bool IsGlobalFunc() const;
|
||||
void SetLambda(asCScriptNode *funcDecl);
|
||||
bool IsLambda() const;
|
||||
void SetVoidExpression();
|
||||
bool IsVoidExpression() const;
|
||||
void Merge(asCExprContext *after);
|
||||
void Copy(asCExprContext *other);
|
||||
void SetAnonymousInitList(asCScriptNode *initList, asCScriptCode *script);
|
||||
bool IsAnonymousInitList() const;
|
||||
|
||||
asCByteCode bc;
|
||||
asCExprValue type;
|
||||
int property_get;
|
||||
int property_set;
|
||||
bool property_const; // If the object that is being accessed through property accessor is read-only
|
||||
bool property_handle; // If the property accessor is called on an object stored in a handle
|
||||
bool property_ref; // If the property accessor is called on a reference
|
||||
bool isVoidExpression; // Set to true if the expression is an explicit 'void', e.g. used to ignore out parameters in func calls
|
||||
bool isCleanArg; // Set to true if the expression has only been initialized with default constructor
|
||||
asCExprContext *property_arg;
|
||||
asCArray<asSDeferredParam> deferredParams;
|
||||
asCScriptNode *exprNode;
|
||||
asCExprContext *origExpr;
|
||||
asCScriptCode *origCode;
|
||||
// TODO: cleanup: use ambiguousName and an enum to say if it is a method, global func, or enum value
|
||||
asCString methodName;
|
||||
asCString enumValue;
|
||||
asSNameSpace *symbolNamespace; // The namespace in which the ambiguous symbol was found
|
||||
bool isAnonymousInitList; // Set to true if the expression is an init list for which the type has not yet been determined
|
||||
};
|
||||
|
||||
struct asSOverloadCandidate
|
||||
{
|
||||
asSOverloadCandidate() : funcId(0), cost(0) {}
|
||||
asSOverloadCandidate(int _id, asUINT _cost) : funcId(_id), cost(_cost) {}
|
||||
int funcId;
|
||||
asUINT cost;
|
||||
};
|
||||
|
||||
struct asSNamedArgument
|
||||
{
|
||||
asCString name;
|
||||
asCExprContext *ctx;
|
||||
asUINT match;
|
||||
};
|
||||
|
||||
enum EImplicitConv
|
||||
{
|
||||
asIC_IMPLICIT_CONV,
|
||||
asIC_EXPLICIT_REF_CAST,
|
||||
asIC_EXPLICIT_VAL_CAST
|
||||
};
|
||||
|
||||
enum EConvCost
|
||||
{
|
||||
asCC_NO_CONV = 0,
|
||||
asCC_CONST_CONV = 1,
|
||||
asCC_ENUM_SAME_SIZE_CONV = 2,
|
||||
asCC_ENUM_DIFF_SIZE_CONV = 3,
|
||||
asCC_PRIMITIVE_SIZE_CONV = 4,
|
||||
asCC_SIGNED_CONV = 5,
|
||||
asCC_INT_FLOAT_CONV = 6,
|
||||
asCC_REF_CONV = 7,
|
||||
asCC_OBJ_TO_PRIMITIVE_CONV = 8,
|
||||
asCC_TO_OBJECT_CONV = 9,
|
||||
asCC_VARIABLE_CONV = 10
|
||||
};
|
||||
|
||||
class asCCompiler
|
||||
{
|
||||
public:
|
||||
asCCompiler(asCScriptEngine *engine);
|
||||
~asCCompiler();
|
||||
|
||||
int CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray<asCString> ¶meterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl);
|
||||
int CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc, sClassDeclaration *classDecl);
|
||||
int CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc);
|
||||
int CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *expr, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc);
|
||||
|
||||
protected:
|
||||
friend class asCBuilder;
|
||||
|
||||
void Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc);
|
||||
|
||||
// Statements
|
||||
void CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc);
|
||||
void CompileDeclaration(asCScriptNode *decl, asCByteCode *bc);
|
||||
void CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc);
|
||||
void CompileIfStatement(asCScriptNode *node, bool *hasReturn, asCByteCode *bc);
|
||||
void CompileSwitchStatement(asCScriptNode *node, bool *hasReturn, asCByteCode *bc);
|
||||
void CompileCase(asCScriptNode *node, asCByteCode *bc);
|
||||
void CompileForStatement(asCScriptNode *node, asCByteCode *bc);
|
||||
void CompileWhileStatement(asCScriptNode *node, asCByteCode *bc);
|
||||
void CompileDoWhileStatement(asCScriptNode *node, asCByteCode *bc);
|
||||
void CompileBreakStatement(asCScriptNode *node, asCByteCode *bc);
|
||||
void CompileContinueStatement(asCScriptNode *node, asCByteCode *bc);
|
||||
void CompileReturnStatement(asCScriptNode *node, asCByteCode *bc);
|
||||
void CompileExpressionStatement(asCScriptNode *node, asCByteCode *bc);
|
||||
void CompileTryCatch(asCScriptNode *node, bool *hasReturn, asCByteCode *bc);
|
||||
|
||||
// Expressions
|
||||
int CompileAssignment(asCScriptNode *expr, asCExprContext *out);
|
||||
int CompileCondition(asCScriptNode *expr, asCExprContext *out);
|
||||
int CompileExpression(asCScriptNode *expr, asCExprContext *out);
|
||||
int CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asCExprContext *out);
|
||||
int CompileExpressionTerm(asCScriptNode *node, asCExprContext *out);
|
||||
int CompileExpressionPreOp(asCScriptNode *node, asCExprContext *out);
|
||||
int CompileExpressionPostOp(asCScriptNode *node, asCExprContext *out);
|
||||
int CompileExpressionValue(asCScriptNode *node, asCExprContext *out);
|
||||
int CompileFunctionCall(asCScriptNode *node, asCExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = "");
|
||||
int CompileConstructCall(asCScriptNode *node, asCExprContext *out);
|
||||
int CompileConversion(asCScriptNode *node, asCExprContext *out);
|
||||
int CompileOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken, bool leftToRight = true);
|
||||
void CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileMathOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileBitwiseOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileComparisonOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileBooleanOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
bool CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool isHandle = false, eTokenType opToken = ttUnrecognizedToken);
|
||||
int CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool specificReturn = false, const asCDataType &returnType = asCDataType::CreatePrimitive(ttVoid, false));
|
||||
|
||||
void CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem);
|
||||
int CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList);
|
||||
int CompileAnonymousInitList(asCScriptNode *listNode, asCExprContext *ctx, const asCDataType &dt);
|
||||
|
||||
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, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar = false, bool derefDestination = false);
|
||||
void CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc);
|
||||
int CompileArgumentList(asCScriptNode *node, asCArray<asCExprContext *> &args, asCArray<asSNamedArgument> &namedArgs);
|
||||
int CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asCExprContext*> &args, int funcId, asCObjectType *type, asCArray<asSNamedArgument> *namedArgs = 0);
|
||||
asUINT MatchFunctions(asCArray<int> &funcs, asCArray<asCExprContext*> &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, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional = false, asCObjectType *objType = 0);
|
||||
void CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults);
|
||||
bool CompileAutoType(asCDataType &autoType, asCExprContext &compiledCtx, asCScriptNode *exprNode, asCScriptNode *errNode);
|
||||
bool CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled = 0);
|
||||
void CompileInitAsCopy(asCDataType &type, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination);
|
||||
|
||||
// Helper functions
|
||||
void ConvertToPostFix(asCScriptNode *expr, asCArray<asCScriptNode *> &postfix);
|
||||
int ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node);
|
||||
int ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node);
|
||||
int ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode);
|
||||
int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false);
|
||||
int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false);
|
||||
void PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap = false);
|
||||
void PrepareOperand(asCExprContext *ctx, asCScriptNode *node);
|
||||
void PrepareForAssignment(asCDataType *lvalue, asCExprContext *rvalue, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr = 0);
|
||||
int PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node);
|
||||
bool IsVariableInitialized(asCExprValue *type, asCScriptNode *node);
|
||||
void Dereference(asCExprContext *ctx, bool generateCode);
|
||||
bool CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode = true);
|
||||
asUINT MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true);
|
||||
int MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true);
|
||||
void PerformFunctionCall(int funcId, asCExprContext *out, bool isConstructor = false, asCArray<asCExprContext*> *args = 0, asCObjectType *objTypeForConstruct = 0, bool useVariable = false, int varOffset = 0, int funcPtrVar = 0);
|
||||
void MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args, bool addOneToOffset);
|
||||
int MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asCExprContext*> &args, asCScriptNode *node, bool useVariable = false, int stackOffset = 0, int funcPtrVar = 0);
|
||||
int PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args);
|
||||
void AfterFunctionCall(int funcId, asCArray<asCExprContext*> &args, asCExprContext *ctx, bool deferAll);
|
||||
void ProcessDeferredParams(asCExprContext *ctx);
|
||||
int PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction = false, int refType = 0, bool isMakingCopy = false);
|
||||
int PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction = false, int refType = 0, bool isMakingCopy = false);
|
||||
bool IsLValue(asCExprValue &type);
|
||||
int DoAssignment(asCExprContext *out, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode);
|
||||
void MergeExprBytecode(asCExprContext *before, asCExprContext *after);
|
||||
void MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after);
|
||||
void FilterConst(asCArray<int> &funcs, bool removeConst = true);
|
||||
void ConvertToVariable(asCExprContext *ctx);
|
||||
void ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude);
|
||||
void ConvertToTempVariable(asCExprContext *ctx);
|
||||
void ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude);
|
||||
void ConvertToReference(asCExprContext *ctx);
|
||||
void PushVariableOnStack(asCExprContext *ctx, bool asReference);
|
||||
void DestroyVariables(asCByteCode *bc);
|
||||
asSNameSpace *DetermineNameSpace(const asCString &scope);
|
||||
int SetupParametersAndReturnVariable(asCArray<asCString> ¶meterNames, asCScriptNode *func);
|
||||
|
||||
enum SYMBOLTYPE
|
||||
{
|
||||
SL_NOMATCH,
|
||||
SL_LOCALCONST,
|
||||
SL_LOCALVAR,
|
||||
SL_THISPTR,
|
||||
SL_CLASSPROPACCESS,
|
||||
SL_CLASSPROP,
|
||||
SL_CLASSMETHOD,
|
||||
SL_CLASSTYPE,
|
||||
SL_GLOBALPROPACCESS,
|
||||
SL_GLOBALCONST,
|
||||
SL_GLOBALVAR,
|
||||
SL_GLOBALFUNC,
|
||||
SL_GLOBALTYPE,
|
||||
SL_ENUMVAL,
|
||||
SL_ERROR = -1
|
||||
};
|
||||
|
||||
SYMBOLTYPE SymbolLookup(const asCString &name, const asCString &scope, asCObjectType *objType, asCExprContext *outResult);
|
||||
SYMBOLTYPE SymbolLookupLocalVar(const asCString &name, asCExprContext *outResult);
|
||||
SYMBOLTYPE SymbolLookupMember(const asCString &name, asCObjectType *objType, asCExprContext *outResult);
|
||||
|
||||
void DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node);
|
||||
|
||||
// Returns the cost of the conversion (the sum of the EConvCost performed)
|
||||
asUINT ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true);
|
||||
asUINT ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true);
|
||||
asUINT ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true);
|
||||
asUINT ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true);
|
||||
asUINT ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true);
|
||||
asUINT ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode);
|
||||
asUINT ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode);
|
||||
void ImplicitConversionConstant(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType);
|
||||
void ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node);
|
||||
asUINT ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true);
|
||||
|
||||
void LineInstr(asCByteCode *bc, size_t pos);
|
||||
|
||||
asUINT ProcessStringConstant(asCString &str, asCScriptNode *node, bool processEscapeSequences = true);
|
||||
void ProcessHeredocStringConstant(asCString &str, asCScriptNode *node);
|
||||
int GetPrecedence(asCScriptNode *op);
|
||||
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, asCObjectType *inType = 0);
|
||||
void AddVariableScope(bool isBreakScope = false, bool isContinueScope = false);
|
||||
void RemoveVariableScope();
|
||||
void FinalizeFunction();
|
||||
|
||||
asCByteCode byteCode;
|
||||
|
||||
bool hasCompileErrors;
|
||||
|
||||
int nextLabel;
|
||||
int numLambdas;
|
||||
|
||||
asCVariableScope *variables;
|
||||
asCBuilder *builder;
|
||||
asCScriptEngine *engine;
|
||||
asCScriptCode *script;
|
||||
asCScriptFunction *outFunc;
|
||||
|
||||
bool m_isConstructor;
|
||||
bool m_isConstructorCalled;
|
||||
sClassDeclaration *m_classDecl;
|
||||
sGlobalVariableDescription *m_globalVar;
|
||||
|
||||
asCArray<int> breakLabels;
|
||||
asCArray<int> continueLabels;
|
||||
|
||||
int AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap = false, bool asReference = false);
|
||||
int AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx);
|
||||
int GetVariableOffset(int varIndex);
|
||||
int GetVariableSlot(int varOffset);
|
||||
void DeallocateVariable(int pos);
|
||||
void ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc);
|
||||
void ReleaseTemporaryVariable(int offset, asCByteCode *bc);
|
||||
bool IsVariableOnHeap(int offset);
|
||||
|
||||
// This ordered array indicates the type of each variable
|
||||
asCArray<asCDataType> variableAllocations;
|
||||
|
||||
// This ordered array indicates which variables are temporaries or not
|
||||
asCArray<bool> variableIsTemporary;
|
||||
|
||||
// This unordered array gives the offsets of all temporary variables, whether currently allocated or not
|
||||
asCArray<int> tempVariableOffsets;
|
||||
|
||||
// This ordered array indicated if the variable is on the heap or not
|
||||
asCArray<bool> variableIsOnHeap;
|
||||
|
||||
// This unordered array gives the indexes of the currently unused variables
|
||||
asCArray<int> freeVariables;
|
||||
|
||||
// This array holds the offsets of the currently allocated temporary variables
|
||||
asCArray<int> tempVariables;
|
||||
|
||||
// This array holds the indices of variables that must not be used in an allocation
|
||||
asCArray<int> reservedVariables;
|
||||
|
||||
// This array holds the string constants that were allocated during the compilation,
|
||||
// so they can be released upon completion, whether the compilation was successful or not.
|
||||
asCArray<void*> usedStringConstants;
|
||||
|
||||
// This array holds the nodes that have been allocated temporarily
|
||||
asCArray<asCScriptNode*> nodesToFreeUponComplete;
|
||||
|
||||
bool isCompilingDefaultArg;
|
||||
bool isProcessingDeferredParams;
|
||||
int noCodeOutput;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_NO_COMPILER
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2020 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_configgroup.cpp
|
||||
//
|
||||
// This class holds configuration groups for the engine
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_configgroup.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asCConfigGroup::asCConfigGroup()
|
||||
{
|
||||
refCount = 0;
|
||||
}
|
||||
|
||||
asCConfigGroup::~asCConfigGroup()
|
||||
{
|
||||
}
|
||||
|
||||
int asCConfigGroup::AddRef()
|
||||
{
|
||||
refCount++;
|
||||
return refCount;
|
||||
}
|
||||
|
||||
int asCConfigGroup::Release()
|
||||
{
|
||||
// Don't delete the object here, the engine will delete the object when ready
|
||||
refCount--;
|
||||
return refCount;
|
||||
}
|
||||
|
||||
asCTypeInfo *asCConfigGroup::FindType(const char *obj)
|
||||
{
|
||||
for( asUINT n = 0; n < types.GetLength(); n++ )
|
||||
if( types[n]->name == obj )
|
||||
return types[n];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void asCConfigGroup::RefConfigGroup(asCConfigGroup *group)
|
||||
{
|
||||
if( group == this || group == 0 ) return;
|
||||
|
||||
// Verify if the group is already referenced
|
||||
for( asUINT n = 0; n < referencedConfigGroups.GetLength(); n++ )
|
||||
if( referencedConfigGroups[n] == group )
|
||||
return;
|
||||
|
||||
referencedConfigGroups.PushLast(group);
|
||||
group->AddRef();
|
||||
}
|
||||
|
||||
void asCConfigGroup::AddReferencesForFunc(asCScriptEngine *engine, asCScriptFunction *func)
|
||||
{
|
||||
AddReferencesForType(engine, func->returnType.GetTypeInfo());
|
||||
for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
|
||||
AddReferencesForType(engine, func->parameterTypes[n].GetTypeInfo());
|
||||
}
|
||||
|
||||
void asCConfigGroup::AddReferencesForType(asCScriptEngine *engine, asCTypeInfo *type)
|
||||
{
|
||||
if( type == 0 ) return;
|
||||
|
||||
// Keep reference to other groups
|
||||
RefConfigGroup(engine->FindConfigGroupForTypeInfo(type));
|
||||
|
||||
// Keep track of which generated template instances the config group uses
|
||||
if( type->flags & asOBJ_TEMPLATE && engine->generatedTemplateTypes.Exists(CastToObjectType(type)) && !generatedTemplateInstances.Exists(CastToObjectType(type)) )
|
||||
generatedTemplateInstances.PushLast(CastToObjectType(type));
|
||||
}
|
||||
|
||||
bool asCConfigGroup::HasLiveObjects()
|
||||
{
|
||||
for( asUINT n = 0; n < types.GetLength(); n++ )
|
||||
if( types[n]->externalRefCount.get() != 0 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void asCConfigGroup::RemoveConfiguration(asCScriptEngine *engine, bool notUsed)
|
||||
{
|
||||
asASSERT( refCount == 0 );
|
||||
|
||||
asUINT n;
|
||||
|
||||
// Remove global variables
|
||||
for( n = 0; n < globalProps.GetLength(); n++ )
|
||||
{
|
||||
int index = engine->registeredGlobalProps.GetIndex(globalProps[n]);
|
||||
if( index >= 0 )
|
||||
{
|
||||
globalProps[n]->Release();
|
||||
|
||||
engine->registeredGlobalProps.Erase(index);
|
||||
}
|
||||
}
|
||||
globalProps.SetLength(0);
|
||||
|
||||
// Remove global functions
|
||||
for( n = 0; n < scriptFunctions.GetLength(); n++ )
|
||||
{
|
||||
int index = engine->registeredGlobalFuncs.GetIndex(scriptFunctions[n]);
|
||||
if( index >= 0 )
|
||||
engine->registeredGlobalFuncs.Erase(index);
|
||||
scriptFunctions[n]->ReleaseInternal();
|
||||
}
|
||||
scriptFunctions.SetLength(0);
|
||||
|
||||
// Remove behaviours and members of object types
|
||||
for( n = 0; n < types.GetLength(); n++ )
|
||||
{
|
||||
asCObjectType *obj = CastToObjectType(types[n]);
|
||||
if( obj )
|
||||
obj->ReleaseAllFunctions();
|
||||
}
|
||||
|
||||
// Remove object types (skip this if it is possible other groups are still using the types)
|
||||
if( !notUsed )
|
||||
{
|
||||
for( n = asUINT(types.GetLength()); n-- > 0; )
|
||||
{
|
||||
asCTypeInfo *t = types[n];
|
||||
asSMapNode<asSNameSpaceNamePair, asCTypeInfo*> *cursor;
|
||||
if( engine->allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(t->nameSpace, t->name)) &&
|
||||
cursor->value == t )
|
||||
{
|
||||
engine->allRegisteredTypes.Erase(cursor);
|
||||
|
||||
if( engine->defaultArrayObjectType == t )
|
||||
engine->defaultArrayObjectType = 0;
|
||||
|
||||
if( t->flags & asOBJ_TYPEDEF )
|
||||
engine->registeredTypeDefs.RemoveValue(CastToTypedefType(t));
|
||||
else if( t->flags & asOBJ_ENUM )
|
||||
engine->registeredEnums.RemoveValue(CastToEnumType(t));
|
||||
else if (t->flags & asOBJ_TEMPLATE)
|
||||
engine->registeredTemplateTypes.RemoveValue(CastToObjectType(t));
|
||||
else if (t->flags & asOBJ_FUNCDEF)
|
||||
{
|
||||
engine->registeredFuncDefs.RemoveValue(CastToFuncdefType(t));
|
||||
engine->RemoveFuncdef(CastToFuncdefType(t));
|
||||
}
|
||||
else
|
||||
engine->registeredObjTypes.RemoveValue(CastToObjectType(t));
|
||||
|
||||
t->DestroyInternal();
|
||||
t->ReleaseInternal();
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx = engine->templateInstanceTypes.IndexOf(CastToObjectType(t));
|
||||
if( idx >= 0 )
|
||||
{
|
||||
engine->templateInstanceTypes.RemoveIndexUnordered(idx);
|
||||
asCObjectType *ot = CastToObjectType(t);
|
||||
ot->DestroyInternal();
|
||||
ot->ReleaseInternal();
|
||||
}
|
||||
}
|
||||
}
|
||||
types.SetLength(0);
|
||||
}
|
||||
|
||||
// Release other config groups
|
||||
for( n = 0; n < referencedConfigGroups.GetLength(); n++ )
|
||||
referencedConfigGroups[n]->refCount--;
|
||||
referencedConfigGroups.SetLength(0);
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_configgroup.h
|
||||
//
|
||||
// This class holds configuration groups for the engine
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_CONFIGGROUP_H
|
||||
#define AS_CONFIGGROUP_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_string.h"
|
||||
#include "as_array.h"
|
||||
#include "as_objecttype.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCConfigGroup
|
||||
{
|
||||
public:
|
||||
asCConfigGroup();
|
||||
~asCConfigGroup();
|
||||
|
||||
// Memory management
|
||||
int AddRef();
|
||||
int Release();
|
||||
|
||||
asCTypeInfo *FindType(const char *name);
|
||||
void RefConfigGroup(asCConfigGroup *group);
|
||||
|
||||
bool HasLiveObjects();
|
||||
void RemoveConfiguration(asCScriptEngine *engine, bool notUsed = false);
|
||||
|
||||
void AddReferencesForFunc(asCScriptEngine *engine, asCScriptFunction *func);
|
||||
void AddReferencesForType(asCScriptEngine *engine, asCTypeInfo *type);
|
||||
|
||||
asCString groupName;
|
||||
int refCount;
|
||||
|
||||
asCArray<asCTypeInfo*> types;
|
||||
asCArray<asCScriptFunction*> scriptFunctions;
|
||||
asCArray<asCGlobalProperty*> globalProps;
|
||||
asCArray<asCConfigGroup*> referencedConfigGroups;
|
||||
|
||||
// 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
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2018 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_context.h
|
||||
//
|
||||
// This class handles the execution of the byte code
|
||||
//
|
||||
|
||||
|
||||
#ifndef AS_CONTEXT_H
|
||||
#define AS_CONTEXT_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_atomic.h"
|
||||
#include "as_array.h"
|
||||
#include "as_string.h"
|
||||
#include "as_objecttype.h"
|
||||
#include "as_callfunc.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCScriptFunction;
|
||||
class asCScriptEngine;
|
||||
|
||||
class asCContext : public asIScriptContext
|
||||
{
|
||||
public:
|
||||
// Memory management
|
||||
int AddRef() const;
|
||||
int Release() const;
|
||||
|
||||
// Miscellaneous
|
||||
asIScriptEngine *GetEngine() const;
|
||||
|
||||
// Execution
|
||||
int Prepare(asIScriptFunction *func);
|
||||
int Unprepare();
|
||||
int Execute();
|
||||
int Abort();
|
||||
int Suspend();
|
||||
asEContextState GetState() const;
|
||||
int PushState();
|
||||
int PopState();
|
||||
bool IsNested(asUINT *nestCount = 0) const;
|
||||
|
||||
// Object pointer for calling class methods
|
||||
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 SetArgVarType(asUINT arg, void *ptr, int typeId);
|
||||
void *GetAddressOfArg(asUINT arg);
|
||||
|
||||
// Return value
|
||||
asBYTE GetReturnByte();
|
||||
asWORD GetReturnWord();
|
||||
asDWORD GetReturnDWord();
|
||||
asQWORD GetReturnQWord();
|
||||
float GetReturnFloat();
|
||||
double GetReturnDouble();
|
||||
void *GetReturnAddress();
|
||||
void *GetReturnObject();
|
||||
void *GetAddressOfReturnValue();
|
||||
|
||||
// Exception handling
|
||||
int SetException(const char *descr, bool allowCatch = true);
|
||||
int GetExceptionLineNumber(int *column, const char **sectionName);
|
||||
asIScriptFunction *GetExceptionFunction();
|
||||
const char * GetExceptionString();
|
||||
bool WillExceptionBeCaught();
|
||||
int SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv);
|
||||
void ClearExceptionCallback();
|
||||
|
||||
// Debugging
|
||||
int SetLineCallback(asSFuncPtr callback, void *obj, int callConv);
|
||||
void ClearLineCallback();
|
||||
asUINT GetCallstackSize() const;
|
||||
asIScriptFunction *GetFunction(asUINT stackLevel);
|
||||
int GetLineNumber(asUINT stackLevel, int *column, const char **sectionName);
|
||||
int GetVarCount(asUINT stackLevel);
|
||||
const char *GetVarName(asUINT varIndex, asUINT stackLevel);
|
||||
const char *GetVarDeclaration(asUINT varIndex, asUINT stackLevel, bool includeNamespace);
|
||||
int GetVarTypeId(asUINT varIndex, asUINT stackLevel);
|
||||
void *GetAddressOfVar(asUINT varIndex, asUINT stackLevel);
|
||||
bool IsVarInScope(asUINT varIndex, asUINT stackLevel);
|
||||
int GetThisTypeId(asUINT stackLevel);
|
||||
void *GetThisPointer(asUINT stackLevel);
|
||||
asIScriptFunction *GetSystemFunction();
|
||||
|
||||
// User data
|
||||
void *SetUserData(void *data, asPWORD type);
|
||||
void *GetUserData(asPWORD type) const;
|
||||
|
||||
public:
|
||||
// Internal public functions
|
||||
asCContext(asCScriptEngine *engine, bool holdRef);
|
||||
virtual ~asCContext();
|
||||
|
||||
//protected:
|
||||
friend class asCScriptEngine;
|
||||
|
||||
void CallLineCallback();
|
||||
void CallExceptionCallback();
|
||||
|
||||
int CallGeneric(asCScriptFunction *func);
|
||||
#ifndef AS_NO_EXCEPTIONS
|
||||
void HandleAppException();
|
||||
#endif
|
||||
void DetachEngine();
|
||||
|
||||
void ExecuteNext();
|
||||
void CleanStack(bool catchException = false);
|
||||
bool CleanStackFrame(bool catchException = false);
|
||||
void CleanArgsOnStack();
|
||||
void CleanReturnObject();
|
||||
void DetermineLiveObjects(asCArray<int> &liveObjects, asUINT stackLevel);
|
||||
|
||||
int PushCallState();
|
||||
void PopCallState();
|
||||
void CallScriptFunction(asCScriptFunction *func);
|
||||
void CallInterfaceMethod(asCScriptFunction *func);
|
||||
void PrepareScriptFunction();
|
||||
|
||||
bool ReserveStackSpace(asUINT size);
|
||||
|
||||
void SetInternalException(const char *descr, bool allowCatch = true);
|
||||
bool FindExceptionTryCatch();
|
||||
|
||||
// Must be protected for multiple accesses
|
||||
mutable asCAtomic m_refCount;
|
||||
|
||||
bool m_holdEngineRef;
|
||||
asCScriptEngine *m_engine;
|
||||
|
||||
asEContextState m_status;
|
||||
bool m_doSuspend;
|
||||
bool m_doAbort;
|
||||
bool m_externalSuspendRequest;
|
||||
|
||||
asCScriptFunction *m_currentFunction;
|
||||
asCScriptFunction *m_callingSystemFunction;
|
||||
|
||||
// The call stack holds program pointer, stack pointer, etc for caller functions
|
||||
asCArray<size_t> m_callStack;
|
||||
|
||||
// Dynamically growing local stack
|
||||
asCArray<asDWORD *> m_stackBlocks;
|
||||
asUINT m_stackBlockSize;
|
||||
asUINT m_stackIndex;
|
||||
asDWORD *m_originalStackPointer;
|
||||
|
||||
// Exception handling
|
||||
bool m_isStackMemoryNotAllocated;
|
||||
bool m_needToCleanupArgs;
|
||||
bool m_inExceptionHandler;
|
||||
asCString m_exceptionString;
|
||||
int m_exceptionFunction;
|
||||
int m_exceptionSectionIdx;
|
||||
int m_exceptionLine;
|
||||
int m_exceptionColumn;
|
||||
bool m_exceptionWillBeCaught;
|
||||
|
||||
// The last prepared function, and some cached values related to it
|
||||
asCScriptFunction *m_initialFunction;
|
||||
int m_returnValueSize;
|
||||
int m_argumentsSize;
|
||||
|
||||
// callbacks
|
||||
bool m_lineCallback;
|
||||
asSSystemFunctionInterface m_lineCallbackFunc;
|
||||
void * m_lineCallbackObj;
|
||||
|
||||
bool m_exceptionCallback;
|
||||
asSSystemFunctionInterface m_exceptionCallbackFunc;
|
||||
void * m_exceptionCallbackObj;
|
||||
|
||||
asCArray<asPWORD> m_userData;
|
||||
|
||||
// Registers available to JIT compiler functions
|
||||
asSVMRegisters m_regs;
|
||||
};
|
||||
|
||||
// TODO: Move these to as_utils.h
|
||||
int as_powi(int base, int exponent, bool& isOverflow);
|
||||
asDWORD as_powu(asDWORD base, asDWORD exponent, bool& isOverflow);
|
||||
asINT64 as_powi64(asINT64 base, asINT64 exponent, bool& isOverflow);
|
||||
asQWORD as_powu64(asQWORD base, asQWORD exponent, bool& isOverflow);
|
||||
|
||||
// Optional template version of powi if overflow detection is not used.
|
||||
#if 0
|
||||
template <class T>
|
||||
T as_powi(T base, T exponent)
|
||||
{
|
||||
// Test for sign bit (huge number is OK)
|
||||
if( exponent & (T(1)<<(sizeof(T)*8-1)) )
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
int result = 1;
|
||||
while( exponent )
|
||||
{
|
||||
if( exponent & 1 )
|
||||
result *= base;
|
||||
exponent >>= 1;
|
||||
base *= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2017 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
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//
|
||||
// as_criticalsection.h
|
||||
//
|
||||
// Classes for multi threading support
|
||||
//
|
||||
|
||||
#ifndef AS_CRITICALSECTION_H
|
||||
#define AS_CRITICALSECTION_H
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
#ifdef AS_NO_THREADS
|
||||
|
||||
#define DECLARECRITICALSECTION(x)
|
||||
#define ENTERCRITICALSECTION(x)
|
||||
#define LEAVECRITICALSECTION(x)
|
||||
|
||||
inline bool tryEnter() { return true; }
|
||||
#define TRYENTERCRITICALSECTION(x) tryEnter()
|
||||
|
||||
#define DECLAREREADWRITELOCK(x)
|
||||
#define ACQUIREEXCLUSIVE(x)
|
||||
#define RELEASEEXCLUSIVE(x)
|
||||
#define ACQUIRESHARED(x)
|
||||
#define RELEASESHARED(x)
|
||||
|
||||
#else
|
||||
|
||||
#define DECLARECRITICALSECTION(x) asCThreadCriticalSection x;
|
||||
#define ENTERCRITICALSECTION(x) x.Enter()
|
||||
#define LEAVECRITICALSECTION(x) x.Leave()
|
||||
#define TRYENTERCRITICALSECTION(x) x.TryEnter()
|
||||
|
||||
#define DECLAREREADWRITELOCK(x) asCThreadReadWriteLock x;
|
||||
#define ACQUIREEXCLUSIVE(x) x.AcquireExclusive()
|
||||
#define RELEASEEXCLUSIVE(x) x.ReleaseExclusive()
|
||||
#define ACQUIRESHARED(x) x.AcquireShared()
|
||||
#define RELEASESHARED(x) x.ReleaseShared()
|
||||
|
||||
#ifdef AS_POSIX_THREADS
|
||||
|
||||
END_AS_NAMESPACE
|
||||
#include <pthread.h>
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCThreadCriticalSection
|
||||
{
|
||||
public:
|
||||
asCThreadCriticalSection();
|
||||
~asCThreadCriticalSection();
|
||||
|
||||
void Enter();
|
||||
void Leave();
|
||||
bool TryEnter();
|
||||
|
||||
protected:
|
||||
pthread_mutex_t cs;
|
||||
};
|
||||
|
||||
class asCThreadReadWriteLock
|
||||
{
|
||||
public:
|
||||
asCThreadReadWriteLock();
|
||||
~asCThreadReadWriteLock();
|
||||
|
||||
void AcquireExclusive();
|
||||
void ReleaseExclusive();
|
||||
bool TryAcquireExclusive();
|
||||
|
||||
void AcquireShared();
|
||||
void ReleaseShared();
|
||||
bool TryAcquireShared();
|
||||
|
||||
protected:
|
||||
pthread_rwlock_t lock;
|
||||
};
|
||||
|
||||
#elif defined(AS_WINDOWS_THREADS)
|
||||
|
||||
END_AS_NAMESPACE
|
||||
#ifdef AS_XBOX360
|
||||
#include <xtl.h>
|
||||
#else
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 // We need this to get the declaration for Windows Phone compatible Ex functions
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// Undefine macros that cause problems in our code
|
||||
#undef GetObject
|
||||
#undef RegisterClass
|
||||
|
||||
class asCThreadCriticalSection
|
||||
{
|
||||
public:
|
||||
asCThreadCriticalSection();
|
||||
~asCThreadCriticalSection();
|
||||
|
||||
void Enter();
|
||||
void Leave();
|
||||
bool TryEnter();
|
||||
|
||||
protected:
|
||||
CRITICAL_SECTION cs;
|
||||
};
|
||||
|
||||
class asCThreadReadWriteLock
|
||||
{
|
||||
public:
|
||||
asCThreadReadWriteLock();
|
||||
~asCThreadReadWriteLock();
|
||||
|
||||
void AcquireExclusive();
|
||||
void ReleaseExclusive();
|
||||
|
||||
void AcquireShared();
|
||||
void ReleaseShared();
|
||||
|
||||
protected:
|
||||
// The Slim Read Write Lock object, SRWLOCK, is more efficient
|
||||
// but it is only available from Windows Vista so we cannot use it and
|
||||
// maintain compatibility with olders versions of Windows.
|
||||
|
||||
// Critical sections and semaphores are available on Windows XP and onwards.
|
||||
// Windows XP is oldest version we support with multithreading.
|
||||
|
||||
// The implementation is based on the following article, that shows
|
||||
// how to implement a fair read/write lock that doesn't risk starving
|
||||
// the writers:
|
||||
|
||||
// http://doc.qt.nokia.com/qq/qq11-mutex.html
|
||||
|
||||
// TODO: Allow use of SRWLOCK through configuration in as_config.h
|
||||
|
||||
CRITICAL_SECTION writeLock;
|
||||
HANDLE readLocks;
|
||||
};
|
||||
|
||||
// This constant really should be a member of asCThreadReadWriteLock,
|
||||
// but it gives a compiler error on MSVC6 so I'm leaving it outside
|
||||
static const asUINT maxReaders = 10;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,690 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2017 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_datatype.cpp
|
||||
//
|
||||
// This class describes the datatype for expressions during compilation
|
||||
//
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_datatype.h"
|
||||
#include "as_tokendef.h"
|
||||
#include "as_typeinfo.h"
|
||||
#include "as_objecttype.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_tokenizer.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asCDataType::asCDataType()
|
||||
{
|
||||
tokenType = ttUnrecognizedToken;
|
||||
typeInfo = 0;
|
||||
isReference = false;
|
||||
isReadOnly = false;
|
||||
isAuto = false;
|
||||
isObjectHandle = false;
|
||||
isConstHandle = false;
|
||||
isHandleToAsHandleType = false;
|
||||
ifHandleThenConst = false;
|
||||
}
|
||||
|
||||
asCDataType::asCDataType(const asCDataType &dt)
|
||||
{
|
||||
tokenType = dt.tokenType;
|
||||
typeInfo = dt.typeInfo;
|
||||
isReference = dt.isReference;
|
||||
isReadOnly = dt.isReadOnly;
|
||||
isAuto = dt.isAuto;
|
||||
isObjectHandle = dt.isObjectHandle;
|
||||
isConstHandle = dt.isConstHandle;
|
||||
isHandleToAsHandleType = dt.isHandleToAsHandleType;
|
||||
ifHandleThenConst = dt.ifHandleThenConst;
|
||||
}
|
||||
|
||||
asCDataType::~asCDataType()
|
||||
{
|
||||
}
|
||||
|
||||
bool asCDataType::IsValid() const
|
||||
{
|
||||
if( tokenType == ttUnrecognizedToken &&
|
||||
!isObjectHandle )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
asCDataType asCDataType::CreateType(asCTypeInfo *ti, bool isConst)
|
||||
{
|
||||
asCDataType dt;
|
||||
|
||||
dt.tokenType = ttIdentifier;
|
||||
dt.typeInfo = ti;
|
||||
dt.isReadOnly = isConst;
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
asCDataType asCDataType::CreateAuto(bool isConst)
|
||||
{
|
||||
asCDataType dt;
|
||||
|
||||
dt.tokenType = ttIdentifier;
|
||||
dt.isReadOnly = isConst;
|
||||
dt.isAuto = true;
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
asCDataType asCDataType::CreateObjectHandle(asCTypeInfo *ot, bool isConst)
|
||||
{
|
||||
asCDataType dt;
|
||||
|
||||
asASSERT(CastToObjectType(ot));
|
||||
|
||||
dt.tokenType = ttIdentifier;
|
||||
dt.typeInfo = ot;
|
||||
dt.isObjectHandle = true;
|
||||
dt.isConstHandle = isConst;
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
asCDataType asCDataType::CreatePrimitive(eTokenType tt, bool isConst)
|
||||
{
|
||||
asCDataType dt;
|
||||
|
||||
dt.tokenType = tt;
|
||||
dt.isReadOnly = isConst;
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
asCDataType asCDataType::CreateNullHandle()
|
||||
{
|
||||
asCDataType dt;
|
||||
|
||||
dt.tokenType = ttUnrecognizedToken;
|
||||
dt.isReadOnly = true;
|
||||
dt.isObjectHandle = true;
|
||||
dt.isConstHandle = true;
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
bool asCDataType::IsNullHandle() const
|
||||
{
|
||||
if( tokenType == ttUnrecognizedToken &&
|
||||
typeInfo == 0 &&
|
||||
isObjectHandle )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
asCString asCDataType::Format(asSNameSpace *currNs, bool includeNamespace) const
|
||||
{
|
||||
if( IsNullHandle() )
|
||||
return "<null handle>";
|
||||
|
||||
asCString str;
|
||||
|
||||
if( isReadOnly )
|
||||
str = "const ";
|
||||
|
||||
// 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 || (typeInfo && typeInfo->nameSpace != currNs))
|
||||
{
|
||||
if (typeInfo && typeInfo->nameSpace && typeInfo->nameSpace->name != "")
|
||||
str += typeInfo->nameSpace->name + "::";
|
||||
}
|
||||
if (typeInfo && typeInfo->nameSpace == 0)
|
||||
{
|
||||
// If funcDef->nameSpace is null it means the funcDef was declared as member of
|
||||
// another type, in which case the scope should be built with the name of that type
|
||||
str += CastToFuncdefType(typeInfo)->parentClass->name + "::";
|
||||
}
|
||||
|
||||
if( tokenType != ttIdentifier )
|
||||
{
|
||||
str += asCTokenizer::GetDefinition(tokenType);
|
||||
}
|
||||
else if( IsArrayType() && typeInfo && !typeInfo->engine->ep.expandDefaultArrayToTemplate )
|
||||
{
|
||||
asCObjectType *ot = CastToObjectType(typeInfo);
|
||||
asASSERT( ot && ot->templateSubTypes.GetLength() == 1 );
|
||||
str += ot->templateSubTypes[0].Format(currNs, includeNamespace);
|
||||
str += "[]";
|
||||
}
|
||||
else if(typeInfo)
|
||||
{
|
||||
str += typeInfo->name;
|
||||
asCObjectType *ot = CastToObjectType(typeInfo);
|
||||
if( ot && ot->templateSubTypes.GetLength() > 0 )
|
||||
{
|
||||
str += "<";
|
||||
for( asUINT subtypeIndex = 0; subtypeIndex < ot->templateSubTypes.GetLength(); subtypeIndex++ )
|
||||
{
|
||||
str += ot->templateSubTypes[subtypeIndex].Format(currNs, includeNamespace);
|
||||
if( subtypeIndex != ot->templateSubTypes.GetLength()-1 )
|
||||
str += ",";
|
||||
}
|
||||
str += ">";
|
||||
}
|
||||
}
|
||||
else if( isAuto )
|
||||
{
|
||||
str += "<auto>";
|
||||
}
|
||||
else
|
||||
{
|
||||
str = "<unknown>";
|
||||
}
|
||||
|
||||
if( isObjectHandle )
|
||||
{
|
||||
str += "@";
|
||||
if( isConstHandle )
|
||||
str += "const";
|
||||
}
|
||||
|
||||
if( isReference )
|
||||
str += "&";
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
asCDataType &asCDataType::operator =(const asCDataType &dt)
|
||||
{
|
||||
tokenType = dt.tokenType;
|
||||
isReference = dt.isReference;
|
||||
typeInfo = dt.typeInfo;
|
||||
isReadOnly = dt.isReadOnly;
|
||||
isObjectHandle = dt.isObjectHandle;
|
||||
isConstHandle = dt.isConstHandle;
|
||||
isAuto = dt.isAuto;
|
||||
isHandleToAsHandleType = dt.isHandleToAsHandleType;
|
||||
ifHandleThenConst = dt.ifHandleThenConst;
|
||||
|
||||
return (asCDataType &)*this;
|
||||
}
|
||||
|
||||
int asCDataType::MakeHandle(bool b, bool acceptHandleForScope)
|
||||
{
|
||||
if( !b )
|
||||
{
|
||||
isObjectHandle = false;
|
||||
isConstHandle = false;
|
||||
isHandleToAsHandleType = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
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( (!typeInfo ||
|
||||
!((typeInfo->flags & asOBJ_REF) || (typeInfo->flags & asOBJ_TEMPLATE_SUBTYPE) || (typeInfo->flags & asOBJ_ASHANDLE) || (typeInfo->flags & asOBJ_FUNCDEF)) ||
|
||||
(typeInfo->flags & asOBJ_NOHANDLE) ||
|
||||
((typeInfo->flags & asOBJ_SCOPED) && !acceptHandleForScope)) )
|
||||
return -1;
|
||||
|
||||
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( (typeInfo->flags & asOBJ_ASHANDLE) )
|
||||
{
|
||||
isObjectHandle = false;
|
||||
isHandleToAsHandleType = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asCDataType::MakeArray(asCScriptEngine *engine, asCModule *module)
|
||||
{
|
||||
if( engine->defaultArrayObjectType == 0 )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
bool tmpIsReadOnly = isReadOnly;
|
||||
isReadOnly = false;
|
||||
asCArray<asCDataType> subTypes;
|
||||
subTypes.PushLast(*this);
|
||||
asCObjectType *at = engine->GetTemplateInstanceType(engine->defaultArrayObjectType, subTypes, module);
|
||||
isReadOnly = tmpIsReadOnly;
|
||||
|
||||
isObjectHandle = false;
|
||||
isConstHandle = false;
|
||||
|
||||
typeInfo = at;
|
||||
tokenType = ttIdentifier;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asCDataType::MakeReference(bool b)
|
||||
{
|
||||
isReference = b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asCDataType::MakeReadOnly(bool b)
|
||||
{
|
||||
if( isObjectHandle )
|
||||
{
|
||||
isConstHandle = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
isReadOnly = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asCDataType::MakeHandleToConst(bool b)
|
||||
{
|
||||
if( !isObjectHandle ) return -1;
|
||||
|
||||
isReadOnly = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool asCDataType::SupportHandles() const
|
||||
{
|
||||
if( typeInfo &&
|
||||
(typeInfo->flags & (asOBJ_REF | asOBJ_ASHANDLE | asOBJ_FUNCDEF)) &&
|
||||
!(typeInfo->flags & asOBJ_NOHANDLE) &&
|
||||
!isObjectHandle )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCDataType::CanBeInstantiated() const
|
||||
{
|
||||
if( GetSizeOnStackDWords() == 0 ) // Void
|
||||
return false;
|
||||
|
||||
if( !IsObject() && !IsFuncdef() ) // Primitives
|
||||
return true;
|
||||
|
||||
if (IsNullHandle()) // null
|
||||
return false;
|
||||
|
||||
if( IsObjectHandle() && !(typeInfo->flags & asOBJ_NOHANDLE) ) // Handles
|
||||
return true;
|
||||
|
||||
// Funcdefs cannot be instantiated without being handles
|
||||
// The exception being delegates, but these can only be created as temporary objects
|
||||
if (IsFuncdef())
|
||||
return false;
|
||||
|
||||
asCObjectType *ot = CastToObjectType(typeInfo);
|
||||
if( ot && (ot->flags & asOBJ_REF) && ot->beh.factories.GetLength() == 0 ) // ref types without factories
|
||||
return false;
|
||||
|
||||
if( ot && (ot->flags & asOBJ_ABSTRACT) && !IsObjectHandle() ) // Can't instantiate abstract classes
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asCDataType::IsAbstractClass() const
|
||||
{
|
||||
return typeInfo && (typeInfo->flags & asOBJ_ABSTRACT) ? true : false;
|
||||
}
|
||||
|
||||
bool asCDataType::IsInterface() const
|
||||
{
|
||||
if (typeInfo == 0)
|
||||
return false;
|
||||
|
||||
asCObjectType *ot = CastToObjectType(typeInfo);
|
||||
return ot && ot->IsInterface();
|
||||
}
|
||||
|
||||
bool asCDataType::CanBeCopied() const
|
||||
{
|
||||
// All primitives can be copied
|
||||
if( IsPrimitive() ) return true;
|
||||
|
||||
// Plain-old-data structures can always be copied
|
||||
if( typeInfo->flags & asOBJ_POD ) return true;
|
||||
|
||||
// It must be possible to instantiate the type
|
||||
if( !CanBeInstantiated() ) return false;
|
||||
|
||||
// It must have a default constructor or factory and the opAssign
|
||||
// Alternatively it must have the copy constructor
|
||||
asCObjectType *ot = CastToObjectType(typeInfo);
|
||||
if (ot && (((ot->beh.construct != 0 || ot->beh.factory != 0) && ot->beh.copy != 0) ||
|
||||
(ot->beh.copyconstruct != 0 || ot->beh.copyfactory != 0)) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCDataType::IsReadOnly() const
|
||||
{
|
||||
if( isObjectHandle )
|
||||
return isConstHandle;
|
||||
|
||||
return isReadOnly;
|
||||
}
|
||||
|
||||
bool asCDataType::IsHandleToConst() const
|
||||
{
|
||||
if( !isObjectHandle ) return false;
|
||||
return isReadOnly;
|
||||
}
|
||||
|
||||
bool asCDataType::IsObjectConst() const
|
||||
{
|
||||
if( IsObjectHandle() )
|
||||
return IsHandleToConst();
|
||||
|
||||
return IsReadOnly();
|
||||
}
|
||||
|
||||
// TODO: 3.0.0: This should be removed
|
||||
bool asCDataType::IsArrayType() const
|
||||
{
|
||||
// This is only true if the type used is the default array type, i.e. the one used for the [] syntax form
|
||||
if( typeInfo && typeInfo->engine->defaultArrayObjectType )
|
||||
return typeInfo->name == typeInfo->engine->defaultArrayObjectType->name;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCDataType::IsTemplate() const
|
||||
{
|
||||
if( typeInfo && (typeInfo->flags & asOBJ_TEMPLATE) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCDataType::IsScriptObject() const
|
||||
{
|
||||
if( typeInfo && (typeInfo->flags & asOBJ_SCRIPT_OBJECT) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
asCDataType asCDataType::GetSubType(asUINT subtypeIndex) const
|
||||
{
|
||||
asASSERT(typeInfo);
|
||||
asCObjectType *ot = CastToObjectType(typeInfo);
|
||||
return ot->templateSubTypes[subtypeIndex];
|
||||
}
|
||||
|
||||
|
||||
bool asCDataType::operator !=(const asCDataType &dt) const
|
||||
{
|
||||
return !(*this == dt);
|
||||
}
|
||||
|
||||
bool asCDataType::operator ==(const asCDataType &dt) const
|
||||
{
|
||||
if( !IsEqualExceptRefAndConst(dt) ) return false;
|
||||
if( isReference != dt.isReference ) return false;
|
||||
if( isReadOnly != dt.isReadOnly ) return false;
|
||||
if( isConstHandle != dt.isConstHandle ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asCDataType::IsEqualExceptRef(const asCDataType &dt) const
|
||||
{
|
||||
if( !IsEqualExceptRefAndConst(dt) ) return false;
|
||||
if( isReadOnly != dt.isReadOnly ) return false;
|
||||
if( isConstHandle != dt.isConstHandle ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asCDataType::IsEqualExceptRefAndConst(const asCDataType &dt) const
|
||||
{
|
||||
// Check base type
|
||||
if( tokenType != dt.tokenType ) return false;
|
||||
if( typeInfo != dt.typeInfo ) return false;
|
||||
if( isObjectHandle != dt.isObjectHandle ) return false;
|
||||
if( isObjectHandle )
|
||||
if( isReadOnly != dt.isReadOnly ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asCDataType::IsEqualExceptConst(const asCDataType &dt) const
|
||||
{
|
||||
if( !IsEqualExceptRefAndConst(dt) ) return false;
|
||||
if( isReference != dt.isReference ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asCDataType::IsPrimitive() const
|
||||
{
|
||||
// Enumerations are primitives
|
||||
if( IsEnumType() )
|
||||
return true;
|
||||
|
||||
// A registered object is never a primitive neither is a pointer nor an array
|
||||
if( typeInfo )
|
||||
return false;
|
||||
|
||||
// Null handle doesn't have a typeInfo, but it is not a primitive
|
||||
if( tokenType == ttUnrecognizedToken )
|
||||
return false;
|
||||
|
||||
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 ||
|
||||
tokenType == ttInt8 ||
|
||||
tokenType == ttInt16 ||
|
||||
tokenType == ttInt64 )
|
||||
return true;
|
||||
|
||||
// Enums are also integer types
|
||||
return IsEnumType();
|
||||
}
|
||||
|
||||
bool asCDataType::IsUnsignedType() const
|
||||
{
|
||||
if( tokenType == ttUInt ||
|
||||
tokenType == ttUInt8 ||
|
||||
tokenType == ttUInt16 ||
|
||||
tokenType == ttUInt64 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCDataType::IsFloatType() const
|
||||
{
|
||||
if( tokenType == ttFloat )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCDataType::IsDoubleType() const
|
||||
{
|
||||
if( tokenType == ttDouble )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCDataType::IsBooleanType() const
|
||||
{
|
||||
if( tokenType == ttBool )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCDataType::IsObject() const
|
||||
{
|
||||
if( IsPrimitive() )
|
||||
return false;
|
||||
|
||||
// Null handle doesn't have an object type but should still be considered an object
|
||||
if( typeInfo == 0 )
|
||||
return IsNullHandle();
|
||||
|
||||
// Template subtypes shouldn't be considered objects
|
||||
return CastToObjectType(typeInfo) ? true : false;
|
||||
}
|
||||
|
||||
bool asCDataType::IsFuncdef() const
|
||||
{
|
||||
if (typeInfo && (typeInfo->flags & asOBJ_FUNCDEF))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int asCDataType::GetSizeInMemoryBytes() const
|
||||
{
|
||||
if( typeInfo != 0 )
|
||||
return typeInfo->size;
|
||||
|
||||
if( tokenType == ttVoid )
|
||||
return 0;
|
||||
|
||||
if( tokenType == ttInt8 ||
|
||||
tokenType == ttUInt8 )
|
||||
return 1;
|
||||
|
||||
if( tokenType == ttInt16 ||
|
||||
tokenType == ttUInt16 )
|
||||
return 2;
|
||||
|
||||
if( tokenType == ttDouble ||
|
||||
tokenType == ttInt64 ||
|
||||
tokenType == ttUInt64 )
|
||||
return 8;
|
||||
|
||||
if( tokenType == ttBool )
|
||||
return AS_SIZEOF_BOOL;
|
||||
|
||||
// null handle
|
||||
if( tokenType == ttUnrecognizedToken )
|
||||
return 4*AS_PTR_SIZE;
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
int asCDataType::GetSizeInMemoryDWords() const
|
||||
{
|
||||
int s = GetSizeInMemoryBytes();
|
||||
if( s == 0 ) return 0;
|
||||
if( s <= 4 ) return 1;
|
||||
|
||||
// Pad the size to 4 bytes
|
||||
if( s & 0x3 )
|
||||
s += 4 - (s & 0x3);
|
||||
|
||||
return s/4;
|
||||
}
|
||||
|
||||
int asCDataType::GetSizeOnStackDWords() const
|
||||
{
|
||||
// If the type is the variable type then the typeid is stored on the stack too
|
||||
int size = tokenType == ttQuestion ? 1 : 0;
|
||||
|
||||
if( isReference ) return AS_PTR_SIZE + size;
|
||||
if( typeInfo && !IsEnumType() ) return AS_PTR_SIZE + size;
|
||||
|
||||
return GetSizeInMemoryDWords() + size;
|
||||
}
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
int asCDataType::GetAlignment() const
|
||||
{
|
||||
if( typeInfo == NULL )
|
||||
{
|
||||
// TODO: Small primitives should not be aligned to 4 byte boundaries
|
||||
return 4; //Default alignment
|
||||
}
|
||||
|
||||
return typeInfo->alignment;
|
||||
}
|
||||
#endif
|
||||
|
||||
asSTypeBehaviour *asCDataType::GetBehaviour() const
|
||||
{
|
||||
if (!typeInfo) return 0;
|
||||
asCObjectType *ot = CastToObjectType(typeInfo);
|
||||
return ot ? &ot->beh : 0;
|
||||
}
|
||||
|
||||
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(typeInfo == 0 || typeInfo->name.GetLength() < 100);
|
||||
|
||||
if (typeInfo && (typeInfo->flags & asOBJ_ENUM))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2016 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_datatype.h
|
||||
//
|
||||
// This class describes the datatype for expressions during compilation
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_DATATYPE_H
|
||||
#define AS_DATATYPE_H
|
||||
|
||||
#include "as_tokendef.h"
|
||||
#include "as_string.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
struct asSTypeBehaviour;
|
||||
class asCScriptEngine;
|
||||
class asCTypeInfo;
|
||||
class asCScriptFunction;
|
||||
class asCModule;
|
||||
class asCObjectType;
|
||||
class asCEnumType;
|
||||
struct asSNameSpace;
|
||||
|
||||
// TODO: refactor: Reference should not be part of the datatype. This should be stored separately, e.g. in asCExprValue
|
||||
// MakeReference, MakeReadOnly, IsReference, IsReadOnly should be removed
|
||||
|
||||
class asCDataType
|
||||
{
|
||||
public:
|
||||
asCDataType();
|
||||
asCDataType(const asCDataType &);
|
||||
~asCDataType();
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
asCString Format(asSNameSpace *currNs, bool includeNamespace = false) const;
|
||||
|
||||
static asCDataType CreatePrimitive(eTokenType tt, bool isConst);
|
||||
static asCDataType CreateType(asCTypeInfo *ti, bool isConst);
|
||||
static asCDataType CreateAuto(bool isConst);
|
||||
static asCDataType CreateObjectHandle(asCTypeInfo *ot, bool isConst);
|
||||
static asCDataType CreateNullHandle();
|
||||
|
||||
int MakeHandle(bool b, bool acceptHandleForScope = false);
|
||||
int MakeArray(asCScriptEngine *engine, asCModule *requestingModule);
|
||||
int MakeReference(bool b);
|
||||
int MakeReadOnly(bool b);
|
||||
int MakeHandleToConst(bool b);
|
||||
void SetIfHandleThenConst(bool b) { ifHandleThenConst = b; }
|
||||
bool HasIfHandleThenConst() const { return ifHandleThenConst; }
|
||||
|
||||
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 IsFuncdef() const;
|
||||
|
||||
bool IsObjectConst() const;
|
||||
|
||||
bool IsEqualExceptRef(const asCDataType &) const;
|
||||
bool IsEqualExceptRefAndConst(const asCDataType &) const;
|
||||
bool IsEqualExceptConst(const asCDataType &) const;
|
||||
bool IsNullHandle() const;
|
||||
|
||||
bool SupportHandles() const;
|
||||
bool CanBeInstantiated() const;
|
||||
bool CanBeCopied() const;
|
||||
|
||||
bool operator ==(const asCDataType &) const;
|
||||
bool operator !=(const asCDataType &) const;
|
||||
|
||||
asCDataType GetSubType(asUINT subtypeIndex = 0) const;
|
||||
eTokenType GetTokenType() const {return tokenType;}
|
||||
asCTypeInfo *GetTypeInfo() const { return typeInfo; }
|
||||
|
||||
int GetSizeOnStackDWords() const;
|
||||
int GetSizeInMemoryBytes() const;
|
||||
int GetSizeInMemoryDWords() const;
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
int GetAlignment() const;
|
||||
#endif
|
||||
|
||||
void SetTokenType(eTokenType tt) {tokenType = tt;}
|
||||
void SetTypeInfo(asCTypeInfo *ti) {typeInfo = ti;}
|
||||
|
||||
asCDataType &operator =(const asCDataType &);
|
||||
|
||||
asSTypeBehaviour *GetBehaviour() const;
|
||||
|
||||
protected:
|
||||
// Base object type
|
||||
eTokenType tokenType;
|
||||
|
||||
// Behaviour type
|
||||
asCTypeInfo *typeInfo;
|
||||
|
||||
// Top level
|
||||
bool isReference:1;
|
||||
bool isReadOnly:1;
|
||||
bool isObjectHandle:1;
|
||||
bool isConstHandle:1;
|
||||
bool isAuto:1;
|
||||
bool isHandleToAsHandleType:1; // Used by the compiler to know how to initialize the object
|
||||
bool ifHandleThenConst:1; // Used when creating template instances to determine if a handle should be const or not
|
||||
char dummy:1;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2016 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_debug.h
|
||||
//
|
||||
|
||||
#ifndef AS_DEBUG_H
|
||||
#define AS_DEBUG_H
|
||||
|
||||
#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(_MSC_VER) && (defined(__GNUC__) || defined(AS_MARMALADE))
|
||||
|
||||
#ifdef __ghs__
|
||||
// WIIU defines __GNUC__ but types are not defined here in 'conventional' way
|
||||
#include <types.h>
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef float float32_t;
|
||||
typedef double float64_t;
|
||||
#else
|
||||
// Define mkdir for GNUC
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#define _mkdir(dirname) mkdir(dirname, S_IRWXU)
|
||||
#endif
|
||||
#else
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
#endif // AS_PSVITA
|
||||
#endif // _WIN32_WCE
|
||||
#endif // AS_WII
|
||||
|
||||
#endif // !defined(AS_DEBUG)
|
||||
|
||||
|
||||
|
||||
#if defined(_MSC_VER) && defined(AS_PROFILE)
|
||||
// Currently only do profiling with MSVC++
|
||||
|
||||
#include <mmsystem.h>
|
||||
#include <direct.h>
|
||||
#include "as_string.h"
|
||||
#include "as_map.h"
|
||||
#include "as_string_util.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
struct TimeCount
|
||||
{
|
||||
double time;
|
||||
int count;
|
||||
double max;
|
||||
double min;
|
||||
};
|
||||
|
||||
class CProfiler
|
||||
{
|
||||
public:
|
||||
CProfiler()
|
||||
{
|
||||
// We need to know how often the clock is updated
|
||||
__int64 tps;
|
||||
if( !QueryPerformanceFrequency((LARGE_INTEGER *)&tps) )
|
||||
usePerformance = false;
|
||||
else
|
||||
{
|
||||
usePerformance = true;
|
||||
ticksPerSecond = double(tps);
|
||||
}
|
||||
|
||||
timeOffset = GetTime();
|
||||
}
|
||||
|
||||
~CProfiler()
|
||||
{
|
||||
WriteSummary();
|
||||
}
|
||||
|
||||
double GetTime()
|
||||
{
|
||||
if( usePerformance )
|
||||
{
|
||||
__int64 ticks;
|
||||
QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
|
||||
|
||||
return double(ticks)/ticksPerSecond - timeOffset;
|
||||
}
|
||||
|
||||
return double(timeGetTime())/1000.0 - timeOffset;
|
||||
}
|
||||
|
||||
double Begin(const char *name)
|
||||
{
|
||||
double time = GetTime();
|
||||
|
||||
// Add the scope to the key
|
||||
if( key.GetLength() )
|
||||
key += "|";
|
||||
key += name;
|
||||
|
||||
// Compensate for the time spent writing to the file
|
||||
timeOffset += GetTime() - time;
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
void End(const char * /*name*/, double beginTime)
|
||||
{
|
||||
double time = GetTime();
|
||||
|
||||
double elapsed = time - beginTime;
|
||||
|
||||
// Update the profile info for this scope
|
||||
asSMapNode<asCString, TimeCount> *cursor;
|
||||
if( map.MoveTo(&cursor, key) )
|
||||
{
|
||||
cursor->value.time += elapsed;
|
||||
cursor->value.count++;
|
||||
if( cursor->value.max < elapsed )
|
||||
cursor->value.max = elapsed;
|
||||
if( cursor->value.min > elapsed )
|
||||
cursor->value.min = elapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
TimeCount tc = {elapsed, 1, elapsed, elapsed};
|
||||
map.Insert(key, tc);
|
||||
}
|
||||
|
||||
// Remove the inner most scope from the key
|
||||
int n = key.FindLast("|");
|
||||
if( n > 0 )
|
||||
key.SetLength(n);
|
||||
else
|
||||
key.SetLength(0);
|
||||
|
||||
// Compensate for the time spent writing to the file
|
||||
timeOffset += GetTime() - time;
|
||||
}
|
||||
|
||||
protected:
|
||||
void WriteSummary()
|
||||
{
|
||||
// Write the analyzed info into a file for inspection
|
||||
_mkdir("AS_DEBUG");
|
||||
FILE *fp;
|
||||
#if _MSC_VER >= 1500 && !defined(AS_MARMALADE)
|
||||
fopen_s(&fp, "AS_DEBUG/profiling_summary.txt", "wt");
|
||||
#else
|
||||
fp = fopen("AS_DEBUG/profiling_summary.txt", "wt");
|
||||
#endif
|
||||
if( fp == 0 )
|
||||
return;
|
||||
|
||||
fprintf(fp, "%-60s %10s %15s %15s %15s %15s\n\n", "Scope", "Count", "Tot time", "Avg time", "Max time", "Min time");
|
||||
|
||||
asSMapNode<asCString, TimeCount> *cursor;
|
||||
map.MoveLast(&cursor);
|
||||
while( cursor )
|
||||
{
|
||||
asCString key = cursor->key;
|
||||
int count;
|
||||
int n = key.FindLast("|", &count);
|
||||
if( count )
|
||||
{
|
||||
key = asCString(" ", count) + key.SubString(n+1);
|
||||
}
|
||||
|
||||
fprintf(fp, "%-60s %10d %15.6f %15.6f %15.6f %15.6f\n", key.AddressOf(), cursor->value.count, cursor->value.time, cursor->value.time / cursor->value.count, cursor->value.max, cursor->value.min);
|
||||
|
||||
map.MovePrev(&cursor, cursor);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
double timeOffset;
|
||||
double ticksPerSecond;
|
||||
bool usePerformance;
|
||||
|
||||
asCString key;
|
||||
asCMap<asCString, TimeCount> map;
|
||||
};
|
||||
|
||||
extern CProfiler g_profiler;
|
||||
|
||||
class CProfilerScope
|
||||
{
|
||||
public:
|
||||
CProfilerScope(const char *name)
|
||||
{
|
||||
this->name = name;
|
||||
beginTime = g_profiler.Begin(name);
|
||||
}
|
||||
|
||||
~CProfilerScope()
|
||||
{
|
||||
g_profiler.End(name, beginTime);
|
||||
}
|
||||
|
||||
protected:
|
||||
const char *name;
|
||||
double beginTime;
|
||||
};
|
||||
|
||||
#define TimeIt(x) CProfilerScope profilescope(x)
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#else // !(_MSC_VER && AS_PROFILE)
|
||||
|
||||
// Define it so nothing is done
|
||||
#define TimeIt(x)
|
||||
|
||||
#endif // !(_MSC_VER && AS_PROFILE)
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // defined(AS_DEBUG_H)
|
||||
|
||||
|
||||
@@ -0,0 +1,997 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2018 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_gc.cpp
|
||||
//
|
||||
// The implementation of the garbage collector
|
||||
//
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "as_gc.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_scriptobject.h"
|
||||
#include "as_texts.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asCGarbageCollector::asCGarbageCollector()
|
||||
{
|
||||
engine = 0;
|
||||
detectState = clearCounters_init;
|
||||
destroyNewState = destroyGarbage_init;
|
||||
destroyOldState = destroyGarbage_init;
|
||||
numDestroyed = 0;
|
||||
numNewDestroyed = 0;
|
||||
numDetected = 0;
|
||||
numAdded = 0;
|
||||
isProcessing = false;
|
||||
|
||||
seqAtSweepStart[0] = 0;
|
||||
seqAtSweepStart[1] = 0;
|
||||
seqAtSweepStart[2] = 0;
|
||||
|
||||
circularRefDetectCallbackFunc = 0;
|
||||
circularRefDetectCallbackParam = 0;
|
||||
}
|
||||
|
||||
asCGarbageCollector::~asCGarbageCollector()
|
||||
{
|
||||
// This local typedef is done to workaround a compiler error on
|
||||
// MSVC6 when using the typedef declared in the class definition
|
||||
typedef asSMapNode_t node_t;
|
||||
for( asUINT n = 0; n < freeNodes.GetLength(); n++ )
|
||||
asDELETE(freeNodes[n], node_t);
|
||||
freeNodes.SetLength(0);
|
||||
}
|
||||
|
||||
int asCGarbageCollector::AddScriptObjectToGC(void *obj, asCObjectType *objType)
|
||||
{
|
||||
if( obj == 0 || objType == 0 )
|
||||
{
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_GC_RECEIVED_NULL_PTR);
|
||||
return asINVALID_ARG;
|
||||
}
|
||||
|
||||
engine->CallObjectMethod(obj, objType->beh.addref);
|
||||
asSObjTypePair ot = {obj, objType, 0};
|
||||
|
||||
// Invoke the garbage collector to destroy a little garbage as new comes in
|
||||
// This will maintain the number of objects in the GC at a maintainable level without
|
||||
// halting the application, and without burdening the application with manually invoking the
|
||||
// garbage collector.
|
||||
if( engine->ep.autoGarbageCollect && gcNewObjects.GetLength() )
|
||||
{
|
||||
// If the GC is already processing in another thread, then don't try this again
|
||||
if( TRYENTERCRITICALSECTION(gcCollecting) )
|
||||
{
|
||||
// Skip this if the GC is already running in this thread
|
||||
if( !isProcessing )
|
||||
{
|
||||
isProcessing = true;
|
||||
|
||||
// TODO: The number of iterations should be dynamic, and increase
|
||||
// if the number of objects in the garbage collector grows high
|
||||
|
||||
// Run one step of DetectGarbage
|
||||
if( gcOldObjects.GetLength() )
|
||||
{
|
||||
IdentifyGarbageWithCyclicRefs();
|
||||
DestroyOldGarbage();
|
||||
}
|
||||
|
||||
// Run a few steps of DestroyGarbage
|
||||
int iter = (int)gcNewObjects.GetLength();
|
||||
if( iter > 10 ) iter = 10;
|
||||
while( iter-- > 0 )
|
||||
DestroyNewGarbage();
|
||||
|
||||
isProcessing = false;
|
||||
}
|
||||
|
||||
LEAVECRITICALSECTION(gcCollecting);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the data to the gcObjects array in a critical section as
|
||||
// another thread might be calling this method at the same time
|
||||
ENTERCRITICALSECTION(gcCritical);
|
||||
ot.seqNbr = numAdded++;
|
||||
gcNewObjects.PushLast(ot);
|
||||
LEAVECRITICALSECTION(gcCritical);
|
||||
|
||||
return ot.seqNbr;
|
||||
}
|
||||
|
||||
int asCGarbageCollector::GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asITypeInfo **type)
|
||||
{
|
||||
if( seqNbr ) *seqNbr = 0;
|
||||
if( obj ) *obj = 0;
|
||||
if( type ) *type = 0;
|
||||
|
||||
ENTERCRITICALSECTION(gcCritical);
|
||||
asSObjTypePair *o = 0;
|
||||
asUINT newObjs = asUINT(gcNewObjects.GetLength());
|
||||
if( idx < newObjs )
|
||||
o = &gcNewObjects[idx];
|
||||
else if( idx < gcOldObjects.GetLength() + newObjs )
|
||||
o = &gcOldObjects[idx-newObjs];
|
||||
else
|
||||
{
|
||||
LEAVECRITICALSECTION(gcCritical);
|
||||
return asINVALID_ARG;
|
||||
}
|
||||
if( seqNbr ) *seqNbr = o->seqNbr;
|
||||
if( obj ) *obj = o->obj;
|
||||
if( type ) *type = o->type;
|
||||
LEAVECRITICALSECTION(gcCritical);
|
||||
|
||||
return asSUCCESS;
|
||||
}
|
||||
|
||||
// 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) )
|
||||
{
|
||||
// If the GC is already processing in this thread, then don't enter here again
|
||||
if( isProcessing )
|
||||
{
|
||||
LEAVECRITICALSECTION(gcCollecting);
|
||||
return 1;
|
||||
}
|
||||
|
||||
isProcessing = true;
|
||||
|
||||
bool doDetect = (flags & asGC_DETECT_GARBAGE) || !(flags & asGC_DESTROY_GARBAGE);
|
||||
bool doDestroy = (flags & asGC_DESTROY_GARBAGE) || !(flags & asGC_DETECT_GARBAGE);
|
||||
|
||||
if( flags & asGC_FULL_CYCLE )
|
||||
{
|
||||
// Reset the state
|
||||
if( doDetect )
|
||||
{
|
||||
// Move all new objects to the old list, so we guarantee that all is detected
|
||||
MoveAllObjectsToOldList();
|
||||
detectState = clearCounters_init;
|
||||
}
|
||||
if( doDestroy )
|
||||
{
|
||||
destroyNewState = destroyGarbage_init;
|
||||
destroyOldState = destroyGarbage_init;
|
||||
}
|
||||
|
||||
// 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
|
||||
if( doDetect )
|
||||
while( IdentifyGarbageWithCyclicRefs() == 1 ) {}
|
||||
|
||||
// Now destroy all known garbage
|
||||
if( doDestroy )
|
||||
{
|
||||
if( !doDetect )
|
||||
while( DestroyNewGarbage() == 1 ) {}
|
||||
while( DestroyOldGarbage() == 1 ) {}
|
||||
}
|
||||
|
||||
// Run another iteration if any garbage was destroyed
|
||||
if( count != (unsigned int)(gcOldObjects.GetLength()) )
|
||||
count = (unsigned int)(gcOldObjects.GetLength());
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
isProcessing = false;
|
||||
LEAVECRITICALSECTION(gcCollecting);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
while( iterations-- > 0 )
|
||||
{
|
||||
// Destroy the garbage that we know of
|
||||
if( doDestroy )
|
||||
{
|
||||
DestroyNewGarbage();
|
||||
DestroyOldGarbage();
|
||||
}
|
||||
|
||||
// Run another incremental step of the identification of cyclic references
|
||||
if( doDetect && gcOldObjects.GetLength() > 0 )
|
||||
IdentifyGarbageWithCyclicRefs();
|
||||
}
|
||||
}
|
||||
|
||||
isProcessing = false;
|
||||
LEAVECRITICALSECTION(gcCollecting);
|
||||
}
|
||||
|
||||
// Return 1 to indicate that the cycle wasn't finished
|
||||
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 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;
|
||||
|
||||
if( totalDetected )
|
||||
*totalDetected = numDetected;
|
||||
|
||||
if( newObjects )
|
||||
*newObjects = (asUINT)gcNewObjects.GetLength();
|
||||
|
||||
if( totalNewDestroyed )
|
||||
*totalNewDestroyed = numNewDestroyed;
|
||||
}
|
||||
|
||||
asCGarbageCollector::asSObjTypePair asCGarbageCollector::GetNewObjectAtIdx(int idx)
|
||||
{
|
||||
// We need to protect this access with a critical section as
|
||||
// another thread might be appending an object at the same time
|
||||
ENTERCRITICALSECTION(gcCritical);
|
||||
asSObjTypePair gcObj = gcNewObjects[idx];
|
||||
LEAVECRITICALSECTION(gcCritical);
|
||||
|
||||
return gcObj;
|
||||
}
|
||||
|
||||
asCGarbageCollector::asSObjTypePair asCGarbageCollector::GetOldObjectAtIdx(int idx)
|
||||
{
|
||||
// We need to protect this access with a critical section as
|
||||
// another thread might be appending an object at the same time
|
||||
ENTERCRITICALSECTION(gcCritical);
|
||||
asSObjTypePair gcObj = gcOldObjects[idx];
|
||||
LEAVECRITICALSECTION(gcCritical);
|
||||
|
||||
return gcObj;
|
||||
}
|
||||
|
||||
void asCGarbageCollector::RemoveNewObjectAtIdx(int idx)
|
||||
{
|
||||
// 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( idx == (int)gcNewObjects.GetLength() - 1)
|
||||
gcNewObjects.PopLast();
|
||||
else
|
||||
gcNewObjects[idx] = gcNewObjects.PopLast();
|
||||
LEAVECRITICALSECTION(gcCritical);
|
||||
}
|
||||
|
||||
void asCGarbageCollector::RemoveOldObjectAtIdx(int idx)
|
||||
{
|
||||
// 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( idx == (int)gcOldObjects.GetLength() - 1)
|
||||
gcOldObjects.PopLast();
|
||||
else
|
||||
gcOldObjects[idx] = gcOldObjects.PopLast();
|
||||
LEAVECRITICALSECTION(gcCritical);
|
||||
}
|
||||
|
||||
void asCGarbageCollector::MoveObjectToOldList(int idx)
|
||||
{
|
||||
// We need to protect this update with a critical section as
|
||||
// another thread might be appending an object at the same time
|
||||
ENTERCRITICALSECTION(gcCritical);
|
||||
gcOldObjects.PushLast(gcNewObjects[idx]);
|
||||
if( idx == (int)gcNewObjects.GetLength() - 1)
|
||||
gcNewObjects.PopLast();
|
||||
else
|
||||
gcNewObjects[idx] = gcNewObjects.PopLast();
|
||||
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
|
||||
asASSERT(isProcessing);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
switch( destroyNewState )
|
||||
{
|
||||
case destroyGarbage_init:
|
||||
{
|
||||
// If there are no objects to be freed then don't start
|
||||
if( gcNewObjects.GetLength() == 0 )
|
||||
return 0;
|
||||
|
||||
// Update the seqAtSweepStart which is used to determine when
|
||||
// to move an object from the new set to the old set
|
||||
seqAtSweepStart[0] = seqAtSweepStart[1];
|
||||
seqAtSweepStart[1] = seqAtSweepStart[2];
|
||||
seqAtSweepStart[2] = numAdded;
|
||||
|
||||
destroyNewIdx = (asUINT)-1;
|
||||
destroyNewState = destroyGarbage_loop;
|
||||
}
|
||||
break;
|
||||
|
||||
case destroyGarbage_loop:
|
||||
case destroyGarbage_haveMore:
|
||||
{
|
||||
// If the refCount has reached 1, then only the GC still holds a
|
||||
// reference to the object, thus we don't need to worry about the
|
||||
// application touching the objects during collection.
|
||||
|
||||
// Destroy all objects that have refCount == 1. If any objects are
|
||||
// destroyed, go over the list again, because it may have made more
|
||||
// objects reach refCount == 1.
|
||||
if( ++destroyNewIdx < gcNewObjects.GetLength() )
|
||||
{
|
||||
asSObjTypePair gcObj = GetNewObjectAtIdx(destroyNewIdx);
|
||||
if( engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount) == 1 )
|
||||
{
|
||||
// Release the object immediately
|
||||
|
||||
// Make sure the refCount is really 0, because the
|
||||
// destructor may have increased the refCount again.
|
||||
bool addRef = false;
|
||||
if( gcObj.type->flags & asOBJ_SCRIPT_OBJECT )
|
||||
{
|
||||
// Script objects may actually be resurrected in the destructor
|
||||
int refCount = ((asCScriptObject*)gcObj.obj)->Release();
|
||||
if( refCount > 0 ) addRef = true;
|
||||
}
|
||||
else
|
||||
engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release);
|
||||
|
||||
// Was the object really destroyed?
|
||||
if( !addRef )
|
||||
{
|
||||
numDestroyed++;
|
||||
numNewDestroyed++;
|
||||
RemoveNewObjectAtIdx(destroyNewIdx);
|
||||
destroyNewIdx--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Since the object was resurrected in the
|
||||
// destructor, we must add our reference again
|
||||
engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref);
|
||||
}
|
||||
|
||||
destroyNewState = destroyGarbage_haveMore;
|
||||
}
|
||||
// Check if this object has been inspected 3 times already, and if so move it to the
|
||||
// set of old objects that are less likely to become garbage in a short time
|
||||
// TODO: Is 3 really a good value? Should the number of times be dynamic?
|
||||
else if( gcObj.seqNbr < seqAtSweepStart[0] )
|
||||
{
|
||||
// We've already verified this object multiple times. It is likely
|
||||
// to live for quite a long time so we'll move it to the list if old objects
|
||||
MoveObjectToOldList(destroyNewIdx);
|
||||
destroyNewIdx--;
|
||||
}
|
||||
|
||||
// Allow the application to work a little
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( destroyNewState == destroyGarbage_haveMore )
|
||||
{
|
||||
// Restart the cycle
|
||||
destroyNewState = destroyGarbage_init;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restart the cycle
|
||||
destroyNewState = destroyGarbage_init;
|
||||
|
||||
// Return 0 to tell the application that there
|
||||
// is no more garbage to destroy at the moment
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Shouldn't reach this point
|
||||
UNREACHABLE_RETURN;
|
||||
}
|
||||
|
||||
int asCGarbageCollector::ReportAndReleaseUndestroyedObjects()
|
||||
{
|
||||
// This function will only be called as the engine is shutting down
|
||||
|
||||
int items = 0;
|
||||
for( asUINT n = 0; n < gcOldObjects.GetLength(); n++ )
|
||||
{
|
||||
asSObjTypePair gcObj = GetOldObjectAtIdx(n);
|
||||
|
||||
int refCount = 0;
|
||||
if( gcObj.type->beh.gcGetRefCount && engine->scriptFunctions[gcObj.type->beh.gcGetRefCount] )
|
||||
refCount = engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount);
|
||||
|
||||
// Report the object as not being properly destroyed
|
||||
asCString msg;
|
||||
msg.Format(TXT_d_GC_CANNOT_FREE_OBJ_OF_TYPE_s_REF_COUNT_d, gcObj.seqNbr, gcObj.type->name.AddressOf(), refCount - 1);
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
|
||||
|
||||
// Add additional info for builtin types
|
||||
if( gcObj.type->name == "$func" )
|
||||
{
|
||||
// Unfortunately we can't show the function declaration here, because the engine may have released the parameter list already so the declaration would only be misleading
|
||||
// We need to show the function type too as for example delegates do not have a name
|
||||
msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, reinterpret_cast<asCScriptFunction*>(gcObj.obj)->GetName(), reinterpret_cast<asCScriptFunction*>(gcObj.obj)->GetFuncType());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
else if( gcObj.type->name == "$obj" )
|
||||
{
|
||||
msg.Format(TXT_PREV_TYPE_IS_NAMED_s, reinterpret_cast<asCObjectType*>(gcObj.obj)->GetName());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
|
||||
// Release the reference that the GC holds if the release functions is still available
|
||||
if( gcObj.type->beh.release && engine->scriptFunctions[gcObj.type->beh.release] )
|
||||
engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release);
|
||||
|
||||
items++;
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
int asCGarbageCollector::DestroyOldGarbage()
|
||||
{
|
||||
// This function will only be called within the critical section gcCollecting
|
||||
asASSERT(isProcessing);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
switch( destroyOldState )
|
||||
{
|
||||
case destroyGarbage_init:
|
||||
{
|
||||
// If there are no objects to be freed then don't start
|
||||
if( gcOldObjects.GetLength() == 0 )
|
||||
return 0;
|
||||
|
||||
destroyOldIdx = (asUINT)-1;
|
||||
destroyOldState = destroyGarbage_loop;
|
||||
}
|
||||
break;
|
||||
|
||||
case destroyGarbage_loop:
|
||||
case destroyGarbage_haveMore:
|
||||
{
|
||||
// If the refCount has reached 1, then only the GC still holds a
|
||||
// reference to the object, thus we don't need to worry about the
|
||||
// application touching the objects during collection.
|
||||
|
||||
// Destroy all objects that have refCount == 1. If any objects are
|
||||
// destroyed, go over the list again, because it may have made more
|
||||
// objects reach refCount == 1.
|
||||
if( ++destroyOldIdx < gcOldObjects.GetLength() )
|
||||
{
|
||||
asSObjTypePair gcObj = GetOldObjectAtIdx(destroyOldIdx);
|
||||
|
||||
if( gcObj.type->beh.gcGetRefCount == 0 )
|
||||
{
|
||||
// If circular references are formed with registered types that hasn't
|
||||
// registered the GC behaviours, then the engine may be forced to free
|
||||
// the object type before the actual object instance. In this case we
|
||||
// will be forced to skip the destruction of the objects, so as not to
|
||||
// crash the application.
|
||||
asCString msg;
|
||||
msg.Format(TXT_d_GC_CANNOT_FREE_OBJ_OF_TYPE_s, gcObj.seqNbr, gcObj.type->name.AddressOf());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
|
||||
|
||||
// Just remove the object, as we will not bother to destroy it
|
||||
numDestroyed++;
|
||||
RemoveOldObjectAtIdx(destroyOldIdx);
|
||||
destroyOldIdx--;
|
||||
}
|
||||
else if( engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount) == 1 )
|
||||
{
|
||||
// Release the object immediately
|
||||
|
||||
// Make sure the refCount is really 0, because the
|
||||
// destructor may have increased the refCount again.
|
||||
bool addRef = false;
|
||||
if( gcObj.type->flags & asOBJ_SCRIPT_OBJECT )
|
||||
{
|
||||
// Script objects may actually be resurrected in the destructor
|
||||
int refCount = ((asCScriptObject*)gcObj.obj)->Release();
|
||||
if( refCount > 0 ) addRef = true;
|
||||
}
|
||||
else
|
||||
engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release);
|
||||
|
||||
// Was the object really destroyed?
|
||||
if( !addRef )
|
||||
{
|
||||
numDestroyed++;
|
||||
RemoveOldObjectAtIdx(destroyOldIdx);
|
||||
destroyOldIdx--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Since the object was resurrected in the
|
||||
// destructor, we must add our reference again
|
||||
engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref);
|
||||
}
|
||||
|
||||
destroyOldState = destroyGarbage_haveMore;
|
||||
}
|
||||
|
||||
// Allow the application to work a little
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( destroyOldState == destroyGarbage_haveMore )
|
||||
{
|
||||
// Restart the cycle
|
||||
destroyOldState = destroyGarbage_init;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restart the cycle
|
||||
destroyOldState = destroyGarbage_init;
|
||||
|
||||
// Return 0 to tell the application that there
|
||||
// is no more garbage to destroy at the moment
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Shouldn't reach this point
|
||||
UNREACHABLE_RETURN;
|
||||
}
|
||||
|
||||
int asCGarbageCollector::IdentifyGarbageWithCyclicRefs()
|
||||
{
|
||||
// This function will only be called within the critical section gcCollecting
|
||||
asASSERT(isProcessing);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
switch( detectState )
|
||||
{
|
||||
case clearCounters_init:
|
||||
detectState = clearCounters_loop;
|
||||
break;
|
||||
|
||||
case clearCounters_loop:
|
||||
{
|
||||
// Decrease reference counter for all objects removed from the map
|
||||
asSMapNode<void*, asSIntTypePair> *cursor = 0;
|
||||
gcMap.MoveFirst(&cursor);
|
||||
if( cursor )
|
||||
{
|
||||
void *obj = gcMap.GetKey(cursor);
|
||||
asSIntTypePair it = gcMap.GetValue(cursor);
|
||||
|
||||
engine->CallObjectMethod(obj, it.type->beh.release);
|
||||
|
||||
ReturnNode(gcMap.Remove(cursor));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
detectState = buildMap_init;
|
||||
}
|
||||
break;
|
||||
|
||||
case buildMap_init:
|
||||
detectIdx = 0;
|
||||
detectState = buildMap_loop;
|
||||
break;
|
||||
|
||||
case buildMap_loop:
|
||||
{
|
||||
// Build a map of objects that will be checked, the map will
|
||||
// hold the object pointer as key, and the gcCount and the
|
||||
// object's type as value. As objects are added to the map the
|
||||
// gcFlag must be set in the objects, so we can be verify if
|
||||
// the object is accessed during the GC cycle.
|
||||
|
||||
// If an object is removed from the gcObjects list during the
|
||||
// iteration of this step, it is possible that an object won't
|
||||
// be used during the analyzing for cyclic references. This
|
||||
// isn't a problem, as the next time the GC cycle starts the
|
||||
// object will be verified.
|
||||
if( detectIdx < gcOldObjects.GetLength() )
|
||||
{
|
||||
// Add the gc count for this object
|
||||
asSObjTypePair gcObj = GetOldObjectAtIdx(detectIdx);
|
||||
|
||||
int refCount = 0;
|
||||
if( gcObj.type->beh.gcGetRefCount )
|
||||
refCount = engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount);
|
||||
|
||||
if( refCount > 1 )
|
||||
{
|
||||
asSIntTypePair it = {refCount-1, gcObj.type};
|
||||
|
||||
gcMap.Insert(GetNode(gcObj.obj, it));
|
||||
|
||||
// Increment the object's reference counter when putting it in the map
|
||||
engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref);
|
||||
|
||||
// Mark the object so that we can
|
||||
// see if it has changed since read
|
||||
engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.gcSetFlag);
|
||||
}
|
||||
|
||||
detectIdx++;
|
||||
|
||||
// Let the application work a little
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
detectState = countReferences_init;
|
||||
}
|
||||
break;
|
||||
|
||||
case countReferences_init:
|
||||
{
|
||||
gcMap.MoveFirst(&gcMapCursor);
|
||||
detectState = countReferences_loop;
|
||||
}
|
||||
break;
|
||||
|
||||
case countReferences_loop:
|
||||
{
|
||||
// Call EnumReferences on all objects in the map to count the number
|
||||
// of references reachable from between objects in the map. If all
|
||||
// references for an object in the map is reachable from other objects
|
||||
// in the map, then we know that no outside references are held for
|
||||
// this object, thus it is a potential dead object in a circular reference.
|
||||
|
||||
// If the gcFlag is cleared for an object we consider the object alive
|
||||
// and referenced from outside the GC, thus we don't enumerate its references.
|
||||
|
||||
// Any new objects created after this step in the GC cycle won't be
|
||||
// in the map, and is thus automatically considered alive.
|
||||
if( gcMapCursor )
|
||||
{
|
||||
void *obj = gcMap.GetKey(gcMapCursor);
|
||||
asCObjectType *type = gcMap.GetValue(gcMapCursor).type;
|
||||
gcMap.MoveNext(&gcMapCursor, gcMapCursor);
|
||||
|
||||
if( engine->CallObjectMethodRetBool(obj, type->beh.gcGetFlag) )
|
||||
{
|
||||
engine->CallObjectMethod(obj, engine, type->beh.gcEnumReferences);
|
||||
}
|
||||
|
||||
// Allow the application to work a little
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
detectState = detectGarbage_init;
|
||||
}
|
||||
break;
|
||||
|
||||
case detectGarbage_init:
|
||||
{
|
||||
gcMap.MoveFirst(&gcMapCursor);
|
||||
liveObjects.SetLength(0);
|
||||
detectState = detectGarbage_loop1;
|
||||
}
|
||||
break;
|
||||
|
||||
case detectGarbage_loop1:
|
||||
{
|
||||
// All objects that are known not to be dead must be removed from the map,
|
||||
// along with all objects they reference. What remains in the map after
|
||||
// this pass is sure to be dead objects in circular references.
|
||||
|
||||
// An object is considered alive if its gcFlag is cleared, or all the
|
||||
// references were not found in the map.
|
||||
|
||||
// Add all alive objects from the map to the liveObjects array
|
||||
if( gcMapCursor )
|
||||
{
|
||||
asSMapNode<void*, asSIntTypePair> *cursor = gcMapCursor;
|
||||
gcMap.MoveNext(&gcMapCursor, gcMapCursor);
|
||||
|
||||
void *obj = gcMap.GetKey(cursor);
|
||||
asSIntTypePair it = gcMap.GetValue(cursor);
|
||||
|
||||
bool gcFlag = engine->CallObjectMethodRetBool(obj, it.type->beh.gcGetFlag);
|
||||
if( !gcFlag || it.i > 0 )
|
||||
{
|
||||
liveObjects.PushLast(obj);
|
||||
}
|
||||
|
||||
// Allow the application to work a little
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
detectState = detectGarbage_loop2;
|
||||
}
|
||||
break;
|
||||
|
||||
case detectGarbage_loop2:
|
||||
{
|
||||
// In this step we are actually removing the alive objects from the map.
|
||||
// As the object is removed, all the objects it references are added to the
|
||||
// liveObjects list, by calling EnumReferences. Only objects still in the map
|
||||
// will be added to the liveObjects list.
|
||||
if( liveObjects.GetLength() )
|
||||
{
|
||||
void *gcObj = liveObjects.PopLast();
|
||||
asCObjectType *type = 0;
|
||||
|
||||
// Remove the object from the map to mark it as alive
|
||||
asSMapNode<void*, asSIntTypePair> *cursor = 0;
|
||||
if( gcMap.MoveTo(&cursor, gcObj) )
|
||||
{
|
||||
type = gcMap.GetValue(cursor).type;
|
||||
ReturnNode(gcMap.Remove(cursor));
|
||||
|
||||
// We need to decrease the reference count again as we remove the object from the map
|
||||
engine->CallObjectMethod(gcObj, type->beh.release);
|
||||
|
||||
// Enumerate all the object's references so that they too can be marked as alive
|
||||
engine->CallObjectMethod(gcObj, engine, type->beh.gcEnumReferences);
|
||||
}
|
||||
|
||||
// Allow the application to work a little
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
detectState = verifyUnmarked_init;
|
||||
}
|
||||
break;
|
||||
|
||||
case verifyUnmarked_init:
|
||||
gcMap.MoveFirst(&gcMapCursor);
|
||||
detectState = verifyUnmarked_loop;
|
||||
break;
|
||||
|
||||
case verifyUnmarked_loop:
|
||||
{
|
||||
// In this step we must make sure that none of the objects still in the map
|
||||
// has been touched by the application. If they have then we must run the
|
||||
// detectGarbage loop once more.
|
||||
if( gcMapCursor )
|
||||
{
|
||||
void *gcObj = gcMap.GetKey(gcMapCursor);
|
||||
asCObjectType *type = gcMap.GetValue(gcMapCursor).type;
|
||||
|
||||
bool gcFlag = engine->CallObjectMethodRetBool(gcObj, type->beh.gcGetFlag);
|
||||
if( !gcFlag )
|
||||
{
|
||||
// The unmarked object was touched, rerun the detectGarbage loop
|
||||
detectState = detectGarbage_init;
|
||||
}
|
||||
else
|
||||
gcMap.MoveNext(&gcMapCursor, gcMapCursor);
|
||||
|
||||
// Allow the application to work a little
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No unmarked object was touched, we can now be sure
|
||||
// that objects that have gcCount == 0 really is garbage
|
||||
detectState = breakCircles_init;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case breakCircles_init:
|
||||
{
|
||||
gcMap.MoveFirst(&gcMapCursor);
|
||||
detectState = breakCircles_loop;
|
||||
|
||||
// If the application has requested a callback for detected circular references,
|
||||
// then make that callback now for all the objects in the list. This step is not
|
||||
// done in incremental steps as it is only meant for debugging purposes and thus
|
||||
// doesn't require interactivity
|
||||
if (gcMapCursor && circularRefDetectCallbackFunc)
|
||||
{
|
||||
while (gcMapCursor)
|
||||
{
|
||||
void *gcObj = gcMap.GetKey(gcMapCursor);
|
||||
asCObjectType *type = gcMap.GetValue(gcMapCursor).type;
|
||||
circularRefDetectCallbackFunc(type, gcObj, circularRefDetectCallbackParam);
|
||||
|
||||
gcMap.MoveNext(&gcMapCursor, gcMapCursor);
|
||||
}
|
||||
|
||||
// Reset iterator
|
||||
gcMap.MoveFirst(&gcMapCursor);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case breakCircles_loop:
|
||||
case breakCircles_haveGarbage:
|
||||
{
|
||||
// All objects in the map are now known to be dead objects
|
||||
// kept alive through circular references. To be able to free
|
||||
// these objects we need to force the breaking of the circle
|
||||
// by having the objects release their references.
|
||||
if( gcMapCursor )
|
||||
{
|
||||
numDetected++;
|
||||
void *gcObj = gcMap.GetKey(gcMapCursor);
|
||||
asCObjectType *type = gcMap.GetValue(gcMapCursor).type;
|
||||
if( type->flags & asOBJ_SCRIPT_OBJECT )
|
||||
{
|
||||
// For script objects we must call the class destructor before
|
||||
// releasing the references, otherwise the destructor may not
|
||||
// be able to perform the necessary clean-up as the handles will
|
||||
// be null.
|
||||
reinterpret_cast<asCScriptObject*>(gcObj)->CallDestructor();
|
||||
}
|
||||
engine->CallObjectMethod(gcObj, engine, type->beh.gcReleaseAllReferences);
|
||||
|
||||
gcMap.MoveNext(&gcMapCursor, gcMapCursor);
|
||||
|
||||
detectState = breakCircles_haveGarbage;
|
||||
|
||||
// Allow the application to work a little
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no garbage was detected we can finish now
|
||||
if( detectState != breakCircles_haveGarbage )
|
||||
{
|
||||
// Restart the GC
|
||||
detectState = clearCounters_init;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restart the GC
|
||||
detectState = clearCounters_init;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // switch
|
||||
}
|
||||
|
||||
// Shouldn't reach this point
|
||||
UNREACHABLE_RETURN;
|
||||
}
|
||||
|
||||
asCGarbageCollector::asSMapNode_t *asCGarbageCollector::GetNode(void *obj, asSIntTypePair it)
|
||||
{
|
||||
// This function will only be called within the critical section gcCollecting
|
||||
asASSERT(isProcessing);
|
||||
|
||||
asSMapNode_t *node;
|
||||
if( freeNodes.GetLength() )
|
||||
node = freeNodes.PopLast();
|
||||
else
|
||||
{
|
||||
node = asNEW(asSMapNode_t);
|
||||
if( !node )
|
||||
{
|
||||
// Out of memory
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
node->Init(obj, it);
|
||||
return node;
|
||||
}
|
||||
|
||||
void asCGarbageCollector::ReturnNode(asSMapNode_t *node)
|
||||
{
|
||||
// This function will only be called within the critical section gcCollecting
|
||||
asASSERT(isProcessing);
|
||||
|
||||
if( node )
|
||||
freeNodes.PushLast(node);
|
||||
}
|
||||
|
||||
void asCGarbageCollector::GCEnumCallback(void *reference)
|
||||
{
|
||||
// This function will only be called within the critical section gcCollecting
|
||||
asASSERT(isProcessing);
|
||||
|
||||
if( detectState == countReferences_loop )
|
||||
{
|
||||
// Find the reference in the map
|
||||
asSMapNode<void*, asSIntTypePair> *cursor = 0;
|
||||
if( gcMap.MoveTo(&cursor, reference) )
|
||||
{
|
||||
// Decrease the counter in the map for the reference
|
||||
gcMap.GetValue(cursor).i--;
|
||||
}
|
||||
}
|
||||
else if( detectState == detectGarbage_loop2 )
|
||||
{
|
||||
// Find the reference in the map
|
||||
asSMapNode<void*, asSIntTypePair> *cursor = 0;
|
||||
if( gcMap.MoveTo(&cursor, reference) )
|
||||
{
|
||||
// Add the object to the list of objects to mark as alive
|
||||
liveObjects.PushLast(reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2018 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_gc.h
|
||||
//
|
||||
// The garbage collector is used to resolve cyclic references
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_GC_H
|
||||
#define AS_GC_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_array.h"
|
||||
#include "as_map.h"
|
||||
#include "as_thread.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCScriptEngine;
|
||||
class asCObjectType;
|
||||
|
||||
class asCGarbageCollector
|
||||
{
|
||||
public:
|
||||
asCGarbageCollector();
|
||||
~asCGarbageCollector();
|
||||
|
||||
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);
|
||||
int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asITypeInfo **type);
|
||||
|
||||
int ReportAndReleaseUndestroyedObjects();
|
||||
|
||||
asCScriptEngine *engine;
|
||||
|
||||
// Callback for when circular reference are detected
|
||||
asCIRCULARREFFUNC_t circularRefDetectCallbackFunc;
|
||||
void * circularRefDetectCallbackParam;
|
||||
|
||||
protected:
|
||||
struct asSObjTypePair {void *obj; asCObjectType *type; asUINT seqNbr;};
|
||||
struct asSIntTypePair {int i; asCObjectType *type;};
|
||||
typedef asSMapNode<void*, asSIntTypePair> asSMapNode_t;
|
||||
|
||||
enum egcDestroyState
|
||||
{
|
||||
destroyGarbage_init = 0,
|
||||
destroyGarbage_loop,
|
||||
destroyGarbage_haveMore
|
||||
};
|
||||
|
||||
enum egcDetectState
|
||||
{
|
||||
clearCounters_init = 0,
|
||||
clearCounters_loop,
|
||||
buildMap_init,
|
||||
buildMap_loop,
|
||||
countReferences_init,
|
||||
countReferences_loop,
|
||||
detectGarbage_init,
|
||||
detectGarbage_loop1,
|
||||
detectGarbage_loop2,
|
||||
verifyUnmarked_init,
|
||||
verifyUnmarked_loop,
|
||||
breakCircles_init,
|
||||
breakCircles_loop,
|
||||
breakCircles_haveGarbage
|
||||
};
|
||||
|
||||
int DestroyNewGarbage();
|
||||
int DestroyOldGarbage();
|
||||
int IdentifyGarbageWithCyclicRefs();
|
||||
asSObjTypePair GetNewObjectAtIdx(int idx);
|
||||
asSObjTypePair GetOldObjectAtIdx(int idx);
|
||||
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;
|
||||
asCArray<asSObjTypePair> gcOldObjects;
|
||||
|
||||
// This array temporarily holds references to objects known to be live objects
|
||||
asCArray<void*> liveObjects;
|
||||
|
||||
// This map holds objects currently being searched for cyclic references, it also holds a
|
||||
// counter that gives the number of references to the object that the GC can't reach
|
||||
asCMap<void*, asSIntTypePair> gcMap;
|
||||
|
||||
// State variables
|
||||
egcDestroyState destroyNewState;
|
||||
egcDestroyState destroyOldState;
|
||||
asUINT destroyNewIdx;
|
||||
asUINT destroyOldIdx;
|
||||
asUINT numDestroyed;
|
||||
asUINT numNewDestroyed;
|
||||
egcDetectState detectState;
|
||||
asUINT detectIdx;
|
||||
asUINT numDetected;
|
||||
asUINT numAdded;
|
||||
asUINT seqAtSweepStart[3];
|
||||
asSMapNode_t *gcMapCursor;
|
||||
bool isProcessing;
|
||||
|
||||
// We'll keep a pool of nodes to avoid allocating memory all the time
|
||||
asSMapNode_t *GetNode(void *obj, asSIntTypePair it);
|
||||
void ReturnNode(asSMapNode_t *node);
|
||||
asCArray<asSMapNode_t*> freeNodes;
|
||||
|
||||
// Critical section for multithreaded access
|
||||
DECLARECRITICALSECTION(gcCritical) // Used for adding/removing objects
|
||||
DECLARECRITICALSECTION(gcCollecting) // Used for processing
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,534 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2016 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_generic.cpp
|
||||
//
|
||||
// This class handles the call to a function registered with asCALL_GENERIC
|
||||
//
|
||||
|
||||
#include "as_generic.h"
|
||||
#include "as_scriptfunction.h"
|
||||
#include "as_objecttype.h"
|
||||
#include "as_scriptengine.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// TODO: runtime optimize: The access to the arguments should be optimized so that code
|
||||
// doesn't have to count the position of the argument with every call
|
||||
|
||||
// internal
|
||||
asCGeneric::asCGeneric(asCScriptEngine *engine, asCScriptFunction *sysFunction, void *currentObject, asDWORD *stackPointer)
|
||||
{
|
||||
this->engine = engine;
|
||||
this->sysFunction = sysFunction;
|
||||
this->currentObject = currentObject;
|
||||
this->stackPointer = stackPointer;
|
||||
|
||||
objectRegister = 0;
|
||||
returnVal = 0;
|
||||
}
|
||||
|
||||
// internal
|
||||
asCGeneric::~asCGeneric()
|
||||
{
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asCGeneric::GetAuxiliary() const
|
||||
{
|
||||
return sysFunction->GetAuxiliary();
|
||||
}
|
||||
|
||||
// interface
|
||||
asIScriptEngine *asCGeneric::GetEngine() const
|
||||
{
|
||||
return (asIScriptEngine*)engine;
|
||||
}
|
||||
|
||||
// interface
|
||||
asIScriptFunction *asCGeneric::GetFunction() const
|
||||
{
|
||||
return sysFunction;
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asCGeneric::GetObject()
|
||||
{
|
||||
return currentObject;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCGeneric::GetObjectTypeId() const
|
||||
{
|
||||
asCDataType dt = asCDataType::CreateType(sysFunction->objectType, false);
|
||||
return engine->GetTypeIdFromDataType(dt);
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCGeneric::GetArgCount() const
|
||||
{
|
||||
return (int)sysFunction->parameterTypes.GetLength();
|
||||
}
|
||||
|
||||
// interface
|
||||
asBYTE asCGeneric::GetArgByte(asUINT arg)
|
||||
{
|
||||
if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() )
|
||||
return 0;
|
||||
|
||||
// Verify that the type is correct
|
||||
asCDataType *dt = &sysFunction->parameterTypes[arg];
|
||||
if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() )
|
||||
return 0;
|
||||
|
||||
if( dt->GetSizeInMemoryBytes() != 1 )
|
||||
return 0;
|
||||
|
||||
// Determine the position of the argument
|
||||
int offset = 0;
|
||||
for( asUINT n = 0; n < arg; n++ )
|
||||
offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
|
||||
|
||||
// Get the value
|
||||
return *(asBYTE*)&stackPointer[offset];
|
||||
}
|
||||
|
||||
// interface
|
||||
asWORD asCGeneric::GetArgWord(asUINT arg)
|
||||
{
|
||||
if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() )
|
||||
return 0;
|
||||
|
||||
// Verify that the type is correct
|
||||
asCDataType *dt = &sysFunction->parameterTypes[arg];
|
||||
if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() )
|
||||
return 0;
|
||||
|
||||
if( dt->GetSizeInMemoryBytes() != 2 )
|
||||
return 0;
|
||||
|
||||
// Determine the position of the argument
|
||||
int offset = 0;
|
||||
for( asUINT n = 0; n < arg; n++ )
|
||||
offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
|
||||
|
||||
// Get the value
|
||||
return *(asWORD*)&stackPointer[offset];
|
||||
}
|
||||
|
||||
// interface
|
||||
asDWORD asCGeneric::GetArgDWord(asUINT arg)
|
||||
{
|
||||
if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() )
|
||||
return 0;
|
||||
|
||||
// Verify that the type is correct
|
||||
asCDataType *dt = &sysFunction->parameterTypes[arg];
|
||||
if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() )
|
||||
return 0;
|
||||
|
||||
if( dt->GetSizeInMemoryBytes() != 4 )
|
||||
return 0;
|
||||
|
||||
// Determine the position of the argument
|
||||
int offset = 0;
|
||||
for( asUINT n = 0; n < arg; n++ )
|
||||
offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
|
||||
|
||||
// Get the value
|
||||
return *(asDWORD*)&stackPointer[offset];
|
||||
}
|
||||
|
||||
// interface
|
||||
asQWORD asCGeneric::GetArgQWord(asUINT arg)
|
||||
{
|
||||
if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() )
|
||||
return 0;
|
||||
|
||||
// Verify that the type is correct
|
||||
asCDataType *dt = &sysFunction->parameterTypes[arg];
|
||||
if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() )
|
||||
return 0;
|
||||
|
||||
if( dt->GetSizeInMemoryBytes() != 8 )
|
||||
return 0;
|
||||
|
||||
// Determine the position of the argument
|
||||
int offset = 0;
|
||||
for( asUINT n = 0; n < arg; n++ )
|
||||
offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
|
||||
|
||||
// Get the value
|
||||
return *(asQWORD*)(&stackPointer[offset]);
|
||||
}
|
||||
|
||||
// interface
|
||||
float asCGeneric::GetArgFloat(asUINT arg)
|
||||
{
|
||||
if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() )
|
||||
return 0;
|
||||
|
||||
// Verify that the type is correct
|
||||
asCDataType *dt = &sysFunction->parameterTypes[arg];
|
||||
if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() )
|
||||
return 0;
|
||||
|
||||
if( dt->GetSizeInMemoryBytes() != 4 )
|
||||
return 0;
|
||||
|
||||
// Determine the position of the argument
|
||||
int offset = 0;
|
||||
for( asUINT n = 0; n < arg; n++ )
|
||||
offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
|
||||
|
||||
// Get the value
|
||||
return *(float*)(&stackPointer[offset]);
|
||||
}
|
||||
|
||||
// interface
|
||||
double asCGeneric::GetArgDouble(asUINT arg)
|
||||
{
|
||||
if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() )
|
||||
return 0;
|
||||
|
||||
// Verify that the type is correct
|
||||
asCDataType *dt = &sysFunction->parameterTypes[arg];
|
||||
if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() )
|
||||
return 0;
|
||||
|
||||
if( dt->GetSizeInMemoryBytes() != 8 )
|
||||
return 0;
|
||||
|
||||
// Determine the position of the argument
|
||||
int offset = 0;
|
||||
for( asUINT n = 0; n < arg; n++ )
|
||||
offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
|
||||
|
||||
// Get the value
|
||||
return *(double*)(&stackPointer[offset]);
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asCGeneric::GetArgAddress(asUINT arg)
|
||||
{
|
||||
if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() )
|
||||
return 0;
|
||||
|
||||
// Verify that the type is correct
|
||||
asCDataType *dt = &sysFunction->parameterTypes[arg];
|
||||
if( !dt->IsReference() && !dt->IsObjectHandle() )
|
||||
return 0;
|
||||
|
||||
// Determine the position of the argument
|
||||
int offset = 0;
|
||||
for( asUINT n = 0; n < arg; n++ )
|
||||
offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
|
||||
|
||||
// Get the value
|
||||
return (void*)*(asPWORD*)(&stackPointer[offset]);
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asCGeneric::GetArgObject(asUINT arg)
|
||||
{
|
||||
if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() )
|
||||
return 0;
|
||||
|
||||
// Verify that the type is correct
|
||||
asCDataType *dt = &sysFunction->parameterTypes[arg];
|
||||
if( !dt->IsObject() && !dt->IsFuncdef() )
|
||||
return 0;
|
||||
|
||||
// Determine the position of the argument
|
||||
int offset = 0;
|
||||
for( asUINT n = 0; n < arg; n++ )
|
||||
offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
|
||||
|
||||
// Get the value
|
||||
return *(void**)(&stackPointer[offset]);
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asCGeneric::GetAddressOfArg(asUINT arg)
|
||||
{
|
||||
if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() )
|
||||
return 0;
|
||||
|
||||
// Determine the position of the argument
|
||||
int offset = 0;
|
||||
for( asUINT n = 0; n < arg; n++ )
|
||||
offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
|
||||
|
||||
// For object variables it's necessary to dereference the pointer to get the address of the value
|
||||
if( !sysFunction->parameterTypes[arg].IsReference() &&
|
||||
sysFunction->parameterTypes[arg].IsObject() &&
|
||||
!sysFunction->parameterTypes[arg].IsObjectHandle() )
|
||||
return *(void**)&stackPointer[offset];
|
||||
|
||||
// Get the address of the value
|
||||
return &stackPointer[offset];
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCGeneric::GetArgTypeId(asUINT arg, asDWORD *flags) const
|
||||
{
|
||||
if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() )
|
||||
return 0;
|
||||
|
||||
if( flags )
|
||||
{
|
||||
*flags = sysFunction->inOutFlags[arg];
|
||||
*flags |= sysFunction->parameterTypes[arg].IsReadOnly() ? asTM_CONST : 0;
|
||||
}
|
||||
|
||||
asCDataType *dt = &sysFunction->parameterTypes[arg];
|
||||
if( dt->GetTokenType() != ttQuestion )
|
||||
return engine->GetTypeIdFromDataType(*dt);
|
||||
else
|
||||
{
|
||||
int offset = 0;
|
||||
for( asUINT n = 0; n < arg; n++ )
|
||||
offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
|
||||
|
||||
// Skip the actual value to get to the type id
|
||||
offset += AS_PTR_SIZE;
|
||||
|
||||
// Get the value
|
||||
return stackPointer[offset];
|
||||
}
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCGeneric::SetReturnByte(asBYTE val)
|
||||
{
|
||||
// Verify the type of the return value
|
||||
if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
if( sysFunction->returnType.GetSizeInMemoryBytes() != 1 )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
// Store the value
|
||||
*(asBYTE*)&returnVal = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCGeneric::SetReturnWord(asWORD val)
|
||||
{
|
||||
// Verify the type of the return value
|
||||
if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
if( sysFunction->returnType.GetSizeInMemoryBytes() != 2 )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
// Store the value
|
||||
*(asWORD*)&returnVal = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCGeneric::SetReturnDWord(asDWORD val)
|
||||
{
|
||||
// Verify the type of the return value
|
||||
if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
if( sysFunction->returnType.GetSizeInMemoryBytes() != 4 )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
// Store the value
|
||||
*(asDWORD*)&returnVal = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCGeneric::SetReturnQWord(asQWORD val)
|
||||
{
|
||||
// Verify the type of the return value
|
||||
if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
if( sysFunction->returnType.GetSizeOnStackDWords() != 2 )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
// Store the value
|
||||
returnVal = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCGeneric::SetReturnFloat(float val)
|
||||
{
|
||||
// Verify the type of the return value
|
||||
if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
if( sysFunction->returnType.GetSizeOnStackDWords() != 1 )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
// Store the value
|
||||
*(float*)&returnVal = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCGeneric::SetReturnDouble(double val)
|
||||
{
|
||||
// Verify the type of the return value
|
||||
if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
if( sysFunction->returnType.GetSizeOnStackDWords() != 2 )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
// Store the value
|
||||
*(double*)&returnVal = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCGeneric::SetReturnAddress(void *val)
|
||||
{
|
||||
// Verify the type of the return value
|
||||
if( sysFunction->returnType.IsReference() )
|
||||
{
|
||||
// Store the value
|
||||
*(void**)&returnVal = val;
|
||||
return 0;
|
||||
}
|
||||
else if( sysFunction->returnType.IsObjectHandle() )
|
||||
{
|
||||
// Store the handle without increasing reference
|
||||
objectRegister = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return asINVALID_TYPE;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCGeneric::SetReturnObject(void *obj)
|
||||
{
|
||||
asCDataType *dt = &sysFunction->returnType;
|
||||
if( !dt->IsObject() && !dt->IsFuncdef() )
|
||||
return asINVALID_TYPE;
|
||||
|
||||
if( dt->IsReference() )
|
||||
{
|
||||
*(void**)&returnVal = obj;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( dt->IsObjectHandle() )
|
||||
{
|
||||
// Increase the reference counter
|
||||
if (dt->IsFuncdef())
|
||||
{
|
||||
if (obj)
|
||||
reinterpret_cast<asIScriptFunction*>(obj)->AddRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
asSTypeBehaviour *beh = &CastToObjectType(dt->GetTypeInfo())->beh;
|
||||
if (obj && beh && beh->addref)
|
||||
engine->CallObjectMethod(obj, beh->addref);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If function returns object by value the memory is already allocated.
|
||||
// Here we should just initialize that memory by calling the copy constructor
|
||||
// or the default constructor followed by the assignment operator
|
||||
void *mem = (void*)*(asPWORD*)&stackPointer[-AS_PTR_SIZE];
|
||||
engine->ConstructScriptObjectCopy(mem, obj, CastToObjectType(dt->GetTypeInfo()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
objectRegister = obj;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// internal
|
||||
void *asCGeneric::GetReturnPointer()
|
||||
{
|
||||
asCDataType &dt = sysFunction->returnType;
|
||||
|
||||
if( (dt.IsObject() ||dt.IsFuncdef()) && !dt.IsReference() )
|
||||
{
|
||||
// This function doesn't support returning on the stack but the use of
|
||||
// the function doesn't require it so we don't need to implement it here.
|
||||
asASSERT( !sysFunction->DoesReturnOnStack() );
|
||||
|
||||
return &objectRegister;
|
||||
}
|
||||
|
||||
return &returnVal;
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asCGeneric::GetAddressOfReturnLocation()
|
||||
{
|
||||
asCDataType &dt = sysFunction->returnType;
|
||||
|
||||
if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsReference() )
|
||||
{
|
||||
if( sysFunction->DoesReturnOnStack() )
|
||||
{
|
||||
// The memory is already preallocated on the stack,
|
||||
// and the pointer to the location is found before the first arg
|
||||
return (void*)*(asPWORD*)&stackPointer[-AS_PTR_SIZE];
|
||||
}
|
||||
|
||||
// Reference types store the handle in the objectReference
|
||||
return &objectRegister;
|
||||
}
|
||||
|
||||
// Primitive types and references are stored in the returnVal property
|
||||
return &returnVal;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCGeneric::GetReturnTypeId(asDWORD *flags) const
|
||||
{
|
||||
return sysFunction->GetReturnTypeId(flags);
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_generic.h
|
||||
//
|
||||
// This class handles the call to a function registered with asCALL_GENERIC
|
||||
//
|
||||
|
||||
|
||||
#ifndef AS_GENERIC_H
|
||||
#define AS_GENERIC_H
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCScriptEngine;
|
||||
class asCScriptFunction;
|
||||
|
||||
class asCGeneric : public asIScriptGeneric
|
||||
{
|
||||
public:
|
||||
//------------------------------
|
||||
// asIScriptGeneric
|
||||
//------------------------------
|
||||
// Miscellaneous
|
||||
asIScriptEngine *GetEngine() const;
|
||||
asIScriptFunction *GetFunction() const;
|
||||
void *GetAuxiliary() const;
|
||||
|
||||
// Object
|
||||
void *GetObject();
|
||||
int GetObjectTypeId() const;
|
||||
|
||||
// Arguments
|
||||
int GetArgCount() const;
|
||||
int GetArgTypeId(asUINT arg, asDWORD *flags = 0) const;
|
||||
asBYTE GetArgByte(asUINT arg);
|
||||
asWORD GetArgWord(asUINT arg);
|
||||
asDWORD GetArgDWord(asUINT arg);
|
||||
asQWORD GetArgQWord(asUINT arg);
|
||||
float GetArgFloat(asUINT arg);
|
||||
double GetArgDouble(asUINT arg);
|
||||
void *GetArgAddress(asUINT arg);
|
||||
void *GetArgObject(asUINT arg);
|
||||
void *GetAddressOfArg(asUINT arg);
|
||||
|
||||
// Return value
|
||||
int GetReturnTypeId(asDWORD *flags = 0) const;
|
||||
int SetReturnByte(asBYTE val);
|
||||
int SetReturnWord(asWORD val);
|
||||
int SetReturnDWord(asDWORD val);
|
||||
int SetReturnQWord(asQWORD val);
|
||||
int SetReturnFloat(float val);
|
||||
int SetReturnDouble(double val);
|
||||
int SetReturnAddress(void *addr);
|
||||
int SetReturnObject(void *obj);
|
||||
void *GetAddressOfReturnLocation();
|
||||
|
||||
//------------------------
|
||||
// internal
|
||||
//-------------------------
|
||||
asCGeneric(asCScriptEngine *engine, asCScriptFunction *sysFunction, void *currentObject, asDWORD *stackPointer);
|
||||
virtual ~asCGeneric();
|
||||
|
||||
void *GetReturnPointer();
|
||||
|
||||
asCScriptEngine *engine;
|
||||
asCScriptFunction *sysFunction;
|
||||
void *currentObject;
|
||||
asDWORD *stackPointer;
|
||||
void *objectRegister;
|
||||
|
||||
asQWORD returnVal;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
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 "as_config.h"
|
||||
#include "as_property.h"
|
||||
#include "as_scriptengine.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asCGlobalProperty::asCGlobalProperty()
|
||||
{
|
||||
memory = &storage;
|
||||
memoryAllocated = false;
|
||||
realAddress = 0;
|
||||
initFunc = 0;
|
||||
accessMask = 0xFFFFFFFF;
|
||||
|
||||
refCount.set(1);
|
||||
}
|
||||
|
||||
asCGlobalProperty::~asCGlobalProperty()
|
||||
{
|
||||
#ifndef WIP_16BYTE_ALIGNED
|
||||
if( memoryAllocated ) { asDELETEARRAY(memory); }
|
||||
#else
|
||||
if( memoryAllocated ) { asDELETEARRAYALIGNED(memory); }
|
||||
#endif
|
||||
|
||||
if( initFunc )
|
||||
initFunc->ReleaseInternal();
|
||||
}
|
||||
|
||||
void asCGlobalProperty::AddRef()
|
||||
{
|
||||
refCount.atomicInc();
|
||||
}
|
||||
|
||||
void asCGlobalProperty::Release()
|
||||
{
|
||||
if( refCount.atomicDec() == 0 )
|
||||
asDELETE(this, asCGlobalProperty);
|
||||
}
|
||||
|
||||
void asCGlobalProperty::DestroyInternal()
|
||||
{
|
||||
if( initFunc )
|
||||
{
|
||||
initFunc->ReleaseInternal();
|
||||
initFunc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void *asCGlobalProperty::GetAddressOfValue()
|
||||
{
|
||||
return memory;
|
||||
}
|
||||
|
||||
// The global property structure is responsible for allocating the storage
|
||||
// method for script declared variables. Each allocation is independent of
|
||||
// other global properties, so that variables can be added and removed at
|
||||
// any time.
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void asCGlobalProperty::SetRegisteredAddress(void *p)
|
||||
{
|
||||
realAddress = p;
|
||||
if( type.IsObject() && !type.IsReference() && !type.IsObjectHandle() )
|
||||
{
|
||||
// The global property is a pointer to a pointer
|
||||
memory = &realAddress;
|
||||
}
|
||||
else
|
||||
memory = p;
|
||||
}
|
||||
|
||||
void *asCGlobalProperty::GetRegisteredAddress() const
|
||||
{
|
||||
return realAddress;
|
||||
}
|
||||
|
||||
void asCGlobalProperty::SetInitFunc(asCScriptFunction *in_initFunc)
|
||||
{
|
||||
// This should only be done once
|
||||
asASSERT( initFunc == 0 );
|
||||
|
||||
initFunc = in_initFunc;
|
||||
initFunc->AddRefInternal();
|
||||
}
|
||||
|
||||
asCScriptFunction *asCGlobalProperty::GetInitFunc()
|
||||
{
|
||||
return initFunc;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
@@ -0,0 +1,786 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_map.h
|
||||
//
|
||||
// This class is used for mapping a value to another
|
||||
//
|
||||
|
||||
|
||||
#ifndef AS_MAP_H
|
||||
#define AS_MAP_H
|
||||
|
||||
template <class KEY, class VAL> struct asSMapNode;
|
||||
|
||||
template <class KEY, class VAL> class asCMap
|
||||
{
|
||||
public:
|
||||
asCMap();
|
||||
~asCMap();
|
||||
|
||||
int Insert(const KEY &key, const VAL &value);
|
||||
int Insert(asSMapNode<KEY,VAL> *node);
|
||||
int GetCount() const;
|
||||
|
||||
const KEY &GetKey(const asSMapNode<KEY,VAL> *cursor) const;
|
||||
const VAL &GetValue(const asSMapNode<KEY,VAL> *cursor) const;
|
||||
VAL &GetValue(asSMapNode<KEY,VAL> *cursor);
|
||||
|
||||
void Erase(asSMapNode<KEY,VAL> *cursor);
|
||||
asSMapNode<KEY,VAL> *Remove(asSMapNode<KEY,VAL> *cursor);
|
||||
void EraseAll();
|
||||
|
||||
void SwapWith(asCMap<KEY,VAL> &other);
|
||||
|
||||
// Returns true as long as cursor is valid
|
||||
|
||||
bool MoveTo(asSMapNode<KEY,VAL> **out, const KEY &key) const;
|
||||
bool MoveFirst(asSMapNode<KEY,VAL> **out) const;
|
||||
bool MoveLast(asSMapNode<KEY,VAL> **out) const;
|
||||
bool MoveNext(asSMapNode<KEY,VAL> **out, asSMapNode<KEY,VAL> *cursor) const;
|
||||
bool MovePrev(asSMapNode<KEY,VAL> **out, asSMapNode<KEY,VAL> *cursor) const;
|
||||
|
||||
// For debugging only
|
||||
|
||||
int CheckIntegrity(asSMapNode<KEY,VAL> *node) const;
|
||||
|
||||
protected:
|
||||
// Don't allow value assignment
|
||||
asCMap &operator=(const asCMap &) { return *this; }
|
||||
|
||||
void BalanceInsert(asSMapNode<KEY,VAL> *node);
|
||||
void BalanceErase(asSMapNode<KEY,VAL> *child, asSMapNode<KEY,VAL> *parent);
|
||||
|
||||
int EraseAll(asSMapNode<KEY,VAL> *node);
|
||||
int RotateLeft(asSMapNode<KEY,VAL> *node);
|
||||
int RotateRight(asSMapNode<KEY,VAL> *node);
|
||||
|
||||
asSMapNode<KEY,VAL> *root;
|
||||
asSMapNode<KEY,VAL> dummy;
|
||||
|
||||
int count;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
// Properties of a Red-Black Tree
|
||||
//
|
||||
// 1. The root is always black
|
||||
// 2. All single paths from the root to leafs
|
||||
// contain the same amount of black nodes
|
||||
// 3. No red node can have a red node as parent
|
||||
|
||||
#define ISRED(x) ((x != 0) && (x)->isRed)
|
||||
#define ISBLACK(x) (!ISRED(x))
|
||||
|
||||
template <class KEY, class VAL> struct asSMapNode
|
||||
{
|
||||
asSMapNode() {parent = 0; left = 0; right = 0; isRed = true;}
|
||||
void Init(KEY k, VAL v) {key = k; value = v; parent = 0; left = 0; right = 0; isRed = true;}
|
||||
|
||||
asSMapNode *parent;
|
||||
asSMapNode *left;
|
||||
asSMapNode *right;
|
||||
bool isRed;
|
||||
|
||||
KEY key;
|
||||
VAL value;
|
||||
};
|
||||
|
||||
template <class KEY, class VAL>
|
||||
asCMap<KEY, VAL>::asCMap()
|
||||
{
|
||||
root = 0;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
asCMap<KEY, VAL>::~asCMap()
|
||||
{
|
||||
EraseAll();
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
void asCMap<KEY,VAL>::SwapWith(asCMap<KEY,VAL> &other)
|
||||
{
|
||||
asSMapNode<KEY,VAL> *tmpRoot = root;
|
||||
int tmpCount = count;
|
||||
|
||||
root = other.root;
|
||||
count = other.count;
|
||||
|
||||
other.root = tmpRoot;
|
||||
other.count = tmpCount;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
void asCMap<KEY, VAL>::EraseAll()
|
||||
{
|
||||
EraseAll(root);
|
||||
root = 0;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
int asCMap<KEY, VAL>::EraseAll(asSMapNode<KEY, VAL> *p)
|
||||
{
|
||||
if( p == 0 ) return -1;
|
||||
|
||||
EraseAll( p->left );
|
||||
EraseAll( p->right );
|
||||
|
||||
typedef asSMapNode<KEY,VAL> node_t;
|
||||
asDELETE(p,node_t);
|
||||
|
||||
count--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
int asCMap<KEY, VAL>::GetCount() const
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
int asCMap<KEY, VAL>::Insert(const KEY &key, const VAL &value)
|
||||
{
|
||||
typedef asSMapNode<KEY,VAL> node_t;
|
||||
asSMapNode<KEY,VAL> *nnode = asNEW(node_t);
|
||||
if( nnode == 0 )
|
||||
{
|
||||
// Out of memory
|
||||
return -1;
|
||||
}
|
||||
|
||||
nnode->key = key;
|
||||
nnode->value = value;
|
||||
|
||||
return Insert(nnode);
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
int asCMap<KEY, VAL>::Insert(asSMapNode<KEY,VAL> *nnode)
|
||||
{
|
||||
// Insert the node
|
||||
if( root == 0 )
|
||||
root = nnode;
|
||||
else
|
||||
{
|
||||
asSMapNode<KEY,VAL> *p = root;
|
||||
for(;;)
|
||||
{
|
||||
if( nnode->key < p->key )
|
||||
{
|
||||
if( p->left == 0 )
|
||||
{
|
||||
nnode->parent = p;
|
||||
p->left = nnode;
|
||||
break;
|
||||
}
|
||||
else
|
||||
p = p->left;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( p->right == 0 )
|
||||
{
|
||||
nnode->parent = p;
|
||||
p->right = nnode;
|
||||
break;
|
||||
}
|
||||
else
|
||||
p = p->right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BalanceInsert(nnode);
|
||||
|
||||
count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
void asCMap<KEY, VAL>::BalanceInsert(asSMapNode<KEY, VAL> *node)
|
||||
{
|
||||
// The node, that is red, can't have a red parent
|
||||
while( node != root && node->parent->isRed )
|
||||
{
|
||||
// Check color of uncle
|
||||
if( node->parent == node->parent->parent->left )
|
||||
{
|
||||
asSMapNode<KEY,VAL> *uncle = node->parent->parent->right;
|
||||
if( ISRED(uncle) )
|
||||
{
|
||||
// B
|
||||
// R R
|
||||
// N
|
||||
|
||||
// Change color on parent, uncle, and grand parent
|
||||
node->parent->isRed = false;
|
||||
uncle->isRed = false;
|
||||
node->parent->parent->isRed = true;
|
||||
|
||||
// Continue balancing from grand parent
|
||||
node = node->parent->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
// B
|
||||
// R B
|
||||
// N
|
||||
|
||||
if( node == node->parent->right )
|
||||
{
|
||||
// Make the node a left child
|
||||
node = node->parent;
|
||||
RotateLeft(node);
|
||||
}
|
||||
|
||||
// Change color on parent and grand parent
|
||||
// Then rotate grand parent to the right
|
||||
node->parent->isRed = false;
|
||||
node->parent->parent->isRed = true;
|
||||
RotateRight(node->parent->parent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asSMapNode<KEY,VAL> *uncle = node->parent->parent->left;
|
||||
if( ISRED(uncle) )
|
||||
{
|
||||
// B
|
||||
// R R
|
||||
// N
|
||||
|
||||
// Change color on parent, uncle, and grand parent
|
||||
// Continue balancing from grand parent
|
||||
node->parent->isRed = false;
|
||||
uncle->isRed = false;
|
||||
node = node->parent->parent;
|
||||
node->isRed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// B
|
||||
// B R
|
||||
// N
|
||||
|
||||
if( node == node->parent->left )
|
||||
{
|
||||
// Make the node a right child
|
||||
node = node->parent;
|
||||
RotateRight(node);
|
||||
}
|
||||
|
||||
// Change color on parent and grand parent
|
||||
// Then rotate grand parent to the right
|
||||
node->parent->isRed = false;
|
||||
node->parent->parent->isRed = true;
|
||||
RotateLeft(node->parent->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
root->isRed = false;
|
||||
}
|
||||
|
||||
// For debugging purposes only
|
||||
template <class KEY, class VAL>
|
||||
int asCMap<KEY, VAL>::CheckIntegrity(asSMapNode<KEY, VAL> *node) const
|
||||
{
|
||||
if( node == 0 )
|
||||
{
|
||||
if( root == 0 )
|
||||
return 0;
|
||||
else if( ISRED(root) )
|
||||
return -1;
|
||||
else
|
||||
node = root;
|
||||
}
|
||||
|
||||
int left = 0, right = 0;
|
||||
if( node->left )
|
||||
left = CheckIntegrity(node->left);
|
||||
if( node->right )
|
||||
right = CheckIntegrity(node->right);
|
||||
|
||||
if( left != right || left == -1 )
|
||||
return -1;
|
||||
|
||||
if( ISBLACK(node) )
|
||||
return left+1;
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
// Returns true if successful
|
||||
template <class KEY, class VAL>
|
||||
bool asCMap<KEY, VAL>::MoveTo(asSMapNode<KEY,VAL> **out, const KEY &key) const
|
||||
{
|
||||
asSMapNode<KEY,VAL> *p = root;
|
||||
while( p )
|
||||
{
|
||||
if( key < p->key )
|
||||
p = p->left;
|
||||
else if( key == p->key )
|
||||
{
|
||||
if( out ) *out = p;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
p = p->right;
|
||||
}
|
||||
|
||||
if( out ) *out = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
void asCMap<KEY, VAL>::Erase(asSMapNode<KEY,VAL> *cursor)
|
||||
{
|
||||
asSMapNode<KEY,VAL> *node = Remove(cursor);
|
||||
asASSERT( node == cursor );
|
||||
|
||||
typedef asSMapNode<KEY,VAL> node_t;
|
||||
asDELETE(node,node_t);
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
asSMapNode<KEY,VAL> *asCMap<KEY, VAL>::Remove(asSMapNode<KEY,VAL> *cursor)
|
||||
{
|
||||
if( cursor == 0 ) return 0;
|
||||
|
||||
asSMapNode<KEY,VAL> *node = cursor;
|
||||
|
||||
//---------------------------------------------------
|
||||
// Choose the node that will replace the erased one
|
||||
asSMapNode<KEY,VAL> *remove;
|
||||
if( node->left == 0 || node->right == 0 )
|
||||
remove = node;
|
||||
else
|
||||
{
|
||||
remove = node->right;
|
||||
while( remove->left ) remove = remove->left;
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// Remove the node
|
||||
asSMapNode<KEY,VAL> *child;
|
||||
if( remove->left )
|
||||
child = remove->left;
|
||||
else
|
||||
child = remove->right;
|
||||
|
||||
if( child ) child->parent = remove->parent;
|
||||
if( remove->parent )
|
||||
{
|
||||
if( remove == remove->parent->left )
|
||||
remove->parent->left = child;
|
||||
else
|
||||
remove->parent->right = child;
|
||||
}
|
||||
else
|
||||
root = child;
|
||||
|
||||
// If we remove a black node we must make sure the tree is balanced
|
||||
if( ISBLACK(remove) )
|
||||
BalanceErase(child, remove->parent);
|
||||
|
||||
//----------------------------------------
|
||||
// Replace the erased node with the removed one
|
||||
if( remove != node )
|
||||
{
|
||||
if( node->parent )
|
||||
{
|
||||
if( node->parent->left == node )
|
||||
node->parent->left = remove;
|
||||
else
|
||||
node->parent->right = remove;
|
||||
}
|
||||
else
|
||||
root = remove;
|
||||
|
||||
remove->isRed = node->isRed;
|
||||
remove->parent = node->parent;
|
||||
|
||||
remove->left = node->left;
|
||||
if( remove->left ) remove->left->parent = remove;
|
||||
remove->right = node->right;
|
||||
if( remove->right ) remove->right->parent = remove;
|
||||
}
|
||||
|
||||
count--;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// Call method only if removed node was black
|
||||
// child is the child of the removed node
|
||||
template <class KEY, class VAL>
|
||||
void asCMap<KEY, VAL>::BalanceErase(asSMapNode<KEY, VAL> *child, asSMapNode<KEY, VAL> *parent)
|
||||
{
|
||||
// If child is red
|
||||
// Color child black
|
||||
// Terminate
|
||||
|
||||
// These tests assume brother is to the right.
|
||||
|
||||
// 1. Brother is red
|
||||
// Color parent red and brother black
|
||||
// Rotate parent left
|
||||
// Transforms to 2b
|
||||
// 2a. Parent and brother is black, brother's children are black
|
||||
// Color brother red
|
||||
// Continue test with parent as child
|
||||
// 2b. Parent is red, brother is black, brother's children are black
|
||||
// Color parent black and brother red
|
||||
// Terminate
|
||||
// 3. Brother is black, and brother's left is red and brother's right is black
|
||||
// Color brother red and brother's left black
|
||||
// Rotate brother to right
|
||||
// Transforms to 4.
|
||||
// 4. Brother is black, brother's right is red
|
||||
// Color brother's right black
|
||||
// Color brother to color of parent
|
||||
// Color parent black
|
||||
// Rotate parent left
|
||||
// Terminate
|
||||
|
||||
while( child != root && ISBLACK(child) )
|
||||
{
|
||||
if( child == parent->left )
|
||||
{
|
||||
asSMapNode<KEY,VAL> *brother = parent->right;
|
||||
|
||||
// Case 1
|
||||
if( ISRED(brother) )
|
||||
{
|
||||
brother->isRed = false;
|
||||
parent->isRed = true;
|
||||
RotateLeft(parent);
|
||||
brother = parent->right;
|
||||
}
|
||||
|
||||
// Case 2
|
||||
if( brother == 0 ) break;
|
||||
if( ISBLACK(brother->left) && ISBLACK(brother->right) )
|
||||
{
|
||||
// Case 2b
|
||||
if( ISRED(parent) )
|
||||
{
|
||||
parent->isRed = false;
|
||||
brother->isRed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
brother->isRed = true;
|
||||
child = parent;
|
||||
parent = child->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Case 3
|
||||
if( ISBLACK(brother->right) )
|
||||
{
|
||||
brother->left->isRed = false;
|
||||
brother->isRed = true;
|
||||
RotateRight(brother);
|
||||
brother = parent->right;
|
||||
}
|
||||
|
||||
// Case 4
|
||||
brother->isRed = parent->isRed;
|
||||
parent->isRed = false;
|
||||
brother->right->isRed = false;
|
||||
RotateLeft(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asSMapNode<KEY,VAL> *brother = parent->left;
|
||||
|
||||
// Case 1
|
||||
if( ISRED(brother) )
|
||||
{
|
||||
brother->isRed = false;
|
||||
parent->isRed = true;
|
||||
RotateRight(parent);
|
||||
brother = parent->left;
|
||||
}
|
||||
|
||||
// Case 2
|
||||
if( brother == 0 ) break;
|
||||
if( ISBLACK(brother->left) && ISBLACK(brother->right) )
|
||||
{
|
||||
// Case 2b
|
||||
if( ISRED(parent) )
|
||||
{
|
||||
parent->isRed = false;
|
||||
brother->isRed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
brother->isRed = true;
|
||||
child = parent;
|
||||
parent = child->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Case 3
|
||||
if( ISBLACK(brother->left) )
|
||||
{
|
||||
brother->right->isRed = false;
|
||||
brother->isRed = true;
|
||||
RotateLeft(brother);
|
||||
brother = parent->left;
|
||||
}
|
||||
|
||||
// Case 4
|
||||
brother->isRed = parent->isRed;
|
||||
parent->isRed = false;
|
||||
brother->left->isRed = false;
|
||||
RotateRight(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( child )
|
||||
child->isRed = false;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
int asCMap<KEY, VAL>::RotateRight(asSMapNode<KEY, VAL> *node)
|
||||
{
|
||||
// P L //
|
||||
// / \ / \ //
|
||||
// L R => Ll P //
|
||||
// / \ / \ //
|
||||
// Ll Lr Lr R //
|
||||
|
||||
if( node->left == 0 ) return -1;
|
||||
|
||||
asSMapNode<KEY,VAL> *left = node->left;
|
||||
|
||||
// Update parent
|
||||
if( node->parent )
|
||||
{
|
||||
asSMapNode<KEY,VAL> *parent = node->parent;
|
||||
if( parent->left == node )
|
||||
parent->left = left;
|
||||
else
|
||||
parent->right = left;
|
||||
|
||||
left->parent = parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
root = left;
|
||||
left->parent = 0;
|
||||
}
|
||||
|
||||
// Move left's right child to node's left child
|
||||
node->left = left->right;
|
||||
if( node->left ) node->left->parent = node;
|
||||
|
||||
// Put node as left's right child
|
||||
left->right = node;
|
||||
node->parent = left;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
int asCMap<KEY, VAL>::RotateLeft(asSMapNode<KEY, VAL> *node)
|
||||
{
|
||||
// P R //
|
||||
// / \ / \ //
|
||||
// L R => P Rr //
|
||||
// / \ / \ //
|
||||
// Rl Rr L Rl //
|
||||
|
||||
if( node->right == 0 ) return -1;
|
||||
|
||||
asSMapNode<KEY,VAL> *right = node->right;
|
||||
|
||||
// Update parent
|
||||
if( node->parent )
|
||||
{
|
||||
asSMapNode<KEY,VAL> *parent = node->parent;
|
||||
if( parent->right == node )
|
||||
parent->right = right;
|
||||
else
|
||||
parent->left = right;
|
||||
|
||||
right->parent = parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
root = right;
|
||||
right->parent = 0;
|
||||
}
|
||||
|
||||
// Move right's left child to node's right child
|
||||
node->right = right->left;
|
||||
if( node->right ) node->right->parent = node;
|
||||
|
||||
// Put node as right's left child
|
||||
right->left = node;
|
||||
node->parent = right;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
const VAL &asCMap<KEY, VAL>::GetValue(const asSMapNode<KEY,VAL> *cursor) const
|
||||
{
|
||||
if( cursor == 0 )
|
||||
return dummy.value;
|
||||
|
||||
return cursor->value;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
VAL &asCMap<KEY, VAL>::GetValue(asSMapNode<KEY,VAL> *cursor)
|
||||
{
|
||||
if( cursor == 0 )
|
||||
return dummy.value;
|
||||
|
||||
return cursor->value;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
const KEY &asCMap<KEY, VAL>::GetKey(const asSMapNode<KEY,VAL> *cursor) const
|
||||
{
|
||||
if( cursor == 0 )
|
||||
return dummy.key;
|
||||
|
||||
return cursor->key;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
bool asCMap<KEY, VAL>::MoveFirst(asSMapNode<KEY,VAL> **out) const
|
||||
{
|
||||
*out = root;
|
||||
if( root == 0 ) return false;
|
||||
|
||||
while( (*out)->left )
|
||||
*out = (*out)->left;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
bool asCMap<KEY, VAL>::MoveLast(asSMapNode<KEY,VAL> **out) const
|
||||
{
|
||||
*out = root;
|
||||
if( root == 0 ) return false;
|
||||
|
||||
while( (*out)->right )
|
||||
*out = (*out)->right;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
bool asCMap<KEY, VAL>::MoveNext(asSMapNode<KEY,VAL> **out, asSMapNode<KEY,VAL> *cursor) const
|
||||
{
|
||||
if( cursor == 0 )
|
||||
{
|
||||
*out = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( cursor->right == 0 )
|
||||
{
|
||||
// Move upwards until we find a parent node to the right
|
||||
while( cursor->parent && cursor->parent->right == cursor )
|
||||
cursor = cursor->parent;
|
||||
|
||||
cursor = cursor->parent;
|
||||
*out = cursor;
|
||||
if( cursor == 0 )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
cursor = cursor->right;
|
||||
while( cursor->left )
|
||||
cursor = cursor->left;
|
||||
|
||||
*out = cursor;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class KEY, class VAL>
|
||||
bool asCMap<KEY, VAL>::MovePrev(asSMapNode<KEY,VAL> **out, asSMapNode<KEY,VAL> *cursor) const
|
||||
{
|
||||
if( cursor == 0 )
|
||||
{
|
||||
*out = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( cursor->left == 0 )
|
||||
{
|
||||
// Move upwards until we find a parent node to the left
|
||||
while( cursor->parent && cursor->parent->left == cursor )
|
||||
cursor = cursor->parent;
|
||||
|
||||
cursor = cursor->parent;
|
||||
|
||||
*out = cursor;
|
||||
if( cursor == 0 )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
cursor = cursor->left;
|
||||
while( cursor->right )
|
||||
cursor = cursor->right;
|
||||
|
||||
*out = cursor;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2020 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_memory.cpp
|
||||
//
|
||||
// Overload the default memory management functions so that we
|
||||
// can let the application decide how to do it.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__SNC__) && !defined(__ghs__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_memory.h"
|
||||
#include "as_scriptnode.h"
|
||||
#include "as_bytecode.h"
|
||||
|
||||
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
|
||||
// library may crash in case the application initializes the engine
|
||||
// as a global variable.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// MSVC let's us choose between a couple of different initialization orders.
|
||||
#pragma warning(disable: 4073)
|
||||
#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;
|
||||
userFree = free;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
void *asAllocMem(size_t size)
|
||||
{
|
||||
return asNEWARRAY(asBYTE, size);
|
||||
}
|
||||
|
||||
// interface
|
||||
void asFreeMem(void *mem)
|
||||
{
|
||||
asDELETEARRAY(mem);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
asCMemoryMgr::asCMemoryMgr()
|
||||
{
|
||||
}
|
||||
|
||||
asCMemoryMgr::~asCMemoryMgr()
|
||||
{
|
||||
FreeUnusedMemory();
|
||||
}
|
||||
|
||||
void asCMemoryMgr::FreeUnusedMemory()
|
||||
{
|
||||
// It's necessary to protect the scriptNodePool from multiple
|
||||
// simultaneous accesses, as the parser is used by several methods
|
||||
// that can be executed simultaneously.
|
||||
ENTERCRITICALSECTION(cs);
|
||||
|
||||
int n;
|
||||
for( n = 0; n < (signed)scriptNodePool.GetLength(); n++ )
|
||||
userFree(scriptNodePool[n]);
|
||||
scriptNodePool.Allocate(0, false);
|
||||
|
||||
LEAVECRITICALSECTION(cs);
|
||||
|
||||
// The engine already protects against multiple threads
|
||||
// compiling scripts simultaneously so this pool doesn't have
|
||||
// to be protected again.
|
||||
for( n = 0; n < (signed)byteInstructionPool.GetLength(); n++ )
|
||||
userFree(byteInstructionPool[n]);
|
||||
byteInstructionPool.Allocate(0, false);
|
||||
}
|
||||
|
||||
void *asCMemoryMgr::AllocScriptNode()
|
||||
{
|
||||
ENTERCRITICALSECTION(cs);
|
||||
|
||||
if( scriptNodePool.GetLength() )
|
||||
{
|
||||
void *tRet = scriptNodePool.PopLast();
|
||||
LEAVECRITICALSECTION(cs);
|
||||
return tRet;
|
||||
}
|
||||
|
||||
LEAVECRITICALSECTION(cs);
|
||||
|
||||
#if defined(AS_DEBUG)
|
||||
return ((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(asCScriptNode), __FILE__, __LINE__);
|
||||
#else
|
||||
return userAlloc(sizeof(asCScriptNode));
|
||||
#endif
|
||||
}
|
||||
|
||||
void asCMemoryMgr::FreeScriptNode(void *ptr)
|
||||
{
|
||||
ENTERCRITICALSECTION(cs);
|
||||
|
||||
// Pre allocate memory for the array to avoid slow growth
|
||||
if( scriptNodePool.GetLength() == 0 )
|
||||
scriptNodePool.Allocate(100, 0);
|
||||
|
||||
scriptNodePool.PushLast(ptr);
|
||||
|
||||
#ifdef AS_DEBUG
|
||||
// clear the memory to facilitate identification of use after free
|
||||
memset(ptr, 0xCDCDCDCD, sizeof(asCScriptNode));
|
||||
#endif
|
||||
|
||||
LEAVECRITICALSECTION(cs);
|
||||
}
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
|
||||
void *asCMemoryMgr::AllocByteInstruction()
|
||||
{
|
||||
// This doesn't need a critical section because, only one compilation is allowed at a time
|
||||
|
||||
if( byteInstructionPool.GetLength() )
|
||||
return byteInstructionPool.PopLast();
|
||||
|
||||
#if defined(AS_DEBUG)
|
||||
return ((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(asCByteInstruction), __FILE__, __LINE__);
|
||||
#else
|
||||
return userAlloc(sizeof(asCByteInstruction));
|
||||
#endif
|
||||
}
|
||||
|
||||
void asCMemoryMgr::FreeByteInstruction(void *ptr)
|
||||
{
|
||||
// Pre allocate memory for the array to avoid slow growth
|
||||
if( byteInstructionPool.GetLength() == 0 )
|
||||
byteInstructionPool.Allocate(100, 0);
|
||||
|
||||
byteInstructionPool.PushLast(ptr);
|
||||
|
||||
#ifdef AS_DEBUG
|
||||
// clear the memory to facilitate identification of use after free
|
||||
memset(ptr, 0xCDCDCDCD, sizeof(asCByteInstruction));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // AS_NO_COMPILER
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_memory.h
|
||||
//
|
||||
// Overload the default memory management functions so that we
|
||||
// can let the application decide how to do it.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_MEMORY_H
|
||||
#define AS_MEMORY_H
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
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
|
||||
|
||||
#define asNEW(x) new(userAlloc(sizeof(x))) x
|
||||
#define asDELETE(ptr,x) {void *tmp = ptr; (ptr)->~x(); userFree(tmp);}
|
||||
|
||||
#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);
|
||||
|
||||
#define asNEW(x) new(((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(x), __FILE__, __LINE__)) x
|
||||
#define asDELETE(ptr,x) {void *tmp = ptr; (ptr)->~x(); userFree(tmp);}
|
||||
|
||||
#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
|
||||
|
||||
#include <new>
|
||||
#include "as_criticalsection.h"
|
||||
#include "as_array.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCMemoryMgr
|
||||
{
|
||||
public:
|
||||
asCMemoryMgr();
|
||||
~asCMemoryMgr();
|
||||
|
||||
void FreeUnusedMemory();
|
||||
|
||||
void *AllocScriptNode();
|
||||
void FreeScriptNode(void *ptr);
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
void *AllocByteInstruction();
|
||||
void FreeByteInstruction(void *ptr);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
DECLARECRITICALSECTION(cs)
|
||||
asCArray<void *> scriptNodePool;
|
||||
asCArray<void *> byteInstructionPool;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2020 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
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//
|
||||
// as_module.h
|
||||
//
|
||||
// A class that holds a script module
|
||||
//
|
||||
|
||||
#ifndef AS_MODULE_H
|
||||
#define AS_MODULE_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_symboltable.h"
|
||||
#include "as_atomic.h"
|
||||
#include "as_string.h"
|
||||
#include "as_array.h"
|
||||
#include "as_datatype.h"
|
||||
#include "as_scriptfunction.h"
|
||||
#include "as_property.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// TODO: import: Remove this when the imported functions are removed
|
||||
const int FUNC_IMPORTED = 0x40000000;
|
||||
|
||||
class asCScriptEngine;
|
||||
class asCCompiler;
|
||||
class asCBuilder;
|
||||
class asCContext;
|
||||
class asCConfigGroup;
|
||||
class asCTypedefType;
|
||||
class asCFuncdefType;
|
||||
struct asSNameSpace;
|
||||
|
||||
struct sBindInfo
|
||||
{
|
||||
asCScriptFunction *importedFunctionSignature;
|
||||
asCString importFromModule;
|
||||
int boundFunctionId;
|
||||
};
|
||||
|
||||
struct sObjectTypePair
|
||||
{
|
||||
asCObjectType *a;
|
||||
asCObjectType *b;
|
||||
};
|
||||
|
||||
|
||||
// TODO: import: Remove function imports. When I have implemented function
|
||||
// pointers the function imports should be deprecated.
|
||||
|
||||
// TODO: Need a separate interface for compiling scripts. The asIScriptCompiler
|
||||
// will have a target module, and will allow the compilation of an entire
|
||||
// script or just individual functions within the scope of the module
|
||||
//
|
||||
// With this separation it will be possible to compile the library without
|
||||
// the compiler, thus giving a much smaller binary executable.
|
||||
|
||||
// TODO: There should be a special compile option that will let the application
|
||||
// recompile an already compiled script. The compiler should check if no
|
||||
// destructive changes have been made (changing function signatures, etc)
|
||||
// then it should simply replace the bytecode within the functions without
|
||||
// changing the values of existing global properties, etc.
|
||||
|
||||
class asCModule : public asIScriptModule
|
||||
{
|
||||
//-------------------------------------------
|
||||
// Public interface
|
||||
//--------------------------------------------
|
||||
public:
|
||||
virtual asIScriptEngine *GetEngine() const;
|
||||
virtual void SetName(const char *name);
|
||||
virtual const char *GetName() const;
|
||||
virtual void Discard();
|
||||
|
||||
// Compilation
|
||||
virtual int AddScriptSection(const char *name, const char *code, size_t codeLength, int lineOffset);
|
||||
virtual int Build();
|
||||
virtual int CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD reserved, asIScriptFunction **outFunc);
|
||||
virtual int CompileGlobalVar(const char *sectionName, const char *code, int lineOffset);
|
||||
virtual asDWORD SetAccessMask(asDWORD accessMask);
|
||||
virtual int SetDefaultNamespace(const char *nameSpace);
|
||||
virtual const char *GetDefaultNamespace() const;
|
||||
|
||||
// Script functions
|
||||
virtual asUINT GetFunctionCount() const;
|
||||
virtual asIScriptFunction *GetFunctionByIndex(asUINT index) const;
|
||||
virtual asIScriptFunction *GetFunctionByDecl(const char *decl) const;
|
||||
virtual asIScriptFunction *GetFunctionByName(const char *name) const;
|
||||
virtual int RemoveFunction(asIScriptFunction *func);
|
||||
|
||||
// Script global variables
|
||||
// TODO: interface: Should be called InitGlobalVars, and should have a bool to reset in case already initialized
|
||||
virtual int ResetGlobalVars(asIScriptContext *ctx);
|
||||
virtual asUINT GetGlobalVarCount() const;
|
||||
virtual int GetGlobalVarIndexByName(const char *name) const;
|
||||
virtual int GetGlobalVarIndexByDecl(const char *decl) const;
|
||||
virtual const char *GetGlobalVarDeclaration(asUINT index, bool includeNamespace) const;
|
||||
virtual int GetGlobalVar(asUINT index, const char **name, const char **nameSpace, int *typeId, bool *isConst) const;
|
||||
virtual void *GetAddressOfGlobalVar(asUINT index);
|
||||
virtual int RemoveGlobalVar(asUINT index);
|
||||
|
||||
// Type identification
|
||||
virtual asUINT GetObjectTypeCount() const;
|
||||
virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const;
|
||||
virtual int GetTypeIdByDecl(const char *decl) const;
|
||||
virtual asITypeInfo *GetTypeInfoByName(const char *name) const;
|
||||
virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const;
|
||||
|
||||
// Enums
|
||||
virtual asUINT GetEnumCount() const;
|
||||
virtual asITypeInfo *GetEnumByIndex(asUINT index) const;
|
||||
|
||||
// Typedefs
|
||||
virtual asUINT GetTypedefCount() const;
|
||||
virtual asITypeInfo *GetTypedefByIndex(asUINT index) const;
|
||||
|
||||
// Dynamic binding between modules
|
||||
virtual asUINT GetImportedFunctionCount() const;
|
||||
virtual int GetImportedFunctionIndexByDecl(const char *decl) const;
|
||||
virtual const char *GetImportedFunctionDeclaration(asUINT importIndex) const;
|
||||
virtual const char *GetImportedFunctionSourceModule(asUINT importIndex) const;
|
||||
virtual int BindImportedFunction(asUINT index, asIScriptFunction *func);
|
||||
virtual int UnbindImportedFunction(asUINT importIndex);
|
||||
virtual int BindAllImportedFunctions();
|
||||
virtual int UnbindAllImportedFunctions();
|
||||
|
||||
// Bytecode Saving/Loading
|
||||
virtual int SaveByteCode(asIBinaryStream *out, bool stripDebugInfo) const;
|
||||
virtual int LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped);
|
||||
|
||||
// User data
|
||||
virtual void *SetUserData(void *data, asPWORD type);
|
||||
virtual void *GetUserData(asPWORD type) const;
|
||||
|
||||
//-----------------------------------------------
|
||||
// Internal
|
||||
//-----------------------------------------------
|
||||
asCModule(const char *name, asCScriptEngine *engine);
|
||||
~asCModule();
|
||||
|
||||
//protected:
|
||||
friend class asCScriptEngine;
|
||||
friend class asCBuilder;
|
||||
friend class asCCompiler;
|
||||
friend class asCContext;
|
||||
friend class asCRestore;
|
||||
|
||||
void InternalReset();
|
||||
bool IsEmpty() const;
|
||||
bool HasExternalReferences(bool shuttingDown);
|
||||
|
||||
int CallInit(asIScriptContext *ctx);
|
||||
void CallExit();
|
||||
int InitGlobalProp(asCGlobalProperty *prop, asIScriptContext *ctx);
|
||||
|
||||
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<asCString> ¶mNames, const asCArray<asETypeModifiers> &inOutFlags, const asCArray<asCString *> &defaultArgs, bool isInterface, asCObjectType *objType = 0, bool isGlobalFunction = false, asSFunctionTraits funcTraits = asSFunctionTraits(), 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, asSFunctionTraits funcTraits, asSNameSpace *ns, const asCString &moduleName);
|
||||
int AddFuncDef(const asCString &name, asSNameSpace *ns, asCObjectType *parent);
|
||||
#endif
|
||||
|
||||
int GetNextImportedFunctionId();
|
||||
asCScriptFunction *GetImportedFunction(int funcId) const;
|
||||
asCTypeInfo *GetType(const asCString &type, asSNameSpace *ns) const;
|
||||
asCObjectType *GetObjectType(const char *type, asSNameSpace *ns) const;
|
||||
asCGlobalProperty *AllocateGlobalProperty(const char *name, const asCDataType &dt, asSNameSpace *ns);
|
||||
void UninitializeGlobalProp(asCGlobalProperty *prop);
|
||||
|
||||
// Adds the class type to the module. The module assumes ownership of the reference without increasing it
|
||||
void AddClassType(asCObjectType*);
|
||||
// Adds the enum type to the module. The module assumes ownership of the reference without increasing it
|
||||
void AddEnumType(asCEnumType*);
|
||||
// Adds the typedef to the module. The module assumes ownership of the reference without increasing it
|
||||
void AddTypeDef(asCTypedefType*);
|
||||
// Adds the funcdef to the module. The module assumes ownership of the reference without increasing it
|
||||
void AddFuncDef(asCFuncdefType*);
|
||||
// Replaces an existing funcdef with another (used for shared funcdefs). Doesn't add or release refCounts
|
||||
void ReplaceFuncDef(asCFuncdefType *oldType, asCFuncdefType *newType);
|
||||
|
||||
asCString m_name;
|
||||
asCScriptEngine *m_engine;
|
||||
asCBuilder *m_builder;
|
||||
asCArray<asPWORD> m_userData;
|
||||
asDWORD m_accessMask;
|
||||
asSNameSpace *m_defaultNamespace;
|
||||
|
||||
// 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 *> m_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> m_globalFunctions; // doesn't increase ref count
|
||||
// This array holds imported functions in the module.
|
||||
asCArray<sBindInfo *> m_bindInformations; // increases ref count
|
||||
// This array holds template instance types created for the module's object types
|
||||
asCArray<asCObjectType*> m_templateInstances; // increases ref count
|
||||
|
||||
// This array holds the global variables declared in the script
|
||||
asCSymbolTable<asCGlobalProperty> m_scriptGlobals; // increases ref count
|
||||
bool m_isGlobalVarInitialized;
|
||||
|
||||
// This array holds class and interface types
|
||||
asCArray<asCObjectType*> m_classTypes; // increases ref count
|
||||
// This array holds enum types
|
||||
asCArray<asCEnumType*> m_enumTypes; // increases ref count
|
||||
// This array holds typedefs
|
||||
asCArray<asCTypedefType*> m_typeDefs; // increases ref count
|
||||
// This array holds the funcdefs declared in the module
|
||||
asCArray<asCFuncdefType*> m_funcDefs; // increases ref count
|
||||
|
||||
// This map contains all the types (also contained in the arrays above) for quick lookup
|
||||
// TODO: memory: Can we eliminate the arrays above?
|
||||
asCMap<asSNameSpaceNamePair, asCTypeInfo*> m_typeLookup; // doesn't increase ref count
|
||||
|
||||
// This array holds types that have been explicitly declared with 'external'
|
||||
asCArray<asCTypeInfo*> m_externalTypes; // doesn't increase ref count
|
||||
// This array holds functions that have been explicitly declared with 'external'
|
||||
asCArray<asCScriptFunction*> m_externalFunctions; // doesn't increase ref count
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
#ifndef AS_NAMESPACE_H
|
||||
#define AS_NAMESPACE_H
|
||||
|
||||
#include "as_string.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
struct asSNameSpace
|
||||
{
|
||||
asCString name;
|
||||
|
||||
// TODO: namespace: A namespace should have access masks. The application should be
|
||||
// able to restrict specific namespaces from access to specific modules
|
||||
};
|
||||
|
||||
|
||||
struct asSNameSpaceNamePair
|
||||
{
|
||||
const asSNameSpace *ns;
|
||||
asCString name;
|
||||
|
||||
asSNameSpaceNamePair() : ns(0) {}
|
||||
asSNameSpaceNamePair(const asSNameSpace *_ns, const asCString &_name) : ns(_ns), name(_name) {}
|
||||
|
||||
asSNameSpaceNamePair &operator=(const asSNameSpaceNamePair &other)
|
||||
{
|
||||
ns = other.ns;
|
||||
name = other.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const asSNameSpaceNamePair &other) const
|
||||
{
|
||||
return (ns == other.ns && name == other.name);
|
||||
}
|
||||
|
||||
bool operator<(const asSNameSpaceNamePair &other) const
|
||||
{
|
||||
return (ns < other.ns || (ns == other.ns && name < other.name));
|
||||
}
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,707 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2017 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_objecttype.cpp
|
||||
//
|
||||
// A class for storing object type information
|
||||
//
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_objecttype.h"
|
||||
#include "as_configgroup.h"
|
||||
#include "as_scriptengine.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asCObjectType::asCObjectType() : asCTypeInfo()
|
||||
{
|
||||
derivedFrom = 0;
|
||||
|
||||
acceptValueSubType = true;
|
||||
acceptRefSubType = true;
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
alignment = 4;
|
||||
#endif
|
||||
}
|
||||
|
||||
asCObjectType::asCObjectType(asCScriptEngine *in_engine) : asCTypeInfo(in_engine)
|
||||
{
|
||||
derivedFrom = 0;
|
||||
|
||||
acceptValueSubType = true;
|
||||
acceptRefSubType = true;
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
alignment = 4;
|
||||
#endif
|
||||
}
|
||||
|
||||
// interface
|
||||
asUINT asCObjectType::GetChildFuncdefCount() const
|
||||
{
|
||||
return childFuncDefs.GetLength();
|
||||
}
|
||||
|
||||
// interface
|
||||
asITypeInfo *asCObjectType::GetChildFuncdef(asUINT index) const
|
||||
{
|
||||
if (index >= childFuncDefs.GetLength())
|
||||
return 0;
|
||||
|
||||
return childFuncDefs[index];
|
||||
}
|
||||
|
||||
// internal
|
||||
void asCObjectType::DestroyInternal()
|
||||
{
|
||||
if( engine == 0 ) return;
|
||||
|
||||
// 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
|
||||
bool isTemplateInstance = templateSubTypes.GetLength() > 0;
|
||||
for( asUINT subtypeIndex = 0; subtypeIndex < templateSubTypes.GetLength(); subtypeIndex++ )
|
||||
{
|
||||
if( templateSubTypes[subtypeIndex].GetTypeInfo() )
|
||||
templateSubTypes[subtypeIndex].GetTypeInfo()->ReleaseInternal();
|
||||
}
|
||||
templateSubTypes.SetLength(0);
|
||||
|
||||
// Clear the child types
|
||||
for (asUINT n = 0; n < childFuncDefs.GetLength(); n++)
|
||||
{
|
||||
asCFuncdefType *func = childFuncDefs[n];
|
||||
if (func)
|
||||
{
|
||||
func->parentClass = 0;
|
||||
if (isTemplateInstance)
|
||||
{
|
||||
// Any child funcdefs that have been created as part of the template
|
||||
// instantiation must be destroyed too
|
||||
// TODO: Before destroying the funcdef, make sure no external references to it is held
|
||||
if (func->externalRefCount.get() == 0)
|
||||
{
|
||||
func->DestroyInternal();
|
||||
engine->RemoveFuncdef(func);
|
||||
func->module = 0;
|
||||
func->ReleaseInternal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
childFuncDefs.SetLength(0);
|
||||
|
||||
if( derivedFrom )
|
||||
derivedFrom->ReleaseInternal();
|
||||
derivedFrom = 0;
|
||||
|
||||
ReleaseAllProperties();
|
||||
|
||||
ReleaseAllFunctions();
|
||||
|
||||
CleanUserData();
|
||||
|
||||
// Remove the type from the engine
|
||||
if( typeId != -1 )
|
||||
engine->RemoveFromTypeIdMap(this);
|
||||
|
||||
// Clear the engine pointer to mark the object type as invalid
|
||||
engine = 0;
|
||||
}
|
||||
|
||||
asCObjectType::~asCObjectType()
|
||||
{
|
||||
DestroyInternal();
|
||||
}
|
||||
|
||||
// interface
|
||||
bool asCObjectType::Implements(const asITypeInfo *objType) const
|
||||
{
|
||||
if( this == objType )
|
||||
return true;
|
||||
|
||||
for( asUINT n = 0; n < interfaces.GetLength(); n++ )
|
||||
if( interfaces[n] == objType ) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// interface
|
||||
bool asCObjectType::DerivesFrom(const asITypeInfo *objType) const
|
||||
{
|
||||
if( this == objType )
|
||||
return true;
|
||||
|
||||
asCObjectType *base = derivedFrom;
|
||||
while( base )
|
||||
{
|
||||
if( base == objType )
|
||||
return true;
|
||||
|
||||
base = base->derivedFrom;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCObjectType::GetSubTypeId(asUINT subtypeIndex) const
|
||||
{
|
||||
// This method is only supported for templates and template specializations
|
||||
if( templateSubTypes.GetLength() == 0 )
|
||||
return asERROR;
|
||||
|
||||
if( subtypeIndex >= templateSubTypes.GetLength() )
|
||||
return asINVALID_ARG;
|
||||
|
||||
return engine->GetTypeIdFromDataType(templateSubTypes[subtypeIndex]);
|
||||
}
|
||||
|
||||
// interface
|
||||
asITypeInfo *asCObjectType::GetSubType(asUINT subtypeIndex) const
|
||||
{
|
||||
if( subtypeIndex >= templateSubTypes.GetLength() )
|
||||
return 0;
|
||||
|
||||
return templateSubTypes[subtypeIndex].GetTypeInfo();
|
||||
}
|
||||
|
||||
asUINT asCObjectType::GetSubTypeCount() const
|
||||
{
|
||||
return asUINT(templateSubTypes.GetLength());
|
||||
}
|
||||
|
||||
asUINT asCObjectType::GetInterfaceCount() const
|
||||
{
|
||||
return asUINT(interfaces.GetLength());
|
||||
}
|
||||
|
||||
asITypeInfo *asCObjectType::GetInterface(asUINT index) const
|
||||
{
|
||||
return interfaces[index];
|
||||
}
|
||||
|
||||
// internal
|
||||
bool asCObjectType::IsInterface() const
|
||||
{
|
||||
if( (flags & asOBJ_SCRIPT_OBJECT) && size == 0 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// interface
|
||||
asUINT asCObjectType::GetFactoryCount() const
|
||||
{
|
||||
return (asUINT)beh.factories.GetLength();
|
||||
}
|
||||
|
||||
// interface
|
||||
asIScriptFunction *asCObjectType::GetFactoryByIndex(asUINT index) const
|
||||
{
|
||||
if( index >= beh.factories.GetLength() )
|
||||
return 0;
|
||||
|
||||
return engine->GetFunctionById(beh.factories[index]);
|
||||
}
|
||||
|
||||
// interface
|
||||
asIScriptFunction *asCObjectType::GetFactoryByDecl(const char *decl) const
|
||||
{
|
||||
if( beh.factories.GetLength() == 0 )
|
||||
return 0;
|
||||
|
||||
// Let the engine parse the string and find the appropriate factory function
|
||||
return engine->GetFunctionById(engine->GetFactoryIdByDecl(this, decl));
|
||||
}
|
||||
|
||||
// interface
|
||||
asUINT asCObjectType::GetMethodCount() const
|
||||
{
|
||||
return (asUINT)methods.GetLength();
|
||||
}
|
||||
|
||||
// interface
|
||||
asIScriptFunction *asCObjectType::GetMethodByIndex(asUINT index, bool getVirtual) const
|
||||
{
|
||||
if( index >= methods.GetLength() )
|
||||
return 0;
|
||||
|
||||
asCScriptFunction *func = engine->scriptFunctions[methods[index]];
|
||||
if( !getVirtual )
|
||||
{
|
||||
if( func && func->funcType == asFUNC_VIRTUAL )
|
||||
return virtualFunctionTable[func->vfTableIdx];
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
// interface
|
||||
asIScriptFunction *asCObjectType::GetMethodByName(const char *in_name, bool in_getVirtual) const
|
||||
{
|
||||
int id = -1;
|
||||
for( asUINT n = 0; n < methods.GetLength(); n++ )
|
||||
{
|
||||
if( engine->scriptFunctions[methods[n]]->name == in_name )
|
||||
{
|
||||
if( id == -1 )
|
||||
id = methods[n];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( id == -1 ) return 0;
|
||||
|
||||
asCScriptFunction *func = engine->scriptFunctions[id];
|
||||
if( !in_getVirtual )
|
||||
{
|
||||
if( func && func->funcType == asFUNC_VIRTUAL )
|
||||
return virtualFunctionTable[func->vfTableIdx];
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
// interface
|
||||
asIScriptFunction *asCObjectType::GetMethodByDecl(const char *decl, bool getVirtual) const
|
||||
{
|
||||
if( methods.GetLength() == 0 )
|
||||
return 0;
|
||||
|
||||
// Get the module from one of the methods, but it will only be
|
||||
// used to allow the parsing of types not already known by the object.
|
||||
// It is possible for object types to be orphaned, e.g. by discarding
|
||||
// the module that created it. In this case it is still possible to
|
||||
// find the methods, but any type not known by the object will result in
|
||||
// an invalid declaration.
|
||||
asCModule *mod = engine->scriptFunctions[methods[0]]->module;
|
||||
int id = engine->GetMethodIdByDecl(this, decl, mod);
|
||||
if( id <= 0 )
|
||||
return 0;
|
||||
|
||||
if( !getVirtual )
|
||||
{
|
||||
asCScriptFunction *func = engine->scriptFunctions[id];
|
||||
if( func && func->funcType == asFUNC_VIRTUAL )
|
||||
return virtualFunctionTable[func->vfTableIdx];
|
||||
}
|
||||
|
||||
return engine->scriptFunctions[id];
|
||||
}
|
||||
|
||||
// interface
|
||||
asUINT asCObjectType::GetPropertyCount() const
|
||||
{
|
||||
return (asUINT)properties.GetLength();
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCObjectType::GetProperty(asUINT index, const char **out_name, int *out_typeId, bool *out_isPrivate, bool *out_isProtected, int *out_offset, bool *out_isReference, asDWORD *out_accessMask, int *out_compositeOffset, bool *out_isCompositeIndirect) const
|
||||
{
|
||||
if( index >= properties.GetLength() )
|
||||
return asINVALID_ARG;
|
||||
|
||||
asCObjectProperty *prop = properties[index];
|
||||
if( out_name )
|
||||
*out_name = prop->name.AddressOf();
|
||||
if( out_typeId )
|
||||
*out_typeId = engine->GetTypeIdFromDataType(prop->type);
|
||||
if( out_isPrivate )
|
||||
*out_isPrivate = prop->isPrivate;
|
||||
if( out_isProtected )
|
||||
*out_isProtected = prop->isProtected;
|
||||
if( out_offset )
|
||||
*out_offset = prop->byteOffset;
|
||||
if( out_isReference )
|
||||
*out_isReference = prop->type.IsReference();
|
||||
if( out_accessMask )
|
||||
*out_accessMask = prop->accessMask;
|
||||
if (out_compositeOffset)
|
||||
*out_compositeOffset = prop->compositeOffset;
|
||||
if (out_isCompositeIndirect)
|
||||
*out_isCompositeIndirect = prop->isCompositeIndirect;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
const char *asCObjectType::GetPropertyDeclaration(asUINT index, bool includeNamespace) const
|
||||
{
|
||||
if( index >= properties.GetLength() )
|
||||
return 0;
|
||||
|
||||
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(nameSpace, includeNamespace);
|
||||
*tempString += " ";
|
||||
*tempString += properties[index]->name;
|
||||
|
||||
return tempString->AddressOf();
|
||||
}
|
||||
|
||||
asITypeInfo *asCObjectType::GetBaseType() const
|
||||
{
|
||||
return derivedFrom;
|
||||
}
|
||||
|
||||
asUINT asCObjectType::GetBehaviourCount() const
|
||||
{
|
||||
// Count the number of behaviours (except factory functions)
|
||||
asUINT count = 0;
|
||||
|
||||
if( beh.destruct ) count++;
|
||||
if( beh.addref ) count++;
|
||||
if( beh.release ) count++;
|
||||
if( beh.gcGetRefCount ) count++;
|
||||
if( beh.gcSetFlag ) count++;
|
||||
if( beh.gcGetFlag ) count++;
|
||||
if( beh.gcEnumReferences ) count++;
|
||||
if( beh.gcReleaseAllReferences ) count++;
|
||||
if( beh.templateCallback ) count++;
|
||||
if( beh.listFactory ) count++;
|
||||
if( beh.getWeakRefFlag ) count++;
|
||||
|
||||
// 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();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
asIScriptFunction *asCObjectType::GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const
|
||||
{
|
||||
// Find the correct behaviour
|
||||
asUINT count = 0;
|
||||
|
||||
if( beh.destruct && count++ == index ) // only increase count if the behaviour is registered
|
||||
{
|
||||
if( outBehaviour ) *outBehaviour = asBEHAVE_DESTRUCT;
|
||||
return engine->scriptFunctions[beh.destruct];
|
||||
}
|
||||
|
||||
if( beh.addref && count++ == index )
|
||||
{
|
||||
if( outBehaviour ) *outBehaviour = asBEHAVE_ADDREF;
|
||||
return engine->scriptFunctions[beh.addref];
|
||||
}
|
||||
|
||||
if( beh.release && count++ == index )
|
||||
{
|
||||
if( outBehaviour ) *outBehaviour = asBEHAVE_RELEASE;
|
||||
return engine->scriptFunctions[beh.release];
|
||||
}
|
||||
|
||||
if( beh.gcGetRefCount && count++ == index )
|
||||
{
|
||||
if( outBehaviour ) *outBehaviour = asBEHAVE_GETREFCOUNT;
|
||||
return engine->scriptFunctions[beh.gcGetRefCount];
|
||||
}
|
||||
|
||||
if( beh.gcSetFlag && count++ == index )
|
||||
{
|
||||
if( outBehaviour ) *outBehaviour = asBEHAVE_SETGCFLAG;
|
||||
return engine->scriptFunctions[beh.gcSetFlag];
|
||||
}
|
||||
|
||||
if( beh.gcGetFlag && count++ == index )
|
||||
{
|
||||
if( outBehaviour ) *outBehaviour = asBEHAVE_GETGCFLAG;
|
||||
return engine->scriptFunctions[beh.gcGetFlag];
|
||||
}
|
||||
|
||||
if( beh.gcEnumReferences && count++ == index )
|
||||
{
|
||||
if( outBehaviour ) *outBehaviour = asBEHAVE_ENUMREFS;
|
||||
return engine->scriptFunctions[beh.gcEnumReferences];
|
||||
}
|
||||
|
||||
if( beh.gcReleaseAllReferences && count++ == index )
|
||||
{
|
||||
if( outBehaviour ) *outBehaviour = asBEHAVE_RELEASEREFS;
|
||||
return engine->scriptFunctions[beh.gcReleaseAllReferences];
|
||||
}
|
||||
|
||||
if( beh.templateCallback && count++ == index )
|
||||
{
|
||||
if( outBehaviour ) *outBehaviour = asBEHAVE_TEMPLATE_CALLBACK;
|
||||
return engine->scriptFunctions[beh.templateCallback];
|
||||
}
|
||||
|
||||
if( beh.listFactory && count++ == index )
|
||||
{
|
||||
if( outBehaviour )
|
||||
{
|
||||
if( flags & asOBJ_VALUE )
|
||||
*outBehaviour = asBEHAVE_LIST_CONSTRUCT;
|
||||
else
|
||||
*outBehaviour = asBEHAVE_LIST_FACTORY;
|
||||
}
|
||||
|
||||
return engine->scriptFunctions[beh.listFactory];
|
||||
}
|
||||
|
||||
if( beh.getWeakRefFlag && count++ == index )
|
||||
{
|
||||
if( outBehaviour ) *outBehaviour = asBEHAVE_GET_WEAKREF_FLAG;
|
||||
return engine->scriptFunctions[beh.getWeakRefFlag];
|
||||
}
|
||||
|
||||
// For reference types, the factories are also stored in the constructor
|
||||
// list, so it is sufficient to enumerate only those
|
||||
if( index - count < beh.constructors.GetLength() )
|
||||
{
|
||||
if( outBehaviour ) *outBehaviour = asBEHAVE_CONSTRUCT;
|
||||
return engine->scriptFunctions[beh.constructors[index - count]];
|
||||
}
|
||||
else
|
||||
count += (asUINT)beh.constructors.GetLength();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// internal
|
||||
asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &propName, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited)
|
||||
{
|
||||
asASSERT( flags & asOBJ_SCRIPT_OBJECT );
|
||||
asASSERT( dt.CanBeInstantiated() );
|
||||
asASSERT( !IsInterface() );
|
||||
|
||||
// Store the properties in the object type descriptor
|
||||
asCObjectProperty *prop = asNEW(asCObjectProperty);
|
||||
if( prop == 0 )
|
||||
{
|
||||
// Out of memory
|
||||
return 0;
|
||||
}
|
||||
|
||||
prop->name = propName;
|
||||
prop->type = dt;
|
||||
prop->isPrivate = isPrivate;
|
||||
prop->isProtected = isProtected;
|
||||
prop->isInherited = isInherited;
|
||||
|
||||
int propSize;
|
||||
if( dt.IsObject() )
|
||||
{
|
||||
// Non-POD value types can't be allocated inline,
|
||||
// because there is a risk that the script might
|
||||
// try to access the content without knowing that
|
||||
// it hasn't been initialized yet.
|
||||
if( dt.GetTypeInfo()->flags & asOBJ_POD )
|
||||
propSize = dt.GetSizeInMemoryBytes();
|
||||
else
|
||||
{
|
||||
propSize = dt.GetSizeOnStackDWords()*4;
|
||||
if( !dt.IsObjectHandle() )
|
||||
prop->type.MakeReference(true);
|
||||
}
|
||||
}
|
||||
else if (dt.IsFuncdef())
|
||||
{
|
||||
// Funcdefs don't have a size, as they must always be stored as handles
|
||||
asASSERT(dt.IsObjectHandle());
|
||||
propSize = AS_PTR_SIZE * 4;
|
||||
}
|
||||
else
|
||||
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;
|
||||
|
||||
properties.PushLast(prop);
|
||||
|
||||
// Make sure the struct holds a reference to the config group where the object is registered
|
||||
asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(prop->type.GetTypeInfo());
|
||||
if( group != 0 ) group->AddRef();
|
||||
|
||||
// Add reference to object types
|
||||
asCTypeInfo *type = prop->type.GetTypeInfo();
|
||||
if( type )
|
||||
type->AddRefInternal();
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
// internal
|
||||
void asCObjectType::ReleaseAllProperties()
|
||||
{
|
||||
for( asUINT n = 0; n < properties.GetLength(); n++ )
|
||||
{
|
||||
if( properties[n] )
|
||||
{
|
||||
if( flags & asOBJ_SCRIPT_OBJECT )
|
||||
{
|
||||
// Release the config group for script classes that are being destroyed
|
||||
asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(properties[n]->type.GetTypeInfo());
|
||||
if( group != 0 ) group->Release();
|
||||
|
||||
// Release references to objects types
|
||||
asCTypeInfo *type = properties[n]->type.GetTypeInfo();
|
||||
if( type )
|
||||
type->ReleaseInternal();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Release template instance types (ref increased by RegisterObjectProperty)
|
||||
asCTypeInfo *type = properties[n]->type.GetTypeInfo();
|
||||
if( type )
|
||||
type->ReleaseInternal();
|
||||
}
|
||||
|
||||
asDELETE(properties[n],asCObjectProperty);
|
||||
}
|
||||
}
|
||||
|
||||
properties.SetLength(0);
|
||||
}
|
||||
|
||||
// internal
|
||||
void asCObjectType::ReleaseAllFunctions()
|
||||
{
|
||||
beh.factory = 0;
|
||||
beh.copyfactory = 0;
|
||||
for( asUINT a = 0; a < beh.factories.GetLength(); a++ )
|
||||
{
|
||||
if( engine->scriptFunctions[beh.factories[a]] )
|
||||
engine->scriptFunctions[beh.factories[a]]->ReleaseInternal();
|
||||
}
|
||||
beh.factories.SetLength(0);
|
||||
|
||||
beh.construct = 0;
|
||||
beh.copyconstruct = 0;
|
||||
for( asUINT b = 0; b < beh.constructors.GetLength(); b++ )
|
||||
{
|
||||
if( engine->scriptFunctions[beh.constructors[b]] )
|
||||
engine->scriptFunctions[beh.constructors[b]]->ReleaseInternal();
|
||||
}
|
||||
beh.constructors.SetLength(0);
|
||||
|
||||
if( beh.templateCallback )
|
||||
engine->scriptFunctions[beh.templateCallback]->ReleaseInternal();
|
||||
beh.templateCallback = 0;
|
||||
|
||||
if( beh.listFactory )
|
||||
engine->scriptFunctions[beh.listFactory]->ReleaseInternal();
|
||||
beh.listFactory = 0;
|
||||
|
||||
if( beh.destruct )
|
||||
engine->scriptFunctions[beh.destruct]->ReleaseInternal();
|
||||
beh.destruct = 0;
|
||||
|
||||
if( beh.copy )
|
||||
engine->scriptFunctions[beh.copy]->ReleaseInternal();
|
||||
beh.copy = 0;
|
||||
|
||||
for( asUINT c = 0; c < methods.GetLength(); c++ )
|
||||
{
|
||||
if( engine->scriptFunctions[methods[c]] )
|
||||
engine->scriptFunctions[methods[c]]->ReleaseInternal();
|
||||
}
|
||||
methods.SetLength(0);
|
||||
|
||||
for( asUINT d = 0; d < virtualFunctionTable.GetLength(); d++ )
|
||||
{
|
||||
if( virtualFunctionTable[d] )
|
||||
virtualFunctionTable[d]->ReleaseInternal();
|
||||
}
|
||||
virtualFunctionTable.SetLength(0);
|
||||
|
||||
// GC behaviours
|
||||
if( beh.addref )
|
||||
engine->scriptFunctions[beh.addref]->ReleaseInternal();
|
||||
beh.addref = 0;
|
||||
|
||||
if( beh.release )
|
||||
engine->scriptFunctions[beh.release]->ReleaseInternal();
|
||||
beh.release = 0;
|
||||
|
||||
if( beh.gcEnumReferences )
|
||||
engine->scriptFunctions[beh.gcEnumReferences]->ReleaseInternal();
|
||||
beh.gcEnumReferences = 0;
|
||||
|
||||
if( beh.gcGetFlag )
|
||||
engine->scriptFunctions[beh.gcGetFlag]->ReleaseInternal();
|
||||
beh.gcGetFlag = 0;
|
||||
|
||||
if( beh.gcGetRefCount )
|
||||
engine->scriptFunctions[beh.gcGetRefCount]->ReleaseInternal();
|
||||
beh.gcGetRefCount = 0;
|
||||
|
||||
if( beh.gcReleaseAllReferences )
|
||||
engine->scriptFunctions[beh.gcReleaseAllReferences]->ReleaseInternal();
|
||||
beh.gcReleaseAllReferences = 0;
|
||||
|
||||
if( beh.gcSetFlag )
|
||||
engine->scriptFunctions[beh.gcSetFlag]->ReleaseInternal();
|
||||
beh.gcSetFlag = 0;
|
||||
|
||||
if ( beh.getWeakRefFlag )
|
||||
engine->scriptFunctions[beh.getWeakRefFlag]->ReleaseInternal();
|
||||
beh.getWeakRefFlag = 0;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2017 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
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//
|
||||
// as_objecttype.h
|
||||
//
|
||||
// A class for storing object type information
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_OBJECTTYPE_H
|
||||
#define AS_OBJECTTYPE_H
|
||||
|
||||
#include "as_property.h"
|
||||
#include "as_array.h"
|
||||
#include "as_scriptfunction.h"
|
||||
#include "as_typeinfo.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
struct asSTypeBehaviour
|
||||
{
|
||||
asSTypeBehaviour()
|
||||
{
|
||||
factory = 0;
|
||||
listFactory = 0;
|
||||
copyfactory = 0;
|
||||
construct = 0;
|
||||
copyconstruct = 0;
|
||||
destruct = 0;
|
||||
copy = 0;
|
||||
addref = 0;
|
||||
release = 0;
|
||||
gcGetRefCount = 0;
|
||||
gcSetFlag = 0;
|
||||
gcGetFlag = 0;
|
||||
gcEnumReferences = 0;
|
||||
gcReleaseAllReferences = 0;
|
||||
templateCallback = 0;
|
||||
getWeakRefFlag = 0;
|
||||
}
|
||||
|
||||
int factory;
|
||||
int listFactory; // Used for initialization lists only
|
||||
int copyfactory;
|
||||
int construct;
|
||||
int copyconstruct;
|
||||
int destruct;
|
||||
int copy;
|
||||
int addref;
|
||||
int release;
|
||||
int templateCallback;
|
||||
|
||||
// GC behaviours
|
||||
int gcGetRefCount;
|
||||
int gcSetFlag;
|
||||
int gcGetFlag;
|
||||
int gcEnumReferences;
|
||||
int gcReleaseAllReferences;
|
||||
|
||||
// Weakref behaviours
|
||||
int getWeakRefFlag;
|
||||
|
||||
asCArray<int> factories;
|
||||
asCArray<int> constructors;
|
||||
};
|
||||
|
||||
class asCScriptEngine;
|
||||
struct asSNameSpace;
|
||||
|
||||
class asCObjectType : public asCTypeInfo
|
||||
{
|
||||
public:
|
||||
asITypeInfo *GetBaseType() const;
|
||||
bool DerivesFrom(const asITypeInfo *objType) const;
|
||||
int GetSubTypeId(asUINT subtypeIndex = 0) const;
|
||||
asITypeInfo *GetSubType(asUINT subtypeIndex = 0) const;
|
||||
asUINT GetSubTypeCount() const;
|
||||
asUINT GetInterfaceCount() const;
|
||||
asITypeInfo *GetInterface(asUINT index) const;
|
||||
bool Implements(const asITypeInfo *objType) const;
|
||||
asUINT GetFactoryCount() const;
|
||||
asIScriptFunction *GetFactoryByIndex(asUINT index) const;
|
||||
asIScriptFunction *GetFactoryByDecl(const char *decl) const;
|
||||
asUINT GetMethodCount() const;
|
||||
asIScriptFunction *GetMethodByIndex(asUINT index, bool getVirtual) const;
|
||||
asIScriptFunction *GetMethodByName(const char *name, bool getVirtual) const;
|
||||
asIScriptFunction *GetMethodByDecl(const char *decl, bool getVirtual) const;
|
||||
asUINT GetPropertyCount() const;
|
||||
int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask, int *compositeOffset, bool *isCompositeIndirect) const;
|
||||
const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const;
|
||||
asUINT GetBehaviourCount() const;
|
||||
asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const;
|
||||
asUINT GetChildFuncdefCount() const;
|
||||
asITypeInfo *GetChildFuncdef(asUINT index) const;
|
||||
|
||||
public:
|
||||
asCObjectType(asCScriptEngine *engine);
|
||||
~asCObjectType();
|
||||
void DestroyInternal();
|
||||
|
||||
void ReleaseAllFunctions();
|
||||
|
||||
bool IsInterface() const;
|
||||
|
||||
asCObjectProperty *AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited);
|
||||
void ReleaseAllProperties();
|
||||
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
int alignment;
|
||||
#endif
|
||||
asCArray<asCObjectProperty*> properties;
|
||||
asCArray<int> methods;
|
||||
|
||||
// TODO: These are not used by template types. Should perhaps create a derived class to save memory on ordinary object types
|
||||
asCArray<asCObjectType*> interfaces;
|
||||
asCArray<asUINT> interfaceVFTOffsets;
|
||||
asCObjectType * derivedFrom;
|
||||
asCArray<asCScriptFunction*> virtualFunctionTable;
|
||||
|
||||
// Used for funcdefs declared as members of class.
|
||||
// TODO: child funcdef: Should be possible to enumerate these from application
|
||||
asCArray<asCFuncdefType*> childFuncDefs;
|
||||
|
||||
asSTypeBehaviour beh;
|
||||
|
||||
// Used for template types
|
||||
asCArray<asCDataType> templateSubTypes; // increases refCount for typeinfo held in datatype
|
||||
bool acceptValueSubType;
|
||||
bool acceptRefSubType;
|
||||
|
||||
protected:
|
||||
friend class asCScriptEngine;
|
||||
friend class asCConfigGroup;
|
||||
friend class asCModule;
|
||||
asCObjectType();
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_outputbuffer.cpp
|
||||
//
|
||||
// This class appends strings to one large buffer that can later
|
||||
// be sent to the real output stream
|
||||
//
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
|
||||
#include "as_outputbuffer.h"
|
||||
#include "as_scriptengine.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asCOutputBuffer::~asCOutputBuffer()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void asCOutputBuffer::Clear()
|
||||
{
|
||||
for( asUINT n = 0; n < messages.GetLength(); n++ )
|
||||
{
|
||||
if( messages[n] )
|
||||
{
|
||||
asDELETE(messages[n],message_t);
|
||||
}
|
||||
}
|
||||
messages.SetLength(0);
|
||||
}
|
||||
|
||||
void asCOutputBuffer::Callback(asSMessageInfo *msg)
|
||||
{
|
||||
message_t *msgInfo = asNEW(message_t);
|
||||
if( msgInfo == 0 )
|
||||
return;
|
||||
|
||||
msgInfo->section = msg->section;
|
||||
msgInfo->row = msg->row;
|
||||
msgInfo->col = msg->col;
|
||||
msgInfo->type = msg->type;
|
||||
msgInfo->msg = msg->message;
|
||||
|
||||
messages.PushLast(msgInfo);
|
||||
}
|
||||
|
||||
void asCOutputBuffer::Append(asCOutputBuffer &in)
|
||||
{
|
||||
for( asUINT n = 0; n < in.messages.GetLength(); n++ )
|
||||
messages.PushLast(in.messages[n]);
|
||||
in.messages.SetLength(0);
|
||||
}
|
||||
|
||||
void asCOutputBuffer::SendToCallback(asCScriptEngine *engine, asSSystemFunctionInterface *func, void *obj)
|
||||
{
|
||||
for( asUINT n = 0; n < messages.GetLength(); n++ )
|
||||
{
|
||||
asSMessageInfo msg;
|
||||
msg.section = messages[n]->section.AddressOf();
|
||||
msg.row = messages[n]->row;
|
||||
msg.col = messages[n]->col;
|
||||
msg.type = messages[n]->type;
|
||||
msg.message = messages[n]->msg.AddressOf();
|
||||
|
||||
if( func->callConv < ICC_THISCALL )
|
||||
engine->CallGlobalFunction(&msg, obj, func, 0);
|
||||
else
|
||||
engine->CallObjectMethod(obj, &msg, func, 0);
|
||||
}
|
||||
Clear();
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_NO_COMPILER
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_outputbuffer.h
|
||||
//
|
||||
// This class appends strings to one large buffer that can later
|
||||
// be sent to the real output stream
|
||||
//
|
||||
|
||||
|
||||
#ifndef AS_OUTPUTBUFFER_H
|
||||
#define AS_OUTPUTBUFFER_H
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
|
||||
#include "as_string.h"
|
||||
#include "as_array.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
struct asSSystemFunctionInterface;
|
||||
class asCScriptEngine;
|
||||
|
||||
class asCOutputBuffer
|
||||
{
|
||||
public:
|
||||
~asCOutputBuffer ();
|
||||
void Clear();
|
||||
void Callback(asSMessageInfo *msg);
|
||||
void Append(asCOutputBuffer &in);
|
||||
void SendToCallback(asCScriptEngine *engine, asSSystemFunctionInterface *func, void *obj);
|
||||
|
||||
struct message_t
|
||||
{
|
||||
asCString section;
|
||||
int row;
|
||||
int col;
|
||||
asEMsgType type;
|
||||
asCString msg;
|
||||
};
|
||||
|
||||
asCArray<message_t*> messages;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_NO_COMPILER
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2018 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_parser.h
|
||||
//
|
||||
// This class parses the script code and builds a tree for compilation
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_PARSER_H
|
||||
#define AS_PARSER_H
|
||||
|
||||
#include "as_scriptnode.h"
|
||||
#include "as_scriptcode.h"
|
||||
#include "as_builder.h"
|
||||
#include "as_tokenizer.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCParser
|
||||
{
|
||||
public:
|
||||
asCParser(asCBuilder *builder);
|
||||
~asCParser();
|
||||
|
||||
int ParseFunctionDefinition(asCScriptCode *script, bool expectListPattern);
|
||||
int ParsePropertyDeclaration(asCScriptCode *script);
|
||||
int ParseDataType(asCScriptCode *script, bool isReturnType);
|
||||
int ParseTemplateDecl(asCScriptCode *script);
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
int ParseScript(asCScriptCode *script);
|
||||
|
||||
// Called from compiler
|
||||
int ParseStatementBlock(asCScriptCode *script, asCScriptNode *block);
|
||||
int ParseVarInit(asCScriptCode *script, asCScriptNode *init);
|
||||
int ParseExpression(asCScriptCode *script);
|
||||
#endif
|
||||
|
||||
asCScriptNode *GetScriptNode();
|
||||
|
||||
protected:
|
||||
void Reset();
|
||||
|
||||
void GetToken(sToken *token);
|
||||
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);
|
||||
|
||||
asCScriptNode *ParseFunctionDefinition();
|
||||
asCScriptNode *ParseParameterList();
|
||||
asCScriptNode *SuperficiallyParseExpression();
|
||||
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, bool allowAuto = false);
|
||||
asCScriptNode *ParseIdentifier();
|
||||
bool ParseTemplTypeList(asCScriptNode *node, bool required = true);
|
||||
void ParseMethodAttributes(asCScriptNode *funcNode);
|
||||
|
||||
asCScriptNode *ParseListPattern();
|
||||
|
||||
bool IsRealType(int tokenType);
|
||||
bool IsDataType(const sToken &token);
|
||||
bool IdentifierIs(const sToken &t, const char *str);
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
// Statements
|
||||
asCScriptNode *SuperficiallyParseStatementBlock();
|
||||
asCScriptNode *SuperficiallyParseVarInit();
|
||||
asCScriptNode *ParseStatementBlock();
|
||||
asCScriptNode *ParseStatement();
|
||||
asCScriptNode *ParseExpressionStatement();
|
||||
asCScriptNode *ParseSwitch();
|
||||
asCScriptNode *ParseCase();
|
||||
asCScriptNode *ParseIf();
|
||||
asCScriptNode *ParseFor();
|
||||
asCScriptNode *ParseWhile();
|
||||
asCScriptNode *ParseDoWhile();
|
||||
asCScriptNode *ParseReturn();
|
||||
asCScriptNode *ParseBreak();
|
||||
asCScriptNode *ParseContinue();
|
||||
asCScriptNode *ParseTryCatch();
|
||||
|
||||
// Declarations
|
||||
asCScriptNode *ParseDeclaration(bool isClassProp = false, bool isGlobalVar = false);
|
||||
asCScriptNode *ParseImport();
|
||||
asCScriptNode *ParseScript(bool inBlock);
|
||||
asCScriptNode *ParseNamespace();
|
||||
asCScriptNode *ParseFunction(bool isMethod = false);
|
||||
asCScriptNode *ParseFuncDef();
|
||||
asCScriptNode *ParseClass();
|
||||
asCScriptNode *ParseMixin();
|
||||
asCScriptNode *ParseInitList();
|
||||
asCScriptNode *ParseInterface();
|
||||
asCScriptNode *ParseInterfaceMethod();
|
||||
asCScriptNode *ParseVirtualPropertyDecl(bool isMethod, bool isInterface);
|
||||
asCScriptNode *ParseEnumeration();
|
||||
asCScriptNode *ParseTypedef();
|
||||
bool IsVarDecl();
|
||||
bool IsVirtualPropertyDecl();
|
||||
bool IsFuncDecl(bool isMethod);
|
||||
bool IsLambda();
|
||||
bool IsFunctionCall();
|
||||
|
||||
// Expressions
|
||||
asCScriptNode *ParseAssignment();
|
||||
asCScriptNode *ParseAssignOperator();
|
||||
asCScriptNode *ParseCondition();
|
||||
asCScriptNode *ParseExpression();
|
||||
asCScriptNode *ParseExprTerm();
|
||||
asCScriptNode *ParseExprOperator();
|
||||
asCScriptNode *ParseExprPreOp();
|
||||
asCScriptNode *ParseExprPostOp();
|
||||
asCScriptNode *ParseExprValue();
|
||||
asCScriptNode *ParseArgList(bool withParenthesis = true);
|
||||
asCScriptNode *ParseFunctionCall();
|
||||
asCScriptNode *ParseVariableAccess();
|
||||
asCScriptNode *ParseConstructCall();
|
||||
asCScriptNode *ParseCast();
|
||||
asCScriptNode *ParseConstant();
|
||||
asCScriptNode *ParseStringConstant();
|
||||
asCScriptNode *ParseLambda();
|
||||
|
||||
bool IsType(sToken &nextToken);
|
||||
bool IsConstant(int tokenType);
|
||||
bool IsOperator(int tokenType);
|
||||
bool IsPreOperator(int tokenType);
|
||||
bool IsPostOperator(int tokenType);
|
||||
bool IsAssignOperator(int tokenType);
|
||||
|
||||
bool CheckTemplateType(const sToken &t);
|
||||
#endif
|
||||
|
||||
asCScriptNode *ParseToken(int token);
|
||||
asCScriptNode *ParseOneOf(int *tokens, int num);
|
||||
|
||||
asCString ExpectedToken(const char *token);
|
||||
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;
|
||||
bool checkValidTypes;
|
||||
bool isParsingAppInterface;
|
||||
|
||||
asCScriptEngine *engine;
|
||||
asCBuilder *builder;
|
||||
asCScriptCode *script;
|
||||
asCScriptNode *scriptNode;
|
||||
|
||||
asCString tempString; // Used for reduzing amount of dynamic allocations
|
||||
|
||||
sToken lastToken;
|
||||
size_t sourcePos;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2017 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_property.h
|
||||
//
|
||||
// A class for storing object property information
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_PROPERTY_H
|
||||
#define AS_PROPERTY_H
|
||||
|
||||
#include "as_string.h"
|
||||
#include "as_datatype.h"
|
||||
#include "as_atomic.h"
|
||||
#include "as_scriptfunction.h"
|
||||
#include "as_symboltable.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
struct asSNameSpace;
|
||||
|
||||
class asCObjectProperty
|
||||
{
|
||||
public:
|
||||
asCObjectProperty() : byteOffset(0), accessMask(0xFFFFFFFF), compositeOffset(0), isCompositeIndirect(false), isPrivate(false), isProtected(false), isInherited(false) {}
|
||||
asCObjectProperty(const asCObjectProperty &o) : name(o.name), type(o.type), byteOffset(o.byteOffset), accessMask(o.accessMask), compositeOffset(o.compositeOffset), isCompositeIndirect(o.isCompositeIndirect), isPrivate(o.isPrivate), isProtected(o.isProtected), isInherited(o.isInherited) {}
|
||||
asCString name;
|
||||
asCDataType type;
|
||||
int byteOffset;
|
||||
asDWORD accessMask;
|
||||
int compositeOffset;
|
||||
bool isCompositeIndirect;
|
||||
bool isPrivate;
|
||||
bool isProtected;
|
||||
bool isInherited;
|
||||
};
|
||||
|
||||
class asCGlobalProperty
|
||||
{
|
||||
public:
|
||||
asCGlobalProperty();
|
||||
~asCGlobalProperty();
|
||||
|
||||
void AddRef();
|
||||
void Release();
|
||||
void DestroyInternal();
|
||||
|
||||
void *GetAddressOfValue();
|
||||
void AllocateMemory();
|
||||
void SetRegisteredAddress(void *p);
|
||||
void *GetRegisteredAddress() const;
|
||||
|
||||
asCString name;
|
||||
asCDataType type;
|
||||
asUINT id;
|
||||
asSNameSpace *nameSpace;
|
||||
|
||||
void SetInitFunc(asCScriptFunction *initFunc);
|
||||
asCScriptFunction *GetInitFunc();
|
||||
|
||||
//protected:
|
||||
// This is only stored for registered properties, and keeps the pointer given by the application
|
||||
void *realAddress;
|
||||
|
||||
bool memoryAllocated;
|
||||
void *memory;
|
||||
asQWORD storage;
|
||||
|
||||
asCScriptFunction *initFunc;
|
||||
|
||||
asDWORD accessMask;
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
class asCCompGlobPropType : public asIFilter
|
||||
{
|
||||
public:
|
||||
const asCDataType &m_type;
|
||||
|
||||
asCCompGlobPropType(const asCDataType &type) : m_type(type) {}
|
||||
|
||||
bool operator()(const void *p) const
|
||||
{
|
||||
const asCGlobalProperty* prop = reinterpret_cast<const asCGlobalProperty*>(p);
|
||||
return prop->type == m_type;
|
||||
}
|
||||
|
||||
private:
|
||||
// The assignment operator is required for MSVC9, otherwise it will complain that it is not possible to auto generate the operator
|
||||
asCCompGlobPropType &operator=(const asCCompGlobPropType &) {return *this;}
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2021 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_restore.h
|
||||
//
|
||||
// Functions for saving and restoring module bytecode
|
||||
// asCRestore was originally written by Dennis Bollyn, dennis@gyrbo.be
|
||||
// It was later split in two classes asCReader and asCWriter by me
|
||||
|
||||
#ifndef AS_RESTORE_H
|
||||
#define AS_RESTORE_H
|
||||
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_context.h"
|
||||
#include "as_map.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCReader
|
||||
{
|
||||
public:
|
||||
asCReader(asCModule *module, asIBinaryStream *stream, asCScriptEngine *engine);
|
||||
|
||||
int Read(bool *wasDebugInfoStripped);
|
||||
|
||||
protected:
|
||||
asCModule *module;
|
||||
asIBinaryStream *stream;
|
||||
asCScriptEngine *engine;
|
||||
bool noDebugInfo;
|
||||
bool error;
|
||||
asUINT bytesRead;
|
||||
|
||||
int Error(const char *msg);
|
||||
|
||||
int ReadInner();
|
||||
|
||||
int ReadData(void *data, asUINT size);
|
||||
void ReadString(asCString *str);
|
||||
asCScriptFunction *ReadFunction(bool &isNew, bool addToModule = true, bool addToEngine = true, bool addToGC = true, bool *isExternal = 0);
|
||||
void ReadFunctionSignature(asCScriptFunction *func, asCObjectType **parentClass = 0);
|
||||
void ReadGlobalProperty();
|
||||
void ReadObjectProperty(asCObjectType *ot);
|
||||
void ReadDataType(asCDataType *dt);
|
||||
asCTypeInfo *ReadTypeInfo();
|
||||
void ReadTypeDeclaration(asCTypeInfo *ot, int phase, bool *isExternal = 0);
|
||||
void ReadByteCode(asCScriptFunction *func);
|
||||
asWORD ReadEncodedUInt16();
|
||||
asUINT ReadEncodedUInt();
|
||||
int ReadEncodedInt();
|
||||
asQWORD ReadEncodedUInt64();
|
||||
asUINT SanityCheck(asUINT val, asUINT max);
|
||||
int SanityCheck(int val, asUINT max);
|
||||
|
||||
void ReadUsedTypeIds();
|
||||
void ReadUsedFunctions();
|
||||
void ReadUsedGlobalProps();
|
||||
void ReadUsedStringConstants();
|
||||
void ReadUsedObjectProps();
|
||||
|
||||
asCTypeInfo * FindType(int idx);
|
||||
int FindTypeId(int idx);
|
||||
short FindObjectPropOffset(asWORD index);
|
||||
asCScriptFunction *FindFunction(int idx);
|
||||
|
||||
// After loading, each function needs to be translated to update pointers, function ids, etc
|
||||
void TranslateFunction(asCScriptFunction *func);
|
||||
void CalculateAdjustmentByPos(asCScriptFunction *func);
|
||||
int AdjustStackPosition(int pos);
|
||||
int AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos);
|
||||
void CalculateStackNeeded(asCScriptFunction *func);
|
||||
asCScriptFunction *GetCalledFunction(asCScriptFunction *func, asDWORD programPos);
|
||||
|
||||
// Temporary storage for persisting variable data
|
||||
asCArray<int> usedTypeIds;
|
||||
asCArray<asCTypeInfo*> usedTypes;
|
||||
asCArray<asCScriptFunction*> usedFunctions;
|
||||
asCArray<void*> usedGlobalProperties;
|
||||
asCArray<void*> usedStringConstants;
|
||||
|
||||
asCArray<asCScriptFunction*> savedFunctions;
|
||||
asCArray<asCDataType> savedDataTypes;
|
||||
asCArray<asCString> savedStrings;
|
||||
|
||||
asCArray<int> adjustByPos;
|
||||
asCArray<int> adjustNegativeStackByPos;
|
||||
|
||||
struct SObjProp
|
||||
{
|
||||
asCObjectType *objType;
|
||||
asCObjectProperty *prop;
|
||||
};
|
||||
asCArray<SObjProp> usedObjectProperties;
|
||||
|
||||
asCMap<void*,bool> existingShared;
|
||||
asCMap<asCScriptFunction*,bool> dontTranslate;
|
||||
|
||||
// Helper class for adjusting offsets within initialization list buffers
|
||||
struct SListAdjuster
|
||||
{
|
||||
SListAdjuster(asCReader *rd, asDWORD *bc, asCObjectType *ot);
|
||||
void AdjustAllocMem();
|
||||
int AdjustOffset(int offset);
|
||||
void SetRepeatCount(asUINT rc);
|
||||
void SetNextType(int typeId);
|
||||
|
||||
struct SInfo
|
||||
{
|
||||
asUINT repeatCount;
|
||||
asSListPatternNode *startNode;
|
||||
};
|
||||
asCArray<SInfo> stack;
|
||||
|
||||
asCReader *reader;
|
||||
asDWORD *allocMemBC;
|
||||
asUINT maxOffset;
|
||||
asCObjectType *patternType;
|
||||
asUINT repeatCount;
|
||||
int lastOffset;
|
||||
int nextOffset;
|
||||
asUINT lastAdjustedOffset;
|
||||
asSListPatternNode *patternNode;
|
||||
int nextTypeId;
|
||||
};
|
||||
asCArray<SListAdjuster*> listAdjusters;
|
||||
};
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
|
||||
class asCWriter
|
||||
{
|
||||
public:
|
||||
asCWriter(asCModule *module, asIBinaryStream *stream, asCScriptEngine *engine, bool stripDebugInfo);
|
||||
|
||||
int Write();
|
||||
|
||||
protected:
|
||||
asCModule *module;
|
||||
asIBinaryStream *stream;
|
||||
asCScriptEngine *engine;
|
||||
bool stripDebugInfo;
|
||||
bool error;
|
||||
asUINT bytesWritten;
|
||||
|
||||
int Error(const char *msg);
|
||||
|
||||
int WriteData(const void *data, asUINT size);
|
||||
|
||||
void WriteString(asCString *str);
|
||||
void WriteFunction(asCScriptFunction *func);
|
||||
void WriteFunctionSignature(asCScriptFunction *func);
|
||||
void WriteGlobalProperty(asCGlobalProperty *prop);
|
||||
void WriteObjectProperty(asCObjectProperty *prop);
|
||||
void WriteDataType(const asCDataType *dt);
|
||||
void WriteTypeInfo(asCTypeInfo *ot);
|
||||
void WriteTypeDeclaration(asCTypeInfo *ot, int phase);
|
||||
void WriteByteCode(asCScriptFunction *func);
|
||||
void WriteEncodedInt64(asINT64 i);
|
||||
|
||||
// Helper functions for storing variable data
|
||||
int FindTypeInfoIdx(asCTypeInfo *ti);
|
||||
int FindTypeIdIdx(int typeId);
|
||||
int FindFunctionIndex(asCScriptFunction *func);
|
||||
int FindGlobalPropPtrIndex(void *);
|
||||
int FindStringConstantIndex(void *str);
|
||||
int FindObjectPropIndex(short offset, int typeId, asDWORD *bc);
|
||||
|
||||
void CalculateAdjustmentByPos(asCScriptFunction *func);
|
||||
int AdjustStackPosition(int pos);
|
||||
int AdjustProgramPosition(int pos);
|
||||
int AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos);
|
||||
|
||||
// Intermediate data used for storing that which isn't constant, function id's, pointers, etc
|
||||
void WriteUsedTypeIds();
|
||||
void WriteUsedFunctions();
|
||||
void WriteUsedGlobalProps();
|
||||
void WriteUsedStringConstants();
|
||||
void WriteUsedObjectProps();
|
||||
|
||||
// Temporary storage for persisting variable data
|
||||
asCArray<int> usedTypeIds;
|
||||
asCArray<asCTypeInfo*> usedTypes;
|
||||
asCArray<asCScriptFunction*> usedFunctions;
|
||||
asCArray<void*> usedGlobalProperties;
|
||||
asCArray<void*> usedStringConstants;
|
||||
asCMap<void*, int> stringToIndexMap;
|
||||
|
||||
asCArray<asCScriptFunction*> savedFunctions;
|
||||
asCArray<asCDataType> savedDataTypes;
|
||||
asCArray<asCString> savedStrings;
|
||||
asCMap<asCString, int> stringToIdMap;
|
||||
asCArray<int> adjustStackByPos;
|
||||
asCArray<int> adjustNegativeStackByPos;
|
||||
asCArray<int> bytecodeNbrByPos;
|
||||
|
||||
struct SObjProp
|
||||
{
|
||||
asCObjectType *objType;
|
||||
asCObjectProperty *prop;
|
||||
};
|
||||
asCArray<SObjProp> usedObjectProperties;
|
||||
|
||||
// Helper class for adjusting offsets within initialization list buffers
|
||||
struct SListAdjuster
|
||||
{
|
||||
SListAdjuster(asCObjectType *ot);
|
||||
int AdjustOffset(int offset, asCObjectType *listPatternType);
|
||||
void SetRepeatCount(asUINT rc);
|
||||
void SetNextType(int typeId);
|
||||
|
||||
struct SInfo
|
||||
{
|
||||
asUINT repeatCount;
|
||||
asSListPatternNode *startNode;
|
||||
};
|
||||
asCArray<SInfo> stack;
|
||||
|
||||
asCObjectType *patternType;
|
||||
asUINT repeatCount;
|
||||
asSListPatternNode *patternNode;
|
||||
asUINT entries;
|
||||
int lastOffset; // Last offset adjusted
|
||||
int nextOffset; // next expected offset to be adjusted
|
||||
int nextTypeId;
|
||||
};
|
||||
asCArray<SListAdjuster*> listAdjusters;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_RESTORE_H
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_scriptcode.cpp
|
||||
//
|
||||
// A container class for the script code to be compiled
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_scriptcode.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asCScriptCode::asCScriptCode()
|
||||
{
|
||||
lineOffset = 0;
|
||||
code = 0;
|
||||
codeLength = 0;
|
||||
sharedCode = false;
|
||||
}
|
||||
|
||||
asCScriptCode::~asCScriptCode()
|
||||
{
|
||||
if( !sharedCode && code )
|
||||
{
|
||||
asDELETEARRAY(code);
|
||||
}
|
||||
}
|
||||
|
||||
int asCScriptCode::SetCode(const char *in_name, const char *in_code, bool in_makeCopy)
|
||||
{
|
||||
return SetCode(in_name, in_code, 0, in_makeCopy);
|
||||
}
|
||||
|
||||
int asCScriptCode::SetCode(const char *in_name, const char *in_code, size_t in_length, bool in_makeCopy)
|
||||
{
|
||||
if( !in_code) return asINVALID_ARG;
|
||||
this->name = in_name ? in_name : "";
|
||||
if( !sharedCode && code )
|
||||
asDELETEARRAY(code);
|
||||
|
||||
if( in_length == 0 )
|
||||
in_length = strlen(in_code);
|
||||
if( in_makeCopy )
|
||||
{
|
||||
codeLength = in_length;
|
||||
sharedCode = false;
|
||||
code = asNEWARRAY(char, in_length);
|
||||
if( code == 0 )
|
||||
return asOUT_OF_MEMORY;
|
||||
memcpy(code, in_code, in_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
codeLength = in_length;
|
||||
code = const_cast<char*>(in_code);
|
||||
sharedCode = true;
|
||||
}
|
||||
|
||||
// Find the positions of each line
|
||||
linePositions.PushLast(0);
|
||||
for( size_t n = 0; n < in_length; n++ )
|
||||
if( in_code[n] == '\n' ) linePositions.PushLast(n+1);
|
||||
linePositions.PushLast(in_length);
|
||||
|
||||
return asSUCCESS;
|
||||
}
|
||||
|
||||
void asCScriptCode::ConvertPosToRowCol(size_t pos, int *row, int *col)
|
||||
{
|
||||
if( linePositions.GetLength() == 0 )
|
||||
{
|
||||
if( row ) *row = lineOffset;
|
||||
if( col ) *col = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do a binary search in the buffer
|
||||
int max = (int)linePositions.GetLength() - 1;
|
||||
int min = 0;
|
||||
int i = max/2;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if( linePositions[i] < pos )
|
||||
{
|
||||
// Have we found the largest number < programPosition?
|
||||
if( min == i ) break;
|
||||
|
||||
min = i;
|
||||
i = (max + min)/2;
|
||||
}
|
||||
else if( linePositions[i] > pos )
|
||||
{
|
||||
// Have we found the smallest number > programPoisition?
|
||||
if( max == i ) break;
|
||||
|
||||
max = i;
|
||||
i = (max + min)/2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We found the exact position
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( row ) *row = i + 1 + lineOffset;
|
||||
if( col ) *col = (int)(pos - linePositions[i]) + 1;
|
||||
}
|
||||
|
||||
bool asCScriptCode::TokenEquals(size_t pos, size_t len, const char *str)
|
||||
{
|
||||
if( pos + len > codeLength ) return false;
|
||||
if( strncmp(code + pos, str, len) == 0 && strlen(str) == len )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2011 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_scriptcode.h
|
||||
//
|
||||
// A container class for the script code to be compiled
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_SCRIPTCODE_H
|
||||
#define AS_SCRIPTCODE_H
|
||||
|
||||
#include "as_array.h"
|
||||
#include "as_string.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCScriptCode
|
||||
{
|
||||
public:
|
||||
asCScriptCode();
|
||||
~asCScriptCode();
|
||||
|
||||
int SetCode(const char *name, const char *code, bool makeCopy);
|
||||
int SetCode(const char *name, const char *code, size_t length, bool makeCopy);
|
||||
|
||||
void ConvertPosToRowCol(size_t pos, int *row, int *col);
|
||||
|
||||
bool TokenEquals(size_t pos, size_t len, const char *str);
|
||||
|
||||
asCString name;
|
||||
char *code;
|
||||
size_t codeLength;
|
||||
bool sharedCode;
|
||||
int idx;
|
||||
int lineOffset;
|
||||
asCArray<size_t> linePositions;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,527 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2019 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_scriptengine.h
|
||||
//
|
||||
// The implementation of the script engine interface
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_SCRIPTENGINE_H
|
||||
#define AS_SCRIPTENGINE_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_atomic.h"
|
||||
#include "as_scriptfunction.h"
|
||||
#include "as_array.h"
|
||||
#include "as_datatype.h"
|
||||
#include "as_objecttype.h"
|
||||
#include "as_module.h"
|
||||
#include "as_callfunc.h"
|
||||
#include "as_configgroup.h"
|
||||
#include "as_memory.h"
|
||||
#include "as_gc.h"
|
||||
#include "as_tokenizer.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCBuilder;
|
||||
class asCContext;
|
||||
|
||||
// TODO: import: Remove this when import is removed
|
||||
struct sBindInfo;
|
||||
|
||||
class asCScriptEngine : public asIScriptEngine
|
||||
{
|
||||
//=============================================================
|
||||
// From asIScriptEngine
|
||||
//=============================================================
|
||||
public:
|
||||
// Memory management
|
||||
virtual int AddRef() const;
|
||||
virtual int Release() const;
|
||||
virtual int ShutDownAndRelease();
|
||||
|
||||
// Engine properties
|
||||
virtual int SetEngineProperty(asEEngineProp property, asPWORD value);
|
||||
virtual asPWORD GetEngineProperty(asEEngineProp property) const;
|
||||
|
||||
// Compiler messages
|
||||
virtual int SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv);
|
||||
virtual int ClearMessageCallback();
|
||||
virtual int WriteMessage(const char *section, int row, int col, asEMsgType type, const char *message);
|
||||
|
||||
// JIT Compiler
|
||||
virtual int SetJITCompiler(asIJITCompiler *compiler);
|
||||
virtual asIJITCompiler *GetJITCompiler() const;
|
||||
|
||||
// Global functions
|
||||
virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0);
|
||||
virtual asUINT GetGlobalFunctionCount() const;
|
||||
virtual asIScriptFunction *GetGlobalFunctionByIndex(asUINT index) const;
|
||||
virtual asIScriptFunction *GetGlobalFunctionByDecl(const char *declaration) const;
|
||||
|
||||
// Global properties
|
||||
virtual int RegisterGlobalProperty(const char *declaration, void *pointer);
|
||||
virtual asUINT GetGlobalPropertyCount() const;
|
||||
virtual int GetGlobalPropertyByIndex(asUINT index, const char **name, const char **nameSpace = 0, int *typeId = 0, bool *isConst = 0, const char **configGroup = 0, void **pointer = 0, asDWORD *accessMask = 0) const;
|
||||
virtual int GetGlobalPropertyIndexByName(const char *name) const;
|
||||
virtual int GetGlobalPropertyIndexByDecl(const char *decl) const;
|
||||
|
||||
// Type registration
|
||||
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags);
|
||||
virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset = 0, bool isCompositeIndirect = false);
|
||||
virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false);
|
||||
virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false);
|
||||
virtual int RegisterInterface(const char *name);
|
||||
virtual int RegisterInterfaceMethod(const char *intf, const char *declaration);
|
||||
virtual asUINT GetObjectTypeCount() const;
|
||||
virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const;
|
||||
|
||||
// String factory
|
||||
virtual int RegisterStringFactory(const char *datatype, asIStringFactory *factory);
|
||||
virtual int GetStringFactoryReturnTypeId(asDWORD *flags) const;
|
||||
|
||||
// Default array type
|
||||
virtual int RegisterDefaultArrayType(const char *type);
|
||||
virtual int GetDefaultArrayTypeId() const;
|
||||
|
||||
// Enums
|
||||
virtual int RegisterEnum(const char *type);
|
||||
virtual int RegisterEnumValue(const char *type, const char *name, int value);
|
||||
virtual asUINT GetEnumCount() const;
|
||||
virtual asITypeInfo *GetEnumByIndex(asUINT index) const;
|
||||
|
||||
// Funcdefs
|
||||
virtual int RegisterFuncdef(const char *decl);
|
||||
virtual asUINT GetFuncdefCount() const;
|
||||
virtual asITypeInfo *GetFuncdefByIndex(asUINT index) const;
|
||||
|
||||
// Typedefs
|
||||
// TODO: interface: Should perhaps rename this to Alias, since it doesn't really create a new type
|
||||
virtual int RegisterTypedef(const char *type, const char *decl);
|
||||
virtual asUINT GetTypedefCount() const;
|
||||
virtual asITypeInfo *GetTypedefByIndex(asUINT index) const;
|
||||
|
||||
// Configuration groups
|
||||
virtual int BeginConfigGroup(const char *groupName);
|
||||
virtual int EndConfigGroup();
|
||||
virtual int RemoveConfigGroup(const char *groupName);
|
||||
virtual asDWORD SetDefaultAccessMask(asDWORD defaultMask);
|
||||
virtual int SetDefaultNamespace(const char *nameSpace);
|
||||
virtual const char *GetDefaultNamespace() const;
|
||||
|
||||
// Script modules
|
||||
virtual asIScriptModule *GetModule(const char *module, asEGMFlags flag);
|
||||
virtual int DiscardModule(const char *module);
|
||||
virtual asUINT GetModuleCount() const;
|
||||
virtual asIScriptModule *GetModuleByIndex(asUINT index) const;
|
||||
|
||||
// Script functions
|
||||
virtual asIScriptFunction *GetFunctionById(int funcId) const;
|
||||
|
||||
// Type identification
|
||||
virtual int GetTypeIdByDecl(const char *decl) const;
|
||||
virtual const char *GetTypeDeclaration(int typeId, bool includeNamespace = false) const;
|
||||
virtual int GetSizeOfPrimitiveType(int typeId) const;
|
||||
virtual asITypeInfo *GetTypeInfoById(int typeId) const;
|
||||
virtual asITypeInfo *GetTypeInfoByName(const char *name) const;
|
||||
virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const;
|
||||
|
||||
// Script execution
|
||||
virtual asIScriptContext *CreateContext();
|
||||
virtual void *CreateScriptObject(const asITypeInfo *type);
|
||||
virtual void *CreateScriptObjectCopy(void *obj, const asITypeInfo *type);
|
||||
virtual void *CreateUninitializedScriptObject(const asITypeInfo *type);
|
||||
virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj);
|
||||
virtual int AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type);
|
||||
virtual void ReleaseScriptObject(void *obj, const asITypeInfo *type);
|
||||
virtual void AddRefScriptObject(void *obj, const asITypeInfo *type);
|
||||
virtual int RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast = false);
|
||||
virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *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, asUINT *tokenLength = 0) const;
|
||||
|
||||
// Garbage collection
|
||||
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, asITypeInfo *type);
|
||||
virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj = 0, asITypeInfo **type = 0);
|
||||
virtual void GCEnumCallback(void *reference);
|
||||
virtual void ForwardGCEnumReferences(void *ref, asITypeInfo *type);
|
||||
virtual void ForwardGCReleaseReferences(void *ref, asITypeInfo *type);
|
||||
virtual void SetCircularRefDetectedCallback(asCIRCULARREFFUNC_t callback, void *param = 0);
|
||||
|
||||
// User data
|
||||
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 SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type);
|
||||
virtual void SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type);
|
||||
|
||||
// Exception handling
|
||||
virtual int SetTranslateAppExceptionCallback(asSFuncPtr callback, void *param, int callConv);
|
||||
|
||||
//===========================================================
|
||||
// internal methods
|
||||
//===========================================================
|
||||
public:
|
||||
asCScriptEngine();
|
||||
virtual ~asCScriptEngine();
|
||||
|
||||
//protected:
|
||||
friend class asCBuilder;
|
||||
friend class asCCompiler;
|
||||
friend class asCContext;
|
||||
friend class asCDataType;
|
||||
friend class asCModule;
|
||||
friend class asCRestore;
|
||||
friend class asCByteCode;
|
||||
friend int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine);
|
||||
|
||||
int RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false);
|
||||
int RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false);
|
||||
|
||||
int VerifyVarTypeNotInFunction(asCScriptFunction *func);
|
||||
|
||||
void *CallAlloc(const asCObjectType *objType) const;
|
||||
void CallFree(void *obj) const;
|
||||
|
||||
void *CallGlobalFunctionRetPtr(int func) const;
|
||||
void *CallGlobalFunctionRetPtr(int func, void *param1) const;
|
||||
void *CallGlobalFunctionRetPtr(asSSystemFunctionInterface *func, asCScriptFunction *desc) const;
|
||||
void *CallGlobalFunctionRetPtr(asSSystemFunctionInterface *i, asCScriptFunction *s, void *param1) const;
|
||||
void CallObjectMethod(void *obj, int func) const;
|
||||
void CallObjectMethod(void *obj, void *param, int func) const;
|
||||
void CallObjectMethod(void *obj, asSSystemFunctionInterface *func, asCScriptFunction *desc) const;
|
||||
void CallObjectMethod(void *obj, void *param, asSSystemFunctionInterface *func, asCScriptFunction *desc) const;
|
||||
bool CallObjectMethodRetBool(void *obj, int func) const;
|
||||
int CallObjectMethodRetInt(void *obj, int func) const;
|
||||
void *CallObjectMethodRetPtr(void *obj, int func) const;
|
||||
void *CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const;
|
||||
void CallGlobalFunction(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const;
|
||||
bool CallGlobalFunctionRetBool(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const;
|
||||
int CallScriptObjectMethod(void *obj, int func);
|
||||
|
||||
void ConstructScriptObjectCopy(void *mem, void *obj, asCObjectType *type);
|
||||
|
||||
void DeleteDiscardedModules();
|
||||
|
||||
void RemoveTemplateInstanceType(asCObjectType *t);
|
||||
|
||||
asCConfigGroup *FindConfigGroupForFunction(int funcId) const;
|
||||
asCConfigGroup *FindConfigGroupForGlobalVar(int gvarId) const;
|
||||
asCConfigGroup *FindConfigGroupForTypeInfo(const asCTypeInfo *type) const;
|
||||
asCConfigGroup *FindConfigGroupForFuncDef(const asCFuncdefType *funcDef) const;
|
||||
|
||||
int RequestBuild();
|
||||
void BuildCompleted();
|
||||
|
||||
void PrepareEngine();
|
||||
bool isPrepared;
|
||||
|
||||
int CreateContext(asIScriptContext **context, bool isInternal);
|
||||
|
||||
asCTypeInfo *GetRegisteredType(const asCString &name, asSNameSpace *ns) const;
|
||||
|
||||
asCObjectType *GetListPatternType(int listPatternFuncId);
|
||||
void DestroyList(asBYTE *buffer, const asCObjectType *listPatternType);
|
||||
void DestroySubList(asBYTE *&buffer, asSListPatternNode *&patternNode);
|
||||
|
||||
int AddBehaviourFunction(asCScriptFunction &func, asSSystemFunctionInterface &internal);
|
||||
|
||||
asCString GetFunctionDeclaration(int funcId);
|
||||
|
||||
asCScriptFunction *GetScriptFunction(int funcId) const;
|
||||
|
||||
asCModule *GetModule(const char *name, bool create);
|
||||
asCModule *GetModuleFromFuncId(int funcId);
|
||||
|
||||
int GetMethodIdByDecl(const asCObjectType *ot, const char *decl, asCModule *mod);
|
||||
int GetFactoryIdByDecl(const asCObjectType *ot, const char *decl);
|
||||
|
||||
int GetNextScriptFunctionId();
|
||||
void AddScriptFunction(asCScriptFunction *func);
|
||||
void RemoveScriptFunction(asCScriptFunction *func);
|
||||
void RemoveFuncdef(asCFuncdefType *func);
|
||||
|
||||
int ConfigError(int err, const char *funcName, const char *arg1, const char *arg2);
|
||||
|
||||
int GetTypeIdFromDataType(const asCDataType &dt) const;
|
||||
asCDataType GetDataTypeFromTypeId(int typeId) const;
|
||||
asCObjectType *GetObjectTypeFromTypeId(int typeId) const;
|
||||
void RemoveFromTypeIdMap(asCTypeInfo *type);
|
||||
|
||||
bool IsTemplateType(const char *name) const;
|
||||
int SetTemplateRestrictions(asCObjectType *templateType, asCScriptFunction *func, const char *caller, const char *decl);
|
||||
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);
|
||||
asCFuncdefType *GenerateNewTemplateFuncdef(asCObjectType *templateType, asCObjectType *templateInstanceType, asCFuncdefType *templateFuncdef);
|
||||
asCDataType DetermineTypeForTemplate(const asCDataType &orig, asCObjectType *tmpl, asCObjectType *ot);
|
||||
bool RequireTypeReplacement(asCDataType &type, asCObjectType *templateType);
|
||||
|
||||
asCModule *FindNewOwnerForSharedType(asCTypeInfo *type, asCModule *mod);
|
||||
asCModule *FindNewOwnerForSharedFunc(asCScriptFunction *func, asCModule *mod);
|
||||
|
||||
asCFuncdefType *FindMatchingFuncdef(asCScriptFunction *func, asCModule *mod);
|
||||
|
||||
int DetermineNameAndNamespace(const char *in_name, asSNameSpace *implicitNs, asCString &out_name, asSNameSpace *&out_ns) const;
|
||||
|
||||
// Global property management
|
||||
asCGlobalProperty *AllocateGlobalProperty();
|
||||
void RemoveGlobalProperty(asCGlobalProperty *prop);
|
||||
|
||||
int GetScriptSectionNameIndex(const char *name);
|
||||
|
||||
// Namespace management
|
||||
asSNameSpace *AddNameSpace(const char *name);
|
||||
asSNameSpace *FindNameSpace(const char *name) const;
|
||||
asSNameSpace *GetParentNameSpace(asSNameSpace *ns) const;
|
||||
|
||||
//===========================================================
|
||||
// internal properties
|
||||
//===========================================================
|
||||
asCMemoryMgr memoryMgr;
|
||||
|
||||
asCObjectType *defaultArrayObjectType;
|
||||
asCObjectType scriptTypeBehaviours;
|
||||
asCObjectType functionBehaviours;
|
||||
|
||||
// Registered interface
|
||||
asCArray<asCObjectType *> registeredObjTypes; // doesn't increase ref count
|
||||
asCArray<asCTypedefType *> registeredTypeDefs; // doesn't increase ref count
|
||||
asCArray<asCEnumType *> registeredEnums; // doesn't increase ref count
|
||||
// TODO: memory savings: Since there can be only one property with the same name a simpler symbol table should be used for global props
|
||||
asCSymbolTable<asCGlobalProperty> registeredGlobalProps; // increases ref count
|
||||
asCSymbolTable<asCScriptFunction> registeredGlobalFuncs;
|
||||
asCArray<asCFuncdefType *> registeredFuncDefs; // doesn't increase ref count
|
||||
asCArray<asCObjectType *> registeredTemplateTypes; // doesn't increase ref count
|
||||
asIStringFactory *stringFactory;
|
||||
asCDataType stringType;
|
||||
bool configFailed;
|
||||
|
||||
// Stores all registered types
|
||||
asCMap<asSNameSpaceNamePair, asCTypeInfo*> allRegisteredTypes; // increases ref count
|
||||
|
||||
// Dummy types used to name the subtypes in the template objects
|
||||
asCArray<asCTypeInfo *> templateSubTypes;
|
||||
|
||||
// Store information about template types
|
||||
// This list will contain all instances of templates, both registered specialized
|
||||
// types and those automacially instantiated from scripts
|
||||
asCArray<asCObjectType *> templateInstanceTypes; // increases ref count
|
||||
|
||||
// Store information about list patterns
|
||||
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; // 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; // doesn't increase ref count
|
||||
|
||||
// Stores all functions, i.e. registered functions, script functions, class methods, behaviours, etc.
|
||||
asCArray<asCScriptFunction *> scriptFunctions; // doesn't increase ref count
|
||||
asCArray<int> freeScriptFunctionIds;
|
||||
asCArray<asCScriptFunction *> signatureIds;
|
||||
|
||||
// An array with all module imported functions
|
||||
asCArray<sBindInfo *> importedFunctions; // doesn't increase ref count
|
||||
asCArray<int> freeImportedFunctionIdxs;
|
||||
|
||||
// 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 instantiated once to share resources
|
||||
asCTokenizer tok;
|
||||
|
||||
// Stores shared script declared types (classes, interfaces, enums)
|
||||
asCArray<asCTypeInfo *> 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
|
||||
// TODO: 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<asCFuncdefType *> funcDefs; // doesn't increases ref count
|
||||
|
||||
// Stores the names of the script sections for debugging purposes
|
||||
asCArray<asCString *> scriptSectionNames;
|
||||
|
||||
// Type identifiers
|
||||
mutable int typeIdSeqNbr;
|
||||
mutable asCMap<int, asCTypeInfo*> mapTypeIdToTypeInfo;
|
||||
|
||||
// Garbage collector
|
||||
asCGarbageCollector gc;
|
||||
|
||||
// Dynamic groups
|
||||
asCConfigGroup defaultGroup;
|
||||
asCArray<asCConfigGroup*> configGroups;
|
||||
asCConfigGroup *currentGroup;
|
||||
asDWORD defaultAccessMask;
|
||||
asSNameSpace *defaultNamespace;
|
||||
|
||||
// Message callback
|
||||
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
|
||||
// These are shared between all entities and are
|
||||
// only deleted once the engine is destroyed
|
||||
asCArray<asSNameSpace*> nameSpaces;
|
||||
|
||||
// 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;
|
||||
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 STypeInfoClean { asPWORD type; asCLEANTYPEINFOFUNC_t cleanFunc; };
|
||||
asCArray<STypeInfoClean> cleanTypeInfoFuncs;
|
||||
struct SScriptObjClean { asPWORD type; asCLEANSCRIPTOBJECTFUNC_t cleanFunc; };
|
||||
asCArray<SScriptObjClean> cleanScriptObjectFuncs;
|
||||
|
||||
// Synchronization for threads
|
||||
DECLAREREADWRITELOCK(mutable engineRWLock)
|
||||
|
||||
// Engine properties
|
||||
struct
|
||||
{
|
||||
bool allowUnsafeReferences;
|
||||
bool optimizeByteCode;
|
||||
bool copyScriptSections;
|
||||
asUINT maximumContextStackSize;
|
||||
asUINT initContextStackSize;
|
||||
bool useCharacterLiterals;
|
||||
bool allowMultilineStrings;
|
||||
bool allowImplicitHandleTypes;
|
||||
bool buildWithoutLineCues;
|
||||
bool initGlobalVarsAfterBuild;
|
||||
bool requireEnumScope;
|
||||
int scanner;
|
||||
bool includeJitInstructions;
|
||||
int stringEncoding;
|
||||
int propertyAccessorMode;
|
||||
bool expandDefaultArrayToTemplate;
|
||||
bool autoGarbageCollect;
|
||||
bool disallowGlobalVars;
|
||||
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;
|
||||
bool allowUnicodeIdentifiers;
|
||||
int heredocTrimMode;
|
||||
asUINT maxNestedCalls;
|
||||
asUINT genericCallMode;
|
||||
asUINT initCallStackSize;
|
||||
asUINT maxCallStackSize;
|
||||
} ep;
|
||||
|
||||
// Callbacks
|
||||
#ifndef AS_NO_EXCEPTIONS
|
||||
bool translateExceptionCallback;
|
||||
asSSystemFunctionInterface translateExceptionCallbackFunc;
|
||||
void * translateExceptionCallbackObj;
|
||||
#endif
|
||||
|
||||
// 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
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2021 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_scriptfunction.h
|
||||
//
|
||||
// A container for a compiled script function
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_SCRIPTFUNCTION_H
|
||||
#define AS_SCRIPTFUNCTION_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_string.h"
|
||||
#include "as_array.h"
|
||||
#include "as_datatype.h"
|
||||
#include "as_atomic.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCScriptEngine;
|
||||
class asCModule;
|
||||
class asCConfigGroup;
|
||||
class asCGlobalProperty;
|
||||
class asCScriptNode;
|
||||
class asCFuncdefType;
|
||||
struct asSNameSpace;
|
||||
|
||||
struct asSScriptVariable
|
||||
{
|
||||
asCString name;
|
||||
asCDataType type;
|
||||
int stackOffset;
|
||||
asUINT declaredAtProgramPos;
|
||||
};
|
||||
|
||||
enum asEListPatternNodeType
|
||||
{
|
||||
asLPT_REPEAT,
|
||||
asLPT_REPEAT_SAME,
|
||||
asLPT_START,
|
||||
asLPT_END,
|
||||
asLPT_TYPE
|
||||
};
|
||||
|
||||
struct asSListPatternNode
|
||||
{
|
||||
asSListPatternNode(asEListPatternNodeType t) : type(t), next(0) {}
|
||||
virtual ~asSListPatternNode() {};
|
||||
virtual asSListPatternNode *Duplicate() { return asNEW(asSListPatternNode)(type); }
|
||||
asEListPatternNodeType type;
|
||||
asSListPatternNode *next;
|
||||
};
|
||||
|
||||
struct asSListPatternDataTypeNode : public asSListPatternNode
|
||||
{
|
||||
asSListPatternDataTypeNode(const asCDataType &dt) : asSListPatternNode(asLPT_TYPE), dataType(dt) {}
|
||||
asSListPatternNode *Duplicate() { return asNEW(asSListPatternDataTypeNode)(dataType); }
|
||||
asCDataType dataType;
|
||||
};
|
||||
|
||||
enum asEObjVarInfoOption
|
||||
{
|
||||
asOBJ_UNINIT, // object is uninitialized/destroyed
|
||||
asOBJ_INIT, // object is initialized
|
||||
asBLOCK_BEGIN, // scope block begins
|
||||
asBLOCK_END, // scope block ends
|
||||
asOBJ_VARDECL // object variable is declared (but not necessarily initialized)
|
||||
};
|
||||
|
||||
enum asEFuncTrait
|
||||
{
|
||||
asTRAIT_CONSTRUCTOR = 1,
|
||||
asTRAIT_DESTRUCTOR = 2,
|
||||
asTRAIT_CONST = 4,
|
||||
asTRAIT_PRIVATE = 8,
|
||||
asTRAIT_PROTECTED = 16,
|
||||
asTRAIT_FINAL = 32,
|
||||
asTRAIT_OVERRIDE = 64,
|
||||
asTRAIT_SHARED = 128,
|
||||
asTRAIT_EXTERNAL = 256,
|
||||
asTRAIT_EXPLICIT = 512,
|
||||
asTRAIT_PROPERTY = 1024
|
||||
};
|
||||
|
||||
struct asSFunctionTraits
|
||||
{
|
||||
asSFunctionTraits() : traits(0) {}
|
||||
void SetTrait(asEFuncTrait trait, bool set) { if (set) traits |= trait; else traits &= ~trait; }
|
||||
bool GetTrait(asEFuncTrait trait) const { return (traits & trait) ? true : false; }
|
||||
protected:
|
||||
asDWORD traits;
|
||||
};
|
||||
|
||||
struct asSObjectVariableInfo
|
||||
{
|
||||
asUINT programPos;
|
||||
int variableOffset;
|
||||
asEObjVarInfoOption option;
|
||||
};
|
||||
|
||||
struct asSTryCatchInfo
|
||||
{
|
||||
asUINT tryPos;
|
||||
asUINT catchPos;
|
||||
};
|
||||
|
||||
struct asSSystemFunctionInterface;
|
||||
|
||||
// TODO: Might be interesting to allow enumeration of accessed global variables, and
|
||||
// also functions/methods that are being called. This could be used to build a
|
||||
// code database with call graphs, etc.
|
||||
|
||||
void RegisterScriptFunction(asCScriptEngine *engine);
|
||||
|
||||
class asCScriptFunction : public asIScriptFunction
|
||||
{
|
||||
public:
|
||||
// From asIScriptFunction
|
||||
asIScriptEngine *GetEngine() const;
|
||||
|
||||
// Memory management
|
||||
int AddRef() const;
|
||||
int Release() const;
|
||||
|
||||
// Miscellaneous
|
||||
int GetId() const;
|
||||
asEFuncType GetFuncType() const;
|
||||
const char *GetModuleName() const;
|
||||
asIScriptModule *GetModule() const;
|
||||
const char *GetScriptSectionName() const;
|
||||
const char *GetConfigGroup() const;
|
||||
asDWORD GetAccessMask() const;
|
||||
void *GetAuxiliary() const;
|
||||
|
||||
// Function signature
|
||||
asITypeInfo *GetObjectType() const;
|
||||
const char *GetObjectName() const;
|
||||
const char *GetName() const;
|
||||
const char *GetNamespace() 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;
|
||||
bool IsExplicit() const;
|
||||
bool IsProperty() const;
|
||||
asUINT GetParamCount() const;
|
||||
int GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const;
|
||||
int GetReturnTypeId(asDWORD *flags = 0) const;
|
||||
|
||||
// Type id for function pointers
|
||||
int GetTypeId() const;
|
||||
bool IsCompatibleWithTypeId(int typeId) const;
|
||||
|
||||
// Delegates
|
||||
void *GetDelegateObject() const;
|
||||
asITypeInfo *GetDelegateObjectType() const;
|
||||
asIScriptFunction *GetDelegateFunction() const;
|
||||
|
||||
// Debug information
|
||||
asUINT GetVarCount() const;
|
||||
int GetVar(asUINT index, const char **name, int *typeId = 0) const;
|
||||
const char * GetVarDecl(asUINT index, bool includeNamespace = false) const;
|
||||
int FindNextLineWithCode(int line) const;
|
||||
|
||||
// For JIT compilation
|
||||
asDWORD *GetByteCode(asUINT *length = 0);
|
||||
|
||||
// User data
|
||||
void *SetUserData(void *userData, asPWORD type);
|
||||
void *GetUserData(asPWORD type) const;
|
||||
|
||||
public:
|
||||
//-----------------------------------
|
||||
// Internal methods
|
||||
|
||||
void SetShared(bool set) { traits.SetTrait(asTRAIT_SHARED, set); }
|
||||
void SetReadOnly(bool set) { traits.SetTrait(asTRAIT_CONST, set); }
|
||||
void SetFinal(bool set) { traits.SetTrait(asTRAIT_FINAL, set); }
|
||||
void SetOverride(bool set) { traits.SetTrait(asTRAIT_OVERRIDE, set); }
|
||||
void SetExplicit(bool set) { traits.SetTrait(asTRAIT_EXPLICIT, set); }
|
||||
void SetProtected(bool set) { traits.SetTrait(asTRAIT_PROTECTED, set); }
|
||||
void SetPrivate(bool set) { traits.SetTrait(asTRAIT_PRIVATE, set); }
|
||||
void SetProperty(bool set) { traits.SetTrait(asTRAIT_PROPERTY, set); }
|
||||
bool IsFactory() const;
|
||||
|
||||
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: operator==
|
||||
// TODO: 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: 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 AddVariable(asCString &name, asCDataType &type, int stackOffset);
|
||||
|
||||
int GetSpaceNeededForArguments();
|
||||
int GetSpaceNeededForReturnValue();
|
||||
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;
|
||||
bool IsSignatureExceptNameEqual(const asCScriptFunction *func) const;
|
||||
bool IsSignatureExceptNameEqual(const asCDataType &retType, const asCArray<asCDataType> ¶mTypes, const asCArray<asETypeModifiers> &inOutFlags, const asCObjectType *type, bool isReadOnly) const;
|
||||
bool IsSignatureExceptNameAndReturnTypeEqual(const asCScriptFunction *fun) const;
|
||||
bool IsSignatureExceptNameAndReturnTypeEqual(const asCArray<asCDataType> ¶mTypes, const asCArray<asETypeModifiers> &inOutFlags, const asCObjectType *type, bool isReadOnly) const;
|
||||
bool IsSignatureExceptNameAndObjectTypeEqual(const asCScriptFunction *func) const;
|
||||
|
||||
asCTypeInfo *GetTypeInfoOfLocalVar(short varOffset);
|
||||
|
||||
void MakeDelegate(asCScriptFunction *func, void *obj);
|
||||
|
||||
int RegisterListPattern(const char *decl, asCScriptNode *listPattern);
|
||||
int ParseListPattern(asSListPatternNode *&target, const char *decl, asCScriptNode *listPattern);
|
||||
|
||||
bool DoesReturnOnStack() const;
|
||||
|
||||
void JITCompile();
|
||||
|
||||
void AddReferences();
|
||||
void ReleaseReferences();
|
||||
|
||||
void AllocateScriptFunctionData();
|
||||
void DeallocateScriptFunctionData();
|
||||
|
||||
asCGlobalProperty *GetPropertyByGlobalVarPtr(void *gvarPtr);
|
||||
|
||||
// GC methods (for delegates)
|
||||
int GetRefCount();
|
||||
void SetFlag();
|
||||
bool GetFlag();
|
||||
void EnumReferences(asIScriptEngine *engine);
|
||||
void ReleaseAllHandles(asIScriptEngine *engine);
|
||||
|
||||
public:
|
||||
//-----------------------------------
|
||||
// Properties
|
||||
|
||||
mutable asCAtomic externalRefCount; // Used for external referneces
|
||||
asCAtomic internalRefCount; // Used for internal references
|
||||
mutable bool gcFlag;
|
||||
asCScriptEngine *engine;
|
||||
asCModule *module;
|
||||
|
||||
asCArray<asPWORD> userData;
|
||||
|
||||
// Function signature
|
||||
asCString name;
|
||||
asCDataType returnType;
|
||||
asCArray<asCDataType> parameterTypes;
|
||||
asCArray<asCString> parameterNames;
|
||||
asCArray<asETypeModifiers> inOutFlags;
|
||||
asCArray<asCString *> defaultArgs;
|
||||
asSFunctionTraits traits;
|
||||
asCObjectType *objectType;
|
||||
int signatureId;
|
||||
|
||||
int id;
|
||||
|
||||
asEFuncType funcType;
|
||||
asDWORD accessMask;
|
||||
|
||||
// Namespace will be null for funcdefs that are declared as child funcdefs
|
||||
// of a class. In this case the namespace shall be taken from the parentClass
|
||||
// in the funcdefType
|
||||
asSNameSpace *nameSpace;
|
||||
|
||||
asCFuncdefType *funcdefType; // Doesn't increase refCount
|
||||
|
||||
// Used by asFUNC_DELEGATE
|
||||
void *objForDelegate;
|
||||
asCScriptFunction *funcForDelegate;
|
||||
|
||||
// Used by list factory behaviour
|
||||
asSListPatternNode *listPattern;
|
||||
|
||||
// Used by asFUNC_SCRIPT
|
||||
struct ScriptFunctionData
|
||||
{
|
||||
// Bytecode for the script function
|
||||
asCArray<asDWORD> byteCode;
|
||||
|
||||
// The stack space needed for the local variables
|
||||
asDWORD variableSpace;
|
||||
|
||||
// These hold information on objects and function pointers, including temporary
|
||||
// variables used by exception handler and when saving bytecode
|
||||
asCArray<asCTypeInfo*> objVariableTypes;
|
||||
asCArray<int> objVariablePos; // offset on stackframe
|
||||
|
||||
// The first variables in above array are allocated on the heap, the rest on the stack.
|
||||
// This variable shows how many are on the heap.
|
||||
asUINT objVariablesOnHeap;
|
||||
|
||||
// Holds information on scope for object variables on the stack
|
||||
asCArray<asSObjectVariableInfo> objVariableInfo;
|
||||
|
||||
// Holds information on try/catch blocks for exception handling
|
||||
asCArray<asSTryCatchInfo> tryCatchInfo;
|
||||
|
||||
// The stack needed to execute the function
|
||||
int stackNeeded;
|
||||
|
||||
// JIT compiled code of this function
|
||||
asJITFunction jitFunction;
|
||||
|
||||
// Holds debug information on explicitly declared variables
|
||||
asCArray<asSScriptVariable*> variables;
|
||||
// Store position, line number pairs for debug information
|
||||
asCArray<int> lineNumbers;
|
||||
// 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;
|
||||
// Store position/index pairs if the bytecode is compiled from multiple script sections
|
||||
asCArray<int> sectionIdxs;
|
||||
};
|
||||
ScriptFunctionData *scriptData;
|
||||
|
||||
// Stub functions and delegates don't own the object and parameters
|
||||
bool dontCleanUpOnException;
|
||||
|
||||
// Used by asFUNC_VIRTUAL
|
||||
int vfTableIdx;
|
||||
|
||||
// Used by asFUNC_SYSTEM
|
||||
asSSystemFunctionInterface *sysFuncIntf;
|
||||
};
|
||||
|
||||
const char * const DELEGATE_FACTORY = "$dlgte";
|
||||
asCScriptFunction *CreateDelegate(asCScriptFunction *func, void *obj);
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_scriptnode.cpp
|
||||
//
|
||||
// A node in the script tree built by the parser for compilation
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include "as_scriptnode.h"
|
||||
#include "as_scriptengine.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asCScriptNode::asCScriptNode(eScriptNode type)
|
||||
{
|
||||
nodeType = type;
|
||||
tokenType = ttUnrecognizedToken;
|
||||
tokenPos = 0;
|
||||
tokenLength = 0;
|
||||
|
||||
parent = 0;
|
||||
next = 0;
|
||||
prev = 0;
|
||||
firstChild = 0;
|
||||
lastChild = 0;
|
||||
}
|
||||
|
||||
void asCScriptNode::Destroy(asCScriptEngine *engine)
|
||||
{
|
||||
// Destroy all children
|
||||
asCScriptNode *node = firstChild;
|
||||
asCScriptNode *nxt;
|
||||
|
||||
while( node )
|
||||
{
|
||||
nxt = node->next;
|
||||
node->Destroy(engine);
|
||||
node = nxt;
|
||||
}
|
||||
|
||||
// Return the memory to the memory manager
|
||||
engine->memoryMgr.FreeScriptNode(this);
|
||||
}
|
||||
|
||||
asCScriptNode *asCScriptNode::CreateCopy(asCScriptEngine *engine)
|
||||
{
|
||||
void *ptr = engine->memoryMgr.AllocScriptNode();
|
||||
if( ptr == 0 )
|
||||
{
|
||||
// Out of memory
|
||||
return 0;
|
||||
}
|
||||
|
||||
new(ptr) asCScriptNode(nodeType);
|
||||
|
||||
asCScriptNode *node = reinterpret_cast<asCScriptNode*>(ptr);
|
||||
node->tokenLength = tokenLength;
|
||||
node->tokenPos = tokenPos;
|
||||
node->tokenType = tokenType;
|
||||
|
||||
asCScriptNode *child = firstChild;
|
||||
while( child )
|
||||
{
|
||||
node->AddChildLast(child->CreateCopy(engine));
|
||||
child = child->next;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void asCScriptNode::SetToken(sToken *token)
|
||||
{
|
||||
tokenType = token->type;
|
||||
}
|
||||
|
||||
void asCScriptNode::UpdateSourcePos(size_t pos, size_t length)
|
||||
{
|
||||
if( pos == 0 && length == 0 ) return;
|
||||
|
||||
if( tokenPos == 0 && tokenLength == 0 )
|
||||
{
|
||||
tokenPos = pos;
|
||||
tokenLength = length;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( tokenPos > pos )
|
||||
{
|
||||
tokenLength = tokenPos + tokenLength - pos;
|
||||
tokenPos = pos;
|
||||
}
|
||||
|
||||
if( pos + length > tokenPos + tokenLength )
|
||||
{
|
||||
tokenLength = pos + length - tokenPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void asCScriptNode::AddChildLast(asCScriptNode *node)
|
||||
{
|
||||
// We might get a null pointer if the parser encounter an out-of-memory situation
|
||||
if( node == 0 ) return;
|
||||
|
||||
if( lastChild )
|
||||
{
|
||||
lastChild->next = node;
|
||||
node->next = 0;
|
||||
node->prev = lastChild;
|
||||
node->parent = this;
|
||||
lastChild = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
firstChild = node;
|
||||
lastChild = node;
|
||||
node->next = 0;
|
||||
node->prev = 0;
|
||||
node->parent = this;
|
||||
}
|
||||
|
||||
UpdateSourcePos(node->tokenPos, node->tokenLength);
|
||||
}
|
||||
|
||||
void asCScriptNode::DisconnectParent()
|
||||
{
|
||||
if( parent )
|
||||
{
|
||||
if( parent->firstChild == this )
|
||||
parent->firstChild = next;
|
||||
if( parent->lastChild == this )
|
||||
parent->lastChild = prev;
|
||||
}
|
||||
|
||||
if( next )
|
||||
next->prev = prev;
|
||||
|
||||
if( prev )
|
||||
prev->next = next;
|
||||
|
||||
parent = 0;
|
||||
next = 0;
|
||||
prev = 0;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2018 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_scriptnode.h
|
||||
//
|
||||
// A node in the script tree built by the parser for compilation
|
||||
//
|
||||
|
||||
|
||||
#ifndef AS_SCRIPTNODE_H
|
||||
#define AS_SCRIPTNODE_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_tokendef.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
enum eScriptNode
|
||||
{
|
||||
snUndefined,
|
||||
snScript,
|
||||
snFunction,
|
||||
snConstant,
|
||||
snDataType,
|
||||
snIdentifier,
|
||||
snParameterList,
|
||||
snStatementBlock,
|
||||
snDeclaration,
|
||||
snExpressionStatement,
|
||||
snIf,
|
||||
snFor,
|
||||
snWhile,
|
||||
snReturn,
|
||||
snExpression,
|
||||
snExprTerm,
|
||||
snFunctionCall,
|
||||
snConstructCall,
|
||||
snArgList,
|
||||
snExprPreOp,
|
||||
snExprPostOp,
|
||||
snExprOperator,
|
||||
snExprValue,
|
||||
snBreak,
|
||||
snContinue,
|
||||
snDoWhile,
|
||||
snAssignment,
|
||||
snCondition,
|
||||
snSwitch,
|
||||
snCase,
|
||||
snImport,
|
||||
snClass,
|
||||
snInitList,
|
||||
snInterface,
|
||||
snEnum,
|
||||
snTypedef,
|
||||
snCast,
|
||||
snVariableAccess,
|
||||
snFuncDef,
|
||||
snVirtualProperty,
|
||||
snNamespace,
|
||||
snMixin,
|
||||
snListPattern,
|
||||
snNamedArgument,
|
||||
snScope,
|
||||
snTryCatch
|
||||
};
|
||||
|
||||
struct sToken
|
||||
{
|
||||
eTokenType type;
|
||||
size_t pos;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
class asCScriptEngine;
|
||||
|
||||
class asCScriptNode
|
||||
{
|
||||
public:
|
||||
asCScriptNode(eScriptNode nodeType);
|
||||
|
||||
void Destroy(asCScriptEngine *engine);
|
||||
asCScriptNode *CreateCopy(asCScriptEngine *engine);
|
||||
|
||||
void SetToken(sToken *token);
|
||||
void AddChildLast(asCScriptNode *node);
|
||||
void DisconnectParent();
|
||||
|
||||
void UpdateSourcePos(size_t pos, size_t length);
|
||||
|
||||
eScriptNode nodeType;
|
||||
eTokenType tokenType;
|
||||
size_t tokenPos;
|
||||
size_t tokenLength;
|
||||
|
||||
asCScriptNode *parent;
|
||||
asCScriptNode *next;
|
||||
asCScriptNode *prev;
|
||||
asCScriptNode *firstChild;
|
||||
asCScriptNode *lastChild;
|
||||
|
||||
protected:
|
||||
// Must call Destroy instead
|
||||
~asCScriptNode() {}
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2019 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
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//
|
||||
// as_scriptobject.h
|
||||
//
|
||||
// A generic class for handling script declared structures
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_SCRIPTOBJECT_H
|
||||
#define AS_SCRIPTOBJECT_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_atomic.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCObjectType;
|
||||
|
||||
// TODO: Add const overload for GetAddressOfProperty
|
||||
|
||||
// TODO: weak: Should move to its own file
|
||||
class asCLockableSharedBool : public asILockableSharedBool
|
||||
{
|
||||
public:
|
||||
asCLockableSharedBool();
|
||||
int AddRef() const;
|
||||
int Release() const;
|
||||
|
||||
bool Get() const;
|
||||
void Set(bool);
|
||||
|
||||
void Lock() const;
|
||||
void Unlock() const;
|
||||
|
||||
protected:
|
||||
mutable asCAtomic refCount;
|
||||
bool value;
|
||||
DECLARECRITICALSECTION(mutable lock)
|
||||
};
|
||||
|
||||
class asCScriptObject : public asIScriptObject
|
||||
{
|
||||
public:
|
||||
//===================================
|
||||
// From asIScriptObject
|
||||
//===================================
|
||||
|
||||
// Memory management
|
||||
int AddRef() const;
|
||||
int Release() const;
|
||||
asILockableSharedBool *GetWeakRefFlag() const;
|
||||
|
||||
// Type info
|
||||
int GetTypeId() const;
|
||||
asITypeInfo *GetObjectType() const;
|
||||
|
||||
// Class properties
|
||||
asUINT GetPropertyCount() const;
|
||||
int GetPropertyTypeId(asUINT prop) const;
|
||||
const char *GetPropertyName(asUINT prop) const;
|
||||
void *GetAddressOfProperty(asUINT prop);
|
||||
|
||||
// Miscellaneous
|
||||
asIScriptEngine *GetEngine() const;
|
||||
int CopyFrom(const asIScriptObject *other);
|
||||
|
||||
// User data
|
||||
void *SetUserData(void *data, asPWORD type = 0);
|
||||
void *GetUserData(asPWORD type = 0) const;
|
||||
|
||||
//====================================
|
||||
// Internal
|
||||
//====================================
|
||||
asCScriptObject(asCObjectType *objType, bool doInitialize = true);
|
||||
virtual ~asCScriptObject();
|
||||
|
||||
asCScriptObject &operator=(const asCScriptObject &other);
|
||||
|
||||
// GC methods
|
||||
void Destruct();
|
||||
int GetRefCount();
|
||||
void SetFlag();
|
||||
bool GetFlag();
|
||||
void EnumReferences(asIScriptEngine *engine);
|
||||
void ReleaseAllHandles(asIScriptEngine *engine);
|
||||
|
||||
// Used for properties
|
||||
void *AllocateUninitializedObject(asCObjectType *objType, asCScriptEngine *engine);
|
||||
void FreeObject(void *ptr, asCObjectType *objType, asCScriptEngine *engine);
|
||||
void CopyObject(const void *src, void *dst, asCObjectType *objType, asCScriptEngine *engine);
|
||||
void CopyHandle(asPWORD *src, asPWORD *dst, asCObjectType *objType, asCScriptEngine *engine);
|
||||
int CopyFromAs(const asCScriptObject *other, asCObjectType *objType);
|
||||
|
||||
void CallDestructor();
|
||||
|
||||
//=============================================
|
||||
// Properties
|
||||
//=============================================
|
||||
protected:
|
||||
friend class asCContext;
|
||||
asCObjectType *objType;
|
||||
|
||||
mutable asCAtomic refCount;
|
||||
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);
|
||||
asCScriptObject &ScriptObject_Assignment(asCScriptObject *other, asCScriptObject *self);
|
||||
|
||||
void ScriptObject_ConstructUnitialized(asCObjectType *objType, asCScriptObject *self);
|
||||
|
||||
void RegisterScriptObject(asCScriptEngine *engine);
|
||||
|
||||
asIScriptObject *ScriptObjectFactory(const asCObjectType *objType, asCScriptEngine *engine);
|
||||
asIScriptObject *ScriptObjectCopyFactory(const asCObjectType *objType, void *origObj, asCScriptEngine *engine);
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2017 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 "as_config.h"
|
||||
|
||||
#include <stdarg.h> // va_list, va_start(), etc
|
||||
#include <stdlib.h> // strtod(), strtol()
|
||||
#include <string.h> // some compilers declare memcpy() here
|
||||
|
||||
#if !defined(AS_NO_MEMORY_H)
|
||||
#include <memory.h>
|
||||
#endif
|
||||
|
||||
#include "as_string.h"
|
||||
#include "as_string_util.h"
|
||||
|
||||
asCString::asCString()
|
||||
{
|
||||
length = 0;
|
||||
local[0] = 0;
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
asCString::asCString(const asCString &str)
|
||||
{
|
||||
length = 0;
|
||||
local[0] = 0;
|
||||
|
||||
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;
|
||||
local[0] = 0;
|
||||
|
||||
Assign(str, len);
|
||||
}
|
||||
|
||||
asCString::asCString(const char *str)
|
||||
{
|
||||
length = 0;
|
||||
local[0] = 0;
|
||||
|
||||
size_t len = strlen(str);
|
||||
Assign(str, len);
|
||||
}
|
||||
|
||||
asCString::asCString(char ch)
|
||||
{
|
||||
length = 0;
|
||||
local[0] = 0;
|
||||
|
||||
Assign(&ch, 1);
|
||||
}
|
||||
|
||||
asCString::~asCString()
|
||||
{
|
||||
if( length > 11 && dynamic )
|
||||
{
|
||||
asDELETEARRAY(dynamic);
|
||||
}
|
||||
}
|
||||
|
||||
char *asCString::AddressOf()
|
||||
{
|
||||
if( length <= 11 )
|
||||
return local;
|
||||
else
|
||||
return dynamic;
|
||||
}
|
||||
|
||||
const char *asCString::AddressOf() const
|
||||
{
|
||||
if( length <= 11 )
|
||||
return local;
|
||||
else
|
||||
return dynamic;
|
||||
}
|
||||
|
||||
void asCString::SetLength(size_t len)
|
||||
{
|
||||
Allocate(len, true);
|
||||
}
|
||||
|
||||
void asCString::Allocate(size_t len, bool keepData)
|
||||
{
|
||||
// If we stored the capacity of the dynamically allocated buffer it would be possible
|
||||
// to save some memory allocations if a string decreases in size then increases again,
|
||||
// but this would require extra bytes in the string object itself, or a decrease of
|
||||
// the static buffer, which in turn would mean extra memory is needed. I've tested each
|
||||
// of these options, and it turned out that the current choice is what best balanced
|
||||
// the number of allocations against the size of the allocations.
|
||||
|
||||
if( len > 11 && len > length )
|
||||
{
|
||||
// Allocate a new dynamic buffer if the new one is larger than the old
|
||||
char *buf = asNEWARRAY(char,len+1);
|
||||
if( buf == 0 )
|
||||
{
|
||||
// Out of memory. Return without modifying anything
|
||||
return;
|
||||
}
|
||||
|
||||
if( keepData )
|
||||
{
|
||||
int l = (int)len < (int)length ? (int)len : (int)length;
|
||||
memcpy(buf, AddressOf(), l);
|
||||
}
|
||||
|
||||
if( length > 11 )
|
||||
{
|
||||
asDELETEARRAY(dynamic);
|
||||
}
|
||||
|
||||
dynamic = buf;
|
||||
}
|
||||
else if( len <= 11 && length > 11 )
|
||||
{
|
||||
// Free the dynamic buffer, since it is no longer needed
|
||||
char *buf = dynamic;
|
||||
if( keepData )
|
||||
{
|
||||
memcpy(&local, buf, len);
|
||||
}
|
||||
asDELETEARRAY(buf);
|
||||
}
|
||||
|
||||
length = (int)len;
|
||||
|
||||
// Make sure the buffer is null terminated
|
||||
AddressOf()[length] = 0;
|
||||
}
|
||||
|
||||
void asCString::Assign(const char *str, size_t len)
|
||||
{
|
||||
Allocate(len, false);
|
||||
|
||||
// Copy the string
|
||||
memcpy(AddressOf(), str, length);
|
||||
AddressOf()[length] = 0;
|
||||
}
|
||||
|
||||
asCString &asCString::operator =(const char *str)
|
||||
{
|
||||
size_t len = str ? strlen(str) : 0;
|
||||
Assign(str, len);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
asCString &asCString::operator =(const asCString &str)
|
||||
{
|
||||
Assign(str.AddressOf(), str.length);
|
||||
|
||||
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);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void asCString::Concatenate(const char *str, size_t len)
|
||||
{
|
||||
asUINT oldLength = length;
|
||||
SetLength(length + len);
|
||||
|
||||
memcpy(AddressOf() + oldLength, str, len);
|
||||
AddressOf()[length] = 0;
|
||||
}
|
||||
|
||||
asCString &asCString::operator +=(const char *str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
Concatenate(str, len);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
asCString &asCString::operator +=(const asCString &str)
|
||||
{
|
||||
Concatenate(str.AddressOf(), str.length);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
asCString &asCString::operator +=(char ch)
|
||||
{
|
||||
Concatenate(&ch, 1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t asCString::GetLength() const
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
// Returns the length
|
||||
size_t asCString::Format(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
const size_t startSize = 1024;
|
||||
char tmp[startSize];
|
||||
int r = asVSNPRINTF(tmp, startSize-1, format, args);
|
||||
|
||||
if( r > 0 && r < int(startSize) )
|
||||
{
|
||||
Assign(tmp, r);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: For some reason this doesn't work properly on Linux. Perhaps the
|
||||
// problem is related to vsnprintf not keeping the state of va_arg.
|
||||
// Perhaps I need to rewrite this in some way to keep the state
|
||||
size_t n = startSize*2;
|
||||
asCString str; // Use temporary string in case the current buffer is a parameter
|
||||
str.Allocate(n, false);
|
||||
|
||||
while( (r = asVSNPRINTF(str.AddressOf(), n, format, args)) < 0 || r >= int(n) )
|
||||
{
|
||||
n *= 2;
|
||||
str.Allocate(n, false);
|
||||
}
|
||||
|
||||
Assign(str.AddressOf(), r);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
char &asCString::operator [](size_t index)
|
||||
{
|
||||
asASSERT(index < length);
|
||||
|
||||
return AddressOf()[index];
|
||||
}
|
||||
|
||||
const char &asCString::operator [](size_t index) const
|
||||
{
|
||||
asASSERT(index < length);
|
||||
|
||||
return AddressOf()[index];
|
||||
}
|
||||
|
||||
asCString asCString::SubString(size_t in_start, size_t in_length) const
|
||||
{
|
||||
if( in_start >= GetLength() || in_length == 0 )
|
||||
return asCString("");
|
||||
|
||||
if( in_length == (size_t)(-1) ) in_length = GetLength() - in_start;
|
||||
|
||||
asCString tmp;
|
||||
tmp.Assign(AddressOf() + in_start, in_length);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int asCString::Compare(const char *str) const
|
||||
{
|
||||
return asCompareStrings(AddressOf(), length, str, strlen(str));
|
||||
}
|
||||
|
||||
int asCString::Compare(const asCString &str) const
|
||||
{
|
||||
return asCompareStrings(AddressOf(), length, str.AddressOf(), str.GetLength());
|
||||
}
|
||||
|
||||
int asCString::Compare(const char *str, size_t len) const
|
||||
{
|
||||
return asCompareStrings(AddressOf(), length, str, len);
|
||||
}
|
||||
|
||||
size_t asCString::RecalculateLength()
|
||||
{
|
||||
SetLength(strlen(AddressOf()));
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int asCString::FindLast(const char *str, int *count) const
|
||||
{
|
||||
// There is no strstr that starts from the end, so
|
||||
// we'll iterate until we find the last occurrance.
|
||||
// This shouldn't cause a performance problem because
|
||||
// it is not expected that this will be done very often,
|
||||
// and then only on quite short strings anyway.
|
||||
|
||||
if( count ) *count = 0;
|
||||
|
||||
const char *last = 0;
|
||||
const char *curr = AddressOf()-1;
|
||||
while( (curr = strstr(curr+1, str)) != 0 )
|
||||
{
|
||||
if( count ) (*count)++;
|
||||
last = curr;
|
||||
}
|
||||
|
||||
if( last )
|
||||
return int(last - AddressOf());
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper functions
|
||||
|
||||
bool operator ==(const asCString &a, const char *b)
|
||||
{
|
||||
return a.Compare(b) == 0;
|
||||
}
|
||||
|
||||
bool operator !=(const asCString &a, const char *b)
|
||||
{
|
||||
return a.Compare(b) != 0;
|
||||
}
|
||||
|
||||
bool operator ==(const asCString &a, const asCString &b)
|
||||
{
|
||||
return a.Compare(b) == 0;
|
||||
}
|
||||
|
||||
bool operator !=(const asCString &a, const asCString &b)
|
||||
{
|
||||
return a.Compare(b) != 0;
|
||||
}
|
||||
|
||||
bool operator ==(const char *a, const asCString &b)
|
||||
{
|
||||
return b.Compare(a) == 0;
|
||||
}
|
||||
|
||||
bool operator !=(const char *a, const asCString &b)
|
||||
{
|
||||
return b.Compare(a) != 0;
|
||||
}
|
||||
|
||||
bool operator <(const asCString &a, const asCString &b)
|
||||
{
|
||||
return a.Compare(b) < 0;
|
||||
}
|
||||
|
||||
asCString operator +(const asCString &a, const asCString &b)
|
||||
{
|
||||
asCString res = a;
|
||||
res += b;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
asCString operator +(const char *a, const asCString &b)
|
||||
{
|
||||
asCString res = a;
|
||||
res += b;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
asCString operator +(const asCString &a, const char *b)
|
||||
{
|
||||
asCString res = a;
|
||||
res += b;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// wrapper class
|
||||
|
||||
asCStringPointer::asCStringPointer()
|
||||
: string(0), length(0), cstring(0)
|
||||
{
|
||||
}
|
||||
|
||||
asCStringPointer::asCStringPointer(const char *str, size_t len)
|
||||
: string(str), length(len), cstring(0)
|
||||
{
|
||||
}
|
||||
|
||||
asCStringPointer::asCStringPointer(asCString *cstr)
|
||||
: string(0), length(0), cstring(cstr)
|
||||
{
|
||||
}
|
||||
|
||||
const char *asCStringPointer::AddressOf() const
|
||||
{
|
||||
return string ? string : cstring->AddressOf();
|
||||
}
|
||||
|
||||
size_t asCStringPointer::GetLength() const
|
||||
{
|
||||
return string ? length : cstring->GetLength();
|
||||
}
|
||||
|
||||
bool asCStringPointer::operator==(const asCStringPointer& other) const
|
||||
{
|
||||
return asCompareStrings(AddressOf(), GetLength(), other.AddressOf(), other.GetLength()) == 0;
|
||||
}
|
||||
|
||||
bool asCStringPointer::operator<(const asCStringPointer& other) const
|
||||
{
|
||||
return asCompareStrings(AddressOf(), GetLength(), other.AddressOf(), other.GetLength()) < 0;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
// This class has been designed to be easy to use, but not necessarily efficiency.
|
||||
// It doesn't use shared string memory, or reference counting. It keeps track of
|
||||
// string length, memory size. It also makes sure that the string is null-terminated.
|
||||
|
||||
#ifndef AS_STRING_H
|
||||
#define AS_STRING_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
explicit asCString(char);
|
||||
|
||||
void Allocate(size_t len, bool keepData);
|
||||
void SetLength(size_t len);
|
||||
size_t GetLength() const;
|
||||
|
||||
void Concatenate(const char *str, size_t length);
|
||||
asCString &operator +=(const asCString &);
|
||||
asCString &operator +=(const char *);
|
||||
asCString &operator +=(char);
|
||||
|
||||
void Assign(const char *str, size_t length);
|
||||
asCString &operator =(const asCString &);
|
||||
asCString &operator =(const char *);
|
||||
asCString &operator =(char);
|
||||
|
||||
asCString SubString(size_t start, size_t length = (size_t)(-1)) const;
|
||||
|
||||
int FindLast(const char *str, int *count = 0) const;
|
||||
|
||||
size_t Format(const char *fmt, ...);
|
||||
|
||||
int Compare(const char *str) const;
|
||||
int Compare(const asCString &str) const;
|
||||
int Compare(const char *str, size_t length) const;
|
||||
|
||||
char *AddressOf();
|
||||
const char *AddressOf() const;
|
||||
char &operator [](size_t index);
|
||||
const char &operator[](size_t index) const;
|
||||
size_t RecalculateLength();
|
||||
|
||||
protected:
|
||||
unsigned int length;
|
||||
union
|
||||
{
|
||||
char *dynamic;
|
||||
char local[12];
|
||||
};
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
|
||||
bool operator ==(const asCString &, const asCString &);
|
||||
bool operator !=(const asCString &, const asCString &);
|
||||
|
||||
bool operator ==(const asCString &, const char *);
|
||||
bool operator !=(const asCString &, const char *);
|
||||
|
||||
bool operator ==(const char *, const asCString &);
|
||||
bool operator !=(const char *, const asCString &);
|
||||
|
||||
bool operator <(const asCString &, const asCString &);
|
||||
|
||||
asCString operator +(const asCString &, const char *);
|
||||
asCString operator +(const char *, const asCString &);
|
||||
asCString operator +(const asCString &, const asCString &);
|
||||
|
||||
// a wrapper for using the pointer of asCString in asCMap
|
||||
class asCStringPointer
|
||||
{
|
||||
public:
|
||||
asCStringPointer();
|
||||
asCStringPointer(const char *str, size_t len);
|
||||
asCStringPointer(asCString *cstr);
|
||||
|
||||
const char *AddressOf() const;
|
||||
size_t GetLength() const;
|
||||
|
||||
bool operator==(const asCStringPointer& other) const;
|
||||
bool operator<(const asCStringPointer& other) const;
|
||||
|
||||
private:
|
||||
// Either string/length or cstring is stored
|
||||
const char *string;
|
||||
size_t length;
|
||||
asCString *cstring;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2017 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 "as_config.h"
|
||||
|
||||
#include <string.h> // some compilers declare memcpy() here
|
||||
#include <math.h> // pow()
|
||||
|
||||
#if !defined(AS_NO_MEMORY_H)
|
||||
#include <memory.h>
|
||||
#endif
|
||||
|
||||
#include "as_string.h"
|
||||
#include "as_string_util.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
int asCompareStrings(const char *str1, size_t len1, const char *str2, size_t len2)
|
||||
{
|
||||
if( len1 == 0 )
|
||||
{
|
||||
if( str2 == 0 || len2 == 0 ) return 0; // Equal
|
||||
|
||||
return 1; // The other string is larger than this
|
||||
}
|
||||
|
||||
if( str2 == 0 )
|
||||
{
|
||||
if( len1 == 0 )
|
||||
return 0; // Equal
|
||||
|
||||
return -1; // The other string is smaller than this
|
||||
}
|
||||
|
||||
if( len2 < len1 )
|
||||
{
|
||||
int result = memcmp(str1, str2, len2);
|
||||
if( result == 0 ) return -1; // The other string is smaller than this
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int result = memcmp(str1, str2, len1);
|
||||
if( result == 0 && len1 < len2 ) return 1; // The other string is larger than this
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double asStringScanDouble(const char *string, size_t *numScanned)
|
||||
{
|
||||
// I decided to do my own implementation of strtod() because this function
|
||||
// doesn't seem to be present on all systems. iOS 5 for example doesn't appear
|
||||
// to include the function in the standard lib.
|
||||
|
||||
// Another reason is that the standard implementation of strtod() is dependent
|
||||
// on the locale on some systems, i.e. it may use comma instead of dot for
|
||||
// the decimal indicator. This can be avoided by forcing the locale to "C" with
|
||||
// setlocale(), but this is another thing that is highly platform dependent.
|
||||
|
||||
double value = 0;
|
||||
double fraction = 0.1;
|
||||
int exponent = 0;
|
||||
bool negativeExponent = false;
|
||||
int c = 0;
|
||||
|
||||
// The tokenizer separates the sign from the number in
|
||||
// two tokens so we'll never have a sign to parse here
|
||||
|
||||
// Parse the integer value
|
||||
for( ;; )
|
||||
{
|
||||
if( string[c] >= '0' && string[c] <= '9' )
|
||||
value = value*10 + double(string[c] - '0');
|
||||
else
|
||||
break;
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
if( string[c] == '.' )
|
||||
{
|
||||
c++;
|
||||
|
||||
// Parse the fraction
|
||||
for( ;; )
|
||||
{
|
||||
if( string[c] >= '0' && string[c] <= '9' )
|
||||
value += fraction * double(string[c] - '0');
|
||||
else
|
||||
break;
|
||||
|
||||
c++;
|
||||
fraction *= 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
if( string[c] == 'e' || string[c] == 'E' )
|
||||
{
|
||||
c++;
|
||||
|
||||
// Parse the sign of the exponent
|
||||
if( string[c] == '-' )
|
||||
{
|
||||
negativeExponent = true;
|
||||
c++;
|
||||
}
|
||||
else if( string[c] == '+' )
|
||||
c++;
|
||||
|
||||
// Parse the exponent value
|
||||
for( ;; )
|
||||
{
|
||||
if( string[c] >= '0' && string[c] <= '9' )
|
||||
exponent = exponent*10 + int(string[c] - '0');
|
||||
else
|
||||
break;
|
||||
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
if( exponent )
|
||||
{
|
||||
if( negativeExponent )
|
||||
exponent = -exponent;
|
||||
value *= pow(10.0, exponent);
|
||||
}
|
||||
|
||||
if( numScanned )
|
||||
*numScanned = c;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Converts a character to the decimal number based on the radix
|
||||
// Returns -1 if the character is not valid for the radix
|
||||
static int asCharToNbr(char ch, int radix)
|
||||
{
|
||||
if( ch >= '0' && ch <= '9' ) return ((ch -= '0') < radix ? ch : -1);
|
||||
if( ch >= 'A' && ch <= 'Z' ) return ((ch -= 'A'-10) < radix ? ch : -1);
|
||||
if( ch >= 'a' && ch <= 'z' ) return ((ch -= 'a'-10) < radix ? ch : -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If base is 0 the string should be prefixed by 0x, 0d, 0o, or 0b to allow the function to automatically determine the radix
|
||||
asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned, bool *overflow)
|
||||
{
|
||||
asASSERT(base == 10 || base == 16 || base == 0);
|
||||
|
||||
if (overflow)
|
||||
*overflow = false;
|
||||
|
||||
const char *end = string;
|
||||
|
||||
static const asQWORD QWORD_MAX = (~asQWORD(0));
|
||||
|
||||
asQWORD res = 0;
|
||||
if( base == 10 )
|
||||
{
|
||||
while( *end >= '0' && *end <= '9' )
|
||||
{
|
||||
if( overflow && ((res > QWORD_MAX / 10) || ((asUINT(*end - '0') > (QWORD_MAX - (QWORD_MAX / 10) * 10)) && res == QWORD_MAX / 10)) )
|
||||
*overflow = true;
|
||||
res *= 10;
|
||||
res += *end++ - '0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( base == 0 && string[0] == '0')
|
||||
{
|
||||
// Determine the radix from the prefix
|
||||
switch( string[1] )
|
||||
{
|
||||
case 'b': case 'B': base = 2; break;
|
||||
case 'o': case 'O': base = 8; break;
|
||||
case 'd': case 'D': base = 10; break;
|
||||
case 'x': case 'X': base = 16; break;
|
||||
}
|
||||
end += 2;
|
||||
}
|
||||
|
||||
asASSERT( base );
|
||||
|
||||
if( base )
|
||||
{
|
||||
for (int nbr; (nbr = asCharToNbr(*end, base)) >= 0; end++)
|
||||
{
|
||||
if (overflow && ((res > QWORD_MAX / base) || ((asUINT(nbr) > (QWORD_MAX - (QWORD_MAX / base) * base)) && res == QWORD_MAX / base)) )
|
||||
*overflow = true;
|
||||
|
||||
res = res * base + nbr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( numScanned )
|
||||
*numScanned = end - string;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
// The function will encode the unicode code point into the outEncodedBuffer, and then
|
||||
// return the length of the encoded value. If the input value is not a valid unicode code
|
||||
// point, then the function will return -1.
|
||||
//
|
||||
// This function is taken from the AngelCode ToolBox.
|
||||
//
|
||||
int asStringEncodeUTF8(unsigned int value, char *outEncodedBuffer)
|
||||
{
|
||||
unsigned char *buf = (unsigned char*)outEncodedBuffer;
|
||||
|
||||
int length = -1;
|
||||
|
||||
if( value <= 0x7F )
|
||||
{
|
||||
buf[0] = static_cast<unsigned char>(value);
|
||||
return 1;
|
||||
}
|
||||
else if( value >= 0x80 && value <= 0x7FF )
|
||||
{
|
||||
// Encode it with 2 characters
|
||||
buf[0] = static_cast<unsigned char>(0xC0 + (value >> 6));
|
||||
length = 2;
|
||||
}
|
||||
else if( (value >= 0x800 && value <= 0xD7FF) || (value >= 0xE000 && value <= 0xFFFF) )
|
||||
{
|
||||
// Note: Values 0xD800 to 0xDFFF are not valid unicode characters
|
||||
buf[0] = static_cast<unsigned char>(0xE0 + (value >> 12));
|
||||
length = 3;
|
||||
}
|
||||
else if( value >= 0x10000 && value <= 0x10FFFF )
|
||||
{
|
||||
buf[0] = static_cast<unsigned char>(0xF0 + (value >> 18));
|
||||
length = 4;
|
||||
}
|
||||
|
||||
int n = length-1;
|
||||
for( ; n > 0; n-- )
|
||||
{
|
||||
buf[n] = static_cast<unsigned char>(0x80 + (value & 0x3F));
|
||||
value >>= 6;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
//
|
||||
// The function will decode an UTF8 character and return the unicode code point.
|
||||
// outLength will receive the number of bytes that were decoded.
|
||||
//
|
||||
// This function is taken from the AngelCode ToolBox.
|
||||
//
|
||||
int asStringDecodeUTF8(const char *encodedBuffer, unsigned int *outLength)
|
||||
{
|
||||
const unsigned char *buf = (const unsigned char*)encodedBuffer;
|
||||
|
||||
int value = 0;
|
||||
int length = -1;
|
||||
unsigned char byte = buf[0];
|
||||
if( (byte & 0x80) == 0 )
|
||||
{
|
||||
// This is the only byte
|
||||
if( outLength ) *outLength = 1;
|
||||
return byte;
|
||||
}
|
||||
else if( (byte & 0xE0) == 0xC0 )
|
||||
{
|
||||
// There is one more byte
|
||||
value = int(byte & 0x1F);
|
||||
length = 2;
|
||||
|
||||
// The value at this moment must not be less than 2, because
|
||||
// that should have been encoded with one byte only.
|
||||
if( value < 2 )
|
||||
length = -1;
|
||||
}
|
||||
else if( (byte & 0xF0) == 0xE0 )
|
||||
{
|
||||
// There are two more bytes
|
||||
value = int(byte & 0x0F);
|
||||
length = 3;
|
||||
}
|
||||
else if( (byte & 0xF8) == 0xF0 )
|
||||
{
|
||||
// There are three more bytes
|
||||
value = int(byte & 0x07);
|
||||
length = 4;
|
||||
}
|
||||
|
||||
int n = 1;
|
||||
for( ; n < length; n++ )
|
||||
{
|
||||
byte = buf[n];
|
||||
if( (byte & 0xC0) == 0x80 )
|
||||
value = (value << 6) + int(byte & 0x3F);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if( n == length )
|
||||
{
|
||||
if( outLength ) *outLength = (unsigned)length;
|
||||
return value;
|
||||
}
|
||||
|
||||
// The byte sequence isn't a valid UTF-8 byte sequence.
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// The function will encode the unicode code point into the outEncodedBuffer, and then
|
||||
// return the length of the encoded value. If the input value is not a valid unicode code
|
||||
// point, then the function will return -1.
|
||||
//
|
||||
// This function is taken from the AngelCode ToolBox.
|
||||
//
|
||||
int asStringEncodeUTF16(unsigned int value, char *outEncodedBuffer)
|
||||
{
|
||||
if( value < 0x10000 )
|
||||
{
|
||||
#ifndef AS_BIG_ENDIAN
|
||||
outEncodedBuffer[0] = (value & 0xFF);
|
||||
outEncodedBuffer[1] = ((value >> 8) & 0xFF);
|
||||
#else
|
||||
outEncodedBuffer[1] = (value & 0xFF);
|
||||
outEncodedBuffer[0] = ((value >> 8) & 0xFF);
|
||||
#endif
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
value -= 0x10000;
|
||||
int surrogate1 = ((value >> 10) & 0x3FF) + 0xD800;
|
||||
int surrogate2 = (value & 0x3FF) + 0xDC00;
|
||||
|
||||
#ifndef AS_BIG_ENDIAN
|
||||
outEncodedBuffer[0] = (surrogate1 & 0xFF);
|
||||
outEncodedBuffer[1] = ((surrogate1 >> 8) & 0xFF);
|
||||
outEncodedBuffer[2] = (surrogate2 & 0xFF);
|
||||
outEncodedBuffer[3] = ((surrogate2 >> 8) & 0xFF);
|
||||
#else
|
||||
outEncodedBuffer[1] = (surrogate1 & 0xFF);
|
||||
outEncodedBuffer[0] = ((surrogate1 >> 8) & 0xFF);
|
||||
outEncodedBuffer[3] = (surrogate2 & 0xFF);
|
||||
outEncodedBuffer[2] = ((surrogate2 >> 8) & 0xFF);
|
||||
#endif
|
||||
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
END_AS_NAMESPACE
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2016 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
|
||||
*/
|
||||
|
||||
|
||||
#ifndef AS_STRING_UTIL_H
|
||||
#define AS_STRING_UTIL_H
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
int asCompareStrings(const char *str1, size_t len1, const char *str2, size_t len2);
|
||||
|
||||
double asStringScanDouble(const char *string, size_t *numScanned);
|
||||
asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned, bool *overflow);
|
||||
|
||||
int asStringEncodeUTF8(unsigned int value, char *outEncodedBuffer);
|
||||
int asStringDecodeUTF8(const char *encodedBuffer, unsigned int *outLength);
|
||||
|
||||
int asStringEncodeUTF16(unsigned int value, char *outEncodedBuffer);
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,567 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2012-2021 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_symboltable.h
|
||||
//
|
||||
// Created on: Jun 19, 2012
|
||||
// Author: Markus Lenger, a.k.a. mlengerx
|
||||
//
|
||||
// This class is used for fast symbol lookups while parsing or loading bytecode
|
||||
//
|
||||
|
||||
#ifndef AS_SYMBOLTABLE_H
|
||||
#define AS_SYMBOLTABLE_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_memory.h"
|
||||
#include "as_string.h"
|
||||
#include "as_map.h"
|
||||
#include "as_datatype.h"
|
||||
#include "as_namespace.h"
|
||||
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Interface to avoid nested templates which is not well supported by older compilers, e.g. MSVC6
|
||||
struct asIFilter
|
||||
{
|
||||
virtual bool operator()(const void*) const = 0;
|
||||
virtual ~asIFilter() {};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// forward declaration
|
||||
template<class T>
|
||||
class asCSymbolTable;
|
||||
|
||||
|
||||
|
||||
|
||||
// Iterator that allows iterating in index order
|
||||
template<class T, class T2 = T>
|
||||
class asCSymbolTableIterator
|
||||
{
|
||||
public:
|
||||
T2* operator*() const;
|
||||
T2* operator->() const;
|
||||
asCSymbolTableIterator<T, T2>& operator++(int);
|
||||
asCSymbolTableIterator<T, T2>& operator--(int);
|
||||
operator bool() const;
|
||||
int GetIndex() const { return m_idx; }
|
||||
|
||||
private:
|
||||
friend class asCSymbolTable<T>;
|
||||
asCSymbolTableIterator(asCSymbolTable<T> *table);
|
||||
|
||||
void Next();
|
||||
void Previous();
|
||||
|
||||
asCSymbolTable<T>* m_table;
|
||||
unsigned int m_idx;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Symbol table mapping namespace + name to symbols
|
||||
// The structure keeps the entries indexed in an array so the indices will not change
|
||||
// There is also a map for a quick lookup. The map supports multiple entries with the same name
|
||||
template<class T>
|
||||
class asCSymbolTable
|
||||
{
|
||||
public:
|
||||
typedef asCSymbolTableIterator<T, T> iterator;
|
||||
typedef asCSymbolTableIterator<T, const T> const_iterator;
|
||||
|
||||
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;
|
||||
int GetLastIndex() const;
|
||||
|
||||
int GetIndex(const T*) const;
|
||||
|
||||
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(asUINT index);
|
||||
const T* Get(asUINT index) const;
|
||||
T* GetLast();
|
||||
const T* GetLast() const;
|
||||
|
||||
const asCArray<asUINT> &GetIndexes(const asSNameSpace *ns, const asCString &name) const;
|
||||
|
||||
asUINT Put(T* entry);
|
||||
|
||||
asUINT GetSize() const;
|
||||
|
||||
void SwapWith(asCSymbolTable<T> &other);
|
||||
|
||||
void Clear();
|
||||
bool Erase(asUINT idx);
|
||||
void Allocate(asUINT elem_cnt, bool keep_data);
|
||||
|
||||
iterator List();
|
||||
const_iterator List() const;
|
||||
|
||||
private:
|
||||
// Don't allow assignment
|
||||
asCSymbolTable<T>& operator=(const asCSymbolTable<T> &other) { return *this; }
|
||||
|
||||
friend class asCSymbolTableIterator<T, T>;
|
||||
friend class asCSymbolTableIterator<T, const T>;
|
||||
|
||||
void GetKey(const T *entry, asSNameSpaceNamePair &key) const;
|
||||
bool CheckIdx(asUINT idx) const;
|
||||
|
||||
asCMap<asSNameSpaceNamePair, asCArray<asUINT> > m_map;
|
||||
asCArray<T*> m_entries;
|
||||
unsigned int m_size;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
void asCSymbolTable<T>::SwapWith(asCSymbolTable<T> &other)
|
||||
{
|
||||
m_map.SwapWith(other.m_map);
|
||||
m_entries.SwapWith(other.m_entries);
|
||||
|
||||
asUINT tmp = m_size;
|
||||
m_size = other.m_size;
|
||||
other.m_size = tmp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Constructor
|
||||
// initialCapacity gives the number of entries to allocate in advance
|
||||
template<class T>
|
||||
asCSymbolTable<T>::asCSymbolTable(asUINT initialCapacity) : m_entries(initialCapacity)
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
int asCSymbolTable<T>::GetFirstIndex(
|
||||
const asSNameSpace *ns,
|
||||
const asCString &name,
|
||||
const asIFilter &filter) const
|
||||
{
|
||||
asSNameSpaceNamePair key(ns, name);
|
||||
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
|
||||
if( m_map.MoveTo(&cursor, key) )
|
||||
{
|
||||
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) )
|
||||
return arr[n];
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
const asCArray<asUINT> &asCSymbolTable<T>::GetIndexes(const asSNameSpace *ns, const asCString &name) const
|
||||
{
|
||||
asSNameSpaceNamePair key(ns, name);
|
||||
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
|
||||
if( m_map.MoveTo(&cursor, key) )
|
||||
return m_map.GetValue(cursor);
|
||||
|
||||
static asCArray<asUINT> dummy;
|
||||
return dummy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
T* asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comp) const
|
||||
{
|
||||
int idx = GetFirstIndex(ns, name, comp);
|
||||
if (idx != -1) return m_entries[idx];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
int asCSymbolTable<T>::GetFirstIndex(const asSNameSpace *ns, const asCString &name) const
|
||||
{
|
||||
asSNameSpaceNamePair key(ns, name);
|
||||
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
|
||||
if( m_map.MoveTo(&cursor, key) )
|
||||
return m_map.GetValue(cursor)[0];
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Find the index of a certain symbol
|
||||
// ATTENTION: this function has linear runtime complexity O(n)!!
|
||||
template<class T>
|
||||
int asCSymbolTable<T>::GetIndex(const T* entry) const
|
||||
{
|
||||
for( asUINT n = 0; n < m_entries.GetLength(); n++ )
|
||||
if( m_entries[n] == entry )
|
||||
return n;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
T* asCSymbolTable<T>::Get(asUINT idx)
|
||||
{
|
||||
if( !CheckIdx(idx) )
|
||||
return 0;
|
||||
|
||||
return m_entries[idx];
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const T* asCSymbolTable<T>::Get(asUINT idx) const
|
||||
{
|
||||
return const_cast< asCSymbolTable<T>* >(this)->Get(idx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
T* asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name)
|
||||
{
|
||||
int idx = GetFirstIndex(ns, name);
|
||||
return Get(idx);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const T* asCSymbolTable<T>::GetFirst(const asSNameSpace *ns, const asCString &name) const
|
||||
{
|
||||
return const_cast< asCSymbolTable<T>* >(this)->GetFirst(ns, name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
T* asCSymbolTable<T>::GetLast()
|
||||
{
|
||||
return Get(GetLastIndex());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const T* asCSymbolTable<T>::GetLast() const
|
||||
{
|
||||
return const_cast< asCSymbolTable<T>* >(this)->GetLast();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Clear the symbol table
|
||||
// ATTENTION: The contained symbols are not rleased. This is up to the client
|
||||
template<class T>
|
||||
void asCSymbolTable<T>::Clear()
|
||||
{
|
||||
m_entries.SetLength(0);
|
||||
m_map.EraseAll();
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Pre-allocate slots for elemCnt entries
|
||||
template<class T>
|
||||
void asCSymbolTable<T>::Allocate(asUINT elemCnt, bool keepData)
|
||||
{
|
||||
asASSERT( elemCnt >= m_entries.GetLength() );
|
||||
m_entries.Allocate(elemCnt, keepData);
|
||||
if( !keepData )
|
||||
m_map.EraseAll();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
bool asCSymbolTable<T>::Erase(asUINT idx)
|
||||
{
|
||||
if( !CheckIdx(idx) )
|
||||
{
|
||||
asASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
T *entry = m_entries[idx];
|
||||
asASSERT(entry);
|
||||
if( !entry )
|
||||
return false;
|
||||
|
||||
// Remove the symbol from the lookup map
|
||||
asSNameSpaceNamePair key;
|
||||
GetKey(entry, key);
|
||||
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
|
||||
if( m_map.MoveTo(&cursor, key) )
|
||||
{
|
||||
asCArray<asUINT> &arr = m_map.GetValue(cursor);
|
||||
arr.RemoveValue(idx);
|
||||
if( arr.GetLength() == 0 )
|
||||
m_map.Erase(cursor);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
asUINT asCSymbolTable<T>::Put(T *entry)
|
||||
{
|
||||
asUINT idx = m_entries.GetLength();
|
||||
asSNameSpaceNamePair key;
|
||||
GetKey(entry, key);
|
||||
|
||||
asSMapNode<asSNameSpaceNamePair, asCArray<asUINT> > *cursor;
|
||||
if( m_map.MoveTo(&cursor, key) )
|
||||
m_map.GetValue(cursor).PushLast(idx);
|
||||
else
|
||||
{
|
||||
asCArray<asUINT> arr(1);
|
||||
arr.PushLast(idx);
|
||||
m_map.Insert(key, arr);
|
||||
}
|
||||
|
||||
m_entries.PushLast(entry);
|
||||
m_size++;
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Return key for specified symbol (namespace and name are used to generate the key)
|
||||
template<class T>
|
||||
void asCSymbolTable<T>::GetKey(const T *entry, asSNameSpaceNamePair &key) const
|
||||
{
|
||||
key = asSNameSpaceNamePair(entry->nameSpace, entry->name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
asUINT asCSymbolTable<T>::GetSize() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
bool asCSymbolTable<T>::CheckIdx(asUINT idx) const
|
||||
{
|
||||
return idx < m_entries.GetLength();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
int asCSymbolTable<T>::GetLastIndex() const
|
||||
{
|
||||
int idx = int(m_entries.GetLength()) - 1;
|
||||
asASSERT( idx == -1 || m_entries[idx] );
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
asCSymbolTableIterator<T, T> asCSymbolTable<T>::List()
|
||||
{
|
||||
return asCSymbolTableIterator<T, T>(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
typename asCSymbolTable<T>::const_iterator asCSymbolTable<T>::List() const
|
||||
{
|
||||
return asCSymbolTableIterator<T, const T>(const_cast< asCSymbolTable<T> *>(this));
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Iterator
|
||||
|
||||
|
||||
template<class T, class T2>
|
||||
asCSymbolTableIterator<T, T2>::asCSymbolTableIterator(asCSymbolTable<T> *table) : m_table(table), m_idx(0)
|
||||
{
|
||||
asUINT sz = m_table->m_entries.GetLength();
|
||||
while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
|
||||
m_idx++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T, class T2>
|
||||
T2* asCSymbolTableIterator<T, T2>::operator*() const
|
||||
{
|
||||
asASSERT(m_table->CheckIdx(m_idx));
|
||||
return m_table->m_entries[m_idx];
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T, class T2>
|
||||
T2* asCSymbolTableIterator<T, T2>::operator->() const
|
||||
{
|
||||
asASSERT(m_table->CheckIdx(m_idx));
|
||||
return m_table->m_entries[m_idx];
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T, class T2>
|
||||
asCSymbolTableIterator<T, T2>& asCSymbolTableIterator<T, T2>::operator++(int)
|
||||
{
|
||||
Next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Return true if more elements are following
|
||||
// ATTENTION: When deleting the object currently pointed to by this iterator this
|
||||
// method returns false even though there might be more elements in the list
|
||||
template<class T, class T2>
|
||||
asCSymbolTableIterator<T, T2>::operator bool() const
|
||||
{
|
||||
return m_idx < m_table->m_entries.GetLength() && m_table->m_entries[m_idx] != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T, class T2>
|
||||
void asCSymbolTableIterator<T, T2>::Next()
|
||||
{
|
||||
asUINT sz = m_table->m_entries.GetLength();
|
||||
m_idx++;
|
||||
while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
|
||||
m_idx++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T, class T2>
|
||||
void asCSymbolTableIterator<T, T2>::Previous()
|
||||
{
|
||||
// overflow on stepping over first element
|
||||
asUINT sz = m_table->m_entries.GetLength();
|
||||
m_idx--;
|
||||
while( m_idx < sz && m_table->m_entries[m_idx] == 0 )
|
||||
m_idx--;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T, class T2>
|
||||
asCSymbolTableIterator<T, T2>& asCSymbolTableIterator<T, T2>::operator--(int)
|
||||
{
|
||||
Previous();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_SYMBOLTABLE_H
|
||||
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2021 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_texts.h
|
||||
//
|
||||
// These are text strings used through out the library
|
||||
//
|
||||
|
||||
|
||||
#ifndef AS_TEXTS_H
|
||||
#define AS_TEXTS_H
|
||||
|
||||
// Compiler messages
|
||||
|
||||
#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 "Can't find unambiguous implicit conversion to make both expressions 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_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_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_ACCESS_NON_STATIC_MEMBER_s "Cannot access non-static member '%s' like this"
|
||||
#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_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX "Implemented property accessor '%s' does not expect index argument"
|
||||
#define TXT_PROP_ACCESS_s_EXPECTS_INDEX "Implemented property accessor '%s' expects index argument"
|
||||
|
||||
#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_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_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_EXPR_s_IS_DATA_TYPE "Expression '%s' is a data type"
|
||||
#define TXT_EXTERNAL_SHARED_s_NOT_FOUND "External shared entity '%s' not found"
|
||||
#define TXT_EXTERNAL_SHARED_s_CANNOT_REDEF "External shared entity '%s' cannot redefine the original entity"
|
||||
|
||||
#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"
|
||||
#define TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC "Float value truncated in implicit conversion to integer"
|
||||
#define TXT_FOUND_MULTIPLE_ENUM_VALUES "Found multiple matching enum values"
|
||||
#define TXT_FUNCTION_ALREADY_EXIST "A function with the same name and parameters already exists"
|
||||
#define TXT_FUNCTION_s_NOT_FOUND "Function '%s' not found"
|
||||
|
||||
#define TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s "The property '%s' has mismatching types for the get and set accessors"
|
||||
#define TXT_GLOBAL_VARS_NOT_ALLOWED "Global variables have been disabled by the application"
|
||||
|
||||
#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_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_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_INSTEAD_FOUND_IDENTIFIER_s "Instead found identifier '%s'"
|
||||
#define TXT_INSTEAD_FOUND_KEYWORD_s "Instead found reserved keyword '%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_EXPRESSION_AMBIGUOUS_NAME "Invalid expression: ambiguous name"
|
||||
#define TXT_INVALID_EXPRESSION_LAMBDA "Invalid expression: stand-alone anonymous function"
|
||||
#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_SIG_FOR_VIRTPROP "Invalid signature for virtual property"
|
||||
#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_USE_OF_NAMED_ARGS "Invalid use of named arguments"
|
||||
|
||||
#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_METHOD_s_NOT_PART_OF_OBJECT_s "Method '%s' is not part of object '%s'"
|
||||
#define TXT_MISSING_IMPLEMENTATION_OF_s "Missing implementation of '%s'"
|
||||
#define TXT_MISSING_DEFINITION_OF_s "Missing definition 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"
|
||||
#define TXT_MIXIN_CLASS_CANNOT_INHERIT "Mixin class cannot inherit from classes"
|
||||
#define TXT_MIXIN_CANNOT_HAVE_CHILD_TYPES "Mixin classes cannot have child types"
|
||||
#define TXT_MORE_THAN_ONE_MATCHING_OP "Found more than one matching operator"
|
||||
#define TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s "Multiple matching signatures to '%s'"
|
||||
#define TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s "Found multiple get accessors for property '%s'"
|
||||
#define TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s "Found multiple set accessors for property '%s'"
|
||||
#define TXT_MULTILINE_STRINGS_NOT_ALLOWED "Multiline strings are not allowed in this application"
|
||||
#define TXT_MUST_BE_OBJECT "Only objects have constructors"
|
||||
#define TXT_MUST_RETURN_VALUE "Must return a value"
|
||||
|
||||
#define TXT_NAMESPACE_s_DOESNT_EXIST "Namespace '%s' doesn't exist."
|
||||
#define TXT_NAME_CONFLICT_s_EXTENDED_TYPE "Name conflict. '%s' is an extended data type."
|
||||
#define TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY "Name conflict. '%s' is a global property."
|
||||
#define TXT_NAME_CONFLICT_s_IS_NAMED_TYPE "Name conflict. '%s' is a named type."
|
||||
#define TXT_NAME_CONFLICT_s_IS_FUNCDEF "Name conflict. '%s' is a funcdef."
|
||||
#define TXT_NAME_CONFLICT_s_IS_FUNCTION "Name conflict. '%s' is a global function."
|
||||
#define TXT_NAME_CONFLICT_s_IS_MIXIN "Name conflict. '%s' is a mixin class."
|
||||
#define TXT_NAME_CONFLICT_s_IS_VIRTPROP "Name conflict. '%s' is a virtual property."
|
||||
#define TXT_NAME_CONFLICT_s_STRUCT "Name conflict. '%s' is a class."
|
||||
#define TXT_NAME_CONFLICT_s_INTF "Name conflict. '%s' is an interface."
|
||||
#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_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 "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"
|
||||
#define TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s "No matching operator that takes the types '%s' and '%s' found"
|
||||
#define TXT_NO_MATCHING_SYMBOL_s "No matching symbol '%s'"
|
||||
#define TXT_NON_CONST_METHOD_ON_CONST_OBJ "Non-const method call on read-only object reference"
|
||||
#define TXT_NONTERMINATED_STRING "Non-terminated string literal"
|
||||
#define TXT_NOT_A_FUNC_s_IS_TYPE_s "Expression doesn't form a function call. '%s' evaluates to the non-function type '%s'"
|
||||
#define TXT_NOT_ALL_PATHS_RETURN "Not all paths return a value"
|
||||
#define TXT_NOT_ENOUGH_VALUES_FOR_LIST "Not enough values to match pattern"
|
||||
#define TXT_s_NOT_DECLARED "'%s' is not declared"
|
||||
#define TXT_NOT_EXACT "Implicit conversion of value is not exact"
|
||||
#define TXT_s_NOT_INITIALIZED "'%s' is not initialized."
|
||||
#define TXT_NOT_LVALUE "Expression is not an l-value"
|
||||
#define TXT_s_NOT_MEMBER_OF_s "'%s' is not a member of '%s'"
|
||||
#define TXT_NOT_VALID_REFERENCE "Not a valid reference"
|
||||
#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_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 instantiated."
|
||||
#define TXT_POS_ARG_AFTER_NAMED_ARG "Positional arguments cannot be passed after named arguments"
|
||||
#define TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s "Previous error occurred while attempting to compile initialization list for type '%s'"
|
||||
#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_PROP_ACCESS_WITH_INDEX_ONE_ARG "Property accessor with index must have 1 and only 1 index argument"
|
||||
#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"
|
||||
#define TXT_PROPERTY_HAS_NO_GET_ACCESSOR "The property has no get accessor"
|
||||
#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"
|
||||
#define TXT_REF_IS_TEMP "Reference is temporary"
|
||||
#define TXT_REF_TYPE_CANT_BE_PASSED_BY_VAL "Reference types cannot be passed by value in function parameters"
|
||||
#define TXT_REF_TYPE_CANT_BE_RETURNED_BY_VAL "Reference types cannot be returned by value from functions"
|
||||
#define TXT_RETURN_CANT_BE_s "Return type can't be '%s'"
|
||||
|
||||
#define TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s "Shared code cannot access non-shared global variable '%s'"
|
||||
#define TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s "Shared code cannot call non-shared function '%s'"
|
||||
#define TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s "Shared type cannot implement non-shared interface '%s'"
|
||||
#define TXT_SHARED_CANNOT_INHERIT_FROM_NON_SHARED_s "Shared class cannot inherit from non-shared class '%s'"
|
||||
#define TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s "Shared code cannot use non-shared type '%s'"
|
||||
#define TXT_SHARED_s_DOESNT_MATCH_ORIGINAL "Shared type '%s' doesn't match the original declaration in other module"
|
||||
#define TXT_SECTION_IS_EMPTY "The script section is empty"
|
||||
#define TXT_SIGNED_UNSIGNED_MISMATCH "Signed/Unsigned mismatch"
|
||||
#define TXT_STRINGS_NOT_RECOGNIZED "Strings are not recognized by the application"
|
||||
#define TXT_SWITCH_CASE_MUST_BE_CONSTANT "Case expressions must be constants"
|
||||
#define TXT_SWITCH_MUST_BE_INTEGRAL "Switch expressions must be integral numbers"
|
||||
|
||||
#define TXT_TMPL_s_EXPECTS_d_SUBTYPES "Template '%s' expects %d sub type(s)"
|
||||
#define TXT_TMPL_SUBTYPE_MUST_NOT_BE_READ_ONLY "Template subtype must not be read-only"
|
||||
#define TXT_TOO_MANY_JUMP_LABELS "The function has too many jump labels to handle. Split the function into smaller ones."
|
||||
#define TXT_TOO_MANY_VALUES_FOR_LIST "Too many values to match pattern"
|
||||
#define TXT_TYPE_s_CANNOT_BE_REFERENCE "Type '%s' cannot be a reference"
|
||||
#define TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE "Type '%s' is not available for this module"
|
||||
#define TXT_TYPE_s_NOT_TEMPLATE "Type '%s' is not a template type"
|
||||
|
||||
#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_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"
|
||||
|
||||
#define TXT_WARNINGS_TREATED_AS_ERROR "Warnings are treated as errors by the application"
|
||||
#define TXT_WHERE_s_IS_s "Where '%s' is '%s'"
|
||||
#define TXT_WHILE_PARSING_ARG_LIST "While parsing argument list"
|
||||
#define TXT_WHILE_PARSING_EXPRESSION "While parsing expression"
|
||||
#define TXT_WHILE_PARSING_INIT_LIST "While parsing initialization list"
|
||||
#define TXT_WHILE_PARSING_NAMESPACE "While parsing namespace"
|
||||
#define TXT_WHILE_PARSING_STATEMENT_BLOCK "While parsing statement block"
|
||||
#define TXT_WHILE_INCLUDING_MIXIN "Previous error occurred while including mixin"
|
||||
|
||||
// Global variable initialization
|
||||
|
||||
#define TXT_FAILED_TO_INITIALIZE_s "Failed to initialize global variable '%s'"
|
||||
#define TXT_EXCEPTION_s_IN_s "Exception '%s' in '%s'"
|
||||
|
||||
// Engine message
|
||||
|
||||
#define TXT_AUTOHANDLE_CANNOT_BE_USED_FOR_NOCOUNT "Autohandles cannot be used with types that have been registered with NOCOUNT"
|
||||
#define TXT_FIRST_PARAM_MUST_BE_REF_FOR_TEMPLATE_FACTORY "First parameter to template factory must be a reference. This will be used to pass the object type of the template"
|
||||
#define TXT_INVALID_CONFIGURATION "Invalid configuration. Verify the registered application interface."
|
||||
#define TXT_VALUE_TYPE_MUST_HAVE_SIZE "A value type must be registered with a non-zero size"
|
||||
#define TXT_TYPE_s_IS_MISSING_BEHAVIOURS "Type '%s' is missing behaviours"
|
||||
#define TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE "The behaviour is not compatible with the type"
|
||||
#define TXT_GC_REQUIRE_ADD_REL_GC_BEHAVIOUR "A garbage collected ref type must have the addref, release, and all gc behaviours"
|
||||
#define TXT_VALUE_GC_REQUIRE_GC_BEHAVIOUR "A garbage collected value type must have the gc enum references behaviour"
|
||||
#define TXT_SCOPE_REQUIRE_REL_BEHAVIOUR "A scoped reference type must have the release behaviour"
|
||||
#define TXT_REF_REQUIRE_ADD_REL_BEHAVIOUR "A reference type must have the addref and release behaviours"
|
||||
#define TXT_NON_POD_REQUIRE_CONSTR_DESTR_BEHAVIOUR "A non-pod value type must have at least one constructor and the destructor behaviours"
|
||||
#define TXT_CANNOT_PASS_TYPE_s_BY_VAL "Can't pass type '%s' by value unless the application type is informed in the registration"
|
||||
#define TXT_CANNOT_RET_TYPE_s_BY_VAL "Can't return type '%s' by value unless the application type is informed in the registration"
|
||||
// TODO: Should be something like "This platform requires that AngelScript knows the exact content of the type '%s' in order to pass by value to application in native calling convention"
|
||||
#define TXT_DONT_SUPPORT_TYPE_s_BY_VAL "Don't support passing type '%s' by value to application in native calling convention on this platform"
|
||||
// TODO: Should be something like "This platform requires that AngelScript knows the exact content of the type '%s' in order to return by value from application in native calling convention"
|
||||
#define TXT_DONT_SUPPORT_RET_TYPE_s_BY_VAL "Don't support returning type '%s' by value from application in native calling convention on this platform"
|
||||
#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_FAILED_IN_FUNC_s_s_d "Failed in call to function '%s' (Code: %s, %d)"
|
||||
#define TXT_FAILED_IN_FUNC_s_WITH_s_s_d "Failed in call to function '%s' with '%s' (Code: %s, %d)"
|
||||
#define TXT_FAILED_IN_FUNC_s_WITH_s_AND_s_s_d "Failed in call to function '%s' with '%s' and '%s' (Code: %s, %d)"
|
||||
#define TXT_GC_RECEIVED_NULL_PTR "AddScriptObjectToGC called with null pointer"
|
||||
#define TXT_EXCEPTION_IN_NESTED_CALL "An exception occurred in a nested call"
|
||||
#define TXT_TYPE_s_IS_STILL_USED_BY_FUNC_s "Type '%s' is still used by function '%s'"
|
||||
#define TXT_PREV_TYPE_IS_NAMED_s "The builtin type in previous message is named '%s'"
|
||||
#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
|
||||
|
||||
#define TXT_PROPERTY "Property"
|
||||
#define TXT_SYSTEM_FUNCTION "System function"
|
||||
#define TXT_VARIABLE_DECL "Variable declaration"
|
||||
|
||||
// Exceptions
|
||||
|
||||
#define TXT_STACK_OVERFLOW "Stack overflow"
|
||||
#define TXT_NULL_POINTER_ACCESS "Null pointer access"
|
||||
#define TXT_DIVIDE_BY_ZERO "Divide by zero"
|
||||
#define TXT_DIVIDE_OVERFLOW "Overflow in integer division"
|
||||
#define TXT_POW_OVERFLOW "Overflow in exponent operation"
|
||||
#define TXT_UNRECOGNIZED_BYTE_CODE "Unrecognized byte code"
|
||||
#define TXT_INVALID_CALLING_CONVENTION "Invalid calling convention"
|
||||
#define TXT_UNBOUND_FUNCTION "Unbound function called"
|
||||
#define TXT_OUT_OF_BOUNDS "Out of range"
|
||||
#define TXT_EXCEPTION_CAUGHT "Caught an exception from the application"
|
||||
#define TXT_MISMATCH_IN_VALUE_ASSIGN "Mismatching types in value assignment"
|
||||
#define TXT_TOO_MANY_NESTED_CALLS "Too many nested calls"
|
||||
|
||||
// Error codes
|
||||
#define ERROR_NAME(x) #x
|
||||
static const char*const errorNames[] =
|
||||
{
|
||||
ERROR_NAME(asSUCCESS),
|
||||
ERROR_NAME(asERROR),
|
||||
ERROR_NAME(asCONTEXT_ACTIVE),
|
||||
ERROR_NAME(asCONTEXT_NOT_FINISHED),
|
||||
ERROR_NAME(asCONTEXT_NOT_PREPARED),
|
||||
ERROR_NAME(asINVALID_ARG),
|
||||
ERROR_NAME(asNO_FUNCTION),
|
||||
ERROR_NAME(asNOT_SUPPORTED),
|
||||
ERROR_NAME(asINVALID_NAME),
|
||||
ERROR_NAME(asNAME_TAKEN),
|
||||
ERROR_NAME(asINVALID_DECLARATION),
|
||||
ERROR_NAME(asINVALID_OBJECT),
|
||||
ERROR_NAME(asINVALID_TYPE),
|
||||
ERROR_NAME(asALREADY_REGISTERED),
|
||||
ERROR_NAME(asMULTIPLE_FUNCTIONS),
|
||||
ERROR_NAME(asNO_MODULE),
|
||||
ERROR_NAME(asNO_GLOBAL_VAR),
|
||||
ERROR_NAME(asINVALID_CONFIGURATION),
|
||||
ERROR_NAME(asINVALID_INTERFACE),
|
||||
ERROR_NAME(asCANT_BIND_ALL_FUNCTIONS),
|
||||
ERROR_NAME(asLOWER_ARRAY_DIMENSION_NOT_REGISTERED),
|
||||
ERROR_NAME(asWRONG_CONFIG_GROUP),
|
||||
ERROR_NAME(asCONFIG_GROUP_IS_IN_USE),
|
||||
ERROR_NAME(asILLEGAL_BEHAVIOUR_FOR_TYPE),
|
||||
ERROR_NAME(asWRONG_CALLING_CONV),
|
||||
ERROR_NAME(asBUILD_IN_PROGRESS),
|
||||
ERROR_NAME(asINIT_GLOBAL_VARS_FAILED),
|
||||
ERROR_NAME(asOUT_OF_MEMORY),
|
||||
ERROR_NAME(asMODULE_IS_IN_USE)
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,468 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//
|
||||
// as_thread.cpp
|
||||
//
|
||||
// Functions for multi threading support
|
||||
//
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_thread.h"
|
||||
#include "as_atomic.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
//=======================================================================
|
||||
|
||||
// Singleton
|
||||
static asCThreadManager *threadManager = 0;
|
||||
|
||||
//======================================================================
|
||||
|
||||
// Global API functions
|
||||
extern "C"
|
||||
{
|
||||
|
||||
AS_API int asThreadCleanup()
|
||||
{
|
||||
return asCThreadManager::CleanupLocalData();
|
||||
}
|
||||
|
||||
AS_API asIThreadManager *asGetThreadManager()
|
||||
{
|
||||
return threadManager;
|
||||
}
|
||||
|
||||
AS_API int asPrepareMultithread(asIThreadManager *externalThreadMgr)
|
||||
{
|
||||
return asCThreadManager::Prepare(externalThreadMgr);
|
||||
}
|
||||
|
||||
AS_API void asUnprepareMultithread()
|
||||
{
|
||||
asCThreadManager::Unprepare();
|
||||
}
|
||||
|
||||
AS_API void asAcquireExclusiveLock()
|
||||
{
|
||||
if( threadManager )
|
||||
{
|
||||
ACQUIREEXCLUSIVE(threadManager->appRWLock);
|
||||
}
|
||||
}
|
||||
|
||||
AS_API void asReleaseExclusiveLock()
|
||||
{
|
||||
if( threadManager )
|
||||
{
|
||||
RELEASEEXCLUSIVE(threadManager->appRWLock);
|
||||
}
|
||||
}
|
||||
|
||||
AS_API void asAcquireSharedLock()
|
||||
{
|
||||
if( threadManager )
|
||||
{
|
||||
ACQUIRESHARED(threadManager->appRWLock);
|
||||
}
|
||||
}
|
||||
|
||||
AS_API void asReleaseSharedLock()
|
||||
{
|
||||
if( threadManager )
|
||||
{
|
||||
RELEASESHARED(threadManager->appRWLock);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
#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
|
||||
|
||||
asCThreadManager::asCThreadManager()
|
||||
{
|
||||
// We're already in the critical section when this function is called
|
||||
|
||||
#ifdef AS_NO_THREADS
|
||||
tld = 0;
|
||||
#else
|
||||
// Allocate the thread local storage
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_key_t pKey;
|
||||
pthread_key_create(&pKey, 0);
|
||||
tlsKey = (asDWORD)pKey;
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
tld = 0;
|
||||
#else
|
||||
tlsKey = (asDWORD)TlsAlloc();
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
refCount = 1;
|
||||
}
|
||||
|
||||
int asCThreadManager::Prepare(asIThreadManager *externalThreadMgr)
|
||||
{
|
||||
// Don't allow an external thread manager if there
|
||||
// is already a thread manager defined
|
||||
if( externalThreadMgr && threadManager )
|
||||
return asINVALID_ARG;
|
||||
|
||||
// The critical section cannot be declared globally, as there is no
|
||||
// guarantee for the order in which global variables are initialized
|
||||
// or uninitialized.
|
||||
|
||||
// For this reason it's not possible to prevent two threads from calling
|
||||
// AddRef at the same time, so there is a chance for a race condition here.
|
||||
|
||||
// To avoid the race condition when the thread manager is first created,
|
||||
// the application must make sure to call the global asPrepareForMultiThread()
|
||||
// in the main thread before any other thread creates a script engine.
|
||||
if( threadManager == 0 && externalThreadMgr == 0 )
|
||||
threadManager = asNEW(asCThreadManager);
|
||||
else
|
||||
{
|
||||
// If an application uses different dlls each dll will get it's own memory
|
||||
// space for global variables. If multiple dlls then uses AngelScript's
|
||||
// global thread support functions it is then best to share the thread
|
||||
// manager to make sure all dlls use the same critical section.
|
||||
if( externalThreadMgr )
|
||||
threadManager = reinterpret_cast<asCThreadManager*>(externalThreadMgr);
|
||||
|
||||
ENTERCRITICALSECTION(threadManager->criticalSection);
|
||||
threadManager->refCount++;
|
||||
LEAVECRITICALSECTION(threadManager->criticalSection);
|
||||
}
|
||||
|
||||
// Success
|
||||
return 0;
|
||||
}
|
||||
|
||||
void asCThreadManager::Unprepare()
|
||||
{
|
||||
asASSERT(threadManager);
|
||||
|
||||
if( threadManager == 0 )
|
||||
return;
|
||||
|
||||
// It's necessary to protect this section so no
|
||||
// other thread attempts to call AddRef or Release
|
||||
// while clean up is in progress.
|
||||
ENTERCRITICALSECTION(threadManager->criticalSection);
|
||||
if( --threadManager->refCount == 0 )
|
||||
{
|
||||
// Make sure the local data is destroyed, at least for the current thread
|
||||
CleanupLocalData();
|
||||
|
||||
// As the critical section will be destroyed together
|
||||
// with the thread manager we must first clear the global
|
||||
// variable in case a new thread manager needs to be created;
|
||||
asCThreadManager *mgr = threadManager;
|
||||
threadManager = 0;
|
||||
|
||||
// Leave the critical section before it is destroyed
|
||||
LEAVECRITICALSECTION(mgr->criticalSection);
|
||||
|
||||
asDELETE(mgr,asCThreadManager);
|
||||
}
|
||||
else
|
||||
LEAVECRITICALSECTION(threadManager->criticalSection);
|
||||
}
|
||||
|
||||
asCThreadManager::~asCThreadManager()
|
||||
{
|
||||
#ifndef AS_NO_THREADS
|
||||
// Deallocate the thread local storage
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_key_delete((pthread_key_t)tlsKey);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
tld = 0;
|
||||
#else
|
||||
TlsFree((DWORD)tlsKey);
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
if( tld )
|
||||
{
|
||||
asDELETE(tld,asCThreadLocalData);
|
||||
}
|
||||
tld = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int asCThreadManager::CleanupLocalData()
|
||||
{
|
||||
if( threadManager == 0 )
|
||||
return 0;
|
||||
|
||||
#ifndef AS_NO_THREADS
|
||||
#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_FAMILY_PHONE_APP)
|
||||
asCThreadLocalData *tld = (asCThreadLocalData*)TlsGetValue((DWORD)threadManager->tlsKey);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if( tld == 0 )
|
||||
return 0;
|
||||
|
||||
if( tld->activeContexts.GetLength() == 0 )
|
||||
{
|
||||
asDELETE(tld,asCThreadLocalData);
|
||||
#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_FAMILY_PHONE_APP)
|
||||
tld = 0;
|
||||
#else
|
||||
TlsSetValue((DWORD)threadManager->tlsKey, 0);
|
||||
#endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return asCONTEXT_ACTIVE;
|
||||
|
||||
#else
|
||||
if( threadManager->tld )
|
||||
{
|
||||
if( threadManager->tld->activeContexts.GetLength() == 0 )
|
||||
{
|
||||
asDELETE(threadManager->tld,asCThreadLocalData);
|
||||
threadManager->tld = 0;
|
||||
}
|
||||
else
|
||||
return asCONTEXT_ACTIVE;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
asCThreadLocalData *asCThreadManager::GetLocalData()
|
||||
{
|
||||
if( threadManager == 0 )
|
||||
return 0;
|
||||
|
||||
#ifndef AS_NO_THREADS
|
||||
#if defined AS_POSIX_THREADS
|
||||
asCThreadLocalData *tld = (asCThreadLocalData*)pthread_getspecific((pthread_key_t)threadManager->tlsKey);
|
||||
if( tld == 0 )
|
||||
{
|
||||
tld = asNEW(asCThreadLocalData)();
|
||||
pthread_setspecific((pthread_key_t)threadManager->tlsKey, tld);
|
||||
}
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
if( tld == 0 )
|
||||
tld = asNEW(asCThreadLocalData)();
|
||||
#else
|
||||
asCThreadLocalData *tld = (asCThreadLocalData*)TlsGetValue((DWORD)threadManager->tlsKey);
|
||||
if( tld == 0 )
|
||||
{
|
||||
tld = asNEW(asCThreadLocalData)();
|
||||
TlsSetValue((DWORD)threadManager->tlsKey, tld);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return tld;
|
||||
#else
|
||||
if( threadManager->tld == 0 )
|
||||
threadManager->tld = asNEW(asCThreadLocalData)();
|
||||
|
||||
return threadManager->tld;
|
||||
#endif
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
|
||||
asCThreadLocalData::asCThreadLocalData()
|
||||
{
|
||||
}
|
||||
|
||||
asCThreadLocalData::~asCThreadLocalData()
|
||||
{
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
|
||||
#ifndef AS_NO_THREADS
|
||||
asCThreadCriticalSection::asCThreadCriticalSection()
|
||||
{
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_mutex_init(&cs, 0);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP)
|
||||
// Only the Ex version is available on Windows Store
|
||||
InitializeCriticalSectionEx(&cs, 4000, 0);
|
||||
#else
|
||||
// Only the non-Ex version is available on WinXP and older
|
||||
// MinGW also only defines this version
|
||||
InitializeCriticalSection(&cs);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
asCThreadCriticalSection::~asCThreadCriticalSection()
|
||||
{
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_mutex_destroy(&cs);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
DeleteCriticalSection(&cs);
|
||||
#endif
|
||||
}
|
||||
|
||||
void asCThreadCriticalSection::Enter()
|
||||
{
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_mutex_lock(&cs);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
EnterCriticalSection(&cs);
|
||||
#endif
|
||||
}
|
||||
|
||||
void asCThreadCriticalSection::Leave()
|
||||
{
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_mutex_unlock(&cs);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
LeaveCriticalSection(&cs);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool asCThreadCriticalSection::TryEnter()
|
||||
{
|
||||
#if defined AS_POSIX_THREADS
|
||||
return !pthread_mutex_trylock(&cs);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
return TryEnterCriticalSection(&cs) ? true : false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
asCThreadReadWriteLock::asCThreadReadWriteLock()
|
||||
{
|
||||
#if defined AS_POSIX_THREADS
|
||||
int r = pthread_rwlock_init(&lock, 0);
|
||||
asASSERT( r == 0 );
|
||||
UNUSED_VAR(r);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
#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
|
||||
InitializeCriticalSectionEx(&writeLock, 4000, 0);
|
||||
#else
|
||||
readLocks = CreateSemaphoreW(NULL, maxReaders, maxReaders, 0);
|
||||
InitializeCriticalSection(&writeLock);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
asCThreadReadWriteLock::~asCThreadReadWriteLock()
|
||||
{
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_rwlock_destroy(&lock);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
DeleteCriticalSection(&writeLock);
|
||||
CloseHandle(readLocks);
|
||||
#endif
|
||||
}
|
||||
|
||||
void asCThreadReadWriteLock::AcquireExclusive()
|
||||
{
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_rwlock_wrlock(&lock);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
// Synchronize writers, so only one tries to lock out the readers
|
||||
EnterCriticalSection(&writeLock);
|
||||
|
||||
// Lock all reader out from the semaphore. Do this one by one,
|
||||
// so the lock doesn't have to wait until there are no readers at all.
|
||||
// If we try to lock all at once it is quite possible the writer will
|
||||
// never succeed.
|
||||
for( asUINT n = 0; n < maxReaders; n++ )
|
||||
WaitForSingleObjectEx(readLocks, INFINITE, FALSE);
|
||||
|
||||
// Allow another writer to lock. It will only be able to
|
||||
// lock the readers when this writer releases them anyway.
|
||||
LeaveCriticalSection(&writeLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void asCThreadReadWriteLock::ReleaseExclusive()
|
||||
{
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_rwlock_unlock(&lock);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
// Release all readers at once
|
||||
ReleaseSemaphore(readLocks, maxReaders, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void asCThreadReadWriteLock::AcquireShared()
|
||||
{
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_rwlock_rdlock(&lock);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
// Lock a reader slot
|
||||
WaitForSingleObjectEx(readLocks, INFINITE, FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void asCThreadReadWriteLock::ReleaseShared()
|
||||
{
|
||||
#if defined AS_POSIX_THREADS
|
||||
pthread_rwlock_unlock(&lock);
|
||||
#elif defined AS_WINDOWS_THREADS
|
||||
// Release the reader slot
|
||||
ReleaseSemaphore(readLocks, 1, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//========================================================================
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2017 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
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//
|
||||
// as_thread.h
|
||||
//
|
||||
// Classes for multi threading support
|
||||
//
|
||||
|
||||
#ifndef AS_THREAD_H
|
||||
#define AS_THREAD_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_string.h"
|
||||
#include "as_array.h"
|
||||
#include "as_map.h"
|
||||
#include "as_criticalsection.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCThreadLocalData;
|
||||
|
||||
class asCThreadManager : public asIThreadManager
|
||||
{
|
||||
public:
|
||||
static asCThreadLocalData *GetLocalData();
|
||||
static int CleanupLocalData();
|
||||
|
||||
static int Prepare(asIThreadManager *externalThreadMgr);
|
||||
static void Unprepare();
|
||||
|
||||
// This read/write lock can be used by the application to provide simple synchronization
|
||||
DECLAREREADWRITELOCK(appRWLock)
|
||||
|
||||
protected:
|
||||
asCThreadManager();
|
||||
~asCThreadManager();
|
||||
|
||||
// No need to use the atomic int here, as it will only be
|
||||
// updated within the thread manager's critical section
|
||||
int refCount;
|
||||
|
||||
#ifndef AS_NO_THREADS
|
||||
#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.
|
||||
// ref: http://msdn.microsoft.com/en-us/library/2s9wt68x.aspx
|
||||
// ref: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx
|
||||
__declspec(thread) static asCThreadLocalData *tld;
|
||||
#else
|
||||
asDWORD tlsKey;
|
||||
#endif
|
||||
DECLARECRITICALSECTION(criticalSection)
|
||||
#else
|
||||
asCThreadLocalData *tld;
|
||||
#endif
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
|
||||
class asIScriptContext;
|
||||
|
||||
class asCThreadLocalData
|
||||
{
|
||||
public:
|
||||
asCArray<asIScriptContext *> activeContexts;
|
||||
asCString string;
|
||||
|
||||
protected:
|
||||
friend class asCThreadManager;
|
||||
|
||||
asCThreadLocalData();
|
||||
~asCThreadLocalData();
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2019 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_tokendef.h
|
||||
//
|
||||
// Definitions for tokens identifiable by the tokenizer
|
||||
//
|
||||
|
||||
|
||||
#ifndef AS_TOKENDEF_H
|
||||
#define AS_TOKENDEF_H
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
enum eTokenType
|
||||
{
|
||||
ttUnrecognizedToken,
|
||||
|
||||
ttEnd, // End of file
|
||||
|
||||
// White space and comments
|
||||
ttWhiteSpace, // ' ', '\t', '\r', '\n', UTF8 byte-order-mark
|
||||
ttOnelineComment, // // \n
|
||||
ttMultilineComment, // /* */
|
||||
|
||||
// Atoms
|
||||
ttIdentifier, // abc123
|
||||
ttIntConstant, // 1234
|
||||
ttFloatConstant, // 12.34e56f
|
||||
ttDoubleConstant, // 12.34e56
|
||||
ttStringConstant, // "123"
|
||||
ttMultilineStringConstant, //
|
||||
ttHeredocStringConstant, // """text"""
|
||||
ttNonTerminatedStringConstant, // "123
|
||||
ttBitsConstant, // 0xFFFF
|
||||
|
||||
// Math operators
|
||||
ttPlus, // +
|
||||
ttMinus, // -
|
||||
ttStar, // *
|
||||
ttSlash, // /
|
||||
ttPercent, // %
|
||||
ttStarStar, // **
|
||||
|
||||
ttHandle, // @
|
||||
|
||||
ttAddAssign, // +=
|
||||
ttSubAssign, // -=
|
||||
ttMulAssign, // *=
|
||||
ttDivAssign, // /=
|
||||
ttModAssign, // %=
|
||||
ttPowAssign, // **=
|
||||
|
||||
ttOrAssign, // |=
|
||||
ttAndAssign, // &=
|
||||
ttXorAssign, // ^=
|
||||
ttShiftLeftAssign, // <<=
|
||||
ttShiftRightLAssign, // >>=
|
||||
ttShiftRightAAssign, // >>>=
|
||||
|
||||
ttInc, // ++
|
||||
ttDec, // --
|
||||
|
||||
ttDot, // .
|
||||
ttScope, // ::
|
||||
|
||||
// Statement tokens
|
||||
ttAssignment, // =
|
||||
ttEndStatement, // ;
|
||||
ttListSeparator, // ,
|
||||
ttStartStatementBlock, // {
|
||||
ttEndStatementBlock, // }
|
||||
ttOpenParanthesis, // (
|
||||
ttCloseParanthesis, // )
|
||||
ttOpenBracket, // [
|
||||
ttCloseBracket, // ]
|
||||
ttAmp, // &
|
||||
|
||||
// Bitwise operators
|
||||
ttBitOr, // |
|
||||
ttBitNot, // ~
|
||||
ttBitXor, // ^
|
||||
ttBitShiftLeft, // <<
|
||||
ttBitShiftRight, // >> // TODO: In Java this is the arithmetical shift
|
||||
ttBitShiftRightArith, // >>> // TODO: In Java this is the logical shift
|
||||
|
||||
// Compare operators
|
||||
ttEqual, // ==
|
||||
ttNotEqual, // !=
|
||||
ttLessThan, // <
|
||||
ttGreaterThan, // >
|
||||
ttLessThanOrEqual, // <=
|
||||
ttGreaterThanOrEqual, // >=
|
||||
|
||||
ttQuestion, // ?
|
||||
ttColon, // :
|
||||
|
||||
// Reserved keywords
|
||||
ttIf, // if
|
||||
ttElse, // else
|
||||
ttFor, // for
|
||||
ttWhile, // while
|
||||
ttBool, // bool
|
||||
ttFuncDef, // funcdef
|
||||
ttImport, // import
|
||||
ttInt, // int
|
||||
ttInt8, // int8
|
||||
ttInt16, // int16
|
||||
ttInt64, // int64
|
||||
ttInterface, // interface
|
||||
ttIs, // is
|
||||
ttNotIs, // !is
|
||||
ttUInt, // uint
|
||||
ttUInt8, // uint8
|
||||
ttUInt16, // uint16
|
||||
ttUInt64, // uint64
|
||||
ttFloat, // float
|
||||
ttVoid, // void
|
||||
ttTrue, // true
|
||||
ttFalse, // false
|
||||
ttReturn, // return
|
||||
ttNot, // not
|
||||
ttAnd, // and, &&
|
||||
ttOr, // or, ||
|
||||
ttXor, // xor, ^^
|
||||
ttBreak, // break
|
||||
ttContinue, // continue
|
||||
ttConst, // const
|
||||
ttDo, // do
|
||||
ttDouble, // double
|
||||
ttSwitch, // switch
|
||||
ttCase, // case
|
||||
ttDefault, // default
|
||||
ttIn, // in
|
||||
ttOut, // out
|
||||
ttInOut, // inout
|
||||
ttNull, // null
|
||||
ttClass, // class
|
||||
ttTypedef, // typedef
|
||||
ttEnum, // enum
|
||||
ttCast, // cast
|
||||
ttPrivate, // private
|
||||
ttProtected, // protected
|
||||
ttNamespace, // namespace
|
||||
ttMixin, // mixin
|
||||
ttAuto, // auto
|
||||
ttTry, // try
|
||||
ttCatch // catch
|
||||
};
|
||||
|
||||
struct sTokenWord
|
||||
{
|
||||
const char *word;
|
||||
size_t wordLength;
|
||||
eTokenType tokenType;
|
||||
};
|
||||
|
||||
#define asTokenDef(str, tok) {str, sizeof(str)-1, tok}
|
||||
|
||||
sTokenWord const tokenWords[] =
|
||||
{
|
||||
asTokenDef("+" , ttPlus),
|
||||
asTokenDef("+=" , ttAddAssign),
|
||||
asTokenDef("++" , ttInc),
|
||||
asTokenDef("-" , ttMinus),
|
||||
asTokenDef("-=" , ttSubAssign),
|
||||
asTokenDef("--" , ttDec),
|
||||
asTokenDef("*" , ttStar),
|
||||
asTokenDef("*=" , ttMulAssign),
|
||||
asTokenDef("/" , ttSlash),
|
||||
asTokenDef("/=" , ttDivAssign),
|
||||
asTokenDef("%" , ttPercent),
|
||||
asTokenDef("%=" , ttModAssign),
|
||||
asTokenDef("**" , ttStarStar),
|
||||
asTokenDef("**=" , ttPowAssign),
|
||||
asTokenDef("=" , ttAssignment),
|
||||
asTokenDef("==" , ttEqual),
|
||||
asTokenDef("." , ttDot),
|
||||
asTokenDef("|" , ttBitOr),
|
||||
asTokenDef("|=" , ttOrAssign),
|
||||
asTokenDef("||" , ttOr),
|
||||
asTokenDef("&" , ttAmp),
|
||||
asTokenDef("&=" , ttAndAssign),
|
||||
asTokenDef("&&" , ttAnd),
|
||||
asTokenDef("^" , ttBitXor),
|
||||
asTokenDef("^=" , ttXorAssign),
|
||||
asTokenDef("^^" , ttXor),
|
||||
asTokenDef("<" , ttLessThan),
|
||||
asTokenDef("<=" , ttLessThanOrEqual),
|
||||
asTokenDef("<<" , ttBitShiftLeft),
|
||||
asTokenDef("<<=" , ttShiftLeftAssign),
|
||||
asTokenDef(">" , ttGreaterThan),
|
||||
asTokenDef(">=" , ttGreaterThanOrEqual),
|
||||
asTokenDef(">>" , ttBitShiftRight),
|
||||
asTokenDef(">>=" , ttShiftRightLAssign),
|
||||
asTokenDef(">>>" , ttBitShiftRightArith),
|
||||
asTokenDef(">>>=" , ttShiftRightAAssign),
|
||||
asTokenDef("~" , ttBitNot),
|
||||
asTokenDef(";" , ttEndStatement),
|
||||
asTokenDef("," , ttListSeparator),
|
||||
asTokenDef("{" , ttStartStatementBlock),
|
||||
asTokenDef("}" , ttEndStatementBlock),
|
||||
asTokenDef("(" , ttOpenParanthesis),
|
||||
asTokenDef(")" , ttCloseParanthesis),
|
||||
asTokenDef("[" , ttOpenBracket),
|
||||
asTokenDef("]" , ttCloseBracket),
|
||||
asTokenDef("?" , ttQuestion),
|
||||
asTokenDef(":" , ttColon),
|
||||
asTokenDef("::" , ttScope),
|
||||
asTokenDef("!" , ttNot),
|
||||
asTokenDef("!=" , ttNotEqual),
|
||||
asTokenDef("!is" , ttNotIs),
|
||||
asTokenDef("@" , ttHandle),
|
||||
asTokenDef("and" , ttAnd),
|
||||
asTokenDef("auto" , ttAuto),
|
||||
asTokenDef("bool" , ttBool),
|
||||
asTokenDef("break" , ttBreak),
|
||||
asTokenDef("case" , ttCase),
|
||||
asTokenDef("cast" , ttCast),
|
||||
asTokenDef("catch" , ttCatch),
|
||||
asTokenDef("class" , ttClass),
|
||||
asTokenDef("const" , ttConst),
|
||||
asTokenDef("continue" , ttContinue),
|
||||
asTokenDef("default" , ttDefault),
|
||||
asTokenDef("do" , ttDo),
|
||||
#ifdef AS_USE_DOUBLE_AS_FLOAT
|
||||
asTokenDef("double" , ttFloat),
|
||||
#else
|
||||
asTokenDef("double" , ttDouble),
|
||||
#endif
|
||||
asTokenDef("else" , ttElse),
|
||||
asTokenDef("enum" , ttEnum),
|
||||
asTokenDef("false" , ttFalse),
|
||||
asTokenDef("float" , ttFloat),
|
||||
asTokenDef("for" , ttFor),
|
||||
asTokenDef("funcdef" , ttFuncDef),
|
||||
asTokenDef("if" , ttIf),
|
||||
asTokenDef("import" , ttImport),
|
||||
asTokenDef("in" , ttIn),
|
||||
asTokenDef("inout" , ttInOut),
|
||||
asTokenDef("int" , ttInt),
|
||||
asTokenDef("int8" , ttInt8),
|
||||
asTokenDef("int16" , ttInt16),
|
||||
asTokenDef("int32" , ttInt),
|
||||
asTokenDef("int64" , ttInt64),
|
||||
asTokenDef("interface" , ttInterface),
|
||||
asTokenDef("is" , ttIs),
|
||||
asTokenDef("mixin" , ttMixin),
|
||||
asTokenDef("namespace" , ttNamespace),
|
||||
asTokenDef("not" , ttNot),
|
||||
asTokenDef("null" , ttNull),
|
||||
asTokenDef("or" , ttOr),
|
||||
asTokenDef("out" , ttOut),
|
||||
asTokenDef("private" , ttPrivate),
|
||||
asTokenDef("protected" , ttProtected),
|
||||
asTokenDef("return" , ttReturn),
|
||||
asTokenDef("switch" , ttSwitch),
|
||||
asTokenDef("true" , ttTrue),
|
||||
asTokenDef("try" , ttTry),
|
||||
asTokenDef("typedef" , ttTypedef),
|
||||
asTokenDef("uint" , ttUInt),
|
||||
asTokenDef("uint8" , ttUInt8),
|
||||
asTokenDef("uint16" , ttUInt16),
|
||||
asTokenDef("uint32" , ttUInt),
|
||||
asTokenDef("uint64" , ttUInt64),
|
||||
asTokenDef("void" , ttVoid),
|
||||
asTokenDef("while" , ttWhile),
|
||||
asTokenDef("xor" , ttXor),
|
||||
};
|
||||
|
||||
const unsigned int numTokenWords = sizeof(tokenWords)/sizeof(sTokenWord);
|
||||
|
||||
const char * const whiteSpace = " \t\r\n";
|
||||
|
||||
// Some keywords that are not considered tokens by the parser
|
||||
// These only have meaning in specific situations. Outside these
|
||||
// situations they are treated as normal identifiers.
|
||||
const char * const THIS_TOKEN = "this";
|
||||
const char * const FROM_TOKEN = "from";
|
||||
const char * const SUPER_TOKEN = "super";
|
||||
const char * const SHARED_TOKEN = "shared";
|
||||
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";
|
||||
const char * const FUNCTION_TOKEN = "function";
|
||||
const char * const IF_HANDLE_TOKEN = "if_handle_then_const";
|
||||
const char * const EXTERNAL_TOKEN = "external";
|
||||
const char * const EXPLICIT_TOKEN = "explicit";
|
||||
const char * const PROPERTY_TOKEN = "property";
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_tokenizer.cpp
|
||||
//
|
||||
// This class identifies tokens from the script code
|
||||
//
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_tokenizer.h"
|
||||
#include "as_tokendef.h"
|
||||
|
||||
#if !defined(AS_NO_MEMORY_H)
|
||||
#include <memory.h>
|
||||
#endif
|
||||
#include <string.h> // strcmp()
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asCTokenizer::asCTokenizer()
|
||||
{
|
||||
engine = 0;
|
||||
memset(keywordTable, 0, sizeof(keywordTable));
|
||||
|
||||
// Initialize the jump table
|
||||
for( asUINT n = 0; n < numTokenWords; n++ )
|
||||
{
|
||||
const sTokenWord& current = tokenWords[n];
|
||||
unsigned char start = current.word[0];
|
||||
|
||||
// Create new jump table entry if none exists
|
||||
if( !keywordTable[start] )
|
||||
{
|
||||
// Surely there won't ever be more than 32 keywords starting with
|
||||
// the same character. Right?
|
||||
keywordTable[start] = asNEWARRAY(const sTokenWord*, 32);
|
||||
memset(keywordTable[start], 0, sizeof(sTokenWord*)*32);
|
||||
}
|
||||
|
||||
// Add the token sorted from longest to shortest so
|
||||
// we check keywords greedily.
|
||||
const sTokenWord** tok = keywordTable[start];
|
||||
unsigned insert = 0, index = 0;
|
||||
while( tok[index] )
|
||||
{
|
||||
if(tok[index]->wordLength >= current.wordLength)
|
||||
++insert;
|
||||
++index;
|
||||
}
|
||||
|
||||
while( index > insert )
|
||||
{
|
||||
tok[index] = tok[index - 1];
|
||||
--index;
|
||||
}
|
||||
|
||||
tok[insert] = ¤t;
|
||||
}
|
||||
}
|
||||
|
||||
asCTokenizer::~asCTokenizer()
|
||||
{
|
||||
// Deallocate the jump table
|
||||
for( asUINT n = 0; n < 256; n++ )
|
||||
{
|
||||
if( keywordTable[n] )
|
||||
asDELETEARRAY(keywordTable[n]);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
const char *asCTokenizer::GetDefinition(int tokenType)
|
||||
{
|
||||
if( tokenType == ttUnrecognizedToken ) return "<unrecognized token>";
|
||||
if( tokenType == ttEnd ) return "<end of file>";
|
||||
if( tokenType == ttWhiteSpace ) return "<white space>";
|
||||
if( tokenType == ttOnelineComment ) return "<one line comment>";
|
||||
if( tokenType == ttMultilineComment ) return "<multiple lines comment>";
|
||||
if( tokenType == ttIdentifier ) return "<identifier>";
|
||||
if( tokenType == ttIntConstant ) return "<integer constant>";
|
||||
if( tokenType == ttFloatConstant ) return "<float constant>";
|
||||
if( tokenType == ttDoubleConstant ) return "<double constant>";
|
||||
if( tokenType == ttStringConstant ) return "<string constant>";
|
||||
if( tokenType == ttMultilineStringConstant ) return "<multiline string constant>";
|
||||
if( tokenType == ttNonTerminatedStringConstant ) return "<nonterminated string constant>";
|
||||
if( tokenType == ttBitsConstant ) return "<bits constant>";
|
||||
if( tokenType == ttHeredocStringConstant ) return "<heredoc string constant>";
|
||||
|
||||
for( asUINT n = 0; n < numTokenWords; n++ )
|
||||
if( tokenWords[n].tokenType == tokenType )
|
||||
return tokenWords[n].word;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool asCTokenizer::IsDigitInRadix(char ch, int radix) const
|
||||
{
|
||||
if( ch >= '0' && ch <= '9' ) return (ch -= '0') < radix;
|
||||
if( ch >= 'A' && ch <= 'Z' ) return (ch -= 'A'-10) < radix;
|
||||
if( ch >= 'a' && ch <= 'z' ) return (ch -= 'a'-10) < radix;
|
||||
return false;
|
||||
}
|
||||
|
||||
eTokenType asCTokenizer::GetToken(const char *source, size_t sourceLength, size_t *tokenLength, asETokenClass *tc) const
|
||||
{
|
||||
asASSERT(source != 0);
|
||||
asASSERT(tokenLength != 0);
|
||||
|
||||
eTokenType tokenType;
|
||||
size_t tlen;
|
||||
asETokenClass t = ParseToken(source, sourceLength, tlen, tokenType);
|
||||
if( tc ) *tc = t;
|
||||
if( tokenLength ) *tokenLength = tlen;
|
||||
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
asETokenClass asCTokenizer::ParseToken(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const
|
||||
{
|
||||
if( IsWhiteSpace(source, sourceLength, tokenLength, tokenType) ) return asTC_WHITESPACE;
|
||||
if( IsComment(source, sourceLength, tokenLength, tokenType) ) return asTC_COMMENT;
|
||||
if( IsConstant(source, sourceLength, tokenLength, tokenType) ) return asTC_VALUE;
|
||||
if( IsIdentifier(source, sourceLength, tokenLength, tokenType) ) return asTC_IDENTIFIER;
|
||||
if( IsKeyWord(source, sourceLength, tokenLength, tokenType) ) return asTC_KEYWORD;
|
||||
|
||||
// If none of the above this is an unrecognized token
|
||||
// We can find the length of the token by advancing
|
||||
// one step and trying to identify a token there
|
||||
tokenType = ttUnrecognizedToken;
|
||||
tokenLength = 1;
|
||||
|
||||
return asTC_UNKNOWN;
|
||||
}
|
||||
|
||||
bool asCTokenizer::IsWhiteSpace(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const
|
||||
{
|
||||
// Treat UTF8 byte-order-mark (EF BB BF) as whitespace
|
||||
if( sourceLength >= 3 &&
|
||||
asBYTE(source[0]) == 0xEFu &&
|
||||
asBYTE(source[1]) == 0xBBu &&
|
||||
asBYTE(source[2]) == 0xBFu )
|
||||
{
|
||||
tokenType = ttWhiteSpace;
|
||||
tokenLength = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Group all other white space characters into one
|
||||
size_t n;
|
||||
int numWsChars = (int)strlen(whiteSpace);
|
||||
for( n = 0; n < sourceLength; n++ )
|
||||
{
|
||||
bool isWhiteSpace = false;
|
||||
for( int w = 0; w < numWsChars; w++ )
|
||||
{
|
||||
if( source[n] == whiteSpace[w] )
|
||||
{
|
||||
isWhiteSpace = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( !isWhiteSpace ) break;
|
||||
}
|
||||
|
||||
if( n > 0 )
|
||||
{
|
||||
tokenType = ttWhiteSpace;
|
||||
tokenLength = n;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCTokenizer::IsComment(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const
|
||||
{
|
||||
if( sourceLength < 2 )
|
||||
return false;
|
||||
|
||||
if( source[0] != '/' )
|
||||
return false;
|
||||
|
||||
if( source[1] == '/' )
|
||||
{
|
||||
// One-line comment
|
||||
|
||||
// Find the length
|
||||
size_t n;
|
||||
for( n = 2; n < sourceLength; n++ )
|
||||
{
|
||||
if( source[n] == '\n' )
|
||||
break;
|
||||
}
|
||||
|
||||
tokenType = ttOnelineComment;
|
||||
tokenLength = n < sourceLength ? n+1 : n;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( source[1] == '*' )
|
||||
{
|
||||
// Multi-line comment
|
||||
|
||||
// Find the length
|
||||
size_t n;
|
||||
for( n = 2; n < sourceLength-1; )
|
||||
{
|
||||
if( source[n++] == '*' && source[n] == '/' )
|
||||
break;
|
||||
}
|
||||
|
||||
tokenType = ttMultilineComment;
|
||||
tokenLength = n+1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCTokenizer::IsConstant(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const
|
||||
{
|
||||
// Starting with number
|
||||
if( (source[0] >= '0' && source[0] <= '9') || (source[0] == '.' && sourceLength > 1 && source[1] >= '0' && source[1] <= '9') )
|
||||
{
|
||||
// Is it a based number?
|
||||
if( source[0] == '0' && sourceLength > 1 )
|
||||
{
|
||||
// Determine the radix for the constant
|
||||
int radix = 0;
|
||||
switch( source[1] )
|
||||
{
|
||||
case 'b': case 'B': radix = 2; break;
|
||||
case 'o': case 'O': radix = 8; break;
|
||||
case 'd': case 'D': radix = 10; break;
|
||||
case 'x': case 'X': radix = 16; break;
|
||||
}
|
||||
|
||||
if( radix )
|
||||
{
|
||||
size_t n;
|
||||
for( n = 2; n < sourceLength; n++ )
|
||||
if( !IsDigitInRadix(source[n], radix) )
|
||||
break;
|
||||
|
||||
tokenType = ttBitsConstant;
|
||||
tokenLength = n;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
size_t n;
|
||||
for( n = 0; n < sourceLength; n++ )
|
||||
{
|
||||
if( source[n] < '0' || source[n] > '9' )
|
||||
break;
|
||||
}
|
||||
|
||||
if( n < sourceLength && (source[n] == '.' || source[n] == 'e' || source[n] == 'E') )
|
||||
{
|
||||
if( source[n] == '.' )
|
||||
{
|
||||
n++;
|
||||
for( ; n < sourceLength; n++ )
|
||||
{
|
||||
if( source[n] < '0' || source[n] > '9' )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( n < sourceLength && (source[n] == 'e' || source[n] == 'E') )
|
||||
{
|
||||
n++;
|
||||
if( n < sourceLength && (source[n] == '-' || source[n] == '+') )
|
||||
n++;
|
||||
|
||||
for( ; n < sourceLength; n++ )
|
||||
{
|
||||
if( source[n] < '0' || source[n] > '9' )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( n < sourceLength && (source[n] == 'f' || source[n] == 'F') )
|
||||
{
|
||||
tokenType = ttFloatConstant;
|
||||
tokenLength = n + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef AS_USE_DOUBLE_AS_FLOAT
|
||||
tokenType = ttFloatConstant;
|
||||
#else
|
||||
tokenType = ttDoubleConstant;
|
||||
#endif
|
||||
tokenLength = n;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
tokenType = ttIntConstant;
|
||||
tokenLength = n;
|
||||
return true;
|
||||
}
|
||||
|
||||
// String constant between double or single quotes
|
||||
if( source[0] == '"' || source[0] == '\'' )
|
||||
{
|
||||
// Is it a normal string constant or a heredoc string constant?
|
||||
if( sourceLength >= 6 && source[0] == '"' && source[1] == '"' && source[2] == '"' )
|
||||
{
|
||||
// Heredoc string constant (spans multiple lines, no escape sequences)
|
||||
|
||||
// Find the length
|
||||
size_t n;
|
||||
for( n = 3; n < sourceLength-2; n++ )
|
||||
{
|
||||
if( source[n] == '"' && source[n+1] == '"' && source[n+2] == '"' )
|
||||
break;
|
||||
}
|
||||
|
||||
tokenType = ttHeredocStringConstant;
|
||||
tokenLength = n+3;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal string constant
|
||||
tokenType = ttStringConstant;
|
||||
char quote = source[0];
|
||||
bool evenSlashes = true;
|
||||
size_t n;
|
||||
for( n = 1; n < sourceLength; n++ )
|
||||
{
|
||||
#ifdef AS_DOUBLEBYTE_CHARSET
|
||||
// Double-byte characters are only allowed for ASCII
|
||||
if( (source[n] & 0x80) && engine->ep.scanner == 0 )
|
||||
{
|
||||
// This is a leading character in a double byte character,
|
||||
// include both in the string and continue processing.
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( source[n] == '\n' )
|
||||
tokenType = ttMultilineStringConstant;
|
||||
if( source[n] == quote && evenSlashes )
|
||||
{
|
||||
tokenLength = n+1;
|
||||
return true;
|
||||
}
|
||||
if( source[n] == '\\' ) evenSlashes = !evenSlashes; else evenSlashes = true;
|
||||
}
|
||||
|
||||
tokenType = ttNonTerminatedStringConstant;
|
||||
tokenLength = n;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCTokenizer::IsIdentifier(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const
|
||||
{
|
||||
// char is unsigned by default on some architectures, e.g. ppc and arm
|
||||
// Make sure the value is always treated as signed in the below comparisons
|
||||
signed char c = source[0];
|
||||
|
||||
// Starting with letter or underscore
|
||||
if( (c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
c == '_' ||
|
||||
(c < 0 && engine->ep.allowUnicodeIdentifiers) )
|
||||
{
|
||||
tokenType = ttIdentifier;
|
||||
tokenLength = 1;
|
||||
|
||||
for( size_t n = 1; n < sourceLength; n++ )
|
||||
{
|
||||
c = source[n];
|
||||
if( (c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
c == '_' ||
|
||||
(c < 0 && engine->ep.allowUnicodeIdentifiers) )
|
||||
tokenLength++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Make sure the identifier isn't a reserved keyword
|
||||
if( IsKeyWord(source, tokenLength, tokenLength, tokenType) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCTokenizer::IsKeyWord(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const
|
||||
{
|
||||
unsigned char start = source[0];
|
||||
const sTokenWord **ptr = keywordTable[start];
|
||||
|
||||
if( !ptr )
|
||||
return false;
|
||||
|
||||
for( ; *ptr; ++ptr )
|
||||
{
|
||||
size_t wlen = (*ptr)->wordLength;
|
||||
if( sourceLength >= wlen && strncmp(source, (*ptr)->word, wlen) == 0 )
|
||||
{
|
||||
// Tokens that end with a character that can be part of an
|
||||
// identifier require an extra verification to guarantee that
|
||||
// we don't split an identifier token, e.g. the "!is" token
|
||||
// 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] >= '0' && source[wlen-1] <= '9')) &&
|
||||
((source[wlen] >= 'a' && source[wlen] <= 'z') ||
|
||||
(source[wlen] >= 'A' && source[wlen] <= 'Z') ||
|
||||
(source[wlen] >= '0' && source[wlen] <= '9') ||
|
||||
(source[wlen] == '_')) )
|
||||
{
|
||||
// The token doesn't really match, even though
|
||||
// the start of the source matches the token
|
||||
continue;
|
||||
}
|
||||
|
||||
tokenType = (*ptr)->tokenType;
|
||||
tokenLength = wlen;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_tokenizer.cpp
|
||||
//
|
||||
// This class identifies tokens from the script code
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_TOKENIZER_H
|
||||
#define AS_TOKENIZER_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_tokendef.h"
|
||||
#include "as_map.h"
|
||||
#include "as_string.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCTokenizer
|
||||
{
|
||||
public:
|
||||
eTokenType GetToken(const char *source, size_t sourceLength, size_t *tokenLength, asETokenClass *tc = 0) const;
|
||||
|
||||
static const char *GetDefinition(int tokenType);
|
||||
|
||||
protected:
|
||||
friend class asCScriptEngine;
|
||||
|
||||
asCTokenizer();
|
||||
~asCTokenizer();
|
||||
|
||||
asETokenClass ParseToken(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const;
|
||||
bool IsWhiteSpace(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const;
|
||||
bool IsComment(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const;
|
||||
bool IsConstant(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const;
|
||||
bool IsKeyWord(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const;
|
||||
bool IsIdentifier(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const;
|
||||
bool IsDigitInRadix(char ch, int radix) const;
|
||||
|
||||
const asCScriptEngine *engine;
|
||||
|
||||
const sTokenWord **keywordTable[256];
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,476 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2020 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_typeinfo.cpp
|
||||
//
|
||||
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_typeinfo.h"
|
||||
#include "as_scriptengine.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asCTypeInfo::asCTypeInfo()
|
||||
{
|
||||
externalRefCount.set(0);
|
||||
internalRefCount.set(1); // start with one internal ref-count
|
||||
engine = 0;
|
||||
module = 0;
|
||||
size = 0;
|
||||
flags = 0;
|
||||
typeId = -1; // start as -1 to signal that it hasn't been defined
|
||||
|
||||
scriptSectionIdx = -1;
|
||||
declaredAt = 0;
|
||||
|
||||
accessMask = 0xFFFFFFFF;
|
||||
nameSpace = 0;
|
||||
}
|
||||
|
||||
asCTypeInfo::asCTypeInfo(asCScriptEngine *in_engine)
|
||||
{
|
||||
externalRefCount.set(0);
|
||||
internalRefCount.set(1); // start with one internal ref count
|
||||
engine = in_engine;
|
||||
module = 0;
|
||||
size = 0;
|
||||
flags = 0;
|
||||
typeId = -1; // start as -1 to signal that it hasn't been defined
|
||||
|
||||
scriptSectionIdx = -1;
|
||||
declaredAt = 0;
|
||||
|
||||
accessMask = 0xFFFFFFFF;
|
||||
nameSpace = engine->nameSpaces[0];
|
||||
}
|
||||
|
||||
asCTypeInfo::~asCTypeInfo()
|
||||
{
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCTypeInfo::AddRef() const
|
||||
{
|
||||
return externalRefCount.atomicInc();
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCTypeInfo::Release() const
|
||||
{
|
||||
int r = externalRefCount.atomicDec();
|
||||
|
||||
if (r == 0)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// 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<asCTypeInfo*>(this), asCTypeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int asCTypeInfo::AddRefInternal()
|
||||
{
|
||||
return internalRefCount.atomicInc();
|
||||
}
|
||||
|
||||
int asCTypeInfo::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<asCTypeInfo*>(this), asCTypeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// interface
|
||||
asIScriptModule *asCTypeInfo::GetModule() const
|
||||
{
|
||||
return module;
|
||||
}
|
||||
|
||||
void *asCTypeInfo::SetUserData(void *data, asPWORD type)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
void *asCTypeInfo::GetUserData(asPWORD type) const
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
// interface
|
||||
const char *asCTypeInfo::GetName() const
|
||||
{
|
||||
return name.AddressOf();
|
||||
}
|
||||
|
||||
// interface
|
||||
const char *asCTypeInfo::GetNamespace() const
|
||||
{
|
||||
if( nameSpace )
|
||||
return nameSpace->name.AddressOf();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
asDWORD asCTypeInfo::GetFlags() const
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
|
||||
// interface
|
||||
asUINT asCTypeInfo::GetSize() const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCTypeInfo::GetTypeId() const
|
||||
{
|
||||
if (typeId == -1)
|
||||
{
|
||||
// We need a non const pointer to create the asCDataType object.
|
||||
// We're not breaking anything here because this function is not
|
||||
// modifying the object, so this const cast is safe.
|
||||
asCTypeInfo *ot = const_cast<asCTypeInfo*>(this);
|
||||
|
||||
// The engine will define the typeId for this object type
|
||||
engine->GetTypeIdFromDataType(asCDataType::CreateType(ot, false));
|
||||
}
|
||||
|
||||
return typeId;
|
||||
}
|
||||
|
||||
// interface
|
||||
asIScriptEngine *asCTypeInfo::GetEngine() const
|
||||
{
|
||||
return engine;
|
||||
}
|
||||
|
||||
// interface
|
||||
const char *asCTypeInfo::GetConfigGroup() const
|
||||
{
|
||||
asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(this);
|
||||
if (group == 0)
|
||||
return 0;
|
||||
|
||||
return group->groupName.AddressOf();
|
||||
}
|
||||
|
||||
// interface
|
||||
asDWORD asCTypeInfo::GetAccessMask() const
|
||||
{
|
||||
return accessMask;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCTypeInfo::GetProperty(asUINT index, const char **out_name, int *out_typeId, bool *out_isPrivate, bool *out_isProtected, int *out_offset, bool *out_isReference, asDWORD *out_accessMask, int *out_compositeOffset, bool *out_isCompositeIndirect) const
|
||||
{
|
||||
UNUSED_VAR(index);
|
||||
if (out_name) *out_name = 0;
|
||||
if (out_typeId) *out_typeId = 0;
|
||||
if (out_isPrivate) *out_isPrivate = false;
|
||||
if (out_isProtected) *out_isProtected = false;
|
||||
if (out_offset) *out_offset = 0;
|
||||
if (out_isReference) *out_isReference = false;
|
||||
if (out_accessMask) *out_accessMask = 0;
|
||||
if (out_compositeOffset) *out_compositeOffset = 0;
|
||||
if (out_isCompositeIndirect) *out_isCompositeIndirect = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// internal
|
||||
asCObjectType *CastToObjectType(asCTypeInfo *ti)
|
||||
{
|
||||
// Allow call on null pointer
|
||||
if (ti == 0) return 0;
|
||||
|
||||
// TODO: type: Should List pattern have its own type class?
|
||||
if ((ti->flags & (asOBJ_VALUE | asOBJ_REF | asOBJ_LIST_PATTERN)) && !(ti->flags & asOBJ_FUNCDEF))
|
||||
return reinterpret_cast<asCObjectType*>(ti);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// internal
|
||||
asCEnumType *CastToEnumType(asCTypeInfo *ti)
|
||||
{
|
||||
// Allow call on null pointer
|
||||
if (ti == 0) return 0;
|
||||
|
||||
if (ti->flags & (asOBJ_ENUM))
|
||||
return reinterpret_cast<asCEnumType*>(ti);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// internal
|
||||
asCTypedefType *CastToTypedefType(asCTypeInfo *ti)
|
||||
{
|
||||
// Allow call on null pointer
|
||||
if (ti == 0) return 0;
|
||||
|
||||
if (ti->flags & (asOBJ_TYPEDEF))
|
||||
return reinterpret_cast<asCTypedefType*>(ti);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// internal
|
||||
asCFuncdefType *CastToFuncdefType(asCTypeInfo *ti)
|
||||
{
|
||||
// Allow call on null pointer
|
||||
if (ti == 0) return 0;
|
||||
|
||||
if (ti->flags & (asOBJ_FUNCDEF))
|
||||
return reinterpret_cast<asCFuncdefType*>(ti);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// internal
|
||||
void asCTypeInfo::CleanUserData()
|
||||
{
|
||||
asASSERT(engine);
|
||||
for (asUINT n = 0; n < userData.GetLength(); n += 2)
|
||||
{
|
||||
if (userData[n + 1])
|
||||
{
|
||||
for (asUINT c = 0; c < engine->cleanTypeInfoFuncs.GetLength(); c++)
|
||||
if (engine->cleanTypeInfoFuncs[c].type == userData[n])
|
||||
engine->cleanTypeInfoFuncs[c].cleanFunc(this);
|
||||
}
|
||||
}
|
||||
userData.SetLength(0);
|
||||
}
|
||||
|
||||
// internal
|
||||
bool asCTypeInfo::IsShared() const
|
||||
{
|
||||
// Types that can be declared by scripts need to have the explicit flag asOBJ_SHARED
|
||||
if (flags & (asOBJ_SCRIPT_OBJECT | asOBJ_ENUM)) return flags & asOBJ_SHARED ? true : false;
|
||||
|
||||
// Otherwise we assume the type to be shared
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
asCEnumType::~asCEnumType()
|
||||
{
|
||||
asUINT n;
|
||||
for (n = 0; n < enumValues.GetLength(); n++)
|
||||
{
|
||||
if (enumValues[n])
|
||||
asDELETE(enumValues[n], asSEnumValue);
|
||||
}
|
||||
enumValues.SetLength(0);
|
||||
}
|
||||
|
||||
// interface
|
||||
asUINT asCEnumType::GetEnumValueCount() const
|
||||
{
|
||||
return enumValues.GetLength();
|
||||
}
|
||||
|
||||
// interface
|
||||
const char *asCEnumType::GetEnumValueByIndex(asUINT index, int *outValue) const
|
||||
{
|
||||
if (outValue)
|
||||
*outValue = 0;
|
||||
|
||||
if (index >= enumValues.GetLength())
|
||||
return 0;
|
||||
|
||||
if (outValue)
|
||||
*outValue = enumValues[index]->value;
|
||||
|
||||
return enumValues[index]->name.AddressOf();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
asCTypedefType::~asCTypedefType()
|
||||
{
|
||||
DestroyInternal();
|
||||
}
|
||||
|
||||
void asCTypedefType::DestroyInternal()
|
||||
{
|
||||
if (engine == 0) return;
|
||||
|
||||
// Release the object types held by the alias
|
||||
if (aliasForType.GetTypeInfo())
|
||||
aliasForType.GetTypeInfo()->ReleaseInternal();
|
||||
|
||||
aliasForType = asCDataType::CreatePrimitive(ttVoid, false);
|
||||
|
||||
CleanUserData();
|
||||
|
||||
// Remove the type from the engine
|
||||
if (typeId != -1)
|
||||
engine->RemoveFromTypeIdMap(this);
|
||||
|
||||
// Clear the engine pointer to mark the object type as invalid
|
||||
engine = 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
int asCTypedefType::GetTypedefTypeId() const
|
||||
{
|
||||
return engine->GetTypeIdFromDataType(aliasForType);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
asCFuncdefType::asCFuncdefType(asCScriptEngine *en, asCScriptFunction *func) : asCTypeInfo(en)
|
||||
{
|
||||
asASSERT(func->funcType == asFUNC_FUNCDEF);
|
||||
asASSERT(func->funcdefType == 0);
|
||||
|
||||
// A function pointer is special kind of reference type
|
||||
// It must be possible to garbage collect, as funcdefs can form circular references if used as delegates
|
||||
flags = asOBJ_REF | asOBJ_GC | asOBJ_FUNCDEF | (func->IsShared() ? asOBJ_SHARED : 0);
|
||||
name = func->name;
|
||||
nameSpace = func->nameSpace;
|
||||
module = func->module;
|
||||
accessMask = func->accessMask;
|
||||
funcdef = func; // reference already counted by the asCScriptFunction constructor
|
||||
parentClass = 0;
|
||||
|
||||
func->funcdefType = this;
|
||||
}
|
||||
|
||||
asCFuncdefType::~asCFuncdefType()
|
||||
{
|
||||
DestroyInternal();
|
||||
}
|
||||
|
||||
void asCFuncdefType::DestroyInternal()
|
||||
{
|
||||
if (engine == 0) return;
|
||||
|
||||
// Release the funcdef
|
||||
if( funcdef )
|
||||
funcdef->ReleaseInternal();
|
||||
funcdef = 0;
|
||||
|
||||
// Detach from parent class
|
||||
if (parentClass)
|
||||
{
|
||||
parentClass->childFuncDefs.RemoveValue(this);
|
||||
parentClass = 0;
|
||||
}
|
||||
|
||||
CleanUserData();
|
||||
|
||||
// Remove the type from the engine
|
||||
if (typeId != -1)
|
||||
engine->RemoveFromTypeIdMap(this);
|
||||
|
||||
// Clear the engine pointer to mark the object type as invalid
|
||||
engine = 0;
|
||||
}
|
||||
|
||||
// interface
|
||||
asIScriptFunction *asCFuncdefType::GetFuncdefSignature() const
|
||||
{
|
||||
return funcdef;
|
||||
}
|
||||
|
||||
// interface
|
||||
asITypeInfo *asCFuncdefType::GetParentType() const
|
||||
{
|
||||
return parentClass;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2017 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_typeinfo.h
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef AS_TYPEINFO_H
|
||||
#define AS_TYPEINFO_H
|
||||
|
||||
#include "as_config.h"
|
||||
#include "as_string.h"
|
||||
#include "as_atomic.h"
|
||||
#include "as_datatype.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asCScriptEngine;
|
||||
class asCModule;
|
||||
class asCObjectType;
|
||||
class asCEnumType;
|
||||
class asCTypedefType;
|
||||
class asCFuncdefType;
|
||||
struct asSNameSpace;
|
||||
|
||||
// TODO: type: asCPrimitiveType shall be implemented to represent primitives (void, int, double, etc)
|
||||
|
||||
// TODO: type: asCTypeInfo should have an internal virtual method GetBehaviours. For asCObjectType it
|
||||
// should return the beh member. For asCFuncdefType it should return the beh member of
|
||||
// engine->functionBehaviours. This will allow the code that needs the behaviour to handle
|
||||
// both object types and funcdefs the same way
|
||||
|
||||
class asCTypeInfo : public asITypeInfo
|
||||
{
|
||||
public:
|
||||
//=====================================
|
||||
// From asITypeInfo
|
||||
//=====================================
|
||||
asIScriptEngine *GetEngine() const;
|
||||
const char *GetConfigGroup() const;
|
||||
asDWORD GetAccessMask() const;
|
||||
asIScriptModule *GetModule() const;
|
||||
|
||||
// Memory management
|
||||
int AddRef() const;
|
||||
int Release() const;
|
||||
|
||||
// Type info
|
||||
const char *GetName() const;
|
||||
const char *GetNamespace() const;
|
||||
asITypeInfo *GetBaseType() const { return 0; }
|
||||
bool DerivesFrom(const asITypeInfo *objType) const { UNUSED_VAR(objType); return 0; }
|
||||
asDWORD GetFlags() const;
|
||||
asUINT GetSize() const;
|
||||
int GetTypeId() const;
|
||||
int GetSubTypeId(asUINT subtypeIndex = 0) const { UNUSED_VAR(subtypeIndex); return -1; }
|
||||
asITypeInfo *GetSubType(asUINT subtypeIndex = 0) const { UNUSED_VAR(subtypeIndex); return 0; }
|
||||
asUINT GetSubTypeCount() const { return 0; }
|
||||
|
||||
// Interfaces
|
||||
asUINT GetInterfaceCount() const { return 0; }
|
||||
asITypeInfo *GetInterface(asUINT index) const { UNUSED_VAR(index); return 0; }
|
||||
bool Implements(const asITypeInfo *objType) const { UNUSED_VAR(objType); return false; }
|
||||
|
||||
// Factories
|
||||
asUINT GetFactoryCount() const { return 0; }
|
||||
asIScriptFunction *GetFactoryByIndex(asUINT index) const { UNUSED_VAR(index); return 0; }
|
||||
asIScriptFunction *GetFactoryByDecl(const char *decl) const { UNUSED_VAR(decl); return 0; }
|
||||
|
||||
// Methods
|
||||
asUINT GetMethodCount() const { return 0; }
|
||||
asIScriptFunction *GetMethodByIndex(asUINT index, bool getVirtual) const { UNUSED_VAR(index); UNUSED_VAR(getVirtual); return 0; }
|
||||
asIScriptFunction *GetMethodByName(const char *in_name, bool getVirtual) const { UNUSED_VAR(in_name); UNUSED_VAR(getVirtual); return 0; }
|
||||
asIScriptFunction *GetMethodByDecl(const char *decl, bool getVirtual) const { UNUSED_VAR(decl); UNUSED_VAR(getVirtual); return 0; }
|
||||
|
||||
// Properties
|
||||
asUINT GetPropertyCount() const { return 0; }
|
||||
int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask, int *compositeOffset, bool *isCompositeIndirect) const;
|
||||
const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const { UNUSED_VAR(index); UNUSED_VAR(includeNamespace); return 0; }
|
||||
|
||||
// Behaviours
|
||||
asUINT GetBehaviourCount() const { return 0; }
|
||||
asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const { UNUSED_VAR(index); UNUSED_VAR(outBehaviour); return 0; }
|
||||
|
||||
// Child types
|
||||
asUINT GetChildFuncdefCount() const { return 0; }
|
||||
asITypeInfo *GetChildFuncdef(asUINT index) const { UNUSED_VAR(index); return 0; }
|
||||
asITypeInfo *GetParentType() const { return 0; }
|
||||
|
||||
// Enums
|
||||
virtual asUINT GetEnumValueCount() const { return 0; }
|
||||
virtual const char *GetEnumValueByIndex(asUINT index, int *outValue) const { UNUSED_VAR(index); if (outValue) *outValue = 0; return 0; }
|
||||
|
||||
// Typedef
|
||||
virtual int GetTypedefTypeId() const { return asERROR; }
|
||||
|
||||
// Funcdef
|
||||
virtual asIScriptFunction *GetFuncdefSignature() const { return 0; }
|
||||
|
||||
// User data
|
||||
void *SetUserData(void *data, asPWORD type);
|
||||
void *GetUserData(asPWORD type) const;
|
||||
|
||||
//===========================================
|
||||
// Internal
|
||||
//===========================================
|
||||
public:
|
||||
asCTypeInfo(asCScriptEngine *engine);
|
||||
virtual ~asCTypeInfo();
|
||||
|
||||
// Keep an internal reference counter to separate references coming from
|
||||
// application or script objects and references coming from the script code
|
||||
virtual int AddRefInternal();
|
||||
virtual int ReleaseInternal();
|
||||
|
||||
virtual void DestroyInternal() {}
|
||||
|
||||
void CleanUserData();
|
||||
|
||||
bool IsShared() const;
|
||||
|
||||
// These can be safely used on null pointers (which will return null)
|
||||
friend asCObjectType *CastToObjectType(asCTypeInfo *);
|
||||
friend asCEnumType *CastToEnumType(asCTypeInfo *);
|
||||
friend asCTypedefType *CastToTypedefType(asCTypeInfo *);
|
||||
friend asCFuncdefType *CastToFuncdefType(asCTypeInfo *);
|
||||
|
||||
|
||||
asCString name;
|
||||
asSNameSpace *nameSpace;
|
||||
int size;
|
||||
mutable int typeId;
|
||||
asDWORD flags;
|
||||
asDWORD accessMask;
|
||||
|
||||
// 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;
|
||||
friend class asCObjectType;
|
||||
asCTypeInfo();
|
||||
|
||||
mutable asCAtomic externalRefCount;
|
||||
asCAtomic internalRefCount;
|
||||
};
|
||||
|
||||
struct asSEnumValue
|
||||
{
|
||||
asCString name;
|
||||
int value;
|
||||
};
|
||||
|
||||
class asCEnumType : public asCTypeInfo
|
||||
{
|
||||
public:
|
||||
asCEnumType(asCScriptEngine *engine) : asCTypeInfo(engine) {}
|
||||
~asCEnumType();
|
||||
|
||||
asCArray<asSEnumValue*> enumValues;
|
||||
|
||||
asUINT GetEnumValueCount() const;
|
||||
const char *GetEnumValueByIndex(asUINT index, int *outValue) const;
|
||||
|
||||
protected:
|
||||
asCEnumType() : asCTypeInfo() {}
|
||||
};
|
||||
|
||||
class asCTypedefType : public asCTypeInfo
|
||||
{
|
||||
public:
|
||||
asCTypedefType(asCScriptEngine *engine) : asCTypeInfo(engine) {}
|
||||
~asCTypedefType();
|
||||
|
||||
void DestroyInternal();
|
||||
|
||||
asCDataType aliasForType; // increase refCount for typeinfo inside datatype
|
||||
|
||||
int GetTypedefTypeId() const;
|
||||
|
||||
protected:
|
||||
asCTypedefType() : asCTypeInfo() {}
|
||||
};
|
||||
|
||||
class asCFuncdefType : public asCTypeInfo
|
||||
{
|
||||
public:
|
||||
asCFuncdefType(asCScriptEngine *engine, asCScriptFunction *func);
|
||||
~asCFuncdefType();
|
||||
|
||||
asIScriptFunction *GetFuncdefSignature() const;
|
||||
asITypeInfo *GetParentType() const;
|
||||
|
||||
void DestroyInternal();
|
||||
asCScriptFunction *funcdef; // increases refCount
|
||||
asCObjectType *parentClass; // doesn't increase refCount
|
||||
|
||||
protected:
|
||||
asCFuncdefType() : asCTypeInfo(), funcdef(0), parentClass(0) {}
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_variablescope.cpp
|
||||
//
|
||||
// A manager class for variable declarations
|
||||
//
|
||||
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
|
||||
#include "as_variablescope.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asCVariableScope::asCVariableScope(asCVariableScope *parent)
|
||||
{
|
||||
this->parent = parent;
|
||||
Reset();
|
||||
}
|
||||
|
||||
asCVariableScope::~asCVariableScope()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void asCVariableScope::Reset()
|
||||
{
|
||||
isBreakScope = false;
|
||||
isContinueScope = false;
|
||||
|
||||
for( asUINT n = 0; n < variables.GetLength(); n++ )
|
||||
if( variables[n] )
|
||||
{
|
||||
asDELETE(variables[n],sVariable);
|
||||
}
|
||||
variables.SetLength(0);
|
||||
}
|
||||
|
||||
int asCVariableScope::DeclareVariable(const char *name, const asCDataType &type, int stackOffset, bool onHeap)
|
||||
{
|
||||
// TODO: optimize: Improve linear search
|
||||
// See if the variable is already declared
|
||||
if( strcmp(name, "") != 0 )
|
||||
{
|
||||
for( asUINT n = 0; n < variables.GetLength(); n++ )
|
||||
{
|
||||
if( variables[n]->name == name )
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
sVariable *var = asNEW(sVariable);
|
||||
if( var == 0 )
|
||||
{
|
||||
// Out of memory. Return without allocating the var
|
||||
return -2;
|
||||
}
|
||||
var->name = name;
|
||||
var->type = type;
|
||||
var->stackOffset = stackOffset;
|
||||
var->isInitialized = false;
|
||||
var->isPureConstant = false;
|
||||
var->onHeap = onHeap;
|
||||
|
||||
// Parameters are initialized
|
||||
if( stackOffset <= 0 )
|
||||
var->isInitialized = true;
|
||||
|
||||
variables.PushLast(var);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sVariable *asCVariableScope::GetVariable(const char *name)
|
||||
{
|
||||
// TODO: optimize: Improve linear search
|
||||
// Find the variable
|
||||
for( asUINT n = 0; n < variables.GetLength(); n++ )
|
||||
{
|
||||
if( variables[n]->name == name )
|
||||
return variables[n];
|
||||
}
|
||||
|
||||
if( parent )
|
||||
return parent->GetVariable(name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sVariable *asCVariableScope::GetVariableByOffset(int offset)
|
||||
{
|
||||
// TODO: optimize: Improve linear search
|
||||
// Find the variable
|
||||
for( asUINT n = 0; n < variables.GetLength(); n++ )
|
||||
{
|
||||
if( variables[n]->stackOffset == offset )
|
||||
return variables[n];
|
||||
}
|
||||
|
||||
if( parent )
|
||||
return parent->GetVariableByOffset(offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_NO_COMPILER
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 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
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// as_variablescope.h
|
||||
//
|
||||
// A manager class for variable declarations
|
||||
//
|
||||
|
||||
|
||||
#ifndef AS_VARIABLESCOPE_H
|
||||
#define AS_VARIABLESCOPE_H
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_NO_COMPILER
|
||||
|
||||
#include "as_array.h"
|
||||
#include "as_string.h"
|
||||
#include "as_datatype.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
struct sVariable
|
||||
{
|
||||
asCString name;
|
||||
asCDataType type;
|
||||
int stackOffset;
|
||||
bool isInitialized;
|
||||
bool isPureConstant;
|
||||
asQWORD constantValue;
|
||||
bool onHeap;
|
||||
};
|
||||
|
||||
class asCVariableScope
|
||||
{
|
||||
public:
|
||||
asCVariableScope(asCVariableScope *parent);
|
||||
~asCVariableScope();
|
||||
|
||||
void Reset();
|
||||
|
||||
int DeclareVariable(const char *name, const asCDataType &type, int stackOffset, bool isObjectOnHeap);
|
||||
sVariable *GetVariable(const char *name);
|
||||
sVariable *GetVariableByOffset(int offset);
|
||||
|
||||
asCVariableScope *parent;
|
||||
|
||||
bool isBreakScope;
|
||||
bool isContinueScope;
|
||||
|
||||
asCArray<sVariable *> variables;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_NO_COMPILER
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
Bullet Physics Library is an open source project with help from the community at the Physics Forum
|
||||
See the forum at http://bulletphysics.com
|
||||
|
||||
The project was started by Erwin Coumans
|
||||
|
||||
Following people contributed to Bullet
|
||||
(random order, please let us know on the forum if your name should be in this list)
|
||||
|
||||
Gino van den Bergen: LinearMath classes
|
||||
Christer Ericson: parts of the voronoi simplex solver
|
||||
Simon Hobbs: 3d axis sweep and prune, Extras/SATCollision, separating axis theorem + SIMD code
|
||||
Dirk Gregorius: generic D6 constraint
|
||||
Erin Catto: accumulated impulse in sequential impulse
|
||||
Nathanael Presson: EPA penetration depth calculation
|
||||
Francisco Leon: GIMPACT Concave Concave collision
|
||||
Joerg Henrichs: make buildsystem (work in progress)
|
||||
Eric Sunshine: jam + msvcgen buildsystem
|
||||
Steve Baker: GPU physics and general implementation improvements
|
||||
Jay Lee: Double precision support
|
||||
KleMiX, aka Vsevolod Klementjev, managed version, rewritten in C# for XNA
|
||||
Erwin Coumans: most other source code
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
Free for commercial use, please report projects in the forum at http://www.bulletphysics.org
|
||||
|
||||
In case you want to display a Bullet logo in your software: you can download the Bullet logo in various vector formats and high resolution at the download section in http://bullet.googlecode.com
|
||||
@@ -0,0 +1,306 @@
|
||||
# CMakeLists.txt for Bullet in STK
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/)
|
||||
|
||||
if(APPLE AND NOT IOS)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch ${ARCHFLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch ${ARCHFLAGS} -F/Library/Frameworks")
|
||||
endif()
|
||||
|
||||
# libbulletmath
|
||||
add_library(bulletmath STATIC
|
||||
src/LinearMath/btAabbUtil2.h src/LinearMath/btMotionState.h
|
||||
src/LinearMath/btAlignedAllocator.cpp src/LinearMath/btPoolAllocator.h
|
||||
src/LinearMath/btAlignedAllocator.h src/LinearMath/btQuadWord.h
|
||||
src/LinearMath/btAlignedObjectArray.h src/LinearMath/btQuaternion.h
|
||||
src/LinearMath/btConvexHull.cpp src/LinearMath/btQuickprof.cpp
|
||||
src/LinearMath/btConvexHull.h src/LinearMath/btQuickprof.h
|
||||
src/LinearMath/btConvexHullComputer.h src/LinearMath/btConvexHullComputer.cpp
|
||||
src/LinearMath/btDefaultMotionState.h src/LinearMath/btRandom.h
|
||||
src/LinearMath/btGeometryUtil.cpp src/LinearMath/btScalar.h
|
||||
src/LinearMath/btGeometryUtil.h src/LinearMath/btSerializer.cpp
|
||||
src/LinearMath/btGrahamScan2dConvexHull.h
|
||||
src/LinearMath/btHashMap.h src/LinearMath/btSerializer.h
|
||||
src/LinearMath/btIDebugDraw.h src/LinearMath/btStackAlloc.h
|
||||
src/LinearMath/btList.h src/LinearMath/btTransform.h
|
||||
src/LinearMath/btMatrix3x3.h src/LinearMath/btTransformUtil.h
|
||||
src/LinearMath/btMinMax.h src/LinearMath/btVector3.h
|
||||
)
|
||||
|
||||
# TODO: original comment:
|
||||
# Certain g++ versions causes stk to crash if btVoronoiSimplexSolver.cpp is
|
||||
# compiled with optimisations. Since it's rather difficult to specify certain
|
||||
# flags for one file only with auto-tools (you can only specify flags per
|
||||
# library, so you have to put this one file into a separate library) we compile
|
||||
# the whole libbulletcollision with the modified flags - i.e. by adding
|
||||
# -fno-elide-constructors to the flags. The overall performance impact is
|
||||
# quite low anyway.
|
||||
|
||||
# libbulletcollision
|
||||
add_library(bulletcollision STATIC
|
||||
src/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp
|
||||
src/BulletCollision/BroadphaseCollision/btAxisSweep3.h
|
||||
src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h
|
||||
src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp
|
||||
src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h
|
||||
src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp
|
||||
src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h
|
||||
src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp
|
||||
src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h
|
||||
src/BulletCollision/BroadphaseCollision/btDbvt.cpp
|
||||
src/BulletCollision/BroadphaseCollision/btDbvt.h
|
||||
src/BulletCollision/BroadphaseCollision/btDispatcher.cpp
|
||||
src/BulletCollision/BroadphaseCollision/btDispatcher.h
|
||||
src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp
|
||||
src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h
|
||||
src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp
|
||||
src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h
|
||||
src/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h
|
||||
src/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp
|
||||
src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h
|
||||
src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp
|
||||
src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h
|
||||
src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp
|
||||
src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h
|
||||
src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
|
||||
src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h
|
||||
src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp
|
||||
src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h
|
||||
src/BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp
|
||||
src/BulletCollision/CollisionDispatch/btBoxBoxDetector.h
|
||||
src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h
|
||||
src/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h
|
||||
src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp
|
||||
src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h
|
||||
src/BulletCollision/CollisionDispatch/btCollisionObject.cpp
|
||||
src/BulletCollision/CollisionDispatch/btCollisionObject.h
|
||||
src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
|
||||
src/BulletCollision/CollisionDispatch/btCollisionWorld.h
|
||||
src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
|
||||
src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h
|
||||
src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp
|
||||
src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h
|
||||
src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp
|
||||
src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h
|
||||
src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp
|
||||
src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h
|
||||
src/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp
|
||||
src/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h
|
||||
src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp
|
||||
src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h
|
||||
src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp
|
||||
src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h
|
||||
src/BulletCollision/CollisionDispatch/btGhostObject.cpp
|
||||
src/BulletCollision/CollisionDispatch/btGhostObject.h
|
||||
src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp
|
||||
src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h
|
||||
src/BulletCollision/CollisionDispatch/btManifoldResult.cpp
|
||||
src/BulletCollision/CollisionDispatch/btManifoldResult.h
|
||||
src/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp
|
||||
src/BulletCollision/CollisionDispatch/btSimulationIslandManager.h
|
||||
src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp
|
||||
src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h
|
||||
src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp
|
||||
src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h
|
||||
src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp
|
||||
src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h
|
||||
src/BulletCollision/CollisionDispatch/btUnionFind.cpp
|
||||
src/BulletCollision/CollisionDispatch/btUnionFind.h
|
||||
src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp
|
||||
src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h
|
||||
src/BulletCollision/CollisionShapes/btBox2dShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btBox2dShape.h
|
||||
src/BulletCollision/CollisionShapes/btBoxShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btBoxShape.h
|
||||
src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h
|
||||
src/BulletCollision/CollisionShapes/btCapsuleShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btCapsuleShape.h
|
||||
src/BulletCollision/CollisionShapes/btCollisionMargin.h
|
||||
src/BulletCollision/CollisionShapes/btCollisionShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btCollisionShape.h
|
||||
src/BulletCollision/CollisionShapes/btCompoundShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btCompoundShape.h
|
||||
src/BulletCollision/CollisionShapes/btConcaveShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btConcaveShape.h
|
||||
src/BulletCollision/CollisionShapes/btConeShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btConeShape.h
|
||||
src/BulletCollision/CollisionShapes/btConvex2dShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btConvex2dShape.h
|
||||
src/BulletCollision/CollisionShapes/btConvexHullShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btConvexHullShape.h
|
||||
src/BulletCollision/CollisionShapes/btConvexInternalShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btConvexInternalShape.h
|
||||
src/BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btConvexPointCloudShape.h
|
||||
src/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp
|
||||
src/BulletCollision/CollisionShapes/btConvexPolyhedron.h
|
||||
src/BulletCollision/CollisionShapes/btConvexShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btConvexShape.h
|
||||
src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h
|
||||
src/BulletCollision/CollisionShapes/btCylinderShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btCylinderShape.h
|
||||
src/BulletCollision/CollisionShapes/btEmptyShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btEmptyShape.h
|
||||
src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h
|
||||
src/BulletCollision/CollisionShapes/btMaterial.h
|
||||
src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btMinkowskiSumShape.h
|
||||
src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h
|
||||
src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btMultiSphereShape.h
|
||||
src/BulletCollision/CollisionShapes/btOptimizedBvh.cpp
|
||||
src/BulletCollision/CollisionShapes/btOptimizedBvh.h
|
||||
src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h
|
||||
src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h
|
||||
src/BulletCollision/CollisionShapes/btShapeHull.cpp
|
||||
src/BulletCollision/CollisionShapes/btShapeHull.h
|
||||
src/BulletCollision/CollisionShapes/btSphereShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btSphereShape.h
|
||||
src/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btStaticPlaneShape.h
|
||||
src/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp
|
||||
src/BulletCollision/CollisionShapes/btStridingMeshInterface.h
|
||||
src/BulletCollision/CollisionShapes/btTetrahedronShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btTetrahedronShape.h
|
||||
src/BulletCollision/CollisionShapes/btTriangleBuffer.cpp
|
||||
src/BulletCollision/CollisionShapes/btTriangleBuffer.h
|
||||
src/BulletCollision/CollisionShapes/btTriangleCallback.cpp
|
||||
src/BulletCollision/CollisionShapes/btTriangleCallback.h
|
||||
src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp
|
||||
src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h
|
||||
src/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp
|
||||
src/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h
|
||||
src/BulletCollision/CollisionShapes/btTriangleInfoMap.h
|
||||
src/BulletCollision/CollisionShapes/btTriangleMesh.cpp
|
||||
src/BulletCollision/CollisionShapes/btTriangleMesh.h
|
||||
src/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btTriangleMeshShape.h
|
||||
src/BulletCollision/CollisionShapes/btTriangleShape.h
|
||||
src/BulletCollision/CollisionShapes/btUniformScalingShape.cpp
|
||||
src/BulletCollision/CollisionShapes/btUniformScalingShape.h
|
||||
src/BulletCollision/Gimpact/btBoxCollision.h
|
||||
src/BulletCollision/Gimpact/btClipPolygon.h
|
||||
src/BulletCollision/Gimpact/btContactProcessing.cpp
|
||||
src/BulletCollision/Gimpact/btContactProcessing.h
|
||||
src/BulletCollision/Gimpact/btGenericPoolAllocator.cpp
|
||||
src/BulletCollision/Gimpact/btGenericPoolAllocator.h
|
||||
src/BulletCollision/Gimpact/btGeometryOperations.h
|
||||
src/BulletCollision/Gimpact/btGImpactBvh.cpp
|
||||
src/BulletCollision/Gimpact/btGImpactBvh.h
|
||||
src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp
|
||||
src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h
|
||||
src/BulletCollision/Gimpact/btGImpactMassUtil.h
|
||||
src/BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp
|
||||
src/BulletCollision/Gimpact/btGImpactQuantizedBvh.h
|
||||
src/BulletCollision/Gimpact/btGImpactShape.cpp
|
||||
src/BulletCollision/Gimpact/btGImpactShape.h
|
||||
src/BulletCollision/Gimpact/btQuantization.h
|
||||
src/BulletCollision/Gimpact/btTriangleShapeEx.cpp
|
||||
src/BulletCollision/Gimpact/btTriangleShapeEx.h
|
||||
src/BulletCollision/Gimpact/gim_array.h
|
||||
src/BulletCollision/Gimpact/gim_basic_geometry_operations.h
|
||||
src/BulletCollision/Gimpact/gim_bitset.h
|
||||
src/BulletCollision/Gimpact/gim_box_collision.h
|
||||
src/BulletCollision/Gimpact/gim_box_set.cpp
|
||||
src/BulletCollision/Gimpact/gim_box_set.h
|
||||
src/BulletCollision/Gimpact/gim_clip_polygon.h
|
||||
src/BulletCollision/Gimpact/gim_contact.cpp
|
||||
src/BulletCollision/Gimpact/gim_contact.h
|
||||
src/BulletCollision/Gimpact/gim_geometry.h
|
||||
src/BulletCollision/Gimpact/gim_geom_types.h
|
||||
src/BulletCollision/Gimpact/gim_hash_table.h
|
||||
src/BulletCollision/Gimpact/gim_linear_math.h
|
||||
src/BulletCollision/Gimpact/gim_math.h
|
||||
src/BulletCollision/Gimpact/gim_memory.cpp
|
||||
src/BulletCollision/Gimpact/gim_memory.h
|
||||
src/BulletCollision/Gimpact/gim_radixsort.h
|
||||
src/BulletCollision/Gimpact/gim_tri_collision.cpp
|
||||
src/BulletCollision/Gimpact/gim_tri_collision.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp
|
||||
src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btConvexCast.cpp
|
||||
src/BulletCollision/NarrowPhaseCollision/btConvexCast.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp
|
||||
src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp
|
||||
src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp
|
||||
src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp
|
||||
src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp
|
||||
src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp
|
||||
src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btPointCollector.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
|
||||
src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp
|
||||
src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp
|
||||
src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h
|
||||
src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp
|
||||
src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h
|
||||
)
|
||||
|
||||
# libbulletdynamics
|
||||
add_library(bulletdynamics STATIC
|
||||
src/BulletDynamics/Character/btCharacterControllerInterface.h
|
||||
src/BulletDynamics/Character/btKinematicCharacterController.cpp
|
||||
src/BulletDynamics/Character/btKinematicCharacterController.h
|
||||
src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp
|
||||
src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h
|
||||
src/BulletDynamics/ConstraintSolver/btConstraintSolver.h
|
||||
src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp
|
||||
src/BulletDynamics/ConstraintSolver/btContactConstraint.h
|
||||
src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h
|
||||
src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp
|
||||
src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h
|
||||
src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp
|
||||
src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h
|
||||
src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp
|
||||
src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h
|
||||
src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp
|
||||
src/BulletDynamics/ConstraintSolver/btHingeConstraint.h
|
||||
src/BulletDynamics/ConstraintSolver/btJacobianEntry.h
|
||||
src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp
|
||||
src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h
|
||||
src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp
|
||||
src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h
|
||||
src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp
|
||||
src/BulletDynamics/ConstraintSolver/btSliderConstraint.h
|
||||
src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp
|
||||
src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h
|
||||
src/BulletDynamics/ConstraintSolver/btSolverBody.h
|
||||
src/BulletDynamics/ConstraintSolver/btSolverConstraint.h
|
||||
src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp
|
||||
src/BulletDynamics/ConstraintSolver/btTypedConstraint.h
|
||||
src/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp
|
||||
src/BulletDynamics/ConstraintSolver/btUniversalConstraint.h
|
||||
src/BulletDynamics/Dynamics/btActionInterface.h
|
||||
src/BulletDynamics/Dynamics/btContinuousDynamicsWorld.cpp
|
||||
src/BulletDynamics/Dynamics/btContinuousDynamicsWorld.h
|
||||
src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp
|
||||
src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h
|
||||
src/BulletDynamics/Dynamics/btDynamicsWorld.h
|
||||
src/BulletDynamics/Dynamics/btRigidBody.cpp
|
||||
src/BulletDynamics/Dynamics/btRigidBody.h
|
||||
src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp
|
||||
src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h
|
||||
src/BulletDynamics/Dynamics/Bullet-C-API.cpp
|
||||
src/BulletDynamics/Vehicle/btRaycastVehicle.cpp
|
||||
src/BulletDynamics/Vehicle/btRaycastVehicle.h
|
||||
src/BulletDynamics/Vehicle/btVehicleRaycaster.h
|
||||
src/BulletDynamics/Vehicle/btWheelInfo.cpp
|
||||
src/BulletDynamics/Vehicle/btWheelInfo.h
|
||||
)
|
||||
@@ -0,0 +1,788 @@
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Primary author and maintainer: Erwin Coumans
|
||||
|
||||
This ChangeLog is incomplete, for an up-to-date list of all fixed issues see http://bullet.googlecode.com
|
||||
using http://tinyurl.com/yabmjjj
|
||||
|
||||
2011 September 15
|
||||
- Bullet 2.79 release, revision 2433 (mainly a bugfix release)
|
||||
- Revert a change in 2.78 related to speculative contacts (it has undesired side effects)
|
||||
- Use HACD Hierachical Approximate Convex Decomposition (thanks to Khaled Mammou and Sujeon Kim)
|
||||
- Add Intel cmake-build support for OpenCL accelerated cloth/particle
|
||||
- add premake4 build system support to autogenerate visual studio project files that can be shipped (see msvc folder)
|
||||
- preliminary build support for Google NativeClient, using premake4 (see msvc folder)
|
||||
|
||||
|
||||
2011 April 8
|
||||
- Bullet 2.78 release 2383
|
||||
- Added FractureDemo
|
||||
- Added Separatinx Axis Test and Polyhedral Clipping support (See InternalEdgeDemo)
|
||||
- Added speculative contacts as CCD response method (See CcdPhysicsDemo)
|
||||
- OpenCL and DirectCompute cloth as basic support for capsule collision
|
||||
|
||||
2010 September 7
|
||||
- autotools now uses CamelCase naming for libraries just like cmake:
|
||||
libbulletdynamics -> libBulletDynamics, libbulletmath -> libLinearMath
|
||||
|
||||
2010 July 21
|
||||
- Preparing for Bullet 2.77 release, around revision r2135
|
||||
- Added an OpenCL particle demo, running on NVidia, AMD and MiniCL
|
||||
Thanks to NVidia for the original particle demo from their OpenCL SDK
|
||||
- Added GPU deformable object solvers for OpenCL and DirectCompute, and a DirectX 11 cloth demo
|
||||
Thanks to AMD
|
||||
- Create a separate library for MiniCL,
|
||||
MiniCL is a rudimentary OpenCL wrapper that allows to compile OpenCL kernels for multi-core CPU, using Win32 Threads or Posix
|
||||
- Moved vectormath into Bullet/src, and added a SSE implementation
|
||||
- Added a btParallelConstraintSolver, mainly for PlayStation 3 Cell SPUs (although it runs fine on CPU too)
|
||||
|
||||
2010 March 6
|
||||
- Dynamica Maya plugin (and COLLADA support) is moved to http://dynamica.googlecode.com
|
||||
|
||||
2010 February
|
||||
- Bullet 2.76 release, revision 2010
|
||||
- support for the .bullet binary file format
|
||||
- btInternalEdgeUtility to adjust unwanted collisions against internal triangle edges
|
||||
- Improved Maya Dynamica plugin with better constraint authoring and .bullet file export
|
||||
|
||||
|
||||
2009 September 17
|
||||
- Minor update to Bullet 2.75 release, revision 1776
|
||||
- Support for btConvex2dShape, check out Bullet/Demos/Box2dDemo
|
||||
- Fixes in build systems
|
||||
- Minor fix in btGjkPairDetector
|
||||
- Initialize world transform for btCollisionShape in constructor
|
||||
|
||||
|
||||
2009 September 6
|
||||
- Bullet 2.75 release
|
||||
- Added SPH fluid simulation in Extras, not integrated with rigid body / soft body yet
|
||||
Thanks to Rama Hoetzlein to make this contribution available under the ZLib license
|
||||
- add special capsule-capsule collider code in btConvexConvexCollisionAlgorithm, to speed up capsule-ragdolls
|
||||
- soft body improvement: faster building of bending constraints
|
||||
- soft body improvement: allow to disable/enable cluster self-collision
|
||||
- soft body fix: 'exploding' soft bodies when using cluster collision
|
||||
- fix some degenerate cases in continuous convex cast, could impact ray cast/convex cast
|
||||
Thanks to Jacob Langford for the report and reproduction cases, see http://code.google.com/p/bullet/issues/detail?id=250&can=1&start=200
|
||||
- re-enabled split impulse
|
||||
- added btHinge2Constraint, btUniversalConstraint, btGeneric6DofSpringConstraint
|
||||
- demonstrate 2D physics with 2D/3D object interaction
|
||||
|
||||
|
||||
2008 December 2
|
||||
- Fix contact refresh issues with btCompoundShape, introduced with btDbvt acceleration structure in btCompoundCollisionAlgorithm
|
||||
- Made btSequentialImpulseConstraintSolver 100% compatible with ODE quickstep
|
||||
constraints can use 'solveConstraint' method or 'getInfo/getInfo2'
|
||||
|
||||
2008 November 30
|
||||
- Add highly optimized SIMD branchless PGS/SI solver innerloop
|
||||
|
||||
2008 November 12
|
||||
- Add compound shape export to BulletColladaConverter
|
||||
Thanks to JamesH for the report: http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=12&t=2840
|
||||
- Fix compiler build for Visual Studio 6
|
||||
Thanks to JoF for the report: http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=2841
|
||||
|
||||
2008 November 11
|
||||
- Add CProfileManager::dumpAll() to dump performance statistics to console using printf.
|
||||
- Add support for interaction between btSoftBody and btCollisionObject/btGhostObject
|
||||
|
||||
2008 November 8
|
||||
- Fix PosixThreadSupport
|
||||
- Add improved btHeightfieldTerrainShape support and new Demos/TerrainDemo
|
||||
Thanks to tomva, http://code.google.com/p/bullet/issues/detail?id=63&can=1
|
||||
- Moved kinematic character controller from Demos/CharacterDemo into src/BulletDynamics/Character/btKinematicCharacterController.cpp
|
||||
|
||||
2008 November 6
|
||||
- reduced default memory pool allocation from 40Mb to 3Mb. This should be more suitable for all platforms, including iPhone
|
||||
- improved CUDA broadphase
|
||||
- IBM Cell SDK 3.x support, fix ibmsdk Makefiles
|
||||
- improved CMake support with 'install' and 'framework option
|
||||
|
||||
2008 November 4
|
||||
- add btAxisSweep::resetPool to avoid non-determinism due to shuffled linked list
|
||||
Thanks to Ole for the contribution,
|
||||
|
||||
2008 October 30
|
||||
- disabled btTriangleMesh duplicate search by default, it is extremely slow
|
||||
- added Extras/IFF binary chunk serialization library as preparation for in-game native platform serialization (planned COLLADA DOM -> IFF converter)
|
||||
|
||||
2008 October 20
|
||||
- added SCE Physics Effects box-box collision detection for SPU/BulletMultiThreaded version
|
||||
See Bullet/src/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/boxBoxDistance.cpp
|
||||
Thanks to Sony Computer Entertainment Japan, SCEI for the contribution
|
||||
|
||||
2008 October 17
|
||||
- Added btGhostObject support, this helps character controller, explosions, triggers and other local spatial queries
|
||||
|
||||
2008 October 10
|
||||
- Moved aabb to btBroadphaseProxy, improves rayTest dramatically. Further raytest improvements using the broadphase acceleration structures are planned
|
||||
- Moved BulletMultiThreaded from Extras to /src/BulletMultiThreaded for better integration
|
||||
|
||||
|
||||
2008 October 3
|
||||
- Add support for autoconf automake
|
||||
./autogen.sh and ./configure will create both Makefile and Jamfile. CMake and autogenerated Visual Studio projectfiles remain supported too.
|
||||
- Improved ColladaConverter: plane shape export, and callback for shape construction to allow deletion of memory
|
||||
|
||||
2008 Sept 30
|
||||
- Improved Soft Body support, fixed issues related to soft body colliding against concave triangle meshes
|
||||
- Shared more code between regular version and SPU/BulletMultiThreaded, in particular GJK/EPA
|
||||
|
||||
2008 Sept 28
|
||||
- Fixed rotation issues in Dynamic Maya Plugin
|
||||
|
||||
2008 Sept 11
|
||||
- Enable CCD motion clamping for btDiscreteDynamicsWorld, to avoid tunneling. A more advanced solution will be implemented in btContinuousDynamicsWorld.
|
||||
|
||||
2008 Sept 7
|
||||
- Add btScaledBvhTriangleMeshShape, to allow re-use of btBvhTriangleMeshShape of different sizes, without copying of the BVH data.
|
||||
|
||||
2008 Sept 5
|
||||
- Enabled Demos/ForkLiftDemo
|
||||
Thanks Roman Ponomarev.
|
||||
|
||||
2008 Sept 4
|
||||
- Added btCudaBroadphase in Extras/CUDA: some research into accelerating Bullet using CUDA.
|
||||
Thanks to the particle demo from the NVidia CUDA SDK.
|
||||
|
||||
2008 Sept 3
|
||||
- Several bug fixes and contributions related to inertia tensor, memory leaks etc.
|
||||
Thanks to Ole K.
|
||||
|
||||
2008 Sept 1
|
||||
- Updated CDTestFramework, with latest version of OPCODE Array SAP. See Extras/CDTestFramework
|
||||
Thanks to Pierre Terdiman for the update
|
||||
|
||||
2008 August 25
|
||||
- Walt Disney Studios contributes their in-house Maya Plugin for simulating Bullet physics, with options for other engines such as PhysBam or PhysX.
|
||||
Thanks to Nicola Candussi and Arthur Shek
|
||||
|
||||
2008 August 14
|
||||
- Improved performance for btDbvtBroadphase, based on dual dynamic AABB trees (one for static, one for dynamic objects, where objects can move from one to the other tree)
|
||||
Thanks to Nathanael Presson again, for all his work.
|
||||
|
||||
2008 July 31
|
||||
- Added Havok .hkx to COLLADA Physics .dae converter patch+information
|
||||
- Fix btSubsimplexConvexCast
|
||||
Thanks to Nacho, http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=2422)
|
||||
- Fix in rendering, GL_STENCIL
|
||||
- btTriangleIndexVertexArray indices should be unsigned int/unsigned short int,
|
||||
- Made InternalProcessAllTriangles virtual, thanks to
|
||||
Both thank to Fullmetalcoder, http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=2401
|
||||
- clamp impulse for btPoint2PointConstraint
|
||||
Thanks to Martijn Reuvers, http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=2418
|
||||
- Free memory of bvh, pass in scaling factor (optional)
|
||||
Thanks to Roy Eltham, http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=2375
|
||||
|
||||
2008 July 27
|
||||
|
||||
btDbvtBroadphase:
|
||||
- Fixed a performance issues reported by 'reltham'
|
||||
- Added btDbvtBroadphase::optimize() for people who want good performances right
|
||||
away or don't do dynamics.
|
||||
- fixed compilation issues when DBVT_BP_PROFILE was set.
|
||||
btSoftBody:
|
||||
- Fixed singular matrix issues related to polar decomposition (flat meshes).
|
||||
DemoApplication:
|
||||
- Shadows (enable/disable through 'g' or DemoApplication::setShadows(bool)).
|
||||
- Texture can be enable/disable through 'u'
|
||||
CDFramework:
|
||||
- fixed compilation issues.
|
||||
All thanks to Nathanael Presson
|
||||
|
||||
2008 July 10
|
||||
- Added btMultimaterialTriangleMeshShape and MultiMaterialDemo
|
||||
Thanks to Alex Silverman for the contribution
|
||||
|
||||
2008 June 30
|
||||
- Added initial support for kinematic character controller
|
||||
Thanks to John McCutchan
|
||||
|
||||
2008 April 14
|
||||
- Added ray cast support for Soft Bodies
|
||||
Thanks to Nathanael Presson for the contribution
|
||||
|
||||
2008 April 9
|
||||
- Cleanup of Stan Melax ConvexHull, removed Extras/ConvexHull, moved sources into LinearMath/BulletCollision
|
||||
|
||||
2008 April 4
|
||||
- Added btSliderConstraint and demo
|
||||
Thanks Roman Ponomarev
|
||||
|
||||
2008 April 3
|
||||
- Fixed btMinkowskiSumShape, and added hitpoint to btSubsimplexConvexCast
|
||||
|
||||
2008 April 2
|
||||
- Added Extras/CdTestFrameWork
|
||||
Thanks Pierre Terdiman
|
||||
|
||||
2008 April 1
|
||||
- Added posix thread (pthread) support
|
||||
Thanks Enrico
|
||||
|
||||
2008 March 30
|
||||
- Added Soft Body, cloth, rope and deformable volumes, including demos and interaction
|
||||
Thanks Nathanael Presson for this great contribution
|
||||
|
||||
2008 March 17
|
||||
- Improved BulletColladaConverter
|
||||
Thanks John McCutchan
|
||||
|
||||
2008 March 15
|
||||
- btMultiSapBroadphase in a working state. Needs more optimizations to be fully useable.
|
||||
- Allow btOptimizedBvh to be used for arbitrary objects, not just triangles
|
||||
- added quicksort to btAlignedObjectArray
|
||||
- removed btTypedUserInfo, added btHashMap
|
||||
|
||||
2008 March 30
|
||||
- Moved quickstep solver and boxbox into Bullet/src folder
|
||||
Thanks Russell L. Smith for permission to redistribute Open Dynamics Engine quickstep and box-box under the ZLib license
|
||||
|
||||
2008 Feb 27
|
||||
- Added initial version for Character Control Demo
|
||||
- Applied fixes to IBM Cell SDK 3.0 build makefiles
|
||||
Thanks Jochen and mojo for reporting/providing patch: http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1922
|
||||
|
||||
2008 Feb 8
|
||||
- Bugfixes in ConvexCast support against the world.
|
||||
Thanks to Isgmasa for reporting/providing fix: http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1823
|
||||
|
||||
2008 Feb 6
|
||||
- Added btCapsuleShapeX and btCapsuleShapeZ for capsules around X and Z axis (default capsule is around Y)
|
||||
|
||||
2008 Feb 3
|
||||
- Added btTypedUserInfo, useful for serialization
|
||||
|
||||
2008 Jan 31
|
||||
- Add support for 16 and 32-bit indices for SPU / BulletMultiThreaded version.
|
||||
|
||||
2008 Jan 29
|
||||
- Added COLLADA Physics export/serialization/snapshot from any Bullet btDynamicsWorld. Saving the physics world into a text .xml file is useful for debugging etc.
|
||||
|
||||
2008 Jan 23
|
||||
- Added Stan Melax Convex Hull utility library in Extras/ConvexHull. This is useful to render non-polyhedral convex objects, and to simplify convex polyhedra.
|
||||
|
||||
2008 Jan 14
|
||||
- Add support for batch raycasting on SPU / BulletMultiThreaded
|
||||
|
||||
2007 Dec 16
|
||||
- Added btRigidBodyConstructionInfo, to make it easier to set individual setting (and leave other untouched) during rigid body construction.
|
||||
Thanks Vangelis Kokkevis for pointing this out.
|
||||
- Fixed memoryleak in the ConstraintDemo and Raytracer demo.
|
||||
- Fixed issue with clearing forces/gravity at the end of the stepSimulation, instead of during internalSingleStepSimulation.
|
||||
Thanks chunky for pointing this out: http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1780
|
||||
- Disabled additional damping in rigid body by default, but enable it in most demos. Set btRigidBodyConstructionInfo m_additionalDamping to true to enable this.
|
||||
- Removed obsolete QUICKPROF BEGIN/END_PROFILE, and enabled BT_PROFILE. Profiling is enabled by default (see Bullet/Demos/OpenGL/DemoApplication.cpp how to use this).
|
||||
User can switch off profiling by enabling define BT_NO_PROFILE in Bullet/src/btQuickprof.h.
|
||||
|
||||
2007 Dec 14
|
||||
- Added Hello World and BulletMultiThreaded demos
|
||||
- Add portable version of BulletMultiThreaded, through SequentialThreadSupport (non-parallel but sharing the same code-path)
|
||||
- Add Cmake support for AllBulletDemos
|
||||
|
||||
|
||||
2007 Dec 11
|
||||
- Moved the 'btRigidBody::clearForce' to the end of the stepSimulation, instead of in each substep.
|
||||
See discussion http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1601
|
||||
- Added btConvexPlaneCollisionAlgorithm, makes planes perform better, and prevents tunneling
|
||||
Thanks Andy O'Neil for reporting the performance/functionality issue
|
||||
- Fixes for IBM Cell SDK 3.0
|
||||
Thanks to Jochen Roth for the patch.
|
||||
|
||||
2007 Dec 10
|
||||
- Fixes in btHeightfieldTerrainShape
|
||||
Thanks to Jay Lee for the patch.
|
||||
|
||||
2007 Dec 9
|
||||
- Only update aabb of active objects
|
||||
Thanks Peter Tchernev for reporting (http://bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1764 )
|
||||
- Added workaround to compile libxml under Visual Studio 2008 Beta 2
|
||||
- Make glui compile under MSVC 9.0 beta (vsnprintf is already defined)
|
||||
|
||||
2007 Dec 6
|
||||
- Added DynamicControlDemo, showing dynamic control through constraint motors
|
||||
Thanks to Eddy Boxerman
|
||||
- Add support for generic concave shapes for convex cast.
|
||||
- Added convex cast query to collision world.
|
||||
- Added workaround for OpenGL bug in Mac OS X 10.5.0 (Leopard)
|
||||
- Added concave raycast demo
|
||||
All above thanks to John McCutchan (JMC)
|
||||
- Fixed issues that prevent Linux version to compile.
|
||||
Thanks to Enrico for reporting and patch, see
|
||||
- Fixed misleading name 'numTriangleIndices' into 'numTriangles'
|
||||
Thanks Sean Tasker for reporting:
|
||||
|
||||
2007 Nov 28:
|
||||
- Added raycast against trianglemesh. Will be extended to object cast soon.
|
||||
Thanks John McCutchan (JMC)
|
||||
- make getNumPoints const correct, add const getPoints().
|
||||
Thanks Dirk Gregorius
|
||||
- Bugfix: allow btCollisionObjects (non-btRigidBody) to interact properly with btRigidBody for cache-friendly btSequentialImpulseConstraintSolver.
|
||||
Thanks Andy O'Neil for pointing this out.
|
||||
- Bugfix: don't fail if spheres have identical center, use arbitrary separating normal (1,0,0)
|
||||
Thanks Sean Tasker for reporting! http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1681
|
||||
|
||||
|
||||
2007, November 20
|
||||
- Added hierarchical profiling
|
||||
- Fixed memory leak in btMultiSapBroadphase,
|
||||
- Fixed hash function (typo, should use 2 proxies)
|
||||
Thanks to Stephen (shatcher) for reporting and fixes! http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1696
|
||||
|
||||
2007 Nov 11
|
||||
- Fixed parallel solver (BulletMultiThreaded) friction issue
|
||||
- Terminate Win32 Threads when closing the CcdPhysicsDemo (when USE_PARALLEL_SOLVER/USE_PARALLEL_DISPATCHER is defined)
|
||||
|
||||
2007 Nov 6
|
||||
- Added support for 16-bit indices for triangle meshes
|
||||
- Added support for multiple mesh parts using btBvhTriangleMeshShape.
|
||||
Thanks to Tim Johansson
|
||||
|
||||
2007 Oct 22
|
||||
- All memory allocations go through btAlignedAlloc/btAlignedFree. User can override this to verify memory leaks
|
||||
- added a few more demos to AllBulletDemos
|
||||
- fix for one of the constructors of btHingeConstraint
|
||||
Thanks Marcus Hennix
|
||||
|
||||
2007 Oct 20
|
||||
- included glui, a GLUT/OpenGL based toolkit for some graphical user elements
|
||||
Removed dynamic_cast from glui, to allow linkage without rtti
|
||||
- added Box2D framework using glui, allowing all demos to run within one executable
|
||||
Thanks Erin Catto for the FrameWork skeleton (http://www.box2d.org)
|
||||
|
||||
2007 Ocy 17
|
||||
- Allow user to pass in their own memory (stack and pool) allocators, through collisionConfiguration. See demos how to use this
|
||||
|
||||
2007 Oct 14
|
||||
- Included working version of Cell SPU parallel optimized version for Libspe2 SPU task scheduler.
|
||||
This version compiles and runs on Playstation 3 Linux and IBM CellBlade, see BulletSpuOptimized.pdf for build instructions
|
||||
(Official Playstation 3 developers can request a SPURS version through Sony PS3 Devnet.)
|
||||
Thanks to IBM 'Extreme Blue' project for the contribution
|
||||
http://www-913.ibm.com/employment/us/extremeblue/
|
||||
Thanks Minh Cuong Tran, Benjamin Hoeferlin, Frederick Roth and Martina Huellmann
|
||||
for various contributions to get this initial Libspe2 parallel version up and running.
|
||||
|
||||
2007 Oct 13
|
||||
- made 'btCollisionShape::calculateLocalInertia' const
|
||||
Thanks to cgripeos, see http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1514
|
||||
- applied a large patch to remove warnings
|
||||
Thanks to Enrico, see http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1568
|
||||
- removed SSE includes, added #incude <string.h> for memset in Extras/quickstep, thanks Eternl Knight
|
||||
|
||||
2007 Oct 11
|
||||
- added Hashed Overlapping Pair Cache, recommended by Pierre Terdiman. It works like a charm, thanks Pierre and Erin Catto (code from Box2D)
|
||||
- modified some margins inside btBoxShape, btCylinderShape and btSphereShape
|
||||
- added cone debug rendering (for cones with x, y and z up-axis)
|
||||
- added improvements for optional Extra/quickstep, thanks to Remotion
|
||||
- some performance improvements for Bullet constraint solver
|
||||
|
||||
2007 Sept 28
|
||||
- upgraded GIMPACT to version 0.3
|
||||
Thanks to Francisco Leon
|
||||
|
||||
2007 Sept 27
|
||||
- added contribution from IBM Extreme Blue project for Libspe2 support. This allow to execute BulletMultiThreaded on Cell SPU under PS3 Linux and Cell Blade. See http://www-913.ibm.com/employment/us/extremeblue
|
||||
Thanks to Minh Cuong Tran, Frederick Roth, Martina Heullmann and Benjamin Hoeferlin.
|
||||
|
||||
2007 Sept 13
|
||||
- Improved btGenericD6Constraint. It can be used to create ragdolls (similar to the new btConeTwistConstraint). See GenericJointDemo
|
||||
- Added support for Bullet constraints in the optional Extras/quickstep ODE solver. See CcdPhysicsDemo, enable #COMPARE_WITH_QUICKSTEP and add libquickstep to the dependencies.
|
||||
For both patches/improvements thanks Francisco Leon/projectileman
|
||||
|
||||
2007 Sept 10
|
||||
- removed union from btQuadWordStorage, it caused issues under certain version of gcc/Linux
|
||||
|
||||
2007 Sept 10
|
||||
- Reverted constraint solver, due to some issues. Need to review the recent memory allocation changes.
|
||||
- Fixed issue with kinematic objects rotating at low speed: quaternion was de-normalized, passing value > 1 into acosf returns #IND00 invalid values
|
||||
- 16 byte memory alignment for BVH serialization
|
||||
- memory cleanup for btPoolAllocator
|
||||
|
||||
2007 Sept 9
|
||||
- Added serialization for BVH/btBvhTriangleMeshShape, including endian swapping. See ConcaveDemo for an example.
|
||||
Thanks to Phil Knight for the contribution.
|
||||
- Fixed issues related to stack allocator/compound collision algorithm
|
||||
Thanks Proctoid, http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=18&t=1460
|
||||
- Increase some default memory pool settings, and added a fallback for the constraints solver to use heap memory
|
||||
- Removed accidential testing code in btScalar.h related to operator new.
|
||||
- Enable btAxis3Sweep and bt32BitAxis3Sweep to be linked in at the same time, using template
|
||||
|
||||
2007 Sept 7
|
||||
- Replaced several dynamic memory allocations by stack allocation and pool allocations
|
||||
- Added branch-free quantized aabb bounding box overlap check, works better on Playstation 3 and XBox 360
|
||||
Thanks to Phil Knight. Also see www.cellperformance.com for related articles
|
||||
- Collision algorithms and settings for the memory/stack allocator can be done using btDefaultCollisionConfiguration
|
||||
This is an API change. See demos how to modify existing implementations with a one-liner.
|
||||
- Register several collision algorithms by default (sphere-sphere, sphere-box, sphere-triangle)
|
||||
- Use other traveral method for BVH by default, this improves triangle mesh collision performance.
|
||||
|
||||
2007 Aug 31
|
||||
- fixed MSVC 6 build
|
||||
Thanks Proctoid, http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1375
|
||||
- fixed double precision build issues
|
||||
Thanks Alex Silverman, http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1434
|
||||
|
||||
2007 Aug 24
|
||||
- fixed bug in btMatrix3x3::transposeTimes(const btMatrix3x3& m) const. Luckily it wasn't used in core parts of the library (yet).
|
||||
Thanks to Jay Lee
|
||||
|
||||
2007 Aug 15
|
||||
- fixed bug in Extras/GIMPACT 0.2 related to moving triangle meshes
|
||||
Thanks Thomas, http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1368
|
||||
|
||||
2007 Aug 14
|
||||
- added parallel constraint solver. Works on Playstation 3 Cell SPU and multi core (Win Threads on PC and XBox 360).
|
||||
See Extras/BulletMultiThreaded for SpuSolverTask subfolder and SpuParallelSolver.cpp
|
||||
Thanks Marten Svanfeldt (Starbreeze Studios)
|
||||
- fixed some bugs related to parallel collision detection (Extras/BulletMultiThreaded)
|
||||
Thanks Marten Svanfeldt (Starbreeze Studios)
|
||||
|
||||
2007 Aug 2
|
||||
- added compound and concave-convex (swapped) case for BulletMultiThreaded collision detection, thanks to Marten Svanfeldt
|
||||
- refactored broadphase and overlapping pair cache. This allows performance improvement by combining multiple broadphases. This helps add/remove of large batches of objects and large worlds. See also Pierre Terdiman forum topic:
|
||||
http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1329
|
||||
|
||||
|
||||
2007 July 27
|
||||
- added Ragdoll Demo
|
||||
Thanks to Marten Svanfeldt (Starbreeze Studios)
|
||||
|
||||
- added Vector Math library for SIMD 3D graphics linear algebra (vector, matrix, quaternion)
|
||||
See Bullet/Extras/vectormathlibrary
|
||||
Supports SIMD SSE, PowerPC PPU and Cell SPU (including PS3 Linux and CellBlade), as well as generic portable scalar version
|
||||
Will be used to improve BulletMultiThreaded performance
|
||||
Open Sourced by Sony Computer Entertainment Inc. under the new BSD license
|
||||
- added SIMD math library
|
||||
4-way SIMD for common math functions like atan2f4, cosf4, floorf4, fabsf4, rsqrtf4 etc. Used by Vector Math library under PPU and SPU.
|
||||
Supports PowerPC (PPU) and Cell SPU, including PS3 Linux and CellBlade.
|
||||
See Bullet/Extras/simdmathlibrary
|
||||
Open sourced by Sony Computer Entertainment Inc. under the new BSD license
|
||||
|
||||
|
||||
2007 July 25
|
||||
- added several patches: per-rigidbody sleeping threshold. added Assert to prevent deletion of rigidbody while constraints are still pointing at it
|
||||
Thanks to Marten Svanfeldt (Starbreeze Studios)
|
||||
|
||||
2007 July 13
|
||||
- fixed relative #include paths again. We can't use "../" relative paths: some compilers choke on it (it causes extreme long paths)
|
||||
Within the libraries, we always need to start with "BulletCollision/" or "BulletDynamics/ or "LinearMath/"
|
||||
|
||||
2007 July 10
|
||||
- Updated Bullet User Manual
|
||||
|
||||
2007 July 5
|
||||
- added btConeTwistConstraint, especially useful for ragdolls. See Demos/RagdollDemo
|
||||
Thanks to Marten Svanfeldt (Starbreeze Studios)
|
||||
|
||||
2007 June 29
|
||||
- btHeightfieldTerrainShape: Added heightfield support, with customizations
|
||||
- Upgraded to GIMPACT 0.2, see Extras/GIMPACT and MovingConcaveDemo
|
||||
- Several patches from Marten Svanfeldt (Starbreeze Studios)
|
||||
Improved collision filtering (in broadphase and rigidbody)
|
||||
Improved debug rendering
|
||||
Allow to set collision filter group/mask in addRigidBody
|
||||
|
||||
|
||||
2007 June 15
|
||||
- Changed btAlignedObjectArray to call copy constructor/replacement new for duplication, rather then assignment operator (operator=).
|
||||
|
||||
2007 June 11
|
||||
- Added multi-threading. Originally for Playstation 3 Cell SPU, but the same code can run using Win32 Threads using fake DMA transfers (memcpy)
|
||||
Libspe2 support for Cell Blade / PS3 Linux is upcoming
|
||||
See Extras/BulletMultiThreaded. Usage: replace btCollisionDispatcher by btSpuGatheringCollisionDispatcher
|
||||
|
||||
- Added managed Bullet library, entirely rewritten in C# for Windows and XBox 360 XNA
|
||||
See Extras/BulletX
|
||||
Thanks to KleMiX, aka Vsevolod Klementjev
|
||||
|
||||
2007 May 31
|
||||
- sign-bit went wrong in case of 32-bit broadphase, causing quantization problems.
|
||||
Thanks DevO for reporting.
|
||||
|
||||
2007 May 23
|
||||
- Fixed quantization problem for planar triangle meshes in btOptimizedBvh
|
||||
Thanks Phil Knight for reporting and helping to fix this bug.
|
||||
|
||||
2007 May 20
|
||||
- btAxisSweep3: Fixed a bug in btAxisSweep3 (sweep and prune) related to object removal. Only showed up when at least one btStaticPlaneShape was inserted.
|
||||
Thanks tbp for more details on reproducing case.
|
||||
- btAxisSweep3: Fixed issue with full 32bit precision btAxisSweep3 (define BP_USE_FIXEDPOINT_INT_32), it used only 0xffff/65536 for quantization instead of full integer space (0xffffffff)
|
||||
- btRaycastVehicle: Added 'getForwardVector' and getCurrentSpeedKmHour utility functions
|
||||
- Fixed local scaling issues (btConvexTriangleMeshShape, btBvhTriangleMeshShape, removed scaling from btMatrix3x3).
|
||||
Thanks Volker for reporting!
|
||||
- Added second filename search, so that starting BspDemo and ConvexDecompositionDemo from within Visual Studio (without setting the starting path) still works
|
||||
|
||||
2007 April 22
|
||||
- Added braking functionality to btRaycastVehicle
|
||||
- Removed tons of warnings, under MSVC 2005 compilation in -W4
|
||||
|
||||
2007 March 21
|
||||
- Fixed issues: comma at end of enum causes errors for some compilers
|
||||
- Fixed initialization bug in LocalRayResult ( m_localShapeInfo(localShapeInfo) )
|
||||
|
||||
2007 March 20
|
||||
- Added refit tree to quantized stackless tree, and updated ConcaveDemo as example.
|
||||
|
||||
2007 March 17
|
||||
- Added constraint solver optimizations, avoiding cross products during iterations, and gather rigidbody/constraint info in contiguous memory (btSolverBody/btSolverConstraint)
|
||||
- These optimizations don't give large benefit yet, but it has good potential. Turned on by default. Can be switched off using solver->setSolverMode(SOLVER_RANDMIZE_ORDER).
|
||||
- Enabled anti-jitter for rigid bodies. This is experimental, and can be switched off by setting a global (it is experimental so no proper interface) gJitterVelocityDampingFactor = 1.0;
|
||||
- Fixed bug in islandmanifold.heapSort(btPersistentManifoldSortPredicate()); , thanks Noehrgel for reporting this (affected Sun Solaris)
|
||||
|
||||
2007 March 12
|
||||
- Added compile-time toggle between on 16-bit and 32-bit fixed-point SAP broadphase.
|
||||
This allows the number of bodies to exceed 32767
|
||||
- Enable useQuantizedAabbCompression on btTriangleMesh, see ColladaDemo
|
||||
|
||||
2007 March 8
|
||||
- Fixed bug in constraint/island sorting (caused by replacing STL by dedicated btAlignedObjectArray with heapSort)
|
||||
Thanks Clemens Unterkofler for pointing this out!
|
||||
|
||||
2007 March 6
|
||||
- removed STL from the Bullet library: replace std::vector by btAlignedObjectArray. Also removed the std::set for overlapping pair set, and turned it into an overlapping pair array. The SAP only adds objects, never removed. Removal is postponed for during traversal of overlapping pairs (duplicates and non-overlapping pairs are removed during that traversal).
|
||||
- added heap sort and binary search/linear search to btAlignedObjectArray
|
||||
- fixed wrong cast, thanks Hamstray, http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1015
|
||||
|
||||
|
||||
2007 Feb 25
|
||||
- Improved performance of convex collision shapes, cache local AABB instead of recomputation. This fixes issue with very slow performance in larger .bsp levels
|
||||
|
||||
2007 Feb 24
|
||||
- Added compressed/quantized AABB tree, 16 bytes per node, while supporting 32-bit (triangle) indices.
|
||||
Should be faster and smaller then original version (quantized aabb check is done in integer space)
|
||||
Original aabb tree nodes are still supported. They are 44 bytes, with full floating point precision and additional subPart index.
|
||||
- added meter-unit scaling support in ColladaConverter.cpp
|
||||
|
||||
2007 Feb 21
|
||||
- Build system: updated bullet.pc.in library names
|
||||
- Updated EPA comparison integration (missing parameter)
|
||||
|
||||
2007 Jan 04
|
||||
- fixed optimized AABB tree building: in some cases the tree building fails due to unbalanced trees, which generated stack overflow
|
||||
|
||||
2006 Dec 15
|
||||
- added contribution to allow double precision collision detection/dynamics. Define BT_USE_DOUBLE_PRECISION in your project and libraries that include Bullet
|
||||
|
||||
2006 Dec 14
|
||||
- merged contact and non-contact constraint solving into one loop, will improve stability of jointed bodies during collisions
|
||||
- added first draft for hingeConstraint motor
|
||||
|
||||
2006 Dec 8, Erwin Coumans
|
||||
- preparation for SIMD: added btAlignedAllocator and btAlignedObjectArray, to replace stl std::vector, same interface, but compatible with 16 byte alignment
|
||||
- cleaned up dependencies in autogenerated msvc projectfiles
|
||||
- aligned btVector3 on 16 bytes boundary, under win32. see if developers will come up with problems
|
||||
|
||||
2006 Dec 04, Erwin Coumans
|
||||
Added btNearCallback. This is similar to Open Dynamics Engine (ODE) dNearCallback, but important differences:
|
||||
- contact points are persistent (lifetime more then one frame, for warmstarting/incremental contact point management)
|
||||
- continuous collision detection, time of impact
|
||||
Added btRigidBody::isInWorld(), returns true if btRigidBody is inside a btCollisionWorld/btDynamicsWorld derived class
|
||||
Added angularFactor to btRigidbody, this helps some character control (no angular impulse applied)
|
||||
|
||||
|
||||
2006 Nov 28
|
||||
Moved StackAlloc from EPA into LinearMath/btStackAlloc
|
||||
renamed internal class ConcaveShape into btConcaveShape
|
||||
added btHeightfieldTerrainShape (not completed yet)
|
||||
|
||||
2006 Nov 15 Nathanael Presson
|
||||
Added EPA penetration depth algorithm, Expanding Polytope Algorithm
|
||||
Added Pierre Terdiman penetration depth comparison/test DEMO
|
||||
Fixed Bullet's Minkowski sampling penetration depth solver
|
||||
Contributed by Nathanael Presson
|
||||
|
||||
2006 Nov 11 Francisco León Nájera
|
||||
Added GIMPACT trimesh collision detection: concave versus concave,
|
||||
Contributed by Francisco León Nájera
|
||||
|
||||
2006 Nov 2
|
||||
Minor refactoring: btCollisionObject changes from struct into class, added accessor methods
|
||||
Force use of btMotionState to synchronize graphics transform, disabled old btRigidBody constructor that accepts btTransform
|
||||
Renamed treshold into threshold throughout the code
|
||||
|
||||
2006 Oct 30
|
||||
Enable decoupling of physics and graphics framerate using interpolation and internal fixed timestep, based on btMotionState
|
||||
Enabled raycast vehicle demo (still needs tuning)
|
||||
Refresh contact points, even when they are already persistent.
|
||||
Fixed debugDraw colors (thanks pc0de for reporting)
|
||||
Use Dispatcher in ConcaveConvexCollisionAlgorithm (so it uses the registered collision algorithm, not hardcoded convexconcave)
|
||||
Improved performance of constraint solver by precalculating the cross product/impulse arm
|
||||
Added collision comparison code: ODE box-box, also sphere-triangle
|
||||
Added safety check into GJK, and an assert for AABB's that are very large
|
||||
Fixed kinematic support (deriving velocities for animated objects)
|
||||
Updated comparison/optional quickstep solver in Extras
|
||||
UserCollisionAlgorithm demonstrates btTriangleMesh usage (easier trimesh compared to index array version)
|
||||
Removed scaling from btTransform (we only want to deal with rigid transforms)
|
||||
|
||||
2006 Oct 4
|
||||
Fixed minor leak in btOptimizeBVH
|
||||
Cleanup of btRigidBody construction
|
||||
added getW() in btQuaternion
|
||||
assert when setLinearVelocity is called on btRigidBody
|
||||
renamed projectfile library from collada-dom to colladadom (to make VC6 happy)
|
||||
|
||||
2006 Sept 27
|
||||
Big Refactoring: renamed and moved files, create a replacement for CcdPhysicsEnvironment/CcdPhysicsController.
|
||||
All Bullet classes in LinearMath, BulletCollision and BulletDynamics start with bt, and methods start with lowercase.
|
||||
Moved classes into src folder, which is the only include folder needed.
|
||||
Added 2 headerfiles in src: btBulletCollisionCommon.h and btBulletDynamicsCommon.h
|
||||
|
||||
2006 Sept 23
|
||||
Fixed 2 bugs, causing crashes when removing objects. Should do better unit-testing. UnionFind and 3D SAP were involved.
|
||||
|
||||
2006 Sept 19
|
||||
Allow programmable friction and contact solver model. User can register their own functions for several interaction types.
|
||||
Improved performance, and removed hardcoded maximum overlaps (switched from C-array to stl::set)
|
||||
|
||||
2006 Sept 16
|
||||
Added Bullet 2.0 User Manual
|
||||
Allow registration of custom user collision algorithms
|
||||
|
||||
2006 Sept 10
|
||||
Started cleaning up demos
|
||||
|
||||
2006 Sept 4
|
||||
Fixed concave collision bug (caused instability/missing collisions in meshes/compounds)
|
||||
Fixed memoryleak in OptimizedBvh, added RayTestSingle to CollisionWorld
|
||||
Prepared for VehicleDemo
|
||||
Increased Performance (island generation for sleeping objects took too much time)
|
||||
Better COLLADA 1.4.1 physics conformance in ColladaDemo
|
||||
|
||||
2006 August 11
|
||||
Added Quake BspDemo
|
||||
Improved CCD for compound and non-convex objects
|
||||
|
||||
2006 August 10
|
||||
Added per-triangle material (friction/restitution) support for non-convex meshes. See ConcaveDemo for usage.
|
||||
|
||||
2006 August 9
|
||||
Added CMake support (see http://cmake.org)
|
||||
This can autogenerate makefiles, projectfiles cross platform (including MacOS X Xcode )
|
||||
Just run cmake . in the root folder and it will autogenerate build files
|
||||
|
||||
2006 July 26 Erwin Coumans
|
||||
Upgraded to COLLADA-DOM 1.4.1, latest SVN version
|
||||
ColladaDemo can export snapshots to .dae
|
||||
|
||||
2006 July 24 Erwin Coumans
|
||||
Added Compound CollisionShape support
|
||||
(this is still low performance -> requires stackless tree-versus-tree traversal for better performance)
|
||||
|
||||
2006 July 15 Erwin Coumans
|
||||
Added initial support for Parallel execution (collision detection, constraint solving)
|
||||
See ParallelPhysicsEnvironment in Extras\PhysicsInterface\CcdPhysics
|
||||
|
||||
2006 July 10 Erwin Coumans
|
||||
Added MacOS X support (some build issues mainly)
|
||||
|
||||
2006 July 5 Erwin Coumans
|
||||
Improved COLLADA 1.4 physics import, both COLLADA-DOM and FCollada
|
||||
|
||||
2006 June 29 Erwin Coumans
|
||||
Refactoring of the broadphase
|
||||
Moved some optional files to Extras: Algebraic ccd and EPA, quickstep
|
||||
Moved the limits on bodies/overlap to 32k and 65k
|
||||
|
||||
2006 June 25 Erwin Coumans
|
||||
Added basic Collision Filtering, during broadphase
|
||||
Allow adding meshes to the TriangleIndexVertexArray,
|
||||
(input for TriangleMeshShape)
|
||||
Preparation for CompoundShape
|
||||
|
||||
2006 June 19 Erwin Coumans
|
||||
Added support for COLLADA Physics Import.
|
||||
Both jam and Visual Studio can compile ColladaDemo
|
||||
|
||||
2006 June 18 Dirk Gregorius <dirk@dirkgregorius.de>
|
||||
Started implementing Generic6DOF joint and setup basic interface
|
||||
|
||||
|
||||
2006 June 17 Frank Richter <resqu@gmx.ch>
|
||||
Bumped version in configure.ac to 1.5.6 (assuming that "1.5f" is
|
||||
the next version released).
|
||||
Updated files in mk/autoconf and mk/jam with copies from CS; fixes a
|
||||
GLU detection issue on MinGW.
|
||||
Set msvc/bullet_ico.ico as the default application icon.
|
||||
Disabled exceptions for gcc builds.
|
||||
Applied a patch from Michael D. Adams to fix a warning with gcc.
|
||||
2006 jUNE 16 Erwin Coumans
|
||||
Constraints now merge simulation islands.
|
||||
|
||||
2006 May 24
|
||||
Improved GJK accuracy, fixed GjkConvexCast issue, thanks to ~MyXa~ for reporting
|
||||
|
||||
2006 May 19
|
||||
Added restitution support
|
||||
Moved out Friction and Dynamics info from ManifoldPoint (removed logical dependency)
|
||||
Added a void* m_userPersistentData in ManifoldPoint.
|
||||
Added a ContactDestroyedCallback, to allow user to handle destruction of m_userPersistentData
|
||||
|
||||
2006 May 13
|
||||
Fixed some bugs in friction / jacobian calculations. Reported by Dirk Gregorius. Thanks!
|
||||
|
||||
2006 May 9
|
||||
Fixed raycasting filtering
|
||||
Moved repository to SVN at https://svn.sourceforge.net/svnroot/bullet
|
||||
|
||||
2006 April 27
|
||||
Moved raycasting to CollisionWorld, to make it more generic
|
||||
Added basic CCD option in the CcdCollisionDemo
|
||||
Fixed 'noResponse' mode, for triggering rigidbodies (useful for Artificial Intelligence queries)
|
||||
Improved Bullet/ODE sample (in Extras)
|
||||
|
||||
2006 April 10
|
||||
Separating Axis Test (SAT) convex hull collision detector, contribution by Simon Hobbs
|
||||
Added SIMD SSE Math classes (for above SAT)
|
||||
Added Mouse picking in CcdPhysicsDemo
|
||||
Improved penetration depth estimation in MinkowskiPenetrationDepthSolver, both accuracy and performance
|
||||
Added Hinge constraint
|
||||
Added quickprof profiling (see http://sourceforge.net/projects/quickprof )
|
||||
|
||||
2006 March 21 Frank Richter <resqu@gmx.ch>
|
||||
Removed VC manifest files.
|
||||
Removed superfluous "grpplugins" projects.
|
||||
|
||||
2006 March 20 Erwin Coumans
|
||||
Clamped the acculumated impulse rather then intermediate impulse (within the iteration)
|
||||
Use the persistent contacts for reusing the impulse
|
||||
Separated friction and normal solving for better stability
|
||||
Decreased the default number of iterations of the constraint solver from 10 to 4
|
||||
|
||||
2006 March 19 Frank Richter <resqu@gmx.ch>
|
||||
Removed a couple of CSisms from the VC projects.
|
||||
Fixed VC include & lib paths to go to the Addtional* options
|
||||
instead the command line arguments.
|
||||
Added pkgconfig support.
|
||||
|
||||
2006 March 14 Frank Richter <resqu@gmx.ch>
|
||||
Added support for shipped GLUT on MinGW.
|
||||
Fixed GLUT support on MinGW.
|
||||
|
||||
2006 March 13 Frank Richter <resqu@gmx.ch>
|
||||
Bolted on Jam-based build system.
|
||||
Generated VC project files.
|
||||
Fixed GCC warnings.
|
||||
Fixed Linux build issues.
|
||||
|
||||
2006 March 13
|
||||
Added 3D Sweep and Prune Broadphase Collision Detection, Contribution from Simon Hobbs.
|
||||
|
||||
2006 March 2
|
||||
Minor change in license to ZLib/LibPNG
|
||||
This makes it legally a bit easier to deploy on Playstation 3
|
||||
Prepared for more generic constraints, added ConstraintsDemo
|
||||
|
||||
2006 Feb 23
|
||||
Rearranged files and dependencies to allow for easier standalone Collision Detection without Bullet Dynamics.
|
||||
See Demos/CollisionInterfaceDemo and Extras/ode/ode/test/test_BulletGjk.cpp for examples how to use.
|
||||
|
||||
2005 August 6
|
||||
Bullet 0.2 release with demos, sources, doxygen, draft manual
|
||||
|
||||
2005 June 1
|
||||
First public release of Bullet
|
||||
|
||||
|
||||
... todo: add history
|
||||
|
||||
2003 Initial version (continuous collision detection)
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
All files in the Bullet/src folder are under this Zlib license.
|
||||
Optional Extras/GIMPACT and Extras/GIMPACTBullet is also under ZLib license. Other optional external libraries in Extras/Demos have own license,see respective files.
|
||||
|
||||
This means Bullet can freely be used in any software, including commercial and console software. A Playstation 3 optimized version is available through Sony.
|
||||
@@ -0,0 +1,5 @@
|
||||
SUBDIRS=src
|
||||
|
||||
EXTRA_DIST = BulletLicense.txt Changelog copy_bullet_files \
|
||||
LICENSE README VERSION CMakeLists.txt
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
Bullet is a 3D Collision Detection and Rigid Body Dynamics Library for games and animation.
|
||||
Free for commercial use, including Playstation 3, open source under the ZLib License.
|
||||
|
||||
See the Bullet_User_Manual.pdf for more info and visit the Bullet Physics Forum at
|
||||
http://bulletphysics.org
|
||||
@@ -0,0 +1 @@
|
||||
2.79
|
||||
@@ -0,0 +1,46 @@
|
||||
LOCATION=$1
|
||||
cp $LOCATION/AUTHORS .
|
||||
cp $LOCATION/BulletLicense.txt .
|
||||
cp $LOCATION/ChangeLog .
|
||||
cp $LOCATION/LICENSE .
|
||||
cp $LOCATION/README .
|
||||
cp $LOCATION/VERSION .
|
||||
cp $LOCATION/src/*.h src
|
||||
cp $LOCATION/src/LinearMath/*.h src/LinearMath/
|
||||
cp $LOCATION/src/LinearMath/*.cpp src/LinearMath/
|
||||
cp $LOCATION/src/BulletCollision/BroadphaseCollision/*.h src/BulletCollision/BroadphaseCollision
|
||||
cp $LOCATION/src/BulletCollision/BroadphaseCollision/*.cpp src/BulletCollision/BroadphaseCollision
|
||||
cp $LOCATION/src/BulletCollision/CollisionDispatch/*.h src/BulletCollision/CollisionDispatch
|
||||
cp $LOCATION/src/BulletCollision/CollisionDispatch/*.cpp src/BulletCollision/CollisionDispatch
|
||||
cp $LOCATION/src/BulletCollision/CollisionShapes/*.h src/BulletCollision/CollisionShapes
|
||||
cp $LOCATION/src/BulletCollision/CollisionShapes/*.cpp src/BulletCollision/CollisionShapes
|
||||
cp $LOCATION/src/BulletCollision/NarrowPhaseCollision/*.h src/BulletCollision/NarrowPhaseCollision
|
||||
cp $LOCATION/src/BulletCollision/NarrowPhaseCollision/*.cpp src/BulletCollision/NarrowPhaseCollision
|
||||
cp $LOCATION/src/BulletDynamics/ConstraintSolver/*.h src/BulletDynamics/ConstraintSolver
|
||||
cp $LOCATION/src/BulletDynamics/ConstraintSolver/*.cpp src/BulletDynamics/ConstraintSolver
|
||||
cp $LOCATION/src/BulletDynamics/Dynamics/*.h src/BulletDynamics/Dynamics
|
||||
cp $LOCATION/src/BulletDynamics/Dynamics/*.cpp src/BulletDynamics/Dynamics
|
||||
cp $LOCATION/src/BulletDynamics/Vehicle/*.h src/BulletDynamics/Vehicle
|
||||
cp $LOCATION/src/BulletDynamics/Vehicle/*.cpp src/BulletDynamics/Vehicle
|
||||
cp $LOCATION/Demos/OpenGL/*.h Demos/OpenGL
|
||||
cp $LOCATION/Demos/OpenGL/*.cpp Demos/OpenGL
|
||||
|
||||
echo "REMEMBER to patch this new bullet version:"
|
||||
echo "1) btDiscreteDynamicsWorld.cpp:
|
||||
--- BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp (revision 4812)
|
||||
+++ BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp (working copy)
|
||||
@@ -262,7 +262,12 @@
|
||||
for (int v=0;v<m_vehicles[i]->getNumWheels();v++)
|
||||
{
|
||||
//synchronize the wheels with the (interpolated) chassis worldtransform
|
||||
+ // updateWheelTransform resets m_isInContact to false. Since
|
||||
+ // this field is needed in STK, we save it here and restore
|
||||
+ // its value after the call to updateWheelTransform.
|
||||
+ bool contact = m_vehicles[i]->getWheelInfo(v).m_raycastInfo.m_isInContact;
|
||||
m_vehicles[i]->updateWheelTransform(v,true);
|
||||
+ m_vehicles[i]->getWheelInfo(v).m_raycastInfo.m_isInContact = contact;
|
||||
}
|
||||
}
|
||||
}
|
||||
"
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Draft high-level generic physics C-API. For low-level access, use the physics SDK native API's.
|
||||
Work in progress, functionality will be added on demand.
|
||||
|
||||
If possible, use the richer Bullet C++ API, by including "btBulletDynamicsCommon.h"
|
||||
*/
|
||||
|
||||
#ifndef BULLET_C_API_H
|
||||
#define BULLET_C_API_H
|
||||
|
||||
#define PL_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name
|
||||
|
||||
#ifdef BT_USE_DOUBLE_PRECISION
|
||||
typedef double plReal;
|
||||
#else
|
||||
typedef float plReal;
|
||||
#endif
|
||||
|
||||
typedef plReal plVector3[3];
|
||||
typedef plReal plQuaternion[4];
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Particular physics SDK (C-API) */
|
||||
PL_DECLARE_HANDLE(plPhysicsSdkHandle);
|
||||
|
||||
/** Dynamics world, belonging to some physics SDK (C-API)*/
|
||||
PL_DECLARE_HANDLE(plDynamicsWorldHandle);
|
||||
|
||||
/** Rigid Body that can be part of a Dynamics World (C-API)*/
|
||||
PL_DECLARE_HANDLE(plRigidBodyHandle);
|
||||
|
||||
/** Collision Shape/Geometry, property of a Rigid Body (C-API)*/
|
||||
PL_DECLARE_HANDLE(plCollisionShapeHandle);
|
||||
|
||||
/** Constraint for Rigid Bodies (C-API)*/
|
||||
PL_DECLARE_HANDLE(plConstraintHandle);
|
||||
|
||||
/** Triangle Mesh interface (C-API)*/
|
||||
PL_DECLARE_HANDLE(plMeshInterfaceHandle);
|
||||
|
||||
/** Broadphase Scene/Proxy Handles (C-API)*/
|
||||
PL_DECLARE_HANDLE(plCollisionBroadphaseHandle);
|
||||
PL_DECLARE_HANDLE(plBroadphaseProxyHandle);
|
||||
PL_DECLARE_HANDLE(plCollisionWorldHandle);
|
||||
|
||||
/**
|
||||
Create and Delete a Physics SDK
|
||||
*/
|
||||
|
||||
extern plPhysicsSdkHandle plNewBulletSdk(void); //this could be also another sdk, like ODE, PhysX etc.
|
||||
extern void plDeletePhysicsSdk(plPhysicsSdkHandle physicsSdk);
|
||||
|
||||
/** Collision World, not strictly necessary, you can also just create a Dynamics World with Rigid Bodies which internally manages the Collision World with Collision Objects */
|
||||
|
||||
typedef void(*btBroadphaseCallback)(void* clientData, void* object1,void* object2);
|
||||
|
||||
extern plCollisionBroadphaseHandle plCreateSapBroadphase(btBroadphaseCallback beginCallback,btBroadphaseCallback endCallback);
|
||||
|
||||
extern void plDestroyBroadphase(plCollisionBroadphaseHandle bp);
|
||||
|
||||
extern plBroadphaseProxyHandle plCreateProxy(plCollisionBroadphaseHandle bp, void* clientData, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ);
|
||||
|
||||
extern void plDestroyProxy(plCollisionBroadphaseHandle bp, plBroadphaseProxyHandle proxyHandle);
|
||||
|
||||
extern void plSetBoundingBox(plBroadphaseProxyHandle proxyHandle, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ);
|
||||
|
||||
/* todo: add pair cache support with queries like add/remove/find pair */
|
||||
|
||||
extern plCollisionWorldHandle plCreateCollisionWorld(plPhysicsSdkHandle physicsSdk);
|
||||
|
||||
/* todo: add/remove objects */
|
||||
|
||||
|
||||
/* Dynamics World */
|
||||
|
||||
extern plDynamicsWorldHandle plCreateDynamicsWorld(plPhysicsSdkHandle physicsSdk);
|
||||
|
||||
extern void plDeleteDynamicsWorld(plDynamicsWorldHandle world);
|
||||
|
||||
extern void plStepSimulation(plDynamicsWorldHandle, plReal timeStep);
|
||||
|
||||
extern void plAddRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object);
|
||||
|
||||
extern void plRemoveRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object);
|
||||
|
||||
|
||||
/* Rigid Body */
|
||||
|
||||
extern plRigidBodyHandle plCreateRigidBody( void* user_data, float mass, plCollisionShapeHandle cshape );
|
||||
|
||||
extern void plDeleteRigidBody(plRigidBodyHandle body);
|
||||
|
||||
|
||||
/* Collision Shape definition */
|
||||
|
||||
extern plCollisionShapeHandle plNewSphereShape(plReal radius);
|
||||
extern plCollisionShapeHandle plNewBoxShape(plReal x, plReal y, plReal z);
|
||||
extern plCollisionShapeHandle plNewCapsuleShape(plReal radius, plReal height);
|
||||
extern plCollisionShapeHandle plNewConeShape(plReal radius, plReal height);
|
||||
extern plCollisionShapeHandle plNewCylinderShape(plReal radius, plReal height);
|
||||
extern plCollisionShapeHandle plNewCompoundShape(void);
|
||||
extern void plAddChildShape(plCollisionShapeHandle compoundShape,plCollisionShapeHandle childShape, plVector3 childPos,plQuaternion childOrn);
|
||||
|
||||
extern void plDeleteShape(plCollisionShapeHandle shape);
|
||||
|
||||
/* Convex Meshes */
|
||||
extern plCollisionShapeHandle plNewConvexHullShape(void);
|
||||
extern void plAddVertex(plCollisionShapeHandle convexHull, plReal x,plReal y,plReal z);
|
||||
/* Concave static triangle meshes */
|
||||
extern plMeshInterfaceHandle plNewMeshInterface(void);
|
||||
extern void plAddTriangle(plMeshInterfaceHandle meshHandle, plVector3 v0,plVector3 v1,plVector3 v2);
|
||||
extern plCollisionShapeHandle plNewStaticTriangleMeshShape(plMeshInterfaceHandle);
|
||||
|
||||
extern void plSetScaling(plCollisionShapeHandle shape, plVector3 scaling);
|
||||
|
||||
/* SOLID has Response Callback/Table/Management */
|
||||
/* PhysX has Triggers, User Callbacks and filtering */
|
||||
/* ODE has the typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); */
|
||||
|
||||
/* typedef void plUpdatedPositionCallback(void* userData, plRigidBodyHandle rbHandle, plVector3 pos); */
|
||||
/* typedef void plUpdatedOrientationCallback(void* userData, plRigidBodyHandle rbHandle, plQuaternion orientation); */
|
||||
|
||||
/* get world transform */
|
||||
extern void plGetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix);
|
||||
extern void plGetPosition(plRigidBodyHandle object,plVector3 position);
|
||||
extern void plGetOrientation(plRigidBodyHandle object,plQuaternion orientation);
|
||||
|
||||
/* set world transform (position/orientation) */
|
||||
extern void plSetPosition(plRigidBodyHandle object, const plVector3 position);
|
||||
extern void plSetOrientation(plRigidBodyHandle object, const plQuaternion orientation);
|
||||
extern void plSetEuler(plReal yaw,plReal pitch,plReal roll, plQuaternion orient);
|
||||
extern void plSetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix);
|
||||
|
||||
typedef struct plRayCastResult {
|
||||
plRigidBodyHandle m_body;
|
||||
plCollisionShapeHandle m_shape;
|
||||
plVector3 m_positionWorld;
|
||||
plVector3 m_normalWorld;
|
||||
} plRayCastResult;
|
||||
|
||||
extern int plRayCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plRayCastResult res);
|
||||
|
||||
/* Sweep API */
|
||||
|
||||
/* extern plRigidBodyHandle plObjectCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plVector3 hitpoint, plVector3 normal); */
|
||||
|
||||
/* Continuous Collision Detection API */
|
||||
|
||||
// needed for source/blender/blenkernel/intern/collision.c
|
||||
double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float q2[3], float q3[3], float *pa, float *pb, float normal[3]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif //BULLET_C_API_H
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
//Bullet Continuous Collision Detection and Physics Library
|
||||
//Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
|
||||
//
|
||||
// btAxisSweep3
|
||||
//
|
||||
// Copyright (c) 2006 Simon Hobbs
|
||||
//
|
||||
// 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.
|
||||
#include "btAxisSweep3.h"
|
||||
|
||||
|
||||
btAxisSweep3::btAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned short int maxHandles, btOverlappingPairCache* pairCache, bool disableRaycastAccelerator)
|
||||
:btAxisSweep3Internal<unsigned short int>(worldAabbMin,worldAabbMax,0xfffe,0xffff,maxHandles,pairCache,disableRaycastAccelerator)
|
||||
{
|
||||
// 1 handle is reserved as sentinel
|
||||
btAssert(maxHandles > 1 && maxHandles < 32767);
|
||||
|
||||
}
|
||||
|
||||
|
||||
bt32BitAxisSweep3::bt32BitAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned int maxHandles , btOverlappingPairCache* pairCache , bool disableRaycastAccelerator)
|
||||
:btAxisSweep3Internal<unsigned int>(worldAabbMin,worldAabbMax,0xfffffffe,0x7fffffff,maxHandles,pairCache,disableRaycastAccelerator)
|
||||
{
|
||||
// 1 handle is reserved as sentinel
|
||||
btAssert(maxHandles > 1 && maxHandles < 2147483647);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef BT_BROADPHASE_INTERFACE_H
|
||||
#define BT_BROADPHASE_INTERFACE_H
|
||||
|
||||
|
||||
|
||||
struct btDispatcherInfo;
|
||||
class btDispatcher;
|
||||
#include "btBroadphaseProxy.h"
|
||||
|
||||
class btOverlappingPairCache;
|
||||
|
||||
|
||||
|
||||
struct btBroadphaseAabbCallback
|
||||
{
|
||||
virtual ~btBroadphaseAabbCallback() {}
|
||||
virtual bool process(const btBroadphaseProxy* proxy) = 0;
|
||||
};
|
||||
|
||||
|
||||
struct btBroadphaseRayCallback : public btBroadphaseAabbCallback
|
||||
{
|
||||
///added some cached data to accelerate ray-AABB tests
|
||||
btVector3 m_rayDirectionInverse;
|
||||
unsigned int m_signs[3];
|
||||
btScalar m_lambda_max;
|
||||
|
||||
virtual ~btBroadphaseRayCallback() {}
|
||||
};
|
||||
|
||||
#include "LinearMath/btVector3.h"
|
||||
|
||||
///The btBroadphaseInterface class provides an interface to detect aabb-overlapping object pairs.
|
||||
///Some implementations for this broadphase interface include btAxisSweep3, bt32BitAxisSweep3 and btDbvtBroadphase.
|
||||
///The actual overlapping pair management, storage, adding and removing of pairs is dealt by the btOverlappingPairCache class.
|
||||
class btBroadphaseInterface
|
||||
{
|
||||
public:
|
||||
virtual ~btBroadphaseInterface() {}
|
||||
|
||||
virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy) =0;
|
||||
virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher)=0;
|
||||
virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher)=0;
|
||||
virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const =0;
|
||||
|
||||
virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0), const btVector3& aabbMax = btVector3(0,0,0)) = 0;
|
||||
|
||||
virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) = 0;
|
||||
|
||||
///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb
|
||||
virtual void calculateOverlappingPairs(btDispatcher* dispatcher)=0;
|
||||
|
||||
virtual btOverlappingPairCache* getOverlappingPairCache()=0;
|
||||
virtual const btOverlappingPairCache* getOverlappingPairCache() const =0;
|
||||
|
||||
///getAabb returns the axis aligned bounding box in the 'global' coordinate frame
|
||||
///will add some transform later
|
||||
virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const =0;
|
||||
|
||||
///reset broadphase internal structures, to ensure determinism/reproducability
|
||||
virtual void resetPool(btDispatcher* dispatcher) { (void) dispatcher; };
|
||||
|
||||
virtual void printStats() = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif //BT_BROADPHASE_INTERFACE_H
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "btBroadphaseProxy.h"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user